Adding support for hiding widgets from the widget tray and reconfiguring widgets

> Removing AppInfo target
> Switching between uninstall and setup based on the drag view

Bug: 63931362
Change-Id: Iccd6f965fa3d61992244a365efc242122292c0ca
This commit is contained in:
Sunny Goyal 2018-02-12 14:25:48 -08:00
parent f454ded32c
commit b29a5fa55c
19 changed files with 239 additions and 172 deletions

View File

@ -15,5 +15,5 @@
-->
<com.android.launcher3.graphics.ShadowDrawable
xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/ic_info_no_shadow"
android:src="@drawable/ic_setting"
android:elevation="@dimen/drop_target_shadow_elevation" />

View File

@ -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" >
<path
android:fillColor="?android:attr/textColorPrimary"
android:fillColor="#FFFFFFFF"
android:pathData="M42.8,28.4l-3.88-2.9c0.06-0.5,0.08-1,0.08-1.52s-0.02-1.02-0.08-1.52l3.88-2.86c0.84-0.62,1.04-1.88,
0.48-2.82l-3.2-5.52c-0.56-0.96-1.76-1.4-2.72-1l-4.28,1.82c-0.96-0.74-2.02-1.36-3.14-1.84l-0.54-4.4C29.28,4.8,28.28,4,
27.18,4h-6.36c-1.1,0-2.1,0.8-2.22,1.84l-0.52,4.38c-1.14,0.48-2.2,1.1-3.16,1.84l-4.28-1.82c-0.96-0.4-2.16,0.04-2.72,

View File

@ -32,18 +32,8 @@
android:gravity="center"
android:text="@string/remove_drop_target_label" />
<!-- App Info -->
<com.android.launcher3.InfoDropTarget
android:id="@+id/info_target_text"
style="@style/DropTargetButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="@string/app_info_drop_target_label" />
<!-- Uninstall target -->
<com.android.launcher3.UninstallDropTarget
<com.android.launcher3.SecondaryDropTarget
android:id="@+id/uninstall_target_text"
style="@style/DropTargetButton"
android:layout_width="wrap_content"

View File

@ -127,7 +127,7 @@
<!-- Accessibility actions -->
<item type="id" name="action_remove" />
<item type="id" name="action_uninstall" />
<item type="id" name="action_info" />
<item type="id" name="action_reconfigure" />
<item type="id" name="action_add_to_workspace" />
<item type="id" name="action_move" />
<item type="id" name="action_move_to_workspace" />

View File

@ -14,7 +14,7 @@
limitations under the License.
-->
<resources>
<drawable name="ic_info_shadow">@drawable/ic_info_no_shadow</drawable>
<drawable name="ic_setup_shadow">@drawable/ic_setting</drawable>
<drawable name="ic_remove_shadow">@drawable/ic_remove_no_shadow</drawable>
<drawable name="ic_uninstall_shadow">@drawable/ic_uninstall_no_shadow</drawable>
</resources>

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}
}

View File

@ -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<UserHandle, Boolean> 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
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);
}
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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);
}
}
}
}

View File

@ -33,6 +33,17 @@
android:resource="@xml/appwidget_no_config" />
</receiver>
<receiver
android:name="com.android.launcher3.testcomponent.AppWdigetHidden"
android:label="Hidden widget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/appwidget_hidden" />
</receiver>
<receiver
android:name="com.android.launcher3.testcomponent.AppWidgetWithConfig"
android:label="With Config">

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider
xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="180dp"
android:minHeight="110dp"
android:updatePeriodMillis="86400000"
android:initialLayout="@layout/test_layout_appwidget_blue"
android:resizeMode="horizontal|vertical"
android:widgetFeatures="hide_from_picker"
android:widgetCategory="home_screen">
</appwidget-provider>

View File

@ -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">
</appwidget-provider>

View File

@ -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 { }