Ambient wallpaper API feedback

Making this api a @SystemApi, protecting it with a permission and
changing boolean animation parameter to a long.

Change-Id: Ife6aac2806a5590288a801751f22d85c3cfd4622
Fixes: 116117810
Test: atest DozeWallpaperStateTest
Test: atest WallpaperServiceTest
Test: set image wallpaper
Test: set AOD wallpaper that holds permission
Test: set AOD wallpaper that doesn't hold permission
This commit is contained in:
Lucas Dupin
2018-11-06 17:47:48 -08:00
parent 4d20bac002
commit 4c8c3274da
14 changed files with 96 additions and 44 deletions

View File

@@ -1312,7 +1312,6 @@ package android {
field public static final int summaryColumn = 16843426; // 0x10102a2
field public static final int summaryOff = 16843248; // 0x10101f0
field public static final int summaryOn = 16843247; // 0x10101ef
field public static final int supportsAmbientMode = 16844173; // 0x101058d
field public static final int supportsAssist = 16844016; // 0x10104f0
field public static final int supportsLaunchVoiceAssistFromKeyguard = 16844017; // 0x10104f1
field public static final int supportsLocalInteraction = 16844047; // 0x101050f
@@ -6352,7 +6351,6 @@ package android.app {
method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
method public android.graphics.drawable.Drawable loadThumbnail(android.content.pm.PackageManager);
method public boolean supportsAmbientMode();
method public boolean supportsMultipleDisplays();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.WallpaperInfo> CREATOR;
@@ -40896,11 +40894,9 @@ package android.service.wallpaper {
method public int getDesiredMinimumHeight();
method public int getDesiredMinimumWidth();
method public android.view.SurfaceHolder getSurfaceHolder();
method public boolean isInAmbientMode();
method public boolean isPreview();
method public boolean isVisible();
method public void notifyColorsChanged();
method public void onAmbientModeChanged(boolean, boolean);
method public void onApplyWindowInsets(android.view.WindowInsets);
method public android.os.Bundle onCommand(java.lang.String, int, int, int, android.os.Bundle, boolean);
method public android.app.WallpaperColors onComputeColors();

View File

@@ -17,6 +17,7 @@ package android {
field public static final java.lang.String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING";
field public static final java.lang.String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE";
field public static final java.lang.String ALLOW_ANY_CODEC_FOR_PLAYBACK = "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK";
field public static final java.lang.String AMBIENT_WALLPAPER = "android.permission.AMBIENT_WALLPAPER";
field public static final java.lang.String BACKUP = "android.permission.BACKUP";
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
@@ -224,6 +225,7 @@ package android {
field public static final int isVrOnly = 16844152; // 0x1010578
field public static final int requiredSystemPropertyName = 16844133; // 0x1010565
field public static final int requiredSystemPropertyValue = 16844134; // 0x1010566
field public static final int supportsAmbientMode = 16844173; // 0x101058d
field public static final int userRestriction = 16844164; // 0x1010584
}
@@ -555,6 +557,10 @@ package android.app {
method public void onVrStateChanged(boolean);
}
public final class WallpaperInfo implements android.os.Parcelable {
method public boolean supportsAmbientMode();
}
public class WallpaperManager {
method public void clearWallpaper(int, int);
method public void setDisplayOffset(android.os.IBinder, int, int);
@@ -5334,6 +5340,15 @@ package android.service.trust {
}
package android.service.wallpaper {
public class WallpaperService.Engine {
method public boolean isInAmbientMode();
method public void onAmbientModeChanged(boolean, long);
}
}
package android.telecom {
public deprecated class AudioState implements android.os.Parcelable {

View File

@@ -159,5 +159,5 @@ interface IWallpaperManager {
/**
* Called from SystemUI when it shows the AoD UI.
*/
oneway void setInAmbientMode(boolean inAmbientMode, boolean animated);
oneway void setInAmbientMode(boolean inAmbientMode, long animationDuration);
}

View File

@@ -16,6 +16,7 @@
package android.app;
import android.annotation.SystemApi;
import android.app.slice.Slice;
import android.content.ComponentName;
import android.content.Context;
@@ -330,7 +331,9 @@ public final class WallpaperInfo implements Parcelable {
* @see WallpaperService.Engine#onAmbientModeChanged(boolean, boolean)
* @see WallpaperService.Engine#isInAmbientMode()
* @return {@code true} if wallpaper can draw when in ambient mode.
* @hide
*/
@SystemApi
public boolean supportsAmbientMode() {
return mSupportsAmbientMode;
}

View File

@@ -27,7 +27,7 @@ oneway interface IWallpaperEngine {
void setDesiredSize(int width, int height);
void setDisplayPadding(in Rect padding);
void setVisibility(boolean visible);
void setInAmbientMode(boolean inAmbientDisplay, boolean animated);
void setInAmbientMode(boolean inAmbientDisplay, long animationDuration);
void dispatchPointer(in MotionEvent event);
void dispatchWallpaperCommand(String action, int x, int y,
int z, in Bundle extras);

View File

@@ -19,6 +19,7 @@ package android.service.wallpaper;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
import android.app.Service;
import android.app.WallpaperColors;
@@ -440,7 +441,9 @@ public abstract class WallpaperService extends Service {
/**
* Returns true if this engine is running in ambient mode -- that is,
* it is being shown in low power mode, on always on display.
* @hide
*/
@SystemApi
public boolean isInAmbientMode() {
return mIsInAmbientMode;
}
@@ -566,14 +569,16 @@ public abstract class WallpaperService extends Service {
* Called when the device enters or exits ambient mode.
*
* @param inAmbientMode {@code true} if in ambient mode.
* @param animated {@code true} if you'll have the opportunity of animating your transition
* {@code false} when the wallpaper should present its ambient version
* immediately.
* @param animationDuration How long the transition animation to change the ambient state
* should run, in milliseconds. If 0 is passed as the argument
* here, the state should be switched immediately.
*
* @see #isInAmbientMode()
* @see WallpaperInfo#supportsAmbientMode()
* @hide
*/
public void onAmbientModeChanged(boolean inAmbientMode, boolean animated) {
@SystemApi
public void onAmbientModeChanged(boolean inAmbientMode, long animationDuration) {
}
/**
@@ -1044,19 +1049,19 @@ public abstract class WallpaperService extends Service {
* message sent from handler.
*
* @param inAmbientMode {@code true} if in ambient mode.
* @param animated {@code true} if the transition will be animated.
* @param animationDuration For how long the transition will last, in ms.
* @hide
*/
@VisibleForTesting
public void doAmbientModeChanged(boolean inAmbientMode, boolean animated) {
public void doAmbientModeChanged(boolean inAmbientMode, long animationDuration) {
if (!mDestroyed) {
if (DEBUG) {
Log.v(TAG, "onAmbientModeChanged(" + inAmbientMode + ", "
+ animated + "): " + this);
+ animationDuration + "): " + this);
}
mIsInAmbientMode = inAmbientMode;
if (mCreated) {
onAmbientModeChanged(inAmbientMode, animated);
onAmbientModeChanged(inAmbientMode, animationDuration);
}
}
}
@@ -1315,10 +1320,10 @@ public abstract class WallpaperService extends Service {
}
@Override
public void setInAmbientMode(boolean inAmbientDisplay, boolean animated)
public void setInAmbientMode(boolean inAmbientDisplay, long animationDuration)
throws RemoteException {
Message msg = mCaller.obtainMessageII(DO_IN_AMBIENT_MODE, inAmbientDisplay ? 1 : 0,
animated ? 1 : 0);
Message msg = mCaller.obtainMessageIO(DO_IN_AMBIENT_MODE, inAmbientDisplay ? 1 : 0,
animationDuration);
mCaller.sendMessage(msg);
}
@@ -1389,7 +1394,7 @@ public abstract class WallpaperService extends Service {
return;
}
case DO_IN_AMBIENT_MODE: {
mEngine.doAmbientModeChanged(message.arg1 != 0, message.arg2 != 0);
mEngine.doAmbientModeChanged(message.arg1 != 0, (Long) message.obj);
return;
}
case MSG_UPDATE_SURFACE:

View File

@@ -4217,6 +4217,10 @@
@hide -->
<permission android:name="android.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY"
android:protectionLevel="signature|preinstalled" />
<!-- @SystemApi Allows wallpaper to be rendered in ambient mode.
@hide -->
<permission android:name="android.permission.AMBIENT_WALLPAPER"
android:protectionLevel="signature|preinstalled" />
<application android:process="system"
android:persistent="true"

View File

@@ -7935,7 +7935,9 @@
wallpaper. -->
<attr name="showMetadataInPreview" format="boolean" />
<!-- Wallpapers optimized and capable of drawing in ambient mode will return true. -->
<!-- Wallpapers optimized and capable of drawing in ambient mode will return true.
This feature requires the android.permission.AMBIENT_WALLPAPER permission.
@hide @SystemApi -->
<attr name="supportsAmbientMode" format="boolean" />
<!-- Uri that specifies a settings Slice for this wallpaper. -->

View File

@@ -2909,6 +2909,7 @@
<public name="opticalInsetRight" />
<public name="opticalInsetBottom" />
<public name="forceDarkAllowed" />
<!-- @hide @SystemApi -->
<public name="supportsAmbientMode" />
<!-- @hide For use by platform and tools only. Developers should not specify this value. -->
<public name="usesNonSdkApi" />

View File

@@ -23,6 +23,7 @@ import android.os.ServiceManager;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.DozeParameters;
import java.io.PrintWriter;
@@ -80,11 +81,12 @@ public class DozeWallpaperState implements DozeMachine.Part {
if (isAmbientMode != mIsAmbientMode) {
mIsAmbientMode = isAmbientMode;
try {
long duration = animated ? StackStateAnimator.ANIMATION_DURATION_WAKEUP : 0L;
if (DEBUG) {
Log.i(TAG, "AOD wallpaper state changed to: " + mIsAmbientMode
+ ", animated: " + animated);
+ ", animationDuration: " + duration);
}
mWallpaperManagerService.setInAmbientMode(mIsAmbientMode, animated);
mWallpaperManagerService.setInAmbientMode(mIsAmbientMode, duration);
} catch (RemoteException e) {
// Cannot notify wallpaper manager service, but it's fine, let's just skip it.
Log.w(TAG, "Cannot notify state to WallpaperManagerService: " + mIsAmbientMode);

View File

@@ -721,7 +721,7 @@ public class StatusBar extends SystemUI implements DemoMode,
IWallpaperManager wallpaperManager = IWallpaperManager.Stub.asInterface(
ServiceManager.getService(Context.WALLPAPER_SERVICE));
try {
wallpaperManager.setInAmbientMode(false /* ambientMode */, false /* animated */);
wallpaperManager.setInAmbientMode(false /* ambientMode */, 0L /* duration */);
} catch (RemoteException e) {
// Just pass, nothing critical.
}

View File

@@ -16,9 +16,8 @@
package com.android.systemui.doze;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -27,8 +26,8 @@ import android.app.IWallpaperManager;
import android.os.RemoteException;
import android.support.test.filters.SmallTest;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.DozeParameters;
import org.junit.Before;
@@ -59,14 +58,14 @@ public class DozeWallpaperStateTest extends SysuiTestCase {
mDozeWallpaperState.transitionTo(DozeMachine.State.UNINITIALIZED,
DozeMachine.State.DOZE_AOD);
verify(mIWallpaperManager).setInAmbientMode(eq(true), anyBoolean());
verify(mIWallpaperManager).setInAmbientMode(eq(true), anyLong());
mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE_AOD, DozeMachine.State.FINISH);
verify(mIWallpaperManager).setInAmbientMode(eq(false), anyBoolean());
verify(mIWallpaperManager).setInAmbientMode(eq(false), anyLong());
// Make sure we're sending false when AoD is off
reset(mDozeParameters);
mDozeWallpaperState.transitionTo(DozeMachine.State.FINISH, DozeMachine.State.DOZE_AOD);
verify(mIWallpaperManager).setInAmbientMode(eq(false), anyBoolean());
verify(mIWallpaperManager).setInAmbientMode(eq(false), anyLong());
}
@Test
@@ -78,10 +77,12 @@ public class DozeWallpaperStateTest extends SysuiTestCase {
mDozeWallpaperState.transitionTo(DozeMachine.State.UNINITIALIZED,
DozeMachine.State.DOZE_AOD);
verify(mIWallpaperManager).setInAmbientMode(eq(true), eq(true));
verify(mIWallpaperManager).setInAmbientMode(eq(true),
eq((long) StackStateAnimator.ANIMATION_DURATION_WAKEUP));
mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE_AOD, DozeMachine.State.FINISH);
verify(mIWallpaperManager).setInAmbientMode(eq(false), eq(true));
verify(mIWallpaperManager).setInAmbientMode(eq(false),
eq((long) StackStateAnimator.ANIMATION_DURATION_WAKEUP));
}
@Test
@@ -93,24 +94,24 @@ public class DozeWallpaperStateTest extends SysuiTestCase {
mDozeWallpaperState.transitionTo(DozeMachine.State.UNINITIALIZED,
DozeMachine.State.DOZE_AOD);
verify(mIWallpaperManager).setInAmbientMode(eq(true), eq(false));
verify(mIWallpaperManager).setInAmbientMode(eq(true), eq(0L));
mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE_AOD, DozeMachine.State.FINISH);
verify(mIWallpaperManager).setInAmbientMode(eq(false), eq(false));
verify(mIWallpaperManager).setInAmbientMode(eq(false), eq(0L));
}
@Test
public void testTransitionTo_requestPulseIsAmbientMode() throws RemoteException {
mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE,
DozeMachine.State.DOZE_REQUEST_PULSE);
verify(mIWallpaperManager).setInAmbientMode(eq(true), eq(false));
verify(mIWallpaperManager).setInAmbientMode(eq(true), eq(0L));
}
@Test
public void testTransitionTo_pulseIsAmbientMode() throws RemoteException {
mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE_REQUEST_PULSE,
DozeMachine.State.DOZE_PULSING);
verify(mIWallpaperManager).setInAmbientMode(eq(true), eq(false));
verify(mIWallpaperManager).setInAmbientMode(eq(true), eq(0L));
}
@Test
@@ -120,6 +121,7 @@ public class DozeWallpaperStateTest extends SysuiTestCase {
reset(mIWallpaperManager);
mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE_PULSING,
DozeMachine.State.FINISH);
verify(mIWallpaperManager).setInAmbientMode(eq(false), eq(true));
verify(mIWallpaperManager).setInAmbientMode(eq(false),
eq((long) StackStateAnimator.ANIMATION_DURATION_WAKEUP));
}
}

View File

@@ -1181,7 +1181,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
// TODO(multi-display) TBD.
if (mInfo != null && mInfo.supportsAmbientMode() && displayId == DEFAULT_DISPLAY) {
try {
connector.mEngine.setInAmbientMode(mInAmbientMode, false /* animated */);
connector.mEngine.setInAmbientMode(mInAmbientMode, 0L /* duration */);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to set ambient mode state", e);
}
@@ -2023,11 +2023,17 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
}
// TODO(b/115486823) Extends this method with specific display.
public void setInAmbientMode(boolean inAmbienMode, boolean animated) {
/**
* TODO(b/115486823) Extends this method with specific display.
* Propagate ambient state to wallpaper engine.
*
* @param inAmbientMode {@code true} when in ambient mode, {@code false} otherwise.
* @param animationDuration Duration of the animation, or 0 when immediate.
*/
public void setInAmbientMode(boolean inAmbientMode, long animationDuration) {
final IWallpaperEngine engine;
synchronized (mLock) {
mInAmbientMode = inAmbienMode;
mInAmbientMode = inAmbientMode;
final WallpaperData data = mWallpaperMap.get(mCurrentUserId);
if (data != null && data.connection != null && data.connection.mInfo != null
&& data.connection.mInfo.supportsAmbientMode()) {
@@ -2040,7 +2046,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
if (engine != null) {
try {
engine.setInAmbientMode(inAmbienMode, animated);
engine.setInAmbientMode(inAmbientMode, animationDuration);
} catch (RemoteException e) {
// Cannot talk to wallpaper engine.
}
@@ -2344,7 +2350,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
return false;
}
if (!android.Manifest.permission.BIND_WALLPAPER.equals(si.permission)) {
String msg = "Selected service does not require "
String msg = "Selected service does not have "
+ android.Manifest.permission.BIND_WALLPAPER
+ ": " + componentName;
if (fromUser) {
@@ -2396,6 +2402,22 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
}
if (wi != null && wi.supportsAmbientMode()) {
final int hasPrivilege = mIPackageManager.checkPermission(
android.Manifest.permission.AMBIENT_WALLPAPER, wi.getPackageName(),
serviceUserId);
if (hasPrivilege != PackageManager.PERMISSION_GRANTED) {
String msg = "Selected service does not have "
+ android.Manifest.permission.AMBIENT_WALLPAPER
+ ": " + componentName;
if (fromUser) {
throw new SecurityException(msg);
}
Slog.w(TAG, msg);
return false;
}
}
// Bind the service!
if (DEBUG) Slog.v(TAG, "Binding to:" + componentName);
final int componentUid = mIPackageManager.getPackageUid(componentName.getPackageName(),

View File

@@ -38,7 +38,7 @@ public class WallpaperServiceTest {
public Engine onCreateEngine() {
return new Engine() {
@Override
public void onAmbientModeChanged(boolean inAmbientMode, boolean animated) {
public void onAmbientModeChanged(boolean inAmbientMode, long duration) {
ambientModeChangedCount[0]++;
}
};
@@ -47,12 +47,12 @@ public class WallpaperServiceTest {
WallpaperService.Engine engine = service.onCreateEngine();
engine.setCreated(true);
engine.doAmbientModeChanged(false, false);
engine.doAmbientModeChanged(false, 0);
assertFalse("ambient mode should be false", engine.isInAmbientMode());
assertEquals("onAmbientModeChanged should have been called",
ambientModeChangedCount[0], 1);
engine.doAmbientModeChanged(true, false);
engine.doAmbientModeChanged(true, 0);
assertTrue("ambient mode should be false", engine.isInAmbientMode());
assertEquals("onAmbientModeChanged should have been called",
ambientModeChangedCount[0], 2);