Permalink
Browse files

Fix 6667238: allow market apps to support ACTION_ASSIST

This change allows market apps and 3rd parties to supply an activity
that responds to ACTION_ASSIST (e.g. market apps).

It also adds a test app to respond to the ASSIST intent and force
the intent disambiguation dialog to appear.

Change-Id: I5a78863c6a9546d18c66275187d178f6a1c9ee17
  • Loading branch information...
1 parent c258546 commit 45308b1b3b1582d048845df2ee5301241e52a5cf Jim Miller committed Jun 19, 2012
@@ -840,29 +840,17 @@ public Cursor getSuggestions(SearchableInfo searchable, String query, int limit)
}
/**
- * Returns true if the global assist activity is available.
- * @return True if the assistant is available.
- *
- * @hide
- */
- public final boolean isAssistantAvailable() {
- Intent intent = getAssistIntent();
- return intent != null
- && mContext.getPackageManager().queryIntentActivities(intent,
- PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
- }
-
- /**
- * Gets an intent to launch the global assist activity, or null if not available.
+ * Gets an intent for launching installed assistant activity, or null if not available.
* @return The assist intent.
*
* @hide
*/
- public final Intent getAssistIntent() {
- ComponentName globalSearchActivity = getGlobalSearchActivity();
- if (globalSearchActivity != null) {
- Intent intent = new Intent(Intent.ACTION_ASSIST);
- intent.setPackage(globalSearchActivity.getPackageName());
+ public static final Intent getAssistIntent(Context context) {
+ PackageManager pm = context.getPackageManager();
+ Intent intent = new Intent(Intent.ACTION_ASSIST);
+ ComponentName component = intent.resolveActivity(pm);
+ if (component != null) {
+ intent.setComponent(component);
return intent;
}
return null;
@@ -29,7 +29,6 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
-import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Vibrator;
@@ -1209,25 +1208,32 @@ public boolean replaceTargetDrawablesIfPresent(ComponentName component, String n
int existingResId) {
if (existingResId == 0) return false;
- try {
- PackageManager packageManager = mContext.getPackageManager();
- // Look for the search icon specified in the activity meta-data
- Bundle metaData = packageManager.getActivityInfo(
- component, PackageManager.GET_META_DATA).metaData;
- if (metaData != null) {
- int iconResId = metaData.getInt(name);
- if (iconResId != 0) {
- Resources res = packageManager.getResourcesForActivity(component);
- return replaceTargetDrawables(res, existingResId, iconResId);
+ boolean replaced = false;
+ if (component != null) {
+ try {
+ PackageManager packageManager = mContext.getPackageManager();
+ // Look for the search icon specified in the activity meta-data
+ Bundle metaData = packageManager.getActivityInfo(
+ component, PackageManager.GET_META_DATA).metaData;
+ if (metaData != null) {
+ int iconResId = metaData.getInt(name);
+ if (iconResId != 0) {
+ Resources res = packageManager.getResourcesForActivity(component);
+ replaced = replaceTargetDrawables(res, existingResId, iconResId);
+ }
}
+ } catch (NameNotFoundException e) {
+ Log.w(TAG, "Failed to swap drawable; "
+ + component.flattenToShortString() + " not found", e);
+ } catch (Resources.NotFoundException nfe) {
+ Log.w(TAG, "Failed to swap drawable from "
+ + component.flattenToShortString(), nfe);
}
- } catch (NameNotFoundException e) {
- Log.w(TAG, "Failed to swap drawable; "
- + component.flattenToShortString() + " not found", e);
- } catch (Resources.NotFoundException nfe) {
- Log.w(TAG, "Failed to swap drawable from "
- + component.flattenToShortString(), nfe);
}
- return false;
+ if (!replaced) {
+ // Restore the original drawable
+ replaceTargetDrawables(mContext.getResources(), existingResId, existingResId);
+ }
+ return replaced;
}
}
@@ -53,7 +53,6 @@
private static final String ASSIST_ICON_METADATA_NAME =
"com.android.systemui.action_assist_icon";
private final Context mContext;
- private final SearchManager mSearchManager;
private BaseStatusBar mBar;
private StatusBarTouchProxy mStatusBarTouchProxy;
@@ -68,25 +67,13 @@ public SearchPanelView(Context context, AttributeSet attrs) {
public SearchPanelView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mContext = context;
- mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
- if (mSearchManager == null) {
- Slog.w(TAG, "Search manager not available");
- }
- }
-
- public boolean isAssistantAvailable() {
- return mSearchManager != null && mSearchManager.isAssistantAvailable();
- }
-
- private Intent getAssistIntent() {
- return mSearchManager != null ? mSearchManager.getAssistIntent() : null;
}
private void startAssistActivity() {
// Close Recent Apps if needed
mBar.animateCollapse(CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL);
// Launch Assist
- Intent intent = getAssistIntent();
+ Intent intent = SearchManager.getAssistIntent(mContext);
if (intent == null) return;
try {
ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
@@ -150,19 +137,17 @@ protected void onFinishInflate() {
// TODO: fetch views
mGlowPadView = (GlowPadView) findViewById(R.id.glow_pad_view);
mGlowPadView.setOnTriggerListener(mGlowPadViewListener);
- if (mSearchManager != null) {
- ComponentName component = mSearchManager.getGlobalSearchActivity();
- if (component != null) {
- if (!mGlowPadView.replaceTargetDrawablesIfPresent(component,
- ASSIST_ICON_METADATA_NAME,
- com.android.internal.R.drawable.ic_action_assist_generic)) {
- Slog.w(TAG, "Couldn't grab icon from component " + component);
- }
- } else {
- Slog.w(TAG, "No search icon specified in component " + component);
+ }
+
+ private void maybeSwapSearchIcon() {
+ Intent intent = SearchManager.getAssistIntent(mContext);
+ if (intent != null) {
+ ComponentName component = intent.getComponent();
+ if (component == null || !mGlowPadView.replaceTargetDrawablesIfPresent(component,
+ ASSIST_ICON_METADATA_NAME,
+ com.android.internal.R.drawable.ic_action_assist_generic)) {
+ if (DEBUG) Slog.v(TAG, "Couldn't grab icon for component " + component);
}
- } else {
- Slog.w(TAG, "No SearchManager");
}
}
@@ -210,6 +195,7 @@ public void show(final boolean show, boolean animate) {
}
mShowing = show;
if (show) {
+ maybeSwapSearchIcon();
if (getVisibility() != View.VISIBLE) {
setVisibility(View.VISIBLE);
// Don't start the animation until we've created the layer, which is done
@@ -289,4 +275,8 @@ private LayoutTransition createLayoutTransitioner() {
transitioner.setAnimator(LayoutTransition.DISAPPEARING, null);
return transitioner;
}
+
+ public boolean isAssistantAvailable() {
+ return SearchManager.getAssistIntent(mContext) != null;
+ }
}
@@ -83,7 +83,6 @@
private View mUnlockWidget;
private boolean mCameraDisabled;
private boolean mSearchDisabled;
- private SearchManager mSearchManager;
// Is there a vibrator
private final boolean mHasVibrator;
@@ -253,23 +252,6 @@ public void cleanUp() {
}
}
- private boolean isAssistantAvailable() {
- SearchManager searchManager = getSearchManager();
- return searchManager != null && searchManager.isAssistantAvailable();
- }
-
- private Intent getAssistIntent() {
- SearchManager searchManager = getSearchManager();
- return searchManager != null ? searchManager.getAssistIntent() : null;
- }
-
- private SearchManager getSearchManager() {
- if (mSearchManager == null) {
- mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
- }
- return mSearchManager;
- }
-
class GlowPadViewMethods implements GlowPadView.OnTriggerListener,
UnlockWidgetCommonMethods {
private final GlowPadView mGlowPadView;
@@ -297,27 +279,21 @@ public void updateResources() {
// Update the search icon with drawable from the search .apk
if (!mSearchDisabled) {
- SearchManager searchManager = getSearchManager();
- if (searchManager != null) {
- ComponentName component = searchManager.getGlobalSearchActivity();
- if (component != null) {
- // XXX Hack. We need to substitute the icon here but haven't formalized
- // the public API. The "_google" metadata will be going away, so
- // DON'T USE IT!
- boolean replaced = mGlowPadView.replaceTargetDrawablesIfPresent(component,
- ASSIST_ICON_METADATA_NAME + "_google",
- com.android.internal.R.drawable.ic_action_assist_generic);
-
- if (!replaced && !mGlowPadView.replaceTargetDrawablesIfPresent(component,
- ASSIST_ICON_METADATA_NAME,
- com.android.internal.R.drawable.ic_action_assist_generic)) {
- Slog.w(TAG, "Couldn't grab icon from package " + component);
- }
- } else {
- Slog.w(TAG, "No search icon specified in package " + component);
+ Intent intent = SearchManager.getAssistIntent(mContext);
+ if (intent != null) {
+ // XXX Hack. We need to substitute the icon here but haven't formalized
+ // the public API. The "_google" metadata will be going away, so
+ // DON'T USE IT!
+ ComponentName component = intent.getComponent();
+ boolean replaced = mGlowPadView.replaceTargetDrawablesIfPresent(component,
+ ASSIST_ICON_METADATA_NAME + "_google",
+ com.android.internal.R.drawable.ic_action_assist_generic);
+
+ if (!replaced && !mGlowPadView.replaceTargetDrawablesIfPresent(component,
+ ASSIST_ICON_METADATA_NAME,
+ com.android.internal.R.drawable.ic_action_assist_generic)) {
+ Slog.w(TAG, "Couldn't grab icon from package " + component);
}
- } else {
- Slog.w(TAG, "No SearchManager");
}
}
@@ -337,7 +313,7 @@ public void onTrigger(View v, int target) {
final int resId = mGlowPadView.getResourceIdForTarget(target);
switch (resId) {
case com.android.internal.R.drawable.ic_action_assist_generic:
- Intent assistIntent = getAssistIntent();
+ Intent assistIntent = SearchManager.getAssistIntent(mContext);
if (assistIntent != null) {
launchActivity(assistIntent);
} else {
@@ -550,7 +526,7 @@ private void updateTargets() {
} else if (disabledBySimState) {
Log.v(TAG, "Camera disabled by Sim State");
}
- boolean searchActionAvailable = isAssistantAvailable();
+ boolean searchActionAvailable = SearchManager.getAssistIntent(mContext) != null;
mCameraDisabled = disabledByAdmin || disabledBySimState || !cameraTargetPresent;
mSearchDisabled = disabledBySimState || !searchActionAvailable || !searchTargetPresent;
mUnlockWidgetMethods.updateResources();
@@ -2081,6 +2081,8 @@ private void launchAssistLongPressAction() {
Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
+ // TODO: This only stops the factory-installed search manager.
+ // Need to formalize an API to handle others
SearchManager searchManager = getSearchManager();
if (searchManager != null) {
searchManager.stopSearch();
@@ -2093,19 +2095,15 @@ private void launchAssistLongPressAction() {
private void launchAssistAction() {
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_ASSIST);
-
- SearchManager searchManager = getSearchManager();
- if (searchManager != null) {
- Intent intent = searchManager.getAssistIntent();
- if (intent != null) {
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_SINGLE_TOP
- | Intent.FLAG_ACTIVITY_CLEAR_TOP);
- try {
- mContext.startActivity(intent);
- } catch (ActivityNotFoundException e) {
- Slog.w(TAG, "No activity to handle assist action.", e);
- }
+ Intent intent = SearchManager.getAssistIntent(mContext);
+ if (intent != null) {
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_SINGLE_TOP
+ | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ try {
+ mContext.startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Slog.w(TAG, "No activity to handle assist action.", e);
}
}
}
View
@@ -0,0 +1,11 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := Assistant
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.google.android.test.assistant">
+
+ <application android:label="@string/activity_title">
+
+ <activity android:name=".AssistActivity"
+ android:theme="@android:style/Theme.NoTitleBar">
+
+ <!-- Handle assist intent -->
+ <intent-filter>
+ <action android:name="android.intent.action.ASSIST" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+
+ <!-- Provide icon for search -->
+ <meta-data android:name="com.android.systemui.action_assist_icon"
+ android:resource="@drawable/ic_action_assist" />
+
+ </activity>
+
+ </application>
+
+</manifest>
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item
+ android:state_enabled="true"
+ android:state_active="false"
+ android:state_focused="false"
+ android:drawable="@drawable/ic_action_assist_normal" />
+
+ <item
+ android:state_enabled="true"
+ android:state_active="true"
+ android:state_focused="false"
+ android:drawable="@drawable/ic_action_assist_activated" />
+
+ <item
+ android:state_enabled="true"
+ android:state_active="false"
+ android:state_focused="true"
+ android:drawable="@drawable/ic_action_assist_activated" />
+
+</selector>
Oops, something went wrong.

0 comments on commit 45308b1

Please sign in to comment.