summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDaniel Sandler <dsandler@android.com>2010-04-27 16:57:25 -0400
committerDaniel Sandler <dsandler@android.com>2010-04-28 15:52:54 -0400
commitab1ebd7e6f10a352867d4e38ce6421a38b0f50d2 (patch)
treee57bc40cf7c3389fe81fdd1b940f31ab08ad8f43 /src
parent6ad7942740b95adfac0e274c3bdbf54925403dd7 (diff)
downloadandroid_packages_apps_Trebuchet-ab1ebd7e6f10a352867d4e38ce6421a38b0f50d2.tar.gz
android_packages_apps_Trebuchet-ab1ebd7e6f10a352867d4e38ce6421a38b0f50d2.tar.bz2
android_packages_apps_Trebuchet-ab1ebd7e6f10a352867d4e38ce6421a38b0f50d2.zip
Hotseats: better strategy for finding the default browser.
To do this, we invoke resolveActivity to see what activity would result from viewing an arbitrary (but valid) URL. If there's just one installed, or there are multiple and the user has chosen a default handler for http:, we take that component and launch it with CATEGORY_HOME (so as not to upset the URL in the frontmost window/tab/what-have-you). We also use this information to extract the localized name of the app, which is then installed into the hotseat as the contentDescription (for accessibility). If there's no default and multiple options are availble, we'll get the activity chooser instead. In this case, we just fire off that chooser and let the user pick an app (possibly setting a default along the way). Because the default may change, we reload all this hotseat information every time one of the hotseats is tapped. Another side-effect of this approach is that until there exists a default browser, the original URL will be sent to the activity the user chooses from the ResolveActivity. So we need a sensible default URL here; one can be found in R.string.default_browser_url (similar to Browser's R.string.homepage_base). This change also moves the hotseat intents and icons into arrays.xml for easier configuration. Change-Id: I06268df8b59e0f41f1f8b0e47f823db4c44ec761
Diffstat (limited to 'src')
-rw-r--r--src/com/android/launcher2/Launcher.java170
1 files changed, 142 insertions, 28 deletions
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index 5a2a7d37e..132f0e907 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -35,8 +35,10 @@ import android.content.Intent.ShortcutIconResource;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.graphics.Rect;
@@ -74,6 +76,7 @@ import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import java.util.ArrayList;
+import java.util.List;
import java.util.HashMap;
import java.io.DataOutputStream;
import java.io.FileNotFoundException;
@@ -203,13 +206,10 @@ public final class Launcher extends Activity
// Hotseats (quick-launch icons next to AllApps)
// TODO: move these intial intents out to Uris in an XML resource
private static final int NUM_HOTSEATS = 2;
- private Intent[] mHotseats = new Intent[] {
- new Intent(Intent.ACTION_MAIN)
- .setComponent(ComponentName.unflattenFromString(
- "com.android.contacts/.ContactsLaunchActivity")),
- new Intent(Intent.ACTION_WEB_SEARCH, Uri.EMPTY),
- };
- private CharSequence[] mHotseatLabels = new CharSequence[2];
+ private String[] mHotseatConfig = null;
+ private Intent[] mHotseats = null;
+ private Drawable[] mHotseatIcons = null;
+ private CharSequence[] mHotseatLabels = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -368,37 +368,144 @@ public final class Launcher extends Activity
wpm.suggestDesiredDimensions(width * WALLPAPER_SCREENS_SPAN, height);
}
+ // Note: This doesn't do all the client-id magic that BrowserProvider does
+ // in Browser. (http://b/2425179)
+ private Uri getDefaultBrowserUri() {
+ String url = getString(R.string.default_browser_url);
+ if (url.indexOf("{CID}") != -1) {
+ url = url.replace("{CID}", "android-google");
+ }
+ return Uri.parse(url);
+ }
+
+ // Load the Intent templates from arrays.xml to populate the hotseats. For
+ // each Intent, if it resolves to a single app, use that as the launch
+ // intent & use that app's label as the contentDescription. Otherwise,
+ // retain the ResolveActivity so the user can pick an app.
private void loadHotseats() {
+ if (mHotseatConfig == null) {
+ mHotseatConfig = getResources().getStringArray(R.array.hotseats);
+ if (mHotseatConfig.length > 0) {
+ mHotseats = new Intent[mHotseatConfig.length];
+ mHotseatLabels = new CharSequence[mHotseatConfig.length];
+ mHotseatIcons = new Drawable[mHotseatConfig.length];
+ } else {
+ mHotseats = null;
+ mHotseatIcons = null;
+ mHotseatLabels = null;
+ }
+
+ TypedArray hotseatIconDrawables = getResources().obtainTypedArray(R.array.hotseat_icons);
+ for (int i=0; i<mHotseatConfig.length; i++) {
+ // load icon for this slot; currently unrelated to the actual activity
+ try {
+ mHotseatIcons[i] = hotseatIconDrawables.getDrawable(i);
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ Log.w(TAG, "Missing hotseat_icons array item #" + i);
+ mHotseatIcons[i] = null;
+ }
+ }
+ hotseatIconDrawables.recycle();
+ }
+
PackageManager pm = getPackageManager();
- for (int i=0; i<mHotseats.length; i++) {
- Intent intent = mHotseats[i];
+ for (int i=0; i<mHotseatConfig.length; i++) {
+ Intent intent = null;
+ if (mHotseatConfig[i].equals("*BROWSER*")) {
+ // magic value meaning "launch user's default web browser"
+ // replace it with a generic web request so we can see if there is indeed a default
+ String defaultUri = getString(R.string.default_browser_url);
+ intent = new Intent(
+ Intent.ACTION_VIEW,
+ ((defaultUri != null)
+ ? Uri.parse(defaultUri)
+ : getDefaultBrowserUri())
+ ).addCategory(Intent.CATEGORY_BROWSABLE);
+ // note: if the user launches this without a default set, she
+ // will always be taken to the default URL above; this is
+ // unavoidable as we must specify a valid URL in order for the
+ // chooser to appear, and once the user selects something, that
+ // URL is unavoidably sent to the chosen app.
+ } else {
+ try {
+ intent = Intent.parseUri(mHotseatConfig[i], 0);
+ } catch (java.net.URISyntaxException ex) {
+ Log.w(TAG, "Invalid hotseat intent: " + mHotseatConfig[i]);
+ // bogus; leave intent=null
+ }
+ }
+
+ if (intent == null) {
+ mHotseats[i] = null;
+ mHotseatLabels[i] = getText(R.string.activity_not_found);
+ continue;
+ }
if (LOGD) {
Log.d(TAG, "loadHotseats: hotseat " + i
- + " initial intent=[" + intent.toUri(Intent.URI_INTENT_SCHEME)
+ + " initial intent=["
+ + intent.toUri(Intent.URI_INTENT_SCHEME)
+ "]");
}
- // fix up the default intents
- if (intent.getAction().equals(Intent.ACTION_WEB_SEARCH)
- && intent.getData().equals(Uri.EMPTY)) {
- // use this to represent "default web browser"
- intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.google.com/"));
+ ResolveInfo bestMatch = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+ List<ResolveInfo> allMatches = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
+ if (LOGD) {
+ Log.d(TAG, "Best match for intent: " + bestMatch);
+ Log.d(TAG, "All matches: ");
+ for (ResolveInfo ri : allMatches) {
+ Log.d(TAG, " --> " + ri);
+ }
}
- ComponentName com = intent.resolveActivity(pm);
- mHotseats[i] = new Intent(Intent.ACTION_MAIN).setComponent(com);
-
- // load the labels for accessibility
- try {
- ActivityInfo ai = pm.getActivityInfo(com, 0);
- mHotseatLabels[i] = ai.loadLabel(pm);
- } catch (PackageManager.NameNotFoundException ex) {
- mHotseatLabels[i] = "";
+ // did this resolve to a single app, or the resolver?
+ if (allMatches.size() == 0 || bestMatch == null) {
+ // can't find any activity to handle this. let's leave the
+ // intent as-is and let Launcher show a toast when it fails
+ // to launch.
+ mHotseats[i] = intent;
+
+ // set accessibility text to "Not installed"
+ mHotseatLabels[i] = getText(R.string.activity_not_found);
+ } else {
+ boolean found = false;
+ for (ResolveInfo ri : allMatches) {
+ if (bestMatch.activityInfo.name.equals(ri.activityInfo.name)
+ && bestMatch.activityInfo.applicationInfo.packageName
+ .equals(ri.activityInfo.applicationInfo.packageName)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ if (LOGD) Log.d(TAG, "Multiple options, no default yet");
+ // the bestMatch is probably the ResolveActivity, meaning the
+ // user has not yet selected a default
+ // so: we'll keep the original intent for now
+ mHotseats[i] = intent;
+
+ // set the accessibility text to "Select shortcut"
+ mHotseatLabels[i] = getText(R.string.title_select_shortcut);
+ } else {
+ // we have an app!
+ // now reconstruct the intent to launch it through the front
+ // door
+ ComponentName com = new ComponentName(
+ bestMatch.activityInfo.applicationInfo.packageName,
+ bestMatch.activityInfo.name);
+ mHotseats[i] = new Intent(Intent.ACTION_MAIN).setComponent(com);
+
+ // load the app label for accessibility
+ mHotseatLabels[i] = bestMatch.activityInfo.loadLabel(pm);
+ }
}
if (LOGD) {
Log.d(TAG, "loadHotseats: hotseat " + i
- + " intent=[" + mHotseats[i].toUri(Intent.URI_INTENT_SCHEME)
+ + " final intent=["
+ + ((mHotseats[i] == null)
+ ? "null"
+ : mHotseats[i].toUri(Intent.URI_INTENT_SCHEME))
+ "] label=[" + mHotseatLabels[i]
+ "]"
);
@@ -622,8 +729,12 @@ public final class Launcher extends Activity
mHandleView.setOnClickListener(this);
mHandleView.setOnLongClickListener(this);
- findViewById(R.id.hotseat_left).setContentDescription(mHotseatLabels[0]);
- findViewById(R.id.hotseat_right).setContentDescription(mHotseatLabels[1]);
+ ImageView hotseatLeft = (ImageView) findViewById(R.id.hotseat_left);
+ hotseatLeft.setContentDescription(mHotseatLabels[0]);
+ hotseatLeft.setImageDrawable(mHotseatIcons[0]);
+ ImageView hotseatRight = (ImageView) findViewById(R.id.hotseat_right);
+ hotseatRight.setContentDescription(mHotseatLabels[1]);
+ hotseatRight.setImageDrawable(mHotseatIcons[1]);
mPreviousView = (ImageView) dragLayer.findViewById(R.id.previous_screen);
mNextView = (ImageView) dragLayer.findViewById(R.id.next_screen);
@@ -678,7 +789,10 @@ public final class Launcher extends Activity
index = 1;
}
- if (index >= 0 && mHotseats[index] != null) {
+ // reload these every tap; you never know when they might change
+ loadHotseats();
+ if (index >= 0 && index < mHotseats.length && mHotseats[index] != null) {
+ Intent intent = mHotseats[index];
startActivitySafely(
mHotseats[index],
"hotseat"