Adds LauncherApps#ShortcutChangeCallback

This CL only defines the APIs and the aidl layer. LauncherAppsService
changes will be added in a separate CL.

Bug: 148085769
Test: atest com.android.server.pm.ShortcutManagerTest1 \
            com.android.server.pm.ShortcutManagerTest2 \
            com.android.server.pm.ShortcutManagerTest3 \
            com.android.server.pm.ShortcutManagerTest4 \
            com.android.server.pm.ShortcutManagerTest5 \
            com.android.server.pm.ShortcutManagerTest6 \
            com.android.server.pm.ShortcutManagerTest7 \
            com.android.server.pm.ShortcutManagerTest8 \
            com.android.server.pm.ShortcutManagerTest9 \
            com.android.server.pm.ShortcutManagerTest10
Change-Id: I9590cd7e2ad2b0336280f23a2766e242158ceb4a
This commit is contained in:
Mehdi Alizadeh
2020-01-16 18:09:24 -08:00
parent 2a198f3bf5
commit 9f68019066
4 changed files with 208 additions and 0 deletions

View File

@@ -25,6 +25,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.IOnAppsChangedListener;
import android.content.pm.LauncherApps;
import android.content.pm.IPackageInstallerCallback;
import android.content.pm.IShortcutChangeCallback;
import android.content.pm.PackageInstaller;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
@@ -89,4 +90,9 @@ interface ILauncherApps {
void registerPackageInstallerCallback(String callingPackage,
in IPackageInstallerCallback callback);
ParceledListSlice getAllSessions(String callingPackage);
void registerShortcutChangeCallback(String callingPackage, long changedSince,
String packageName, in List shortcutIds, in ComponentName componentName, int flags,
in IShortcutChangeCallback callback, int callbackId);
void unregisterShortcutChangeCallback(String callingPackage, int callbackId);
}

View File

@@ -0,0 +1,37 @@
/**
* Copyright (c) 2020, 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 android.content.pm;
import android.content.pm.ParceledListSlice;
import android.content.pm.ShortcutInfo;
import android.os.UserHandle;
import java.util.List;
/**
* Interface for LauncherApps#ShortcutChangeCallbackProxy.
*
* @hide
*/
oneway interface IShortcutChangeCallback
{
void onShortcutsAddedOrUpdated(String packageName, in List<ShortcutInfo> shortcuts,
in UserHandle user);
void onShortcutsRemoved(String packageName, in List<ShortcutInfo> shortcuts,
in UserHandle user);
}

View File

@@ -61,15 +61,21 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Pair;
import com.android.internal.util.function.pooled.PooledLambda;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executor;
@@ -152,6 +158,9 @@ public class LauncherApps {
private final List<CallbackMessageHandler> mCallbacks = new ArrayList<>();
private final List<SessionCallbackDelegate> mDelegates = new ArrayList<>();
private final Map<Integer, Pair<Executor, ShortcutChangeCallback>>
mShortcutChangeCallbacks = new HashMap<>();
/**
* Callbacks for package changes to this and related managed profiles.
*/
@@ -469,6 +478,95 @@ public class LauncherApps {
}
}
/**
* Callbacks for shortcut changes to this and related managed profiles.
*
* @hide
*/
public interface ShortcutChangeCallback {
/**
* Indicates that one or more shortcuts, that match the {@link ShortcutQuery} used to
* register this callback, have been added or updated.
* @see LauncherApps#registerShortcutChangeCallback(ShortcutChangeCallback, ShortcutQuery)
*
* <p>Only the applications that are allowed to access the shortcut information,
* as defined in {@link #hasShortcutHostPermission()}, will receive it.
*
* @param packageName The name of the package that has the shortcuts.
* @param shortcuts Shortcuts from the package that have updated or added. Only "key"
* information will be provided, as defined in {@link ShortcutInfo#hasKeyFieldsOnly()}.
* @param user The UserHandle of the profile that generated the change.
*
* @see ShortcutManager
*/
default void onShortcutsAddedOrUpdated(@NonNull String packageName,
@NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {}
/**
* Indicates that one or more shortcuts, that match the {@link ShortcutQuery} used to
* register this callback, have been removed.
* @see LauncherApps#registerShortcutChangeCallback(ShortcutChangeCallback, ShortcutQuery)
*
* <p>Only the applications that are allowed to access the shortcut information,
* as defined in {@link #hasShortcutHostPermission()}, will receive it.
*
* @param packageName The name of the package that has the shortcuts.
* @param shortcuts Shortcuts from the package that have been removed. Only "key"
* information will be provided, as defined in {@link ShortcutInfo#hasKeyFieldsOnly()}.
* @param user The UserHandle of the profile that generated the change.
*
* @see ShortcutManager
*/
default void onShortcutsRemoved(@NonNull String packageName,
@NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {}
}
/**
* Callback proxy class for {@link ShortcutChangeCallback}
*
* @hide
*/
private static class ShortcutChangeCallbackProxy extends
android.content.pm.IShortcutChangeCallback.Stub {
private final WeakReference<Pair<Executor, ShortcutChangeCallback>> mRemoteReferences;
ShortcutChangeCallbackProxy(Pair<Executor, ShortcutChangeCallback> remoteReferences) {
mRemoteReferences = new WeakReference<>(remoteReferences);
}
@Override
public void onShortcutsAddedOrUpdated(@NonNull String packageName,
@NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
Pair<Executor, ShortcutChangeCallback> remoteReferences = mRemoteReferences.get();
if (remoteReferences == null) {
// Binder is dead.
return;
}
final Executor executor = remoteReferences.first;
final ShortcutChangeCallback callback = remoteReferences.second;
executor.execute(
PooledLambda.obtainRunnable(ShortcutChangeCallback::onShortcutsAddedOrUpdated,
callback, packageName, shortcuts, user).recycleOnUse());
}
@Override
public void onShortcutsRemoved(@NonNull String packageName,
@NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
Pair<Executor, ShortcutChangeCallback> remoteReferences = mRemoteReferences.get();
if (remoteReferences == null) {
// Binder is dead.
return;
}
final Executor executor = remoteReferences.first;
final ShortcutChangeCallback callback = remoteReferences.second;
executor.execute(
PooledLambda.obtainRunnable(ShortcutChangeCallback::onShortcutsRemoved,
callback, packageName, shortcuts, user).recycleOnUse());
}
}
/** @hide */
public LauncherApps(Context context, ILauncherApps service) {
mContext = context;
@@ -1559,6 +1657,62 @@ public class LauncherApps {
}
}
/**
* Register a callback to watch for shortcut change events in this user and managed profiles.
*
* @param callback The callback to register.
* @param query {@link ShortcutQuery} to match and filter the shortcut events. Only matching
* shortcuts will be returned by the callback.
* @param executor {@link Executor} to handle the callbacks. To dispatch callbacks to the main
* thread of your application, you can use {@link android.content.Context#getMainExecutor()}.
*
* @hide
*/
public void registerShortcutChangeCallback(@NonNull ShortcutChangeCallback callback,
@NonNull ShortcutQuery query, @NonNull @CallbackExecutor Executor executor) {
Objects.requireNonNull(callback, "Callback cannot be null");
Objects.requireNonNull(query, "Query cannot be null");
Objects.requireNonNull(executor, "Executor cannot be null");
synchronized (mShortcutChangeCallbacks) {
final int callbackId = callback.hashCode();
final Pair<Executor, ShortcutChangeCallback> state = new Pair<>(executor, callback);
mShortcutChangeCallbacks.put(callbackId, state);
try {
mService.registerShortcutChangeCallback(mContext.getPackageName(),
query.mChangedSince, query.mPackage, query.mShortcutIds, query.mActivity,
query.mQueryFlags, new ShortcutChangeCallbackProxy(state), callbackId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
/**
* Unregisters a callback that was previously registered.
* @see #registerShortcutChangeCallback(ShortcutChangeCallback, ShortcutQuery, Executor)
*
* @param callback Callback to be unregistered.
*
* @hide
*/
public void unregisterShortcutChangeCallback(@NonNull ShortcutChangeCallback callback) {
Objects.requireNonNull(callback, "Callback cannot be null");
synchronized (mShortcutChangeCallbacks) {
final int callbackId = callback.hashCode();
if (mShortcutChangeCallbacks.containsKey(callbackId)) {
mShortcutChangeCallbacks.remove(callbackId);
try {
mService.unregisterShortcutChangeCallback(mContext.getPackageName(),
callbackId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
}
/**
* A helper method to extract a {@link PinItemRequest} set to
* the {@link #EXTRA_PIN_ITEM_REQUEST} extra.

View File

@@ -35,6 +35,7 @@ import android.content.pm.ILauncherApps;
import android.content.pm.IOnAppsChangedListener;
import android.content.pm.IPackageInstallerCallback;
import android.content.pm.IPackageManager;
import android.content.pm.IShortcutChangeCallback;
import android.content.pm.LauncherApps;
import android.content.pm.LauncherApps.ShortcutQuery;
import android.content.pm.PackageInfo;
@@ -680,6 +681,16 @@ public class LauncherAppsService extends SystemService {
injectBinderCallingPid(), injectBinderCallingUid()));
}
@Override
public void registerShortcutChangeCallback(String callingPackage, long changedSince,
String packageName, List shortcutIds, ComponentName componentName, int flags,
IShortcutChangeCallback callback, int callbackId) {
}
@Override
public void unregisterShortcutChangeCallback(String callingPackage, int callbackId) {
}
@Override
public void pinShortcuts(String callingPackage, String packageName, List<String> ids,
UserHandle targetUser) {