Merge changes from topic "CM-API-mode"
* changes: Add callback registration mechanism for listening to communal state changes. Add isCommunalMode() to CommunalManager SystemApi.
This commit is contained in:
@@ -224,6 +224,7 @@ package android {
|
||||
field public static final String READ_APP_SPECIFIC_LOCALES = "android.permission.READ_APP_SPECIFIC_LOCALES";
|
||||
field public static final String READ_CARRIER_APP_INFO = "android.permission.READ_CARRIER_APP_INFO";
|
||||
field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
|
||||
field public static final String READ_COMMUNAL_STATE = "android.permission.READ_COMMUNAL_STATE";
|
||||
field public static final String READ_CONTENT_RATING_SYSTEMS = "android.permission.READ_CONTENT_RATING_SYSTEMS";
|
||||
field public static final String READ_DEVICE_CONFIG = "android.permission.READ_DEVICE_CONFIG";
|
||||
field public static final String READ_DREAM_STATE = "android.permission.READ_DREAM_STATE";
|
||||
@@ -1309,6 +1310,20 @@ package android.app.backup {
|
||||
|
||||
}
|
||||
|
||||
package android.app.communal {
|
||||
|
||||
public final class CommunalManager {
|
||||
method @RequiresPermission(android.Manifest.permission.READ_COMMUNAL_STATE) public void addCommunalModeListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.communal.CommunalManager.CommunalModeListener);
|
||||
method @RequiresPermission(android.Manifest.permission.READ_COMMUNAL_STATE) public boolean isCommunalMode();
|
||||
method @RequiresPermission(android.Manifest.permission.READ_COMMUNAL_STATE) public void removeCommunalModeListener(@NonNull android.app.communal.CommunalManager.CommunalModeListener);
|
||||
}
|
||||
|
||||
@java.lang.FunctionalInterface public static interface CommunalManager.CommunalModeListener {
|
||||
method public void onCommunalModeChanged(boolean);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
package android.app.compat {
|
||||
|
||||
public final class CompatChanges {
|
||||
@@ -2491,6 +2506,7 @@ package android.content {
|
||||
field public static final String BATTERY_STATS_SERVICE = "batterystats";
|
||||
field @Deprecated public static final int BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS = 1048576; // 0x100000
|
||||
field public static final int BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND = 262144; // 0x40000
|
||||
field public static final String COMMUNAL_SERVICE = "communal";
|
||||
field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
|
||||
field public static final String CONTEXTHUB_SERVICE = "contexthub";
|
||||
field public static final String ETHERNET_SERVICE = "ethernet";
|
||||
|
||||
@@ -42,6 +42,7 @@ package android {
|
||||
field public static final String TEST_BIOMETRIC = "android.permission.TEST_BIOMETRIC";
|
||||
field public static final String TEST_MANAGE_ROLLBACKS = "android.permission.TEST_MANAGE_ROLLBACKS";
|
||||
field public static final String UPGRADE_RUNTIME_PERMISSIONS = "android.permission.UPGRADE_RUNTIME_PERMISSIONS";
|
||||
field public static final String WRITE_COMMUNAL_STATE = "android.permission.WRITE_COMMUNAL_STATE";
|
||||
field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG";
|
||||
field @Deprecated public static final String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE";
|
||||
field public static final String WRITE_OBB = "android.permission.WRITE_OBB";
|
||||
@@ -608,6 +609,14 @@ package android.app.blob {
|
||||
|
||||
}
|
||||
|
||||
package android.app.communal {
|
||||
|
||||
public final class CommunalManager {
|
||||
method @RequiresPermission(android.Manifest.permission.WRITE_COMMUNAL_STATE) public void setCommunalViewShowing(boolean);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
package android.app.contentsuggestions {
|
||||
|
||||
public final class ContentSuggestionsManager {
|
||||
@@ -819,6 +828,7 @@ package android.content.pm {
|
||||
method public void holdLock(android.os.IBinder, int);
|
||||
method @RequiresPermission(android.Manifest.permission.KEEP_UNINSTALLED_PACKAGES) public void setKeepUninstalledPackages(@NonNull java.util.List<java.lang.String>);
|
||||
field public static final String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage";
|
||||
field public static final String FEATURE_COMMUNAL_MODE = "android.software.communal_mode";
|
||||
field public static final String FEATURE_FILE_BASED_ENCRYPTION = "android.software.file_based_encryption";
|
||||
field public static final String FEATURE_HDMI_CEC = "android.hardware.hdmi.cec";
|
||||
field public static final int FLAG_PERMISSION_REVOKE_WHEN_REQUESTED = 128; // 0x80
|
||||
|
||||
@@ -1513,7 +1513,7 @@ public final class SystemServiceRegistry {
|
||||
}
|
||||
});
|
||||
|
||||
registerService(Context.COMMUNAL_MANAGER_SERVICE, CommunalManager.class,
|
||||
registerService(Context.COMMUNAL_SERVICE, CommunalManager.class,
|
||||
new CachedServiceFetcher<CommunalManager>() {
|
||||
@Override
|
||||
public CommunalManager createService(ContextImpl ctx) {
|
||||
@@ -1522,7 +1522,7 @@ public final class SystemServiceRegistry {
|
||||
return null;
|
||||
}
|
||||
IBinder iBinder =
|
||||
ServiceManager.getService(Context.COMMUNAL_MANAGER_SERVICE);
|
||||
ServiceManager.getService(Context.COMMUNAL_SERVICE);
|
||||
return iBinder != null ? new CommunalManager(
|
||||
ICommunalManager.Stub.asInterface(iBinder)) : null;
|
||||
}
|
||||
|
||||
@@ -17,15 +17,21 @@
|
||||
package android.app.communal;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.RequiresFeature;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SystemApi;
|
||||
import android.annotation.SystemService;
|
||||
import android.annotation.TestApi;
|
||||
import android.compat.annotation.ChangeId;
|
||||
import android.compat.annotation.Disabled;
|
||||
import android.compat.annotation.Overridable;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.RemoteException;
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* System private class for talking with the
|
||||
@@ -33,10 +39,12 @@ import android.os.RemoteException;
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemService(Context.COMMUNAL_MANAGER_SERVICE)
|
||||
@SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
|
||||
@SystemService(Context.COMMUNAL_SERVICE)
|
||||
@RequiresFeature(PackageManager.FEATURE_COMMUNAL_MODE)
|
||||
public final class CommunalManager {
|
||||
private final ICommunalManager mService;
|
||||
private final ArrayMap<CommunalModeListener, ICommunalModeListener> mCommunalModeListeners;
|
||||
|
||||
/**
|
||||
* This change id is used to annotate packages which can run in communal mode by default,
|
||||
@@ -59,15 +67,20 @@ public final class CommunalManager {
|
||||
@Disabled
|
||||
public static final long ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT = 200324021L;
|
||||
|
||||
/** @hide */
|
||||
public CommunalManager(ICommunalManager service) {
|
||||
mService = service;
|
||||
mCommunalModeListeners = new ArrayMap<CommunalModeListener, ICommunalModeListener>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates whether or not the communal view is currently showing over the lockscreen.
|
||||
*
|
||||
* @param isShowing Whether communal view is showing.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@TestApi
|
||||
@RequiresPermission(Manifest.permission.WRITE_COMMUNAL_STATE)
|
||||
public void setCommunalViewShowing(boolean isShowing) {
|
||||
try {
|
||||
@@ -76,4 +89,72 @@ public final class CommunalManager {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not the communal view is currently showing over the lockscreen.
|
||||
*/
|
||||
@RequiresPermission(Manifest.permission.READ_COMMUNAL_STATE)
|
||||
public boolean isCommunalMode() {
|
||||
try {
|
||||
return mService.isCommunalMode();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener for communal state changes.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface CommunalModeListener {
|
||||
/**
|
||||
* Callback function that executes when the communal state changes.
|
||||
*/
|
||||
void onCommunalModeChanged(boolean isCommunalMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a callback to execute when the communal state changes.
|
||||
*
|
||||
* @param listener The listener to add to receive communal state changes.
|
||||
* @param executor {@link Executor} to dispatch to. To dispatch the callback to the main
|
||||
* thread of your application, use
|
||||
* {@link android.content.Context#getMainExecutor()}.
|
||||
*/
|
||||
@RequiresPermission(Manifest.permission.READ_COMMUNAL_STATE)
|
||||
public void addCommunalModeListener(@NonNull Executor executor,
|
||||
@NonNull CommunalModeListener listener) {
|
||||
synchronized (mCommunalModeListeners) {
|
||||
try {
|
||||
ICommunalModeListener iListener = new ICommunalModeListener.Stub() {
|
||||
@Override
|
||||
public void onCommunalModeChanged(boolean isCommunalMode) {
|
||||
executor.execute(() -> listener.onCommunalModeChanged(isCommunalMode));
|
||||
}
|
||||
};
|
||||
mService.addCommunalModeListener(iListener);
|
||||
mCommunalModeListeners.put(listener, iListener);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters a callback that executes when communal state changes.
|
||||
*/
|
||||
@RequiresPermission(Manifest.permission.READ_COMMUNAL_STATE)
|
||||
public void removeCommunalModeListener(@NonNull CommunalModeListener listener) {
|
||||
synchronized (mCommunalModeListeners) {
|
||||
ICommunalModeListener iListener = mCommunalModeListeners.get(listener);
|
||||
if (iListener != null) {
|
||||
try {
|
||||
mService.removeCommunalModeListener(iListener);
|
||||
mCommunalModeListeners.remove(listener);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,12 +16,17 @@
|
||||
|
||||
package android.app.communal;
|
||||
|
||||
import android.app.communal.ICommunalModeListener;
|
||||
|
||||
/**
|
||||
* System private API for talking with the communal manager service that handles communal mode
|
||||
* state.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
oneway interface ICommunalManager {
|
||||
void setCommunalViewShowing(boolean isShowing);
|
||||
interface ICommunalManager {
|
||||
oneway void setCommunalViewShowing(boolean isShowing);
|
||||
boolean isCommunalMode();
|
||||
void addCommunalModeListener(in ICommunalModeListener listener);
|
||||
void removeCommunalModeListener(in ICommunalModeListener listener);
|
||||
}
|
||||
26
core/java/android/app/communal/ICommunalModeListener.aidl
Normal file
26
core/java/android/app/communal/ICommunalModeListener.aidl
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.app.communal;
|
||||
|
||||
/**
|
||||
* System private API to be notified about communal mode changes.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
oneway interface ICommunalModeListener {
|
||||
void onCommunalModeChanged(boolean isCommunalMode);
|
||||
}
|
||||
@@ -5862,13 +5862,14 @@ public abstract class Context {
|
||||
|
||||
/**
|
||||
* Use with {@link #getSystemService(String)} to retrieve a
|
||||
* {@link android.app.CommunalManager} for interacting with the global system state.
|
||||
* {@link android.app.communal.CommunalManager} for interacting with the global system state.
|
||||
*
|
||||
* @see #getSystemService(String)
|
||||
* @see android.app.CommunalManager
|
||||
* @see android.app.communal.CommunalManager
|
||||
* @hide
|
||||
*/
|
||||
public static final String COMMUNAL_MANAGER_SERVICE = "communal_manager";
|
||||
@SystemApi
|
||||
public static final String COMMUNAL_SERVICE = "communal";
|
||||
|
||||
/**
|
||||
* Use with {@link #getSystemService(String)} to retrieve a
|
||||
|
||||
@@ -3981,6 +3981,7 @@ public abstract class PackageManager {
|
||||
* @hide
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.FEATURE)
|
||||
@TestApi
|
||||
public static final String FEATURE_COMMUNAL_MODE = "android.software.communal_mode";
|
||||
|
||||
/** @hide */
|
||||
|
||||
@@ -5531,10 +5531,18 @@
|
||||
|
||||
<!-- Allows an application to interact with the currently active
|
||||
{@link com.android.server.communal.CommunalManagerService}.
|
||||
@hide -->
|
||||
@hide
|
||||
@TestApi -->
|
||||
<permission android:name="android.permission.WRITE_COMMUNAL_STATE"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<!-- Allows an application to view information from the currently active
|
||||
{@link com.android.server.communal.CommunalManagerService}.
|
||||
@hide
|
||||
@SystemApi -->
|
||||
<permission android:name="android.permission.READ_COMMUNAL_STATE"
|
||||
android:protectionLevel="signature|privileged"/>
|
||||
|
||||
<!-- Allows the holder to manage whether the system can bind to services
|
||||
provided by instant apps. This permission is intended to protect
|
||||
test/development fucntionality and should be used only in such cases.
|
||||
|
||||
@@ -519,6 +519,9 @@ applications that come with the platform
|
||||
<permission name="android.permission.LOCK_DEVICE" />
|
||||
<!-- Permission required for CTS test - CtsSafetyCenterTestCases -->
|
||||
<permission name="android.permission.SEND_SAFETY_CENTER_UPDATE" />
|
||||
<!-- Permission required for CTS test - CommunalManagerTest -->
|
||||
<permission name="android.permission.WRITE_COMMUNAL_STATE" />
|
||||
<permission name="android.permission.READ_COMMUNAL_STATE" />
|
||||
</privapp-permissions>
|
||||
|
||||
<privapp-permissions package="com.android.statementservice">
|
||||
|
||||
@@ -606,6 +606,10 @@
|
||||
<!-- Permission required for CTS test - CtsSafetyCenterTestCases -->
|
||||
<uses-permission android:name="android.permission.SEND_SAFETY_CENTER_UPDATE" />
|
||||
|
||||
<!-- Permission required for CTS test - CommunalManagerTest -->
|
||||
<uses-permission android:name="android.permission.WRITE_COMMUNAL_STATE" />
|
||||
<uses-permission android:name="android.permission.READ_COMMUNAL_STATE" />
|
||||
|
||||
<application android:label="@string/app_label"
|
||||
android:theme="@android:style/Theme.DeviceDefault.DayNight"
|
||||
android:defaultToDeviceProtectedStorage="true"
|
||||
|
||||
@@ -30,6 +30,7 @@ import android.annotation.RequiresPermission;
|
||||
import android.app.KeyguardManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.communal.ICommunalManager;
|
||||
import android.app.communal.ICommunalModeListener;
|
||||
import android.app.compat.CompatChanges;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
@@ -42,6 +43,8 @@ import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.RemoteCallbackList;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.service.dreams.DreamManagerInternal;
|
||||
@@ -77,6 +80,8 @@ public final class CommunalManagerService extends SystemService {
|
||||
private final PackageReceiver mPackageReceiver;
|
||||
private final PackageManager mPackageManager;
|
||||
private final DreamManagerInternal mDreamManagerInternal;
|
||||
private final RemoteCallbackList<ICommunalModeListener> mListeners =
|
||||
new RemoteCallbackList<>();
|
||||
|
||||
private final ActivityInterceptorCallback mActivityInterceptorCallback =
|
||||
new ActivityInterceptorCallback() {
|
||||
@@ -129,7 +134,7 @@ public final class CommunalManagerService extends SystemService {
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
publishBinderService(Context.COMMUNAL_MANAGER_SERVICE, mBinderService);
|
||||
publishBinderService(Context.COMMUNAL_SERVICE, mBinderService);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -242,6 +247,27 @@ public final class CommunalManagerService extends SystemService {
|
||||
return !isAppAllowed(appInfo);
|
||||
}
|
||||
|
||||
private void dispatchCommunalMode(boolean isShowing) {
|
||||
synchronized (mListeners) {
|
||||
int i = mListeners.beginBroadcast();
|
||||
while (i > 0) {
|
||||
i--;
|
||||
try {
|
||||
mListeners.getBroadcastItem(i).onCommunalModeChanged(isShowing);
|
||||
} catch (RemoteException e) {
|
||||
// Handled by the RemoteCallbackList.
|
||||
}
|
||||
}
|
||||
mListeners.finishBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
private void enforceReadPermission() {
|
||||
mContext.enforceCallingPermission(Manifest.permission.READ_COMMUNAL_STATE,
|
||||
Manifest.permission.READ_COMMUNAL_STATE
|
||||
+ "permission required to read communal state.");
|
||||
}
|
||||
|
||||
private final class BinderService extends ICommunalManager.Stub {
|
||||
/**
|
||||
* Sets whether or not we are in communal mode.
|
||||
@@ -252,7 +278,43 @@ public final class CommunalManagerService extends SystemService {
|
||||
mContext.enforceCallingPermission(Manifest.permission.WRITE_COMMUNAL_STATE,
|
||||
Manifest.permission.WRITE_COMMUNAL_STATE
|
||||
+ "permission required to modify communal state.");
|
||||
if (mCommunalViewIsShowing.get() == isShowing) {
|
||||
return;
|
||||
}
|
||||
mCommunalViewIsShowing.set(isShowing);
|
||||
dispatchCommunalMode(isShowing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not we are in communal mode.
|
||||
*/
|
||||
@RequiresPermission(Manifest.permission.READ_COMMUNAL_STATE)
|
||||
@Override
|
||||
public boolean isCommunalMode() {
|
||||
enforceReadPermission();
|
||||
return mCommunalViewIsShowing.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a callback to execute when communal state changes.
|
||||
*/
|
||||
@RequiresPermission(Manifest.permission.READ_COMMUNAL_STATE)
|
||||
public void addCommunalModeListener(ICommunalModeListener listener) {
|
||||
enforceReadPermission();
|
||||
synchronized (mListeners) {
|
||||
mListeners.register(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an added callback that execute when communal state changes.
|
||||
*/
|
||||
@RequiresPermission(Manifest.permission.READ_COMMUNAL_STATE)
|
||||
public void removeCommunalModeListener(ICommunalModeListener listener) {
|
||||
enforceReadPermission();
|
||||
synchronized (mListeners) {
|
||||
mListeners.unregister(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -123,6 +123,8 @@ public class CommunalManagerServiceTest {
|
||||
|
||||
doNothing().when(mContextSpy).enforceCallingPermission(
|
||||
eq(Manifest.permission.WRITE_COMMUNAL_STATE), anyString());
|
||||
doNothing().when(mContextSpy).enforceCallingPermission(
|
||||
eq(Manifest.permission.READ_COMMUNAL_STATE), anyString());
|
||||
|
||||
mService = new CommunalManagerService(mContextSpy);
|
||||
mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
|
||||
@@ -202,6 +204,18 @@ public class CommunalManagerServiceTest {
|
||||
return new Intent(action, Uri.parse("package:" + packageName));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsCommunalMode_isTrue() throws RemoteException {
|
||||
mBinder.setCommunalViewShowing(true);
|
||||
assertThat(mBinder.isCommunalMode()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsCommunalMode_isFalse() throws RemoteException {
|
||||
mBinder.setCommunalViewShowing(false);
|
||||
assertThat(mBinder.isCommunalMode()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntercept_unlocked_communalOff_appNotEnabled_showWhenLockedOff() {
|
||||
when(mKeyguardManager.isKeyguardLocked()).thenReturn(false);
|
||||
|
||||
Reference in New Issue
Block a user