AppWidgetManager: direct add widget support.
Test: Manual test and all the unit tests: adb shell am instrument -e class com.android.server.pm.ShortcutManagerTest1 -w com.android.frameworks.servicestests ... to test9 adb shell am instrument -e class com.android.server.appwidget.AppWidgetServiceImplTest -w com.android.frameworks.servicestests Bug 32404406 Change-Id: Icd6d4cbd25d9cdf4508da725d95d6401cc3a46a7
This commit is contained in:
@@ -16,11 +16,15 @@
|
||||
|
||||
package android.appwidget;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.Process;
|
||||
@@ -1079,4 +1083,41 @@ public class AppWidgetManager {
|
||||
info.minResizeHeight = TypedValue.complexToDimensionPixelSize(info.minResizeHeight,
|
||||
mDisplayMetrics);
|
||||
}
|
||||
|
||||
/**
|
||||
* Request to pin an app widget on the current launcher. It's up to the launcher to accept this
|
||||
* request (optionally showing a user confirmation). If the request is accepted, the caller will
|
||||
* get a confirmation with extra {@link #EXTRA_APPWIDGET_ID}.
|
||||
*
|
||||
* <p>When a request is denied by the user, the caller app will not get any response.
|
||||
*
|
||||
* <p>Only apps with a foreground activity or a foreground service can call it. Otherwise
|
||||
* it'll throw {@link IllegalStateException}.
|
||||
*
|
||||
* <p>When an app calls this API when a previous request is still waiting for a response,
|
||||
* the previous request will be canceled.
|
||||
*
|
||||
* @param provider The {@link ComponentName} for the {@link
|
||||
* android.content.BroadcastReceiver BroadcastReceiver} provider for your AppWidget.
|
||||
* @param successCallback If not null, this intent will be sent when the widget is created.
|
||||
*
|
||||
* @return {@code TRUE} if the launcher supports this feature. Note the API will return without
|
||||
* waiting for the user to respond, so getting {@code TRUE} from this API does *not* mean
|
||||
* the shortcut is pinned. {@code FALSE} if the launcher doesn't support this feature.
|
||||
*
|
||||
* @see android.content.pm.ShortcutManager#isRequestPinShortcutSupported()
|
||||
* @see android.content.pm.ShortcutManager#requestPinShortcut(ShortcutInfo, IntentSender)
|
||||
*
|
||||
* @throws IllegalStateException The caller doesn't have a foreground activity or a foreground
|
||||
* service or when the user is locked.
|
||||
*/
|
||||
public boolean requestPinAppWidget(@NonNull ComponentName provider,
|
||||
@Nullable PendingIntent successCallback) {
|
||||
try {
|
||||
return mService.requestPinAppWidget(mPackageName, provider,
|
||||
successCallback == null ? null : successCallback.getIntentSender());
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.annotation.Nullable;
|
||||
import android.annotation.SdkConstant;
|
||||
import android.annotation.SdkConstant.SdkConstantType;
|
||||
import android.annotation.TestApi;
|
||||
import android.appwidget.AppWidgetProviderInfo;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -1138,21 +1139,35 @@ public class LauncherApps {
|
||||
/** This is a request to pin shortcut. */
|
||||
public static final int REQUEST_TYPE_SHORTCUT = 1;
|
||||
|
||||
/** This is a request to pin app widget. */
|
||||
public static final int REQUEST_TYPE_APPWIDGET = 2;
|
||||
|
||||
@IntDef(value = {REQUEST_TYPE_SHORTCUT})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface RequestType {}
|
||||
|
||||
private final int mRequestType;
|
||||
private final ShortcutInfo mShortcutInfo;
|
||||
private final AppWidgetProviderInfo mAppWidgetInfo;
|
||||
private final IPinItemRequest mInner;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public PinItemRequest(@RequestType int requestType, ShortcutInfo shortcutInfo,
|
||||
IPinItemRequest inner) {
|
||||
mRequestType = requestType;
|
||||
public PinItemRequest(ShortcutInfo shortcutInfo, IPinItemRequest inner) {
|
||||
mRequestType = REQUEST_TYPE_SHORTCUT;
|
||||
mShortcutInfo = shortcutInfo;
|
||||
mAppWidgetInfo = null;
|
||||
mInner = inner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public PinItemRequest(AppWidgetProviderInfo appWidgetInfo, IPinItemRequest inner) {
|
||||
mRequestType = REQUEST_TYPE_APPWIDGET;
|
||||
mShortcutInfo = null;
|
||||
mAppWidgetInfo = appWidgetInfo;
|
||||
mInner = inner;
|
||||
}
|
||||
|
||||
@@ -1174,6 +1189,15 @@ public class LauncherApps {
|
||||
return mShortcutInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AppWidgetProviderInfo} sent by the requesting app. Always non-null for a
|
||||
* {@link #REQUEST_TYPE_APPWIDGET} request.
|
||||
*/
|
||||
@Nullable
|
||||
public AppWidgetProviderInfo getAppWidgetProviderInfo() {
|
||||
return mAppWidgetInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@code TRUE} if a request is valid -- i.e. {@link #accept(Bundle)} has not been
|
||||
* called, and it has not been canceled.
|
||||
@@ -1208,14 +1232,22 @@ public class LauncherApps {
|
||||
final ClassLoader cl = getClass().getClassLoader();
|
||||
|
||||
mRequestType = source.readInt();
|
||||
mShortcutInfo = source.readParcelable(cl);
|
||||
mShortcutInfo = mRequestType == REQUEST_TYPE_SHORTCUT ?
|
||||
(ShortcutInfo) source.readParcelable(cl) : null;
|
||||
mAppWidgetInfo = mRequestType == REQUEST_TYPE_APPWIDGET ?
|
||||
(AppWidgetProviderInfo) source.readParcelable(cl) : null;
|
||||
mInner = IPinItemRequest.Stub.asInterface(source.readStrongBinder());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(mRequestType);
|
||||
dest.writeParcelable(mShortcutInfo, flags);
|
||||
if (mRequestType == REQUEST_TYPE_SHORTCUT) {
|
||||
dest.writeParcelable(mShortcutInfo, flags);
|
||||
}
|
||||
if (mRequestType == REQUEST_TYPE_APPWIDGET) {
|
||||
dest.writeParcelable(mAppWidgetInfo, flags);
|
||||
}
|
||||
dest.writeStrongBinder(mInner.asBinder());
|
||||
}
|
||||
|
||||
|
||||
@@ -867,7 +867,7 @@ public class ShortcutManager {
|
||||
*
|
||||
* @throws IllegalArgumentException if a shortcut with the same ID exists and is disabled.
|
||||
* @throws IllegalStateException The caller doesn't have a foreground activity or a foreground
|
||||
* service.
|
||||
* service or when the user is locked.
|
||||
*/
|
||||
public boolean requestPinShortcut(@NonNull ShortcutInfo shortcut,
|
||||
@Nullable IntentSender resultIntent) {
|
||||
|
||||
@@ -19,8 +19,10 @@ package android.content.pm;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.appwidget.AppWidgetProviderInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.content.pm.LauncherApps.ShortcutQuery;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
|
||||
@@ -68,4 +70,8 @@ public abstract class ShortcutServiceInternal {
|
||||
|
||||
public abstract boolean hasShortcutHostPermission(int launcherUserId,
|
||||
@NonNull String callingPackage);
|
||||
|
||||
public abstract boolean requestPinAppWidget(@NonNull String callingPackage,
|
||||
@NonNull AppWidgetProviderInfo appWidget, @Nullable IntentSender resultIntent,
|
||||
int userId);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user