summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt8
-rw-r--r--api/system-current.txt8
-rw-r--r--cmds/sm/src/com/android/commands/sm/Sm.java10
-rw-r--r--core/java/android/app/ActivityManager.java10
-rw-r--r--core/java/android/app/ActivityManagerNative.java20
-rw-r--r--core/java/android/app/ActivityView.java172
-rw-r--r--core/java/android/app/IActivityManager.java2
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java43
-rw-r--r--core/java/android/app/admin/DevicePolicyManagerInternal.java6
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl3
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java18
-rw-r--r--core/java/android/content/pm/PackageParser.java16
-rw-r--r--core/java/android/hardware/Camera.java4
-rw-r--r--core/java/android/hardware/camera2/CameraMetadata.java4
-rw-r--r--core/java/android/hardware/camera2/CaptureRequest.java4
-rw-r--r--core/java/android/net/http/X509TrustManagerExtensions.java73
-rw-r--r--core/java/android/os/storage/IMountService.java170
-rw-r--r--core/java/android/os/storage/StorageManager.java50
-rw-r--r--core/java/android/preference/PreferenceFragment.java24
-rw-r--r--core/java/android/preference/SwitchPreference.java2
-rw-r--r--core/java/android/print/PrintAttributes.java8
-rw-r--r--core/java/android/security/net/config/NetworkSecurityConfig.java4
-rw-r--r--core/java/android/security/net/config/NetworkSecurityTrustManager.java23
-rw-r--r--core/java/android/security/net/config/RootTrustManager.java21
-rw-r--r--core/java/android/util/PathParser.java25
-rw-r--r--core/java/android/view/View.java4
-rw-r--r--core/java/android/view/ViewRootImpl.java2
-rw-r--r--core/java/android/widget/Editor.java31
-rw-r--r--core/java/android/widget/TextView.java9
-rw-r--r--core/java/com/android/internal/util/ArrayUtils.java7
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java25
-rw-r--r--core/jni/Android.mk1
-rw-r--r--core/jni/AndroidRuntime.cpp2
-rw-r--r--core/jni/android_util_PathParser.cpp43
-rw-r--r--core/res/AndroidManifest.xml8
-rw-r--r--core/res/res/layout/preference_list_fragment.xml25
-rw-r--r--core/res/res/layout/preference_list_fragment_material.xml25
-rw-r--r--core/res/res/layout/preference_widget_switch.xml2
-rw-r--r--core/res/res/values/attrs.xml1
-rw-r--r--core/res/res/values/attrs_manifest.xml1
-rw-r--r--core/res/res/values/config.xml4
-rw-r--r--core/res/res/values/ids.xml3
-rw-r--r--core/res/res/values/public.xml6
-rw-r--r--core/res/res/values/styles_material.xml1
-rw-r--r--core/res/res/values/symbols.xml2
-rw-r--r--core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java31
-rw-r--r--docs/html/guide/topics/manifest/uses-feature-element.jd9
-rw-r--r--libs/hwui/Android.mk2
-rw-r--r--libs/hwui/BakedOpRenderer.cpp158
-rw-r--r--libs/hwui/BakedOpRenderer.h35
-rw-r--r--libs/hwui/BakedOpState.h33
-rw-r--r--libs/hwui/DisplayListCanvas.h17
-rw-r--r--libs/hwui/LayerCache.cpp21
-rw-r--r--libs/hwui/OpReorderer.cpp62
-rw-r--r--libs/hwui/OpReorderer.h11
-rw-r--r--libs/hwui/PathParser.cpp8
-rw-r--r--libs/hwui/PathParser.h7
-rw-r--r--libs/hwui/Properties.cpp18
-rw-r--r--libs/hwui/Properties.h2
-rw-r--r--libs/hwui/RecordedOp.h26
-rw-r--r--libs/hwui/RecordingCanvas.h7
-rw-r--r--libs/hwui/RenderNode.cpp34
-rw-r--r--libs/hwui/RenderProperties.h10
-rw-r--r--libs/hwui/renderstate/OffscreenBufferPool.cpp196
-rw-r--r--libs/hwui/renderstate/OffscreenBufferPool.h142
-rw-r--r--libs/hwui/renderstate/RenderState.cpp15
-rw-r--r--libs/hwui/renderstate/RenderState.h7
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp6
-rw-r--r--libs/hwui/tests/TreeContentAnimation.cpp2
-rw-r--r--libs/hwui/unit_tests/BakedOpStateTests.cpp28
-rw-r--r--libs/hwui/unit_tests/OffscreenBufferPoolTests.cpp121
-rw-r--r--libs/hwui/unit_tests/OpReordererTests.cpp531
-rw-r--r--libs/hwui/unit_tests/PathParserTests.cpp255
-rw-r--r--libs/hwui/unit_tests/TestUtils.h25
-rw-r--r--libs/hwui/utils/Macros.h3
-rw-r--r--media/java/android/media/MediaScanner.java89
-rw-r--r--packages/DefaultContainerService/AndroidManifest.xml4
-rw-r--r--packages/FakeOemFeatures/AndroidManifest.xml4
-rw-r--r--packages/FusedLocation/AndroidManifest.xml6
-rw-r--r--packages/InputDevices/AndroidManifest.xml4
-rw-r--r--packages/Keyguard/AndroidManifest.xml4
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java17
-rw-r--r--packages/PrintSpooler/res/values/strings.xml3
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java4
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java17
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java8
-rw-r--r--packages/SettingsProvider/AndroidManifest.xml9
-rw-r--r--packages/Shell/AndroidManifest.xml4
-rw-r--r--packages/SystemUI/AndroidManifest.xml4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java57
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/events/activity/EnterRecentsWindowAnimationCompletedEvent.java (renamed from packages/SystemUI/src/com/android/systemui/recents/events/activity/EnterRecentsWindowAnimationStartedEvent.java)6
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java13
-rw-r--r--packages/services/Proxy/AndroidManifest.xml4
-rw-r--r--services/accessibility/java/com/android/server/accessibility/MagnificationController.java6
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java246
-rw-r--r--services/core/java/com/android/server/BluetoothService.java5
-rw-r--r--services/core/java/com/android/server/MountService.java125
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java51
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java3
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java6
-rw-r--r--services/core/java/com/android/server/am/TaskRecord.java2
-rw-r--r--services/core/java/com/android/server/am/UserController.java37
-rw-r--r--services/core/java/com/android/server/am/UserState.java8
-rw-r--r--services/core/java/com/android/server/pm/Installer.java9
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java39
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java17
-rw-r--r--services/core/java/com/android/server/wm/DimLayer.java2
-rw-r--r--services/core/java/com/android/server/wm/DimLayerController.java15
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java103
-rw-r--r--services/core/java/com/android/server/wm/DockedStackDividerController.java2
-rw-r--r--services/core/java/com/android/server/wm/DragState.java2
-rw-r--r--services/core/java/com/android/server/wm/Task.java85
-rw-r--r--services/core/java/com/android/server/wm/TaskPositioner.java36
-rw-r--r--services/core/java/com/android/server/wm/TaskStack.java8
-rw-r--r--services/core/java/com/android/server/wm/TaskTapPointerEventListener.java6
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java11
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java56
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfacePlacer.java9
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java169
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java12
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java4
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java9
-rw-r--r--tools/layoutlib/bridge/src/android/view/BridgeInflater.java43
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java77
131 files changed, 2839 insertions, 1462 deletions
diff --git a/api/current.txt b/api/current.txt
index c161242260d0..96ecad617a91 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -499,6 +499,7 @@ package android {
field public static final int ellipsize = 16842923; // 0x10100ab
field public static final int ems = 16843096; // 0x1010158
field public static final int enabled = 16842766; // 0x101000e
+ field public static final int encryptionAware = 16844038; // 0x1010506
field public static final int end = 16843996; // 0x10104dc
field public static final int endColor = 16843166; // 0x101019e
field public static final deprecated int endYear = 16843133; // 0x101017d
@@ -559,6 +560,7 @@ package android {
field public static final int fontFamily = 16843692; // 0x10103ac
field public static final int fontFeatureSettings = 16843959; // 0x10104b7
field public static final int footerDividersEnabled = 16843311; // 0x101022f
+ field public static final int forceDeviceEncrypted = 16844037; // 0x1010505
field public static final int foreground = 16843017; // 0x1010109
field public static final int foregroundGravity = 16843264; // 0x1010200
field public static final int foregroundTint = 16843885; // 0x101046d
@@ -931,6 +933,7 @@ package android {
field public static final int port = 16842793; // 0x1010029
field public static final int positiveButtonText = 16843253; // 0x10101f5
field public static final int preferenceCategoryStyle = 16842892; // 0x101008c
+ field public static final int preferenceFragmentStyle = 16844039; // 0x1010507
field public static final int preferenceInformationStyle = 16842893; // 0x101008d
field public static final int preferenceLayoutChild = 16842900; // 0x1010094
field public static final int preferenceScreenStyle = 16842891; // 0x101008b
@@ -1708,11 +1711,13 @@ package android {
field public static final int icon = 16908294; // 0x1020006
field public static final int icon1 = 16908295; // 0x1020007
field public static final int icon2 = 16908296; // 0x1020008
+ field public static final int icon_frame = 16908350; // 0x102003e
field public static final int input = 16908297; // 0x1020009
field public static final int inputArea = 16908318; // 0x102001e
field public static final int inputExtractEditText = 16908325; // 0x1020025
field public static final int keyboardView = 16908326; // 0x1020026
field public static final int list = 16908298; // 0x102000a
+ field public static final int list_container = 16908351; // 0x102003f
field public static final int mask = 16908334; // 0x102002e
field public static final int message = 16908299; // 0x102000b
field public static final int navigationBarBackground = 16908336; // 0x1020030
@@ -1732,6 +1737,7 @@ package android {
field public static final int stopSelectingText = 16908329; // 0x1020029
field public static final int summary = 16908304; // 0x1020010
field public static final int switchInputMethod = 16908324; // 0x1020024
+ field public static final int switch_widget = 16908352; // 0x1020040
field public static final int tabcontent = 16908305; // 0x1020011
field public static final int tabhost = 16908306; // 0x1020012
field public static final int tabs = 16908307; // 0x1020013
@@ -5705,6 +5711,7 @@ package android.app.admin {
method public boolean getCrossProfileCallerIdDisabled(android.content.ComponentName);
method public java.util.List<java.lang.String> getCrossProfileWidgetProviders(android.content.ComponentName);
method public int getCurrentFailedPasswordAttempts();
+ method public java.lang.String getDeviceOwnerLockScreenInfo();
method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
method public int getKeyguardDisabledFeatures(android.content.ComponentName);
method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
@@ -5757,6 +5764,7 @@ package android.app.admin {
method public void setCameraDisabled(android.content.ComponentName, boolean);
method public void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException;
method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
+ method public boolean setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.String);
method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
diff --git a/api/system-current.txt b/api/system-current.txt
index 8729d84295b0..0605851f058d 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -591,6 +591,7 @@ package android {
field public static final int ellipsize = 16842923; // 0x10100ab
field public static final int ems = 16843096; // 0x1010158
field public static final int enabled = 16842766; // 0x101000e
+ field public static final int encryptionAware = 16844038; // 0x1010506
field public static final int end = 16843996; // 0x10104dc
field public static final int endColor = 16843166; // 0x101019e
field public static final deprecated int endYear = 16843133; // 0x101017d
@@ -651,6 +652,7 @@ package android {
field public static final int fontFamily = 16843692; // 0x10103ac
field public static final int fontFeatureSettings = 16843959; // 0x10104b7
field public static final int footerDividersEnabled = 16843311; // 0x101022f
+ field public static final int forceDeviceEncrypted = 16844037; // 0x1010505
field public static final int foreground = 16843017; // 0x1010109
field public static final int foregroundGravity = 16843264; // 0x1010200
field public static final int foregroundTint = 16843885; // 0x101046d
@@ -1023,6 +1025,7 @@ package android {
field public static final int port = 16842793; // 0x1010029
field public static final int positiveButtonText = 16843253; // 0x10101f5
field public static final int preferenceCategoryStyle = 16842892; // 0x101008c
+ field public static final int preferenceFragmentStyle = 16844039; // 0x1010507
field public static final int preferenceInformationStyle = 16842893; // 0x101008d
field public static final int preferenceLayoutChild = 16842900; // 0x1010094
field public static final int preferenceScreenStyle = 16842891; // 0x101008b
@@ -1804,11 +1807,13 @@ package android {
field public static final int icon = 16908294; // 0x1020006
field public static final int icon1 = 16908295; // 0x1020007
field public static final int icon2 = 16908296; // 0x1020008
+ field public static final int icon_frame = 16908350; // 0x102003e
field public static final int input = 16908297; // 0x1020009
field public static final int inputArea = 16908318; // 0x102001e
field public static final int inputExtractEditText = 16908325; // 0x1020025
field public static final int keyboardView = 16908326; // 0x1020026
field public static final int list = 16908298; // 0x102000a
+ field public static final int list_container = 16908351; // 0x102003f
field public static final int mask = 16908334; // 0x102002e
field public static final int message = 16908299; // 0x102000b
field public static final int navigationBarBackground = 16908336; // 0x1020030
@@ -1828,6 +1833,7 @@ package android {
field public static final int stopSelectingText = 16908329; // 0x1020029
field public static final int summary = 16908304; // 0x1020010
field public static final int switchInputMethod = 16908324; // 0x1020024
+ field public static final int switch_widget = 16908352; // 0x1020040
field public static final int tabcontent = 16908305; // 0x1020011
field public static final int tabhost = 16908306; // 0x1020012
field public static final int tabs = 16908307; // 0x1020013
@@ -5831,6 +5837,7 @@ package android.app.admin {
method public deprecated java.lang.String getDeviceInitializerApp();
method public deprecated android.content.ComponentName getDeviceInitializerComponent();
method public java.lang.String getDeviceOwner();
+ method public java.lang.String getDeviceOwnerLockScreenInfo();
method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
method public int getKeyguardDisabledFeatures(android.content.ComponentName);
method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
@@ -5889,6 +5896,7 @@ package android.app.admin {
method public void setCameraDisabled(android.content.ComponentName, boolean);
method public void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException;
method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
+ method public boolean setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.String);
method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java
index 1ee60b068694..b208e438f171 100644
--- a/cmds/sm/src/com/android/commands/sm/Sm.java
+++ b/cmds/sm/src/com/android/commands/sm/Sm.java
@@ -86,6 +86,8 @@ public final class Sm {
runBenchmark();
} else if ("forget".equals(op)) {
runForget();
+ } else if ("set-emulate-fbe".equals(op)) {
+ runSetEmulateFbe();
} else {
throw new IllegalArgumentException();
}
@@ -137,6 +139,12 @@ public final class Sm {
StorageManager.DEBUG_FORCE_ADOPTABLE);
}
+ public void runSetEmulateFbe() throws RemoteException {
+ final boolean emulateFbe = Boolean.parseBoolean(nextArg());
+ mSm.setDebugFlags(emulateFbe ? StorageManager.DEBUG_EMULATE_FBE : 0,
+ StorageManager.DEBUG_EMULATE_FBE);
+ }
+
public void runPartition() throws RemoteException {
final String diskId = nextArg();
final String type = nextArg();
@@ -205,6 +213,8 @@ public final class Sm {
System.err.println("");
System.err.println(" sm forget [UUID|all]");
System.err.println("");
+ System.err.println(" sm set-emulate-fbe [true|false]");
+ System.err.println("");
return 1;
}
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 351064a2fd0d..65de4ca5f59a 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1558,6 +1558,16 @@ public class ActivityManager {
readFromParcel(source);
}
+ /**
+ * Resets this info state to the initial state.
+ * @hide
+ */
+ public void reset() {
+ taskWidth = 0;
+ taskHeight = 0;
+ screenOrientation = 0;
+ }
+
/** @hide */
public void saveToXml(XmlSerializer out) throws IOException {
out.attribute(null, ATTR_TASK_WIDTH, Integer.toString(taskWidth));
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 65c63f6951aa..4449e4fa8665 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2611,6 +2611,14 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case UPDATE_DEVICE_OWNER_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ String packageName = data.readString();
+ updateDeviceOwner(packageName);
+ reply.writeNoException();
+ return true;
+ }
+
case GET_PACKAGE_PROCESS_STATE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
String pkg = data.readString();
@@ -6155,6 +6163,18 @@ class ActivityManagerProxy implements IActivityManager
}
@Override
+ public void updateDeviceOwner(String packageName) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeString(packageName);
+ mRemote.transact(UPDATE_DEVICE_OWNER_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
+ @Override
public int getPackageProcessState(String packageName, String callingPackage)
throws RemoteException {
Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 371c92393d17..c075ed675948 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -24,8 +24,6 @@ import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentSender;
import android.graphics.SurfaceTexture;
-import android.os.Handler;
-import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Message;
import android.os.OperationCanceledException;
@@ -45,6 +43,17 @@ import android.view.WindowManager;
import dalvik.system.CloseGuard;
import java.lang.ref.WeakReference;
+import java.util.ArrayDeque;
+import java.util.concurrent.Executor;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import com.android.internal.annotations.GuardedBy;
+
/** @hide */
public class ActivityView extends ViewGroup {
@@ -53,9 +62,64 @@ public class ActivityView extends ViewGroup {
private static final int MSG_SET_SURFACE = 1;
- DisplayMetrics mMetrics = new DisplayMetrics();
+ private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
+ private static final int MINIMUM_POOL_SIZE = 1;
+ private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
+ private static final int KEEP_ALIVE = 1;
+
+ private static final ThreadFactory sThreadFactory = new ThreadFactory() {
+ private final AtomicInteger mCount = new AtomicInteger(1);
+
+ public Thread newThread(Runnable r) {
+ return new Thread(r, "ActivityView #" + mCount.getAndIncrement());
+ }
+ };
+
+ private static final BlockingQueue<Runnable> sPoolWorkQueue =
+ new LinkedBlockingQueue<Runnable>(128);
+
+ /**
+ * An {@link Executor} that can be used to execute tasks in parallel.
+ */
+ private static final Executor sExecutor = new ThreadPoolExecutor(MINIMUM_POOL_SIZE,
+ MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
+
+
+ private static class SerialExecutor implements Executor {
+ private final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
+ private Runnable mActive;
+
+ public synchronized void execute(final Runnable r) {
+ mTasks.offer(new Runnable() {
+ public void run() {
+ try {
+ r.run();
+ } finally {
+ scheduleNext();
+ }
+ }
+ });
+ if (mActive == null) {
+ scheduleNext();
+ }
+ }
+
+ protected synchronized void scheduleNext() {
+ if ((mActive = mTasks.poll()) != null) {
+ sExecutor.execute(mActive);
+ }
+ }
+ }
+
+ private final SerialExecutor mExecutor = new SerialExecutor();
+
+ private final int mDensityDpi;
private final TextureView mTextureView;
+
+ @GuardedBy("mActivityContainerLock")
private ActivityContainerWrapper mActivityContainer;
+ private Object mActivityContainerLock = new Object();
+
private Activity mActivity;
private int mWidth;
private int mHeight;
@@ -63,8 +127,6 @@ public class ActivityView extends ViewGroup {
private int mLastVisibility;
private ActivityViewCallback mActivityViewCallback;
- private HandlerThread mThread = new HandlerThread("ActivityViewThread");
- private Handler mHandler;
public ActivityView(Context context) {
this(context, null);
@@ -97,28 +159,14 @@ public class ActivityView extends ViewGroup {
+ e);
}
- mThread.start();
- mHandler = new Handler(mThread.getLooper()) {
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- if (msg.what == MSG_SET_SURFACE) {
- try {
- mActivityContainer.setSurface((Surface) msg.obj, msg.arg1, msg.arg2,
- mMetrics.densityDpi);
- } catch (RemoteException e) {
- throw new RuntimeException(
- "ActivityView: Unable to set surface of ActivityContainer. " + e);
- }
- }
- }
- };
mTextureView = new TextureView(context);
mTextureView.setSurfaceTextureListener(new ActivityViewSurfaceTextureListener());
addView(mTextureView);
WindowManager wm = (WindowManager)mActivity.getSystemService(Context.WINDOW_SERVICE);
- wm.getDefaultDisplay().getMetrics(mMetrics);
+ DisplayMetrics metrics = new DisplayMetrics();
+ wm.getDefaultDisplay().getMetrics(metrics);
+ mDensityDpi = metrics.densityDpi;
mLastVisibility = getVisibility();
@@ -131,15 +179,13 @@ public class ActivityView extends ViewGroup {
}
@Override
- protected void onVisibilityChanged(View changedView, int visibility) {
+ protected void onVisibilityChanged(View changedView, final int visibility) {
super.onVisibilityChanged(changedView, visibility);
if (mSurface != null && (visibility == View.GONE || mLastVisibility == View.GONE)) {
- Message msg = Message.obtain(mHandler, MSG_SET_SURFACE);
- msg.obj = (visibility == View.GONE) ? null : mSurface;
- msg.arg1 = mWidth;
- msg.arg2 = mHeight;
- mHandler.sendMessage(msg);
+ if (DEBUG) Log.v(TAG, "visibility changed; enqueing runnable");
+ final Surface surface = (visibility == View.GONE) ? null : mSurface;
+ setSurfaceAsync(surface, mWidth, mHeight, mDensityDpi, false);
}
mLastVisibility = visibility;
}
@@ -230,8 +276,10 @@ public class ActivityView extends ViewGroup {
Log.e(TAG, "Duplicate call to release");
return;
}
- mActivityContainer.release();
- mActivityContainer = null;
+ synchronized (mActivityContainerLock) {
+ mActivityContainer.release();
+ mActivityContainer = null;
+ }
if (mSurface != null) {
mSurface.release();
@@ -239,25 +287,39 @@ public class ActivityView extends ViewGroup {
}
mTextureView.setSurfaceTextureListener(null);
-
- mThread.quit();
}
- private void attachToSurfaceWhenReady() {
- final SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
- if (surfaceTexture == null || mSurface != null) {
- // Either not ready to attach, or already attached.
- return;
- }
-
- mSurface = new Surface(surfaceTexture);
- try {
- mActivityContainer.setSurface(mSurface, mWidth, mHeight, mMetrics.densityDpi);
- } catch (RemoteException e) {
- mSurface.release();
- mSurface = null;
- throw new RuntimeException("ActivityView: Unable to create ActivityContainer. " + e);
- }
+ private void setSurfaceAsync(final Surface surface, final int width, final int height,
+ final int densityDpi, final boolean callback) {
+ mExecutor.execute(new Runnable() {
+ public void run() {
+ try {
+ synchronized (mActivityContainerLock) {
+ if (mActivityContainer != null) {
+ mActivityContainer.setSurface(surface, width, height, densityDpi);
+ }
+ }
+ } catch (RemoteException e) {
+ throw new RuntimeException(
+ "ActivityView: Unable to set surface of ActivityContainer. ",
+ e);
+ }
+ if (callback) {
+ post(new Runnable() {
+ @Override
+ public void run() {
+ if (mActivityViewCallback != null) {
+ if (surface != null) {
+ mActivityViewCallback.onSurfaceAvailable(ActivityView.this);
+ } else {
+ mActivityViewCallback.onSurfaceDestroyed(ActivityView.this);
+ }
+ }
+ }
+ });
+ }
+ }
+ });
}
/**
@@ -308,10 +370,8 @@ public class ActivityView extends ViewGroup {
+ height);
mWidth = width;
mHeight = height;
- attachToSurfaceWhenReady();
- if (mActivityViewCallback != null) {
- mActivityViewCallback.onSurfaceAvailable(ActivityView.this);
- }
+ mSurface = new Surface(surfaceTexture);
+ setSurfaceAsync(mSurface, mWidth, mHeight, mDensityDpi, true);
}
@Override
@@ -331,15 +391,7 @@ public class ActivityView extends ViewGroup {
if (DEBUG) Log.d(TAG, "onSurfaceTextureDestroyed");
mSurface.release();
mSurface = null;
- try {
- mActivityContainer.setSurface(null, mWidth, mHeight, mMetrics.densityDpi);
- } catch (RemoteException e) {
- throw new RuntimeException(
- "ActivityView: Unable to set surface of ActivityContainer. " + e);
- }
- if (mActivityViewCallback != null) {
- mActivityViewCallback.onSurfaceDestroyed(ActivityView.this);
- }
+ setSurfaceAsync(null, mWidth, mHeight, mDensityDpi, true);
return true;
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index cf2452b05b21..b69a4802d6c7 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -518,6 +518,7 @@ public interface IActivityManager extends IInterface {
public void setVoiceKeepAwake(IVoiceInteractionSession session, boolean keepAwake)
throws RemoteException;
public void updateLockTaskPackages(int userId, String[] packages) throws RemoteException;
+ public void updateDeviceOwner(String packageName) throws RemoteException;
public int getPackageProcessState(String packageName, String callingPackage)
throws RemoteException;
@@ -880,6 +881,7 @@ public interface IActivityManager extends IInterface {
int NOTE_ALARM_FINISH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+292;
int GET_PACKAGE_PROCESS_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+293;
int SHOW_LOCK_TASK_ESCAPE_MESSAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+294;
+ int UPDATE_DEVICE_OWNER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+295;
int KEYGUARD_GOING_AWAY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+296;
int REGISTER_UID_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+297;
int UNREGISTER_UID_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+298;
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index b89c5a61ef10..8bf8dcbd1793 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -595,7 +595,7 @@ public class DevicePolicyManager {
* extra field. This will invoke a UI to bring the user through adding the profile owner admin
* to remotely control restrictions on the user.
*
- * <p>The intent must be invoked via {@link Activity#startActivityForResult} to receive the
+ * <p>The intent must be invoked via {@link Activity#startActivityForResult()} to receive the
* result of whether or not the user approved the action. If approved, the result will
* be {@link Activity#RESULT_OK} and the component will be set as an active admin as well
* as a profile owner.
@@ -2869,9 +2869,6 @@ public class DevicePolicyManager {
*/
public boolean setProfileOwner(@NonNull ComponentName admin, @Deprecated String ownerName,
int userHandle) throws IllegalArgumentException {
- if (admin == null) {
- throw new NullPointerException("admin cannot be null");
- }
if (mService != null) {
try {
if (ownerName == null) {
@@ -2887,6 +2884,42 @@ public class DevicePolicyManager {
}
/**
+ * Sets the device owner information to be shown on the lock screen.
+ *
+ * <p>If the device owner information is {@code null} or empty then the device owner info is
+ * cleared and the user owner info is shown on the lock screen if it is set.
+ *
+ * @param admin The name of the admin component to check.
+ * @param info Device owner information which will be displayed instead of the user
+ * owner info.
+ * @return Whether the device owner information has been set.
+ */
+ public boolean setDeviceOwnerLockScreenInfo(@NonNull ComponentName admin, String info) {
+ if (mService != null) {
+ try {
+ return mService.setDeviceOwnerLockScreenInfo(admin, info);
+ } catch (RemoteException re) {
+ Log.w(TAG, "Failed talking with device policy service", re);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @return The device owner information. If it is not set returns {@code null}.
+ */
+ public String getDeviceOwnerLockScreenInfo() {
+ if (mService != null) {
+ try {
+ return mService.getDeviceOwnerLockScreenInfo();
+ } catch (RemoteException re) {
+ Log.w(TAG, "Failed talking with device policy service", re);
+ }
+ }
+ return null;
+ }
+
+ /**
* Sets the enabled state of the profile. A profile should be enabled only once it is ready to
* be used. Only the profile owner can call this.
*
@@ -2996,7 +3029,7 @@ public class DevicePolicyManager {
/**
* @hide
- * @param userId The user for whom to fetch the profile owner name, if any.
+ * @param user The user for whom to fetch the profile owner name, if any.
* @return the human readable name of the organisation associated with this profile owner or
* null if one is not set.
* @throws IllegalArgumentException if the userId is invalid.
diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java
index 5a46cd5e4043..4270e16b3295 100644
--- a/core/java/android/app/admin/DevicePolicyManagerInternal.java
+++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java
@@ -80,10 +80,4 @@ public abstract class DevicePolicyManagerInternal {
* This method always returns a new {@link Bundle}.
*/
public abstract Bundle getComposedUserRestrictions(int userId, Bundle inBundle);
-
- /**
- * @return true if a package is a device admin (possibly DO or PO) running on
- * user {@code userId}.
- */
- public abstract boolean isDeviceAdminPackage(int userId, String packageName);
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 95a22eff97d4..e7e1833e9ba8 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -127,6 +127,9 @@ interface IDevicePolicyManager {
void clearProfileOwner(in ComponentName who);
boolean hasUserSetupCompleted();
+ boolean setDeviceOwnerLockScreenInfo(in ComponentName who, String deviceOwnerInfo);
+ String getDeviceOwnerLockScreenInfo();
+
boolean installCaCert(in ComponentName admin, in byte[] certBuffer);
void uninstallCaCerts(in ComponentName admin, in String[] aliases);
void enforceCanManageCaCerts(in ComponentName admin);
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 52c2f9bb4914..9c880d3591c3 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -22,7 +22,9 @@ import android.graphics.drawable.Drawable;
import android.os.Environment;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.SystemProperties;
import android.os.UserHandle;
+import android.os.storage.StorageManager;
import android.text.TextUtils;
import android.util.Printer;
@@ -469,6 +471,14 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
public static final int PRIVATE_FLAG_FORCE_DEVICE_ENCRYPTED = 1 << 5;
/**
+ * When set, assume that all components under the given app are encryption
+ * aware, unless otherwise specified.
+ *
+ * @hide
+ */
+ public static final int PRIVATE_FLAG_ENCRYPTION_AWARE = 1 << 6;
+
+ /**
* Private/hidden flags. See {@code PRIVATE_FLAG_...} constants.
* {@hide}
*/
@@ -963,7 +973,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
.getDataUserCredentialEncryptedPackageDirectory(volumeUuid, userId, packageName)
.getAbsolutePath();
- if ((privateFlags & PRIVATE_FLAG_FORCE_DEVICE_ENCRYPTED) != 0) {
+ if ((privateFlags & PRIVATE_FLAG_FORCE_DEVICE_ENCRYPTED) != 0
+ && SystemProperties.getBoolean(StorageManager.PROP_HAS_FBE, false)) {
dataDir = deviceEncryptedDataDir;
} else {
dataDir = credentialEncryptedDataDir;
@@ -1030,6 +1041,11 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
&& (flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
}
+ /** @hide */
+ public boolean isEncryptionAware() {
+ return (privateFlags & ApplicationInfo.PRIVATE_FLAG_ENCRYPTION_AWARE) != 0;
+ }
+
/**
* @hide
*/
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index f176d89925ea..838da37c365d 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2636,6 +2636,10 @@ public class PackageParser {
&& (flags & PARSE_IS_SYSTEM) != 0) {
ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_FORCE_DEVICE_ENCRYPTED;
}
+ if (sa.getBoolean(R.styleable.AndroidManifestApplication_encryptionAware, false)
+ && (flags & PARSE_IS_SYSTEM) != 0) {
+ ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ENCRYPTION_AWARE;
+ }
String str;
str = sa.getNonConfigurationString(
@@ -3236,7 +3240,8 @@ public class PackageParser {
sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0);
a.info.encryptionAware = sa.getBoolean(
- R.styleable.AndroidManifestActivity_encryptionAware, false);
+ R.styleable.AndroidManifestActivity_encryptionAware,
+ owner.applicationInfo.isEncryptionAware());
} else {
a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
a.info.configChanges = 0;
@@ -3253,7 +3258,8 @@ public class PackageParser {
}
a.info.encryptionAware = sa.getBoolean(
- R.styleable.AndroidManifestActivity_encryptionAware, false);
+ R.styleable.AndroidManifestActivity_encryptionAware,
+ owner.applicationInfo.isEncryptionAware());
}
sa.recycle();
@@ -3655,7 +3661,8 @@ public class PackageParser {
}
p.info.encryptionAware = sa.getBoolean(
- R.styleable.AndroidManifestProvider_encryptionAware, false);
+ R.styleable.AndroidManifestProvider_encryptionAware,
+ owner.applicationInfo.isEncryptionAware());
sa.recycle();
@@ -3938,7 +3945,8 @@ public class PackageParser {
}
s.info.encryptionAware = sa.getBoolean(
- R.styleable.AndroidManifestService_encryptionAware, false);
+ R.styleable.AndroidManifestService_encryptionAware,
+ owner.applicationInfo.isEncryptionAware());
sa.recycle();
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 1fc69c0bdfa4..73bb4266e649 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -3182,8 +3182,8 @@ public class Camera {
}
/**
- * Sets GPS processing method. It will store up to 32 characters
- * in JPEG EXIF header.
+ * Sets GPS processing method. The method will be stored in a UTF-8 string up to 31 bytes
+ * long, in the JPEG EXIF header.
*
* @param processing_method The processing method to get this location.
*/
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 35a1d960e22d..f61892ec6114 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -472,13 +472,13 @@ public abstract class CameraMetadata<TKey> {
* <li>The maximum available resolution for RAW_SENSOR streams
* will match either the value in
* {@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize} or
- * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</li>
+ * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.</li>
* <li>All DNG-related optional metadata entries are provided
* by the camera device.</li>
* </ul>
*
- * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
* @see CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE
+ * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
*/
public static final int REQUEST_AVAILABLE_CAPABILITIES_RAW = 3;
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 3f566eb92756..67835a0239d3 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -556,6 +556,10 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* Set a capture request field to a value. The field definitions can be
* found in {@link CaptureRequest}.
*
+ * <p>Setting a field to {@code null} will remove that field from the capture request.
+ * Unless the field is optional, removing it will likely produce an error from the camera
+ * device when the request is submitted.</p>
+ *
* @param key The metadata field to write.
* @param value The value to set the field to, which must be of a matching
* type to the key.
diff --git a/core/java/android/net/http/X509TrustManagerExtensions.java b/core/java/android/net/http/X509TrustManagerExtensions.java
index 25ef8b500cda..67293475a9e7 100644
--- a/core/java/android/net/http/X509TrustManagerExtensions.java
+++ b/core/java/android/net/http/X509TrustManagerExtensions.java
@@ -20,6 +20,9 @@ import android.annotation.SystemApi;
import com.android.org.conscrypt.TrustManagerImpl;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.List;
@@ -36,7 +39,11 @@ import javax.net.ssl.X509TrustManager;
*/
public class X509TrustManagerExtensions {
- final TrustManagerImpl mDelegate;
+ private final TrustManagerImpl mDelegate;
+ // Methods to use when mDelegate is not a TrustManagerImpl and duck typing is being used.
+ private final X509TrustManager mTrustManager;
+ private final Method mCheckServerTrusted;
+ private final Method mIsUserAddedCertificate;
/**
* Constructs a new X509TrustManagerExtensions wrapper.
@@ -47,10 +54,31 @@ public class X509TrustManagerExtensions {
public X509TrustManagerExtensions(X509TrustManager tm) throws IllegalArgumentException {
if (tm instanceof TrustManagerImpl) {
mDelegate = (TrustManagerImpl) tm;
- } else {
- mDelegate = null;
- throw new IllegalArgumentException("tm is an instance of " + tm.getClass().getName() +
- " which is not a supported type of X509TrustManager");
+ mTrustManager = null;
+ mCheckServerTrusted = null;
+ mIsUserAddedCertificate = null;
+ return;
+ }
+ // Use duck typing if possible.
+ mDelegate = null;
+ mTrustManager = tm;
+ // Check that the hostname aware checkServerTrusted is present.
+ try {
+ mCheckServerTrusted = tm.getClass().getMethod("checkServerTrusted",
+ X509Certificate[].class,
+ String.class,
+ String.class);
+ } catch (NoSuchMethodException e) {
+ throw new IllegalArgumentException("Required method"
+ + " checkServerTrusted(X509Certificate[], String, String, String) missing");
+ }
+ // Check that isUserAddedCertificate is present.
+ try {
+ mIsUserAddedCertificate = tm.getClass().getMethod("isUserAddedCertificate",
+ X509Certificate.class);
+ } catch (NoSuchMethodException e) {
+ throw new IllegalArgumentException(
+ "Required method isUserAddedCertificate(X509Certificate) missing");
}
}
@@ -66,7 +94,24 @@ public class X509TrustManagerExtensions {
*/
public List<X509Certificate> checkServerTrusted(X509Certificate[] chain, String authType,
String host) throws CertificateException {
- return mDelegate.checkServerTrusted(chain, authType, host);
+ if (mDelegate != null) {
+ return mDelegate.checkServerTrusted(chain, authType, host);
+ } else {
+ try {
+ return (List<X509Certificate>) mCheckServerTrusted.invoke(mTrustManager, chain,
+ authType, host);
+ } catch (IllegalAccessException e) {
+ throw new CertificateException("Failed to call checkServerTrusted", e);
+ } catch (InvocationTargetException e) {
+ if (e.getCause() instanceof CertificateException) {
+ throw (CertificateException) e.getCause();
+ }
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ }
+ throw new CertificateException("checkServerTrusted failed", e.getCause());
+ }
+ }
}
/**
@@ -80,7 +125,21 @@ public class X509TrustManagerExtensions {
* otherwise.
*/
public boolean isUserAddedCertificate(X509Certificate cert) {
- return mDelegate.isUserAddedCertificate(cert);
+ if (mDelegate != null) {
+ return mDelegate.isUserAddedCertificate(cert);
+ } else {
+ try {
+ return (Boolean) mIsUserAddedCertificate.invoke(mTrustManager, cert);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException("Failed to call isUserAddedCertificate", e);
+ } catch (InvocationTargetException e) {
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ } else {
+ throw new RuntimeException("isUserAddedCertificate failed", e.getCause());
+ }
+ }
+ }
}
/**
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index 5d45ade4e041..d19c7c979501 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -1198,29 +1198,97 @@ public interface IMountService extends IInterface {
}
@Override
- public void createNewUserDir(int userHandle, String path) throws RemoteException {
+ public void createUserKey(int userId, int serialNumber) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
- _data.writeInt(userHandle);
- _data.writeString(path);
- mRemote.transact(Stub.TRANSACTION_createNewUserDir, _data, _reply, 0);
+ _data.writeInt(userId);
+ _data.writeInt(serialNumber);
+ mRemote.transact(Stub.TRANSACTION_createUserKey, _data, _reply, 0);
+ _reply.readException();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ }
+
+ @Override
+ public void destroyUserKey(int userId) throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ _data.writeInt(userId);
+ mRemote.transact(Stub.TRANSACTION_destroyUserKey, _data, _reply, 0);
+ _reply.readException();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ }
+
+ @Override
+ public void unlockUserKey(int userId, int serialNumber, byte[] token) throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ _data.writeInt(userId);
+ _data.writeInt(serialNumber);
+ _data.writeByteArray(token);
+ mRemote.transact(Stub.TRANSACTION_unlockUserKey, _data, _reply, 0);
+ _reply.readException();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ }
+
+ @Override
+ public void lockUserKey(int userId) throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ _data.writeInt(userId);
+ mRemote.transact(Stub.TRANSACTION_lockUserKey, _data, _reply, 0);
+ _reply.readException();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ }
+
+ @Override
+ public boolean isUserKeyUnlocked(int userId) throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ boolean _result;
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ _data.writeInt(userId);
+ mRemote.transact(Stub.TRANSACTION_isUserKeyUnlocked, _data, _reply, 0);
_reply.readException();
+ _result = 0 != _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
+ return _result;
}
@Override
- public void deleteUserKey(int userHandle) throws RemoteException {
+ public void prepareUserStorage(String volumeUuid, int userId, int serialNumber)
+ throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
- _data.writeInt(userHandle);
- mRemote.transact(Stub.TRANSACTION_deleteUserKey, _data, _reply, 0);
+ _data.writeString(volumeUuid);
+ _data.writeInt(userId);
+ _data.writeInt(serialNumber);
+ mRemote.transact(Stub.TRANSACTION_prepareUserStorage, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
@@ -1359,13 +1427,17 @@ public interface IMountService extends IInterface {
static final int TRANSACTION_benchmark = IBinder.FIRST_CALL_TRANSACTION + 59;
static final int TRANSACTION_setDebugFlags = IBinder.FIRST_CALL_TRANSACTION + 60;
- static final int TRANSACTION_createNewUserDir = IBinder.FIRST_CALL_TRANSACTION + 62;
+ static final int TRANSACTION_createUserKey = IBinder.FIRST_CALL_TRANSACTION + 61;
+ static final int TRANSACTION_destroyUserKey = IBinder.FIRST_CALL_TRANSACTION + 62;
- static final int TRANSACTION_deleteUserKey = IBinder.FIRST_CALL_TRANSACTION + 63;
+ static final int TRANSACTION_unlockUserKey = IBinder.FIRST_CALL_TRANSACTION + 63;
+ static final int TRANSACTION_lockUserKey = IBinder.FIRST_CALL_TRANSACTION + 64;
+ static final int TRANSACTION_isUserKeyUnlocked = IBinder.FIRST_CALL_TRANSACTION + 65;
- static final int TRANSACTION_isPerUserEncryptionEnabled = IBinder.FIRST_CALL_TRANSACTION + 64;
+ static final int TRANSACTION_prepareUserStorage = IBinder.FIRST_CALL_TRANSACTION + 66;
- static final int TRANSACTION_isConvertibleToFBE = IBinder.FIRST_CALL_TRANSACTION + 65;
+ static final int TRANSACTION_isPerUserEncryptionEnabled = IBinder.FIRST_CALL_TRANSACTION + 67;
+ static final int TRANSACTION_isConvertibleToFBE = IBinder.FIRST_CALL_TRANSACTION + 68;
/**
* Cast an IBinder object into an IMountService interface, generating a
@@ -1929,18 +2001,51 @@ public interface IMountService extends IInterface {
reply.writeNoException();
return true;
}
- case TRANSACTION_createNewUserDir: {
+ case TRANSACTION_createUserKey: {
data.enforceInterface(DESCRIPTOR);
- int userHandle = data.readInt();
- String path = data.readString();
- createNewUserDir(userHandle, path);
+ int userId = data.readInt();
+ int serialNumber = data.readInt();
+ createUserKey(userId, serialNumber);
+ reply.writeNoException();
+ return true;
+ }
+ case TRANSACTION_destroyUserKey: {
+ data.enforceInterface(DESCRIPTOR);
+ int userId = data.readInt();
+ destroyUserKey(userId);
+ reply.writeNoException();
+ return true;
+ }
+ case TRANSACTION_unlockUserKey: {
+ data.enforceInterface(DESCRIPTOR);
+ int userId = data.readInt();
+ int serialNumber = data.readInt();
+ byte[] token = data.createByteArray();
+ unlockUserKey(userId, serialNumber, token);
reply.writeNoException();
return true;
}
- case TRANSACTION_deleteUserKey: {
+ case TRANSACTION_lockUserKey: {
data.enforceInterface(DESCRIPTOR);
- int userHandle = data.readInt();
- deleteUserKey(userHandle);
+ int userId = data.readInt();
+ lockUserKey(userId);
+ reply.writeNoException();
+ return true;
+ }
+ case TRANSACTION_isUserKeyUnlocked: {
+ data.enforceInterface(DESCRIPTOR);
+ int userId = data.readInt();
+ boolean result = isUserKeyUnlocked(userId);
+ reply.writeNoException();
+ reply.writeInt(result ? 1 : 0);
+ return true;
+ }
+ case TRANSACTION_prepareUserStorage: {
+ data.enforceInterface(DESCRIPTOR);
+ String volumeUuid = data.readString();
+ int userId = data.readInt();
+ int serialNumber = data.readInt();
+ prepareUserStorage(volumeUuid, userId, serialNumber);
reply.writeNoException();
return true;
}
@@ -1948,7 +2053,7 @@ public interface IMountService extends IInterface {
data.enforceInterface(DESCRIPTOR);
boolean result = isPerUserEncryptionEnabled();
reply.writeNoException();
- reply.writeInt((result ? 1 : 0));
+ reply.writeInt(result ? 1 : 0);
return true;
}
}
@@ -2263,24 +2368,15 @@ public interface IMountService extends IInterface {
public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback)
throws RemoteException;
- /**
- * Creates the user data directory, possibly encrypted
- * @param userHandle Handle of the user whose directory we are creating
- * @param path Path at which to create the directory.
- */
- public void createNewUserDir(int userHandle, String path)
- throws RemoteException;
+ public void createUserKey(int userId, int serialNumber) throws RemoteException;
+ public void destroyUserKey(int userId) throws RemoteException;
- /**
- * Securely delete the user's encryption key
- * @param userHandle Handle of the user whose key we are deleting
- */
- public void deleteUserKey(int userHandle)
- throws RemoteException;
+ public void unlockUserKey(int userId, int serialNumber, byte[] token) throws RemoteException;
+ public void lockUserKey(int userId) throws RemoteException;
+ public boolean isUserKeyUnlocked(int userId) throws RemoteException;
- /**
- * Returns whether the current encryption type is per user.
- */
- public boolean isPerUserEncryptionEnabled()
- throws RemoteException;
+ public void prepareUserStorage(String volumeUuid, int userId, int serialNumber)
+ throws RemoteException;
+
+ public boolean isPerUserEncryptionEnabled() throws RemoteException;
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 2ca0b206ef7b..27df46d7ee0e 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -76,7 +76,11 @@ public class StorageManager {
/** {@hide} */
public static final String PROP_HAS_ADOPTABLE = "vold.has_adoptable";
/** {@hide} */
+ public static final String PROP_HAS_FBE = "vold.has_fbe";
+ /** {@hide} */
public static final String PROP_FORCE_ADOPTABLE = "persist.fw.force_adoptable";
+ /** {@hide} */
+ public static final String PROP_EMULATE_FBE = "vold.emulate_fbe";
/** {@hide} */
public static final String UUID_PRIVATE_INTERNAL = null;
@@ -85,6 +89,8 @@ public class StorageManager {
/** {@hide} */
public static final int DEBUG_FORCE_ADOPTABLE = 1 << 0;
+ /** {@hide} */
+ public static final int DEBUG_EMULATE_FBE = 1 << 1;
/** {@hide} */
public static final int FLAG_FOR_WRITE = 1 << 0;
@@ -960,18 +966,54 @@ public class StorageManager {
}
/** {@hide} */
- public void createNewUserDir(int userHandle, File path) {
+ public void createUserKey(int userId, int serialNumber) {
+ try {
+ mMountService.createUserKey(userId, serialNumber);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /** {@hide} */
+ public void destroyUserKey(int userId) {
+ try {
+ mMountService.destroyUserKey(userId);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /** {@hide} */
+ public void unlockUserKey(int userId, int serialNumber, byte[] token) {
+ try {
+ mMountService.unlockUserKey(userId, serialNumber, token);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /** {@hide} */
+ public void lockUserKey(int userId) {
+ try {
+ mMountService.lockUserKey(userId);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /** {@hide} */
+ public void prepareUserStorage(String volumeUuid, int userId, int serialNumber) {
try {
- mMountService.createNewUserDir(userHandle, path.getAbsolutePath());
+ mMountService.prepareUserStorage(volumeUuid, userId, serialNumber);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/** {@hide} */
- public void deleteUserKey(int userHandle) {
+ public boolean isUserKeyUnlocked(int userId) {
try {
- mMountService.deleteUserKey(userHandle);
+ return mMountService.isUserKeyUnlocked(userId);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
diff --git a/core/java/android/preference/PreferenceFragment.java b/core/java/android/preference/PreferenceFragment.java
index db04c7125adc..3e496b6eb550 100644
--- a/core/java/android/preference/PreferenceFragment.java
+++ b/core/java/android/preference/PreferenceFragment.java
@@ -23,14 +23,15 @@ import android.app.Fragment;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewGroup;
import android.view.View.OnKeyListener;
+import android.view.ViewGroup;
import android.widget.ListView;
/**
@@ -179,6 +180,27 @@ public abstract class PreferenceFragment extends Fragment implements
}
@Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ TypedArray a = getActivity().obtainStyledAttributes(null,
+ com.android.internal.R.styleable.PreferenceFragment,
+ com.android.internal.R.attr.preferenceFragmentStyle,
+ 0);
+
+ ListView lv = (ListView) view.findViewById(android.R.id.list);
+ if (lv != null) {
+ Drawable divider =
+ a.getDrawable(com.android.internal.R.styleable.PreferenceFragment_divider);
+ if (divider != null) {
+ lv.setDivider(divider);
+ }
+ }
+
+ a.recycle();
+ }
+
+ @Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
diff --git a/core/java/android/preference/SwitchPreference.java b/core/java/android/preference/SwitchPreference.java
index 9c3cefc33a7c..aa8674e2b608 100644
--- a/core/java/android/preference/SwitchPreference.java
+++ b/core/java/android/preference/SwitchPreference.java
@@ -122,7 +122,7 @@ public class SwitchPreference extends TwoStatePreference {
protected void onBindView(View view) {
super.onBindView(view);
- View checkableView = view.findViewById(com.android.internal.R.id.switchWidget);
+ View checkableView = view.findViewById(com.android.internal.R.id.switch_widget);
if (checkableView != null && checkableView instanceof Checkable) {
if (checkableView instanceof Switch) {
final Switch switchView = (Switch) checkableView;
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index 90d30d637b62..2afbb99b3a26 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -60,7 +60,7 @@ public final class PrintAttributes implements Parcelable {
private Margins mMinMargins;
private int mColorMode;
- private int mDuplexMode = DUPLEX_MODE_NONE;
+ private int mDuplexMode;
PrintAttributes() {
/* hide constructor */
@@ -403,7 +403,7 @@ public final class PrintAttributes implements Parcelable {
mResolution = null;
mMinMargins = null;
mColorMode = 0;
- mDuplexMode = DUPLEX_MODE_NONE;
+ mDuplexMode = 0;
}
/**
@@ -1427,10 +1427,6 @@ public final class PrintAttributes implements Parcelable {
/**
* Creates a new {@link PrintAttributes} instance.
- * <p>
- * If you do not specify a duplex mode, the default
- * {@link #DUPLEX_MODE_NONE} will be used.
- * </p>
*
* @return The new instance.
*/
diff --git a/core/java/android/security/net/config/NetworkSecurityConfig.java b/core/java/android/security/net/config/NetworkSecurityConfig.java
index 503854ed64ff..8906f9b670d4 100644
--- a/core/java/android/security/net/config/NetworkSecurityConfig.java
+++ b/core/java/android/security/net/config/NetworkSecurityConfig.java
@@ -41,7 +41,7 @@ public final class NetworkSecurityConfig {
private final List<CertificatesEntryRef> mCertificatesEntryRefs;
private Set<TrustAnchor> mAnchors;
private final Object mAnchorsLock = new Object();
- private X509TrustManager mTrustManager;
+ private NetworkSecurityTrustManager mTrustManager;
private final Object mTrustManagerLock = new Object();
private NetworkSecurityConfig(boolean cleartextTrafficPermitted, boolean hstsEnforced,
@@ -78,7 +78,7 @@ public final class NetworkSecurityConfig {
return mPins;
}
- public X509TrustManager getTrustManager() {
+ public NetworkSecurityTrustManager getTrustManager() {
synchronized(mTrustManagerLock) {
if (mTrustManager == null) {
mTrustManager = new NetworkSecurityTrustManager(this);
diff --git a/core/java/android/security/net/config/NetworkSecurityTrustManager.java b/core/java/android/security/net/config/NetworkSecurityTrustManager.java
index e69082d3deec..7f5b3ca27bf4 100644
--- a/core/java/android/security/net/config/NetworkSecurityTrustManager.java
+++ b/core/java/android/security/net/config/NetworkSecurityTrustManager.java
@@ -71,9 +71,28 @@ public class NetworkSecurityTrustManager implements X509TrustManager {
@Override
public void checkServerTrusted(X509Certificate[] certs, String authType)
throws CertificateException {
- List<X509Certificate> trustedChain =
- mDelegate.checkServerTrusted(certs, authType, (String) null);
+ checkServerTrusted(certs, authType, null);
+ }
+
+ /**
+ * Hostname aware version of {@link #checkServerTrusted(X509Certificate[], String)}.
+ * This interface is used by conscrypt and android.net.http.X509TrustManagerExtensions do not
+ * modify without modifying those callers.
+ */
+ public List<X509Certificate> checkServerTrusted(X509Certificate[] certs, String authType,
+ String host) throws CertificateException {
+ List<X509Certificate> trustedChain = mDelegate.checkServerTrusted(certs, authType, host);
checkPins(trustedChain);
+ return trustedChain;
+ }
+
+ /**
+ * Check if the provided certificate is a user added certificate authority.
+ * This is required by android.net.http.X509TrustManagerExtensions.
+ */
+ public boolean isUserAddedCertificate(X509Certificate cert) {
+ // TODO: Figure out the right way to handle this, and if it is still even used.
+ return false;
}
private void checkPins(List<X509Certificate> chain) throws CertificateException {
diff --git a/core/java/android/security/net/config/RootTrustManager.java b/core/java/android/security/net/config/RootTrustManager.java
index 1338b9ff97d4..b87bf1fe0695 100644
--- a/core/java/android/security/net/config/RootTrustManager.java
+++ b/core/java/android/security/net/config/RootTrustManager.java
@@ -18,6 +18,7 @@ package android.security.net.config;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
+import java.util.List;
import javax.net.ssl.X509TrustManager;
@@ -61,10 +62,24 @@ public class RootTrustManager implements X509TrustManager {
config.getTrustManager().checkServerTrusted(certs, authType);
}
- public void checkServerTrusted(X509Certificate[] certs, String authType, String hostname)
- throws CertificateException {
+ /**
+ * Hostname aware version of {@link #checkServerTrusted(X509Certificate[], String)}.
+ * This interface is used by conscrypt and android.net.http.X509TrustManagerExtensions do not
+ * modify without modifying those callers.
+ */
+ public List<X509Certificate> checkServerTrusted(X509Certificate[] certs, String authType,
+ String hostname) throws CertificateException {
NetworkSecurityConfig config = mConfig.getConfigForHostname(hostname);
- config.getTrustManager().checkServerTrusted(certs, authType);
+ return config.getTrustManager().checkServerTrusted(certs, authType, hostname);
+ }
+
+ /**
+ * Check if the provided certificate is a user added certificate authority.
+ * This is required by android.net.http.X509TrustManagerExtensions.
+ */
+ public boolean isUserAddedCertificate(X509Certificate cert) {
+ // TODO: Figure out the right way to handle this, and if it is still even used.
+ return false;
}
@Override
diff --git a/core/java/android/util/PathParser.java b/core/java/android/util/PathParser.java
index cebb8f0abcb4..f09947904478 100644
--- a/core/java/android/util/PathParser.java
+++ b/core/java/android/util/PathParser.java
@@ -27,21 +27,21 @@ public class PathParser {
static final String LOGTAG = PathParser.class.getSimpleName();
/**
- * @param pathData The string representing a path, the same as "d" string in svg file.
+ * @param pathString The string representing a path, the same as "d" string in svg file.
* @return the generated Path object.
*/
- public static Path createPathFromPathData(String pathData) {
+ public static Path createPathFromPathData(String pathString) {
+ if (pathString == null) {
+ throw new IllegalArgumentException("Path string can not be null.");
+ }
Path path = new Path();
- PathDataNode[] nodes = createNodesFromPathData(pathData);
- if (nodes != null) {
- try {
- PathDataNode.nodesToPath(nodes, path);
- } catch (RuntimeException e) {
- throw new RuntimeException("Error in parsing " + pathData, e);
- }
- return path;
+ boolean hasValidPathData = nParseStringForPath(path.mNativePath, pathString,
+ pathString.length());
+ if (!hasValidPathData) {
+ throw new IllegalArgumentException("Path string: " + pathString +
+ " does not contain valid path data");
}
- return null;
+ return path;
}
/**
@@ -701,4 +701,7 @@ public class PathParser {
}
}
}
+
+ private static native boolean nParseStringForPath(long pathPtr, String pathString,
+ int stringLength);
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 66b05a20492f..461506bd6253 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -12968,10 +12968,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mPrivateFlags |= PFLAG_DIRTY;
- // Release any resources in-case we don't end up drawing again
- // as anything cached is no longer valid
- resetDisplayList();
-
if (invalidateCache) {
mPrivateFlags |= PFLAG_INVALIDATED;
mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index d80c6a35836f..625ed380efd5 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1625,7 +1625,7 @@ public final class ViewRootImpl implements ViewParent,
if (mPendingConfiguration.seq != 0) {
if (DEBUG_CONFIGURATION) Log.v(TAG, "Visible with new config: "
+ mPendingConfiguration);
- updateConfiguration(mPendingConfiguration, !mFirst);
+ updateConfiguration(new Configuration(mPendingConfiguration), !mFirst);
mPendingConfiguration.seq = 0;
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 2fabe33ddf39..2983053ab3ff 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -2705,11 +2705,22 @@ public class Editor {
mIsShowingUp = false;
}
- private class SuggestionInfo {
+ private final class SuggestionInfo {
int suggestionStart, suggestionEnd; // range of actual suggestion within text
- SuggestionSpan suggestionSpan; // the SuggestionSpan that this TextView represents
+
+ // the SuggestionSpan that this TextView represents
+ @Nullable
+ SuggestionSpan suggestionSpan;
+
int suggestionIndex; // the index of this suggestion inside suggestionSpan
- SpannableStringBuilder text = new SpannableStringBuilder();
+
+ @Nullable
+ final SpannableStringBuilder text = new SpannableStringBuilder();
+
+ void clear() {
+ suggestionSpan = null;
+ text.clear();
+ }
}
private class SuggestionAdapter extends BaseAdapter {
@@ -2863,9 +2874,11 @@ public class Editor {
return Math.min(positionY, displayMetrics.heightPixels - height);
}
- @Override
- public void hide() {
- super.hide();
+ private void hideWithCleanUp() {
+ for (final SuggestionInfo info : mSuggestionInfos) {
+ info.clear();
+ }
+ hide();
}
private boolean updateSuggestions() {
@@ -3017,7 +3030,7 @@ public class Editor {
}
mTextView.deleteText_internal(spanUnionStart, spanUnionEnd);
}
- hide();
+ hideWithCleanUp();
return;
}
@@ -3025,7 +3038,7 @@ public class Editor {
final int spanEnd = editable.getSpanEnd(suggestionInfo.suggestionSpan);
if (spanStart < 0 || spanEnd <= spanStart) {
// Span has been removed
- hide();
+ hideWithCleanUp();
return;
}
@@ -3100,7 +3113,7 @@ public class Editor {
mTextView.setCursorPosition_internal(newCursorPosition, newCursorPosition);
}
- hide();
+ hideWithCleanUp();
}
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index c54a574dfcb8..b5d994dc7c81 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -3975,6 +3975,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
((Editable) mText).append(text, start, end);
+
+ if (mAutoLinkMask != 0) {
+ boolean linksWereAdded = Linkify.addLinks((Spannable) mText, mAutoLinkMask);
+ // Do not change the movement method for text that support text selection as it
+ // would prevent an arbitrary cursor displacement.
+ if (linksWereAdded && mLinksClickable && !textCanBeSelected()) {
+ setMovementMethod(LinkMovementMethod.getInstance());
+ }
+ }
}
private void updateTextColors() {
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index f190d8cf9f0a..e8970bc9bbb1 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -144,6 +144,13 @@ public class ArrayUtils {
}
/**
+ * Checks if given array is null or has zero elements.
+ */
+ public static boolean isEmpty(byte[] array) {
+ return array == null || array.length == 0;
+ }
+
+ /**
* Checks that value is present as at least one of the elements of the array.
* @param array the array to check in
* @param value the value to check for
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 60ef4a47b230..889c7b362d78 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -126,6 +126,8 @@ public class LockPatternUtils {
private static final String LOCK_SCREEN_OWNER_INFO_ENABLED =
Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
+ private static final String LOCK_SCREEN_DEVICE_OWNER_INFO = "lockscreen.device_owner_info";
+
private static final String ENABLED_TRUST_AGENTS = "lockscreen.enabledtrustagents";
// Maximum allowed number of repeated or ordered characters in a sequence before we'll
@@ -578,6 +580,29 @@ public class LockPatternUtils {
}
/**
+ * Sets the device owner information. If the information is {@code null} or empty then the
+ * device owner info is cleared.
+ *
+ * @param info Device owner information which will be displayed instead of the user
+ * owner info.
+ */
+ public void setDeviceOwnerInfo(String info) {
+ if (info != null && info.isEmpty()) {
+ info = null;
+ }
+
+ setString(LOCK_SCREEN_DEVICE_OWNER_INFO, info, UserHandle.USER_SYSTEM);
+ }
+
+ public String getDeviceOwnerInfo() {
+ return getString(LOCK_SCREEN_DEVICE_OWNER_INFO, UserHandle.USER_SYSTEM);
+ }
+
+ public boolean isDeviceOwnerInfoEnabled() {
+ return getDeviceOwnerInfo() != null;
+ }
+
+ /**
* Compute the password quality from the given password string.
*/
static public int computePasswordQuality(String password) {
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index ecee2b2d7cb5..4d648cea4675 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -89,6 +89,7 @@ LOCAL_SRC_FILES:= \
android_util_Binder.cpp \
android_util_EventLog.cpp \
android_util_Log.cpp \
+ android_util_PathParser.cpp \
android_util_Process.cpp \
android_util_StringBlock.cpp \
android_util_XmlBlock.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 4e93730c1554..815d3302ee0b 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -110,6 +110,7 @@ namespace android {
extern int register_android_content_AssetManager(JNIEnv* env);
extern int register_android_util_EventLog(JNIEnv* env);
extern int register_android_util_Log(JNIEnv* env);
+extern int register_android_util_PathParser(JNIEnv* env);
extern int register_android_content_StringBlock(JNIEnv* env);
extern int register_android_content_XmlBlock(JNIEnv* env);
extern int register_android_graphics_Canvas(JNIEnv* env);
@@ -1300,6 +1301,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_os_SystemClock),
REG_JNI(register_android_util_EventLog),
REG_JNI(register_android_util_Log),
+ REG_JNI(register_android_util_PathParser),
REG_JNI(register_android_content_AssetManager),
REG_JNI(register_android_content_StringBlock),
REG_JNI(register_android_content_XmlBlock),
diff --git a/core/jni/android_util_PathParser.cpp b/core/jni/android_util_PathParser.cpp
new file mode 100644
index 000000000000..bf6ffc5487d2
--- /dev/null
+++ b/core/jni/android_util_PathParser.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#include "jni.h"
+
+#include <PathParser.h>
+#include <SkPath.h>
+
+#include "core_jni_helpers.h"
+
+namespace android {
+
+static bool parseStringForPath(JNIEnv* env, jobject, jlong skPathHandle, jstring inputPathStr,
+ jint strLength) {
+ const char* pathString = env->GetStringUTFChars(inputPathStr, NULL);
+ SkPath* skPath = reinterpret_cast<SkPath*>(skPathHandle);
+ bool hasValidData = android::uirenderer::PathParser::parseStringForSkPath(skPath, pathString,
+ strLength);
+ env->ReleaseStringUTFChars(inputPathStr, pathString);
+ return hasValidData;
+}
+
+static const JNINativeMethod gMethods[] = {
+ {"nParseStringForPath", "(JLjava/lang/String;I)Z", (void*)parseStringForPath}
+};
+
+int register_android_util_PathParser(JNIEnv* env) {
+ return RegisterMethodsOrDie(env, "android/util/PathParser", gMethods, NELEM(gMethods));
+}
+};
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 561bcbc26d0c..6bdf71bdba6f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1683,6 +1683,10 @@
<permission android:name="android.permission.MOUNT_FORMAT_FILESYSTEMS"
android:protectionLevel="system|signature" />
+ <!-- @hide -->
+ <permission android:name="android.permission.STORAGE_INTERNAL"
+ android:protectionLevel="signature" />
+
<!-- Allows access to ASEC non-destructive API calls
@hide -->
<permission android:name="android.permission.ASEC_ACCESS"
@@ -2702,7 +2706,9 @@
android:killAfterRestore="false"
android:icon="@drawable/ic_launcher_android"
android:supportsRtl="true"
- android:theme="@style/Theme.Material.DayNight.DarkActionBar">
+ android:theme="@style/Theme.Material.DayNight.DarkActionBar"
+ android:forceDeviceEncrypted="true"
+ android:encryptionAware="true">
<activity android:name="com.android.internal.app.ChooserActivity"
android:theme="@style/Theme.DeviceDefault.Resolver"
android:finishOnCloseSystemDialogs="true"
diff --git a/core/res/res/layout/preference_list_fragment.xml b/core/res/res/layout/preference_list_fragment.xml
index f073c3379727..fc53a1a061b2 100644
--- a/core/res/res/layout/preference_list_fragment.xml
+++ b/core/res/res/layout/preference_list_fragment.xml
@@ -24,18 +24,23 @@
android:background="@android:color/transparent"
android:layout_removeBorders="true">
- <ListView android:id="@android:id/list"
- style="?attr/preferenceFragmentListStyle"
+ <FrameLayout
+ android:id="@android:id/list_container"
android:layout_width="match_parent"
android:layout_height="0px"
- android:layout_weight="1"
- android:paddingTop="0dip"
- android:paddingBottom="@dimen/preference_fragment_padding_bottom"
- android:scrollbarStyle="@integer/preference_fragment_scrollbarStyle"
- android:clipToPadding="false"
- android:drawSelectorOnTop="false"
- android:cacheColorHint="@android:color/transparent"
- android:scrollbarAlwaysDrawVerticalTrack="true" />
+ android:layout_weight="1">
+ <ListView android:id="@android:id/list"
+ style="?attr/preferenceFragmentListStyle"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingTop="0dip"
+ android:paddingBottom="@dimen/preference_fragment_padding_bottom"
+ android:scrollbarStyle="@integer/preference_fragment_scrollbarStyle"
+ android:clipToPadding="false"
+ android:drawSelectorOnTop="false"
+ android:cacheColorHint="@android:color/transparent"
+ android:scrollbarAlwaysDrawVerticalTrack="true" />
+ </FrameLayout>
<TextView android:id="@android:id/empty"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/preference_list_fragment_material.xml b/core/res/res/layout/preference_list_fragment_material.xml
index 62bdffd3937e..e411c0e92a18 100644
--- a/core/res/res/layout/preference_list_fragment_material.xml
+++ b/core/res/res/layout/preference_list_fragment_material.xml
@@ -24,18 +24,23 @@
android:background="@android:color/transparent"
android:layout_removeBorders="true">
- <ListView android:id="@android:id/list"
- style="?attr/preferenceFragmentListStyle"
+ <FrameLayout
+ android:id="@android:id/list_container"
android:layout_width="match_parent"
android:layout_height="0px"
- android:layout_weight="1"
- android:paddingTop="0dip"
- android:paddingBottom="@dimen/preference_fragment_padding_bottom"
- android:scrollbarStyle="@integer/preference_fragment_scrollbarStyle"
- android:clipToPadding="false"
- android:drawSelectorOnTop="false"
- android:cacheColorHint="@android:color/transparent"
- android:scrollbarAlwaysDrawVerticalTrack="true" />
+ android:layout_weight="1">
+ <ListView android:id="@android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingTop="0dip"
+ android:paddingBottom="@dimen/preference_fragment_padding_bottom"
+ style="?attr/preferenceFragmentListStyle"
+ android:scrollbarStyle="@integer/preference_fragment_scrollbarStyle"
+ android:clipToPadding="false"
+ android:drawSelectorOnTop="false"
+ android:cacheColorHint="@android:color/transparent"
+ android:scrollbarAlwaysDrawVerticalTrack="true" />
+ </FrameLayout>
<TextView android:id="@android:id/empty"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/preference_widget_switch.xml b/core/res/res/layout/preference_widget_switch.xml
index 25e8aa65d13a..80c572bb7c01 100644
--- a/core/res/res/layout/preference_widget_switch.xml
+++ b/core/res/res/layout/preference_widget_switch.xml
@@ -17,7 +17,7 @@
<!-- Layout used by SwitchPreference for the switch widget style. This is inflated
inside android.R.layout.preference. -->
<Switch xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+android:id/switchWidget"
+ android:id="@+android:id/switch_widget"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="false"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index d7dd3ec92a56..50cf30262f69 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -7714,6 +7714,7 @@ i
<declare-styleable name="PreferenceFragment">
<!-- The layout for the PreferenceFragment. This should rarely need to be changed. -->
<attr name="layout" />
+ <attr name="divider" />
</declare-styleable>
<!-- Base attributes available to PreferenceActivity. -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 184f2ab96a8c..e3769031810e 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1283,6 +1283,7 @@
<attr name="multiArch" />
<attr name="extractNativeLibs" />
<attr name="forceDeviceEncrypted" format="boolean" />
+ <attr name="encryptionAware" />
</declare-styleable>
<!-- The <code>permission</code> tag declares a security permission that can be
used to control access from other packages to specific components or
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 76f70629c5ac..9c75b7aa701b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1530,8 +1530,8 @@
<!-- If the time difference is greater than this threshold in milliseconds,
then update the time. -->
<integer name="config_ntpThreshold">5000</integer>
- <!-- Timeout to wait for NTP server response. -->
- <integer name="config_ntpTimeout">20000</integer>
+ <!-- Timeout to wait for NTP server response in milliseconds. -->
+ <integer name="config_ntpTimeout">5000</integer>
<!-- Default network policy warning threshold, in megabytes. -->
<integer name="config_networkPolicyDefaultWarning">2048</integer>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 695dafac40b6..9d5e5ac7753b 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -23,12 +23,14 @@
<item type="id" name="empty" />
<item type="id" name="hint" />
<item type="id" name="icon" />
+ <item type="id" name="icon_frame" />
<item type="id" name="icon_badge" />
<item type="id" name="icon1" />
<item type="id" name="icon2" />
<item type="id" name="input" />
<item type="id" name="left_icon" />
<item type="id" name="list" />
+ <item type="id" name="list_container" />
<item type="id" name="menu" />
<item type="id" name="message" />
<item type="id" name="primary" />
@@ -48,6 +50,7 @@
<item type="id" name="lock_screen" />
<item type="id" name="edit" />
<item type="id" name="widget_frame" />
+ <item type="id" name="switch_widget" />
<item type="id" name="button1" />
<item type="id" name="button2" />
<item type="id" name="button3" />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 037f1c43d745..54e43c8e3e7c 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2679,6 +2679,9 @@
<public type="attr" name="contextPopupMenuStyle" />
<public type="attr" name="textAppearancePopupMenuHeader" />
<public type="attr" name="windowBackgroundFallback" />
+ <public type="attr" name="forceDeviceEncrypted" />
+ <public type="attr" name="encryptionAware" />
+ <public type="attr" name="preferenceFragmentStyle" />
<public type="style" name="Theme.Material.DayNight" />
<public type="style" name="Theme.Material.DayNight.DarkActionBar" />
@@ -2699,5 +2702,8 @@
<public type="style" name="Theme.Material.DayNight.DialogWhenLarge.DarkActionBar" />
<public type="id" name="accessibilityActionSetProgress" />
+ <public type="id" name="icon_frame" />
+ <public type="id" name="list_container" />
+ <public type="id" name="switch_widget" />
</resources>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 58640eb2ef55..4b2a4518b36c 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -40,6 +40,7 @@ please see styles_device_defaults.xml.
<item name="layout">@layout/preference_list_fragment_material</item>
<item name="paddingStart">@dimen/preference_fragment_padding_side_material</item>
<item name="paddingEnd">@dimen/preference_fragment_padding_side_material</item>
+ <item name="divider">?attr/listDivider</item>
</style>
<style name="PreferenceActivity.Material">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index cda7faa1f09b..6820c259a51a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -162,7 +162,7 @@
<java-symbol type="id" name="submit_area" />
<java-symbol type="id" name="switch_new" />
<java-symbol type="id" name="switch_old" />
- <java-symbol type="id" name="switchWidget" />
+ <java-symbol type="id" name="switch_widget" />
<java-symbol type="id" name="text" />
<java-symbol type="id" name="time" />
<java-symbol type="id" name="time_current" />
diff --git a/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java b/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
index 87b37854a596..3ce45e9ca8c5 100644
--- a/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
+++ b/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
@@ -61,11 +61,13 @@ public class SuggestionsPopupWindowTest extends ActivityInstrumentationTestCase2
final int expectedHighlightTextColor = tmpTp.getColor();
final float expectedHighlightTextSize = tmpTp.getTextSize();
- // Create and wait until SuggestionsPopupWindow is shown.
final EditText editText = (EditText) activity.findViewById(R.id.textview);
final Editor editor = editText.getEditorForTesting();
assertNotNull(editor);
- activity.runOnUiThread(new Runnable() {
+
+ // Request to show SuggestionsPopupWindow.
+ Runnable showSuggestionWindowRunner = new Runnable() {
+ @Override
public void run() {
SpannableStringBuilder ssb = new SpannableStringBuilder();
ssb.append(sampleText);
@@ -78,8 +80,7 @@ public class SuggestionsPopupWindowTest extends ActivityInstrumentationTestCase2
Selection.setSelection(editText.getText(), singleWordSpanStart, singleWordSpanEnd);
editText.onTextContextMenuItem(TextView.ID_REPLACE);
}
- });
- getInstrumentation().waitForIdleSync();
+ };
// In this test, the SuggestionsPopupWindow looks like
// abc def ghi
@@ -91,7 +92,8 @@ public class SuggestionsPopupWindowTest extends ActivityInstrumentationTestCase2
// | DELETE |
// -----------------
// *XX* means that XX is highlighted.
- activity.runOnUiThread(new Runnable() {
+ Runnable popupVaridator = new Runnable() {
+ @Override
public void run() {
Editor.SuggestionsPopupWindow popupWindow =
editor.getSuggestionsPopupWindowForTesting();
@@ -155,6 +157,25 @@ public class SuggestionsPopupWindowTest extends ActivityInstrumentationTestCase2
assertEquals(multiWordSpanEnd, spanned.getSpanEnd(taSpan[0]));
}
}
+ };
+
+ // Show the SuggestionWindow and verify the contents.
+ activity.runOnUiThread(showSuggestionWindowRunner);
+ getInstrumentation().waitForIdleSync();
+ activity.runOnUiThread(popupVaridator);
+
+ // Request to hide the SuggestionPopupWindow and wait until it is hidden.
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ editText.setText("");
+ }
});
+ getInstrumentation().waitForIdleSync();
+
+ // Show and verify the contents again.
+ activity.runOnUiThread(showSuggestionWindowRunner);
+ getInstrumentation().waitForIdleSync();
+ activity.runOnUiThread(popupVaridator);
}
}
diff --git a/docs/html/guide/topics/manifest/uses-feature-element.jd b/docs/html/guide/topics/manifest/uses-feature-element.jd
index c1ccef0705fd..e22dc4a4bda2 100644
--- a/docs/html/guide/topics/manifest/uses-feature-element.jd
+++ b/docs/html/guide/topics/manifest/uses-feature-element.jd
@@ -562,10 +562,11 @@ is sensitive to delays or lag in sound input or output.</td>
<tr>
<td rowspan="6">Camera</td>
<td><code>android.hardware.camera</code></td>
- <td>The application uses the device's camera. If the device supports
- multiple cameras, the application uses the camera that facing
- away from the screen.</td>
- <td></td>
+ <td>The application uses the device's back-facing (main) camera.</td>
+ <td>Importantly, devices with only a front-facing camera will not list this
+ feature, so the <code>android.hardware.camera.any</code> feature should be
+ used instead if a camera facing any direction is acceptable for the
+ application.</td>
</tr>
<tr>
<td><code>android.hardware.camera.autofocus</code></td>
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 5cdd7232923c..4acad67f716a 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -9,6 +9,7 @@ hwui_src_files := \
font/Font.cpp \
renderstate/Blend.cpp \
renderstate/MeshState.cpp \
+ renderstate/OffscreenBufferPool.cpp \
renderstate/PixelBufferState.cpp \
renderstate/RenderState.cpp \
renderstate/Scissor.cpp \
@@ -216,6 +217,7 @@ LOCAL_SRC_FILES += \
unit_tests/LayerUpdateQueueTests.cpp \
unit_tests/LinearAllocatorTests.cpp \
unit_tests/PathParserTests.cpp \
+ unit_tests/OffscreenBufferPoolTests.cpp \
unit_tests/StringUtilsTests.cpp
ifeq (true, $(HWUI_NEW_OPS))
diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp
index 2fca5ea8b962..1aa291f23a1e 100644
--- a/libs/hwui/BakedOpRenderer.cpp
+++ b/libs/hwui/BakedOpRenderer.cpp
@@ -19,104 +19,29 @@
#include "Caches.h"
#include "Glop.h"
#include "GlopBuilder.h"
+#include "renderstate/OffscreenBufferPool.h"
#include "renderstate/RenderState.h"
-#include "utils/FatVector.h"
#include "utils/GLUtils.h"
+#include "VertexBuffer.h"
namespace android {
namespace uirenderer {
////////////////////////////////////////////////////////////////////////////////
-// OffscreenBuffer
-////////////////////////////////////////////////////////////////////////////////
-
-OffscreenBuffer::OffscreenBuffer(RenderState& renderState, Caches& caches,
- uint32_t textureWidth, uint32_t textureHeight,
- uint32_t viewportWidth, uint32_t viewportHeight)
- : renderState(renderState)
- , viewportWidth(viewportWidth)
- , viewportHeight(viewportHeight)
- , texture(caches) {
- texture.width = textureWidth;
- texture.height = textureHeight;
-
- caches.textureState().activateTexture(0);
- glGenTextures(1, &texture.id);
- caches.textureState().bindTexture(GL_TEXTURE_2D, texture.id);
-
- texture.setWrap(GL_CLAMP_TO_EDGE, false, false, GL_TEXTURE_2D);
- // not setting filter on texture, since it's set when drawing, based on transform
-
- glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.width, texture.height, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
-}
-
-void OffscreenBuffer::updateMeshFromRegion() {
- // avoid T-junctions as they cause artifacts in between the resultant
- // geometry when complex transforms occur.
- // TODO: generate the safeRegion only if necessary based on drawing transform
- Region safeRegion = Region::createTJunctionFreeRegion(region);
-
- size_t count;
- const android::Rect* rects = safeRegion.getArray(&count);
-
- const float texX = 1.0f / float(viewportWidth);
- const float texY = 1.0f / float(viewportHeight);
-
- FatVector<TextureVertex, 64> meshVector(count * 4); // uses heap if more than 64 vertices needed
- TextureVertex* mesh = &meshVector[0];
- for (size_t i = 0; i < count; i++) {
- const android::Rect* r = &rects[i];
-
- const float u1 = r->left * texX;
- const float v1 = (viewportHeight - r->top) * texY;
- const float u2 = r->right * texX;
- const float v2 = (viewportHeight - r->bottom) * texY;
-
- TextureVertex::set(mesh++, r->left, r->top, u1, v1);
- TextureVertex::set(mesh++, r->right, r->top, u2, v1);
- TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
- TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
- }
- elementCount = count * 6;
- renderState.meshState().genOrUpdateMeshBuffer(&vbo,
- sizeof(TextureVertex) * count * 4,
- &meshVector[0],
- GL_DYNAMIC_DRAW); // TODO: GL_STATIC_DRAW if savelayer
-}
-
-OffscreenBuffer::~OffscreenBuffer() {
- texture.deleteTexture();
- renderState.meshState().deleteMeshBuffer(vbo);
- elementCount = 0;
- vbo = 0;
-}
-
-////////////////////////////////////////////////////////////////////////////////
// BakedOpRenderer
////////////////////////////////////////////////////////////////////////////////
-OffscreenBuffer* BakedOpRenderer::createOffscreenBuffer(RenderState& renderState,
- uint32_t width, uint32_t height) {
- // TODO: get from cache!
- return new OffscreenBuffer(renderState, Caches::getInstance(), width, height, width, height);
-}
-
-void BakedOpRenderer::destroyOffscreenBuffer(OffscreenBuffer* offscreenBuffer) {
- // TODO: return texture/offscreenbuffer to cache!
- delete offscreenBuffer;
-}
-
-OffscreenBuffer* BakedOpRenderer::createLayer(uint32_t width, uint32_t height) {
+OffscreenBuffer* BakedOpRenderer::startTemporaryLayer(uint32_t width, uint32_t height) {
LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer...");
- OffscreenBuffer* buffer = createOffscreenBuffer(mRenderState, width, height);
- startLayer(buffer);
+ OffscreenBuffer* buffer = mRenderState.layerPool().get(mRenderState, width, height);
+ startRepaintLayer(buffer);
return buffer;
}
-void BakedOpRenderer::startLayer(OffscreenBuffer* offscreenBuffer) {
+void BakedOpRenderer::startRepaintLayer(OffscreenBuffer* offscreenBuffer) {
+ LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer...");
+
mRenderTarget.offscreenBuffer = offscreenBuffer;
// create and bind framebuffer
@@ -261,6 +186,71 @@ void BakedOpDispatcher::onRectOp(BakedOpRenderer& renderer, const RectOp& op, co
renderer.renderGlop(state, glop);
}
+namespace VertexBufferRenderFlags {
+ enum {
+ Offset = 0x1,
+ ShadowInterp = 0x2,
+ };
+}
+
+static void renderVertexBuffer(BakedOpRenderer& renderer, const BakedOpState& state,
+ const VertexBuffer& vertexBuffer, float translateX, float translateY,
+ SkPaint& paint, int vertexBufferRenderFlags) {
+ if (CC_LIKELY(vertexBuffer.getVertexCount())) {
+ bool shadowInterp = vertexBufferRenderFlags & VertexBufferRenderFlags::ShadowInterp;
+ const int transformFlags = TransformFlags::OffsetByFudgeFactor;
+ Glop glop;
+ GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
+ .setRoundRectClipState(state.roundRectClipState)
+ .setMeshVertexBuffer(vertexBuffer, shadowInterp)
+ .setFillPaint(paint, state.alpha)
+ .setTransform(state.computedState.transform, transformFlags)
+ .setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds())
+ .build();
+ renderer.renderGlop(state, glop);
+ }
+}
+
+static void renderShadow(BakedOpRenderer& renderer, const BakedOpState& state, float casterAlpha,
+ const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer) {
+ SkPaint paint;
+ paint.setAntiAlias(true); // want to use AlphaVertex
+
+ // The caller has made sure casterAlpha > 0.
+ uint8_t ambientShadowAlpha = 128u; //TODO: mAmbientShadowAlpha;
+ if (CC_UNLIKELY(Properties::overrideAmbientShadowStrength >= 0)) {
+ ambientShadowAlpha = Properties::overrideAmbientShadowStrength;
+ }
+ if (ambientShadowVertexBuffer && ambientShadowAlpha > 0) {
+ paint.setAlpha((uint8_t)(casterAlpha * ambientShadowAlpha));
+ renderVertexBuffer(renderer, state, *ambientShadowVertexBuffer, 0, 0,
+ paint, VertexBufferRenderFlags::ShadowInterp);
+ }
+
+ uint8_t spotShadowAlpha = 128u; //TODO: mSpotShadowAlpha;
+ if (CC_UNLIKELY(Properties::overrideSpotShadowStrength >= 0)) {
+ spotShadowAlpha = Properties::overrideSpotShadowStrength;
+ }
+ if (spotShadowVertexBuffer && spotShadowAlpha > 0) {
+ paint.setAlpha((uint8_t)(casterAlpha * spotShadowAlpha));
+ renderVertexBuffer(renderer, state, *spotShadowVertexBuffer, 0, 0,
+ paint, VertexBufferRenderFlags::ShadowInterp);
+ }
+}
+
+void BakedOpDispatcher::onShadowOp(BakedOpRenderer& renderer, const ShadowOp& op, const BakedOpState& state) {
+ TessellationCache::vertexBuffer_pair_t buffers;
+ Vector3 lightCenter = { 300, 300, 300 }; // TODO!
+ float lightRadius = 150; // TODO!
+
+ renderer.caches().tessellationCache.getShadowBuffers(&state.computedState.transform,
+ op.localClipRect, op.casterAlpha >= 1.0f, op.casterPath,
+ &op.shadowMatrixXY, &op.shadowMatrixZ, lightCenter, lightRadius,
+ buffers);
+
+ renderShadow(renderer, state, op.casterAlpha, buffers.first, buffers.second);
+}
+
void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleRectsOp& op, const BakedOpState& state) {
Glop glop;
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
@@ -291,7 +281,7 @@ void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op,
renderer.renderGlop(state, glop);
if (op.destroy) {
- BakedOpRenderer::destroyOffscreenBuffer(buffer);
+ renderer.renderState().layerPool().putOrDelete(buffer);
}
}
diff --git a/libs/hwui/BakedOpRenderer.h b/libs/hwui/BakedOpRenderer.h
index aa1e67d45d56..d6d9cb139328 100644
--- a/libs/hwui/BakedOpRenderer.h
+++ b/libs/hwui/BakedOpRenderer.h
@@ -29,33 +29,6 @@ class Layer;
class RenderState;
/**
- * Lightweight alternative to Layer. Owns the persistent state of an offscreen render target, and
- * encompasses enough information to draw it back on screen (minus paint properties, which are held
- * by LayerOp).
- */
-class OffscreenBuffer {
-public:
- OffscreenBuffer(RenderState& renderState, Caches& caches,
- uint32_t textureWidth, uint32_t textureHeight,
- uint32_t viewportWidth, uint32_t viewportHeight);
- ~OffscreenBuffer();
-
- // must be called prior to rendering, to construct/update vertex buffer
- void updateMeshFromRegion();
-
- RenderState& renderState;
- uint32_t viewportWidth;
- uint32_t viewportHeight;
- Texture texture;
-
- // Portion of offscreen buffer that has been drawn to. Used to minimize drawing area when
- // drawing back to screen / parent FBO.
- Region region;
- GLsizei elementCount = 0;
- GLuint vbo = 0;
-};
-
-/**
* Main rendering manager for a collection of work - one frame + any contained FBOs.
*
* Manages frame and FBO lifecycle, binding the GL framebuffer as appropriate. This is the only
@@ -72,17 +45,13 @@ public:
, mOpaque(opaque) {
}
- static OffscreenBuffer* createOffscreenBuffer(RenderState& renderState,
- uint32_t width, uint32_t height);
- static void destroyOffscreenBuffer(OffscreenBuffer*);
-
RenderState& renderState() { return mRenderState; }
Caches& caches() { return mCaches; }
void startFrame(uint32_t width, uint32_t height);
void endFrame();
- OffscreenBuffer* createLayer(uint32_t width, uint32_t height);
- void startLayer(OffscreenBuffer* offscreenBuffer);
+ OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height);
+ void startRepaintLayer(OffscreenBuffer* offscreenBuffer);
void endLayer();
Texture* getTexture(const SkBitmap* bitmap);
diff --git a/libs/hwui/BakedOpState.h b/libs/hwui/BakedOpState.h
index ddb8c84e08f4..9a40c3b3d3b0 100644
--- a/libs/hwui/BakedOpState.h
+++ b/libs/hwui/BakedOpState.h
@@ -89,6 +89,21 @@ public:
* and early return null in one place.
*/
}
+
+ /**
+ * Constructor for unbounded ops without transform/clip (namely shadows)
+ *
+ * Since the op doesn't have known bounds, we conservatively set the mapped bounds
+ * to the current clipRect, and clipSideFlags to Full.
+ */
+ ResolvedRenderState(const Snapshot& snapshot) {
+ transform = *snapshot.transform;
+ clipRect = snapshot.getRenderTargetClip();
+ clippedBounds = clipRect;
+ transform.mapRect(clippedBounds);
+ clipSideFlags = OpClipSideFlags::Full;
+ }
+
Matrix4 transform;
Rect clipRect;
int clipSideFlags = 0;
@@ -104,8 +119,7 @@ class BakedOpState {
public:
static BakedOpState* tryConstruct(LinearAllocator& allocator,
const Snapshot& snapshot, const RecordedOp& recordedOp) {
- BakedOpState* bakedOp = new (allocator) BakedOpState(
- snapshot, recordedOp);
+ BakedOpState* bakedOp = new (allocator) BakedOpState(snapshot, recordedOp);
if (bakedOp->computedState.clippedBounds.isEmpty()) {
// bounds are empty, so op is rejected
allocator.rewindIfLastAlloc(bakedOp);
@@ -114,6 +128,14 @@ public:
return bakedOp;
}
+ static BakedOpState* tryShadowOpConstruct(LinearAllocator& allocator,
+ const Snapshot& snapshot, const ShadowOp* shadowOpPtr) {
+ if (snapshot.getRenderTargetClip().isEmpty()) return nullptr;
+
+ // clip isn't empty, so construct the op
+ return new (allocator) BakedOpState(snapshot, shadowOpPtr);
+ }
+
static void* operator new(size_t size, LinearAllocator& allocator) {
return allocator.alloc(size);
}
@@ -134,6 +156,13 @@ private:
, roundRectClipState(snapshot.roundRectClipState)
, projectionPathMask(snapshot.projectionPathMask)
, op(&recordedOp) {}
+
+ BakedOpState(const Snapshot& snapshot, const ShadowOp* shadowOpPtr)
+ : computedState(snapshot)
+ , alpha(snapshot.alpha)
+ , roundRectClipState(snapshot.roundRectClipState)
+ , projectionPathMask(snapshot.projectionPathMask)
+ , op(shadowOpPtr) {}
};
}; // namespace uirenderer
diff --git a/libs/hwui/DisplayListCanvas.h b/libs/hwui/DisplayListCanvas.h
index fc08504ff60a..609103b89644 100644
--- a/libs/hwui/DisplayListCanvas.h
+++ b/libs/hwui/DisplayListCanvas.h
@@ -17,6 +17,14 @@
#ifndef ANDROID_HWUI_DISPLAY_LIST_RENDERER_H
#define ANDROID_HWUI_DISPLAY_LIST_RENDERER_H
+#include "Canvas.h"
+#include "CanvasState.h"
+#include "DisplayList.h"
+#include "RenderNode.h"
+#include "ResourceCache.h"
+#include "SkiaCanvasProxy.h"
+#include "utils/Macros.h"
+
#include <SkDrawFilter.h>
#include <SkMatrix.h>
#include <SkPaint.h>
@@ -25,13 +33,6 @@
#include <SkTLazy.h>
#include <cutils/compiler.h>
-#include "Canvas.h"
-#include "CanvasState.h"
-#include "DisplayList.h"
-#include "SkiaCanvasProxy.h"
-#include "RenderNode.h"
-#include "ResourceCache.h"
-
namespace android {
namespace uirenderer {
@@ -66,7 +67,7 @@ public:
virtual ~DisplayListCanvas();
void reset(int width, int height);
- __attribute__((warn_unused_result)) DisplayList* finishRecording();
+ WARN_UNUSED_RESULT DisplayList* finishRecording();
// ----------------------------------------------------------------------------
// HWUI Canvas state operations
diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp
index 39cadd198c83..b117754347ed 100644
--- a/libs/hwui/LayerCache.cpp
+++ b/libs/hwui/LayerCache.cpp
@@ -14,14 +14,15 @@
* limitations under the License.
*/
-#include <GLES2/gl2.h>
-
-#include <utils/Log.h>
+#include "LayerCache.h"
#include "Caches.h"
-#include "LayerCache.h"
#include "Properties.h"
+#include <utils/Log.h>
+
+#include <GLES2/gl2.h>
+
namespace android {
namespace uirenderer {
@@ -29,15 +30,9 @@ namespace uirenderer {
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
-LayerCache::LayerCache(): mSize(0), mMaxSize(MB(DEFAULT_LAYER_CACHE_SIZE)) {
- char property[PROPERTY_VALUE_MAX];
- if (property_get(PROPERTY_LAYER_CACHE_SIZE, property, nullptr) > 0) {
- INIT_LOGD(" Setting layer cache size to %sMB", property);
- setMaxSize(MB(atof(property)));
- } else {
- INIT_LOGD(" Using default layer cache size of %.2fMB", DEFAULT_LAYER_CACHE_SIZE);
- }
-}
+LayerCache::LayerCache()
+ : mSize(0)
+ , mMaxSize(Properties::layerPoolSize) {}
LayerCache::~LayerCache() {
clear();
diff --git a/libs/hwui/OpReorderer.cpp b/libs/hwui/OpReorderer.cpp
index 68f80ea359cd..80efaed44d13 100644
--- a/libs/hwui/OpReorderer.cpp
+++ b/libs/hwui/OpReorderer.cpp
@@ -22,6 +22,7 @@
#include "utils/PaintUtils.h"
#include <SkCanvas.h>
+#include <SkPathOps.h>
#include <utils/Trace.h>
#include <utils/TypeHelpers.h>
@@ -312,7 +313,7 @@ OpReorderer::OpReorderer(const LayerUpdateQueue& layers, const SkRect& clip,
: mCanvasState(*this) {
ATRACE_NAME("prepare drawing commands");
mLayerReorderers.emplace_back(viewportWidth, viewportHeight);
- mLayerStack.push_back(0);
+ mLayerStack.push_back(0);
mCanvasState.initializeSaveStack(viewportWidth, viewportHeight,
clip.fLeft, clip.fTop, clip.fRight, clip.fBottom,
@@ -347,7 +348,6 @@ OpReorderer::OpReorderer(const LayerUpdateQueue& layers, const SkRect& clip,
OpReorderer::OpReorderer(int viewportWidth, int viewportHeight, const DisplayList& displayList)
: mCanvasState(*this) {
ATRACE_NAME("prepare drawing commands");
-
mLayerReorderers.emplace_back(viewportWidth, viewportHeight);
mLayerStack.push_back(0);
@@ -462,8 +462,60 @@ void OpReorderer::defer3dChildren(ChildrenSelectMode mode, const V& zTranslatedN
}
void OpReorderer::deferShadow(const RenderNodeOp& casterNodeOp) {
- // TODO
+ auto& node = *casterNodeOp.renderNode;
+ auto& properties = node.properties();
+
+ if (properties.getAlpha() <= 0.0f
+ || properties.getOutline().getAlpha() <= 0.0f
+ || !properties.getOutline().getPath()
+ || properties.getScaleX() == 0
+ || properties.getScaleY() == 0) {
+ // no shadow to draw
+ return;
+ }
+
+ const SkPath* casterOutlinePath = properties.getOutline().getPath();
+ const SkPath* revealClipPath = properties.getRevealClip().getPath();
+ if (revealClipPath && revealClipPath->isEmpty()) return;
+
+ float casterAlpha = properties.getAlpha() * properties.getOutline().getAlpha();
+
+ // holds temporary SkPath to store the result of intersections
+ SkPath* frameAllocatedPath = nullptr;
+ const SkPath* casterPath = casterOutlinePath;
+
+ // intersect the shadow-casting path with the reveal, if present
+ if (revealClipPath) {
+ frameAllocatedPath = createFrameAllocatedPath();
+
+ Op(*casterPath, *revealClipPath, kIntersect_SkPathOp, frameAllocatedPath);
+ casterPath = frameAllocatedPath;
+ }
+
+ // intersect the shadow-casting path with the clipBounds, if present
+ if (properties.getClippingFlags() & CLIP_TO_CLIP_BOUNDS) {
+ if (!frameAllocatedPath) {
+ frameAllocatedPath = createFrameAllocatedPath();
+ }
+ Rect clipBounds;
+ properties.getClippingRectForFlags(CLIP_TO_CLIP_BOUNDS, &clipBounds);
+ SkPath clipBoundsPath;
+ clipBoundsPath.addRect(clipBounds.left, clipBounds.top,
+ clipBounds.right, clipBounds.bottom);
+
+ Op(*casterPath, clipBoundsPath, kIntersect_SkPathOp, frameAllocatedPath);
+ casterPath = frameAllocatedPath;
+ }
+
+ ShadowOp* shadowOp = new (mAllocator) ShadowOp(casterNodeOp, casterAlpha, casterPath,
+ mCanvasState.getLocalClipBounds());
+ BakedOpState* bakedOpState = BakedOpState::tryShadowOpConstruct(
+ mAllocator, *mCanvasState.currentSnapshot(), shadowOp);
+ if (CC_LIKELY(bakedOpState)) {
+ currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Shadow);
+ }
}
+
/**
* Used to define a list of lambdas referencing private OpReorderer::onXXXXOp() methods.
*
@@ -593,5 +645,9 @@ void OpReorderer::onLayerOp(const LayerOp& op) {
LOG_ALWAYS_FATAL("unsupported");
}
+void OpReorderer::onShadowOp(const ShadowOp& op) {
+ LOG_ALWAYS_FATAL("unsupported");
+}
+
} // namespace uirenderer
} // namespace android
diff --git a/libs/hwui/OpReorderer.h b/libs/hwui/OpReorderer.h
index 936b6ed9566e..2c30f0dc30de 100644
--- a/libs/hwui/OpReorderer.h
+++ b/libs/hwui/OpReorderer.h
@@ -51,6 +51,7 @@ namespace OpBatchType {
AlphaMaskTexture,
Text,
ColorText,
+ Shadow,
Count // must be last
};
@@ -152,11 +153,11 @@ public:
LayerReorderer& layer = mLayerReorderers[i];
if (layer.renderNode) {
// cached HW layer - can't skip layer if empty
- renderer.startLayer(layer.offscreenBuffer);
+ renderer.startRepaintLayer(layer.offscreenBuffer);
layer.replayBakedOpsImpl((void*)&renderer, receivers);
renderer.endLayer();
} else if (!layer.empty()) { // save layer - skip entire layer if empty
- layer.offscreenBuffer = renderer.createLayer(layer.width, layer.height);
+ layer.offscreenBuffer = renderer.startTemporaryLayer(layer.width, layer.height);
layer.replayBakedOpsImpl((void*)&renderer, receivers);
renderer.endLayer();
}
@@ -210,6 +211,10 @@ private:
void replayBakedOpsImpl(void* arg, BakedOpDispatcher* receivers);
+ SkPath* createFrameAllocatedPath() {
+ mFrameAllocatedPaths.emplace_back(new SkPath);
+ return mFrameAllocatedPaths.back().get();
+ }
/**
* Declares all OpReorderer::onXXXXOp() methods for every RecordedOp type.
*
@@ -220,6 +225,8 @@ private:
void on##Type(const Type& op);
MAP_OPS(INTERNAL_OP_HANDLER)
+ std::vector<std::unique_ptr<SkPath> > mFrameAllocatedPaths;
+
// List of every deferred layer's render state. Replayed in reverse order to render a frame.
std::vector<LayerReorderer> mLayerReorderers;
diff --git a/libs/hwui/PathParser.cpp b/libs/hwui/PathParser.cpp
index e8ed8a14100a..61b9d2114a62 100644
--- a/libs/hwui/PathParser.cpp
+++ b/libs/hwui/PathParser.cpp
@@ -183,10 +183,16 @@ void PathParser::dump(const PathData& data) {
ALOGD("points are : %s", os.str().c_str());
}
-void PathParser::parseStringForSkPath(SkPath* skPath, const char* pathStr, size_t strLen) {
+bool PathParser::parseStringForSkPath(SkPath* skPath, const char* pathStr, size_t strLen) {
PathData pathData;
getPathDataFromString(&pathData, pathStr, strLen);
+
+ // Check if there is valid data coming out of parsing the string.
+ if (pathData.verbs.size() == 0) {
+ return false;
+ }
VectorDrawablePath::verbsToPath(skPath, &pathData);
+ return true;
}
}; // namespace uirenderer
diff --git a/libs/hwui/PathParser.h b/libs/hwui/PathParser.h
index 6dc7ee193197..d30bb0f1b973 100644
--- a/libs/hwui/PathParser.h
+++ b/libs/hwui/PathParser.h
@@ -21,13 +21,18 @@
#include <jni.h>
#include <android/log.h>
+#include <cutils/compiler.h>
namespace android {
namespace uirenderer {
class PathParser {
public:
- static void parseStringForSkPath(SkPath* outPath, const char* pathStr, size_t strLength);
+ /**
+ * Parse the string literal and create a Skia Path. Return true on success.
+ */
+ ANDROID_API static bool parseStringForSkPath(SkPath* outPath, const char* pathStr,
+ size_t strLength);
static void getPathDataFromString(PathData* outData, const char* pathStr, size_t strLength);
static void dump(const PathData& data);
};
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index e81818679f3e..0669596b21ca 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -37,6 +37,7 @@ bool Properties::useBufferAge = true;
bool Properties::enablePartialUpdates = true;
float Properties::textGamma = DEFAULT_TEXT_GAMMA;
+int Properties::layerPoolSize = DEFAULT_LAYER_CACHE_SIZE;
DebugLevel Properties::debugLevel = kDebugDisabled;
OverdrawColorSet Properties::overdrawColorSet = OverdrawColorSet::Default;
@@ -52,10 +53,19 @@ int Properties::overrideSpotShadowStrength = -1;
ProfileType Properties::sProfileType = ProfileType::None;
bool Properties::sDisableProfileBars = false;
+static int property_get_int(const char* key, int defaultValue) {
+ char buf[PROPERTY_VALUE_MAX] = {'\0',};
+
+ if (property_get(key, buf, "") > 0) {
+ return atoi(buf);
+ }
+ return defaultValue;
+}
+
static float property_get_float(const char* key, float defaultValue) {
char buf[PROPERTY_VALUE_MAX] = {'\0',};
- if (property_get(PROPERTY_PROFILE, buf, "") > 0) {
+ if (property_get(key, buf, "") > 0) {
return atof(buf);
}
return defaultValue;
@@ -114,16 +124,14 @@ bool Properties::load() {
showDirtyRegions = property_get_bool(PROPERTY_DEBUG_SHOW_DIRTY_REGIONS, false);
- debugLevel = kDebugDisabled;
- if (property_get(PROPERTY_DEBUG, property, nullptr) > 0) {
- debugLevel = (DebugLevel) atoi(property);
- }
+ debugLevel = (DebugLevel) property_get_int(PROPERTY_DEBUG, kDebugDisabled);
skipEmptyFrames = property_get_bool(PROPERTY_SKIP_EMPTY_DAMAGE, true);
useBufferAge = property_get_bool(PROPERTY_USE_BUFFER_AGE, true);
enablePartialUpdates = property_get_bool(PROPERTY_ENABLE_PARTIAL_UPDATES, true);
textGamma = property_get_float(PROPERTY_TEXT_GAMMA, DEFAULT_TEXT_GAMMA);
+ layerPoolSize = MB(property_get_float(PROPERTY_LAYER_CACHE_SIZE, DEFAULT_LAYER_CACHE_SIZE));
return (prevDebugLayersUpdates != debugLayersUpdates)
|| (prevDebugOverdraw != debugOverdraw)
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 1293c786a0bd..1dde7e054aab 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -267,6 +267,8 @@ public:
static float textGamma;
+ static int layerPoolSize;
+
static DebugLevel debugLevel;
static OverdrawColorSet overdrawColorSet;
static StencilClipDebug debugStencilClip;
diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h
index 04af8e36348a..bb7a0a7ce446 100644
--- a/libs/hwui/RecordedOp.h
+++ b/libs/hwui/RecordedOp.h
@@ -43,6 +43,7 @@ struct Vertex;
OP_FN(BitmapOp) \
OP_FN(RectOp) \
OP_FN(RenderNodeOp) \
+ OP_FN(ShadowOp) \
OP_FN(SimpleRectsOp) \
OP_FN(BeginLayerOp) \
OP_FN(EndLayerOp) \
@@ -109,6 +110,31 @@ struct RectOp : RecordedOp {
: SUPER(RectOp) {}
};
+/**
+ * Real-time, dynamic-lit shadow.
+ *
+ * Uses invalid/empty bounds and matrix since ShadowOp bounds aren't known at defer time,
+ * and are resolved dynamically, and transform isn't needed.
+ *
+ * State construction handles these properties specially.
+ */
+struct ShadowOp : RecordedOp {
+ ShadowOp(const RenderNodeOp& casterOp, float casterAlpha, const SkPath* casterPath, const Rect& clipRect)
+ : RecordedOp(RecordedOpId::ShadowOp, Rect(), Matrix4::identity(), clipRect, nullptr)
+ , shadowMatrixXY(casterOp.localMatrix)
+ , shadowMatrixZ(casterOp.localMatrix)
+ , casterAlpha(casterAlpha)
+ , casterPath(casterPath) {
+ const RenderNode& node = *casterOp.renderNode;
+ node.applyViewPropertyTransforms(shadowMatrixXY, false);
+ node.applyViewPropertyTransforms(shadowMatrixZ, true);
+ };
+ Matrix4 shadowMatrixXY;
+ Matrix4 shadowMatrixZ;
+ const float casterAlpha;
+ const SkPath* casterPath;
+};
+
struct SimpleRectsOp : RecordedOp { // Filled, no AA (TODO: better name?)
SimpleRectsOp(BASE_PARAMS, Vertex* vertices, size_t vertexCount)
: SUPER(SimpleRectsOp)
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index fc84c98b76a5..f26b0c827604 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -20,11 +20,12 @@
#include "Canvas.h"
#include "CanvasState.h"
#include "DisplayList.h"
-#include "utils/LinearAllocator.h"
-#include "utils/NinePatch.h"
#include "ResourceCache.h"
#include "SkiaCanvasProxy.h"
#include "Snapshot.h"
+#include "utils/LinearAllocator.h"
+#include "utils/Macros.h"
+#include "utils/NinePatch.h"
#include <SkDrawFilter.h>
#include <SkPaint.h>
@@ -49,7 +50,7 @@ public:
virtual ~RecordingCanvas();
void reset(int width, int height);
- __attribute__((warn_unused_result)) DisplayList* finishRecording();
+ WARN_UNUSED_RESULT DisplayList* finishRecording();
// ----------------------------------------------------------------------------
// MISC HWUI OPERATIONS - TODO: CATEGORIZE
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 15ca718481fe..e177f9a86a2c 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -248,22 +248,31 @@ void RenderNode::prepareLayer(TreeInfo& info, uint32_t dirtyMask) {
}
}
-layer_t* createLayer(RenderState& renderState, uint32_t width, uint32_t height) {
+static layer_t* createLayer(RenderState& renderState, uint32_t width, uint32_t height) {
#if HWUI_NEW_OPS
- return BakedOpRenderer::createOffscreenBuffer(renderState, width, height);
+ return renderState.layerPool().get(renderState, width, height);
#else
return LayerRenderer::createRenderLayer(renderState, width, height);
#endif
}
-void destroyLayer(layer_t* layer) {
+static void destroyLayer(layer_t* layer) {
#if HWUI_NEW_OPS
- BakedOpRenderer::destroyOffscreenBuffer(layer);
+ RenderState& renderState = layer->renderState;
+ renderState.layerPool().putOrDelete(layer);
#else
LayerRenderer::destroyLayer(layer);
#endif
}
+static bool layerMatchesWidthAndHeight(layer_t* layer, int width, int height) {
+#if HWUI_NEW_OPS
+ return layer->viewportWidth == (uint32_t) width && layer->viewportHeight == (uint32_t)height;
+#else
+ return layer->layer.getWidth() == width && layer->layer.getHeight() == height;
+#endif
+}
+
void RenderNode::pushLayerUpdate(TreeInfo& info) {
LayerType layerType = properties().effectiveLayerType();
// If we are not a layer OR we cannot be rendered (eg, view was detached)
@@ -278,17 +287,16 @@ void RenderNode::pushLayerUpdate(TreeInfo& info) {
bool transformUpdateNeeded = false;
if (!mLayer) {
- mLayer = createLayer(info.canvasContext.getRenderState(), getWidth(), getHeight());
- damageSelf(info);
- transformUpdateNeeded = true;
+ mLayer = createLayer(info.canvasContext.getRenderState(), getWidth(), getHeight());
+ damageSelf(info);
+ transformUpdateNeeded = true;
+ } else if (!layerMatchesWidthAndHeight(mLayer, getWidth(), getHeight())) {
#if HWUI_NEW_OPS
- } else if (mLayer->viewportWidth != (uint32_t) getWidth()
- || mLayer->viewportHeight != (uint32_t)getHeight()) {
- // TODO: allow node's layer to grow larger
- if ((uint32_t)getWidth() > mLayer->texture.width
- || (uint32_t)getHeight() > mLayer->texture.height) {
+ RenderState& renderState = mLayer->renderState;
+ if (properties().fitsOnLayer()) {
+ mLayer = renderState.layerPool().resize(mLayer, getWidth(), getHeight());
+ } else {
#else
- } else if (mLayer->layer.getWidth() != getWidth() || mLayer->layer.getHeight() != getHeight()) {
if (!LayerRenderer::resizeLayer(mLayer, getWidth(), getHeight())) {
#endif
destroyLayer(mLayer);
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index ca7789e6f19a..0bd5b65f86aa 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -608,12 +608,16 @@ public:
&& getOutline().getAlpha() != 0.0f;
}
- bool promotedToLayer() const {
+ bool fitsOnLayer() const {
const DeviceInfo* deviceInfo = DeviceInfo::get();
LOG_ALWAYS_FATAL_IF(!deviceInfo, "DeviceInfo uninitialized");
+ return mPrimitiveFields.mWidth <= deviceInfo->maxTextureSize()
+ && mPrimitiveFields.mHeight <= deviceInfo->maxTextureSize();
+ }
+
+ bool promotedToLayer() const {
return mLayerProperties.mType == LayerType::None
- && mPrimitiveFields.mWidth <= deviceInfo->maxTextureSize()
- && mPrimitiveFields.mHeight <= deviceInfo->maxTextureSize()
+ && fitsOnLayer()
&& (mComputedFields.mNeedLayerForFunctors
|| (!MathUtils::isZero(mPrimitiveFields.mAlpha)
&& mPrimitiveFields.mAlpha < 1
diff --git a/libs/hwui/renderstate/OffscreenBufferPool.cpp b/libs/hwui/renderstate/OffscreenBufferPool.cpp
new file mode 100644
index 000000000000..6b44557a377b
--- /dev/null
+++ b/libs/hwui/renderstate/OffscreenBufferPool.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#include "OffscreenBufferPool.h"
+
+#include "Caches.h"
+#include "Properties.h"
+#include "renderstate/RenderState.h"
+#include "utils/FatVector.h"
+
+#include <utils/Log.h>
+
+#include <GLES2/gl2.h>
+
+namespace android {
+namespace uirenderer {
+
+////////////////////////////////////////////////////////////////////////////////
+// OffscreenBuffer
+////////////////////////////////////////////////////////////////////////////////
+
+OffscreenBuffer::OffscreenBuffer(RenderState& renderState, Caches& caches,
+ uint32_t viewportWidth, uint32_t viewportHeight)
+ : renderState(renderState)
+ , viewportWidth(viewportWidth)
+ , viewportHeight(viewportHeight)
+ , texture(caches) {
+ texture.width = computeIdealDimension(viewportWidth);
+ texture.height = computeIdealDimension(viewportHeight);
+ texture.blend = true;
+
+ caches.textureState().activateTexture(0);
+ glGenTextures(1, &texture.id);
+ caches.textureState().bindTexture(GL_TEXTURE_2D, texture.id);
+
+ texture.setWrap(GL_CLAMP_TO_EDGE, false, false, GL_TEXTURE_2D);
+ // not setting filter on texture, since it's set when drawing, based on transform
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.width, texture.height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+}
+
+void OffscreenBuffer::updateMeshFromRegion() {
+ // avoid T-junctions as they cause artifacts in between the resultant
+ // geometry when complex transforms occur.
+ // TODO: generate the safeRegion only if necessary based on drawing transform
+ Region safeRegion = Region::createTJunctionFreeRegion(region);
+
+ size_t count;
+ const android::Rect* rects = safeRegion.getArray(&count);
+
+ const float texX = 1.0f / float(texture.width);
+ const float texY = 1.0f / float(texture.height);
+
+ FatVector<TextureVertex, 64> meshVector(count * 4); // uses heap if more than 64 vertices needed
+ TextureVertex* mesh = &meshVector[0];
+ for (size_t i = 0; i < count; i++) {
+ const android::Rect* r = &rects[i];
+
+ const float u1 = r->left * texX;
+ const float v1 = (viewportHeight - r->top) * texY;
+ const float u2 = r->right * texX;
+ const float v2 = (viewportHeight - r->bottom) * texY;
+
+ TextureVertex::set(mesh++, r->left, r->top, u1, v1);
+ TextureVertex::set(mesh++, r->right, r->top, u2, v1);
+ TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
+ TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
+ }
+ elementCount = count * 6;
+ renderState.meshState().genOrUpdateMeshBuffer(&vbo,
+ sizeof(TextureVertex) * count * 4,
+ &meshVector[0],
+ GL_DYNAMIC_DRAW); // TODO: GL_STATIC_DRAW if savelayer
+}
+
+uint32_t OffscreenBuffer::computeIdealDimension(uint32_t dimension) {
+ return uint32_t(ceilf(dimension / float(LAYER_SIZE)) * LAYER_SIZE);
+}
+
+OffscreenBuffer::~OffscreenBuffer() {
+ texture.deleteTexture();
+ renderState.meshState().deleteMeshBuffer(vbo);
+ elementCount = 0;
+ vbo = 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// OffscreenBufferPool
+///////////////////////////////////////////////////////////////////////////////
+
+OffscreenBufferPool::OffscreenBufferPool()
+ : mMaxSize(Properties::layerPoolSize) {
+}
+
+OffscreenBufferPool::~OffscreenBufferPool() {
+ clear(); // TODO: unique_ptr?
+}
+
+int OffscreenBufferPool::Entry::compare(const Entry& lhs, const Entry& rhs) {
+ int deltaInt = int(lhs.width) - int(rhs.width);
+ if (deltaInt != 0) return deltaInt;
+
+ return int(lhs.height) - int(rhs.height);
+}
+
+void OffscreenBufferPool::clear() {
+ for (auto entry : mPool) {
+ delete entry.layer;
+ }
+ mPool.clear();
+ mSize = 0;
+}
+
+OffscreenBuffer* OffscreenBufferPool::get(RenderState& renderState,
+ const uint32_t width, const uint32_t height) {
+ OffscreenBuffer* layer = nullptr;
+
+ Entry entry(width, height);
+ auto iter = mPool.find(entry);
+
+ if (iter != mPool.end()) {
+ entry = *iter;
+ mPool.erase(iter);
+
+ layer = entry.layer;
+ layer->viewportWidth = width;
+ layer->viewportHeight = height;
+ mSize -= layer->getSizeInBytes();
+ } else {
+ layer = new OffscreenBuffer(renderState, Caches::getInstance(), width, height);
+ }
+
+ return layer;
+}
+
+OffscreenBuffer* OffscreenBufferPool::resize(OffscreenBuffer* layer,
+ const uint32_t width, const uint32_t height) {
+ RenderState& renderState = layer->renderState;
+ if (layer->texture.width == OffscreenBuffer::computeIdealDimension(width)
+ && layer->texture.height == OffscreenBuffer::computeIdealDimension(height)) {
+ // resize in place
+ layer->viewportWidth = width;
+ layer->viewportHeight = height;
+ return layer;
+ }
+ putOrDelete(layer);
+ return get(renderState, width, height);
+}
+
+void OffscreenBufferPool::dump() {
+ for (auto entry : mPool) {
+ ALOGD(" Layer size %dx%d", entry.width, entry.height);
+ }
+}
+
+void OffscreenBufferPool::putOrDelete(OffscreenBuffer* layer) {
+ const uint32_t size = layer->getSizeInBytes();
+ // Don't even try to cache a layer that's bigger than the cache
+ if (size < mMaxSize) {
+ // TODO: Use an LRU
+ while (mSize + size > mMaxSize) {
+ OffscreenBuffer* victim = mPool.begin()->layer;
+ mSize -= victim->getSizeInBytes();
+ delete victim;
+ mPool.erase(mPool.begin());
+ }
+
+ // clear region, since it's no longer valid
+ layer->region.clear();
+
+ Entry entry(layer);
+
+ mPool.insert(entry);
+ mSize += size;
+ } else {
+ delete layer;
+ }
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/renderstate/OffscreenBufferPool.h b/libs/hwui/renderstate/OffscreenBufferPool.h
new file mode 100644
index 000000000000..f0fd82d0444f
--- /dev/null
+++ b/libs/hwui/renderstate/OffscreenBufferPool.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#ifndef ANDROID_HWUI_OFFSCREEN_BUFFER_POOL_H
+#define ANDROID_HWUI_OFFSCREEN_BUFFER_POOL_H
+
+#include "Caches.h"
+#include "Texture.h"
+#include "utils/Macros.h"
+
+#include <ui/Region.h>
+
+#include <set>
+
+namespace android {
+namespace uirenderer {
+
+class RenderState;
+
+/**
+ * Lightweight alternative to Layer. Owns the persistent state of an offscreen render target, and
+ * encompasses enough information to draw it back on screen (minus paint properties, which are held
+ * by LayerOp).
+ */
+class OffscreenBuffer {
+public:
+ OffscreenBuffer(RenderState& renderState, Caches& caches,
+ uint32_t viewportWidth, uint32_t viewportHeight);
+ ~OffscreenBuffer();
+
+ // must be called prior to rendering, to construct/update vertex buffer
+ void updateMeshFromRegion();
+
+ static uint32_t computeIdealDimension(uint32_t dimension);
+
+ uint32_t getSizeInBytes() { return texture.width * texture.height * 4; }
+
+ RenderState& renderState;
+ uint32_t viewportWidth;
+ uint32_t viewportHeight;
+ Texture texture;
+
+ // Portion of layer that has been drawn to. Used to minimize drawing area when
+ // drawing back to screen / parent FBO.
+ Region region;
+ GLsizei elementCount = 0;
+ GLuint vbo = 0;
+};
+
+/**
+ * Pool of OffscreenBuffers allocated, but not currently in use.
+ */
+class OffscreenBufferPool {
+public:
+ OffscreenBufferPool();
+ ~OffscreenBufferPool();
+
+ WARN_UNUSED_RESULT OffscreenBuffer* get(RenderState& renderState,
+ const uint32_t width, const uint32_t height);
+
+ WARN_UNUSED_RESULT OffscreenBuffer* resize(OffscreenBuffer* layer,
+ const uint32_t width, const uint32_t height);
+
+ void putOrDelete(OffscreenBuffer* layer);
+
+ /**
+ * Clears the pool. This causes all layers to be deleted.
+ */
+ void clear();
+
+ /**
+ * Returns the maximum size of the pool in bytes.
+ */
+ uint32_t getMaxSize() { return mMaxSize; }
+
+ /**
+ * Returns the current size of the pool in bytes.
+ */
+ uint32_t getSize() { return mSize; }
+
+ size_t getCount() { return mPool.size(); }
+
+ /**
+ * Prints out the content of the pool.
+ */
+ void dump();
+private:
+ struct Entry {
+ Entry() {}
+
+ Entry(const uint32_t layerWidth, const uint32_t layerHeight)
+ : width(OffscreenBuffer::computeIdealDimension(layerWidth))
+ , height(OffscreenBuffer::computeIdealDimension(layerHeight)) {}
+
+ Entry(OffscreenBuffer* layer)
+ : layer(layer)
+ , width(layer->texture.width)
+ , height(layer->texture.height) {
+ }
+
+ static int compare(const Entry& lhs, const Entry& rhs);
+
+ bool operator==(const Entry& other) const {
+ return compare(*this, other) == 0;
+ }
+
+ bool operator!=(const Entry& other) const {
+ return compare(*this, other) != 0;
+ }
+
+ bool operator<(const Entry& other) const {
+ return Entry::compare(*this, other) < 0;
+ }
+
+ OffscreenBuffer* layer = nullptr;
+ uint32_t width = 0;
+ uint32_t height = 0;
+ }; // struct Entry
+
+ std::multiset<Entry> mPool;
+
+ uint32_t mSize = 0;
+ uint32_t mMaxSize;
+}; // class OffscreenBufferCache
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_OFFSCREEN_BUFFER_POOL_H
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index 9637117bc11a..4fa820058fb2 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -90,6 +90,8 @@ void RenderState::onGLContextDestroyed() {
}
*/
+ mLayerPool.clear();
+
// TODO: reset all cached state in state objects
std::for_each(mActiveLayers.begin(), mActiveLayers.end(), layerLostGlContext);
mAssetAtlas.terminate();
@@ -106,6 +108,19 @@ void RenderState::onGLContextDestroyed() {
mStencil = nullptr;
}
+void RenderState::flush(Caches::FlushMode mode) {
+ switch (mode) {
+ case Caches::FlushMode::Full:
+ // fall through
+ case Caches::FlushMode::Moderate:
+ // fall through
+ case Caches::FlushMode::Layers:
+ mLayerPool.clear();
+ break;
+ }
+ mCaches->flush(mode);
+}
+
void RenderState::setViewport(GLsizei width, GLsizei height) {
mViewportWidth = width;
mViewportHeight = height;
diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h
index 3cda1708da75..dcd5ea69a9fe 100644
--- a/libs/hwui/renderstate/RenderState.h
+++ b/libs/hwui/renderstate/RenderState.h
@@ -21,6 +21,7 @@
#include "Glop.h"
#include "renderstate/Blend.h"
#include "renderstate/MeshState.h"
+#include "renderstate/OffscreenBufferPool.h"
#include "renderstate/PixelBufferState.h"
#include "renderstate/Scissor.h"
#include "renderstate/Stencil.h"
@@ -56,6 +57,8 @@ public:
void onGLContextCreated();
void onGLContextDestroyed();
+ void flush(Caches::FlushMode flushMode);
+
void setViewport(GLsizei width, GLsizei height);
void getViewport(GLsizei* outWidth, GLsizei* outHeight);
@@ -97,6 +100,8 @@ public:
Scissor& scissor() { return *mScissor; }
Stencil& stencil() { return *mStencil; }
+ OffscreenBufferPool& layerPool() { return mLayerPool; }
+
void dump();
private:
@@ -116,6 +121,8 @@ private:
Scissor* mScissor = nullptr;
Stencil* mStencil = nullptr;
+ OffscreenBufferPool mLayerPool;
+
AssetAtlas mAssetAtlas;
std::set<Layer*> mActiveLayers;
std::set<renderthread::CanvasContext*> mRegisteredContexts;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 1b89960afc44..f094b2d0c289 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -599,7 +599,7 @@ void CanvasContext::destroyHardwareResources() {
// Make sure to release all the textures we were owning as there won't
// be another draw
caches.textureCache.resetMarkInUse(this);
- caches.flush(Caches::FlushMode::Layers);
+ mRenderThread.renderState().flush(Caches::FlushMode::Layers);
}
}
@@ -609,10 +609,10 @@ void CanvasContext::trimMemory(RenderThread& thread, int level) {
ATRACE_CALL();
if (level >= TRIM_MEMORY_COMPLETE) {
- Caches::getInstance().flush(Caches::FlushMode::Full);
+ thread.renderState().flush(Caches::FlushMode::Full);
thread.eglManager().destroy();
} else if (level >= TRIM_MEMORY_UI_HIDDEN) {
- Caches::getInstance().flush(Caches::FlushMode::Moderate);
+ thread.renderState().flush(Caches::FlushMode::Moderate);
}
}
diff --git a/libs/hwui/tests/TreeContentAnimation.cpp b/libs/hwui/tests/TreeContentAnimation.cpp
index 29d9803ddf9c..81bf9ed1cde3 100644
--- a/libs/hwui/tests/TreeContentAnimation.cpp
+++ b/libs/hwui/tests/TreeContentAnimation.cpp
@@ -408,7 +408,7 @@ class HwLayerAnimation : public TreeContentAnimation {
public:
sp<RenderNode> card = TestUtils::createNode<TestCanvas>(0, 0, 200, 200, [] (TestCanvas& canvas) {
canvas.drawColor(0xFF0000FF, SkXfermode::kSrcOver_Mode);
- }, true);
+ }, TestUtils::getHwLayerSetupCallback());
void createContent(int width, int height, TestCanvas* canvas) override {
canvas->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode); // background
canvas->drawRenderNode(card.get());
diff --git a/libs/hwui/unit_tests/BakedOpStateTests.cpp b/libs/hwui/unit_tests/BakedOpStateTests.cpp
index bc1b69fa3729..4e00fb3a2f86 100644
--- a/libs/hwui/unit_tests/BakedOpStateTests.cpp
+++ b/libs/hwui/unit_tests/BakedOpStateTests.cpp
@@ -60,24 +60,21 @@ TEST(ResolvedRenderState, resolution) {
TEST(BakedOpState, constructAndReject) {
LinearAllocator allocator;
- Matrix4 identity;
- identity.loadIdentity();
-
Matrix4 translate100x0;
translate100x0.loadTranslate(100, 0, 0);
SkPaint paint;
{
RectOp rejectOp(Rect(30, 40, 100, 200), translate100x0, Rect(0, 0, 100, 200), &paint);
- auto snapshot = TestUtils::makeSnapshot(identity, Rect(0, 0, 100, 200));
+ auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(0, 0, 100, 200));
BakedOpState* bakedOp = BakedOpState::tryConstruct(allocator, *snapshot, rejectOp);
EXPECT_EQ(bakedOp, nullptr); // rejected by clip, so not constructed
EXPECT_LE(allocator.usedSize(), 8u); // no significant allocation space used for rejected op
}
{
- RectOp successOp(Rect(30, 40, 100, 200), identity, Rect(0, 0, 100, 200), &paint);
- auto snapshot = TestUtils::makeSnapshot(identity, Rect(0, 0, 100, 200));
+ RectOp successOp(Rect(30, 40, 100, 200), Matrix4::identity(), Rect(0, 0, 100, 200), &paint);
+ auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(0, 0, 100, 200));
BakedOpState* bakedOp = BakedOpState::tryConstruct(allocator, *snapshot, successOp);
EXPECT_NE(bakedOp, nullptr); // NOT rejected by clip, so will be constructed
@@ -85,5 +82,24 @@ TEST(BakedOpState, constructAndReject) {
}
}
+TEST(BakedOpState, oplessConstructAndReject) {
+ LinearAllocator allocator;
+ {
+ auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(0, 0, 0, 0)); // empty
+ BakedOpState* bakedOp = BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234);
+
+ EXPECT_EQ(bakedOp, nullptr); // rejected by clip, so not constructed
+ EXPECT_LE(allocator.usedSize(), 8u); // no significant allocation space used for rejected op
+ }
+ {
+ auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(0, 0, 100, 200));
+ BakedOpState* bakedOp = BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234);
+
+ EXPECT_NE(bakedOp, nullptr); // NOT rejected by clip, so will be constructed
+ EXPECT_GT(allocator.usedSize(), 64u); // relatively large alloc for non-rejected op
+ EXPECT_EQ((ShadowOp*)0x1234, bakedOp->op);
+ }
+}
+
}
}
diff --git a/libs/hwui/unit_tests/OffscreenBufferPoolTests.cpp b/libs/hwui/unit_tests/OffscreenBufferPoolTests.cpp
new file mode 100644
index 000000000000..ba921572fd09
--- /dev/null
+++ b/libs/hwui/unit_tests/OffscreenBufferPoolTests.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#include <gtest/gtest.h>
+#include <renderstate/OffscreenBufferPool.h>
+
+#include <unit_tests/TestUtils.h>
+
+using namespace android;
+using namespace android::uirenderer;
+
+TEST(OffscreenBuffer, computeIdealDimension) {
+ EXPECT_EQ(64u, OffscreenBuffer::computeIdealDimension(1));
+ EXPECT_EQ(64u, OffscreenBuffer::computeIdealDimension(31));
+ EXPECT_EQ(64u, OffscreenBuffer::computeIdealDimension(33));
+ EXPECT_EQ(64u, OffscreenBuffer::computeIdealDimension(64));
+ EXPECT_EQ(1024u, OffscreenBuffer::computeIdealDimension(1000));
+}
+
+TEST(OffscreenBuffer, construct) {
+ TestUtils::runOnRenderThread([] (renderthread::RenderThread& thread) {
+ OffscreenBuffer layer(thread.renderState(), Caches::getInstance(), 49u, 149u);
+ EXPECT_EQ(49u, layer.viewportWidth);
+ EXPECT_EQ(149u, layer.viewportHeight);
+
+ EXPECT_EQ(64u, layer.texture.width);
+ EXPECT_EQ(192u, layer.texture.height);
+
+ EXPECT_EQ(64u * 192u * 4u, layer.getSizeInBytes());
+ });
+}
+
+TEST(OffscreenBufferPool, construct) {
+ TestUtils::runOnRenderThread([] (renderthread::RenderThread& thread) {
+ OffscreenBufferPool pool;
+ EXPECT_EQ(0u, pool.getCount()) << "pool must be created empty";
+ EXPECT_EQ(0u, pool.getSize()) << "pool must be created empty";
+ EXPECT_EQ((uint32_t) Properties::layerPoolSize, pool.getMaxSize())
+ << "pool must read size from Properties";
+ });
+
+}
+
+TEST(OffscreenBufferPool, getPutClear) {
+ TestUtils::runOnRenderThread([] (renderthread::RenderThread& thread) {
+ OffscreenBufferPool pool;
+
+ auto layer = pool.get(thread.renderState(), 100u, 200u);
+ EXPECT_EQ(100u, layer->viewportWidth);
+ EXPECT_EQ(200u, layer->viewportHeight);
+
+ ASSERT_LT(layer->getSizeInBytes(), pool.getMaxSize());
+
+ pool.putOrDelete(layer);
+ ASSERT_EQ(layer->getSizeInBytes(), pool.getSize());
+
+ auto layer2 = pool.get(thread.renderState(), 102u, 202u);
+ EXPECT_EQ(layer, layer2) << "layer should be recycled";
+ ASSERT_EQ(0u, pool.getSize()) << "pool should have been emptied by removing only layer";
+
+ pool.putOrDelete(layer);
+ EXPECT_EQ(1u, pool.getCount());
+ pool.clear();
+ EXPECT_EQ(0u, pool.getSize());
+ EXPECT_EQ(0u, pool.getCount());
+ });
+}
+
+TEST(OffscreenBufferPool, resize) {
+ TestUtils::runOnRenderThread([] (renderthread::RenderThread& thread) {
+ OffscreenBufferPool pool;
+
+ auto layer = pool.get(thread.renderState(), 64u, 64u);
+
+ // resize in place
+ ASSERT_EQ(layer, pool.resize(layer, 60u, 55u));
+ EXPECT_EQ(60u, layer->viewportWidth);
+ EXPECT_EQ(55u, layer->viewportHeight);
+ EXPECT_EQ(64u, layer->texture.width);
+ EXPECT_EQ(64u, layer->texture.height);
+
+ // resized to use different object in pool
+ auto layer2 = pool.get(thread.renderState(), 128u, 128u);
+ pool.putOrDelete(layer2);
+ ASSERT_EQ(1u, pool.getCount());
+ ASSERT_EQ(layer2, pool.resize(layer, 120u, 125u));
+ EXPECT_EQ(120u, layer2->viewportWidth);
+ EXPECT_EQ(125u, layer2->viewportHeight);
+ EXPECT_EQ(128u, layer2->texture.width);
+ EXPECT_EQ(128u, layer2->texture.height);
+
+ // original allocation now only thing in pool
+ EXPECT_EQ(1u, pool.getCount());
+ EXPECT_EQ(layer->getSizeInBytes(), pool.getSize());
+ });
+}
+
+TEST(OffscreenBufferPool, putAndDestroy) {
+ TestUtils::runOnRenderThread([] (renderthread::RenderThread& thread) {
+ OffscreenBufferPool pool;
+ // layer too big to return to the pool
+ // Note: this relies on the fact that the pool won't reject based on max texture size
+ auto hugeLayer = pool.get(thread.renderState(), pool.getMaxSize() / 64, 64);
+ EXPECT_GT(hugeLayer->getSizeInBytes(), pool.getMaxSize());
+ pool.putOrDelete(hugeLayer);
+ EXPECT_EQ(0u, pool.getCount()); // failed to put (so was destroyed instead)
+ });
+}
diff --git a/libs/hwui/unit_tests/OpReordererTests.cpp b/libs/hwui/unit_tests/OpReordererTests.cpp
index f67c24a1bce8..07080a2f3730 100644
--- a/libs/hwui/unit_tests/OpReordererTests.cpp
+++ b/libs/hwui/unit_tests/OpReordererTests.cpp
@@ -38,17 +38,17 @@ LayerUpdateQueue sEmptyLayerUpdateQueue;
* and allows Renderer vs Dispatching behavior to be merged.
*
* onXXXOp methods fail by default - tests should override ops they expect
- * startLayer fails by default - tests should override if expected
+ * startRepaintLayer fails by default - tests should override if expected
* startFrame/endFrame do nothing by default - tests should override to intercept
*/
class TestRendererBase {
public:
virtual ~TestRendererBase() {}
- virtual OffscreenBuffer* createLayer(uint32_t, uint32_t) {
+ virtual OffscreenBuffer* startTemporaryLayer(uint32_t, uint32_t) {
ADD_FAILURE() << "Layer creation not expected in this test";
return nullptr;
}
- virtual void startLayer(OffscreenBuffer*) {
+ virtual void startRepaintLayer(OffscreenBuffer*) {
ADD_FAILURE() << "Layer repaint not expected in this test";
}
virtual void endLayer() {
@@ -82,27 +82,27 @@ public:
MAP_OPS(DISPATCHER_METHOD);
};
-
class FailRenderer : public TestRendererBase {};
-class SimpleTestRenderer : public TestRendererBase {
-public:
- void startFrame(uint32_t width, uint32_t height) override {
- EXPECT_EQ(0, mIndex++);
- EXPECT_EQ(100u, width);
- EXPECT_EQ(200u, height);
- }
- void onRectOp(const RectOp& op, const BakedOpState& state) override {
- EXPECT_EQ(1, mIndex++);
- }
- void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
- EXPECT_EQ(2, mIndex++);
- }
- void endFrame() override {
- EXPECT_EQ(3, mIndex++);
- }
-};
TEST(OpReorderer, simple) {
+ class SimpleTestRenderer : public TestRendererBase {
+ public:
+ void startFrame(uint32_t width, uint32_t height) override {
+ EXPECT_EQ(0, mIndex++);
+ EXPECT_EQ(100u, width);
+ EXPECT_EQ(200u, height);
+ }
+ void onRectOp(const RectOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(1, mIndex++);
+ }
+ void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(2, mIndex++);
+ }
+ void endFrame() override {
+ EXPECT_EQ(3, mIndex++);
+ }
+ };
+
auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
SkBitmap bitmap = TestUtils::createSkBitmap(25, 25);
canvas.drawRect(0, 0, 100, 200, SkPaint());
@@ -115,7 +115,6 @@ TEST(OpReorderer, simple) {
EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end
}
-
TEST(OpReorderer, simpleRejection) {
auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
@@ -129,18 +128,18 @@ TEST(OpReorderer, simpleRejection) {
reorderer.replayBakedOps<TestDispatcher>(renderer);
}
-
-static int SIMPLE_BATCHING_LOOPS = 5;
-class SimpleBatchingTestRenderer : public TestRendererBase {
-public:
- void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
- EXPECT_TRUE(mIndex++ >= SIMPLE_BATCHING_LOOPS);
- }
- void onRectOp(const RectOp& op, const BakedOpState& state) override {
- EXPECT_TRUE(mIndex++ < SIMPLE_BATCHING_LOOPS);
- }
-};
TEST(OpReorderer, simpleBatching) {
+ static int SIMPLE_BATCHING_LOOPS = 5;
+ class SimpleBatchingTestRenderer : public TestRendererBase {
+ public:
+ void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
+ EXPECT_TRUE(mIndex++ >= SIMPLE_BATCHING_LOOPS);
+ }
+ void onRectOp(const RectOp& op, const BakedOpState& state) override {
+ EXPECT_TRUE(mIndex++ < SIMPLE_BATCHING_LOOPS);
+ }
+ };
+
auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
SkBitmap bitmap = TestUtils::createSkBitmap(10, 10);
@@ -162,24 +161,25 @@ TEST(OpReorderer, simpleBatching) {
EXPECT_EQ(2 * SIMPLE_BATCHING_LOOPS, renderer.getIndex()); // 2 x loops ops, because no merging (TODO: force no merging)
}
-class RenderNodeTestRenderer : public TestRendererBase {
-public:
- void onRectOp(const RectOp& op, const BakedOpState& state) override {
- switch(mIndex++) {
- case 0:
- EXPECT_EQ(Rect(0, 0, 200, 200), state.computedState.clippedBounds);
- EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
- break;
- case 1:
- EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds);
- EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
- break;
- default:
- ADD_FAILURE();
- }
- }
-};
TEST(OpReorderer, renderNode) {
+ class RenderNodeTestRenderer : public TestRendererBase {
+ public:
+ void onRectOp(const RectOp& op, const BakedOpState& state) override {
+ switch(mIndex++) {
+ case 0:
+ EXPECT_EQ(Rect(0, 0, 200, 200), state.computedState.clippedBounds);
+ EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
+ break;
+ case 1:
+ EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds);
+ EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
+ break;
+ default:
+ ADD_FAILURE();
+ }
+ }
+ };
+
sp<RenderNode> child = TestUtils::createNode<RecordingCanvas>(10, 10, 110, 110, [](RecordingCanvas& canvas) {
SkPaint paint;
paint.setColor(SK_ColorWHITE);
@@ -210,16 +210,17 @@ TEST(OpReorderer, renderNode) {
reorderer.replayBakedOps<TestDispatcher>(renderer);
}
-class ClippedTestRenderer : public TestRendererBase {
-public:
- void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
- EXPECT_EQ(0, mIndex++);
- EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clippedBounds);
- EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect);
- EXPECT_TRUE(state.computedState.transform.isIdentity());
- }
-};
TEST(OpReorderer, clipped) {
+ class ClippedTestRenderer : public TestRendererBase {
+ public:
+ void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(0, mIndex++);
+ EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clippedBounds);
+ EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect);
+ EXPECT_TRUE(state.computedState.transform.isIdentity());
+ }
+ };
+
sp<RenderNode> node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200, [](RecordingCanvas& canvas) {
SkBitmap bitmap = TestUtils::createSkBitmap(200, 200);
canvas.drawBitmap(bitmap, 0, 0, nullptr);
@@ -236,36 +237,36 @@ TEST(OpReorderer, clipped) {
reorderer.replayBakedOps<TestDispatcher>(renderer);
}
-
-class SaveLayerSimpleTestRenderer : public TestRendererBase {
-public:
- OffscreenBuffer* createLayer(uint32_t width, uint32_t height) override {
- EXPECT_EQ(0, mIndex++);
- EXPECT_EQ(180u, width);
- EXPECT_EQ(180u, height);
- return nullptr;
- }
- void endLayer() override {
- EXPECT_EQ(2, mIndex++);
- }
- void onRectOp(const RectOp& op, const BakedOpState& state) override {
- EXPECT_EQ(1, mIndex++);
- EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds);
- EXPECT_EQ(Rect(0, 0, 180, 180), state.computedState.clippedBounds);
- EXPECT_EQ(Rect(0, 0, 180, 180), state.computedState.clipRect);
-
- Matrix4 expectedTransform;
- expectedTransform.loadTranslate(-10, -10, 0);
- EXPECT_MATRIX_APPROX_EQ(expectedTransform, state.computedState.transform);
- }
- void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
- EXPECT_EQ(3, mIndex++);
- EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
- EXPECT_EQ(Rect(0, 0, 200, 200), state.computedState.clipRect);
- EXPECT_TRUE(state.computedState.transform.isIdentity());
- }
-};
TEST(OpReorderer, saveLayerSimple) {
+ class SaveLayerSimpleTestRenderer : public TestRendererBase {
+ public:
+ OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
+ EXPECT_EQ(0, mIndex++);
+ EXPECT_EQ(180u, width);
+ EXPECT_EQ(180u, height);
+ return nullptr;
+ }
+ void endLayer() override {
+ EXPECT_EQ(2, mIndex++);
+ }
+ void onRectOp(const RectOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(1, mIndex++);
+ EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds);
+ EXPECT_EQ(Rect(0, 0, 180, 180), state.computedState.clippedBounds);
+ EXPECT_EQ(Rect(0, 0, 180, 180), state.computedState.clipRect);
+
+ Matrix4 expectedTransform;
+ expectedTransform.loadTranslate(-10, -10, 0);
+ EXPECT_MATRIX_APPROX_EQ(expectedTransform, state.computedState.transform);
+ }
+ void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(3, mIndex++);
+ EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
+ EXPECT_EQ(Rect(0, 0, 200, 200), state.computedState.clipRect);
+ EXPECT_TRUE(state.computedState.transform.isIdentity());
+ }
+ };
+
auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
canvas.saveLayerAlpha(10, 10, 190, 190, 128, SkCanvas::kClipToLayer_SaveFlag);
canvas.drawRect(10, 10, 190, 190, SkPaint());
@@ -279,57 +280,57 @@ TEST(OpReorderer, saveLayerSimple) {
EXPECT_EQ(4, renderer.getIndex());
}
-
-/* saveLayer1 {rect1, saveLayer2 { rect2 } } will play back as:
- * - createLayer2, rect2 endLayer2
- * - createLayer1, rect1, drawLayer2, endLayer1
- * - startFrame, layerOp1, endFrame
- */
-class SaveLayerNestedTestRenderer : public TestRendererBase {
-public:
- OffscreenBuffer* createLayer(uint32_t width, uint32_t height) override {
- const int index = mIndex++;
- if (index == 0) {
- EXPECT_EQ(400u, width);
- EXPECT_EQ(400u, height);
- return (OffscreenBuffer*) 0x400;
- } else if (index == 3) {
- EXPECT_EQ(800u, width);
- EXPECT_EQ(800u, height);
- return (OffscreenBuffer*) 0x800;
- } else { ADD_FAILURE(); }
- return (OffscreenBuffer*) nullptr;
- }
- void endLayer() override {
- int index = mIndex++;
- EXPECT_TRUE(index == 2 || index == 6);
- }
- void startFrame(uint32_t width, uint32_t height) override {
- EXPECT_EQ(7, mIndex++);
- }
- void endFrame() override {
- EXPECT_EQ(9, mIndex++);
- }
- void onRectOp(const RectOp& op, const BakedOpState& state) override {
- const int index = mIndex++;
- if (index == 1) {
- EXPECT_EQ(Rect(0, 0, 400, 400), op.unmappedBounds); // inner rect
- } else if (index == 4) {
- EXPECT_EQ(Rect(0, 0, 800, 800), op.unmappedBounds); // outer rect
- } else { ADD_FAILURE(); }
- }
- void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
- const int index = mIndex++;
- if (index == 5) {
- EXPECT_EQ((OffscreenBuffer*)0x400, *op.layerHandle);
- EXPECT_EQ(Rect(0, 0, 400, 400), op.unmappedBounds); // inner layer
- } else if (index == 8) {
- EXPECT_EQ((OffscreenBuffer*)0x800, *op.layerHandle);
- EXPECT_EQ(Rect(0, 0, 800, 800), op.unmappedBounds); // outer layer
- } else { ADD_FAILURE(); }
- }
-};
TEST(OpReorderer, saveLayerNested) {
+ /* saveLayer1 { rect1, saveLayer2 { rect2 } } will play back as:
+ * - startTemporaryLayer2, rect2 endLayer2
+ * - startTemporaryLayer1, rect1, drawLayer2, endLayer1
+ * - startFrame, layerOp1, endFrame
+ */
+ class SaveLayerNestedTestRenderer : public TestRendererBase {
+ public:
+ OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
+ const int index = mIndex++;
+ if (index == 0) {
+ EXPECT_EQ(400u, width);
+ EXPECT_EQ(400u, height);
+ return (OffscreenBuffer*) 0x400;
+ } else if (index == 3) {
+ EXPECT_EQ(800u, width);
+ EXPECT_EQ(800u, height);
+ return (OffscreenBuffer*) 0x800;
+ } else { ADD_FAILURE(); }
+ return (OffscreenBuffer*) nullptr;
+ }
+ void endLayer() override {
+ int index = mIndex++;
+ EXPECT_TRUE(index == 2 || index == 6);
+ }
+ void startFrame(uint32_t width, uint32_t height) override {
+ EXPECT_EQ(7, mIndex++);
+ }
+ void endFrame() override {
+ EXPECT_EQ(9, mIndex++);
+ }
+ void onRectOp(const RectOp& op, const BakedOpState& state) override {
+ const int index = mIndex++;
+ if (index == 1) {
+ EXPECT_EQ(Rect(0, 0, 400, 400), op.unmappedBounds); // inner rect
+ } else if (index == 4) {
+ EXPECT_EQ(Rect(0, 0, 800, 800), op.unmappedBounds); // outer rect
+ } else { ADD_FAILURE(); }
+ }
+ void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
+ const int index = mIndex++;
+ if (index == 5) {
+ EXPECT_EQ((OffscreenBuffer*)0x400, *op.layerHandle);
+ EXPECT_EQ(Rect(0, 0, 400, 400), op.unmappedBounds); // inner layer
+ } else if (index == 8) {
+ EXPECT_EQ((OffscreenBuffer*)0x800, *op.layerHandle);
+ EXPECT_EQ(Rect(0, 0, 800, 800), op.unmappedBounds); // outer layer
+ } else { ADD_FAILURE(); }
+ }
+ };
+
auto dl = TestUtils::createDisplayList<RecordingCanvas>(800, 800, [](RecordingCanvas& canvas) {
canvas.saveLayerAlpha(0, 0, 800, 800, 128, SkCanvas::kClipToLayer_SaveFlag);
{
@@ -369,42 +370,41 @@ TEST(OpReorderer, saveLayerContentRejection) {
reorderer.replayBakedOps<TestDispatcher>(renderer);
}
-class HwLayerSimpleTestRenderer : public TestRendererBase {
-public:
- void startLayer(OffscreenBuffer* offscreenBuffer) override {
- EXPECT_EQ(0, mIndex++);
- EXPECT_EQ(offscreenBuffer, (OffscreenBuffer*) 0x0124);
- }
- void onRectOp(const RectOp& op, const BakedOpState& state) override {
- EXPECT_EQ(1, mIndex++);
+TEST(OpReorderer, hwLayerSimple) {
+ class HwLayerSimpleTestRenderer : public TestRendererBase {
+ public:
+ void startRepaintLayer(OffscreenBuffer* offscreenBuffer) override {
+ EXPECT_EQ(0, mIndex++);
+ EXPECT_EQ(offscreenBuffer, (OffscreenBuffer*) 0x0124);
+ }
+ void onRectOp(const RectOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(1, mIndex++);
- EXPECT_TRUE(state.computedState.transform.isIdentity())
- << "Transform should be reset within layer";
+ EXPECT_TRUE(state.computedState.transform.isIdentity())
+ << "Transform should be reset within layer";
+
+ EXPECT_EQ(state.computedState.clipRect, Rect(25, 25, 75, 75))
+ << "Damage rect should be used to clip layer content";
+ }
+ void endLayer() override {
+ EXPECT_EQ(2, mIndex++);
+ }
+ void startFrame(uint32_t width, uint32_t height) override {
+ EXPECT_EQ(3, mIndex++);
+ }
+ void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(4, mIndex++);
+ }
+ void endFrame() override {
+ EXPECT_EQ(5, mIndex++);
+ }
+ };
- EXPECT_EQ(state.computedState.clipRect, Rect(25, 25, 75, 75))
- << "Damage rect should be used to clip layer content";
- }
- void endLayer() override {
- EXPECT_EQ(2, mIndex++);
- }
- void startFrame(uint32_t width, uint32_t height) override {
- EXPECT_EQ(3, mIndex++);
- }
- void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
- EXPECT_EQ(4, mIndex++);
- }
- void endFrame() override {
- EXPECT_EQ(5, mIndex++);
- }
-};
-TEST(OpReorderer, hwLayerSimple) {
sp<RenderNode> node = TestUtils::createNode<RecordingCanvas>(10, 10, 110, 110, [](RecordingCanvas& canvas) {
SkPaint paint;
paint.setColor(SK_ColorWHITE);
canvas.drawRect(0, 0, 100, 100, paint);
- });
- node->mutateStagingProperties().mutateLayerProperties().setType(LayerType::RenderLayer);
- node->setPropertyFieldsDirty(RenderNode::GENERIC);
+ }, TestUtils::getHwLayerSetupCallback());
OffscreenBuffer** bufferHandle = node->getLayerHandle();
*bufferHandle = (OffscreenBuffer*) 0x0124;
@@ -427,69 +427,67 @@ TEST(OpReorderer, hwLayerSimple) {
*bufferHandle = nullptr;
}
-
-/* parentLayer { greyRect, saveLayer { childLayer { whiteRect } } } will play back as:
- * - startLayer(child), rect(grey), endLayer
- * - createLayer, drawLayer(child), endLayer
- * - startLayer(parent), rect(white), drawLayer(saveLayer), endLayer
- * - startFrame, drawLayer(parent), endLayerb
- */
-class HwLayerComplexTestRenderer : public TestRendererBase {
-public:
- OffscreenBuffer* createLayer(uint32_t width, uint32_t height) {
- EXPECT_EQ(3, mIndex++); // savelayer first
- return (OffscreenBuffer*)0xabcd;
- }
- void startLayer(OffscreenBuffer* offscreenBuffer) override {
- int index = mIndex++;
- if (index == 0) {
- // starting inner layer
- EXPECT_EQ((OffscreenBuffer*)0x4567, offscreenBuffer);
- } else if (index == 6) {
- // starting outer layer
- EXPECT_EQ((OffscreenBuffer*)0x0123, offscreenBuffer);
- } else { ADD_FAILURE(); }
- }
- void onRectOp(const RectOp& op, const BakedOpState& state) override {
- int index = mIndex++;
- if (index == 1) {
- // inner layer's rect (white)
- EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
- } else if (index == 7) {
- // outer layer's rect (grey)
- EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
- } else { ADD_FAILURE(); }
- }
- void endLayer() override {
- int index = mIndex++;
- EXPECT_TRUE(index == 2 || index == 5 || index == 9);
- }
- void startFrame(uint32_t width, uint32_t height) override {
- EXPECT_EQ(10, mIndex++);
- }
- void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
- int index = mIndex++;
- if (index == 4) {
- EXPECT_EQ((OffscreenBuffer*)0x4567, *op.layerHandle);
- } else if (index == 8) {
- EXPECT_EQ((OffscreenBuffer*)0xabcd, *op.layerHandle);
- } else if (index == 11) {
- EXPECT_EQ((OffscreenBuffer*)0x0123, *op.layerHandle);
- } else { ADD_FAILURE(); }
- }
- void endFrame() override {
- EXPECT_EQ(12, mIndex++);
- }
-};
TEST(OpReorderer, hwLayerComplex) {
+ /* parentLayer { greyRect, saveLayer { childLayer { whiteRect } } } will play back as:
+ * - startRepaintLayer(child), rect(grey), endLayer
+ * - startTemporaryLayer, drawLayer(child), endLayer
+ * - startRepaintLayer(parent), rect(white), drawLayer(saveLayer), endLayer
+ * - startFrame, drawLayer(parent), endLayerb
+ */
+ class HwLayerComplexTestRenderer : public TestRendererBase {
+ public:
+ OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
+ EXPECT_EQ(3, mIndex++); // savelayer first
+ return (OffscreenBuffer*)0xabcd;
+ }
+ void startRepaintLayer(OffscreenBuffer* offscreenBuffer) override {
+ int index = mIndex++;
+ if (index == 0) {
+ // starting inner layer
+ EXPECT_EQ((OffscreenBuffer*)0x4567, offscreenBuffer);
+ } else if (index == 6) {
+ // starting outer layer
+ EXPECT_EQ((OffscreenBuffer*)0x0123, offscreenBuffer);
+ } else { ADD_FAILURE(); }
+ }
+ void onRectOp(const RectOp& op, const BakedOpState& state) override {
+ int index = mIndex++;
+ if (index == 1) {
+ // inner layer's rect (white)
+ EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
+ } else if (index == 7) {
+ // outer layer's rect (grey)
+ EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
+ } else { ADD_FAILURE(); }
+ }
+ void endLayer() override {
+ int index = mIndex++;
+ EXPECT_TRUE(index == 2 || index == 5 || index == 9);
+ }
+ void startFrame(uint32_t width, uint32_t height) override {
+ EXPECT_EQ(10, mIndex++);
+ }
+ void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
+ int index = mIndex++;
+ if (index == 4) {
+ EXPECT_EQ((OffscreenBuffer*)0x4567, *op.layerHandle);
+ } else if (index == 8) {
+ EXPECT_EQ((OffscreenBuffer*)0xabcd, *op.layerHandle);
+ } else if (index == 11) {
+ EXPECT_EQ((OffscreenBuffer*)0x0123, *op.layerHandle);
+ } else { ADD_FAILURE(); }
+ }
+ void endFrame() override {
+ EXPECT_EQ(12, mIndex++);
+ }
+ };
+
auto child = TestUtils::createNode<RecordingCanvas>(50, 50, 150, 150,
[](RecordingCanvas& canvas) {
SkPaint paint;
paint.setColor(SK_ColorWHITE);
canvas.drawRect(0, 0, 100, 100, paint);
- });
- child->mutateStagingProperties().mutateLayerProperties().setType(LayerType::RenderLayer);
- child->setPropertyFieldsDirty(RenderNode::GENERIC);
+ }, TestUtils::getHwLayerSetupCallback());
*(child->getLayerHandle()) = (OffscreenBuffer*) 0x4567;
RenderNode* childPtr = child.get();
@@ -502,9 +500,7 @@ TEST(OpReorderer, hwLayerComplex) {
canvas.saveLayerAlpha(50, 50, 150, 150, 128, SkCanvas::kClipToLayer_SaveFlag);
canvas.drawRenderNode(childPtr);
canvas.restore();
- });
- parent->mutateStagingProperties().mutateLayerProperties().setType(LayerType::RenderLayer);
- parent->setPropertyFieldsDirty(RenderNode::GENERIC);
+ }, TestUtils::getHwLayerSetupCallback());
*(parent->getLayerHandle()) = (OffscreenBuffer*) 0x0123;
TestUtils::syncHierarchyPropertiesAndDisplayList(parent);
@@ -527,14 +523,6 @@ TEST(OpReorderer, hwLayerComplex) {
*(parent->getLayerHandle()) = nullptr;
}
-
-class ZReorderTestRenderer : public TestRendererBase {
-public:
- void onRectOp(const RectOp& op, const BakedOpState& state) override {
- int expectedOrder = SkColorGetB(op.paint->getColor()); // extract order from blue channel
- EXPECT_EQ(expectedOrder, mIndex++) << "An op was drawn out of order";
- }
-};
static void drawOrderedRect(RecordingCanvas* canvas, uint8_t expectedDrawOrder) {
SkPaint paint;
paint.setColor(SkColorSetARGB(256, 0, 0, expectedDrawOrder)); // order put in blue channel
@@ -550,6 +538,14 @@ static void drawOrderedNode(RecordingCanvas* canvas, uint8_t expectedDrawOrder,
canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
}
TEST(OpReorderer, zReorder) {
+ class ZReorderTestRenderer : public TestRendererBase {
+ public:
+ void onRectOp(const RectOp& op, const BakedOpState& state) override {
+ int expectedOrder = SkColorGetB(op.paint->getColor()); // extract order from blue channel
+ EXPECT_EQ(expectedOrder, mIndex++) << "An op was drawn out of order";
+ }
+ };
+
auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
[](RecordingCanvas& canvas) {
drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
@@ -576,27 +572,64 @@ TEST(OpReorderer, zReorder) {
EXPECT_EQ(10, renderer.getIndex());
};
+TEST(OpReorderer, shadow) {
+ class ShadowTestRenderer : public TestRendererBase {
+ public:
+ void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(0, mIndex++);
+ }
+ void onRectOp(const RectOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(1, mIndex++);
+ }
+ };
-class PropertyTestRenderer : public TestRendererBase {
-public:
- PropertyTestRenderer(std::function<void(const RectOp&, const BakedOpState&)> callback)
- : mCallback(callback) {}
- void onRectOp(const RectOp& op, const BakedOpState& state) override {
- EXPECT_EQ(mIndex++, 0);
- mCallback(op, state);
- }
- std::function<void(const RectOp&, const BakedOpState&)> mCallback;
-};
+ sp<RenderNode> caster = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
+ [](RecordingCanvas& canvas) {
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ canvas.drawRect(0, 0, 100, 100, paint);
+ }, [] (RenderProperties& properties) {
+ properties.setTranslationZ(5.0f);
+ properties.mutableOutline().setRoundRect(0, 0, 100, 100, 5, 1.0f);
+ return RenderNode::GENERIC | RenderNode::TRANSLATION_Z;
+ });
+ sp<RenderNode> parent = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
+ [&caster] (RecordingCanvas& canvas) {
+ canvas.insertReorderBarrier(true);
+ canvas.drawRenderNode(caster.get());
+ });
+
+ TestUtils::syncHierarchyPropertiesAndDisplayList(parent);
+
+ std::vector< sp<RenderNode> > nodes;
+ nodes.push_back(parent.get());
+
+ OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, nodes);
+
+ ShadowTestRenderer renderer;
+ reorderer.replayBakedOps<TestDispatcher>(renderer);
+ EXPECT_EQ(2, renderer.getIndex());
+}
static void testProperty(
- std::function<int(RenderProperties&)> propSetupCallback,
+ TestUtils::PropSetupCallback propSetupCallback,
std::function<void(const RectOp&, const BakedOpState&)> opValidateCallback) {
+ class PropertyTestRenderer : public TestRendererBase {
+ public:
+ PropertyTestRenderer(std::function<void(const RectOp&, const BakedOpState&)> callback)
+ : mCallback(callback) {}
+ void onRectOp(const RectOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(mIndex++, 0);
+ mCallback(op, state);
+ }
+ std::function<void(const RectOp&, const BakedOpState&)> mCallback;
+ };
+
auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100, [](RecordingCanvas& canvas) {
SkPaint paint;
paint.setColor(SK_ColorWHITE);
canvas.drawRect(0, 0, 100, 100, paint);
- });
- node->setPropertyFieldsDirty(propSetupCallback(node->mutateStagingProperties()));
+ }, propSetupCallback);
TestUtils::syncHierarchyPropertiesAndDisplayList(node);
std::vector< sp<RenderNode> > nodes;
diff --git a/libs/hwui/unit_tests/PathParserTests.cpp b/libs/hwui/unit_tests/PathParserTests.cpp
index 244bd6c7a4bd..60ea219ac916 100644
--- a/libs/hwui/unit_tests/PathParserTests.cpp
+++ b/libs/hwui/unit_tests/PathParserTests.cpp
@@ -30,142 +30,179 @@ struct TestData {
const std::function<void(SkPath*)> skPathLamda;
};
-static TestData testData1 {
- // Path
- "M2.000000,22.000000l20.000000,0.000000 1e0-2e3z",
+const static TestData sTestDataSet[] = {
+ // TestData with scientific notation -2e3 etc.
{
- // Verbs
- {'M', 'l', 'z'},
- // Verb sizes
- {2, 4, 0},
- // Points
- {2, 22, 20, 0, 1, -2000},
+ // Path
+ "M2.000000,22.000000l20.000000,0.000000 1e0-2e3z",
+ {
+ // Verbs
+ {'M', 'l', 'z'},
+ // Verb sizes
+ {2, 4, 0},
+ // Points
+ {2, 22, 20, 0, 1, -2000},
+ },
+ [](SkPath* outPath) {
+ outPath->moveTo(2, 22);
+ outPath->rLineTo(20, 0);
+ outPath->rLineTo(1, -2000);
+ outPath->close();
+ outPath->moveTo(2, 22);
+ }
},
- [](SkPath* outPath) {
- outPath->moveTo(2, 22);
- outPath->rLineTo(20, 0);
- outPath->rLineTo(1, -2000);
- outPath->close();
- outPath->moveTo(2, 22);
- }
-};
-static TestData testData2 {
- // Path
- "M 1 1 m 2 2, l 3 3 L 3 3 H 4 h4 V5 v5, Q6 6 6 6 q 6 6 6 6t 7 7 T 7 7 C 8 8 8 8 8 8 c 8 8 8 8 8 8 S 9 9 9 9 s 9 9 9 9 A 10 10 0 1 1 10 10 a 10 10 0 1 1 10 10",
+ // Comprehensive data, containing all the verbs possible.
{
- // Verbs
- {'M', 'm', 'l', 'L', 'H', 'h', 'V', 'v', 'Q', 'q', 't', 'T', 'C', 'c', 'S', 's', 'A', 'a'},
- // VerbSizes
- {2, 2, 2, 2, 1, 1, 1, 1, 4, 4, 2, 2, 6, 6, 4, 4, 7, 7},
- // Points
- {1.0, 1.0, 2.0, 2.0, 3.0, 3.0, 3.0, 3.0, 4.0, 4.0, 5.0, 5.0, 6.0, 6.0, 6.0, 6.0, 6.0, 6.0, 6.0, 6.0, 7.0, 7.0, 7.0, 7.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 9.0, 9.0, 9.0, 9.0, 9.0, 9.0, 9.0, 9.0, 10.0, 10.0, 0.0, 1.0, 1.0, 10.0, 10.0, 10.0, 10.0, 0.0, 1.0, 1.0, 10.0, 10.0, }
+ // Path
+ "M 1 1 m 2 2, l 3 3 L 3 3 H 4 h4 V5 v5, Q6 6 6 6 q 6 6 6 6t 7 7 T 7 7 C 8 8 8 8 8 8 c 8 8 8 8 8 8 S 9 9 9 9 s 9 9 9 9 A 10 10 0 1 1 10 10 a 10 10 0 1 1 10 10",
+ {
+ // Verbs
+ {'M', 'm', 'l', 'L', 'H', 'h', 'V', 'v', 'Q', 'q', 't', 'T', 'C', 'c', 'S', 's', 'A', 'a'},
+ // VerbSizes
+ {2, 2, 2, 2, 1, 1, 1, 1, 4, 4, 2, 2, 6, 6, 4, 4, 7, 7},
+ // Points
+ {1.0, 1.0, 2.0, 2.0, 3.0, 3.0, 3.0, 3.0, 4.0, 4.0, 5.0, 5.0, 6.0, 6.0, 6.0, 6.0, 6.0, 6.0, 6.0, 6.0, 7.0, 7.0, 7.0, 7.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 9.0, 9.0, 9.0, 9.0, 9.0, 9.0, 9.0, 9.0, 10.0, 10.0, 0.0, 1.0, 1.0, 10.0, 10.0, 10.0, 10.0, 0.0, 1.0, 1.0, 10.0, 10.0, }
+ },
+ [](SkPath* outPath) {
+ outPath->moveTo(1.0, 1.0);
+ outPath->rMoveTo(2.0, 2.0);
+ outPath->rLineTo(3.0, 3.0);
+ outPath->lineTo(3.0, 3.0);
+ outPath->lineTo(4.0, 3.0);
+ outPath->rLineTo(4.0, 0);
+ outPath->lineTo(8.0, 5.0);
+ outPath->rLineTo(0, 5.0);
+ outPath->quadTo(6.0, 6.0, 6.0, 6.0);
+ outPath->rQuadTo(6.0, 6.0, 6.0, 6.0);
+ outPath->rQuadTo(0.0, 0.0, 7.0, 7.0);
+ outPath->quadTo(26.0, 26.0, 7.0, 7.0);
+ outPath->cubicTo(8.0, 8.0, 8.0, 8.0, 8.0, 8.0);
+ outPath->rCubicTo(8.0, 8.0, 8.0, 8.0, 8.0, 8.0);
+ outPath->cubicTo(16.0, 16.0, 9.0, 9.0, 9.0, 9.0);
+ outPath->rCubicTo(0.0, 0.0, 9.0, 9.0, 9.0, 9.0);
+ outPath->cubicTo(18.447775037328352, 20.404243860300607, 17.998389141249767, 22.8911717921705, 16.737515350332117, 24.986664170401575);
+ outPath->cubicTo(15.476641559414468, 27.08215654863265, 13.489843598291483, 28.644011882390082, 11.155893964798905, 29.37447073281729);
+ outPath->cubicTo(8.821944331306327, 30.1049295832445, 6.299226382436471, 29.954422532383525, 4.0686829203897235, 28.951642951534332);
+ outPath->cubicTo(1.838139458342976, 27.94886337068514, 0.05113662931485696, 26.161860541657013, -0.9516429515343354, 23.931317079610267);
+ outPath->cubicTo(-1.9544225323835278, 21.70077361756352, -2.1049295832444987, 19.178055668693663, -1.37447073281729, 16.844106035201087);
+ outPath->cubicTo(-0.6440118823900814, 14.51015640170851, 0.9178434513673546, 12.523358440585524, 3.0133358295984305, 11.262484649667876);
+ outPath->cubicTo(5.108828207829506, 10.001610858750228, 7.5957561396993984, 9.552224962671648, 10.000000000000005, 10.0);
+ outPath->cubicTo(10.0, 7.348852265086975, 11.054287646850167, 4.803576729418881, 12.928932188134523, 2.9289321881345254);
+ outPath->cubicTo(14.803576729418879, 1.0542876468501696, 17.348852265086972, 4.870079381441987E-16, 19.999999999999996, 0.0);
+ outPath->cubicTo(22.65114773491302, -4.870079381441987E-16, 25.19642327058112, 1.0542876468501678, 27.071067811865476, 2.9289321881345227);
+ outPath->cubicTo(28.94571235314983, 4.803576729418878, 30.0, 7.348852265086974, 30.0, 9.999999999999998);
+ outPath->cubicTo(30.0, 12.651147734913023, 28.94571235314983, 15.19642327058112, 27.071067811865476, 17.071067811865476);
+ outPath->cubicTo(25.19642327058112, 18.94571235314983, 22.651147734913028, 20.0, 20.000000000000004, 20.0);
+ }
},
- [](SkPath* outPath) {
- outPath->moveTo(1.0, 1.0);
- outPath->rMoveTo(2.0, 2.0);
- outPath->rLineTo(3.0, 3.0);
- outPath->lineTo(3.0, 3.0);
- outPath->lineTo(4.0, 3.0);
- outPath->rLineTo(4.0, 0);
- outPath->lineTo(8.0, 5.0);
- outPath->rLineTo(0, 5.0);
- outPath->quadTo(6.0, 6.0, 6.0, 6.0);
- outPath->rQuadTo(6.0, 6.0, 6.0, 6.0);
- outPath->rQuadTo(0.0, 0.0, 7.0, 7.0);
- outPath->quadTo(26.0, 26.0, 7.0, 7.0);
- outPath->cubicTo(8.0, 8.0, 8.0, 8.0, 8.0, 8.0);
- outPath->rCubicTo(8.0, 8.0, 8.0, 8.0, 8.0, 8.0);
- outPath->cubicTo(16.0, 16.0, 9.0, 9.0, 9.0, 9.0);
- outPath->rCubicTo(0.0, 0.0, 9.0, 9.0, 9.0, 9.0);
- outPath->cubicTo(18.447775037328352, 20.404243860300607, 17.998389141249767, 22.8911717921705, 16.737515350332117, 24.986664170401575);
- outPath->cubicTo(15.476641559414468, 27.08215654863265, 13.489843598291483, 28.644011882390082, 11.155893964798905, 29.37447073281729);
- outPath->cubicTo(8.821944331306327, 30.1049295832445, 6.299226382436471, 29.954422532383525, 4.0686829203897235, 28.951642951534332);
- outPath->cubicTo(1.838139458342976, 27.94886337068514, 0.05113662931485696, 26.161860541657013, -0.9516429515343354, 23.931317079610267);
- outPath->cubicTo(-1.9544225323835278, 21.70077361756352, -2.1049295832444987, 19.178055668693663, -1.37447073281729, 16.844106035201087);
- outPath->cubicTo(-0.6440118823900814, 14.51015640170851, 0.9178434513673546, 12.523358440585524, 3.0133358295984305, 11.262484649667876);
- outPath->cubicTo(5.108828207829506, 10.001610858750228, 7.5957561396993984, 9.552224962671648, 10.000000000000005, 10.0);
- outPath->cubicTo(10.0, 7.348852265086975, 11.054287646850167, 4.803576729418881, 12.928932188134523, 2.9289321881345254);
- outPath->cubicTo(14.803576729418879, 1.0542876468501696, 17.348852265086972, 4.870079381441987E-16, 19.999999999999996, 0.0);
- outPath->cubicTo(22.65114773491302, -4.870079381441987E-16, 25.19642327058112, 1.0542876468501678, 27.071067811865476, 2.9289321881345227);
- outPath->cubicTo(28.94571235314983, 4.803576729418878, 30.0, 7.348852265086974, 30.0, 9.999999999999998);
- outPath->cubicTo(30.0, 12.651147734913023, 28.94571235314983, 15.19642327058112, 27.071067811865476, 17.071067811865476);
- outPath->cubicTo(25.19642327058112, 18.94571235314983, 22.651147734913028, 20.0, 20.000000000000004, 20.0);
- }
-};
-static TestData testData3 {
- // Path
- "M5.3,13.2c-0.1,0.0 -0.3,0.0 -0.4,-0.1c-0.3,-0.2 -0.4,-0.7 -0.2,-1.0c1.3,-1.9 2.9,-3.4 4.9,-4.5c4.1,-2.2 9.3,-2.2 13.4,0.0c1.9,1.1 3.6,2.5 4.9,4.4c0.2,0.3 0.1,0.8 -0.2,1.0c-0.3,0.2 -0.8,0.1 -1.0,-0.2c-1.2,-1.7 -2.6,-3.0 -4.3,-4.0c-3.7,-2.0 -8.3,-2.0 -12.0,0.0c-1.7,0.9 -3.2,2.3 -4.3,4.0C5.7,13.1 5.5,13.2 5.3,13.2z",
+ // Random long data
{
- // Verbs
- {'M', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'C', 'z'},
- // Verb sizes
- {2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0},
- // Points
- {5.3, 13.2, -0.1, 0, -0.3, 0, -0.4, -0.1, -0.3, -0.2, -0.4, -0.7, -0.2, -1, 1.3, -1.9, 2.9, -3.4, 4.9, -4.5, 4.1, -2.2, 9.3, -2.2, 13.4, 0, 1.9, 1.1, 3.6, 2.5, 4.9, 4.4, 0.2, 0.3, 0.1, 0.8, -0.2, 1, -0.3, 0.2, -0.8, 0.1, -1, -0.2, -1.2, -1.7, -2.6, -3, -4.3, -4, -3.7, -2, -8.3, -2, -12, 0, -1.7, 0.9, -3.2, 2.3, -4.3, 4, 5.7, 13.1, 5.5, 13.2, 5.3, 13.2},
+ // Path
+ "M5.3,13.2c-0.1,0.0 -0.3,0.0 -0.4,-0.1c-0.3,-0.2 -0.4,-0.7 -0.2,-1.0c1.3,-1.9 2.9,-3.4 4.9,-4.5c4.1,-2.2 9.3,-2.2 13.4,0.0c1.9,1.1 3.6,2.5 4.9,4.4c0.2,0.3 0.1,0.8 -0.2,1.0c-0.3,0.2 -0.8,0.1 -1.0,-0.2c-1.2,-1.7 -2.6,-3.0 -4.3,-4.0c-3.7,-2.0 -8.3,-2.0 -12.0,0.0c-1.7,0.9 -3.2,2.3 -4.3,4.0C5.7,13.1 5.5,13.2 5.3,13.2z",
+ {
+ // Verbs
+ {'M', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'C', 'z'},
+ // Verb sizes
+ {2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0},
+ // Points
+ {5.3, 13.2, -0.1, 0, -0.3, 0, -0.4, -0.1, -0.3, -0.2, -0.4, -0.7, -0.2, -1, 1.3, -1.9, 2.9, -3.4, 4.9, -4.5, 4.1, -2.2, 9.3, -2.2, 13.4, 0, 1.9, 1.1, 3.6, 2.5, 4.9, 4.4, 0.2, 0.3, 0.1, 0.8, -0.2, 1, -0.3, 0.2, -0.8, 0.1, -1, -0.2, -1.2, -1.7, -2.6, -3, -4.3, -4, -3.7, -2, -8.3, -2, -12, 0, -1.7, 0.9, -3.2, 2.3, -4.3, 4, 5.7, 13.1, 5.5, 13.2, 5.3, 13.2},
+ },
+ [](SkPath* outPath) {
+ outPath->moveTo(5.3, 13.2);
+ outPath->rCubicTo(-0.1, 0.0, -0.3, 0.0, -0.4, -0.1);
+ outPath->rCubicTo(-0.3, -0.2, -0.4, -0.7, -0.2, -1.0);
+ outPath->rCubicTo(1.3, -1.9, 2.9, -3.4, 4.9, -4.5);
+ outPath->rCubicTo(4.1, -2.2, 9.3, -2.2, 13.4, 0.0);
+ outPath->rCubicTo(1.9, 1.1, 3.6, 2.5, 4.9, 4.4);
+ outPath->rCubicTo(0.2, 0.3, 0.1, 0.8, -0.2, 1.0);
+ outPath->rCubicTo(-0.3, 0.2, -0.8, 0.1, -1.0, -0.2);
+ outPath->rCubicTo(-1.2, -1.7, -2.6, -3.0, -4.3, -4.0);
+ outPath->rCubicTo(-3.7, -2.0, -8.3, -2.0, -12.0, 0.0);
+ outPath->rCubicTo(-1.7, 0.9, -3.2, 2.3, -4.3, 4.0);
+ outPath->cubicTo(5.7, 13.1, 5.5, 13.2, 5.3, 13.2);
+ outPath->close();
+ outPath->moveTo(5.3, 13.2);
+ }
},
- [](SkPath* outPath) {
- outPath->moveTo(5.3, 13.2);
- outPath->rCubicTo(-0.1, 0.0, -0.3, 0.0, -0.4, -0.1);
- outPath->rCubicTo(-0.3, -0.2, -0.4, -0.7, -0.2, -1.0);
- outPath->rCubicTo(1.3, -1.9, 2.9, -3.4, 4.9, -4.5);
- outPath->rCubicTo(4.1, -2.2, 9.3, -2.2, 13.4, 0.0);
- outPath->rCubicTo(1.9, 1.1, 3.6, 2.5, 4.9, 4.4);
- outPath->rCubicTo(0.2, 0.3, 0.1, 0.8, -0.2, 1.0);
- outPath->rCubicTo(-0.3, 0.2, -0.8, 0.1, -1.0, -0.2);
- outPath->rCubicTo(-1.2, -1.7, -2.6, -3.0, -4.3, -4.0);
- outPath->rCubicTo(-3.7, -2.0, -8.3, -2.0, -12.0, 0.0);
- outPath->rCubicTo(-1.7, 0.9, -3.2, 2.3, -4.3, 4.0);
- outPath->cubicTo(5.7, 13.1, 5.5, 13.2, 5.3, 13.2);
- outPath->close();
- outPath->moveTo(5.3, 13.2);
- }
-};
-static TestData testData4 {
- // Path
- "l0.0.0.5.0.0.5-0.5.0.0-.5z",
+ // Extreme case with numbers and decimal points crunched together
{
- // Verbs
- {'l', 'z'},
- // Verb sizes
- {10, 0},
- // Points
- {0, 0, 0.5, 0, 0, 0.5, -0.5, 0, 0, -0.5},
+ // Path
+ "l0.0.0.5.0.0.5-0.5.0.0-.5z",
+ {
+ // Verbs
+ {'l', 'z'},
+ // Verb sizes
+ {10, 0},
+ // Points
+ {0, 0, 0.5, 0, 0, 0.5, -0.5, 0, 0, -0.5},
+ },
+ [](SkPath* outPath) {
+ outPath->rLineTo(0.0, 0.0);
+ outPath->rLineTo(0.5, 0.0);
+ outPath->rLineTo(0.0, 0.5);
+ outPath->rLineTo(-0.5, 0.0);
+ outPath->rLineTo(0.0, -0.5);
+ outPath->close();
+ outPath->moveTo(0.0, 0.0);
+ }
},
- [](SkPath* outPath) {
- outPath->rLineTo(0.0, 0.0);
- outPath->rLineTo(0.5, 0.0);
- outPath->rLineTo(0.0, 0.5);
- outPath->rLineTo(-0.5, 0.0);
- outPath->rLineTo(0.0, -0.5);
- outPath->close();
- outPath->moveTo(0.0, 0.0);
- }
-};
-const static TestData testDataSet[] = {testData1, testData2, testData3, testData4};
+ // Empty test data
+ {
+ "",
+ {
+ // Verbs
+ {},
+ {},
+ {},
+ },
+ [](SkPath* outPath) {}
+ }
-TEST(PathPaser, parseString) {
+};
- for (int i = 0; i < 4; i++) {
+TEST(PathParser, parseStringForData) {
+ for (TestData testData: sTestDataSet) {
// Test generated path data against the given data.
PathData pathData;
- TestData testData = testDataSet[i];
size_t length = strlen(testData.pathString);
PathParser::getPathDataFromString(&pathData, testData.pathString, length);
PathParser::dump(pathData);
EXPECT_EQ(testData.pathData, pathData);
+ }
+
+}
- // Test SkPath generated
+TEST(PathParser, createSkPathFromPathData) {
+ for (TestData testData: sTestDataSet) {
SkPath expectedPath;
testData.skPathLamda(&expectedPath);
SkPath actualPath;
- VectorDrawablePath::verbsToPath(&actualPath, &pathData);
+ VectorDrawablePath::verbsToPath(&actualPath, &testData.pathData);
EXPECT_EQ(expectedPath, actualPath);
}
+}
+TEST(PathParser, parseStringForSkPath) {
+ for (TestData testData: sTestDataSet) {
+ size_t length = strlen(testData.pathString);
+ // Check the return value as well as the SkPath generated.
+ SkPath actualPath;
+ bool hasValidData = PathParser::parseStringForSkPath(&actualPath, testData.pathString,
+ length);
+ EXPECT_EQ(hasValidData, testData.pathData.verbs.size() > 0);
+ SkPath expectedPath;
+ testData.skPathLamda(&expectedPath);
+ EXPECT_EQ(expectedPath, actualPath);
+ }
+ SkPath path;
+ EXPECT_FALSE(PathParser::parseStringForSkPath(&path, "l", 1));
+ EXPECT_FALSE(PathParser::parseStringForSkPath(&path, "1 1", 3));
+ EXPECT_FALSE(PathParser::parseStringForSkPath(&path, "LMFAO", 5));
+ EXPECT_TRUE(PathParser::parseStringForSkPath(&path, "m1 1", 4));
}
}; // namespace uirenderer
diff --git a/libs/hwui/unit_tests/TestUtils.h b/libs/hwui/unit_tests/TestUtils.h
index 28e0fd8f3464..efa28ae90262 100644
--- a/libs/hwui/unit_tests/TestUtils.h
+++ b/libs/hwui/unit_tests/TestUtils.h
@@ -97,25 +97,38 @@ public:
return std::unique_ptr<DisplayList>(canvas.finishRecording());
}
- static sp<RenderNode> createNode(int left, int top, int right, int bottom, bool onLayer = false) {
+ typedef std::function<int(RenderProperties&)> PropSetupCallback;
+
+ static PropSetupCallback getHwLayerSetupCallback() {
+ static PropSetupCallback sLayerSetupCallback = [] (RenderProperties& properties) {
+ properties.mutateLayerProperties().setType(LayerType::RenderLayer);
+ return RenderNode::GENERIC;
+ };
+ return sLayerSetupCallback;
+ }
+
+ static sp<RenderNode> createNode(int left, int top, int right, int bottom,
+ PropSetupCallback propSetupCallback = nullptr) {
+#if HWUI_NULL_GPU
// if RenderNodes are being sync'd/used, device info will be needed, since
// DeviceInfo::maxTextureSize() affects layer property
DeviceInfo::initialize();
+#endif
sp<RenderNode> node = new RenderNode();
node->mutateStagingProperties().setLeftTopRightBottom(left, top, right, bottom);
node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
- if (onLayer) {
- node->mutateStagingProperties().mutateLayerProperties().setType(LayerType::RenderLayer);
- node->setPropertyFieldsDirty(RenderNode::GENERIC);
+ if (propSetupCallback) {
+ node->setPropertyFieldsDirty(propSetupCallback(node->mutateStagingProperties()));
}
return node;
}
template<class CanvasType>
static sp<RenderNode> createNode(int left, int top, int right, int bottom,
- std::function<void(CanvasType& canvas)> canvasCallback, bool onLayer = false) {
- sp<RenderNode> node = createNode(left, top, right, bottom, onLayer);
+ std::function<void(CanvasType& canvas)> canvasCallback,
+ PropSetupCallback propSetupCallback = nullptr) {
+ sp<RenderNode> node = createNode(left, top, right, bottom, propSetupCallback);
auto&& props = node->stagingProperties(); // staging, since not sync'd yet
CanvasType canvas(props.getWidth(), props.getHeight());
diff --git a/libs/hwui/utils/Macros.h b/libs/hwui/utils/Macros.h
index 5ca9083aab87..ccf2287400dc 100644
--- a/libs/hwui/utils/Macros.h
+++ b/libs/hwui/utils/Macros.h
@@ -35,4 +35,7 @@
static_assert(std::is_standard_layout<Type>::value, \
#Type " must have standard layout")
+#define WARN_UNUSED_RESULT \
+ __attribute__((warn_unused_result))
+
#endif /* MACROS_H */
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index f36d64020ba0..9ea672287d88 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -20,7 +20,6 @@ import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
-import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
@@ -42,7 +41,6 @@ import android.provider.MediaStore.Files.FileColumns;
import android.provider.MediaStore.Images;
import android.provider.MediaStore.Video;
import android.provider.Settings;
-import android.provider.Settings.SettingNotFoundException;
import android.sax.Element;
import android.sax.ElementListener;
import android.sax.RootElement;
@@ -326,6 +324,8 @@ public class MediaScanner
// used when scanning the image database so we know whether we have to prune
// old thumbnail files
private int mOriginalCount;
+ /** Whether the database had any entries in it before the scan started */
+ private boolean mWasEmptyPriorToScan = false;
/** Whether the scanner has set a default sound for the ringer ringtone. */
private boolean mDefaultRingtoneSet;
/** Whether the scanner has set a default sound for the notification ringtone. */
@@ -535,18 +535,6 @@ public class MediaScanner
if (mMtpObjectHandle != 0) {
entry.mRowId = 0;
}
-
- if ((!mDefaultNotificationSet &&
- doesPathHaveFilename(entry.mPath, mDefaultNotificationFilename))
- || (!mDefaultRingtoneSet &&
- doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename))
- || (!mDefaultAlarmSet &&
- doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename))) {
- Log.w(TAG, "forcing rescan of " + entry.mPath +
- "since ringtone setting didn't finish");
- scanAlways = true;
- }
-
// rescan for metadata if file was modified since last scan
if (entry != null && (entry.mLastModifiedChanged || scanAlways)) {
if (noMedia) {
@@ -926,26 +914,6 @@ public class MediaScanner
}
Uri result = null;
boolean needToSetSettings = false;
- // Setting a flag in order not to use bulk insert for the file related with
- // notifications, ringtones, and alarms, because the rowId of the inserted file is
- // needed.
- if (notifications && !mDefaultNotificationSet) {
- if (TextUtils.isEmpty(mDefaultNotificationFilename) ||
- doesPathHaveFilename(entry.mPath, mDefaultNotificationFilename)) {
- needToSetSettings = true;
- }
- } else if (ringtones && !mDefaultRingtoneSet) {
- if (TextUtils.isEmpty(mDefaultRingtoneFilename) ||
- doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename)) {
- needToSetSettings = true;
- }
- } else if (alarms && !mDefaultAlarmSet) {
- if (TextUtils.isEmpty(mDefaultAlarmAlertFilename) ||
- doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename)) {
- needToSetSettings = true;
- }
- }
-
if (rowId == 0) {
if (mMtpObjectHandle != 0) {
values.put(MediaStore.MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID, mMtpObjectHandle);
@@ -957,6 +925,28 @@ public class MediaScanner
}
values.put(Files.FileColumns.FORMAT, format);
}
+ // Setting a flag in order not to use bulk insert for the file related with
+ // notifications, ringtones, and alarms, because the rowId of the inserted file is
+ // needed.
+ if (mWasEmptyPriorToScan) {
+ if (notifications && !mDefaultNotificationSet) {
+ if (TextUtils.isEmpty(mDefaultNotificationFilename) ||
+ doesPathHaveFilename(entry.mPath, mDefaultNotificationFilename)) {
+ needToSetSettings = true;
+ }
+ } else if (ringtones && !mDefaultRingtoneSet) {
+ if (TextUtils.isEmpty(mDefaultRingtoneFilename) ||
+ doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename)) {
+ needToSetSettings = true;
+ }
+ } else if (alarms && !mDefaultAlarmSet) {
+ if (TextUtils.isEmpty(mDefaultAlarmAlertFilename) ||
+ doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename)) {
+ needToSetSettings = true;
+ }
+ }
+ }
+
// New file, insert it.
// Directories need to be inserted before the files they contain, so they
// get priority when bulk inserting.
@@ -1026,20 +1016,13 @@ public class MediaScanner
private void setSettingIfNotSet(String settingName, Uri uri, long rowId) {
- if(wasSettingAlreadySet(settingName)) {
- return;
- }
-
String existingSettingValue = Settings.System.getString(mContext.getContentResolver(),
settingName);
if (TextUtils.isEmpty(existingSettingValue)) {
// Set the setting to the given URI
-
- ContentResolver cr = mContext.getContentResolver();
- Settings.System.putString(cr, settingName,
+ Settings.System.putString(mContext.getContentResolver(), settingName,
ContentUris.withAppendedId(uri, rowId).toString());
- Settings.System.putInt(cr, settingSetIndicatorName(settingName), 1);
}
}
@@ -1067,20 +1050,6 @@ public class MediaScanner
}; // end of anonymous MediaScannerClient instance
- private String settingSetIndicatorName(String base) {
- return base + "_set";
- }
-
- private boolean wasSettingAlreadySet(String name) {
- ContentResolver cr = mContext.getContentResolver();
- String indicatorName = settingSetIndicatorName(name);
- try {
- return Settings.System.getInt(cr, indicatorName) != 0;
- } catch (SettingNotFoundException e) {
- return false;
- }
- }
-
private void prescan(String filePath, boolean prescanFiles) throws RemoteException {
Cursor c = null;
String where = null;
@@ -1102,10 +1071,6 @@ public class MediaScanner
selectionArgs = new String[] { "" };
}
- mDefaultRingtoneSet = wasSettingAlreadySet(Settings.System.RINGTONE);
- mDefaultNotificationSet = wasSettingAlreadySet(Settings.System.NOTIFICATION_SOUND);
- mDefaultAlarmSet = wasSettingAlreadySet(Settings.System.ALARM_ALERT);
-
// Tell the provider to not delete the file.
// If the file is truly gone the delete is unnecessary, and we want to avoid
// accidentally deleting files that are really there (this may happen if the
@@ -1124,6 +1089,7 @@ public class MediaScanner
// with CursorWindow positioning.
long lastId = Long.MIN_VALUE;
Uri limitUri = mFilesUri.buildUpon().appendQueryParameter("limit", "1000").build();
+ mWasEmptyPriorToScan = true;
while (true) {
selectionArgs[0] = "" + lastId;
@@ -1142,6 +1108,7 @@ public class MediaScanner
if (num == 0) {
break;
}
+ mWasEmptyPriorToScan = false;
while (c.moveToNext()) {
long rowId = c.getLong(FILES_PRESCAN_ID_COLUMN_INDEX);
String path = c.getString(FILES_PRESCAN_PATH_COLUMN_INDEX);
@@ -1293,7 +1260,7 @@ public class MediaScanner
}
}
- private void postscan(final String[] directories) throws RemoteException {
+ private void postscan(String[] directories) throws RemoteException {
// handle playlists last, after we know what media files are on the storage.
if (mProcessPlaylists) {
diff --git a/packages/DefaultContainerService/AndroidManifest.xml b/packages/DefaultContainerService/AndroidManifest.xml
index e67c5542d40a..ccf1501602fe 100644
--- a/packages/DefaultContainerService/AndroidManifest.xml
+++ b/packages/DefaultContainerService/AndroidManifest.xml
@@ -12,7 +12,9 @@
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<application android:label="@string/service_name"
- android:allowBackup="false">
+ android:allowBackup="false"
+ android:forceDeviceEncrypted="true"
+ android:encryptionAware="true">
<service android:name=".DefaultContainerService"
android:enabled="true"
diff --git a/packages/FakeOemFeatures/AndroidManifest.xml b/packages/FakeOemFeatures/AndroidManifest.xml
index 93b8b47db761..fe74ad87ac1d 100644
--- a/packages/FakeOemFeatures/AndroidManifest.xml
+++ b/packages/FakeOemFeatures/AndroidManifest.xml
@@ -11,7 +11,9 @@
android:allowClearUserData="false"
android:allowBackup="false"
android:hardwareAccelerated="true"
- android:label="Fake OEM Features">
+ android:label="Fake OEM Features"
+ android:forceDeviceEncrypted="true"
+ android:encryptionAware="true">
<service android:name=".FakeCoreService" android:process=":core"
android:label="Fake OEM Core Service" />
diff --git a/packages/FusedLocation/AndroidManifest.xml b/packages/FusedLocation/AndroidManifest.xml
index 6a4d4bfc856a..ed84c0d3126c 100644
--- a/packages/FusedLocation/AndroidManifest.xml
+++ b/packages/FusedLocation/AndroidManifest.xml
@@ -28,7 +28,9 @@
<application
android:label="@string/app_label"
- android:process="system">
+ android:process="system"
+ android:forceDeviceEncrypted="true"
+ android:encryptionAware="true">
<uses-library android:name="com.android.location.provider" />
@@ -37,7 +39,7 @@
version. -->
<service android:name="com.android.location.fused.FusedLocationService"
android:exported="true"
- android:permission="android.permission.WRITE_SECURE_SETTINGS" >
+ android:permission="android.permission.WRITE_SECURE_SETTINGS">
<intent-filter>
<action android:name="com.android.location.service.FusedLocationProvider" />
</intent-filter>
diff --git a/packages/InputDevices/AndroidManifest.xml b/packages/InputDevices/AndroidManifest.xml
index f0e4abcb58bf..07885ea6f04b 100644
--- a/packages/InputDevices/AndroidManifest.xml
+++ b/packages/InputDevices/AndroidManifest.xml
@@ -6,7 +6,9 @@
<application
android:allowClearUserData="false"
android:label="@string/app_label"
- android:process="system">
+ android:process="system"
+ android:forceDeviceEncrypted="true"
+ android:encryptionAware="true">
<receiver android:name=".InputDeviceReceiver"
android:label="@string/keyboard_layouts_label">
diff --git a/packages/Keyguard/AndroidManifest.xml b/packages/Keyguard/AndroidManifest.xml
index e19246cdd561..54972b4bae29 100644
--- a/packages/Keyguard/AndroidManifest.xml
+++ b/packages/Keyguard/AndroidManifest.xml
@@ -45,7 +45,9 @@
<application android:label="@string/app_name"
android:process="com.android.systemui"
android:persistent="true"
- android:supportsRtl="true">
+ android:supportsRtl="true"
+ android:forceDeviceEncrypted="true"
+ android:encryptionAware="true">
</application>
</manifest>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
index f95b0aebfd70..9d1df26514ee 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
@@ -18,7 +18,6 @@ package com.android.keyguard;
import android.app.ActivityManager;
import android.app.AlarmManager;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -198,12 +197,18 @@ public class KeyguardStatusView extends GridLayout {
}
private String getOwnerInfo() {
- ContentResolver res = getContext().getContentResolver();
String info = null;
- final boolean ownerInfoEnabled = mLockPatternUtils.isOwnerInfoEnabled(
- KeyguardUpdateMonitor.getCurrentUser());
- if (ownerInfoEnabled) {
- info = mLockPatternUtils.getOwnerInfo(KeyguardUpdateMonitor.getCurrentUser());
+ if (mLockPatternUtils.isDeviceOwnerInfoEnabled()) {
+ // Use the device owner information set by device policy client via
+ // device policy manager.
+ info = mLockPatternUtils.getDeviceOwnerInfo();
+ } else {
+ // Use the current user owner information if enabled.
+ final boolean ownerInfoEnabled = mLockPatternUtils.isOwnerInfoEnabled(
+ KeyguardUpdateMonitor.getCurrentUser());
+ if (ownerInfoEnabled) {
+ info = mLockPatternUtils.getOwnerInfo(KeyguardUpdateMonitor.getCurrentUser());
+ }
}
return info;
}
diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml
index 502378322cae..70abdf4920bb 100644
--- a/packages/PrintSpooler/res/values/strings.xml
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -149,6 +149,9 @@
<!-- Title for the prompt shown as a placeholder if no printers are found while not searching. [CHAR LIMIT=50] -->
<string name="print_searching_for_printers">Searching for printers</string>
+ <!-- Title for the prompt shown as a placeholder if there are no print services. [CHAR LIMIT=50] -->
+ <string name="print_no_print_services">No print services enabled</string>
+
<!-- Title for the prompt shown as a placeholder if there are no printers while searching. [CHAR LIMIT=50] -->
<string name="print_no_printers">No printers found</string>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index 53e07e9833e4..f409fd43d085 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -240,7 +240,9 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
throw new IllegalArgumentException(PrintManager.EXTRA_PRINT_JOB
+ " cannot be null");
}
- mPrintJob.setAttributes(new PrintAttributes.Builder().build());
+ if (mPrintJob.getAttributes() == null) {
+ mPrintJob.setAttributes(new PrintAttributes.Builder().build());
+ }
final IBinder adapter = extras.getBinder(PrintManager.EXTRA_PRINT_DOCUMENT_ADAPTER);
if (adapter == null) {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
index 3905bada8fe2..f4c15bd0690a 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
@@ -84,6 +84,11 @@ public final class SelectPrinterActivity extends Activity {
private static final String EXTRA_PRINTER_ID = "EXTRA_PRINTER_ID";
+ /**
+ * If there are any enabled print services
+ */
+ private boolean mHasEnabledPrintServices;
+
private final ArrayList<PrintServiceInfo> mAddPrinterServices =
new ArrayList<>();
@@ -175,10 +180,6 @@ public final class SelectPrinterActivity extends Activity {
}
});
- if (mAddPrinterServices.isEmpty()) {
- menu.removeItem(R.id.action_add_printer);
- }
-
return true;
}
@@ -230,6 +231,7 @@ public final class SelectPrinterActivity extends Activity {
public void onResume() {
super.onResume();
updateServicesWithAddPrinterActivity();
+ updateEmptyView((DestinationAdapter)mListView.getAdapter());
invalidateOptionsMenu();
}
@@ -258,6 +260,7 @@ public final class SelectPrinterActivity extends Activity {
}
private void updateServicesWithAddPrinterActivity() {
+ mHasEnabledPrintServices = true;
mAddPrinterServices.clear();
// Get all enabled print services.
@@ -266,6 +269,7 @@ public final class SelectPrinterActivity extends Activity {
// No enabled print services - done.
if (enabledServices.isEmpty()) {
+ mHasEnabledPrintServices = false;
return;
}
@@ -324,7 +328,10 @@ public final class SelectPrinterActivity extends Activity {
}
TextView titleView = (TextView) findViewById(R.id.title);
View progressBar = findViewById(R.id.progress_bar);
- if (adapter.getUnfilteredCount() <= 0) {
+ if (!mHasEnabledPrintServices) {
+ titleView.setText(R.string.print_no_print_services);
+ progressBar.setVisibility(View.GONE);
+ } else if (adapter.getUnfilteredCount() <= 0) {
titleView.setText(R.string.print_searching_for_printers);
progressBar.setVisibility(View.VISIBLE);
} else {
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
index f5fc6985a892..6102befdda99 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
@@ -18,6 +18,7 @@ package com.android.settingslib.drawer;
import android.annotation.LayoutRes;
import android.annotation.Nullable;
import android.app.Activity;
+import android.content.res.TypedArray;
import android.os.Bundle;
import android.support.v4.widget.DrawerLayout;
import android.util.Pair;
@@ -54,6 +55,13 @@ public class SettingsDrawerActivity extends Activity {
return;
}
Toolbar toolbar = (Toolbar) findViewById(R.id.action_bar);
+ TypedArray theme = getTheme().obtainStyledAttributes(android.R.styleable.Theme);
+ if (theme.getBoolean(android.R.styleable.Theme_windowNoTitle, false)) {
+ toolbar.setVisibility(View.GONE);
+ mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
+ mDrawerLayout = null;
+ return;
+ }
setActionBar(toolbar);
mDrawerAdapter = new SettingsDrawerAdapter(this);
ListView listView = (ListView) findViewById(R.id.left_drawer);
diff --git a/packages/SettingsProvider/AndroidManifest.xml b/packages/SettingsProvider/AndroidManifest.xml
index 71aefad935fe..ba991fbe44f8 100644
--- a/packages/SettingsProvider/AndroidManifest.xml
+++ b/packages/SettingsProvider/AndroidManifest.xml
@@ -8,11 +8,12 @@
android:process="system"
android:backupAgent="SettingsBackupAgent"
android:killAfterRestore="false"
- android:icon="@mipmap/ic_launcher_settings">
-
- <!-- todo add: android:neverEncrypt="true" -->
+ android:icon="@mipmap/ic_launcher_settings"
+ android:forceDeviceEncrypted="true"
+ android:encryptionAware="true">
- <provider android:name="SettingsProvider" android:authorities="settings"
+ <provider android:name="SettingsProvider"
+ android:authorities="settings"
android:multiprocess="false"
android:exported="true"
android:singleUser="true"
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 05591cc9bc00..8c39ee654e6d 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -108,7 +108,9 @@
<uses-permission android:name="android.permission.REGISTER_SIM_SUBSCRIPTION" />
<uses-permission android:name="android.permission.GET_APP_OPS_STATS" />
- <application android:label="@string/app_label">
+ <application android:label="@string/app_label"
+ android:forceDeviceEncrypted="true"
+ android:encryptionAware="true">
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.android.shell"
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index be5c0fe143b2..6fda2c69b4ac 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -145,7 +145,9 @@
android:icon="@drawable/icon"
android:process="com.android.systemui"
android:supportsRtl="true"
- android:theme="@style/systemui_theme">
+ android:theme="@style/systemui_theme"
+ android:forceDeviceEncrypted="true"
+ android:encryptionAware="true">
<!-- Keep theme in sync with SystemUIApplication.onCreate().
Setting the theme on the application does not affect views inflated by services.
The application theme is set again from onCreate to take effect for those views. -->
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 58f71242bec0..3ae8827b3fc6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -42,7 +42,7 @@ import com.android.systemui.R;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.AppWidgetProviderChangedEvent;
import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
-import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationStartedEvent;
+import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
import com.android.systemui.recents.events.activity.HideRecentsEvent;
import com.android.systemui.recents.events.activity.IterateRecentsEvent;
@@ -115,29 +115,33 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
});
/**
- * A common Runnable to finish Recents either by calling finish() (with a custom animation) or
- * launching Home with some ActivityOptions. Generally we always launch home when we exit
- * Recents rather than just finishing the activity since we don't know what is behind Recents in
- * the task stack. The only case where we finish() directly is when we are cancelling the full
- * screen transition from the app.
+ * A common Runnable to finish Recents by launching Home with an animation depending on the
+ * last activity launch state. Generally we always launch home when we exit Recents rather than
+ * just finishing the activity since we don't know what is behind Recents in the task stack.
*/
class FinishRecentsRunnable implements Runnable {
Intent mLaunchIntent;
- ActivityOptions mLaunchOpts;
/**
- * Creates a finish runnable that starts the specified intent, using the given
- * ActivityOptions.
+ * Creates a finish runnable that starts the specified intent.
*/
- public FinishRecentsRunnable(Intent launchIntent, ActivityOptions opts) {
+ public FinishRecentsRunnable(Intent launchIntent) {
mLaunchIntent = launchIntent;
- mLaunchOpts = opts;
}
@Override
public void run() {
try {
- startActivityAsUser(mLaunchIntent, mLaunchOpts.toBundle(), UserHandle.CURRENT);
+ RecentsActivityLaunchState launchState =
+ Recents.getConfiguration().getLaunchState();
+ ActivityOptions opts = ActivityOptions.makeCustomAnimation(RecentsActivity.this,
+ launchState.launchedFromSearchHome ?
+ R.anim.recents_to_search_launcher_enter :
+ R.anim.recents_to_launcher_enter,
+ launchState.launchedFromSearchHome ?
+ R.anim.recents_to_search_launcher_exit :
+ R.anim.recents_to_launcher_exit);
+ startActivityAsUser(mLaunchIntent, opts.toBundle(), UserHandle.CURRENT);
} catch (Exception e) {
Log.e(TAG, getString(R.string.recents_launch_error_message, "Home"), e);
}
@@ -191,18 +195,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
mRecentsView.setTaskStack(stack);
}
- // Create the home intent runnable
- Intent homeIntent = new Intent(Intent.ACTION_MAIN, null);
- homeIntent.addCategory(Intent.CATEGORY_HOME);
- homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent,
- ActivityOptions.makeCustomAnimation(this,
- launchState.launchedFromSearchHome ? R.anim.recents_to_search_launcher_enter :
- R.anim.recents_to_launcher_enter,
- launchState.launchedFromSearchHome ? R.anim.recents_to_search_launcher_exit :
- R.anim.recents_to_launcher_exit));
-
// Mark the task that is the launch target
int launchTaskIndexInStack = 0;
if (launchState.launchedToTaskId != -1) {
@@ -361,6 +353,13 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
mEmptyViewStub = (ViewStub) findViewById(R.id.empty_view_stub);
mScrimViews = new SystemBarScrimViews(this);
+ // Create the home intent runnable
+ Intent homeIntent = new Intent(Intent.ACTION_MAIN, null);
+ homeIntent.addCategory(Intent.CATEGORY_HOME);
+ homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
+ Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent);
+
// Bind the search app widget when we first start up
if (!Constants.DebugFlags.App.DisableSearchBar) {
mSearchWidgetInfo = ssp.getOrBindSearchAppWidget(this, mAppWidgetHost);
@@ -396,7 +395,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
boolean wasLaunchedByAm = !launchState.launchedFromHome &&
!launchState.launchedFromAppWithThumbnail;
if (launchState.launchedHasConfigurationChanged || wasLaunchedByAm) {
- EventBus.getDefault().send(new EnterRecentsWindowAnimationStartedEvent());
+ EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
}
if (!launchState.launchedHasConfigurationChanged) {
@@ -422,6 +421,12 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
}
@Override
+ public void onEnterAnimationComplete() {
+ super.onEnterAnimationComplete();
+ EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
+ }
+
+ @Override
protected void onPause() {
super.onPause();
@@ -603,7 +608,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
}
}
- public final void onBusEvent(EnterRecentsWindowAnimationStartedEvent event) {
+ public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) {
// Try and start the enter animation (or restart it on configuration changed)
ReferenceCountedTrigger t = new ReferenceCountedTrigger(this, null, null, null);
ViewAnimation.TaskViewEnterContext ctx = new ViewAnimation.TaskViewEnterContext(t);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 4059543d4658..6fe690924055 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -40,7 +40,6 @@ import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.SystemUIApplication;
import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationStartedEvent;
import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
import com.android.systemui.recents.events.activity.HideRecentsEvent;
import com.android.systemui.recents.events.activity.IterateRecentsEvent;
@@ -70,7 +69,7 @@ import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
* be called remotely from the system user.
*/
public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub
- implements ActivityOptions.OnAnimationStartedListener, ActivityOptions.OnAnimationFinishedListener {
+ implements ActivityOptions.OnAnimationFinishedListener {
private final static String TAG = "RecentsImpl";
private final static boolean DEBUG = false;
@@ -140,7 +139,6 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub
TaskStackListenerImpl mTaskStackListener;
RecentsAppWidgetHost mAppWidgetHost;
boolean mBootCompleted;
- boolean mStartAnimationTriggered;
boolean mCanReuseTaskStackViews = true;
// Task launching
@@ -613,7 +611,7 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub
final Task toTask = new Task();
final TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
topTask.id, toTask);
- ForegroundThread.getHandler().post(new Runnable() {
+ ForegroundThread.getHandler().postAtFrontOfQueue(new Runnable() {
@Override
public void run() {
final Bitmap transitionBitmap = drawThumbnailTransitionBitmap(toTask, toTransform);
@@ -635,7 +633,7 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub
return ActivityOptions.makeCustomAnimation(mContext,
R.anim.recents_from_unknown_enter,
R.anim.recents_from_unknown_exit,
- mHandler, this);
+ mHandler, null);
}
/**
@@ -646,12 +644,12 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub
return ActivityOptions.makeCustomAnimation(mContext,
R.anim.recents_from_search_launcher_enter,
R.anim.recents_from_search_launcher_exit,
- mHandler, this);
+ mHandler, null);
}
return ActivityOptions.makeCustomAnimation(mContext,
R.anim.recents_from_launcher_enter,
R.anim.recents_from_launcher_exit,
- mHandler, this);
+ mHandler, null);
}
/**
@@ -677,7 +675,7 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub
AppTransitionAnimationSpec[] specsArray = new AppTransitionAnimationSpec[specs.size()];
specs.toArray(specsArray);
return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
- specsArray, mHandler, this, this);
+ specsArray, mHandler, null, this);
} else {
// Update the destination rect
Task toTask = new Task();
@@ -688,7 +686,7 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub
if (thumbnail != null) {
return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
thumbnail, (int) toTaskRect.left, (int) toTaskRect.top,
- (int) toTaskRect.width(), (int) toTaskRect.height(), mHandler, this);
+ (int) toTaskRect.width(), (int) toTaskRect.height(), mHandler, null);
}
// If both the screenshot and thumbnail fails, then just fall back to the default transition
return getUnknownTransitionActivityOptions();
@@ -841,8 +839,6 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub
private void startRecentsActivity(ActivityManager.RunningTaskInfo topTask,
ActivityOptions opts, boolean fromHome, boolean fromSearchHome, boolean fromThumbnail,
TaskStackLayoutAlgorithm.VisibilityReport vr) {
- mStartAnimationTriggered = false;
-
// Update the configuration based on the launch options
RecentsConfiguration config = Recents.getConfiguration();
RecentsActivityLaunchState launchState = config.getLaunchState();
@@ -870,16 +866,7 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub
mCanReuseTaskStackViews = true;
}
- /**** OnAnimationStartedListener Implementation ****/
-
- @Override
- public void onAnimationStarted() {
- // Notify recents to start the enter animation
- if (!mStartAnimationTriggered) {
- mStartAnimationTriggered = true;
- EventBus.getDefault().post(new EnterRecentsWindowAnimationStartedEvent());
- }
- }
+ /**** OnAnimationFinishedListener Implementation ****/
@Override
public void onAnimationFinished() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/EnterRecentsWindowAnimationStartedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/EnterRecentsWindowAnimationCompletedEvent.java
index f187178d5fc6..b31f32090ac7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/EnterRecentsWindowAnimationStartedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/EnterRecentsWindowAnimationCompletedEvent.java
@@ -19,8 +19,10 @@ package com.android.systemui.recents.events.activity;
import com.android.systemui.recents.events.EventBus;
/**
- * This is sent when the window animation into Recents starts.
+ * This is sent when the window animation into Recents completes. We use this signal to know when
+ * we can start in-app animations so that they don't conflict with the window transition into
+ * Recents.
*/
-public class EnterRecentsWindowAnimationStartedEvent extends EventBus.Event {
+public class EnterRecentsWindowAnimationCompletedEvent extends EventBus.Event {
// Simple event
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
index a28601be03fa..85b8fcfb4a7f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
@@ -270,7 +270,7 @@ public class RecentsTransitionHelper {
int taskCount = tasks.size();
for (int i = taskCount - 1; i >= 0; i--) {
Task t = tasks.get(i);
- if (t.isFreeformTask()) {
+ if (t.isFreeformTask() || targetStackId == FREEFORM_WORKSPACE_STACK_ID) {
TaskView tv = stackView.getChildViewForTask(t);
if (tv == null) {
// TODO: Create a different animation task rect for this case (though it should
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
index c4e2d8a92c42..5a09ee41c744 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
@@ -26,7 +26,7 @@ import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsActivityLaunchState;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
-import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationStartedEvent;
+import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
/** Manages the scrims for the various system bars. */
public class SystemBarScrimViews {
@@ -81,21 +81,11 @@ public class SystemBarScrimViews {
/**
* Starts animating the scrim views when entering Recents.
*/
- public final void onBusEvent(EnterRecentsWindowAnimationStartedEvent event) {
- RecentsConfiguration config = Recents.getConfiguration();
- RecentsActivityLaunchState launchState = config.getLaunchState();
- int transitionEnterFromAppDelay = mContext.getResources().getInteger(
- R.integer.recents_enter_from_app_transition_duration);
- int transitionEnterFromHomeDelay = mContext.getResources().getInteger(
- R.integer.recents_enter_from_home_transition_duration);
-
+ public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) {
if (mHasStatusBarScrim && mShouldAnimateStatusBarScrim) {
mStatusBarScrimView.setTranslationY(-mStatusBarScrimView.getMeasuredHeight());
mStatusBarScrimView.animate()
.translationY(0)
- .setStartDelay(launchState.launchedFromHome ?
- transitionEnterFromHomeDelay :
- transitionEnterFromAppDelay)
.setDuration(mNavBarScrimEnterDuration)
.setInterpolator(mQuintOutInterpolator)
.withStartAction(new Runnable() {
@@ -110,9 +100,6 @@ public class SystemBarScrimViews {
mNavBarScrimView.setTranslationY(mNavBarScrimView.getMeasuredHeight());
mNavBarScrimView.animate()
.translationY(0)
- .setStartDelay(launchState.launchedFromHome ?
- transitionEnterFromHomeDelay :
- transitionEnterFromAppDelay)
.setDuration(mNavBarScrimEnterDuration)
.setInterpolator(mQuintOutInterpolator)
.withStartAction(new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 9c8829fcefb9..a57ac9dd570f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -1161,7 +1161,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
TaskView frontTv = getChildViewForTask(newFrontMostTask);
if (frontTv != null) {
frontTv.onTaskBound(newFrontMostTask);
- frontTv.fadeInActionButton(0, getResources().getInteger(
+ frontTv.fadeInActionButton(getResources().getInteger(
R.integer.recents_task_enter_from_app_duration));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 4f4b91ad5691..cb7465d12918 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -313,10 +313,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
RecentsActivityLaunchState launchState = config.getLaunchState();
Resources res = mContext.getResources();
final TaskViewTransform transform = ctx.currentTaskTransform;
- final int transitionEnterFromAppDelay = res.getInteger(
- R.integer.recents_enter_from_app_transition_duration);
- final int transitionEnterFromHomeDelay = res.getInteger(
- R.integer.recents_enter_from_home_transition_duration);
final int taskViewEnterFromAppDuration = res.getInteger(
R.integer.recents_task_enter_from_app_duration);
final int taskViewEnterFromHomeDuration = res.getInteger(
@@ -332,25 +328,22 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
if (Constants.DebugFlags.App.EnableThumbnailAlphaOnFrontmost) {
// Animate the thumbnail alpha before the dim animation (to prevent updating the
// hardware layer)
- mThumbnailView.startEnterRecentsAnimation(transitionEnterFromAppDelay,
- new Runnable() {
- @Override
- public void run() {
- animateDimToProgress(0, taskViewEnterFromAppDuration,
- ctx.postAnimationTrigger.decrementOnAnimationEnd());
- }
- });
+ mThumbnailView.startEnterRecentsAnimation(new Runnable() {
+ @Override
+ public void run() {
+ animateDimToProgress(taskViewEnterFromAppDuration,
+ ctx.postAnimationTrigger.decrementOnAnimationEnd());
+ }
+ });
} else {
// Immediately start the dim animation
- animateDimToProgress(transitionEnterFromAppDelay,
- taskViewEnterFromAppDuration,
+ animateDimToProgress(taskViewEnterFromAppDuration,
ctx.postAnimationTrigger.decrementOnAnimationEnd());
}
ctx.postAnimationTrigger.increment();
// Animate the action button in
- fadeInActionButton(transitionEnterFromAppDelay,
- taskViewEnterFromAppDuration);
+ fadeInActionButton(taskViewEnterFromAppDuration);
} else {
// Animate the task up if it was occluding the launch target
if (ctx.currentTaskOccludesLaunchTarget) {
@@ -358,7 +351,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
setAlpha(0f);
animate().alpha(1f)
.translationY(transform.translationY)
- .setStartDelay(transitionEnterFromAppDelay)
.setUpdateListener(null)
.setInterpolator(mFastOutSlowInInterpolator)
.setDuration(taskViewEnterFromHomeDuration)
@@ -377,8 +369,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
} else if (launchState.launchedFromHome) {
// Animate the tasks up
int frontIndex = (ctx.currentStackViewCount - ctx.currentStackViewIndex - 1);
- int delay = transitionEnterFromHomeDelay +
- frontIndex * taskViewEnterFromHomeStaggerDelay;
+ int delay = frontIndex * taskViewEnterFromHomeStaggerDelay;
setScaleX(transform.scale);
setScaleY(transform.scale);
@@ -404,13 +395,12 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
}
}
- public void fadeInActionButton(int delay, int duration) {
+ public void fadeInActionButton(int duration) {
// Hide the action button
mActionButtonView.setAlpha(0f);
// Animate the action button in
mActionButtonView.animate().alpha(1f)
- .setStartDelay(delay)
.setDuration(duration)
.setInterpolator(PhoneStatusBar.ALPHA_IN)
.start();
@@ -611,12 +601,11 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
}
/** Animates the dim to the task progress. */
- void animateDimToProgress(int delay, int duration, Animator.AnimatorListener postAnimRunnable) {
+ void animateDimToProgress(int duration, Animator.AnimatorListener postAnimRunnable) {
// Animate the dim into view as well
int toDim = getDimFromTaskProgress();
if (toDim != getDim()) {
ObjectAnimator anim = ObjectAnimator.ofInt(TaskView.this, "dim", toDim);
- anim.setStartDelay(delay);
anim.setDuration(duration);
if (postAnimRunnable != null) {
anim.addListener(postAnimRunnable);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index 690c297da964..bc5084643686 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -218,13 +218,13 @@ public class TaskViewThumbnail extends View {
void onFocusChanged(boolean focused) {
if (focused) {
if (Float.compare(getAlpha(), 1f) != 0) {
- startFadeAnimation(1f, 0, 150, null);
+ startFadeAnimation(1f, 150, null);
}
} else {
float taskViewThumbnailAlpha = getResources().getFloat(
R.dimen.recents_task_view_thumbnail_alpha);
if (Float.compare(getAlpha(), taskViewThumbnailAlpha) != 0) {
- startFadeAnimation(taskViewThumbnailAlpha, 0, 150, null);
+ startFadeAnimation(taskViewThumbnailAlpha, 150, null);
}
}
}
@@ -244,10 +244,10 @@ public class TaskViewThumbnail extends View {
}
/** Animates this task thumbnail as it enters Recents. */
- void startEnterRecentsAnimation(int delay, Runnable postAnimRunnable) {
+ void startEnterRecentsAnimation(Runnable postAnimRunnable) {
float taskViewThumbnailAlpha = getResources().getFloat(
R.dimen.recents_task_view_thumbnail_alpha);
- startFadeAnimation(taskViewThumbnailAlpha, delay,
+ startFadeAnimation(taskViewThumbnailAlpha,
getResources().getInteger(R.integer.recents_task_enter_from_app_duration),
postAnimRunnable);
}
@@ -256,14 +256,13 @@ public class TaskViewThumbnail extends View {
void startLaunchTaskAnimation(Runnable postAnimRunnable) {
int taskViewExitToAppDuration = mContext.getResources().getInteger(
R.integer.recents_task_exit_to_app_duration);
- startFadeAnimation(1f, 0, taskViewExitToAppDuration, postAnimRunnable);
+ startFadeAnimation(1f, taskViewExitToAppDuration, postAnimRunnable);
}
/** Starts a new thumbnail alpha animation. */
- void startFadeAnimation(float finalAlpha, int delay, int duration, final Runnable postAnimRunnable) {
+ void startFadeAnimation(float finalAlpha, int duration, final Runnable postAnimRunnable) {
Utilities.cancelAnimationWithoutCallbacks(mThumbnailAlphaAnimator);
mThumbnailAlphaAnimator = ValueAnimator.ofFloat(mThumbnailAlpha, finalAlpha);
- mThumbnailAlphaAnimator.setStartDelay(delay);
mThumbnailAlphaAnimator.setDuration(duration);
mThumbnailAlphaAnimator.setInterpolator(mFastOutSlowInInterpolator);
mThumbnailAlphaAnimator.addUpdateListener(mThumbnailAlphaUpdateListener);
diff --git a/packages/services/Proxy/AndroidManifest.xml b/packages/services/Proxy/AndroidManifest.xml
index bbcd6b93bbb0..88f83813fe7f 100644
--- a/packages/services/Proxy/AndroidManifest.xml
+++ b/packages/services/Proxy/AndroidManifest.xml
@@ -7,7 +7,9 @@
<application
android:label="@string/app_label"
- android:process="com.android.proxyhandler">
+ android:process="com.android.proxyhandler"
+ android:forceDeviceEncrypted="true"
+ android:encryptionAware="true">
<service android:name=".ProxyService"
android:exported="true">
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
index b4411cf28487..781d13453be4 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
@@ -341,7 +341,7 @@ class MagnificationController {
mTransformationAnimator.start();
}
- private void setMagnificationSpec(MagnificationSpec spec) {
+ public void setMagnificationSpec(MagnificationSpec spec) {
if (DEBUG_SET_MAGNIFICATION_SPEC) {
Slog.i(LOG_TAG, "Sending: " + spec);
}
@@ -351,6 +351,10 @@ class MagnificationController {
mWindowManager.setMagnificationSpec(MagnificationSpec.obtain(spec));
}
+ public MagnificationSpec getMagnificationSpec() {
+ return mSentMagnificationSpec;
+ }
+
private static class MagnificationSpecEvaluator implements TypeEvaluator<MagnificationSpec> {
private final MagnificationSpec mTempTransformationSpec = MagnificationSpec.obtain();
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index fd67b4148b89..f329cff2c98d 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -95,8 +95,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60;
private static final int MESSAGE_TIMEOUT_BIND =100;
private static final int MESSAGE_TIMEOUT_UNBIND =101;
- private static final int MESSAGE_GET_NAME_AND_ADDRESS=200;
- private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201;
private static final int MESSAGE_USER_SWITCHED = 300;
private static final int MESSAGE_ADD_PROXY_DELAYED = 400;
private static final int MESSAGE_BIND_PROFILE_SERVICE = 401;
@@ -587,15 +585,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
}
- /** @hide*/
- public void getNameAndAddress() {
- if (DBG) {
- Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth +
- " mBinding = " + mBinding);
- }
- Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
- mHandler.sendMessage(msg);
- }
public boolean enableNoAutoConnect()
{
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
@@ -681,14 +670,13 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
if (mUnbinding) return;
mUnbinding = true;
if (mBluetooth != null) {
- if (!mConnection.isGetNameAddressOnly()) {
- //Unregister callback object
- try {
- mBluetooth.unregisterCallback(mBluetoothCallback);
- } catch (RemoteException re) {
- Log.e(TAG, "Unable to unregister BluetoothCallback",re);
- }
+ //Unregister callback object
+ try {
+ mBluetooth.unregisterCallback(mBluetoothCallback);
+ } catch (RemoteException re) {
+ Log.e(TAG, "Unable to unregister BluetoothCallback",re);
}
+
if (DBG) Log.d(TAG, "Sending unbind request.");
mBluetooth = null;
//Unbind
@@ -780,11 +768,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
sendEnableMsg(mQuietEnableExternal);
}
- if (!isNameAndAddressSet()) {
- // Sync the Bluetooth name and address from the Bluetooth Adapter
- if (DBG) Log.d(TAG, "Retrieving Bluetooth Adapter name and address...");
- getNameAndAddress();
- }
}
/**
@@ -957,42 +940,38 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
* Inform BluetoothAdapter instances that Adapter service is up
*/
private void sendBluetoothServiceUpCallback() {
- if (!mConnection.isGetNameAddressOnly()) {
- if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks");
- try {
- int n = mCallbacks.beginBroadcast();
- Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
- for (int i=0; i <n;i++) {
- try {
- mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
- }
+ if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks");
+ try {
+ int n = mCallbacks.beginBroadcast();
+ Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
+ for (int i=0; i <n;i++) {
+ try {
+ mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
}
- } finally {
- mCallbacks.finishBroadcast();
}
+ } finally {
+ mCallbacks.finishBroadcast();
}
}
/**
* Inform BluetoothAdapter instances that Adapter service is down
*/
private void sendBluetoothServiceDownCallback() {
- if (!mConnection.isGetNameAddressOnly()) {
- if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
- try {
- int n = mCallbacks.beginBroadcast();
- Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
- for (int i=0; i <n;i++) {
- try {
- mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
- }
+ if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
+ try {
+ int n = mCallbacks.beginBroadcast();
+ Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
+ for (int i=0; i <n;i++) {
+ try {
+ mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
}
- } finally {
- mCallbacks.finishBroadcast();
}
+ } finally {
+ mCallbacks.finishBroadcast();
}
}
@@ -1052,17 +1031,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
private class BluetoothServiceConnection implements ServiceConnection {
-
- private boolean mGetNameAddressOnly;
-
- public void setGetNameAddressOnly(boolean getOnly) {
- mGetNameAddressOnly = getOnly;
- }
-
- public boolean isGetNameAddressOnly() {
- return mGetNameAddressOnly;
- }
-
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "BluetoothServiceConnection: " + className.getClassName());
Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
@@ -1108,104 +1076,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
public void handleMessage(Message msg) {
if (DBG) Log.d (TAG, "Message: " + msg.what);
switch (msg.what) {
- case MESSAGE_GET_NAME_AND_ADDRESS: {
- if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
- synchronized(mConnection) {
- //Start bind request
- if ((mBluetooth == null) && (!mBinding)) {
- if (DBG) Log.d(TAG, "Binding to service to get name and address");
- mConnection.setGetNameAddressOnly(true);
- //Start bind timeout and bind
- Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
- mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
- Intent i = new Intent(IBluetooth.class.getName());
- if (!doBind(i, mConnection,
- Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
- UserHandle.CURRENT)) {
- mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
- } else {
- mBinding = true;
- }
- }
- else {
- Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
- saveMsg.arg1 = 0;
- if (mBluetooth != null) {
- mHandler.sendMessage(saveMsg);
- } else {
- // if enable is also called to bind the service
- // wait for MESSAGE_BLUETOOTH_SERVICE_CONNECTED
- mHandler.sendMessageDelayed(saveMsg, TIMEOUT_SAVE_MS);
- }
- }
- }
- break;
- }
- case MESSAGE_SAVE_NAME_AND_ADDRESS: {
- boolean unbind = false;
- if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
- synchronized(mConnection) {
- if (!mEnable && mBluetooth != null && !mConnection.isGetNameAddressOnly()) {
- try {
- mBluetooth.enable();
- } catch (RemoteException e) {
- Log.e(TAG,"Unable to call enable()",e);
- }
- }
- }
- if (mBluetooth != null && !mConnection.isGetNameAddressOnly()) waitForOnOff(true, false);
- synchronized(mConnection) {
- if (mBluetooth != null) {
- String name = null;
- String address = null;
- try {
- name = mBluetooth.getName();
- address = mBluetooth.getAddress();
- } catch (RemoteException re) {
- Log.e(TAG,"",re);
- }
-
- if (name != null && address != null) {
- storeNameAndAddress(name,address);
- if (mConnection.isGetNameAddressOnly()) {
- unbind = true;
- }
- } else {
- if (msg.arg1 < MAX_SAVE_RETRIES) {
- Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
- retryMsg.arg1= 1+msg.arg1;
- if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
- mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
- } else {
- Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
- if (mConnection.isGetNameAddressOnly()) {
- unbind = true;
- }
- }
- }
- if (!mEnable && !mConnection.isGetNameAddressOnly()) {
- try {
- mBluetooth.disable();
- } catch (RemoteException e) {
- Log.e(TAG,"Unable to call disable()",e);
- }
- }
- } else {
- // rebind service by Request GET NAME AND ADDRESS
- // if service is unbinded by disable or
- // MESSAGE_BLUETOOTH_SERVICE_CONNECTED is not received
- Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
- mHandler.sendMessage(getMsg);
- }
- }
- if (!mEnable && mBluetooth != null && !mConnection.isGetNameAddressOnly()) {
- waitForOnOff(false, true);
- }
- if (unbind) {
- unbindAndFinish();
- }
- break;
- }
case MESSAGE_ENABLE:
if (DBG) {
Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
@@ -1308,14 +1178,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
Log.e(TAG,"Unable to call configHciSnoopLog", e);
}
- if (mConnection.isGetNameAddressOnly()) {
- //Request GET NAME AND ADDRESS
- Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
- mHandler.sendMessage(getMsg);
- if (!mEnable) return;
- }
-
- mConnection.setGetNameAddressOnly(false);
//Register callback object
try {
mBluetooth.registerCallback(mBluetoothCallback);
@@ -1412,25 +1274,23 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
SERVICE_RESTART_TIME_MS);
}
- if (!mConnection.isGetNameAddressOnly()) {
- sendBluetoothServiceDownCallback();
+ sendBluetoothServiceDownCallback();
- // Send BT state broadcast to update
- // the BT icon correctly
- if ((mState == BluetoothAdapter.STATE_TURNING_ON) ||
- (mState == BluetoothAdapter.STATE_ON)) {
- bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
- BluetoothAdapter.STATE_TURNING_OFF);
- mState = BluetoothAdapter.STATE_TURNING_OFF;
- }
- if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
- bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
- BluetoothAdapter.STATE_OFF);
- }
-
- mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
- mState = BluetoothAdapter.STATE_OFF;
+ // Send BT state broadcast to update
+ // the BT icon correctly
+ if ((mState == BluetoothAdapter.STATE_TURNING_ON) ||
+ (mState == BluetoothAdapter.STATE_ON)) {
+ bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
+ BluetoothAdapter.STATE_TURNING_OFF);
+ mState = BluetoothAdapter.STATE_TURNING_OFF;
+ }
+ if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
+ bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
+ BluetoothAdapter.STATE_OFF);
}
+
+ mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
+ mState = BluetoothAdapter.STATE_OFF;
break;
}
case MESSAGE_RESTART_BLUETOOTH_SERVICE:
@@ -1539,7 +1399,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
//Start bind timeout and bind
Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
- mConnection.setGetNameAddressOnly(false);
Intent i = new Intent(IBluetooth.class.getName());
if (!doBind(i, mConnection,Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
UserHandle.CURRENT)) {
@@ -1548,21 +1407,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
mBinding = true;
}
} else if (mBluetooth != null) {
- if (mConnection.isGetNameAddressOnly()) {
- // if GetNameAddressOnly is set, we can clear this flag,
- // so the service won't be unbind
- // after name and address are saved
- mConnection.setGetNameAddressOnly(false);
- //Register callback object
- try {
- mBluetooth.registerCallback(mBluetoothCallback);
- } catch (RemoteException re) {
- Log.e(TAG, "Unable to register BluetoothCallback",re);
- }
- //Inform BluetoothAdapter instances that service is up
- sendBluetoothServiceUpCallback();
- }
-
//Enable bluetooth
try {
if (!mQuietEnable) {
@@ -1594,9 +1438,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
private void handleDisable() {
synchronized(mConnection) {
- // don't need to disable if GetNameAddressOnly is set,
- // service will be unbinded after Name and Address are saved
- if ((mBluetooth != null) && (!mConnection.isGetNameAddressOnly())) {
+ if (mBluetooth != null) {
if (DBG) Log.d(TAG,"Sending off request.");
try {
diff --git a/services/core/java/com/android/server/BluetoothService.java b/services/core/java/com/android/server/BluetoothService.java
index 73e8c52a3e62..019d03df1942 100644
--- a/services/core/java/com/android/server/BluetoothService.java
+++ b/services/core/java/com/android/server/BluetoothService.java
@@ -31,14 +31,15 @@ class BluetoothService extends SystemService {
@Override
public void onStart() {
- Log.d(TAG, "onStart: publishing BluetoothManagerService");
- publishBinderService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE, mBluetoothManagerService);
}
@Override
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
Log.d(TAG, "onBootPhase: PHASE_SYSTEM_SERVICES_READY");
+ publishBinderService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE, mBluetoothManagerService);
+ } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+ Log.d(TAG, "onBootPhase: PHASE_ACTIVITY_MANAGER_READY");
mBluetoothManagerService.handleOnBootPhase();
}
}
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 6e4f2388f478..37dd884c8dc7 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -96,6 +96,7 @@ import com.android.internal.os.SomeArgs;
import com.android.internal.os.Zygote;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.HexDump;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.server.NativeDaemonConnector.Command;
@@ -119,6 +120,7 @@ import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -284,6 +286,8 @@ class MountService extends IMountService.Stub
@GuardedBy("mLock")
private int[] mStartedUsers = EmptyArray.INT;
+ @GuardedBy("mLock")
+ private int[] mUnlockedUsers = EmptyArray.INT;
/** Map from disk ID to disk */
@GuardedBy("mLock")
@@ -402,6 +406,17 @@ class MountService extends IMountService.Stub
}
}
+ private static String escapeNull(String arg) {
+ if (TextUtils.isEmpty(arg)) {
+ return "!";
+ } else {
+ if (arg.indexOf('\0') != -1 || arg.indexOf(' ') != -1) {
+ throw new IllegalArgumentException(arg);
+ }
+ return arg;
+ }
+ }
+
/** List of crypto types.
* These must match CRYPT_TYPE_XXX in cryptfs.h AND their
* corresponding commands in CommandListener.cpp */
@@ -1892,6 +1907,9 @@ class MountService extends IMountService.Stub
if ((mask & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0) {
mForceAdoptable = (flags & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0;
}
+ if ((mask & StorageManager.DEBUG_EMULATE_FBE) != 0) {
+ // TODO: persist through vold and reboot
+ }
writeSettingsLocked();
mHandler.obtainMessage(H_RESET).sendToTarget();
@@ -2654,65 +2672,99 @@ class MountService extends IMountService.Stub
}
@Override
- public void createNewUserDir(int userHandle, String path) {
- if (Binder.getCallingUid() != Process.SYSTEM_UID) {
- throw new SecurityException("Only SYSTEM_UID can create user directories");
+ public void createUserKey(int userId, int serialNumber) {
+ enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
+ waitForReady();
+
+ try {
+ mCryptConnector.execute("cryptfs", "create_user_key", userId, serialNumber);
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
}
+ }
+ @Override
+ public void destroyUserKey(int userId) {
+ enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
waitForReady();
- if (DEBUG_EVENTS) {
- Slog.i(TAG, "Creating new user dir");
+ try {
+ mCryptConnector.execute("cryptfs", "destroy_user_key", userId);
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+ }
+
+ @Override
+ public void unlockUserKey(int userId, int serialNumber, byte[] token) {
+ enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
+ waitForReady();
+
+ final String encodedToken;
+ if (ArrayUtils.isEmpty(token)) {
+ encodedToken = "!";
+ } else {
+ encodedToken = HexDump.toHexString(token);
}
try {
- NativeDaemonEvent event = mCryptConnector.execute(
- "cryptfs", "createnewuserdir", userHandle, path);
- if (!"0".equals(event.getMessage())) {
- String error = "createnewuserdir sent unexpected message: "
- + event.getMessage();
- Slog.e(TAG, error);
- // ext4enc:TODO is this the right exception?
- throw new RuntimeException(error);
- }
+ mCryptConnector.execute("cryptfs", "unlock_user_key", userId, serialNumber,
+ new SensitiveArg(encodedToken));
} catch (NativeDaemonConnectorException e) {
- Slog.e(TAG, "createnewuserdir threw exception", e);
- throw new RuntimeException("createnewuserdir threw exception", e);
+ throw e.rethrowAsParcelableException();
+ }
+
+ synchronized (mLock) {
+ mUnlockedUsers = ArrayUtils.appendInt(mUnlockedUsers, userId);
}
}
- // ext4enc:TODO duplication between this and createNewUserDir is nasty
@Override
- public void deleteUserKey(int userHandle) {
- if (Binder.getCallingUid() != Process.SYSTEM_UID) {
- throw new SecurityException("Only SYSTEM_UID can delete user keys");
+ public void lockUserKey(int userId) {
+ enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
+ waitForReady();
+
+ try {
+ mCryptConnector.execute("cryptfs", "lock_user_key", userId);
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
}
- waitForReady();
+ synchronized (mLock) {
+ mUnlockedUsers = ArrayUtils.removeInt(mUnlockedUsers, userId);
+ }
+ }
- if (DEBUG_EVENTS) {
- Slog.i(TAG, "Deleting user key");
+ @Override
+ public boolean isUserKeyUnlocked(int userId) {
+ if (SystemProperties.getBoolean(StorageManager.PROP_HAS_FBE, false)) {
+ synchronized (mLock) {
+ return ArrayUtils.contains(mUnlockedUsers, userId);
+ }
+ } else {
+ return true;
}
+ }
+
+ @Override
+ public void prepareUserStorage(String volumeUuid, int userId, int serialNumber) {
+ enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
+ waitForReady();
try {
- NativeDaemonEvent event = mCryptConnector.execute(
- "cryptfs", "deleteuserkey", userHandle);
- if (!"0".equals(event.getMessage())) {
- String error = "deleteuserkey sent unexpected message: "
- + event.getMessage();
- Slog.e(TAG, error);
- // ext4enc:TODO is this the right exception?
- throw new RuntimeException(error);
- }
+ mCryptConnector.execute("cryptfs", "prepare_user_storage", escapeNull(volumeUuid),
+ userId, serialNumber);
} catch (NativeDaemonConnectorException e) {
- Slog.e(TAG, "deleteuserkey threw exception", e);
- throw new RuntimeException("deleteuserkey threw exception", e);
+ throw e.rethrowAsParcelableException();
}
}
@Override
public boolean isPerUserEncryptionEnabled() {
- return "file".equals(SystemProperties.get("ro.crypto.type", "none"));
+ // TODO: switch this over to a single property; currently using two to
+ // handle the emulated case
+ return "file".equals(SystemProperties.get("ro.crypto.type", "none"))
+ || SystemProperties.getBoolean(StorageManager.PROP_HAS_FBE, false);
}
@Override
@@ -3449,6 +3501,9 @@ class MountService extends IMountService.Stub
pw.println();
pw.println("Primary storage UUID: " + mPrimaryStorageUuid);
pw.println("Force adoptable: " + mForceAdoptable);
+ pw.println();
+ pw.println("Started users: " + Arrays.toString(mStartedUsers));
+ pw.println("Unlocked users: " + Arrays.toString(mUnlockedUsers));
}
synchronized (mObbMounts) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2b776b95b44e..cde126ad23fb 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -55,8 +55,6 @@ import android.app.IActivityContainerCallback;
import android.app.IAppTask;
import android.app.ITaskStackListener;
import android.app.ProfilerInfo;
-import android.app.admin.DevicePolicyManagerInternal;
-import android.app.admin.IDevicePolicyManager;
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
import android.app.usage.UsageEvents;
@@ -334,6 +332,11 @@ public final class ActivityManagerService extends ActivityManagerNative
// before we decide it must be hung.
static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10*1000;
+ // How long we will retain processes hosting content providers in the "last activity"
+ // state before allowing them to drop down to the regular cached LRU list. This is
+ // to avoid thrashing of provider processes under low memory situations.
+ static final int CONTENT_PROVIDER_RETAIN_TIME = 20*1000;
+
// How long we wait for a launched process to attach to the activity manager
// before we decide it's never going to come up for real, when the process was
// started with a wrapper for instrumentation (such as Valgrind) because it
@@ -504,6 +507,11 @@ public final class ActivityManagerService extends ActivityManagerNative
*/
SparseArray<String[]> mLockTaskPackages = new SparseArray<>();
+ /**
+ * The package name of the DeviceOwner. This package is not permitted to have its data cleared.
+ */
+ String mDeviceOwnerName;
+
final UserController mUserController;
public class PendingAssistExtras extends Binder implements Runnable {
@@ -5134,12 +5142,8 @@ public final class ActivityManagerService extends ActivityManagerNative
public boolean clearApplicationUserData(final String packageName,
final IPackageDataObserver observer, int userId) {
enforceNotIsolatedCaller("clearApplicationUserData");
-
- final DevicePolicyManagerInternal dpmi =
- LocalServices.getService(DevicePolicyManagerInternal.class);
- if (dpmi != null && dpmi.isDeviceAdminPackage(userId, packageName)) {
- throw new SecurityException(
- "Clearing DeviceAdmin/DeviceOwner/ProfileOwner data is forbidden.");
+ if (packageName != null && packageName.equals(mDeviceOwnerName)) {
+ throw new SecurityException("Clearing DeviceOwner data is forbidden.");
}
int uid = Binder.getCallingUid();
int pid = Binder.getCallingPid();
@@ -9240,6 +9244,17 @@ public final class ActivityManagerService extends ActivityManagerNative
}
@Override
+ public void updateDeviceOwner(String packageName) {
+ final int callingUid = Binder.getCallingUid();
+ if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
+ throw new SecurityException("updateDeviceOwner called from non-system process");
+ }
+ synchronized (this) {
+ mDeviceOwnerName = packageName;
+ }
+ }
+
+ @Override
public void updateLockTaskPackages(int userId, String[] packages) {
final int callingUid = Binder.getCallingUid();
if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
@@ -9636,6 +9651,14 @@ public final class ActivityManagerService extends ActivityManagerNative
if (conn.stableCount == 0 && conn.unstableCount == 0) {
cpr.connections.remove(conn);
conn.client.conProviders.remove(conn);
+ if (conn.client.setProcState < ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
+ // The client is more important than last activity -- note the time this
+ // is happening, so we keep the old provider process around a bit as last
+ // activity to avoid thrashing it.
+ if (cpr.proc != null) {
+ cpr.proc.lastProviderTime = SystemClock.uptimeMillis();
+ }
+ }
stopAssociationLocked(conn.client.uid, conn.client.processName, cpr.uid, cpr.name);
return true;
}
@@ -18390,6 +18413,18 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
+ if (app.lastProviderTime > 0 && (app.lastProviderTime+CONTENT_PROVIDER_RETAIN_TIME) > now) {
+ if (adj > ProcessList.PREVIOUS_APP_ADJ) {
+ adj = ProcessList.PREVIOUS_APP_ADJ;
+ schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+ app.cached = false;
+ app.adjType = "provider";
+ }
+ if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
+ procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
+ }
+ }
+
if (mayBeTop && procState > ActivityManager.PROCESS_STATE_TOP) {
// A client of one of our services or providers is in the top state. We
// *may* want to be in the top state, but not if we are already running in
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index ba6e9b1c1a4d..853a55c0f9f2 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -3103,6 +3103,9 @@ final class ActivityStack {
// If the activity is PAUSING, we will complete the finish once
// it is done pausing; else we can just directly finish it here.
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish not pausing: " + r);
+ if (r.visible) {
+ mWindowManager.setAppVisibility(r.appToken, false);
+ }
return finishCurrentActivityLocked(r, FINISH_AFTER_PAUSE, oomAdj) == null;
} else {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish waiting for pause of: " + r);
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index b77eec8adf0e..4bfe30075cff 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -136,6 +136,7 @@ final class ProcessRecord {
long curCpuTime; // How long proc has run CPU most recently
long lastRequestedGc; // When we last asked the app to do a gc
long lastLowMemory; // When we last told the app that memory is low
+ long lastProviderTime; // The last time someone else was using a provider in this process.
boolean reportLowMemory; // Set to true when waiting to report low mem
boolean empty; // Is this an empty background process?
boolean cached; // Is this a cached process?
@@ -317,6 +318,11 @@ final class ProcessRecord {
pw.print(" foregroundActivities="); pw.print(foregroundActivities);
pw.print(" (rep="); pw.print(repForegroundActivities); pw.println(")");
}
+ if (lastProviderTime > 0) {
+ pw.print(prefix); pw.print("lastProviderTime=");
+ TimeUtils.formatDuration(lastProviderTime, now, pw);
+ pw.println();
+ }
if (hasStartedServices) {
pw.print(prefix); pw.print("hasStartedServices="); pw.println(hasStartedServices);
}
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 096c85e6f2da..b2140806b4aa 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -572,8 +572,8 @@ final class TaskRecord {
* Removes all associated thumbnail data when a task is removed or pruned from recents.
*/
void disposeThumbnail() {
+ mLastThumbnailInfo.reset();
mLastThumbnail = null;
- mLastThumbnailInfo = null;
lastDescription = null;
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index cbc13fee63dd..d6fced6a2b9a 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -18,7 +18,6 @@ package com.android.server.am;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
-
import static android.app.ActivityManager.USER_OP_IS_CURRENT;
import static android.app.ActivityManager.USER_OP_SUCCESS;
import static android.os.Process.SYSTEM_UID;
@@ -57,8 +56,11 @@ import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.storage.IMountService;
+import android.os.storage.StorageManager;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
@@ -134,7 +136,9 @@ final class UserController {
mService = service;
mHandler = mService.mHandler;
// User 0 is the first and only user that runs at boot.
- mStartedUsers.put(UserHandle.USER_SYSTEM, new UserState(UserHandle.SYSTEM, true));
+ final UserState uss = new UserState(UserHandle.SYSTEM);
+ mStartedUsers.put(UserHandle.USER_SYSTEM, uss);
+ updateUserUnlockedState(uss);
mUserLru.add(UserHandle.USER_SYSTEM);
updateStartedUserArrayLocked();
}
@@ -409,6 +413,21 @@ final class UserController {
return userManager;
}
+ private void updateUserUnlockedState(UserState uss) {
+ final IMountService mountService = IMountService.Stub
+ .asInterface(ServiceManager.getService(Context.STORAGE_SERVICE));
+ if (mountService != null) {
+ try {
+ uss.unlocked = mountService.isUserKeyUnlocked(uss.mHandle.getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ } else {
+ // System isn't fully booted yet, so guess based on property
+ uss.unlocked = !SystemProperties.getBoolean(StorageManager.PROP_HAS_FBE, false);
+ }
+ }
+
boolean startUser(final int userId, final boolean foreground) {
if (mService.checkCallingPermission(INTERACT_ACROSS_USERS_FULL)
!= PackageManager.PERMISSION_GRANTED) {
@@ -453,11 +472,14 @@ final class UserController {
// If the user we are switching to is not currently started, then
// we need to start it now.
if (mStartedUsers.get(userId) == null) {
- mStartedUsers.put(userId, new UserState(new UserHandle(userId), false));
+ mStartedUsers.put(userId, new UserState(new UserHandle(userId)));
updateStartedUserArrayLocked();
needStart = true;
}
+ final UserState uss = mStartedUsers.get(userId);
+ updateUserUnlockedState(uss);
+
final Integer userIdInt = userId;
mUserLru.remove(userIdInt);
mUserLru.add(userIdInt);
@@ -479,8 +501,6 @@ final class UserController {
mUserLru.add(currentUserIdInt);
}
- final UserState uss = mStartedUsers.get(userId);
-
// Make sure user is in the started state. If it is currently
// stopping, we need to knock that off.
if (uss.mState == UserState.STATE_STOPPING) {
@@ -956,8 +976,11 @@ final class UserController {
return true;
}
if ((flags & ActivityManager.FLAG_WITH_AMNESIA) != 0) {
- // TODO: add in amnesia lifecycle
- return false;
+ // If user is currently locked, we fall through to default "running"
+ // behavior below
+ if (state.unlocked) {
+ return false;
+ }
}
return state.mState != UserState.STATE_STOPPING
&& state.mState != UserState.STATE_SHUTDOWN;
diff --git a/services/core/java/com/android/server/am/UserState.java b/services/core/java/com/android/server/am/UserState.java
index b3d82bca2de8..b5b5c1d06f6f 100644
--- a/services/core/java/com/android/server/am/UserState.java
+++ b/services/core/java/com/android/server/am/UserState.java
@@ -40,6 +40,7 @@ public final class UserState {
public int mState = STATE_BOOTING;
public boolean switching;
public boolean initializing;
+ public boolean unlocked;
/**
* The last time that a provider was reported to usage stats as being brought to important
@@ -47,7 +48,7 @@ public final class UserState {
*/
public final ArrayMap<String,Long> mProviderLastReportedFg = new ArrayMap<>();
- public UserState(UserHandle handle, boolean initial) {
+ public UserState(UserHandle handle) {
mHandle = handle;
}
@@ -62,6 +63,11 @@ public final class UserState {
}
if (switching) pw.print(" SWITCHING");
if (initializing) pw.print(" INITIALIZING");
+ if (unlocked) {
+ pw.print(" UNLOCKED");
+ } else {
+ pw.print(" LOCKED");
+ }
pw.println();
}
}
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 150c84932aca..99a051af1717 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -185,15 +185,6 @@ public final class Installer extends SystemService {
return mInstaller.execute(builder.toString());
}
- public int rename(String oldname, String newname) {
- StringBuilder builder = new StringBuilder("rename");
- builder.append(' ');
- builder.append(oldname);
- builder.append(' ');
- builder.append(newname);
- return mInstaller.execute(builder.toString());
- }
-
@Deprecated
public int fixUid(String name, int uid, int gid) {
return fixUid(null, name, uid, gid);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ad1cbe6172f7..64628aafbaa2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2981,23 +2981,25 @@ public class PackageManagerService extends IPackageManager.Stub {
* purposefully done before acquiring {@link #mPackages} lock.
*/
private int augmentFlagsForUser(int flags, int userId) {
- // TODO: bring back once locking fixed
-// final IActivityManager am = ActivityManagerNative.getDefault();
-// if (am == null) {
-// // We must be early in boot, so the best we can do is assume the
-// // user is fully running.
-// return flags;
-// }
-// final long token = Binder.clearCallingIdentity();
-// try {
-// if (am.isUserRunning(userId, ActivityManager.FLAG_WITH_AMNESIA)) {
-// flags |= PackageManager.FLAG_USER_RUNNING_WITH_AMNESIA;
-// }
-// } catch (RemoteException e) {
-// throw e.rethrowAsRuntimeException();
-// } finally {
-// Binder.restoreCallingIdentity(token);
-// }
+ if (SystemProperties.getBoolean(StorageManager.PROP_HAS_FBE, false)) {
+ final IMountService mount = IMountService.Stub
+ .asInterface(ServiceManager.getService(Context.STORAGE_SERVICE));
+ if (mount == null) {
+ // We must be early in boot, so the best we can do is assume the
+ // user is fully running.
+ return flags;
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (!mount.isUserKeyUnlocked(userId)) {
+ flags |= PackageManager.FLAG_USER_RUNNING_WITH_AMNESIA;
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
return flags;
}
@@ -15918,13 +15920,14 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
+ final StorageManager sm = mContext.getSystemService(StorageManager.class);
final UserManager um = mContext.getSystemService(UserManager.class);
for (UserInfo user : um.getUsers()) {
final File userDir = Environment.getDataUserDirectory(volumeUuid, user.id);
if (userDir.exists()) continue;
try {
- UserManagerService.prepareUserDirectory(mContext, volumeUuid, user.id);
+ sm.prepareUserStorage(volumeUuid, user.id, user.serialNumber);
UserManagerService.enforceSerialNumber(userDir, user.serialNumber);
} catch (IOException e) {
Log.wtf(TAG, "Failed to create user directory on " + volumeUuid, e);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 9a87abe09f0e..3a1d2de0d37c 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1563,13 +1563,15 @@ public class UserManagerService extends IUserManager.Stub {
userInfo.restrictedProfileParentId = parent.restrictedProfileParentId;
}
}
+
final StorageManager storage = mContext.getSystemService(StorageManager.class);
+ storage.createUserKey(userId, userInfo.serialNumber);
for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
final String volumeUuid = vol.getFsUuid();
try {
final File userDir = Environment.getDataUserDirectory(volumeUuid,
userId);
- prepareUserDirectory(mContext, volumeUuid, userId);
+ storage.prepareUserStorage(volumeUuid, userId, userInfo.serialNumber);
enforceSerialNumber(userDir, userInfo.serialNumber);
} catch (IOException e) {
Log.wtf(LOG_TAG, "Failed to create user directory on " + volumeUuid, e);
@@ -1797,8 +1799,7 @@ public class UserManagerService extends IUserManager.Stub {
}
private void removeUserStateLILP(final int userHandle) {
- mContext.getSystemService(StorageManager.class)
- .deleteUserKey(userHandle);
+ mContext.getSystemService(StorageManager.class).destroyUserKey(userHandle);
// Cleanup package manager settings
mPm.cleanUpUserLILPw(this, userHandle);
@@ -2183,16 +2184,6 @@ public class UserManagerService extends IUserManager.Stub {
}
/**
- * Create new {@code /data/user/[id]} directory and sets default
- * permissions.
- */
- public static void prepareUserDirectory(Context context, String volumeUuid, int userId) {
- final StorageManager storage = context.getSystemService(StorageManager.class);
- final File userDir = Environment.getDataUserDirectory(volumeUuid, userId);
- storage.createNewUserDir(userId, userDir);
- }
-
- /**
* Enforce that serial number stored in user directory inode matches the
* given expected value. Gracefully sets the serial number if currently
* undefined.
diff --git a/services/core/java/com/android/server/wm/DimLayer.java b/services/core/java/com/android/server/wm/DimLayer.java
index 85a12db955ca..4b3620f07fbc 100644
--- a/services/core/java/com/android/server/wm/DimLayer.java
+++ b/services/core/java/com/android/server/wm/DimLayer.java
@@ -70,7 +70,7 @@ public class DimLayer {
/** Returns the display info. of the dim layer user. */
DisplayInfo getDisplayInfo();
/** Gets the bounds of the dim layer user. */
- void getBounds(Rect outBounds);
+ void getDimBounds(Rect outBounds);
String toShortString();
}
/** The user of this dim layer. */
diff --git a/services/core/java/com/android/server/wm/DimLayerController.java b/services/core/java/com/android/server/wm/DimLayerController.java
index 921d27cebe60..bd30bd585bdb 100644
--- a/services/core/java/com/android/server/wm/DimLayerController.java
+++ b/services/core/java/com/android/server/wm/DimLayerController.java
@@ -43,7 +43,7 @@ class DimLayerController {
/** Updates the dim layer bounds, recreating it if needed. */
void updateDimLayer(DimLayer.DimLayerUser dimLayerUser) {
- DimLayerState state = getOrCreateDimLayerState(dimLayerUser, false);
+ DimLayerState state = getOrCreateDimLayerState(dimLayerUser);
final boolean previousFullscreen = state.dimLayer != null
&& state.dimLayer == mSharedFullScreenDimLayer;
DimLayer newDimLayer;
@@ -63,7 +63,7 @@ class DimLayerController {
// Create new full screen dim layer.
newDimLayer = new DimLayer(mDisplayContent.mService, dimLayerUser, displayId);
}
- dimLayerUser.getBounds(mTmpBounds);
+ dimLayerUser.getDimBounds(mTmpBounds);
newDimLayer.setBounds(mTmpBounds);
mSharedFullScreenDimLayer = newDimLayer;
} else if (state.dimLayer != null) {
@@ -73,14 +73,13 @@ class DimLayerController {
newDimLayer = (state.dimLayer == null || previousFullscreen)
? new DimLayer(mDisplayContent.mService, dimLayerUser, displayId)
: state.dimLayer;
- dimLayerUser.getBounds(mTmpBounds);
+ dimLayerUser.getDimBounds(mTmpBounds);
newDimLayer.setBounds(mTmpBounds);
}
state.dimLayer = newDimLayer;
}
- private DimLayerState getOrCreateDimLayerState(
- DimLayer.DimLayerUser dimLayerUser, boolean aboveApp) {
+ private DimLayerState getOrCreateDimLayerState(DimLayer.DimLayerUser dimLayerUser) {
if (DEBUG_DIM_LAYER) Slog.v(TAG, "getOrCreateDimLayerState, dimLayerUser="
+ dimLayerUser.toShortString());
DimLayerState state = mState.get(dimLayerUser);
@@ -88,7 +87,6 @@ class DimLayerController {
state = new DimLayerState();
mState.put(dimLayerUser, state);
}
- state.dimAbove = aboveApp;
return state;
}
@@ -127,7 +125,8 @@ class DimLayerController {
WindowStateAnimator newWinAnimator, boolean aboveApp) {
// Only set dim params on the highest dimmed layer.
// Don't turn on for an unshown surface, or for any layer but the highest dimmed layer.
- DimLayerState state = getOrCreateDimLayerState(dimLayerUser, aboveApp);
+ DimLayerState state = getOrCreateDimLayerState(dimLayerUser);
+ state.dimAbove = aboveApp;
if (DEBUG_DIM_LAYER) Slog.v(TAG, "startDimmingIfNeeded,"
+ " dimLayerUser=" + dimLayerUser.toShortString()
+ " newWinAnimator=" + newWinAnimator
@@ -161,7 +160,7 @@ class DimLayerController {
+ " state.dimLayer.isDimming=" + state.dimLayer.isDimming());
if (!state.continueDimming && state.dimLayer.isDimming()) {
state.animator = null;
- dimLayerUser.getBounds(mTmpBounds);
+ dimLayerUser.getDimBounds(mTmpBounds);
state.dimLayer.setBounds(mTmpBounds);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 8c00a570d837..e264c437241c 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -291,16 +291,18 @@ class DisplayContent {
final ArrayList<Task> tasks = mStacks.get(stackNdx).getTasks();
for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
final Task task = tasks.get(taskNdx);
- // We need to use the visible frame on the window for any touch-related tests.
- // Can't use the task's bounds because the original task bounds might be adjusted
- // to fit the content frame. For example, the presence of the IME adjusting the
+ final WindowState win = task.getTopVisibleAppMainWindow();
+ if (win == null) {
+ continue;
+ }
+ // We need to use the task's dim bounds (which is derived from the visible
+ // bounds of its apps windows) for any touch-related tests. Can't use
+ // the task's original bounds because it might be adjusted to fit the
+ // content frame. For example, the presence of the IME adjusting the
// windows frames when the app window is the IME target.
- final WindowState win = task.getTopAppMainWindow();
- if (win != null) {
- win.getVisibleBounds(mTmpRect, !BOUNDS_FOR_TOUCH);
- if (mTmpRect.contains(x, y)) {
- return task.mTaskId;
- }
+ task.getDimBounds(mTmpRect);
+ if (mTmpRect.contains(x, y)) {
+ return task.mTaskId;
}
}
}
@@ -308,10 +310,10 @@ class DisplayContent {
}
/**
- * Find the window whose outside touch area (for resizing) (x, y) falls within.
+ * Find the task whose outside touch area (for resizing) (x, y) falls within.
* Returns null if the touch doesn't fall into a resizing area.
*/
- WindowState findWindowForControlPoint(int x, int y) {
+ Task findTaskForControlPoint(int x, int y) {
final int delta = mService.dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
TaskStack stack = mStacks.get(stackNdx);
@@ -325,24 +327,22 @@ class DisplayContent {
return null;
}
- // We need to use the visible frame on the window for any touch-related
- // tests. Can't use the task's bounds because the original task bounds
- // might be adjusted to fit the content frame. (One example is when the
- // task is put to top-left quadrant, the actual visible frame would not
- // start at (0,0) after it's adjusted for the status bar.)
- final WindowState win = task.getTopAppMainWindow();
- if (win != null) {
- win.getVisibleBounds(mTmpRect, !BOUNDS_FOR_TOUCH);
- mTmpRect.inset(-delta, -delta);
- if (mTmpRect.contains(x, y)) {
- mTmpRect.inset(delta, delta);
- if (!mTmpRect.contains(x, y)) {
- return win;
- }
- // User touched inside the task. No need to look further,
- // focus transfer will be handled in ACTION_UP.
- return null;
+ // We need to use the task's dim bounds (which is derived from the visible
+ // bounds of its apps windows) for any touch-related tests. Can't use
+ // the task's original bounds because it might be adjusted to fit the
+ // content frame. One example is when the task is put to top-left quadrant,
+ // the actual visible area would not start at (0,0) after it's adjusted
+ // for the status bar.
+ task.getDimBounds(mTmpRect);
+ mTmpRect.inset(-delta, -delta);
+ if (mTmpRect.contains(x, y)) {
+ mTmpRect.inset(delta, delta);
+ if (!mTmpRect.contains(x, y)) {
+ return task;
}
+ // User touched inside the task. No need to look further,
+ // focus transfer will be handled in ACTION_UP.
+ return null;
}
}
}
@@ -351,12 +351,18 @@ class DisplayContent {
void setTouchExcludeRegion(Task focusedTask) {
mTouchExcludeRegion.set(mBaseDisplayRect);
- WindowList windows = getWindowList();
final int delta = mService.dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
- for (int i = windows.size() - 1; i >= 0; --i) {
- final WindowState win = windows.get(i);
- final Task task = win.getTask();
- if (win.isVisibleLw() && task != null) {
+ boolean addBackFocusedTask = false;
+ for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ TaskStack stack = mStacks.get(stackNdx);
+ final ArrayList<Task> tasks = stack.getTasks();
+ for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+ final Task task = tasks.get(taskNdx);
+ final WindowState win = task.getTopVisibleAppMainWindow();
+ if (win == null) {
+ continue;
+ }
+
/**
* Exclusion region is the region that TapDetector doesn't care about.
* Here we want to remove all non-focused tasks from the exclusion region.
@@ -368,13 +374,17 @@ class DisplayContent {
*/
final boolean isFreeformed = task.inFreeformWorkspace();
if (task != focusedTask || isFreeformed) {
- mTmpRect.set(win.mVisibleFrame);
- mTmpRect.intersect(win.mVisibleInsets);
- /**
- * If the task is freeformed, enlarge the area to account for outside
- * touch area for resize.
- */
+ task.getDimBounds(mTmpRect);
if (isFreeformed) {
+ // If we're removing a freeform, focused app from the exclusion region,
+ // we need to add back its touchable frame later. Remember the touchable
+ // frame now.
+ if (task == focusedTask) {
+ addBackFocusedTask = true;
+ mTmpRect2.set(mTmpRect);
+ }
+ // If the task is freeformed, enlarge the area to account for outside
+ // touch area for resize.
mTmpRect.inset(-delta, -delta);
// Intersect with display content rect. If we have system decor (status bar/
// navigation bar), we want to exclude that from the tap detection.
@@ -385,17 +395,14 @@ class DisplayContent {
}
mTouchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE);
}
- /**
- * If we removed the focused task above, add it back and only leave its
- * outside touch area in the exclusion. TapDectector is not interested in
- * any touch inside the focused task itself.
- */
- if (task == focusedTask && isFreeformed) {
- mTmpRect.inset(delta, delta);
- mTouchExcludeRegion.op(mTmpRect, Region.Op.UNION);
- }
}
}
+ // If we removed the focused task above, add it back and only leave its
+ // outside touch area in the exclusion. TapDectector is not interested in
+ // any touch inside the focused task itself.
+ if (addBackFocusedTask) {
+ mTouchExcludeRegion.op(mTmpRect2, Region.Op.UNION);
+ }
if (mTapDetector != null) {
mTapDetector.setTouchExcludeRegion(mTouchExcludeRegion);
}
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index c1e04811c38a..6b6246760b39 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -87,7 +87,7 @@ public class DockedStackDividerController {
frame.set(mLastRect);
return;
} else {
- stack.getBounds(mTmpRect);
+ stack.getDimBounds(mTmpRect);
}
int side = stack.getDockSide();
switch (side) {
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 400cc5e3d9b5..2be7ab8516b6 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -435,7 +435,7 @@ class DragState {
continue;
}
- child.getVisibleBounds(mTmpRect, !BOUNDS_FOR_TOUCH);
+ child.getVisibleBounds(mTmpRect);
if (!mTmpRect.contains(x, y)) {
// outside of this window's activity stack == don't tell about drags
continue;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 7c9268439158..46cd7cd5b0aa 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -253,8 +253,7 @@ class Task implements DimLayer.DimLayerUser {
return false;
}
- /** Bounds of the task with other system factors taken into consideration. */
- @Override
+ /** Original bounds of the task if applicable, otherwise fullscreen rect. */
public void getBounds(Rect out) {
if (useCurrentBounds()) {
// No need to adjust the output bounds if fullscreen or the docked stack is visible
@@ -269,6 +268,70 @@ class Task implements DimLayer.DimLayerUser {
mStack.getDisplayContent().getLogicalDisplayRect(out);
}
+
+ /**
+ * Calculate the maximum visible area of this task. If the task has only one app,
+ * the result will be visible frame of that app. If the task has more than one apps,
+ * we search from top down if the next app got different visible area.
+ *
+ * This effort is to handle the case where some task (eg. GMail composer) might pop up
+ * a dialog that's different in size from the activity below, in which case we should
+ * be dimming the entire task area behind the dialog.
+ *
+ * @param out Rect containing the max visible bounds.
+ * @return true if the task has some visible app windows; false otherwise.
+ */
+ boolean getMaxVisibleBounds(Rect out) {
+ boolean foundTop = false;
+ for (int i = mAppTokens.size() - 1; i >= 0; i--) {
+ final AppWindowToken token = mAppTokens.get(i);
+ // skip hidden (or about to hide) apps
+ if (token.mIsExiting || token.clientHidden || token.hiddenRequested) {
+ continue;
+ }
+ final WindowState win = token.findMainWindow();
+ if (win == null) {
+ continue;
+ }
+ if (!foundTop) {
+ out.set(win.mVisibleFrame);
+ foundTop = true;
+ continue;
+ }
+ if (win.mVisibleFrame.left < out.left) {
+ out.left = win.mVisibleFrame.left;
+ }
+ if (win.mVisibleFrame.top < out.top) {
+ out.top = win.mVisibleFrame.top;
+ }
+ if (win.mVisibleFrame.right > out.right) {
+ out.right = win.mVisibleFrame.right;
+ }
+ if (win.mVisibleFrame.bottom > out.bottom) {
+ out.bottom = win.mVisibleFrame.bottom;
+ }
+ }
+ return foundTop;
+ }
+
+ /** Bounds of the task to be used for dimming, as well as touch related tests. */
+ @Override
+ public void getDimBounds(Rect out) {
+ if (useCurrentBounds()) {
+ if (inFreeformWorkspace() && getMaxVisibleBounds(out)) {
+ return;
+ }
+
+ out.set(mBounds);
+ return;
+ }
+
+ // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
+ // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
+ // system.
+ mStack.getDisplayContent().getLogicalDisplayRect(out);
+ }
+
void setDragResizing(boolean dragResizing) {
mDragResizing = dragResizing;
}
@@ -355,14 +418,20 @@ class Task implements DimLayer.DimLayerUser {
return mStack != null && mStack.mStackId == DOCKED_STACK_ID;
}
- WindowState getTopAppMainWindow() {
- final int tokensCount = mAppTokens.size();
- return tokensCount > 0 ? mAppTokens.get(tokensCount - 1).findMainWindow() : null;
+ WindowState getTopVisibleAppMainWindow() {
+ final AppWindowToken token = getTopVisibleAppToken();
+ return token != null ? token.findMainWindow() : null;
}
- AppWindowToken getTopAppWindowToken() {
- final int tokensCount = mAppTokens.size();
- return tokensCount > 0 ? mAppTokens.get(tokensCount - 1) : null;
+ AppWindowToken getTopVisibleAppToken() {
+ for (int i = mAppTokens.size() - 1; i >= 0; i--) {
+ final AppWindowToken token = mAppTokens.get(i);
+ // skip hidden (or about to hide) apps
+ if (!token.mIsExiting && !token.clientHidden && !token.hiddenRequested) {
+ return token;
+ }
+ }
+ return null;
}
@Override
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index aae3bd24439f..f5e4e3be3477 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -149,7 +149,7 @@ class TaskPositioner implements DimLayer.DimLayerUser {
}
synchronized (mService.mWindowMap) {
mDragEnded = notifyMoveLocked(newX, newY);
- mTask.getBounds(mTmpRect);
+ mTask.getDimBounds(mTmpRect);
}
if (!mTmpRect.equals(mWindowDragBounds)) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
@@ -332,28 +332,34 @@ class TaskPositioner implements DimLayer.DimLayerUser {
+ ", {" + startX + ", " + startY + "}");
}
mCtrlType = CTRL_NONE;
+ mTask = win.getTask();
+ mStartDragX = startX;
+ mStartDragY = startY;
+
+ // Use the dim bounds, not the original task bounds. The cursor
+ // movement should be calculated relative to the visible bounds.
+ // Also, use the dim bounds of the task which accounts for
+ // multiple app windows. Don't use any bounds from win itself as it
+ // may not be the same size as the task.
+ mTask.getDimBounds(mTmpRect);
+
if (resize) {
- final Rect visibleFrame = win.mVisibleFrame;
- if (startX < visibleFrame.left) {
+ if (startX < mTmpRect.left) {
mCtrlType |= CTRL_LEFT;
}
- if (startX > visibleFrame.right) {
+ if (startX > mTmpRect.right) {
mCtrlType |= CTRL_RIGHT;
}
- if (startY < visibleFrame.top) {
+ if (startY < mTmpRect.top) {
mCtrlType |= CTRL_TOP;
}
- if (startY > visibleFrame.bottom) {
+ if (startY > mTmpRect.bottom) {
mCtrlType |= CTRL_BOTTOM;
}
mResizing = true;
}
- mTask = win.getTask();
- mStartDragX = startX;
- mStartDragY = startY;
-
- mService.getTaskBounds(mTask.mTaskId, mWindowOriginalBounds);
+ mWindowOriginalBounds.set(mTmpRect);
}
private void endDragLocked() {
@@ -393,7 +399,7 @@ class TaskPositioner implements DimLayer.DimLayerUser {
}
// This is a moving operation.
- mTask.mStack.getBounds(mTmpRect);
+ mTask.mStack.getDimBounds(mTmpRect);
mTmpRect.inset(mMinVisibleWidth, mMinVisibleHeight);
if (!mTmpRect.contains((int) x, (int) y)) {
// We end the moving operation if position is outside the stack bounds.
@@ -438,7 +444,7 @@ class TaskPositioner implements DimLayer.DimLayerUser {
return CTRL_NONE;
}
- mTask.mStack.getBounds(mTmpRect);
+ mTask.mStack.getDimBounds(mTmpRect);
if (x - mSideMargin <= mTmpRect.left) {
return CTRL_LEFT;
}
@@ -450,7 +456,7 @@ class TaskPositioner implements DimLayer.DimLayerUser {
}
private void showDimLayer() {
- mTask.mStack.getBounds(mTmpRect);
+ mTask.mStack.getDimBounds(mTmpRect);
if (mCurrentDimSide == CTRL_LEFT) {
mTmpRect.right = mTmpRect.centerX();
} else if (mCurrentDimSide == CTRL_RIGHT) {
@@ -473,7 +479,7 @@ class TaskPositioner implements DimLayer.DimLayerUser {
}
@Override
- public void getBounds(Rect out) {
+ public void getDimBounds(Rect out) {
// This dim layer user doesn't need this.
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 7c02b43604be..8085f13ca7f9 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -189,8 +189,6 @@ public class TaskStack implements DimLayer.DimLayerUser {
return false;
}
- /** Bounds of the stack with other system factors taken into consideration. */
- @Override
public void getBounds(Rect out) {
if (useCurrentBounds()) {
// No need to adjust the output bounds if fullscreen or the docked stack is visible
@@ -205,6 +203,12 @@ public class TaskStack implements DimLayer.DimLayerUser {
mDisplayContent.getLogicalDisplayRect(out);
}
+ /** Bounds of the stack with other system factors taken into consideration. */
+ @Override
+ public void getDimBounds(Rect out) {
+ getBounds(out);
+ }
+
void updateDisplayInfo(Rect bounds) {
if (mDisplayContent != null) {
for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
diff --git a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
index a33fb13f0325..f5b83bbb4f8b 100644
--- a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
@@ -90,11 +90,11 @@ public class TaskTapPointerEventListener implements PointerEventListener {
case MotionEvent.ACTION_HOVER_MOVE: {
final int x = (int) motionEvent.getX();
final int y = (int) motionEvent.getY();
- final WindowState window = mDisplayContent.findWindowForControlPoint(x, y);
- if (window == null) {
+ final Task task = mDisplayContent.findTaskForControlPoint(x, y);
+ if (task == null) {
break;
}
- window.getVisibleBounds(mTmpRect, false);
+ task.getDimBounds(mTmpRect);
if (!mTmpRect.isEmpty() && !mTmpRect.contains(x, y)) {
int iconShape = STYLE_DEFAULT;
if (x < mTmpRect.left) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index d9af27dd95c0..a22f8213e15d 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -5850,7 +5850,7 @@ public class WindowManagerService extends IWindowManager.Stub
int right = wf.right - cr.right;
int bottom = wf.bottom - cr.bottom;
frame.union(left, top, right, bottom);
- ws.getVisibleBounds(stackBounds, !BOUNDS_FOR_TOUCH);
+ ws.getVisibleBounds(stackBounds);
if (!frame.intersect(stackBounds)) {
// Set frame empty if there's no intersection.
frame.setEmpty();
@@ -7069,15 +7069,16 @@ public class WindowManagerService extends IWindowManager.Stub
}
private void startResizingTask(DisplayContent displayContent, int startX, int startY) {
- WindowState win = null;
+ Task task = null;
synchronized (mWindowMap) {
- win = displayContent.findWindowForControlPoint(startX, startY);
- if (win == null || !startPositioningLocked(win, true /*resize*/, startX, startY)) {
+ task = displayContent.findTaskForControlPoint(startX, startY);
+ if (task == null || !startPositioningLocked(
+ task.getTopVisibleAppMainWindow(), true /*resize*/, startX, startY)) {
return;
}
}
try {
- mActivityManager.setFocusedTask(win.getTask().mTaskId);
+ mActivityManager.setFocusedTask(task.mTaskId);
} catch(RemoteException e) {}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 080a2d1e2b58..673c21ff9931 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -729,8 +729,18 @@ final class WindowState implements WindowManagerPolicy.WindowState {
mVisibleFrame.set(mContentFrame);
mStableFrame.set(mContentFrame);
} else if (mAttrs.type == TYPE_DOCK_DIVIDER) {
- mDisplayContent.getDockedDividerController().positionDockedStackedDivider(mFrame);
- mContentFrame.set(mFrame);
+ if (isVisibleLw()) {
+ // We don't adjust the dock divider frame for reasons other than performance. The
+ // real reason is that if it gets adjusted before it is shown for the first time,
+ // it would get size (0, 0). This causes a problem when we finally show the dock
+ // divider and try to draw to it. We do set the surface size at that moment to
+ // the correct size, but it's too late for the Surface Flinger to make it
+ // available for view rendering and as a result the renderer receives size 1, 1.
+ // This way we just keep the divider at the original size and Surface Flinger
+ // will return the correct value to the renderer.
+ mDisplayContent.getDockedDividerController().positionDockedStackedDivider(mFrame);
+ mContentFrame.set(mFrame);
+ }
} else {
mContentFrame.set(Math.max(mContentFrame.left, mFrame.left),
Math.max(mContentFrame.top, mFrame.top),
@@ -962,17 +972,15 @@ final class WindowState implements WindowManagerPolicy.WindowState {
/**
* Retrieves the visible bounds of the window.
* @param bounds The rect which gets the bounds.
- * @param forTouch Pass in BOUNDS_FOR_TOUCH to get touch related bounds, otherwise visible
- * bounds will be returned.
*/
- void getVisibleBounds(Rect bounds, boolean forTouch) {
+ void getVisibleBounds(Rect bounds) {
boolean intersectWithStackBounds = mAppToken != null && mAppToken.mCropWindowsToStack;
bounds.setEmpty();
mTmpRect.setEmpty();
if (intersectWithStackBounds) {
final TaskStack stack = getStack();
if (stack != null) {
- stack.getBounds(mTmpRect);
+ stack.getDimBounds(mTmpRect);
} else {
intersectWithStackBounds = false;
}
@@ -990,12 +998,6 @@ final class WindowState implements WindowManagerPolicy.WindowState {
}
return;
}
- if (forTouch && inFreeformWorkspace()) {
- final DisplayMetrics displayMetrics = getDisplayContent().getDisplayMetrics();
- final int delta = WindowManagerService.dipToPixel(
- RESIZE_HANDLE_WIDTH_IN_DP, displayMetrics);
- bounds.inset(-delta, -delta);
- }
}
public long getInputDispatchingTimeoutNanos() {
@@ -1415,22 +1417,24 @@ final class WindowState implements WindowManagerPolicy.WindowState {
if (modal && mAppToken != null) {
// Limit the outer touch to the activity stack region.
flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
- if (!inFreeformWorkspace()) {
- // If this is a modal window we need to dismiss it if it's not full screen and the
- // touch happens outside of the frame that displays the content. This means we
- // need to intercept touches outside of that window. The dim layer user
- // associated with the window (task or stack) will give us the good bounds, as
- // they would be used to display the dim layer.
- final DimLayer.DimLayerUser dimLayerUser = getDimLayerUser();
- if (dimLayerUser != null) {
- dimLayerUser.getBounds(mTmpRect);
- } else {
- getVisibleBounds(mTmpRect, BOUNDS_FOR_TOUCH);
- }
+ // If this is a modal window we need to dismiss it if it's not full screen and the
+ // touch happens outside of the frame that displays the content. This means we
+ // need to intercept touches outside of that window. The dim layer user
+ // associated with the window (task or stack) will give us the good bounds, as
+ // they would be used to display the dim layer.
+ final DimLayer.DimLayerUser dimLayerUser = getDimLayerUser();
+ if (dimLayerUser != null) {
+ dimLayerUser.getDimBounds(mTmpRect);
} else {
+ getVisibleBounds(mTmpRect);
+ }
+ if (inFreeformWorkspace()) {
// For freeform windows we the touch region to include the whole surface for the
// shadows.
- getVisibleBounds(mTmpRect, BOUNDS_FOR_TOUCH);
+ final DisplayMetrics displayMetrics = getDisplayContent().getDisplayMetrics();
+ final int delta = WindowManagerService.dipToPixel(
+ RESIZE_HANDLE_WIDTH_IN_DP, displayMetrics);
+ mTmpRect.inset(-delta, -delta);
}
region.set(mTmpRect);
} else {
@@ -1704,7 +1708,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
Task task = getTask();
if (task == null || task.inHomeStack()
- || task.getTopAppWindowToken() != mAppToken) {
+ || task.getTopVisibleAppToken() != mAppToken) {
// Don't save surfaces for home stack apps. These usually resume and draw
// first frame very fast. Saving surfaces are mostly a waste of memory.
// Don't save if the window is not the topmost window.
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index ae62f5056644..decfb342acad 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1148,7 +1148,7 @@ class WindowStateAnimator {
// gets removed. The window that will replace it will abide them.
if (task != null && appToken.mCropWindowsToStack && !appToken.mWillReplaceWindow) {
TaskStack stack = task.mStack;
- stack.getBounds(mTmpStackBounds);
+ stack.getDimBounds(mTmpStackBounds);
// When we resize we use the big surface approach, which means we can't trust the
// window frame bounds anymore. Instead, the window will be placed at 0, 0, but to avoid
// hardcoding it, we use surface coordinates.
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 4b9a538c97cc..3b5763473b8e 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -932,6 +932,13 @@ class WindowSurfacePlacer {
win.prelayout();
mService.mPolicy.layoutWindowLw(win, null);
win.mLayoutSeq = seq;
+
+ // Window frames may have changed. Update dim layer with the new bounds.
+ final Task task = win.getTask();
+ if (task != null) {
+ displayContent.mDimLayerController.updateDimLayer(task);
+ }
+
if (DEBUG_LAYOUT) Slog.v(TAG,
" LAYOUT: mFrame="
+ win.mFrame + " mContainingFrame="
@@ -986,7 +993,7 @@ class WindowSurfacePlacer {
}
}
- // Window frames may have changed. Tell the input dispatcher about it.
+ // Window frames may have changed. Tell the input dispatcher about it.
mService.mInputMonitor.setUpdateInputWindowsNeededLw();
if (updateInputWindows) {
mService.mInputMonitor.updateInputWindowsLw(false /*force*/);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index eee7d9289e4d..6c2bd00fa40d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -156,11 +156,6 @@ import java.util.Set;
/**
* Implementation of the device policy APIs.
- *
- * Locking policies:
- * - {@link DevicePolicyManagerService} must not call into {@link IActivityManager} within {@code
- * this} lock to avoid lock inversion.
- * - Methods that call into {@link IActivityManager} must have the "AM" suffix.
*/
public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@@ -1110,7 +1105,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
.asInterface(ServiceManager.getService(Context.WINDOW_SERVICE));
}
- IActivityManager getIActivityManagerInner() {
+ IActivityManager getIActivityManager() {
return ActivityManagerNative.getDefault();
}
@@ -1241,16 +1236,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
/**
- * Caller must not hold {@code this} lock. See also the class javadoc.
- */
- final IActivityManager getIActivityManager() {
- if (Thread.holdsLock(this)) {
- Slog.wtfStack(LOG_TAG, "Call to ActivityManager detected within DPMS lock");
- }
- return mInjector.getIActivityManagerInner();
- }
-
- /**
* Instantiates the service.
*/
public DevicePolicyManagerService(Context context) {
@@ -1364,6 +1349,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// TODO PO may not have a class name either due to b/17652534. Address that too.
+ updateDeviceOwnerLocked();
+
// TODO Notify UM to update restrictions (?)
}
}
@@ -2050,23 +2037,36 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
validatePasswordOwnerLocked(policy);
updateMaximumTimeToLockLocked(policy);
- updateLockTaskPackages(policy.mLockTaskPackages, userHandle);
+ updateLockTaskPackagesLocked(policy.mLockTaskPackages, userHandle);
if (policy.mStatusBarDisabled) {
setStatusBarDisabledInternal(policy.mStatusBarDisabled, userHandle);
}
}
- private void updateLockTaskPackages(List<String> packages, final int userId) {
- final String[] copy = packages.toArray(new String[packages.size()]);
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- try {
- getIActivityManager().updateLockTaskPackages(userId, copy);
- } catch (RemoteException willNotHappen) {
- }
+ private void updateLockTaskPackagesLocked(List<String> packages, int userId) {
+ long ident = mInjector.binderClearCallingIdentity();
+ try {
+ mInjector.getIActivityManager()
+ .updateLockTaskPackages(userId, packages.toArray(new String[packages.size()]));
+ } catch (RemoteException e) {
+ // Not gonna happen.
+ } finally {
+ mInjector.binderRestoreCallingIdentity(ident);
+ }
+ }
+
+ private void updateDeviceOwnerLocked() {
+ long ident = mInjector.binderClearCallingIdentity();
+ try {
+ if (getDeviceOwner() != null) {
+ mInjector.getIActivityManager()
+ .updateDeviceOwner(getDeviceOwner().getPackageName());
}
- });
+ } catch (RemoteException e) {
+ // Not gonna happen.
+ } finally {
+ mInjector.binderRestoreCallingIdentity(ident);
+ }
}
static void validateQualityConstant(int quality) {
@@ -2137,21 +2137,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
private void ensureDeviceOwnerUserStarted() {
- if (!mOwners.hasDeviceOwner()) {
- return;
- }
- final int userId = mOwners.getDeviceOwnerUserId();
- if (userId == UserHandle.USER_SYSTEM) {
- return;
- }
- if (VERBOSE_LOG) {
- Log.v(LOG_TAG, "Starting non-system DO user: " + userId);
- }
- mHandler.post(new Runnable() {
- @Override
- public void run() {
+ if (mOwners.hasDeviceOwner()) {
+ final int userId = mOwners.getDeviceOwnerUserId();
+ if (VERBOSE_LOG) {
+ Log.v(LOG_TAG, "Starting non-system DO user: " + userId);
+ }
+ if (userId != UserHandle.USER_SYSTEM) {
try {
- getIActivityManager().startUserInBackground(userId);
+ mInjector.getIActivityManager().startUserInBackground(userId);
// STOPSHIP Prevent the DO user from being killed.
@@ -2159,7 +2152,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Slog.w(LOG_TAG, "Exception starting user", e);
}
}
- });
+ }
}
private void cleanUpOldUsers() {
@@ -2425,19 +2418,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
- return packageHasActiveAdminsLocked(packageName, userHandle);
- }
- }
-
- boolean packageHasActiveAdminsLocked(String packageName, int userHandle) {
- DevicePolicyData policy = getUserData(userHandle);
- final int N = policy.mAdminList.size();
- for (int i = 0; i < N; i++) {
- if (policy.mAdminList.get(i).info.getPackageName().equals(packageName)) {
- return true;
+ DevicePolicyData policy = getUserData(userHandle);
+ final int N = policy.mAdminList.size();
+ for (int i=0; i<N; i++) {
+ if (policy.mAdminList.get(i).info.getPackageName().equals(packageName)) {
+ return true;
+ }
}
+ return false;
}
- return false;
}
@Override
@@ -3740,7 +3729,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@Override
public void run() {
try {
- IActivityManager am = getIActivityManager();
+ IActivityManager am = mInjector.getIActivityManager();
if (am.getCurrentUser().id == userHandle) {
am.switchUser(UserHandle.USER_SYSTEM);
}
@@ -4496,6 +4485,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mOwners.setDeviceOwner(admin, ownerName, userId);
mOwners.writeDeviceOwner();
+ updateDeviceOwnerLocked();
Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED);
ident = mInjector.binderClearCallingIdentity();
@@ -4597,6 +4587,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mOwners.clearDeviceOwner();
mOwners.writeDeviceOwner();
+ updateDeviceOwnerLocked();
// Reactivate backup service.
long ident = mInjector.binderClearCallingIdentity();
try {
@@ -4645,6 +4636,30 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
+ @Override
+ public boolean setDeviceOwnerLockScreenInfo(ComponentName who, String info) {
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ if (!mHasFeature) {
+ return false;
+ }
+
+ synchronized (this) {
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ long token = mInjector.binderClearCallingIdentity();
+ try {
+ new LockPatternUtils(mContext).setDeviceOwnerInfo(info);
+ } finally {
+ mInjector.binderRestoreCallingIdentity(token);
+ }
+ return true;
+ }
+ }
+
+ @Override
+ public String getDeviceOwnerLockScreenInfo() {
+ return new LockPatternUtils(mContext).getDeviceOwnerInfo();
+ }
+
private void clearUserPoliciesLocked(UserHandle userHandle) {
int userId = userHandle.getIdentifier();
// Reset some of the user-specific policies
@@ -5357,14 +5372,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- private boolean checkCallerIsCurrentUserOrProfileAM() {
+ private boolean checkCallerIsCurrentUserOrProfile() {
int callingUserId = UserHandle.getCallingUserId();
long token = mInjector.binderClearCallingIdentity();
try {
UserInfo currentUser;
UserInfo callingUser = mUserManager.getUserInfo(callingUserId);
try {
- currentUser = getIActivityManager().getCurrentUser();
+ currentUser = mInjector.getIActivityManager().getCurrentUser();
} catch (RemoteException e) {
Slog.e(LOG_TAG, "Failed to talk to activity managed.", e);
return false;
@@ -5395,7 +5410,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// TODO When InputMethodManager supports per user calls remove
// this restriction.
- if (!checkCallerIsCurrentUserOrProfileAM()) {
+ if (!checkCallerIsCurrentUserOrProfile()) {
return false;
}
@@ -5447,7 +5462,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
public List getPermittedInputMethodsForCurrentUser() {
UserInfo currentUser;
try {
- currentUser = getIActivityManager().getCurrentUser();
+ currentUser = mInjector.getIActivityManager().getCurrentUser();
} catch (RemoteException e) {
Slog.e(LOG_TAG, "Failed to make remote calls to get current user", e);
// Activity managed is dead, just allow all IMEs
@@ -5542,7 +5557,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
// Start user in background.
- getIActivityManager().startUserInBackground(userHandle);
+ mInjector.getIActivityManager().startUserInBackground(userHandle);
} catch (RemoteException e) {
Slog.e(LOG_TAG, "Failed to make remote calls for configureUser", e);
}
@@ -5575,20 +5590,20 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Preconditions.checkNotNull(who, "ComponentName is null");
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
- }
- long id = mInjector.binderClearCallingIdentity();
- try {
- int userId = UserHandle.USER_SYSTEM;
- if (userHandle != null) {
- userId = userHandle.getIdentifier();
+ long id = mInjector.binderClearCallingIdentity();
+ try {
+ int userId = UserHandle.USER_SYSTEM;
+ if (userHandle != null) {
+ userId = userHandle.getIdentifier();
+ }
+ return mInjector.getIActivityManager().switchUser(userId);
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, "Couldn't switch user", e);
+ return false;
+ } finally {
+ mInjector.binderRestoreCallingIdentity(id);
}
- return getIActivityManager().switchUser(userId);
- } catch (RemoteException e) {
- Log.e(LOG_TAG, "Couldn't switch user", e);
- return false;
- } finally {
- mInjector.binderRestoreCallingIdentity(id);
}
}
@@ -6060,7 +6075,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// Store the settings persistently.
saveSettingsLocked(userHandle);
- updateLockTaskPackages(packages, userHandle);
+ updateLockTaskPackagesLocked(packages, userHandle);
}
/**
@@ -6428,16 +6443,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- @Override
- public boolean isDeviceAdminPackage(int userId, String packageName) {
- if (packageName == null) {
- return false;
- }
- synchronized (DevicePolicyManagerService.this) {
- return packageHasActiveAdminsLocked(packageName, userId);
- }
- }
-
private void notifyCrossProfileProvidersChanged(int userId, List<String> packages) {
final List<OnCrossProfileWidgetProvidersChangeListener> listeners;
synchronized (DevicePolicyManagerService.this) {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 6419338108a8..2c01b8aaac12 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -128,7 +128,7 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
}
@Override
- IActivityManager getIActivityManagerInner() {
+ IActivityManager getIActivityManager() {
return context.iactivityManager;
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index ca3d95056ddc..36980e3c7d49 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -476,6 +476,10 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// Fire!
assertTrue(dpm.setDeviceOwner(admin1, "owner-name"));
+ // Verify internal calls.
+ verify(mContext.iactivityManager, times(1)).updateDeviceOwner(
+ eq(admin1.getPackageName()));
+
// TODO We should check if the caller has called clearCallerIdentity().
verify(mContext.ibackupManager, times(1)).setBackupServiceActive(
eq(UserHandle.USER_SYSTEM), eq(false));
@@ -542,6 +546,10 @@ public class DevicePolicyManagerTest extends DpmTestBase {
dpm.setActiveAdmin(admin1, /* replace =*/ false);
assertTrue(dpm.setDeviceOwner(admin1, "owner-name"));
+ // Verify internal calls.
+ verify(mContext.iactivityManager, times(1)).updateDeviceOwner(
+ eq(admin1.getPackageName()));
+
assertEquals(admin1.getPackageName(), dpm.getDeviceOwner());
// Set up other mocks.
@@ -576,6 +584,10 @@ public class DevicePolicyManagerTest extends DpmTestBase {
dpm.setActiveAdmin(admin1, /* replace =*/ false);
assertTrue(dpm.setDeviceOwner(admin1, "owner-name"));
+ // Verify internal calls.
+ verify(mContext.iactivityManager, times(1)).updateDeviceOwner(
+ eq(admin1.getPackageName()));
+
assertEquals(admin1.getPackageName(), dpm.getDeviceOwner());
// Now call clear from the secondary user, which should throw.
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index f078a35006ec..2b0919b7bfc0 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -215,11 +215,11 @@ public class UsageStatsService extends SystemService implements
mPowerManager = getContext().getSystemService(PowerManager.class);
mScreenOnSystemTimeSnapshot = System.currentTimeMillis();
- synchronized (this) {
+ synchronized (mLock) {
mScreenOnTime = readScreenOnTimeLocked();
}
mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
- synchronized (this) {
+ synchronized (mLock) {
updateDisplayLocked();
}
} else if (phase == PHASE_BOOT_COMPLETED) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index a96c164b545e..f396c2dbc5f0 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -291,21 +291,26 @@ public class VoiceInteractionManagerService extends SystemService {
String curService = Settings.Secure.getStringForUser(
mResolver, Settings.Secure.VOICE_INTERACTION_SERVICE, mCurUser);
ComponentName serviceComponent = null;
+ ServiceInfo serviceInfo = null;
if (curService != null && !curService.isEmpty()) {
try {
serviceComponent = ComponentName.unflattenFromString(curService);
- } catch (RuntimeException e) {
+ serviceInfo = AppGlobals.getPackageManager()
+ .getServiceInfo(serviceComponent, 0, mCurUser);
+ } catch (RuntimeException | RemoteException e) {
Slog.wtf(TAG, "Bad voice interaction service name " + curService, e);
serviceComponent = null;
+ serviceInfo = null;
}
}
+
if (force || mImpl == null || mImpl.mUser != mCurUser
|| !mImpl.mComponent.equals(serviceComponent)) {
mSoundTriggerHelper.stopAllRecognitions();
if (mImpl != null) {
mImpl.shutdownLocked();
}
- if (serviceComponent != null) {
+ if (serviceComponent != null && serviceInfo != null) {
mImpl = new VoiceInteractionManagerServiceImpl(mContext,
UiThread.getHandler(), this, mCurUser, serviceComponent);
mImpl.startLocked();
diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
index 5db1bde5f3f0..723e8278bcc0 100644
--- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
@@ -23,6 +23,7 @@ import com.android.ide.common.rendering.api.ResourceReference;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.BridgeConstants;
+import com.android.layoutlib.bridge.MockView;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
import com.android.layoutlib.bridge.android.support.DrawerLayoutUtil;
@@ -126,6 +127,9 @@ public final class BridgeInflater extends LayoutInflater {
if (view == null) {
view = loadCustomView(name, attrs);
}
+ } catch (InflateException e) {
+ // Don't catch the InflateException below as that results in hiding the real cause.
+ throw e;
} catch (Exception e) {
// Wrap the real exception in a ClassNotFoundException, so that the calling method
// can deal with it.
@@ -154,23 +158,30 @@ public final class BridgeInflater extends LayoutInflater {
}
ta.recycle();
}
- final Object lastContext = mConstructorArgs[0];
- mConstructorArgs[0] = context;
- // try to load the class from using the custom view loader
- try {
- view = loadCustomView(name, attrs);
- } catch (Exception e2) {
- // Wrap the real exception in an InflateException so that the calling
- // method can deal with it.
- InflateException exception = new InflateException();
- if (!e2.getClass().equals(ClassNotFoundException.class)) {
- exception.initCause(e2);
- } else {
- exception.initCause(e);
+ if (!(e.getCause() instanceof ClassNotFoundException)) {
+ // There is some unknown inflation exception in inflating a View that was found.
+ view = new MockView(context, attrs);
+ ((MockView) view).setText(name);
+ Bridge.getLog().error(LayoutLog.TAG_BROKEN, e.getMessage(), e, null);
+ } else {
+ final Object lastContext = mConstructorArgs[0];
+ mConstructorArgs[0] = context;
+ // try to load the class from using the custom view loader
+ try {
+ view = loadCustomView(name, attrs);
+ } catch (Exception e2) {
+ // Wrap the real exception in an InflateException so that the calling
+ // method can deal with it.
+ InflateException exception = new InflateException();
+ if (!e2.getClass().equals(ClassNotFoundException.class)) {
+ exception.initCause(e2);
+ } else {
+ exception.initCause(e);
+ }
+ throw exception;
+ } finally {
+ mConstructorArgs[0] = lastContext;
}
- throw exception;
- } finally {
- mConstructorArgs[0] = lastContext;
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java
index 44a9aad55daa..d392f213e5c8 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java
@@ -17,39 +17,90 @@
package com.android.layoutlib.bridge;
import android.content.Context;
-import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
import android.widget.TextView;
/**
* Base class for mocked views.
- *
- * TODO: implement onDraw and draw a rectangle in a random color with the name of the class
- * (or better the id of the view).
+ * <p/>
+ * FrameLayout with a single TextView. Doesn't allow adding any other views to itself.
*/
-public class MockView extends TextView {
+public class MockView extends FrameLayout {
+
+ private final TextView mView;
+
+ public MockView(Context context) {
+ this(context, null);
+ }
public MockView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
- public MockView(Context context, AttributeSet attrs, int defStyle) {
- this(context, attrs, defStyle, 0);
+ public MockView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
}
public MockView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
-
- setText(this.getClass().getSimpleName());
- setTextColor(0xFF000000);
+ mView = new TextView(context, attrs);
+ mView.setTextColor(0xFF000000);
setGravity(Gravity.CENTER);
+ setText(getClass().getSimpleName());
+ addView(mView);
+ setBackgroundColor(0xFF7F7F7F);
+ }
+
+ // Only allow adding one TextView.
+ @Override
+ public void addView(View child) {
+ if (child == mView) {
+ super.addView(child);
+ }
+ }
+
+ @Override
+ public void addView(View child, int index) {
+ if (child == mView) {
+ super.addView(child, index);
+ }
}
@Override
- public void onDraw(Canvas canvas) {
- canvas.drawARGB(0xFF, 0x7F, 0x7F, 0x7F);
+ public void addView(View child, int width, int height) {
+ if (child == mView) {
+ super.addView(child, width, height);
+ }
+ }
+
+ @Override
+ public void addView(View child, ViewGroup.LayoutParams params) {
+ if (child == mView) {
+ super.addView(child, params);
+ }
+ }
+
+ @Override
+ public void addView(View child, int index, ViewGroup.LayoutParams params) {
+ if (child == mView) {
+ super.addView(child, index, params);
+ }
+ }
+
+ // The following methods are called by the IDE via reflection, and should be considered part
+ // of the API.
+ // Historically, MockView used to be a textView and had these methods. Now, we simply delegate
+ // them to the contained textView.
+
+ public void setText(CharSequence text) {
+ mView.setText(text);
+ }
- super.onDraw(canvas);
+ public void setGravity(int gravity) {
+ mView.setGravity(gravity);
}
}