Merge branch 'chrome-custom-tabs' of https://github.com/sturmen/Tusky into sturmen-chrome-custom-tabs
This commit is contained in:
commit
e557d0c002
8 changed files with 210 additions and 8 deletions
|
@ -29,10 +29,11 @@ dependencies {
|
||||||
compile('com.mikepenz:materialdrawer:5.8.2@aar') {
|
compile('com.mikepenz:materialdrawer:5.8.2@aar') {
|
||||||
transitive = true
|
transitive = true
|
||||||
}
|
}
|
||||||
compile 'com.android.support:appcompat-v7:25.2.0'
|
compile 'com.android.support:appcompat-v7:25.3.1'
|
||||||
compile 'com.android.support:recyclerview-v7:25.2.0'
|
compile 'com.android.support:customtabs:25.3.1'
|
||||||
compile 'com.android.support:support-v13:25.2.0'
|
compile 'com.android.support:recyclerview-v7:25.3.1'
|
||||||
compile 'com.android.support:design:25.2.0'
|
compile 'com.android.support:support-v13:25.3.1'
|
||||||
|
compile 'com.android.support:design:25.3.1'
|
||||||
compile 'com.squareup.picasso:picasso:2.5.2'
|
compile 'com.squareup.picasso:picasso:2.5.2'
|
||||||
compile 'com.pkmmte.view:circularimageview:1.1'
|
compile 'com.pkmmte.view:circularimageview:1.1'
|
||||||
compile 'com.github.peter9870:sparkbutton:master'
|
compile 'com.github.peter9870:sparkbutton:master'
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
package com.keylesspalace.tusky;
|
||||||
|
|
||||||
|
import android.content.ActivityNotFoundException;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
import android.support.customtabs.CustomTabsIntent;
|
||||||
|
import android.support.v4.content.ContextCompat;
|
||||||
|
import android.text.style.URLSpan;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
class CustomTabURLSpan extends URLSpan {
|
||||||
|
CustomTabURLSpan(String url) {
|
||||||
|
super(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CustomTabURLSpan(Parcel src) {
|
||||||
|
super(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Parcelable.Creator<CustomTabURLSpan> CREATOR = new Parcelable.Creator<CustomTabURLSpan>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CustomTabURLSpan createFromParcel(Parcel source) {
|
||||||
|
return new CustomTabURLSpan(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CustomTabURLSpan[] newArray(int size) {
|
||||||
|
return new CustomTabURLSpan[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View widget) {
|
||||||
|
Uri uri = Uri.parse(getURL());
|
||||||
|
Context context = widget.getContext();
|
||||||
|
boolean lightTheme = PreferenceManager.getDefaultSharedPreferences(context).getBoolean("lightTheme", false);
|
||||||
|
int toolbarColor = ContextCompat.getColor(context, lightTheme ? R.color.custom_tab_toolbar_light : R.color.custom_tab_toolbar_dark);
|
||||||
|
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
|
||||||
|
builder.setToolbarColor(toolbarColor);
|
||||||
|
CustomTabsIntent customTabsIntent = builder.build();
|
||||||
|
try {
|
||||||
|
String packageName = CustomTabsHelper.getPackageNameToUse(context);
|
||||||
|
|
||||||
|
//If we cant find a package name, it means theres no browser that supports
|
||||||
|
//Chrome Custom Tabs installed. So, we fallback to the webview
|
||||||
|
if (packageName == null) {
|
||||||
|
super.onClick(widget);
|
||||||
|
} else {
|
||||||
|
customTabsIntent.intent.setPackage(packageName);
|
||||||
|
customTabsIntent.launchUrl(context, uri);
|
||||||
|
}
|
||||||
|
} catch (ActivityNotFoundException e) {
|
||||||
|
android.util.Log.w("URLSpan", "Activity was not found for intent, " + customTabsIntent.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
122
app/src/main/java/com/keylesspalace/tusky/CustomTabsHelper.java
Normal file
122
app/src/main/java/com/keylesspalace/tusky/CustomTabsHelper.java
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
package com.keylesspalace.tusky;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.pm.ResolveInfo;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stolen from https://github.com/GoogleChrome/custom-tabs-client/blob/master/shared/src/main/java/org/chromium/customtabsclient/shared/CustomTabsHelper.java
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class CustomTabsHelper {
|
||||||
|
private static final String TAG = "CustomTabsHelper";
|
||||||
|
static final String STABLE_PACKAGE = "com.android.chrome";
|
||||||
|
static final String BETA_PACKAGE = "com.chrome.beta";
|
||||||
|
static final String DEV_PACKAGE = "com.chrome.dev";
|
||||||
|
static final String LOCAL_PACKAGE = "com.google.android.apps.chrome";
|
||||||
|
private static final String EXTRA_CUSTOM_TABS_KEEP_ALIVE =
|
||||||
|
"android.support.customtabs.extra.KEEP_ALIVE";
|
||||||
|
private static final String ACTION_CUSTOM_TABS_CONNECTION =
|
||||||
|
"android.support.customtabs.action.CustomTabsService";
|
||||||
|
|
||||||
|
private static String sPackageNameToUse;
|
||||||
|
|
||||||
|
private CustomTabsHelper() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Goes through all apps that handle VIEW intents and have a warmup service. Picks
|
||||||
|
* the one chosen by the user if there is one, otherwise makes a best effort to return a
|
||||||
|
* valid package name.
|
||||||
|
*
|
||||||
|
* This is <strong>not</strong> threadsafe.
|
||||||
|
*
|
||||||
|
* @param context {@link Context} to use for accessing {@link PackageManager}.
|
||||||
|
* @return The package name recommended to use for connecting to custom tabs related components.
|
||||||
|
*/
|
||||||
|
public static String getPackageNameToUse(Context context) {
|
||||||
|
if (sPackageNameToUse != null) return sPackageNameToUse;
|
||||||
|
|
||||||
|
PackageManager pm = context.getPackageManager();
|
||||||
|
// Get default VIEW intent handler.
|
||||||
|
Intent activityIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.example.com"));
|
||||||
|
ResolveInfo defaultViewHandlerInfo = pm.resolveActivity(activityIntent, 0);
|
||||||
|
String defaultViewHandlerPackageName = null;
|
||||||
|
if (defaultViewHandlerInfo != null) {
|
||||||
|
defaultViewHandlerPackageName = defaultViewHandlerInfo.activityInfo.packageName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all apps that can handle VIEW intents.
|
||||||
|
List<ResolveInfo> resolvedActivityList = pm.queryIntentActivities(activityIntent, 0);
|
||||||
|
List<String> packagesSupportingCustomTabs = new ArrayList<>();
|
||||||
|
for (ResolveInfo info : resolvedActivityList) {
|
||||||
|
Intent serviceIntent = new Intent();
|
||||||
|
serviceIntent.setAction(ACTION_CUSTOM_TABS_CONNECTION);
|
||||||
|
serviceIntent.setPackage(info.activityInfo.packageName);
|
||||||
|
if (pm.resolveService(serviceIntent, 0) != null) {
|
||||||
|
packagesSupportingCustomTabs.add(info.activityInfo.packageName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now packagesSupportingCustomTabs contains all apps that can handle both VIEW intents
|
||||||
|
// and service calls.
|
||||||
|
if (packagesSupportingCustomTabs.isEmpty()) {
|
||||||
|
sPackageNameToUse = null;
|
||||||
|
} else if (packagesSupportingCustomTabs.size() == 1) {
|
||||||
|
sPackageNameToUse = packagesSupportingCustomTabs.get(0);
|
||||||
|
} else if (!TextUtils.isEmpty(defaultViewHandlerPackageName)
|
||||||
|
&& !hasSpecializedHandlerIntents(context, activityIntent)
|
||||||
|
&& packagesSupportingCustomTabs.contains(defaultViewHandlerPackageName)) {
|
||||||
|
sPackageNameToUse = defaultViewHandlerPackageName;
|
||||||
|
} else if (packagesSupportingCustomTabs.contains(STABLE_PACKAGE)) {
|
||||||
|
sPackageNameToUse = STABLE_PACKAGE;
|
||||||
|
} else if (packagesSupportingCustomTabs.contains(BETA_PACKAGE)) {
|
||||||
|
sPackageNameToUse = BETA_PACKAGE;
|
||||||
|
} else if (packagesSupportingCustomTabs.contains(DEV_PACKAGE)) {
|
||||||
|
sPackageNameToUse = DEV_PACKAGE;
|
||||||
|
} else if (packagesSupportingCustomTabs.contains(LOCAL_PACKAGE)) {
|
||||||
|
sPackageNameToUse = LOCAL_PACKAGE;
|
||||||
|
}
|
||||||
|
return sPackageNameToUse;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to check whether there is a specialized handler for a given intent.
|
||||||
|
* @param intent The intent to check with.
|
||||||
|
* @return Whether there is a specialized handler for the given intent.
|
||||||
|
*/
|
||||||
|
private static boolean hasSpecializedHandlerIntents(Context context, Intent intent) {
|
||||||
|
try {
|
||||||
|
PackageManager pm = context.getPackageManager();
|
||||||
|
List<ResolveInfo> handlers = pm.queryIntentActivities(
|
||||||
|
intent,
|
||||||
|
PackageManager.GET_RESOLVED_FILTER);
|
||||||
|
if (handlers == null || handlers.size() == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (ResolveInfo resolveInfo : handlers) {
|
||||||
|
IntentFilter filter = resolveInfo.filter;
|
||||||
|
if (filter == null) continue;
|
||||||
|
if (filter.countDataAuthorities() == 0 || filter.countDataPaths() == 0) continue;
|
||||||
|
if (resolveInfo.activityInfo == null) continue;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
Log.e(TAG, "Runtime exception while getting specialized handlers");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return All possible chrome package names that provide custom tabs feature.
|
||||||
|
*/
|
||||||
|
public static String[] getPackages() {
|
||||||
|
return new String[]{"", STABLE_PACKAGE, BETA_PACKAGE, DEV_PACKAGE, LOCAL_PACKAGE};
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,8 @@
|
||||||
package com.keylesspalace.tusky;
|
package com.keylesspalace.tusky;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.text.SpannableStringBuilder;
|
import android.text.SpannableStringBuilder;
|
||||||
|
@ -105,6 +107,7 @@ class StatusViewHolder extends RecyclerView.ViewHolder {
|
||||||
/* Redirect URLSpan's in the status content to the listener for viewing tag pages and
|
/* Redirect URLSpan's in the status content to the listener for viewing tag pages and
|
||||||
* account pages. */
|
* account pages. */
|
||||||
SpannableStringBuilder builder = new SpannableStringBuilder(content);
|
SpannableStringBuilder builder = new SpannableStringBuilder(content);
|
||||||
|
boolean useCustomTabs = PreferenceManager.getDefaultSharedPreferences(container.getContext()).getBoolean("customTabs", true);
|
||||||
URLSpan[] urlSpans = content.getSpans(0, content.length(), URLSpan.class);
|
URLSpan[] urlSpans = content.getSpans(0, content.length(), URLSpan.class);
|
||||||
for (URLSpan span : urlSpans) {
|
for (URLSpan span : urlSpans) {
|
||||||
int start = builder.getSpanStart(span);
|
int start = builder.getSpanStart(span);
|
||||||
|
@ -140,6 +143,10 @@ class StatusViewHolder extends RecyclerView.ViewHolder {
|
||||||
builder.removeSpan(span);
|
builder.removeSpan(span);
|
||||||
builder.setSpan(newSpan, start, end, flags);
|
builder.setSpan(newSpan, start, end, flags);
|
||||||
}
|
}
|
||||||
|
} else if (useCustomTabs) {
|
||||||
|
ClickableSpan newSpan = new CustomTabURLSpan(span.getURL());
|
||||||
|
builder.removeSpan(span);
|
||||||
|
builder.setSpan(newSpan, start, end, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Set the contents.
|
// Set the contents.
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
<color name="compose_mention_dark">#AFBFCF</color>
|
<color name="compose_mention_dark">#AFBFCF</color>
|
||||||
<color name="report_status_background_dark">#000000</color>
|
<color name="report_status_background_dark">#000000</color>
|
||||||
<color name="report_status_divider_dark">#2F2F2F</color>
|
<color name="report_status_divider_dark">#2F2F2F</color>
|
||||||
|
<color name="custom_tab_toolbar_dark">#363c4b</color>
|
||||||
<!--Light Theme Colors-->
|
<!--Light Theme Colors-->
|
||||||
<color name="color_primary_light">#dfdfdf</color>
|
<color name="color_primary_light">#dfdfdf</color>
|
||||||
<color name="color_primary_dark_light">#8f8f8f</color>
|
<color name="color_primary_dark_light">#8f8f8f</color>
|
||||||
|
@ -68,4 +69,6 @@
|
||||||
<color name="compose_mention_light">#2F5F6F</color>
|
<color name="compose_mention_light">#2F5F6F</color>
|
||||||
<color name="report_status_background_light">#EFEFEF</color>
|
<color name="report_status_background_light">#EFEFEF</color>
|
||||||
<color name="report_status_divider_light">#9F9F9F</color>
|
<color name="report_status_divider_light">#9F9F9F</color>
|
||||||
|
<color name="custom_tab_toolbar_light">#ffffff</color>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -107,6 +107,7 @@
|
||||||
<string name="visibility_private">Only followers and mentions can see</string>
|
<string name="visibility_private">Only followers and mentions can see</string>
|
||||||
|
|
||||||
<string name="pref_title_notification_settings">Notifications</string>
|
<string name="pref_title_notification_settings">Notifications</string>
|
||||||
|
<string name="pref_title_edit_notification_settings">Edit Notifications</string>
|
||||||
<string name="pref_title_notifications_enabled">Push notifications</string>
|
<string name="pref_title_notifications_enabled">Push notifications</string>
|
||||||
<string name="pref_title_notification_alerts">Alerts</string>
|
<string name="pref_title_notification_alerts">Alerts</string>
|
||||||
<string name="pref_title_notification_alert_sound">Notify with a sound</string>
|
<string name="pref_title_notification_alert_sound">Notify with a sound</string>
|
||||||
|
@ -119,6 +120,8 @@
|
||||||
<string name="pref_title_notification_filter_favourites">my posts are favourited</string>
|
<string name="pref_title_notification_filter_favourites">my posts are favourited</string>
|
||||||
<string name="pref_title_appearance_settings">Appearance</string>
|
<string name="pref_title_appearance_settings">Appearance</string>
|
||||||
<string name="pref_title_light_theme">Use the Light Theme</string>
|
<string name="pref_title_light_theme">Use the Light Theme</string>
|
||||||
|
<string name="pref_title_browser_settings">Browser</string>
|
||||||
|
<string name="pre_title_custom_tabs">Use Chrome Custom Tabs</string>
|
||||||
|
|
||||||
<string name="notification_mention_format">%s mentioned you</string>
|
<string name="notification_mention_format">%s mentioned you</string>
|
||||||
<string name="notification_summary_large">%1$s, %2$s, %3$s and %4$d others</string>
|
<string name="notification_summary_large">%1$s, %2$s, %3$s and %4$d others</string>
|
||||||
|
|
|
@ -10,8 +10,14 @@
|
||||||
android:defaultValue="false" />
|
android:defaultValue="false" />
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
<PreferenceCategory android:title="@string/pref_title_browser_settings">
|
||||||
<PreferenceScreen android:title="@string/pref_title_notification_settings">
|
<CheckBoxPreference
|
||||||
|
android:key="customTabs"
|
||||||
|
android:title="@string/pre_title_custom_tabs"
|
||||||
|
android:defaultValue="true" />
|
||||||
|
</PreferenceCategory>
|
||||||
|
<PreferenceCategory android:title="@string/pref_title_notification_settings">
|
||||||
|
<PreferenceScreen android:title="@string/pref_title_edit_notification_settings">
|
||||||
|
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:key="notificationsEnabled"
|
android:key="notificationsEnabled"
|
||||||
|
@ -66,5 +72,5 @@
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
</PreferenceCategory>
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
|
|
@ -5,7 +5,7 @@ buildscript {
|
||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:2.3.0'
|
classpath 'com.android.tools.build:gradle:2.3.1'
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
|
|
Loading…
Reference in a new issue