From 1054d4e8f2c690689ab3289826eebdcd00cb59af Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Mon, 5 Mar 2018 19:39:21 +0000 Subject: [PATCH] Revert "Revert "Adding support for hiding widgets from the widget tray and reconfiguring widgets"" This reverts commit f502e5faecbd460ad3b8258168c5812cbaa34c4e. Reason for revert: Reverting post-build Change-Id: I09eb292dbbbe37ffaf3abc477aa2ddb5700093b8 --- ...ic_info_shadow.xml => ic_setup_shadow.xml} | 2 +- res/drawable/ic_setting.xml | 5 +- res/layout/drop_target_bar.xml | 12 +- res/values/config.xml | 2 +- res/values/drawables.xml | 2 +- .../android/launcher3/ButtonDropTarget.java | 12 +- .../android/launcher3/DeleteDropTarget.java | 8 +- src/com/android/launcher3/InfoDropTarget.java | 120 ------------------ .../LauncherAppWidgetProviderInfo.java | 8 ++ ...opTarget.java => SecondaryDropTarget.java} | 116 ++++++++++++++--- .../LauncherAccessibilityDelegate.java | 11 +- .../launcher3/logging/LoggerUtils.java | 11 +- .../android/launcher3/model/WidgetsModel.java | 7 + .../launcher3/popup/SystemShortcut.java | 4 +- .../launcher3/util/PackageManagerHelper.java | 45 +++++++ tests/AndroidManifest-common.xml | 11 ++ tests/res/xml/appwidget_hidden.xml | 11 ++ tests/res/xml/appwidget_with_config.xml | 1 + .../testcomponent/AppWidgetHidden.java | 23 ++++ 19 files changed, 239 insertions(+), 172 deletions(-) rename res/drawable-v24/{ic_info_shadow.xml => ic_setup_shadow.xml} (94%) delete mode 100644 src/com/android/launcher3/InfoDropTarget.java rename src/com/android/launcher3/{UninstallDropTarget.java => SecondaryDropTarget.java} (61%) create mode 100644 tests/res/xml/appwidget_hidden.xml create mode 100644 tests/src/com/android/launcher3/testcomponent/AppWidgetHidden.java diff --git a/res/drawable-v24/ic_info_shadow.xml b/res/drawable-v24/ic_setup_shadow.xml similarity index 94% rename from res/drawable-v24/ic_info_shadow.xml rename to res/drawable-v24/ic_setup_shadow.xml index 1fe2c46b4b..10aeee6e02 100644 --- a/res/drawable-v24/ic_info_shadow.xml +++ b/res/drawable-v24/ic_setup_shadow.xml @@ -15,5 +15,5 @@ --> diff --git a/res/drawable/ic_setting.xml b/res/drawable/ic_setting.xml index 08eba253dc..33cd6ce34a 100644 --- a/res/drawable/ic_setting.xml +++ b/res/drawable/ic_setting.xml @@ -17,9 +17,10 @@ Copyright (C) 2016 The Android Open Source Project android:width="@dimen/options_menu_icon_size" android:height="@dimen/options_menu_icon_size" android:viewportWidth="48.0" - android:viewportHeight="48.0"> + android:viewportHeight="48.0" + android:tint="?android:attr/textColorPrimary" > - - - - - + diff --git a/res/values/drawables.xml b/res/values/drawables.xml index fea17b1530..1367174b1b 100644 --- a/res/values/drawables.xml +++ b/res/values/drawables.xml @@ -14,7 +14,7 @@ limitations under the License. --> - @drawable/ic_info_no_shadow + @drawable/ic_setting @drawable/ic_remove_no_shadow @drawable/ic_uninstall_no_shadow \ No newline at end of file diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java index 19ee0b8505..c86688020e 100644 --- a/src/com/android/launcher3/ButtonDropTarget.java +++ b/src/com/android/launcher3/ButtonDropTarget.java @@ -108,6 +108,12 @@ public abstract class ButtonDropTarget extends TextView setContentDescription(mText); } + protected void updateText(int resId) { + setText(resId); + mText = getText(); + setContentDescription(mText); + } + protected void setDrawable(int resId) { // We do not set the drawable in the xml as that inflates two drawables corresponding to // drawableLeft and drawableStart. @@ -236,9 +242,7 @@ public abstract class ButtonDropTarget extends TextView protected abstract boolean supportsDrop(ItemInfo info); - public boolean supportsAccessibilityDrop(ItemInfo info) { - return supportsDrop(info); - } + public abstract boolean supportsAccessibilityDrop(ItemInfo info, View view); @Override public boolean isDropEnabled() { @@ -368,4 +372,6 @@ public abstract class ButtonDropTarget extends TextView TextUtils.TruncateAt.END); return !mText.equals(displayedText); } + + public abstract int getControlTypeForLogging(); } diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java index c12ea57c37..28d11291b9 100644 --- a/src/com/android/launcher3/DeleteDropTarget.java +++ b/src/com/android/launcher3/DeleteDropTarget.java @@ -24,6 +24,7 @@ import android.view.View; import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.folder.Folder; +import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType; public class DeleteDropTarget extends ButtonDropTarget { @@ -54,7 +55,7 @@ public class DeleteDropTarget extends ButtonDropTarget { * @return true for items that should have a "Remove" action in accessibility. */ @Override - public boolean supportsAccessibilityDrop(ItemInfo info) { + public boolean supportsAccessibilityDrop(ItemInfo info, View view) { return (info instanceof ShortcutInfo) || (info instanceof LauncherAppWidgetInfo) || (info instanceof FolderInfo); @@ -103,4 +104,9 @@ public class DeleteDropTarget extends ButtonDropTarget { mLauncher.getDragLayer() .announceForAccessibility(getContext().getString(R.string.item_removed)); } + + @Override + public int getControlTypeForLogging() { + return ControlType.REMOVE_TARGET; + } } diff --git a/src/com/android/launcher3/InfoDropTarget.java b/src/com/android/launcher3/InfoDropTarget.java deleted file mode 100644 index e52fd765b9..0000000000 --- a/src/com/android/launcher3/InfoDropTarget.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2011 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. - */ - -package com.android.launcher3; - -import android.content.ActivityNotFoundException; -import android.content.ComponentName; -import android.content.Context; -import android.graphics.Rect; -import android.os.Bundle; -import android.provider.Settings; -import android.util.AttributeSet; -import android.util.Log; -import android.widget.Toast; - -import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; -import com.android.launcher3.compat.LauncherAppsCompat; -import com.android.launcher3.util.Themes; - -public class InfoDropTarget extends UninstallDropTarget { - - private static final String TAG = "InfoDropTarget"; - - public InfoDropTarget(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public InfoDropTarget(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - @Override - protected void setupUi() { - // Get the hover color - mHoverColor = Themes.getColorAccent(getContext()); - setDrawable(R.drawable.ic_info_shadow); - } - - @Override - protected ComponentName performDropAction(ItemInfo item) { - return performDropAction(mLauncher, item, null, null); - } - - /** - * @return Whether the activity was started. - */ - public static boolean startDetailsActivityForInfo( - ItemInfo info, Launcher launcher, Rect sourceBounds, Bundle opts) { - return performDropAction(launcher, info, sourceBounds, opts) != null; - } - - /** - * Performs the drop action and returns the target component for the dragObject or null if - * the action was not performed. - */ - private static ComponentName performDropAction(Context context, ItemInfo info, - Rect sourceBounds, Bundle opts) { - if (info instanceof PromiseAppInfo) { - PromiseAppInfo promiseAppInfo = (PromiseAppInfo) info; - context.startActivity(promiseAppInfo.getMarketIntent(context)); - return null; - } - ComponentName componentName = null; - if (info instanceof AppInfo) { - componentName = ((AppInfo) info).componentName; - } else if (info instanceof ShortcutInfo) { - componentName = info.getTargetComponent(); - } else if (info instanceof PendingAddItemInfo) { - componentName = ((PendingAddItemInfo) info).componentName; - } else if (info instanceof LauncherAppWidgetInfo) { - componentName = ((LauncherAppWidgetInfo) info).providerName; - } - if (componentName != null) { - try { - LauncherAppsCompat.getInstance(context) - .showAppDetailsForProfile(componentName, info.user, sourceBounds, opts); - return componentName; - } catch (SecurityException | ActivityNotFoundException e) { - Toast.makeText(context, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); - Log.e(TAG, "Unable to launch settings", e); - } - } - return null; - } - - @Override - public int getAccessibilityAction() { - return LauncherAccessibilityDelegate.INFO; - } - - @Override - protected boolean supportsDrop(ItemInfo info) { - // Only show the App Info drop target if developer settings are enabled. - boolean developmentSettingsEnabled = Settings.Global.getInt( - getContext().getContentResolver(), - Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) == 1; - if (!developmentSettingsEnabled) { - return false; - } - return info.itemType != LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT && - (info instanceof AppInfo || - (info instanceof ShortcutInfo && !((ShortcutInfo) info).isPromise()) || - (info instanceof LauncherAppWidgetInfo && - ((LauncherAppWidgetInfo) info).restoreStatus == 0) || - info instanceof PendingAddItemInfo); - } -} diff --git a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java index c7139925c8..80758c99b9 100644 --- a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java +++ b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java @@ -94,4 +94,12 @@ public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo { public boolean isCustomWidget() { return provider.getClassName().startsWith(CLS_CUSTOM_WIDGET_PREFIX); } + + public int getWidgetFeatures() { + if (Utilities.ATLEAST_P) { + return widgetFeatures; + } else { + return 0; + } + } } diff --git a/src/com/android/launcher3/UninstallDropTarget.java b/src/com/android/launcher3/SecondaryDropTarget.java similarity index 61% rename from src/com/android/launcher3/UninstallDropTarget.java rename to src/com/android/launcher3/SecondaryDropTarget.java index 68a441ad98..024b4eb593 100644 --- a/src/com/android/launcher3/UninstallDropTarget.java +++ b/src/com/android/launcher3/SecondaryDropTarget.java @@ -1,8 +1,19 @@ package com.android.launcher3; +import static android.appwidget.AppWidgetManager.INVALID_APPWIDGET_ID; +import static android.appwidget.AppWidgetProviderInfo.WIDGET_FEATURE_RECONFIGURABLE; + import static com.android.launcher3.ItemInfoWithIcon.FLAG_SYSTEM_MASK; import static com.android.launcher3.ItemInfoWithIcon.FLAG_SYSTEM_NO; +import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP; +import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.RECONFIGURE; +import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.UNINSTALL; +import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType.SETTINGS_BUTTON; +import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType.UNINSTALL_TARGET; +import android.appwidget.AppWidgetHostView; +import android.appwidget.AppWidgetManager; +import android.appwidget.AppWidgetProviderInfo; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -20,27 +31,33 @@ import android.view.View; import android.widget.Toast; import com.android.launcher3.Launcher.OnResumeCallback; -import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.userevent.nano.LauncherLogProto.Target; +import com.android.launcher3.util.Themes; import java.net.URISyntaxException; -public class UninstallDropTarget extends ButtonDropTarget implements OnAlarmListener { +/** + * Drop target which provides a secondary option for an item. + * For app targets: shows as uninstall + * For configurable widgets: shows as setup + */ +public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmListener { - private static final String TAG = "UninstallDropTarget"; + private static final String TAG = "SecondaryDropTarget"; private static final long CACHE_EXPIRE_TIMEOUT = 5000; private final ArrayMap mUninstallDisabledCache = new ArrayMap<>(1); private final Alarm mCacheExpireAlarm; - public UninstallDropTarget(Context context, AttributeSet attrs) { + private int mCurrentAccessibilityAction = -1; + public SecondaryDropTarget(Context context, AttributeSet attrs) { this(context, attrs, 0); } - public UninstallDropTarget(Context context, AttributeSet attrs, int defStyle) { + public SecondaryDropTarget(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); mCacheExpireAlarm = new Alarm(); @@ -50,13 +67,24 @@ public class UninstallDropTarget extends ButtonDropTarget implements OnAlarmList @Override protected void onFinishInflate() { super.onFinishInflate(); - setupUi(); + setupUi(UNINSTALL); } - protected void setupUi() { - // Get the hover color - mHoverColor = getResources().getColor(R.color.uninstall_target_hover_tint); - setDrawable(R.drawable.ic_uninstall_shadow); + private void setupUi(int action) { + if (action == mCurrentAccessibilityAction) { + return; + } + mCurrentAccessibilityAction = action; + + if (action == UNINSTALL) { + mHoverColor = getResources().getColor(R.color.uninstall_target_hover_tint); + setDrawable(R.drawable.ic_uninstall_shadow); + updateText(R.string.uninstall_drop_target_label); + } else { + mHoverColor = Themes.getColorAccent(getContext()); + setDrawable(R.drawable.ic_setup_shadow); + updateText(R.string.gadget_setup_text); + } } @Override @@ -66,11 +94,30 @@ public class UninstallDropTarget extends ButtonDropTarget implements OnAlarmList @Override public int getAccessibilityAction() { - return LauncherAccessibilityDelegate.UNINSTALL; + return mCurrentAccessibilityAction; + } + + @Override + public int getControlTypeForLogging() { + return mCurrentAccessibilityAction == UNINSTALL ? UNINSTALL_TARGET : SETTINGS_BUTTON; } @Override protected boolean supportsDrop(ItemInfo info) { + return supportsAccessibilityDrop(info, getViewUnderDrag(info)); + } + + @Override + public boolean supportsAccessibilityDrop(ItemInfo info, View view) { + if (view instanceof AppWidgetHostView) { + if (getReconfigurableWidgetId(view) != INVALID_APPWIDGET_ID) { + setupUi(RECONFIGURE); + return true; + } + return false; + } + + setupUi(UNINSTALL); Boolean uninstallDisabled = mUninstallDisabledCache.get(info.user); if (uninstallDisabled == null) { UserManager userManager = @@ -126,7 +173,7 @@ public class UninstallDropTarget extends ButtonDropTarget implements OnAlarmList @Override public void completeDrop(final DragObject d) { - ComponentName target = performDropAction(d.dragInfo); + ComponentName target = performDropAction(getViewUnderDrag(d.dragInfo), d.dragInfo); if (d.dragSource instanceof DeferredOnComplete) { DeferredOnComplete deferred = (DeferredOnComplete) d.dragSource; if (target != null) { @@ -138,11 +185,48 @@ public class UninstallDropTarget extends ButtonDropTarget implements OnAlarmList } } + private View getViewUnderDrag(ItemInfo info) { + if (info instanceof LauncherAppWidgetInfo && info.container == CONTAINER_DESKTOP && + mLauncher.getWorkspace().getDragInfo() != null) { + return mLauncher.getWorkspace().getDragInfo().cell; + } + return null; + } + + /** + * Verifies that the view is an reconfigurable widget and returns the corresponding widget Id, + * otherwise return {@code INVALID_APPWIDGET_ID} + */ + private int getReconfigurableWidgetId(View view) { + if (!(view instanceof AppWidgetHostView)) { + return INVALID_APPWIDGET_ID; + } + AppWidgetHostView hostView = (AppWidgetHostView) view; + AppWidgetProviderInfo widgetInfo = hostView.getAppWidgetInfo(); + if (widgetInfo == null || widgetInfo.configure == null) { + return INVALID_APPWIDGET_ID; + } + if ( (LauncherAppWidgetProviderInfo.fromProviderInfo(getContext(), widgetInfo) + .getWidgetFeatures() & WIDGET_FEATURE_RECONFIGURABLE) == 0) { + return INVALID_APPWIDGET_ID; + } + return hostView.getAppWidgetId(); + } + /** * Performs the drop action and returns the target component for the dragObject or null if * the action was not performed. */ - protected ComponentName performDropAction(ItemInfo info) { + protected ComponentName performDropAction(View view, ItemInfo info) { + if (mCurrentAccessibilityAction == RECONFIGURE) { + int widgetId = getReconfigurableWidgetId(view); + if (widgetId != INVALID_APPWIDGET_ID) { + mLauncher.getAppWidgetHost().startConfigActivity(mLauncher, widgetId, -1); + } + return null; + } + // else: mCurrentAccessibilityAction == UNINSTALL + ComponentName cn = getUninstallTarget(info); if (cn == null) { // System applications cannot be installed. For now, show a toast explaining that. @@ -164,7 +248,7 @@ public class UninstallDropTarget extends ButtonDropTarget implements OnAlarmList @Override public void onAccessibilityDrop(View view, ItemInfo item) { - performDropAction(item); + performDropAction(view, item); } /** @@ -203,7 +287,7 @@ public class UninstallDropTarget extends ButtonDropTarget implements OnAlarmList .getApplicationInfo(mPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, mDragObject.dragInfo.user) == null) { mDragObject.dragSource = mOriginal; - mOriginal.onDropCompleted(UninstallDropTarget.this, mDragObject, true); + mOriginal.onDropCompleted(SecondaryDropTarget.this, mDragObject, true); } else { sendFailure(); } @@ -212,7 +296,7 @@ public class UninstallDropTarget extends ButtonDropTarget implements OnAlarmList public void sendFailure() { mDragObject.dragSource = mOriginal; mDragObject.cancelled = true; - mOriginal.onDropCompleted(UninstallDropTarget.this, mDragObject, false); + mOriginal.onDropCompleted(SecondaryDropTarget.this, mDragObject, false); } } } diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java index 3b6fea9465..2cd8b1d729 100644 --- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java +++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java @@ -47,8 +47,8 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme private static final String TAG = "LauncherAccessibilityDelegate"; public static final int REMOVE = R.id.action_remove; - public static final int INFO = R.id.action_info; public static final int UNINSTALL = R.id.action_uninstall; + public static final int RECONFIGURE = R.id.action_reconfigure; protected static final int ADD_TO_WORKSPACE = R.id.action_add_to_workspace; protected static final int MOVE = R.id.action_move; protected static final int MOVE_TO_WORKSPACE = R.id.action_move_to_workspace; @@ -77,10 +77,10 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme mActions.put(REMOVE, new AccessibilityAction(REMOVE, launcher.getText(R.string.remove_drop_target_label))); - mActions.put(INFO, new AccessibilityAction(INFO, - launcher.getText(R.string.app_info_drop_target_label))); mActions.put(UNINSTALL, new AccessibilityAction(UNINSTALL, launcher.getText(R.string.uninstall_drop_target_label))); + mActions.put(RECONFIGURE, new AccessibilityAction(RECONFIGURE, + launcher.getText(R.string.gadget_setup_text))); mActions.put(ADD_TO_WORKSPACE, new AccessibilityAction(ADD_TO_WORKSPACE, launcher.getText(R.string.action_add_to_workspace))); mActions.put(MOVE, new AccessibilityAction(MOVE, @@ -110,7 +110,7 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme } for (ButtonDropTarget target : mLauncher.getDropTargetBar().getDropTargets()) { - if (target.supportsAccessibilityDrop(item)) { + if (target.supportsAccessibilityDrop(item, host)) { info.addAction(mActions.get(target.getAccessibilityAction())); } } @@ -222,7 +222,8 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme return PopupContainerWithArrow.showForIcon((BubbleTextView) host) != null; } else { for (ButtonDropTarget dropTarget : mLauncher.getDropTargetBar().getDropTargets()) { - if (action == dropTarget.getAccessibilityAction()) { + if (dropTarget.supportsAccessibilityDrop(item, host) && + action == dropTarget.getAccessibilityAction()) { dropTarget.onAccessibilityDrop(host, item); return true; } diff --git a/src/com/android/launcher3/logging/LoggerUtils.java b/src/com/android/launcher3/logging/LoggerUtils.java index c608a233ff..d68ac15966 100644 --- a/src/com/android/launcher3/logging/LoggerUtils.java +++ b/src/com/android/launcher3/logging/LoggerUtils.java @@ -20,11 +20,8 @@ import android.util.SparseArray; import android.view.View; import com.android.launcher3.ButtonDropTarget; -import com.android.launcher3.DeleteDropTarget; -import com.android.launcher3.InfoDropTarget; import com.android.launcher3.ItemInfo; import com.android.launcher3.LauncherSettings; -import com.android.launcher3.UninstallDropTarget; import com.android.launcher3.userevent.nano.LauncherLogExtensions.TargetExtension; import com.android.launcher3.userevent.nano.LauncherLogProto.Action; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; @@ -165,12 +162,8 @@ public class LoggerUtils { return newTarget(Target.Type.CONTAINER); } Target t = newTarget(Target.Type.CONTROL); - if (v instanceof InfoDropTarget) { - t.controlType = ControlType.APPINFO_TARGET; - } else if (v instanceof UninstallDropTarget) { - t.controlType = ControlType.UNINSTALL_TARGET; - } else if (v instanceof DeleteDropTarget) { - t.controlType = ControlType.REMOVE_TARGET; + if (v instanceof ButtonDropTarget) { + t.controlType = ((ButtonDropTarget) v).getControlTypeForLogging(); } return t; } diff --git a/src/com/android/launcher3/model/WidgetsModel.java b/src/com/android/launcher3/model/WidgetsModel.java index 1ff0daca05..9f8f2632eb 100644 --- a/src/com/android/launcher3/model/WidgetsModel.java +++ b/src/com/android/launcher3/model/WidgetsModel.java @@ -1,6 +1,8 @@ package com.android.launcher3.model; +import static android.appwidget.AppWidgetProviderInfo.WIDGET_FEATURE_HIDE_FROM_PICKER; + import android.appwidget.AppWidgetProviderInfo; import android.content.Context; import android.content.pm.PackageManager; @@ -153,6 +155,11 @@ public class WidgetsModel { // add and update. for (WidgetItem item : rawWidgetsShortcuts) { if (item.widgetInfo != null) { + if ((item.widgetInfo.getWidgetFeatures() & WIDGET_FEATURE_HIDE_FROM_PICKER) != 0) { + // Widget is hidden from picker + continue; + } + // Ensure that all widgets we show can be added on a workspace of this size int minSpanX = Math.min(item.widgetInfo.spanX, item.widgetInfo.minSpanX); int minSpanY = Math.min(item.widgetInfo.spanY, item.widgetInfo.minSpanY); diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java index 32fd0633c5..2cc8dfa76b 100644 --- a/src/com/android/launcher3/popup/SystemShortcut.java +++ b/src/com/android/launcher3/popup/SystemShortcut.java @@ -9,7 +9,6 @@ import android.os.Bundle; import android.view.View; import com.android.launcher3.AbstractFloatingView; -import com.android.launcher3.InfoDropTarget; import com.android.launcher3.ItemInfo; import com.android.launcher3.Launcher; import com.android.launcher3.R; @@ -83,7 +82,8 @@ public abstract class SystemShortcut extends ItemInfo { public void onClick(View view) { Rect sourceBounds = launcher.getViewBounds(view); Bundle opts = launcher.getActivityLaunchOptionsAsBundle(view, false); - InfoDropTarget.startDetailsActivityForInfo(itemInfo, launcher, sourceBounds, opts); + new PackageManagerHelper(launcher).startDetailsActivityForInfo( + itemInfo, sourceBounds, opts); launcher.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP, ControlType.APPINFO_TARGET, view); } diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java index 81df153807..0b3b632c02 100644 --- a/src/com/android/launcher3/util/PackageManagerHelper.java +++ b/src/com/android/launcher3/util/PackageManagerHelper.java @@ -17,6 +17,8 @@ package com.android.launcher3.util; import android.app.AppOpsManager; +import android.content.ActivityNotFoundException; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; @@ -24,13 +26,23 @@ import android.content.pm.LauncherActivityInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; +import android.graphics.Rect; import android.net.Uri; import android.os.Build; +import android.os.Bundle; import android.os.UserHandle; import android.text.TextUtils; +import android.util.Log; +import android.widget.Toast; import com.android.launcher3.AppInfo; +import com.android.launcher3.ItemInfo; +import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherAppWidgetInfo; +import com.android.launcher3.PendingAddItemInfo; +import com.android.launcher3.PromiseAppInfo; import com.android.launcher3.R; +import com.android.launcher3.ShortcutInfo; import com.android.launcher3.Utilities; import com.android.launcher3.compat.LauncherAppsCompat; @@ -42,6 +54,8 @@ import java.util.List; */ public class PackageManagerHelper { + private static final String TAG = "PackageManagerHelper"; + private final Context mContext; private final PackageManager mPm; private final LauncherAppsCompat mLauncherApps; @@ -169,4 +183,35 @@ public class PackageManagerHelper { throw new RuntimeException(e); } } + + + /** + * Starts the details activity for {@code info} + */ + public void startDetailsActivityForInfo(ItemInfo info, Rect sourceBounds, Bundle opts) { + if (info instanceof PromiseAppInfo) { + PromiseAppInfo promiseAppInfo = (PromiseAppInfo) info; + mContext.startActivity(promiseAppInfo.getMarketIntent(mContext)); + return; + } + ComponentName componentName = null; + if (info instanceof AppInfo) { + componentName = ((AppInfo) info).componentName; + } else if (info instanceof ShortcutInfo) { + componentName = info.getTargetComponent(); + } else if (info instanceof PendingAddItemInfo) { + componentName = ((PendingAddItemInfo) info).componentName; + } else if (info instanceof LauncherAppWidgetInfo) { + componentName = ((LauncherAppWidgetInfo) info).providerName; + } + if (componentName != null) { + try { + mLauncherApps.showAppDetailsForProfile( + componentName, info.user, sourceBounds, opts); + } catch (SecurityException | ActivityNotFoundException e) { + Toast.makeText(mContext, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); + Log.e(TAG, "Unable to launch settings", e); + } + } + } } diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml index 0a29147729..a54268af0b 100644 --- a/tests/AndroidManifest-common.xml +++ b/tests/AndroidManifest-common.xml @@ -33,6 +33,17 @@ android:resource="@xml/appwidget_no_config" /> + + + + + + + + diff --git a/tests/res/xml/appwidget_hidden.xml b/tests/res/xml/appwidget_hidden.xml new file mode 100644 index 0000000000..6f0e0066fd --- /dev/null +++ b/tests/res/xml/appwidget_hidden.xml @@ -0,0 +1,11 @@ + + + \ No newline at end of file diff --git a/tests/res/xml/appwidget_with_config.xml b/tests/res/xml/appwidget_with_config.xml index 3e96c6f2fb..8403689876 100644 --- a/tests/res/xml/appwidget_with_config.xml +++ b/tests/res/xml/appwidget_with_config.xml @@ -7,5 +7,6 @@ android:initialLayout="@layout/test_layout_appwidget_blue" android:configure="com.android.launcher3.testcomponent.WidgetConfigActivity" android:resizeMode="horizontal|vertical" + android:widgetFeatures="reconfigurable" android:widgetCategory="home_screen"> \ No newline at end of file diff --git a/tests/src/com/android/launcher3/testcomponent/AppWidgetHidden.java b/tests/src/com/android/launcher3/testcomponent/AppWidgetHidden.java new file mode 100644 index 0000000000..83492bfd29 --- /dev/null +++ b/tests/src/com/android/launcher3/testcomponent/AppWidgetHidden.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2018 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. + */ +package com.android.launcher3.testcomponent; + +import android.appwidget.AppWidgetProvider; + +/** + * A simple app widget without any configuration screen and is hidden in picker. + */ +public class AppWidgetHidden extends AppWidgetProvider { }