mirror of
https://github.com/gsantner/dandelion
synced 2024-12-22 19:08:03 +01:00
Use customTabs to open external links. This is a very basic implementation
This commit is contained in:
parent
0b0b0198df
commit
ae2cefd6a5
6 changed files with 331 additions and 4 deletions
|
@ -48,6 +48,7 @@ dependencies {
|
|||
compile 'com.jakewharton:butterknife:8.0.1'
|
||||
compile 'info.guardianproject.netcipher:netcipher:2.0.0-alpha1'
|
||||
compile 'info.guardianproject.netcipher:netcipher-webkit:2.0.0-alpha1'
|
||||
compile "com.android.support:customtabs:24.2.0"
|
||||
apt 'com.jakewharton:butterknife-compiler:8.0.1'
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ import android.os.Handler;
|
|||
import android.os.StrictMode;
|
||||
import android.provider.MediaStore;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.customtabs.CustomTabsIntent;
|
||||
import android.support.design.widget.AppBarLayout;
|
||||
import android.support.design.widget.NavigationView;
|
||||
import android.support.design.widget.Snackbar;
|
||||
|
@ -79,6 +80,8 @@ import com.github.dfa.diaspora_android.data.PodUserProfile;
|
|||
import com.github.dfa.diaspora_android.listener.WebUserProfileChangedListener;
|
||||
import com.github.dfa.diaspora_android.ui.ContextMenuWebView;
|
||||
import com.github.dfa.diaspora_android.ui.CustomWebViewClient;
|
||||
import com.github.dfa.diaspora_android.util.CustomTabHelpers.BrowserFallback;
|
||||
import com.github.dfa.diaspora_android.util.CustomTabHelpers.CustomTabActivityHelper;
|
||||
import com.github.dfa.diaspora_android.util.DiasporaUrlHelper;
|
||||
import com.github.dfa.diaspora_android.util.Helpers;
|
||||
import com.github.dfa.diaspora_android.util.Log;
|
||||
|
@ -111,6 +114,7 @@ public class MainActivity extends AppCompatActivity
|
|||
public static final int REQUEST_CODE__ACCESS_EXTERNAL_STORAGE = 124;
|
||||
|
||||
public static final String ACTION_OPEN_URL = "com.github.dfa.diaspora_android.MainActivity.open_url";
|
||||
public static final String ACTION_OPEN_EXTERNAL_URL = "com.github.dfa.diaspora_android.MainActivity.open_external_url";
|
||||
public static final String ACTION_CHANGE_ACCOUNT = "com.github.dfa.diaspora_android.MainActivity.change_account";
|
||||
public static final String ACTION_CLEAR_CACHE = "com.github.dfa.diaspora_android.MainActivity.clear_cache";
|
||||
public static final String ACTION_UPDATE_TITLE_FROM_URL = "com.github.dfa.diaspora_android.MainActivity.set_title";
|
||||
|
@ -123,6 +127,7 @@ public class MainActivity extends AppCompatActivity
|
|||
private ValueCallback<Uri[]> imageUploadFilePathCallbackNew;
|
||||
private ValueCallback<Uri> imageUploadFilePathCallbackOld;
|
||||
private String mCameraPhotoPath;
|
||||
private CustomTabActivityHelper customTabActivityHelper;
|
||||
private WebSettings webSettings;
|
||||
private AppSettings appSettings;
|
||||
private DiasporaUrlHelper urls;
|
||||
|
@ -186,6 +191,7 @@ public class MainActivity extends AppCompatActivity
|
|||
podUserProfile.setCallbackHandler(uiHandler);
|
||||
podUserProfile.setListener(this);
|
||||
urls = new DiasporaUrlHelper(appSettings);
|
||||
customTabActivityHelper = new CustomTabActivityHelper();
|
||||
|
||||
if (appSettings.isProxyEnabled()) {
|
||||
if (!setProxy(appSettings.getProxyHost(), appSettings.getProxyPort())) {
|
||||
|
@ -203,7 +209,7 @@ public class MainActivity extends AppCompatActivity
|
|||
Log.i(App.TAG, "MainActivity.setupUI()");
|
||||
boolean newWebView = (webView == null);
|
||||
if(newWebView) {
|
||||
Log.v(App.TAG, "Webview was null. Create new one.");
|
||||
Log.v(App.TAG, "WebView was null. Create new one.");
|
||||
View webviewHolder = getLayoutInflater().inflate(R.layout.webview, this.contentLayout, false);
|
||||
webView = (ContextMenuWebView) webviewHolder.findViewById(R.id.webView);
|
||||
((LinearLayout)webView.getParent()).removeView(webView);
|
||||
|
@ -727,11 +733,40 @@ public class MainActivity extends AppCompatActivity
|
|||
}
|
||||
};
|
||||
|
||||
private final BroadcastReceiver brOpenExternalLink = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String url = intent.getStringExtra(EXTRA_URL);
|
||||
if(url != null) {
|
||||
CustomTabsIntent.Builder intentBuilder = new CustomTabsIntent.Builder();
|
||||
if(Build.VERSION.SDK_INT >= 23) {
|
||||
intentBuilder.setToolbarColor(getResources().getColor(R.color.colorPrimary, getTheme()));
|
||||
} else {
|
||||
intentBuilder.setToolbarColor(getResources().getColor(R.color.colorPrimary));
|
||||
}
|
||||
CustomTabActivityHelper.openCustomTab(MainActivity.this, intentBuilder.build(), Uri.parse(url), new BrowserFallback());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
customTabActivityHelper.bindCustomTabsService(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
customTabActivityHelper.unbindCustomTabsService(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
Log.v(App.TAG, "MainActivity.onPause()");
|
||||
Log.v(App.TAG, "Unregister BroadcastReceivers");
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(brSetTitle);
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(brOpenExternalLink);
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
|
@ -741,6 +776,7 @@ public class MainActivity extends AppCompatActivity
|
|||
super.onResume();
|
||||
Log.v(App.TAG, "Register BroadcastReceivers");
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(brSetTitle, new IntentFilter(ACTION_UPDATE_TITLE_FROM_URL));
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(brOpenExternalLink, new IntentFilter(ACTION_OPEN_EXTERNAL_URL));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -20,11 +20,13 @@ package com.github.dfa.diaspora_android.ui;
|
|||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.webkit.CookieManager;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
|
||||
import com.github.dfa.diaspora_android.App;
|
||||
import com.github.dfa.diaspora_android.activity.MainActivity;
|
||||
|
||||
public class CustomWebViewClient extends WebViewClient {
|
||||
private final App app;
|
||||
|
@ -37,9 +39,9 @@ public class CustomWebViewClient extends WebViewClient {
|
|||
|
||||
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
||||
if (!url.contains(app.getSettings().getPodDomain())) {
|
||||
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
app.getApplicationContext().startActivity(i);
|
||||
Intent i = new Intent(MainActivity.ACTION_OPEN_EXTERNAL_URL);
|
||||
i.putExtra(MainActivity.EXTRA_URL, url);
|
||||
LocalBroadcastManager.getInstance(app.getApplicationContext()).sendBroadcast(i);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
package com.github.dfa.diaspora_android.util.CustomTabHelpers;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
|
||||
/**
|
||||
* Adapted from https://medium.com/ribot-labs/exploring-chrome-customs-tabs-on-android-ef427effe2f4
|
||||
*/
|
||||
|
||||
public class BrowserFallback implements CustomTabActivityHelper.CustomTabFallback {
|
||||
@Override
|
||||
public void openUri(Activity activity, Uri uri) {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setData(uri);
|
||||
activity.startActivity(intent);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
package com.github.dfa.diaspora_android.util.CustomTabHelpers;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ComponentName;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.customtabs.CustomTabsClient;
|
||||
import android.support.customtabs.CustomTabsIntent;
|
||||
import android.support.customtabs.CustomTabsServiceConnection;
|
||||
import android.support.customtabs.CustomTabsSession;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Adapted from https://medium.com/ribot-labs/exploring-chrome-customs-tabs-on-android-ef427effe2f4
|
||||
*/
|
||||
|
||||
public class CustomTabActivityHelper {
|
||||
private CustomTabsSession mCustomTabsSession;
|
||||
private CustomTabsClient mClient;
|
||||
private CustomTabsServiceConnection mConnection;
|
||||
private ConnectionCallback mConnectionCallback;
|
||||
|
||||
/**
|
||||
* Opens the URL on a Custom Tab if possible. Otherwise fallsback to opening it on a WebView
|
||||
*
|
||||
* @param activity The host activity
|
||||
* @param customTabsIntent a CustomTabsIntent to be used if Custom Tabs is available
|
||||
* @param uri the Uri to be opened
|
||||
* @param fallback a CustomTabFallback to be used if Custom Tabs is not available
|
||||
*/
|
||||
public static void openCustomTab(Activity activity,
|
||||
CustomTabsIntent customTabsIntent,
|
||||
Uri uri,
|
||||
CustomTabFallback fallback) {
|
||||
String packageName = CustomTabsHelper.getPackageNameToUse(activity);
|
||||
|
||||
//If we cant find a package name, it means there's no browser that supports
|
||||
//Chrome Custom Tabs installed. So, we fallback to the webview
|
||||
if (packageName == null) {
|
||||
if (fallback != null) {
|
||||
fallback.openUri(activity, uri);
|
||||
}
|
||||
} else {
|
||||
customTabsIntent.intent.setPackage(packageName);
|
||||
customTabsIntent.launchUrl(activity, uri);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unbinds the Activity from the Custom Tabs Service
|
||||
* @param activity the activity that is connected to the service
|
||||
*/
|
||||
public void unbindCustomTabsService(Activity activity) {
|
||||
if (mConnection == null) return;
|
||||
activity.unbindService(mConnection);
|
||||
mClient = null;
|
||||
mCustomTabsSession = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates or retrieves an exiting CustomTabsSession
|
||||
*
|
||||
* @return a CustomTabsSession
|
||||
*/
|
||||
public CustomTabsSession getSession() {
|
||||
if (mClient == null) {
|
||||
mCustomTabsSession = null;
|
||||
} else if (mCustomTabsSession == null) {
|
||||
mCustomTabsSession = mClient.newSession(null);
|
||||
}
|
||||
return mCustomTabsSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a Callback to be called when connected or disconnected from the Custom Tabs Service
|
||||
* @param connectionCallback
|
||||
*/
|
||||
public void setConnectionCallback(ConnectionCallback connectionCallback) {
|
||||
this.mConnectionCallback = connectionCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the Activity to the Custom Tabs Service
|
||||
* @param activity the activity to be binded to the service
|
||||
*/
|
||||
public void bindCustomTabsService(Activity activity) {
|
||||
if (mClient != null) return;
|
||||
|
||||
String packageName = CustomTabsHelper.getPackageNameToUse(activity);
|
||||
if (packageName == null) return;
|
||||
mConnection = new CustomTabsServiceConnection() {
|
||||
@Override
|
||||
public void onCustomTabsServiceConnected(ComponentName name, CustomTabsClient client) {
|
||||
mClient = client;
|
||||
mClient.warmup(0L);
|
||||
if (mConnectionCallback != null) mConnectionCallback.onCustomTabsConnected();
|
||||
//Initialize a session as soon as possible.
|
||||
getSession();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
mClient = null;
|
||||
if (mConnectionCallback != null) mConnectionCallback.onCustomTabsDisconnected();
|
||||
}
|
||||
};
|
||||
CustomTabsClient.bindCustomTabsService(activity, packageName, mConnection);
|
||||
}
|
||||
|
||||
public boolean mayLaunchUrl(Uri uri, Bundle extras, List<Bundle> otherLikelyBundles) {
|
||||
if (mClient == null) return false;
|
||||
|
||||
CustomTabsSession session = getSession();
|
||||
if (session == null) return false;
|
||||
|
||||
return session.mayLaunchUrl(uri, extras, otherLikelyBundles);
|
||||
}
|
||||
|
||||
/**
|
||||
* A Callback for when the service is connected or disconnected. Use those callbacks to
|
||||
* handle UI changes when the service is connected or disconnected
|
||||
*/
|
||||
public interface ConnectionCallback {
|
||||
/**
|
||||
* Called when the service is connected
|
||||
*/
|
||||
void onCustomTabsConnected();
|
||||
|
||||
/**
|
||||
* Called when the service is disconnected
|
||||
*/
|
||||
void onCustomTabsDisconnected();
|
||||
}
|
||||
|
||||
/**
|
||||
* To be used as a fallback to open the Uri when Custom Tabs is not available
|
||||
*/
|
||||
public interface CustomTabFallback {
|
||||
/**
|
||||
*
|
||||
* @param activity The Activity that wants to open the Uri
|
||||
* @param uri The uri to be opened by the fallback
|
||||
*/
|
||||
void openUri(Activity activity, Uri uri);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
package com.github.dfa.diaspora_android.util.CustomTabHelpers;
|
||||
|
||||
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.support.customtabs.CustomTabsService;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Helper class for Custom Tabs. Adapted from https://medium.com/ribot-labs/exploring-chrome-customs-tabs-on-android-ef427effe2f4
|
||||
*/
|
||||
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 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(CustomTabsService.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};
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue