summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/test-current.txt18
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java2
-rw-r--r--core/java/android/app/StatusBarManager.java3
-rw-r--r--core/java/android/app/WindowConfiguration.java59
-rw-r--r--core/java/android/bluetooth/BluetoothUuid.java2
-rw-r--r--core/java/android/content/res/Configuration.java37
-rw-r--r--core/java/android/text/format/Formatter.java29
-rw-r--r--core/java/android/webkit/WebView.java43
-rw-r--r--core/proto/android/app/window_configuration.proto31
-rw-r--r--core/proto/android/content/configuration.proto2
-rw-r--r--core/proto/android/server/windowmanagerservice.proto117
-rw-r--r--core/res/res/values/strings.xml13
-rw-r--r--core/res/res/values/symbols.xml5
-rw-r--r--core/tests/coretests/src/android/content/pm/PackageManagerTests.java4
-rw-r--r--core/tests/coretests/src/android/text/format/FormatterTest.java24
-rw-r--r--media/java/android/media/MediaRouter.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java6
-rw-r--r--services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java86
-rw-r--r--services/backup/java/com/android/server/backup/internal/PerformBackupTask.java4
-rw-r--r--services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java3
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java13
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java18
-rw-r--r--services/core/java/com/android/server/am/LockTaskController.java99
-rw-r--r--services/core/java/com/android/server/am/TaskRecord.java40
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java2
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java10
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java108
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java4
-rw-r--r--services/core/java/com/android/server/wm/ConfigurationContainer.java23
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java7
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java13
-rw-r--r--services/core/java/com/android/server/wm/Task.java7
-rw-r--r--services/core/java/com/android/server/wm/TaskStack.java7
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java21
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java7
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java117
44 files changed, 753 insertions, 316 deletions
diff --git a/api/test-current.txt b/api/test-current.txt
index 0902fc6daaf1..7256e5cf1cf9 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -6226,11 +6226,28 @@ package android.app {
}
public class WindowConfiguration implements java.lang.Comparable android.os.Parcelable {
+ ctor public WindowConfiguration();
method public int compareTo(android.app.WindowConfiguration);
method public int describeContents();
+ method public int getActivityType();
+ method public android.graphics.Rect getAppBounds();
+ method public int getWindowingMode();
+ method public void setActivityType(int);
+ method public void setAppBounds(android.graphics.Rect);
+ method public void setTo(android.app.WindowConfiguration);
+ method public void setWindowingMode(int);
method public void writeToParcel(android.os.Parcel, int);
+ field public static final int ACTIVITY_TYPE_ASSISTANT = 4; // 0x4
field public static final int ACTIVITY_TYPE_HOME = 2; // 0x2
field public static final int ACTIVITY_TYPE_RECENTS = 3; // 0x3
+ field public static final int ACTIVITY_TYPE_STANDARD = 1; // 0x1
+ field public static final int ACTIVITY_TYPE_UNDEFINED = 0; // 0x0
+ field public static final int WINDOWING_MODE_FREEFORM = 5; // 0x5
+ field public static final int WINDOWING_MODE_FULLSCREEN = 1; // 0x1
+ field public static final int WINDOWING_MODE_PINNED = 2; // 0x2
+ field public static final int WINDOWING_MODE_SPLIT_SCREEN_PRIMARY = 3; // 0x3
+ field public static final int WINDOWING_MODE_SPLIT_SCREEN_SECONDARY = 4; // 0x4
+ field public static final int WINDOWING_MODE_UNDEFINED = 0; // 0x0
}
}
@@ -11328,6 +11345,7 @@ package android.content.res {
field public int smallestScreenWidthDp;
field public int touchscreen;
field public int uiMode;
+ field public final android.app.WindowConfiguration windowConfiguration;
}
public class ObbInfo implements android.os.Parcelable {
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index ad989dee7b55..79faa1bf97a2 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -636,7 +636,7 @@ public final class Pm {
out = session.openWrite(splitName, 0, sizeBytes);
int total = 0;
- byte[] buffer = new byte[65536];
+ byte[] buffer = new byte[1024 * 1024];
int c;
while ((c = in.read(buffer)) != -1) {
total += c;
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 4a092140ed78..fe7afed8de13 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -14,15 +14,14 @@
* limitations under the License.
*/
-
package android.app;
import android.annotation.IntDef;
import android.annotation.SystemService;
import android.content.Context;
import android.os.Binder;
-import android.os.RemoteException;
import android.os.IBinder;
+import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Slog;
import android.view.View;
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index 5d87e1c2a157..07eb5de15d9f 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -17,6 +17,9 @@
package android.app;
import static android.app.ActivityThread.isSystem;
+import static android.app.WindowConfigurationProto.ACTIVITY_TYPE;
+import static android.app.WindowConfigurationProto.APP_BOUNDS;
+import static android.app.WindowConfigurationProto.WINDOWING_MODE;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -25,6 +28,7 @@ import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.proto.ProtoOutputStream;
import android.view.DisplayInfo;
/**
@@ -48,26 +52,20 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
/** The current windowing mode of the configuration. */
private @WindowingMode int mWindowingMode;
- /** Windowing mode is currently not defined.
- * @hide */
+ /** Windowing mode is currently not defined. */
public static final int WINDOWING_MODE_UNDEFINED = 0;
- /** Occupies the full area of the screen or the parent container.
- * @hide */
+ /** Occupies the full area of the screen or the parent container. */
public static final int WINDOWING_MODE_FULLSCREEN = 1;
- /** Always on-top (always visible). of other siblings in its parent container.
- * @hide */
+ /** Always on-top (always visible). of other siblings in its parent container. */
public static final int WINDOWING_MODE_PINNED = 2;
- /** The primary container driving the screen to be in split-screen mode.
- * @hide */
+ /** The primary container driving the screen to be in split-screen mode. */
public static final int WINDOWING_MODE_SPLIT_SCREEN_PRIMARY = 3;
/**
* The containers adjacent to the {@link #WINDOWING_MODE_SPLIT_SCREEN_PRIMARY} container in
* split-screen mode.
- * @hide
*/
public static final int WINDOWING_MODE_SPLIT_SCREEN_SECONDARY = 4;
- /** Can be freely resized within its parent container.
- * @hide */
+ /** Can be freely resized within its parent container. */
public static final int WINDOWING_MODE_FREEFORM = 5;
/** @hide */
@@ -84,18 +82,15 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
/** The current activity type of the configuration. */
private @ActivityType int mActivityType;
- /** Activity type is currently not defined.
- * @hide */
+ /** Activity type is currently not defined. */
public static final int ACTIVITY_TYPE_UNDEFINED = 0;
- /** Standard activity type. Nothing special about the activity...
- * @hide */
+ /** Standard activity type. Nothing special about the activity... */
public static final int ACTIVITY_TYPE_STANDARD = 1;
/** Home/Launcher activity type. */
public static final int ACTIVITY_TYPE_HOME = 2;
/** Recents/Overview activity type. */
public static final int ACTIVITY_TYPE_RECENTS = 3;
- /** Assistant activity type.
- * @hide */
+ /** Assistant activity type. */
public static final int ACTIVITY_TYPE_ASSISTANT = 4;
/** @hide */
@@ -127,7 +122,6 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
})
public @interface WindowConfig {}
- /** @hide */
public WindowConfiguration() {
unset();
}
@@ -176,7 +170,6 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
* Set {@link #mAppBounds} to the input Rect.
* @param rect The rect value to set {@link #mAppBounds} to.
* @see #getAppBounds()
- * @hide
*/
public void setAppBounds(Rect rect) {
if (rect == null) {
@@ -200,26 +193,20 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
mAppBounds.set(left, top, right, bottom);
}
- /**
- * @see #setAppBounds(Rect)
- * @hide
- */
+ /** @see #setAppBounds(Rect) */
public Rect getAppBounds() {
return mAppBounds;
}
- /** @hide */
public void setWindowingMode(@WindowingMode int windowingMode) {
mWindowingMode = windowingMode;
}
- /** @hide */
@WindowingMode
public int getWindowingMode() {
return mWindowingMode;
}
- /** @hide */
public void setActivityType(@ActivityType int activityType) {
if (mActivityType == activityType) {
return;
@@ -237,13 +224,11 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
mActivityType = activityType;
}
- /** @hide */
@ActivityType
public int getActivityType() {
return mActivityType;
}
- /** @hide */
public void setTo(WindowConfiguration other) {
setAppBounds(other.mAppBounds);
setWindowingMode(other.mWindowingMode);
@@ -382,6 +367,24 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
}
/**
+ * Write to a protocol buffer output stream.
+ * Protocol buffer message definition at {@link android.app.WindowConfigurationProto}
+ *
+ * @param protoOutputStream Stream to write the WindowConfiguration object to.
+ * @param fieldId Field Id of the WindowConfiguration as defined in the parent message
+ * @hide
+ */
+ public void writeToProto(ProtoOutputStream protoOutputStream, long fieldId) {
+ final long token = protoOutputStream.start(fieldId);
+ if (mAppBounds != null) {
+ mAppBounds.writeToProto(protoOutputStream, APP_BOUNDS);
+ }
+ protoOutputStream.write(WINDOWING_MODE, mWindowingMode);
+ protoOutputStream.write(ACTIVITY_TYPE, mActivityType);
+ protoOutputStream.end(token);
+ }
+
+ /**
* Returns true if the activities associated with this window configuration display a shadow
* around their border.
* @hide
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index 5bfc54d267ca..76cb3f5b548e 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -232,7 +232,7 @@ public final class BluetoothUuid {
*/
public static int getServiceIdentifierFromParcelUuid(ParcelUuid parcelUuid) {
UUID uuid = parcelUuid.getUuid();
- long value = (uuid.getMostSignificantBits() & 0x0000FFFF00000000L) >>> 32;
+ long value = (uuid.getMostSignificantBits() & 0xFFFFFFFF00000000L) >>> 32;
return (int) value;
}
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 780e6f769290..1310e30300e2 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -16,9 +16,20 @@
package android.content.res;
+import static android.content.ConfigurationProto.DENSITY_DPI;
+import static android.content.ConfigurationProto.FONT_SCALE;
+import static android.content.ConfigurationProto.ORIENTATION;
+import static android.content.ConfigurationProto.SCREEN_HEIGHT_DP;
+import static android.content.ConfigurationProto.SCREEN_LAYOUT;
+import static android.content.ConfigurationProto.SCREEN_WIDTH_DP;
+import static android.content.ConfigurationProto.SMALLEST_SCREEN_WIDTH_DP;
+import static android.content.ConfigurationProto.UI_MODE;
+import static android.content.ConfigurationProto.WINDOW_CONFIGURATION;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.app.WindowConfiguration;
import android.content.pm.ActivityInfo;
import android.content.pm.ActivityInfo.Config;
@@ -27,6 +38,7 @@ import android.os.LocaleList;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import android.util.proto.ProtoOutputStream;
import android.view.View;
import com.android.internal.util.XmlUtils;
@@ -295,11 +307,12 @@ public final class Configuration implements Parcelable, Comparable<Configuration
public int screenLayout;
/**
- * @hide
* Configuration relating to the windowing state of the object associated with this
* Configuration. Contents of this field are not intended to affect resources, but need to be
* communicated and propagated at the same time as the rest of Configuration.
+ * @hide
*/
+ @TestApi
public final WindowConfiguration windowConfiguration = new WindowConfiguration();
/** @hide */
@@ -1054,6 +1067,28 @@ public final class Configuration implements Parcelable, Comparable<Configuration
}
/**
+ * Write to a protocol buffer output stream.
+ * Protocol buffer message definition at {@link android.content.ConfigurationProto}
+ *
+ * @param protoOutputStream Stream to write the Configuration object to.
+ * @param fieldId Field Id of the Configuration as defined in the parent message
+ * @hide
+ */
+ public void writeToProto(ProtoOutputStream protoOutputStream, long fieldId) {
+ final long token = protoOutputStream.start(fieldId);
+ protoOutputStream.write(FONT_SCALE, fontScale);
+ protoOutputStream.write(SCREEN_LAYOUT, screenLayout);
+ protoOutputStream.write(ORIENTATION, orientation);
+ protoOutputStream.write(UI_MODE, uiMode);
+ protoOutputStream.write(SCREEN_WIDTH_DP, screenWidthDp);
+ protoOutputStream.write(SCREEN_HEIGHT_DP, screenHeightDp);
+ protoOutputStream.write(SMALLEST_SCREEN_WIDTH_DP, smallestScreenWidthDp);
+ protoOutputStream.write(DENSITY_DPI, densityDpi);
+ windowConfiguration.writeToProto(protoOutputStream, WINDOW_CONFIGURATION);
+ protoOutputStream.end(token);
+ }
+
+ /**
* Set this object to the system defaults.
*/
public void setToDefaults() {
diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java
index fc56455236a2..2c83fc4d9049 100644
--- a/core/java/android/text/format/Formatter.java
+++ b/core/java/android/text/format/Formatter.java
@@ -32,6 +32,7 @@ import android.text.BidiFormatter;
import android.text.TextUtils;
import android.view.View;
+import java.lang.reflect.Constructor;
import java.math.BigDecimal;
import java.util.Locale;
@@ -194,13 +195,29 @@ public final class Formatter {
/**
* ICU doesn't support PETABYTE yet. Fake it so that we can treat all units the same way.
- * {@hide}
*/
- public static final MeasureUnit PETABYTE = MeasureUnit.internalGetInstance(
- "digital", "petabyte");
+ private static final MeasureUnit PETABYTE = createPetaByte();
- /** {@hide} */
- public static class RoundedBytesResult {
+ /**
+ * Create a petabyte MeasureUnit without registering it with ICU.
+ * ICU doesn't support user-create MeasureUnit and the only public (but hidden) method to do so
+ * is {@link MeasureUnit#internalGetInstance(String, String)} which also registers the unit as
+ * an available type and thus leaks it to code that doesn't expect or support it.
+ * <p>This method uses reflection to create an instance of MeasureUnit to avoid leaking it. This
+ * instance is <b>only</b> to be used in this class.
+ */
+ private static MeasureUnit createPetaByte() {
+ try {
+ Constructor<MeasureUnit> constructor = MeasureUnit.class
+ .getDeclaredConstructor(String.class, String.class);
+ constructor.setAccessible(true);
+ return constructor.newInstance("digital", "petabyte");
+ } catch (ReflectiveOperationException e) {
+ throw new RuntimeException("Failed to create petabyte MeasureUnit", e);
+ }
+ }
+
+ private static class RoundedBytesResult {
public final float value;
public final MeasureUnit units;
public final int fractionDigits;
@@ -218,7 +235,7 @@ public final class Formatter {
* Returns a RoundedBytesResult object based on the input size in bytes and the rounding
* flags. The result can be used for formatting.
*/
- public static RoundedBytesResult roundBytes(long sizeBytes, int flags) {
+ static RoundedBytesResult roundBytes(long sizeBytes, int flags) {
final boolean isNegative = (sizeBytes < 0);
float result = isNegative ? -sizeBytes : sizeBytes;
MeasureUnit units = MeasureUnit.BYTE;
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 419b7b24fddb..3a4bfd686333 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2718,25 +2718,20 @@ public class WebView extends AbsoluteLayout
* {@code IFRAME}, in which case it would be treated the same way as multiple forms described
* above, except that the {@link ViewStructure#setWebDomain(String) web domain} of the
* {@code FORM} contains the {@code src} attribute from the {@code IFRAME} node.
- * <li>If the Android SDK provides a similar View, then should be set with the
- * fully-qualified class name of such view.
* <li>The W3C autofill field ({@code autocomplete} tag attribute) maps to
- * {@link ViewStructure#setAutofillHints(String[])}.
- * <li>The {@code type} attribute of {@code INPUT} tags maps to
- * {@link ViewStructure#setInputType(int)}.
- * <li>The {@code value} attribute of {@code INPUT} tags maps to
- * {@link ViewStructure#setText(CharSequence)}.
- * <li>If the view is editalbe, the {@link ViewStructure#setAutofillType(int)} and
+ * {@link ViewStructure#setAutofillHints(String[])}.
+ * <li>If the view is editable, the {@link ViewStructure#setAutofillType(int)} and
* {@link ViewStructure#setAutofillValue(AutofillValue)} must be set.
* <li>The {@code placeholder} attribute maps to {@link ViewStructure#setHint(CharSequence)}.
* <li>Other HTML attributes can be represented through
* {@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)}.
* </ol>
*
- * <p>It should also call {@code structure.setDataIsSensitive(false)} for fields whose value
- * were not dynamically changed (for example, through Javascript).
+ * <p>If the WebView implementation can determine that the value of a field was set statically
+ * (for example, not through Javascript), it should also call
+ * {@code structure.setDataIsSensitive(false)}.
*
- * <p>Example1: an HTML form with 2 fields for username and password.
+ * <p>For example, an HTML form with 2 fields for username and password:
*
* <pre class="prettyprint">
* &lt;input type="text" name="username" id="user" value="Type your username" autocomplete="username" placeholder="Email or username"&gt;
@@ -2749,51 +2744,27 @@ public class WebView extends AbsoluteLayout
* int index = structure.addChildCount(2);
* ViewStructure username = structure.newChild(index);
* username.setAutofillId(structure.getAutofillId(), 1); // id 1 - first child
- * username.setClassName("input");
- * username.setInputType("android.widget.EditText");
* username.setAutofillHints("username");
* username.setHtmlInfo(username.newHtmlInfoBuilder("input")
* .addAttribute("type", "text")
* .addAttribute("name", "username")
- * .addAttribute("id", "user")
* .build());
* username.setHint("Email or username");
* username.setAutofillType(View.AUTOFILL_TYPE_TEXT);
* username.setAutofillValue(AutofillValue.forText("Type your username"));
- * username.setText("Type your username");
- * // Value of the field is not sensitive because it was not dynamically changed:
+ * // Value of the field is not sensitive because it was created statically and not changed.
* username.setDataIsSensitive(false);
*
* ViewStructure password = structure.newChild(index + 1);
* username.setAutofillId(structure, 2); // id 2 - second child
- * password.setInputType("android.widget.EditText");
- * password.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD);
* password.setAutofillHints("current-password");
* password.setHtmlInfo(password.newHtmlInfoBuilder("input")
* .addAttribute("type", "password")
* .addAttribute("name", "password")
- * .addAttribute("id", "pass")
* .build());
* password.setHint("Password");
* password.setAutofillType(View.AUTOFILL_TYPE_TEXT);
* </pre>
- *
- * <p>Example2: an IFRAME tag.
- *
- * <pre class="prettyprint">
- * &lt;iframe src="https://example.com/login"/&gt;
- * </pre>
- *
- * <p>Would map to:
- *
- * <pre class="prettyprint">
- * int index = structure.addChildCount(1);
- * ViewStructure iframe = structure.newChildFor(index);
- * iframe.setAutofillId(structure.getAutofillId(), 1);
- * iframe.setHtmlInfo(iframe.newHtmlInfoBuilder("iframe")
- * .addAttribute("src", "https://example.com/login")
- * .build());
- * </pre>
*/
@Override
public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) {
diff --git a/core/proto/android/app/window_configuration.proto b/core/proto/android/app/window_configuration.proto
new file mode 100644
index 000000000000..03910df09194
--- /dev/null
+++ b/core/proto/android/app/window_configuration.proto
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+syntax = "proto3";
+
+option java_package = "android.app";
+option java_multiple_files = true;
+
+package android.app;
+
+import "frameworks/base/core/proto/android/graphics/rect.proto";
+
+/** Proto representation for WindowConfiguration.java class. */
+message WindowConfigurationProto {
+ .android.graphics.RectProto app_bounds = 1;
+ int32 windowing_mode = 2;
+ int32 activity_type = 3;
+}
diff --git a/core/proto/android/content/configuration.proto b/core/proto/android/content/configuration.proto
index f46b73afa750..804e0b489c0d 100644
--- a/core/proto/android/content/configuration.proto
+++ b/core/proto/android/content/configuration.proto
@@ -21,6 +21,7 @@ option java_multiple_files = true;
package android.content;
+import "frameworks/base/core/proto/android/app/window_configuration.proto";
import "frameworks/base/core/proto/android/content/locale.proto";
/**
@@ -43,5 +44,6 @@ message ConfigurationProto {
uint32 screen_height_dp = 14;
uint32 smallest_screen_width_dp = 15;
uint32 density_dpi = 16;
+ .android.app.WindowConfigurationProto window_configuration = 17;
}
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index ee8a6dc452b7..d177f1ca8104 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -16,6 +16,7 @@
syntax = "proto3";
+import "frameworks/base/core/proto/android/content/configuration.proto";
import "frameworks/base/core/proto/android/graphics/rect.proto";
import "frameworks/base/core/proto/android/view/displayinfo.proto";
import "frameworks/base/core/proto/android/view/windowlayoutparams.proto";
@@ -26,17 +27,23 @@ option java_multiple_files = true;
message WindowManagerServiceProto {
WindowManagerPolicyProto policy = 1;
- /* window manager hierarchy structure */
+ /* window hierarchy root */
+ RootWindowContainerProto root_window_container = 2;
+ IdentifierProto focused_window = 3;
+ string focused_app = 4;
+ IdentifierProto input_method_window = 5;
+ bool display_frozen = 6;
+ int32 rotation = 7;
+ int32 last_orientation = 8;
+ AppTransitionProto app_transition = 9;
+}
+
+/* represents DisplayContent */
+message RootWindowContainerProto {
+ WindowContainerProto window_container = 1;
repeated DisplayProto displays = 2;
/* window references in top down z order */
repeated IdentifierProto windows = 3;
- IdentifierProto focused_window = 4;
- string focused_app = 5;
- IdentifierProto input_method_window = 6;
- bool display_frozen = 7;
- int32 rotation = 8;
- int32 last_orientation = 9;
- AppTransitionProto app_transition = 10;
}
/* represents PhoneWindowManager */
@@ -81,18 +88,19 @@ message AppTransitionProto {
/* represents DisplayContent */
message DisplayProto {
- int32 id = 1;
- repeated StackProto stacks = 2;
- DockedStackDividerControllerProto docked_stack_divider_controller = 3;
- PinnedStackControllerProto pinned_stack_controller = 4;
+ WindowContainerProto window_container = 1;
+ int32 id = 2;
+ repeated StackProto stacks = 3;
+ DockedStackDividerControllerProto docked_stack_divider_controller = 4;
+ PinnedStackControllerProto pinned_stack_controller = 5;
/* non app windows */
- repeated WindowTokenProto above_app_windows = 5;
- repeated WindowTokenProto below_app_windows = 6;
- repeated WindowTokenProto ime_windows = 7;
- int32 dpi = 8;
- .android.view.DisplayInfoProto display_info = 9;
- int32 rotation = 10;
- ScreenRotationAnimationProto screen_rotation_animation = 11;
+ repeated WindowTokenProto above_app_windows = 6;
+ repeated WindowTokenProto below_app_windows = 7;
+ repeated WindowTokenProto ime_windows = 8;
+ int32 dpi = 9;
+ .android.view.DisplayInfoProto display_info = 10;
+ int32 rotation = 11;
+ ScreenRotationAnimationProto screen_rotation_animation = 12;
}
@@ -109,20 +117,22 @@ message PinnedStackControllerProto {
/* represents TaskStack */
message StackProto {
- int32 id = 1;
- repeated TaskProto tasks = 2;
- bool fills_parent = 3;
- .android.graphics.RectProto bounds = 4;
- bool animation_background_surface_is_dimming = 5;
+ WindowContainerProto window_container = 1;
+ int32 id = 2;
+ repeated TaskProto tasks = 3;
+ bool fills_parent = 4;
+ .android.graphics.RectProto bounds = 5;
+ bool animation_background_surface_is_dimming = 6;
}
/* represents Task */
message TaskProto {
- int32 id = 1;
- repeated AppWindowTokenProto app_window_tokens = 2;
- bool fills_parent = 3;
- .android.graphics.RectProto bounds = 4;
- .android.graphics.RectProto temp_inset_bounds = 5;
+ WindowContainerProto window_container = 1;
+ int32 id = 2;
+ repeated AppWindowTokenProto app_window_tokens = 3;
+ bool fills_parent = 4;
+ .android.graphics.RectProto bounds = 5;
+ .android.graphics.RectProto temp_inset_bounds = 6;
}
/* represents AppWindowToken */
@@ -134,26 +144,28 @@ message AppWindowTokenProto {
/* represents WindowToken */
message WindowTokenProto {
- int32 hash_code = 1;
- repeated WindowStateProto windows = 2;
+ WindowContainerProto window_container = 1;
+ int32 hash_code = 2;
+ repeated WindowStateProto windows = 3;
}
/* represents WindowState */
message WindowStateProto {
- IdentifierProto identifier = 1;
- int32 display_id = 2;
- int32 stack_id = 3;
- .android.view.WindowLayoutParamsProto attributes = 4;
- .android.graphics.RectProto given_content_insets = 5;
- .android.graphics.RectProto frame = 6;
- .android.graphics.RectProto containing_frame = 7;
- .android.graphics.RectProto parent_frame = 8;
- .android.graphics.RectProto content_frame = 9;
- .android.graphics.RectProto content_insets = 10;
- .android.graphics.RectProto surface_insets = 11;
- WindowStateAnimatorProto animator = 12;
- bool animating_exit = 13;
- repeated WindowStateProto child_windows = 14;
+ WindowContainerProto window_container = 1;
+ IdentifierProto identifier = 2;
+ int32 display_id = 3;
+ int32 stack_id = 4;
+ .android.view.WindowLayoutParamsProto attributes = 5;
+ .android.graphics.RectProto given_content_insets = 6;
+ .android.graphics.RectProto frame = 7;
+ .android.graphics.RectProto containing_frame = 8;
+ .android.graphics.RectProto parent_frame = 9;
+ .android.graphics.RectProto content_frame = 10;
+ .android.graphics.RectProto content_insets = 11;
+ .android.graphics.RectProto surface_insets = 12;
+ WindowStateAnimatorProto animator = 13;
+ bool animating_exit = 14;
+ repeated WindowStateProto child_windows = 15;
}
message IdentifierProto {
@@ -178,4 +190,17 @@ message WindowSurfaceControllerProto {
message ScreenRotationAnimationProto {
bool started = 1;
bool animation_running = 2;
-} \ No newline at end of file
+}
+
+/* represents WindowContainer */
+message WindowContainerProto {
+ ConfigurationContainerProto configuration_container = 1;
+ int32 orientation = 2;
+}
+
+/* represents ConfigurationContainer */
+message ConfigurationContainerProto {
+ .android.content.ConfigurationProto override_configuration = 1;
+ .android.content.ConfigurationProto full_configuration = 2;
+ .android.content.ConfigurationProto merged_override_configuration = 3;
+}
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index bd5b7116c435..7416113b4e90 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3785,15 +3785,18 @@
a headphone or other wired audio output jack. [CHAR LIMIT=50] -->
<string name="default_audio_route_name" product="default">Phone</string>
+ <!-- Name of the default audio route when an audio dock is connected. [CHAR LIMIT=50] -->
+ <string name="default_audio_route_name_dock_speakers">Dock speakers</string>
+
+ <!-- Name of the default audio route when HDMI is connected. [CHAR LIMIT=50] -->
+ <string name="default_audio_route_name_hdmi">HDMI</string>
+
<!-- Name of the default audio route when wired headphones are
connected. [CHAR LIMIT=50] -->
<string name="default_audio_route_name_headphones">Headphones</string>
- <!-- Name of the default audio route when an audio dock is connected. [CHAR LIMIT=50] -->
- <string name="default_audio_route_name_dock_speakers">Dock speakers</string>
-
- <!-- Name of the default media route when HDMI is connected. [CHAR LIMIT=50] -->
- <string name="default_media_route_name_hdmi">HDMI</string>
+ <!-- Name of the default audio route when USB is connected. [CHAR LIMIT=50] -->
+ <string name="default_audio_route_name_usb">USB</string>
<!-- Name of the default audio route category. [CHAR LIMIT=50] -->
<string name="default_audio_route_category_name">System</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 435b122bf744..c4a45ee11098 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1025,9 +1025,10 @@
<java-symbol type="string" name="granularity_label_link" />
<java-symbol type="string" name="granularity_label_line" />
<java-symbol type="string" name="default_audio_route_name" />
- <java-symbol type="string" name="default_audio_route_name_headphones" />
<java-symbol type="string" name="default_audio_route_name_dock_speakers" />
- <java-symbol type="string" name="default_media_route_name_hdmi" />
+ <java-symbol type="string" name="default_audio_route_name_hdmi" />
+ <java-symbol type="string" name="default_audio_route_name_headphones" />
+ <java-symbol type="string" name="default_audio_route_name_usb" />
<java-symbol type="string" name="default_audio_route_category_name" />
<java-symbol type="string" name="stk_cc_ss_to_dial" />
<java-symbol type="string" name="stk_cc_ss_to_ss" />
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 0a89b7409250..b8fa06c6e1c3 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -871,7 +871,7 @@ public class PackageManagerTests extends AndroidTestCase {
receiver = new InstallReceiver(ip.pkg.packageName);
}
try {
- invokeInstallPackage(ip.packageURI, flags, receiver, replace);
+ invokeInstallPackage(ip.packageURI, flags, receiver, true);
if (replace) {
assertInstall(ip.pkg, flags, ip.pkg.installLocation);
}
@@ -881,7 +881,7 @@ public class PackageManagerTests extends AndroidTestCase {
}
@LargeTest
- public void testReplaceFailNormalInternal() throws Exception {
+ public void testReplaceFlagDoesNotNeedToBeSet() throws Exception {
sampleReplaceFromRawResource(0);
}
diff --git a/core/tests/coretests/src/android/text/format/FormatterTest.java b/core/tests/coretests/src/android/text/format/FormatterTest.java
index ff75c29cc112..24e3646e02fc 100644
--- a/core/tests/coretests/src/android/text/format/FormatterTest.java
+++ b/core/tests/coretests/src/android/text/format/FormatterTest.java
@@ -17,10 +17,12 @@
package android.text.format;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.icu.util.MeasureUnit;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -32,6 +34,8 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Locale;
+import java.util.Set;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -205,4 +209,24 @@ public class FormatterTest {
Locale.setDefault(locale);
}
+
+ /**
+ * Verifies that Formatter doesn't "leak" the locally defined petabyte unit into ICU via the
+ * {@link MeasureUnit} registry. This test can fail for two reasons:
+ * 1. we regressed and started leaking again. In this case the code needs to be fixed.
+ * 2. ICU started supporting petabyte as a unit, in which case change one needs to revert this
+ * change (I494fb59a3b3742f35cbdf6b8705817f404a2c6b0), remove Formatter.PETABYTE and replace any
+ * usages of that field with just MeasureUnit.PETABYTE.
+ */
+ // http://b/65632959
+ @Test
+ public void doesNotLeakPetabyte() {
+ // Ensure that the Formatter class is loaded when we call .getAvailable().
+ Formatter.formatFileSize(mContext, Long.MAX_VALUE);
+ Set<MeasureUnit> digitalUnits = MeasureUnit.getAvailable("digital");
+ for (MeasureUnit unit : digitalUnits) {
+ // This assert can fail if we don't leak PETABYTE, but ICU has added it, see #2 above.
+ assertNotEquals("petabyte", unit.getSubtype());
+ }
+ }
}
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 2894e8956c1c..fe427a73bf96 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -193,7 +193,9 @@ public class MediaRouter {
} else if ((newRoutes.mainType&AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) {
name = com.android.internal.R.string.default_audio_route_name_dock_speakers;
} else if ((newRoutes.mainType&AudioRoutesInfo.MAIN_HDMI) != 0) {
- name = com.android.internal.R.string.default_media_route_name_hdmi;
+ name = com.android.internal.R.string.default_audio_route_name_hdmi;
+ } else if ((newRoutes.mainType&AudioRoutesInfo.MAIN_USB) != 0) {
+ name = com.android.internal.R.string.default_audio_route_name_usb;
} else {
name = com.android.internal.R.string.default_audio_route_name;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 7fe7f399f123..8fa904e10b4a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -2024,14 +2024,15 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
@Override
- public int getMinHeight() {
- if (mGuts != null && mGuts.isExposed()) {
+ public int getMinHeight(boolean ignoreTemporaryStates) {
+ if (!ignoreTemporaryStates && mGuts != null && mGuts.isExposed()) {
return mGuts.getIntrinsicHeight();
- } else if (isHeadsUpAllowed() && mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
+ } else if (!ignoreTemporaryStates && isHeadsUpAllowed() && mIsHeadsUp
+ && mHeadsUpManager.isTrackingHeadsUp()) {
return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
} else if (mIsSummaryWithChildren && !isGroupExpanded() && !mShowingPublic) {
return mChildrenContainer.getMinHeight();
- } else if (isHeadsUpAllowed() && mIsHeadsUp) {
+ } else if (!ignoreTemporaryStates && isHeadsUpAllowed() && mIsHeadsUp) {
return mHeadsUpHeight;
}
NotificationContentView showingLayout = getShowingLayout();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index efe5e0c2ade4..aac9af8a0234 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -151,9 +151,21 @@ public abstract class ExpandableView extends FrameLayout {
}
/**
- * @return The minimum content height of this notification.
+ * @return The minimum content height of this notification. This also respects the temporary
+ * states of the view.
*/
public int getMinHeight() {
+ return getMinHeight(false /* ignoreTemporaryStates */);
+ }
+
+ /**
+ * Get the minimum height of this view.
+ *
+ * @param ignoreTemporaryStates should temporary states be ignored like the guts or heads-up.
+ *
+ * @return The minimum height that this view needs.
+ */
+ public int getMinHeight(boolean ignoreTemporaryStates) {
return getHeight();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index ddc7dd063d4e..d0417b59448d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -292,8 +292,8 @@ public class NotificationData {
if (mRankingMap != null) {
// RankingMap as received from NoMan
- mRankingMap.getRanking(a.key, mRankingA);
- mRankingMap.getRanking(b.key, mRankingB);
+ getRanking(a.key, mRankingA);
+ getRanking(b.key, mRankingB);
aImportance = mRankingA.getImportance();
bImportance = mRankingB.getImportance();
aRank = mRankingA.getRank();
@@ -381,7 +381,7 @@ public class NotificationData {
public boolean isAmbient(String key) {
if (mRankingMap != null) {
- mRankingMap.getRanking(key, mTmpRanking);
+ getRanking(key, mTmpRanking);
return mTmpRanking.isAmbient();
}
return false;
@@ -389,7 +389,7 @@ public class NotificationData {
public int getVisibilityOverride(String key) {
if (mRankingMap != null) {
- mRankingMap.getRanking(key, mTmpRanking);
+ getRanking(key, mTmpRanking);
return mTmpRanking.getVisibilityOverride();
}
return Ranking.VISIBILITY_NO_OVERRIDE;
@@ -397,7 +397,7 @@ public class NotificationData {
public boolean shouldSuppressScreenOff(String key) {
if (mRankingMap != null) {
- mRankingMap.getRanking(key, mTmpRanking);
+ getRanking(key, mTmpRanking);
return (mTmpRanking.getSuppressedVisualEffects()
& NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) != 0;
}
@@ -406,7 +406,7 @@ public class NotificationData {
public boolean shouldSuppressScreenOn(String key) {
if (mRankingMap != null) {
- mRankingMap.getRanking(key, mTmpRanking);
+ getRanking(key, mTmpRanking);
return (mTmpRanking.getSuppressedVisualEffects()
& NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON) != 0;
}
@@ -415,7 +415,7 @@ public class NotificationData {
public int getImportance(String key) {
if (mRankingMap != null) {
- mRankingMap.getRanking(key, mTmpRanking);
+ getRanking(key, mTmpRanking);
return mTmpRanking.getImportance();
}
return NotificationManager.IMPORTANCE_UNSPECIFIED;
@@ -423,7 +423,7 @@ public class NotificationData {
public String getOverrideGroupKey(String key) {
if (mRankingMap != null) {
- mRankingMap.getRanking(key, mTmpRanking);
+ getRanking(key, mTmpRanking);
return mTmpRanking.getOverrideGroupKey();
}
return null;
@@ -431,7 +431,7 @@ public class NotificationData {
public List<SnoozeCriterion> getSnoozeCriteria(String key) {
if (mRankingMap != null) {
- mRankingMap.getRanking(key, mTmpRanking);
+ getRanking(key, mTmpRanking);
return mTmpRanking.getSnoozeCriteria();
}
return null;
@@ -439,7 +439,7 @@ public class NotificationData {
public NotificationChannel getChannel(String key) {
if (mRankingMap != null) {
- mRankingMap.getRanking(key, mTmpRanking);
+ getRanking(key, mTmpRanking);
return mTmpRanking.getChannel();
}
return null;
@@ -452,6 +452,9 @@ public class NotificationData {
final int N = mEntries.size();
for (int i = 0; i < N; i++) {
Entry entry = mEntries.valueAt(i);
+ if (!getRanking(entry.key, mTmpRanking)) {
+ continue;
+ }
final StatusBarNotification oldSbn = entry.notification.cloneLight();
final String overrideGroupKey = getOverrideGroupKey(entry.key);
if (!Objects.equals(oldSbn.getOverrideGroupKey(), overrideGroupKey)) {
@@ -466,6 +469,19 @@ public class NotificationData {
filterAndSort();
}
+ /**
+ * Get the ranking from the current ranking map.
+ *
+ * @param key the key to look up
+ * @param outRanking the ranking to populate
+ *
+ * @return {@code true} if the ranking was properly obtained.
+ */
+ @VisibleForTesting
+ protected boolean getRanking(String key, Ranking outRanking) {
+ return mRankingMap.getRanking(key, outRanking);
+ }
+
// TODO: This should not be public. Instead the Environment should notify this class when
// anything changed, and this class should call back the UI so it updates itself.
public void filterAndSort() {
@@ -573,7 +589,7 @@ public class NotificationData {
}
private void dumpEntry(PrintWriter pw, String indent, int i, Entry e) {
- mRankingMap.getRanking(e.key, mTmpRanking);
+ getRanking(e.key, mTmpRanking);
pw.print(indent);
pw.println(" [" + i + "] key=" + e.key + " icon=" + e.icon);
StatusBarNotification n = e.notification;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index 1f44abea755a..4bca79715422 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -50,7 +50,7 @@ public class BarTransitions {
public static final int MODE_LIGHTS_OUT_TRANSPARENT = 6;
public static final int LIGHTS_IN_DURATION = 250;
- public static final int LIGHTS_OUT_DURATION = 750;
+ public static final int LIGHTS_OUT_DURATION = 1500;
public static final int BACKGROUND_DURATION = 200;
private final String mTag;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 078e8189f5b3..c19161839998 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -509,7 +509,8 @@ public class NotificationPanelView extends PanelView implements
if (row.isRemoved()) {
continue;
}
- availableSpace -= child.getMinHeight() + notificationPadding;
+ availableSpace -= child.getMinHeight(true /* ignoreTemporaryStates */)
+ + notificationPadding;
if (availableSpace >= 0 && count < maximum) {
count++;
} else if (availableSpace > -shelfSize) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index efc8d8b97114..200cada972a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -339,7 +339,7 @@ public class StatusBar extends SystemUI implements DemoMode,
private static final int STATUS_OR_NAV_TRANSIENT =
View.STATUS_BAR_TRANSIENT | View.NAVIGATION_BAR_TRANSIENT;
- private static final long AUTOHIDE_TIMEOUT_MS = 3000;
+ private static final long AUTOHIDE_TIMEOUT_MS = 2250;
/** The minimum delay in ms between reports of notification visibility. */
private static final int VISIBILITY_REPORT_MIN_DELAY_MS = 500;
@@ -3321,7 +3321,6 @@ public class StatusBar extends SystemUI implements DemoMode,
} else {
cancelAutohide();
}
- touchAutoDim();
}
protected int computeStatusBarMode(int oldVal, int newVal) {
@@ -3404,10 +3403,10 @@ public class StatusBar extends SystemUI implements DemoMode,
}
// manually dismiss the volume panel when interacting with the nav bar
if (changing && interacting && barWindow == StatusBarManager.WINDOW_NAVIGATION_BAR) {
+ touchAutoDim();
dismissVolumeDialog();
}
checkBarModes();
- touchAutoDim();
}
private void dismissVolumeDialog() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java
index 18c5756b3fb6..972eddb46901 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java
@@ -135,5 +135,11 @@ public class NotificationDataTest extends SysuiTestCase {
public NotificationChannel getChannel(String key) {
return new NotificationChannel(null, null, 0);
}
+
+ @Override
+ protected boolean getRanking(String key, NotificationListenerService.Ranking outRanking) {
+ super.getRanking(key, outRanking);
+ return true;
+ }
}
}
diff --git a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
index 141f9207b314..c203dff07e89 100644
--- a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
@@ -77,6 +77,7 @@ import android.os.RemoteException;
import android.os.SELinux;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.Trace;
import android.os.UserHandle;
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
@@ -149,6 +150,7 @@ import java.util.Queue;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicInteger;
public class RefactoredBackupManagerService implements BackupManagerServiceInterface {
@@ -546,9 +548,12 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
@Override
public void onUnlockUser(int userId) {
if (userId == UserHandle.USER_SYSTEM) {
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup init");
sInstance.initialize(userId);
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// Migrate legacy setting
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup migrate");
if (!backupSettingMigrated(userId)) {
if (DEBUG) {
Slog.i(TAG, "Backup enable apparently not migrated");
@@ -569,12 +574,15 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
}
}
}
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup enable");
try {
sInstance.setBackupEnabled(readBackupEnableState(userId));
} catch (RemoteException e) {
// can't happen; it's a local object
}
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}
}
@@ -619,6 +627,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
private final SparseArray<Operation> mCurrentOperations = new SparseArray<>();
private final Object mCurrentOpLock = new Object();
private final Random mTokenGenerator = new Random();
+ final AtomicInteger mNextToken = new AtomicInteger();
private final SparseArray<AdbParams> mAdbBackupRestoreConfirmations = new SparseArray<>();
@@ -658,15 +667,15 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
@GuardedBy("mQueueLock")
private ArrayList<FullBackupEntry> mFullBackupQueue;
- // Utility: build a new random integer token
+ // Utility: build a new random integer token. The low bits are the ordinal of the
+ // operation for near-time uniqueness, and the upper bits are random for app-
+ // side unpredictability.
@Override
public int generateRandomIntegerToken() {
- int token;
- do {
- synchronized (mTokenGenerator) {
- token = mTokenGenerator.nextInt();
- }
- } while (token < 0);
+ int token = mTokenGenerator.nextInt();
+ if (token < 0) token = -token;
+ token &= ~0xFF;
+ token |= (mNextToken.incrementAndGet() & 0xFF);
return token;
}
@@ -1507,7 +1516,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
long token = mAncestralToken;
synchronized (mQueueLock) {
- if (mProcessedPackagesJournal.hasBeenProcessed(packageName)) {
+ if (mCurrentToken != 0 && mProcessedPackagesJournal.hasBeenProcessed(packageName)) {
if (MORE_DEBUG) {
Slog.i(TAG, "App in ever-stored, so using current token");
}
@@ -1759,8 +1768,12 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
// Can't delete op from mCurrentOperations here. waitUntilOperationComplete may be
// called after we receive cancel here. We need this op's state there.
- // Remove all pending timeout messages for this operation type.
- mBackupHandler.removeMessages(getMessageIdForOperationType(op.type));
+ // Remove all pending timeout messages of types OP_TYPE_BACKUP_WAIT and
+ // OP_TYPE_RESTORE_WAIT. On the other hand, OP_TYPE_BACKUP cannot time out and
+ // doesn't require cancellation.
+ if (op.type == OP_TYPE_BACKUP_WAIT || op.type == OP_TYPE_RESTORE_WAIT) {
+ mBackupHandler.removeMessages(getMessageIdForOperationType(op.type));
+ }
}
mCurrentOpLock.notifyAll();
}
@@ -2108,14 +2121,26 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
// so tear down any ongoing backup task right away.
@Override
public void endFullBackup() {
- synchronized (mQueueLock) {
- if (mRunningFullBackupTask != null) {
- if (DEBUG_SCHEDULING) {
- Slog.i(TAG, "Telling running backup to stop");
+ // offload the mRunningFullBackupTask.handleCancel() call to another thread,
+ // as we might have to wait for mCancelLock
+ Runnable endFullBackupRunnable = new Runnable() {
+ @Override
+ public void run() {
+ PerformFullTransportBackupTask pftbt = null;
+ synchronized (mQueueLock) {
+ if (mRunningFullBackupTask != null) {
+ pftbt = mRunningFullBackupTask;
+ }
+ }
+ if (pftbt != null) {
+ if (DEBUG_SCHEDULING) {
+ Slog.i(TAG, "Telling running backup to stop");
+ }
+ pftbt.handleCancel(true);
}
- mRunningFullBackupTask.handleCancel(true);
}
- }
+ };
+ new Thread(endFullBackupRunnable, "end-full-backup").start();
}
// Used by both incremental and full restore
@@ -2800,8 +2825,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
final long oldId = Binder.clearCallingIdentity();
try {
String prevTransport = mTransportManager.selectTransport(transport);
- Settings.Secure.putString(mContext.getContentResolver(),
- Settings.Secure.BACKUP_TRANSPORT, transport);
+ updateStateForTransport(transport);
Slog.v(TAG, "selectBackupTransport() set " + mTransportManager.getCurrentTransportName()
+ " returning " + prevTransport);
return prevTransport;
@@ -2826,9 +2850,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
@Override
public void onSuccess(String transportName) {
mTransportManager.selectTransport(transportName);
- Settings.Secure.putString(mContext.getContentResolver(),
- Settings.Secure.BACKUP_TRANSPORT,
- mTransportManager.getCurrentTransportName());
+ updateStateForTransport(mTransportManager.getCurrentTransportName());
Slog.v(TAG, "Transport successfully selected: "
+ transport.flattenToShortString());
try {
@@ -2853,6 +2875,28 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
Binder.restoreCallingIdentity(oldId);
}
+ private void updateStateForTransport(String newTransportName) {
+ // Publish the name change
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.BACKUP_TRANSPORT, newTransportName);
+
+ // And update our current-dataset bookkeeping
+ IBackupTransport transport = mTransportManager.getTransportBinder(newTransportName);
+ if (transport != null) {
+ try {
+ mCurrentToken = transport.getCurrentRestoreSet();
+ } catch (Exception e) {
+ // Oops. We can't know the current dataset token, so reset and figure it out
+ // when we do the next k/v backup operation on this transport.
+ mCurrentToken = 0;
+ }
+ } else {
+ // The named transport isn't bound at this particular moment, so we can't
+ // know yet what its current dataset token is. Reset as above.
+ mCurrentToken = 0;
+ }
+ }
+
// Supply the configuration Intent for the given transport. If the name is not one
// of the available transports, or if the transport does not supply any configuration
// UI, the method returns null.
diff --git a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
index ce4f906ecdec..6bbed8cbfdf9 100644
--- a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
+++ b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
@@ -227,9 +227,8 @@ public class PerformBackupTask implements BackupRestoreTask {
if (!mFinished) {
finalizeBackup();
} else {
- Slog.e(TAG, "Duplicate finish");
+ Slog.e(TAG, "Duplicate finish of K/V pass");
}
- mFinished = true;
break;
}
}
@@ -609,6 +608,7 @@ public class PerformBackupTask implements BackupRestoreTask {
break;
}
}
+ mFinished = true;
Slog.i(TAG, "K/V backup pass finished.");
// Only once we're entirely finished do we release the wakelock for k/v backup.
backupManagerService.getWakelock().release();
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index 21d5dc21c196..283a1f0e93dd 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -779,6 +779,9 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
// state RESTORE_FINISHED : provide the "no more data" signpost callback at the end
private void restoreFinished() {
+ if (DEBUG) {
+ Slog.d(TAG, "restoreFinished packageName=" + mCurrentPackage.packageName);
+ }
try {
backupManagerService
.prepareOperationTimeout(mEphemeralOpToken,
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 02eb3b432dfe..c8e2dc57e0ed 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -682,11 +682,6 @@ public class ActivityManagerService extends IActivityManager.Stub
ActivityInfo mLastAddedTaskActivity;
/**
- * List of packages whitelisted by DevicePolicyManager for locktask. Indexed by userId.
- */
- SparseArray<String[]> mLockTaskPackages = new SparseArray<>();
-
- /**
* The package name of the DeviceOwner. This package is not permitted to have its data cleared.
*/
String mDeviceOwnerName;
@@ -10882,7 +10877,6 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public void updateLockTaskPackages(int userId, String[] packages) {
- // TODO: move this into LockTaskController
final int callingUid = Binder.getCallingUid();
if (callingUid != 0 && callingUid != SYSTEM_UID) {
enforceCallingPermission(android.Manifest.permission.UPDATE_LOCK_TASK_PACKAGES,
@@ -10891,8 +10885,7 @@ public class ActivityManagerService extends IActivityManager.Stub
synchronized (this) {
if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Whitelisting " + userId + ":" +
Arrays.toString(packages));
- mLockTaskPackages.put(userId, packages);
- mLockTaskController.onLockTaskPackagesUpdated();
+ mLockTaskController.updateLockTaskPackages(userId, packages);
}
}
@@ -13982,10 +13975,10 @@ public class ActivityManagerService extends IActivityManager.Stub
mContext.getPackageManager().hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT)
|| Settings.Global.getInt(
resolver, DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0;
- final boolean supportsPictureInPicture =
- mContext.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE);
final boolean supportsMultiWindow = ActivityManager.supportsMultiWindow(mContext);
+ final boolean supportsPictureInPicture = supportsMultiWindow &&
+ mContext.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE);
final boolean supportsSplitScreenMultiWindow =
ActivityManager.supportsSplitScreenMultiWindow(mContext);
final boolean supportsMultiDisplay = mContext.getPackageManager()
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index fe28956d6923..c8a2a230a7e1 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -166,7 +166,6 @@ import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
@@ -1639,6 +1638,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
return true;
}
+ // Check if caller is already present on display
+ final boolean uidPresentOnDisplay = activityDisplay.isUidPresent(callingUid);
+
final int displayOwnerUid = activityDisplay.mDisplay.getOwnerUid();
if (activityDisplay.mDisplay.getType() == TYPE_VIRTUAL && displayOwnerUid != SYSTEM_UID
&& displayOwnerUid != aInfo.applicationInfo.uid) {
@@ -1651,7 +1653,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
// Check if the caller is allowed to embed activities from other apps.
if (mService.checkPermission(ACTIVITY_EMBEDDING, callingPid, callingUid)
- == PERMISSION_DENIED) {
+ == PERMISSION_DENIED && !uidPresentOnDisplay) {
if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
+ " disallow activity embedding without permission.");
return false;
@@ -1672,8 +1674,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
return true;
}
- // Check if caller is present on display
- if (activityDisplay.isUidPresent(callingUid)) {
+ if (uidPresentOnDisplay) {
if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
+ " allow launch for caller present on the display");
return true;
@@ -3556,15 +3557,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
pw.println("mCurTaskIdForUser=" + mCurTaskIdForUser);
pw.print(prefix); pw.println("mUserStackInFront=" + mUserStackInFront);
pw.print(prefix); pw.println("mStacks=" + mStacks);
- // TODO: move this to LockTaskController
- final SparseArray<String[]> packages = mService.mLockTaskPackages;
- if (packages.size() > 0) {
- pw.print(prefix); pw.println("mLockTaskPackages (userId:packages)=");
- for (int i = 0; i < packages.size(); ++i) {
- pw.print(prefix); pw.print(prefix); pw.print(packages.keyAt(i));
- pw.print(":"); pw.println(Arrays.toString(packages.valueAt(i)));
- }
- }
if (!mWaitingForActivityVisible.isEmpty()) {
pw.print(prefix); pw.println("mWaitingForActivityVisible=");
for (int i = 0; i < mWaitingForActivityVisible.size(); ++i) {
diff --git a/services/core/java/com/android/server/am/LockTaskController.java b/services/core/java/com/android/server/am/LockTaskController.java
index d8706bcc5e35..241e58391144 100644
--- a/services/core/java/com/android/server/am/LockTaskController.java
+++ b/services/core/java/com/android/server/am/LockTaskController.java
@@ -31,6 +31,7 @@ import static android.os.UserHandle.USER_ALL;
import static android.os.UserHandle.USER_CURRENT;
import static android.provider.Settings.Secure.LOCK_TO_APP_EXIT_LOCKED;
import static android.view.Display.DEFAULT_DISPLAY;
+
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
@@ -55,7 +56,9 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;
import android.util.Slog;
+import android.util.SparseArray;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.widget.LockPatternUtils;
@@ -65,6 +68,7 @@ import com.android.server.wm.WindowManagerService;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
/**
* Helper class that deals with all things related to task locking. This includes the screen pinning
@@ -123,6 +127,11 @@ public class LockTaskController {
private final ArrayList<TaskRecord> mLockTaskModeTasks = new ArrayList<>();
/**
+ * Packages that are allowed to be launched into the lock task mode for each user.
+ */
+ private final SparseArray<String[]> mLockTaskPackages = new SparseArray<>();
+
+ /**
* Store the current lock task mode. Possible values:
* {@link ActivityManager#LOCK_TASK_MODE_NONE}, {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
* {@link ActivityManager#LOCK_TASK_MODE_PINNED}
@@ -159,8 +168,8 @@ public class LockTaskController {
}
/**
- * @return whether the given task can be moved to the back of the stack. Locked tasks cannot be
- * moved to the back of the stack.
+ * @return whether the given task is locked at the moment. Locked tasks cannot be moved to the
+ * back of the stack.
*/
boolean checkLockedTask(TaskRecord task) {
if (mLockTaskModeTasks.contains(task)) {
@@ -452,29 +461,35 @@ public class LockTaskController {
}
/**
- * Called when the list of packages whitelisted for lock task mode is changed. Any currently
- * locked tasks that got removed from the whitelist will be finished.
+ * Update packages that are allowed to be launched in lock task mode.
+ * @param userId Which user this whitelist is associated with
+ * @param packages The whitelist of packages allowed in lock task mode
+ * @see #mLockTaskPackages
*/
- // TODO: Missing unit tests
- void onLockTaskPackagesUpdated() {
- boolean didSomething = false;
+ void updateLockTaskPackages(int userId, String[] packages) {
+ mLockTaskPackages.put(userId, packages);
+
+ boolean taskChanged = false;
for (int taskNdx = mLockTaskModeTasks.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord lockedTask = mLockTaskModeTasks.get(taskNdx);
- final boolean wasWhitelisted =
- (lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) ||
- (lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED);
+ final boolean wasWhitelisted = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
+ || lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED;
lockedTask.setLockTaskAuth();
- final boolean isWhitelisted =
- (lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) ||
- (lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED);
- if (wasWhitelisted && !isWhitelisted) {
- // Lost whitelisting authorization. End it now.
- if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "onLockTaskPackagesUpdated: removing " +
- lockedTask + " mLockTaskAuth()=" + lockedTask.lockTaskAuthToString());
- removeLockedTask(lockedTask);
- lockedTask.performClearTaskLocked();
- didSomething = true;
+ final boolean isWhitelisted = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
+ || lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED;
+
+ if (mLockTaskModeState != LOCK_TASK_MODE_LOCKED
+ || lockedTask.userId != userId
+ || !wasWhitelisted || isWhitelisted) {
+ continue;
}
+
+ // Terminate locked tasks that have recently lost whitelist authorization.
+ if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "onLockTaskPackagesUpdated: removing " +
+ lockedTask + " mLockTaskAuth()=" + lockedTask.lockTaskAuthToString());
+ removeLockedTask(lockedTask);
+ lockedTask.performClearTaskLocked();
+ taskChanged = true;
}
for (int displayNdx = mSupervisor.getChildCount() - 1; displayNdx >= 0; --displayNdx) {
@@ -484,22 +499,40 @@ public class LockTaskController {
stack.onLockTaskPackagesUpdatedLocked();
}
}
+
final ActivityRecord r = mSupervisor.topRunningActivityLocked();
- final TaskRecord task = r != null ? r.getTask() : null;
- if (mLockTaskModeTasks.isEmpty() && task != null
+ final TaskRecord task = (r != null) ? r.getTask() : null;
+ if (mLockTaskModeTasks.isEmpty() && task!= null
&& task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) {
// This task must have just been authorized.
if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK,
"onLockTaskPackagesUpdated: starting new locktask task=" + task);
- setLockTaskMode(task, LOCK_TASK_MODE_LOCKED, "package updated",
- false);
- didSomething = true;
+ setLockTaskMode(task, LOCK_TASK_MODE_LOCKED, "package updated", false);
+ taskChanged = true;
}
- if (didSomething) {
+
+ if (taskChanged) {
mSupervisor.resumeFocusedStackTopActivityLocked();
}
}
+ boolean isPackageWhitelisted(int userId, String pkg) {
+ if (pkg == null) {
+ return false;
+ }
+ String[] whitelist;
+ whitelist = mLockTaskPackages.get(userId);
+ if (whitelist == null) {
+ return false;
+ }
+ for (String whitelistedPkg : whitelist) {
+ if (pkg.equals(whitelistedPkg)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* @return the topmost locked task
*/
@@ -556,8 +589,18 @@ public class LockTaskController {
}
public void dump(PrintWriter pw, String prefix) {
- pw.print(prefix); pw.print("mLockTaskModeState=" + lockTaskModeToString());
- pw.println(" mLockTaskModeTasks" + mLockTaskModeTasks);
+ pw.println(prefix + "LockTaskController");
+ prefix = prefix + " ";
+ pw.println(prefix + "mLockTaskModeState=" + lockTaskModeToString());
+ pw.println(prefix + "mLockTaskModeTasks=");
+ for (int i = 0; i < mLockTaskModeTasks.size(); ++i) {
+ pw.println(prefix + " #" + i + " " + mLockTaskModeTasks.get(i));
+ }
+ pw.println(prefix + "mLockTaskPackages (userId:packages)=");
+ for (int i = 0; i < mLockTaskPackages.size(); ++i) {
+ pw.println(prefix + " u" + mLockTaskPackages.keyAt(i)
+ + ":" + Arrays.toString(mLockTaskPackages.valueAt(i)));
+ }
}
private String lockTaskModeToString() {
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 0e651845df8d..48da6555e75c 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -78,7 +78,6 @@ import android.app.ActivityManager.TaskSnapshot;
import android.app.ActivityOptions;
import android.app.AppGlobals;
import android.app.IActivityManager;
-import android.app.WindowConfiguration;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
@@ -857,8 +856,13 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
}
mResizeMode = info.resizeMode;
mSupportsPictureInPicture = info.supportsPictureInPicture();
- mLockTaskMode = info.lockTaskLaunchMode;
mPrivileged = (info.applicationInfo.privateFlags & PRIVATE_FLAG_PRIVILEGED) != 0;
+ mLockTaskMode = info.lockTaskLaunchMode;
+ if (!mPrivileged && (mLockTaskMode == LOCK_TASK_LAUNCH_MODE_ALWAYS
+ || mLockTaskMode == LOCK_TASK_LAUNCH_MODE_NEVER)) {
+ // Non-priv apps are not allowed to use always or never, fall back to default
+ mLockTaskMode = LOCK_TASK_LAUNCH_MODE_DEFAULT;
+ }
setLockTaskAuth();
}
@@ -1396,16 +1400,11 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
}
void setLockTaskAuth() {
- if (!mPrivileged &&
- (mLockTaskMode == LOCK_TASK_LAUNCH_MODE_ALWAYS ||
- mLockTaskMode == LOCK_TASK_LAUNCH_MODE_NEVER)) {
- // Non-priv apps are not allowed to use always or never, fall back to default
- mLockTaskMode = LOCK_TASK_LAUNCH_MODE_DEFAULT;
- }
+ final String pkg = (realActivity != null) ? realActivity.getPackageName() : null;
switch (mLockTaskMode) {
case LOCK_TASK_LAUNCH_MODE_DEFAULT:
- mLockTaskAuth = isLockTaskWhitelistedLocked() ?
- LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE;
+ mLockTaskAuth = mService.mLockTaskController.isPackageWhitelisted(userId, pkg)
+ ? LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE;
break;
case LOCK_TASK_LAUNCH_MODE_NEVER:
@@ -1417,31 +1416,14 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
break;
case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED:
- mLockTaskAuth = isLockTaskWhitelistedLocked() ?
- LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
+ mLockTaskAuth = mService.mLockTaskController.isPackageWhitelisted(userId, pkg)
+ ? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
break;
}
if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this +
" mLockTaskAuth=" + lockTaskAuthToString());
}
- private boolean isLockTaskWhitelistedLocked() {
- String pkg = (realActivity != null) ? realActivity.getPackageName() : null;
- if (pkg == null) {
- return false;
- }
- String[] packages = mService.mLockTaskPackages.get(userId);
- if (packages == null) {
- return false;
- }
- for (int i = packages.length - 1; i >= 0; --i) {
- if (pkg.equals(packages[i])) {
- return true;
- }
- }
- return false;
- }
-
boolean isOverHomeStack() {
return mTaskToReturnTo == ACTIVITY_TYPE_HOME;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 930e4f098f5f..1f03e666d072 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -1441,7 +1441,7 @@ class PackageManagerShellCommand extends ShellCommand {
out = session.openWrite(splitName, 0, sizeBytes);
int total = 0;
- byte[] buffer = new byte[65536];
+ byte[] buffer = new byte[1024 * 1024];
int c;
while ((c = in.read(buffer)) != -1) {
total += c;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index a806af46d021..1d7f66f54faf 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3627,10 +3627,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return -1;
}
- // If the device is in Vr mode, drop the volume keys and don't
- // forward it to the application/dispatch the audio event.
+ // If the device is in VR mode and keys are "internal" (e.g. on the side of the
+ // device), then drop the volume keys and don't forward it to the application/dispatch
+ // the audio event.
if (mPersistentVrModeEnabled) {
- return -1;
+ final InputDevice d = event.getDevice();
+ if (d != null && !d.isExternal()) {
+ return -1;
+ }
}
} else if (keyCode == KeyEvent.KEYCODE_TAB && event.isMetaPressed()) {
// Pass through keyboard navigation keys.
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 38dc33fa4dbc..f10bf1a3ffb5 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -97,12 +97,58 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
int what2;
IBinder token;
+ public DisableRecord(int userId, IBinder token) {
+ this.userId = userId;
+ this.token = token;
+ try {
+ token.linkToDeath(this, 0);
+ } catch (RemoteException re) {
+ // Give up
+ }
+ }
+
+ @Override
public void binderDied() {
Slog.i(TAG, "binder died for pkg=" + pkg);
disableForUser(0, token, pkg, userId);
disable2ForUser(0, token, pkg, userId);
token.unlinkToDeath(this, 0);
}
+
+ public void setFlags(int what, int which, String pkg) {
+ switch (which) {
+ case 1:
+ what1 = what;
+ return;
+ case 2:
+ what2 = what;
+ return;
+ default:
+ Slog.w(TAG, "Can't set unsupported disable flag " + which
+ + ": 0x" + Integer.toHexString(what));
+ }
+ this.pkg = pkg;
+ }
+
+ public int getFlags(int which) {
+ switch (which) {
+ case 1: return what1;
+ case 2: return what2;
+ default:
+ Slog.w(TAG, "Can't get unsupported disable flag " + which);
+ return 0;
+ }
+ }
+
+ public boolean isEmpty() {
+ return what1 == 0 && what2 == 0;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("userId=%d what1=0x%08X what2=0x%08X pkg=%s token=%s",
+ userId, what1, what2, pkg, token);
+ }
}
/**
@@ -970,42 +1016,42 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
Slog.d(TAG, "manageDisableList userId=" + userId
+ " what=0x" + Integer.toHexString(what) + " pkg=" + pkg);
}
- // update the list
+
+ // Find matching record, if any
final int N = mDisableRecords.size();
- DisableRecord tok = null;
+ DisableRecord record = null;
int i;
- for (i=0; i<N; i++) {
- DisableRecord t = mDisableRecords.get(i);
- if (t.token == token && t.userId == userId) {
- tok = t;
+ for (i = 0; i < N; i++) {
+ DisableRecord r = mDisableRecords.get(i);
+ if (r.token == token && r.userId == userId) {
+ record = r;
break;
}
}
- if (what == 0 || !token.isBinderAlive()) {
- if (tok != null) {
+
+ // Remove record if binder is already dead
+ if (!token.isBinderAlive()) {
+ if (record != null) {
mDisableRecords.remove(i);
- tok.token.unlinkToDeath(tok, 0);
- }
- } else {
- if (tok == null) {
- tok = new DisableRecord();
- tok.userId = userId;
- try {
- token.linkToDeath(tok, 0);
- }
- catch (RemoteException ex) {
- return; // give up
- }
- mDisableRecords.add(tok);
+ record.token.unlinkToDeath(record, 0);
}
- if (which == 1) {
- tok.what1 = what;
- } else {
- tok.what2 = what;
+ return;
+ }
+
+ // Update existing record
+ if (record != null) {
+ record.setFlags(what, which, pkg);
+ if (record.isEmpty()) {
+ mDisableRecords.remove(i);
+ record.token.unlinkToDeath(record, 0);
}
- tok.token = token;
- tok.pkg = pkg;
+ return;
}
+
+ // Record doesn't exist, so we create a new one
+ record = new DisableRecord(userId, token);
+ record.setFlags(what, which, pkg);
+ mDisableRecords.add(record);
}
// lock on mDisableRecords
@@ -1016,7 +1062,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
for (int i=0; i<N; i++) {
final DisableRecord rec = mDisableRecords.get(i);
if (rec.userId == userId) {
- net |= (which == 1) ? rec.what1 : rec.what2;
+ net |= rec.getFlags(which);
}
}
return net;
@@ -1036,11 +1082,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
pw.println(" mDisableRecords.size=" + N);
for (int i=0; i<N; i++) {
DisableRecord tok = mDisableRecords.get(i);
- pw.println(" [" + i + "] userId=" + tok.userId
- + " what1=0x" + Integer.toHexString(tok.what1)
- + " what2=0x" + Integer.toHexString(tok.what2)
- + " pkg=" + tok.pkg
- + " token=" + tok.token);
+ pw.println(" [" + i + "] " + tok);
}
pw.println(" mCurrentUserId=" + mCurrentUserId);
pw.println(" mIcons=");
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index ea2f305989fe..2d1fc912fcfc 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -53,6 +53,7 @@ import static com.android.server.wm.WindowManagerService.logWithStack;
import static com.android.server.wm.proto.AppWindowTokenProto.NAME;
import static com.android.server.wm.proto.AppWindowTokenProto.WINDOW_TOKEN;
+import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.app.Activity;
import android.content.res.Configuration;
@@ -1620,8 +1621,9 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
}
}
+ @CallSuper
@Override
- void writeToProto(ProtoOutputStream proto, long fieldId) {
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
writeNameToProto(proto, NAME);
super.writeToProto(proto, WINDOW_TOKEN);
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 28ba9b3db777..1da94da1b3b6 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -24,9 +24,14 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.activityTypeToString;
+import static com.android.server.wm.proto.ConfigurationContainerProto.FULL_CONFIGURATION;
+import static com.android.server.wm.proto.ConfigurationContainerProto.MERGED_OVERRIDE_CONFIGURATION;
+import static com.android.server.wm.proto.ConfigurationContainerProto.OVERRIDE_CONFIGURATION;
+import android.annotation.CallSuper;
import android.app.WindowConfiguration;
import android.content.res.Configuration;
+import android.util.proto.ProtoOutputStream;
import java.util.ArrayList;
@@ -252,6 +257,24 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
}
}
+ /**
+ * Write to a protocol buffer output stream. Protocol buffer message definition is at
+ * {@link com.android.server.wm.proto.ConfigurationContainerProto}.
+ *
+ * @param protoOutputStream Stream to write the ConfigurationContainer object to.
+ * @param fieldId Field Id of the ConfigurationContainer as defined in the parent
+ * message.
+ * @hide
+ */
+ @CallSuper
+ public void writeToProto(ProtoOutputStream protoOutputStream, long fieldId) {
+ final long token = protoOutputStream.start(fieldId);
+ mOverrideConfiguration.writeToProto(protoOutputStream, OVERRIDE_CONFIGURATION);
+ mFullConfiguration.writeToProto(protoOutputStream, FULL_CONFIGURATION);
+ mMergedOverrideConfiguration.writeToProto(protoOutputStream, MERGED_OVERRIDE_CONFIGURATION);
+ protoOutputStream.end(token);
+ }
+
abstract protected int getChildCount();
abstract protected E getChildAt(int index);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 6cf608ab0591..817a01c5c8d7 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -112,7 +112,9 @@ import static com.android.server.wm.proto.DisplayProto.PINNED_STACK_CONTROLLER;
import static com.android.server.wm.proto.DisplayProto.ROTATION;
import static com.android.server.wm.proto.DisplayProto.SCREEN_ROTATION_ANIMATION;
import static com.android.server.wm.proto.DisplayProto.STACKS;
+import static com.android.server.wm.proto.DisplayProto.WINDOW_CONTAINER;
+import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.app.ActivityManager.StackId;
import android.app.WindowConfiguration;
@@ -2119,8 +2121,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
}
- void writeToProto(ProtoOutputStream proto, long fieldId) {
+ @CallSuper
+ @Override
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
+ super.writeToProto(proto, WINDOW_CONTAINER);
proto.write(ID, mDisplayId);
for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
final TaskStack stack = mTaskStackContainers.get(stackNdx);
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 8a749762f993..227e4b2b59af 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import android.annotation.CallSuper;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.hardware.power.V1_0.PowerHint;
@@ -89,8 +90,9 @@ import static com.android.server.wm.WindowSurfacePlacer.SET_TURN_ON_SCREEN;
import static com.android.server.wm.WindowSurfacePlacer.SET_UPDATE_ROTATION;
import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_ACTION_PENDING;
import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE;
-import static com.android.server.wm.proto.WindowManagerServiceProto.DISPLAYS;
-import static com.android.server.wm.proto.WindowManagerServiceProto.WINDOWS;
+import static com.android.server.wm.proto.RootWindowContainerProto.DISPLAYS;
+import static com.android.server.wm.proto.RootWindowContainerProto.WINDOWS;
+import static com.android.server.wm.proto.RootWindowContainerProto.WINDOW_CONTAINER;
/** Root {@link WindowContainer} for the device. */
class RootWindowContainer extends WindowContainer<DisplayContent> {
@@ -1077,7 +1079,11 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {
}
}
- void writeToProto(ProtoOutputStream proto) {
+ @CallSuper
+ @Override
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ super.writeToProto(proto, WINDOW_CONTAINER);
if (mService.mDisplayReady) {
final int count = mChildren.size();
for (int i = 0; i < count; ++i) {
@@ -1088,6 +1094,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {
forAllWindows((w) -> {
w.writeIdentifierToProto(proto, WINDOWS);
}, true);
+ proto.end(token);
}
@Override
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 55b6c912ef90..7464a9b92d40 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -34,7 +34,9 @@ import static com.android.server.wm.proto.TaskProto.BOUNDS;
import static com.android.server.wm.proto.TaskProto.FILLS_PARENT;
import static com.android.server.wm.proto.TaskProto.ID;
import static com.android.server.wm.proto.TaskProto.TEMP_INSET_BOUNDS;
+import static com.android.server.wm.proto.TaskProto.WINDOW_CONTAINER;
+import android.annotation.CallSuper;
import android.app.ActivityManager.StackId;
import android.app.ActivityManager.TaskDescription;
import android.content.pm.ActivityInfo;
@@ -735,8 +737,11 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
return "Task=" + mTaskId;
}
- void writeToProto(ProtoOutputStream proto, long fieldId) {
+ @CallSuper
+ @Override
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
+ super.writeToProto(proto, WINDOW_CONTAINER);
proto.write(ID, mTaskId);
for (int i = mChildren.size() - 1; i >= 0; i--) {
final AppWindowToken appWindowToken = mChildren.get(i);
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 4664dcbbfa75..126d820e69b6 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -41,7 +41,9 @@ import static com.android.server.wm.proto.StackProto.BOUNDS;
import static com.android.server.wm.proto.StackProto.FILLS_PARENT;
import static com.android.server.wm.proto.StackProto.ID;
import static com.android.server.wm.proto.StackProto.TASKS;
+import static com.android.server.wm.proto.StackProto.WINDOW_CONTAINER;
+import android.annotation.CallSuper;
import android.app.ActivityManager.StackId;
import android.content.res.Configuration;
import android.graphics.Rect;
@@ -1219,8 +1221,11 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
return mMinimizeAmount != 0f;
}
- void writeToProto(ProtoOutputStream proto, long fieldId) {
+ @CallSuper
+ @Override
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
+ super.writeToProto(proto, WINDOW_CONTAINER);
proto.write(ID, mStackId);
for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; taskNdx--) {
mChildren.get(taskNdx).writeToProto(proto, TASKS);
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 926719ddf318..40923c8216c0 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -19,12 +19,14 @@ package com.android.server.wm;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static android.content.res.Configuration.EMPTY;
+import static com.android.server.wm.proto.WindowContainerProto.CONFIGURATION_CONTAINER;
+import static com.android.server.wm.proto.WindowContainerProto.ORIENTATION;
import android.annotation.CallSuper;
import android.content.res.Configuration;
import android.util.Pools;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.util.ToBooleanFunction;
import java.util.Comparator;
@@ -685,6 +687,23 @@ a * Returns whether this child is on top of the window hierarchy.
}
}
+ /**
+ * Write to a protocol buffer output stream. Protocol buffer message definition is at
+ * {@link com.android.server.wm.proto.WindowContainerProto}.
+ *
+ * @param protoOutputStream Stream to write the WindowContainer object to.
+ * @param fieldId Field Id of the WindowContainer as defined in the parent message.
+ * @hide
+ */
+ @CallSuper
+ @Override
+ public void writeToProto(ProtoOutputStream protoOutputStream, long fieldId) {
+ final long token = protoOutputStream.start(fieldId);
+ super.writeToProto(protoOutputStream, CONFIGURATION_CONTAINER);
+ protoOutputStream.write(ORIENTATION, mOrientation);
+ protoOutputStream.end(token);
+ }
+
String getName() {
return toString();
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 32ee51c8f751..6f796481cc08 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -109,6 +109,7 @@ import static com.android.server.wm.proto.WindowManagerServiceProto.FOCUSED_WIND
import static com.android.server.wm.proto.WindowManagerServiceProto.INPUT_METHOD_WINDOW;
import static com.android.server.wm.proto.WindowManagerServiceProto.LAST_ORIENTATION;
import static com.android.server.wm.proto.WindowManagerServiceProto.POLICY;
+import static com.android.server.wm.proto.WindowManagerServiceProto.ROOT_WINDOW_CONTAINER;
import static com.android.server.wm.proto.WindowManagerServiceProto.ROTATION;
import android.Manifest;
@@ -6505,7 +6506,7 @@ public class WindowManagerService extends IWindowManager.Stub
private void writeToProtoLocked(ProtoOutputStream proto) {
mPolicy.writeToProto(proto, POLICY);
- mRoot.writeToProto(proto);
+ mRoot.writeToProto(proto, ROOT_WINDOW_CONTAINER);
if (mCurrentFocus != null) {
mCurrentFocus.writeIdentifierToProto(proto, FOCUSED_WINDOW);
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 1b055664093f..8a2cb5a148d8 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -116,7 +116,9 @@ import static com.android.server.wm.proto.WindowStateProto.IDENTIFIER;
import static com.android.server.wm.proto.WindowStateProto.PARENT_FRAME;
import static com.android.server.wm.proto.WindowStateProto.STACK_ID;
import static com.android.server.wm.proto.WindowStateProto.SURFACE_INSETS;
+import static com.android.server.wm.proto.WindowStateProto.WINDOW_CONTAINER;
+import android.annotation.CallSuper;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.res.Configuration;
@@ -3124,8 +3126,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|| (isChildWindow() && getParentWindow().isDockedResizing());
}
- void writeToProto(ProtoOutputStream proto, long fieldId) {
+ @CallSuper
+ @Override
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
+ super.writeToProto(proto, WINDOW_CONTAINER);
writeIdentifierToProto(proto, IDENTIFIER);
proto.write(DISPLAY_ID, getDisplayId());
proto.write(STACK_ID, getStackId());
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 422615b10fc1..943448eea2b0 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import android.annotation.CallSuper;
import android.util.proto.ProtoOutputStream;
import java.util.Comparator;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
@@ -28,6 +29,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import static com.android.server.wm.proto.WindowTokenProto.HASH_CODE;
import static com.android.server.wm.proto.WindowTokenProto.WINDOWS;
+import static com.android.server.wm.proto.WindowTokenProto.WINDOW_CONTAINER;
import android.os.Debug;
import android.os.IBinder;
@@ -263,8 +265,11 @@ class WindowToken extends WindowContainer<WindowState> {
super.onDisplayChanged(dc);
}
- void writeToProto(ProtoOutputStream proto, long fieldId) {
+ @CallSuper
+ @Override
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
+ super.writeToProto(proto, WINDOW_CONTAINER);
proto.write(HASH_CODE, System.identityHashCode(this));
for (int i = 0; i < mChildren.size(); i++) {
final WindowState w = mChildren.get(i);
diff --git a/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java b/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java
index e98e5bfb110e..f9d7f9d4904a 100644
--- a/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java
@@ -20,19 +20,13 @@ import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
import static android.os.Process.SYSTEM_UID;
+
import static com.android.server.am.LockTaskController.STATUS_BAR_MASK_LOCKED;
import static com.android.server.am.LockTaskController.STATUS_BAR_MASK_PINNED;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
+
+import static org.junit.Assert.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
import android.app.StatusBarManager;
import android.app.admin.IDevicePolicyManager;
@@ -72,7 +66,8 @@ import org.mockito.verification.VerificationMode;
@SmallTest
public class LockTaskControllerTest {
private static final String TEST_PACKAGE_NAME = "com.test.package";
- private static final String TEST_CLASS_NAME = TEST_PACKAGE_NAME + ".TestClass";
+ private static final String TEST_PACKAGE_NAME_2 = "com.test.package2";
+ private static final String TEST_CLASS_NAME = ".TestClass";
private static final int TEST_USER_ID = 123;
private static final int TEST_UID = 10467;
@@ -309,15 +304,111 @@ public class LockTaskControllerTest {
verify(mLockPatternUtils).requireCredentialEntry(UserHandle.USER_ALL);
}
+ @Test
+ public void testUpdateLockTaskPackages() throws Exception {
+ String[] whitelist1 = {TEST_PACKAGE_NAME, TEST_PACKAGE_NAME_2};
+ String[] whitelist2 = {TEST_PACKAGE_NAME};
+
+ // No package is whitelisted initially
+ for (String pkg : whitelist1) {
+ assertFalse("Package shouldn't be whitelisted: " + pkg,
+ mLockTaskController.isPackageWhitelisted(TEST_USER_ID, pkg));
+ assertFalse("Package shouldn't be whitelisted for user 0: " + pkg,
+ mLockTaskController.isPackageWhitelisted(0, pkg));
+ }
+
+ // Apply whitelist
+ mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist1);
+
+ // Assert the whitelist is applied to the correct user
+ for (String pkg : whitelist1) {
+ assertTrue("Package should be whitelisted: " + pkg,
+ mLockTaskController.isPackageWhitelisted(TEST_USER_ID, pkg));
+ assertFalse("Package shouldn't be whitelisted for user 0: " + pkg,
+ mLockTaskController.isPackageWhitelisted(0, pkg));
+ }
+
+ // Update whitelist
+ mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist2);
+
+ // Assert the new whitelist is applied
+ assertTrue("Package should remain whitelisted: " + TEST_PACKAGE_NAME,
+ mLockTaskController.isPackageWhitelisted(TEST_USER_ID, TEST_PACKAGE_NAME));
+ assertFalse("Package should no longer be whitelisted: " + TEST_PACKAGE_NAME_2,
+ mLockTaskController.isPackageWhitelisted(TEST_USER_ID, TEST_PACKAGE_NAME_2));
+ }
+
+ @Test
+ public void testUpdateLockTaskPackages_taskRemoved() throws Exception {
+ // GIVEN two tasks which are whitelisted initially
+ TaskRecord tr1 = getTaskRecordForUpdate(TEST_PACKAGE_NAME, true);
+ TaskRecord tr2 = getTaskRecordForUpdate(TEST_PACKAGE_NAME_2, false);
+ String[] whitelist = {TEST_PACKAGE_NAME, TEST_PACKAGE_NAME_2};
+ mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist);
+
+ // GIVEN the tasks are launched into LockTask mode
+ mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
+ mLockTaskController.startLockTaskMode(tr2, false, TEST_UID);
+ assertEquals(LOCK_TASK_MODE_LOCKED, mLockTaskController.getLockTaskModeState());
+ assertTrue(mLockTaskController.checkLockedTask(tr1));
+ assertTrue(mLockTaskController.checkLockedTask(tr2));
+ verifyLockTaskStarted(STATUS_BAR_MASK_LOCKED);
+
+ // WHEN removing one package from whitelist
+ whitelist = new String[] {TEST_PACKAGE_NAME};
+ mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist);
+
+ // THEN the task running that package should be stopped
+ verify(tr2).performClearTaskLocked();
+ assertFalse(mLockTaskController.checkLockedTask(tr2));
+ // THEN the other task should remain locked
+ assertEquals(LOCK_TASK_MODE_LOCKED, mLockTaskController.getLockTaskModeState());
+ assertTrue(mLockTaskController.checkLockedTask(tr1));
+ verifyLockTaskStarted(STATUS_BAR_MASK_LOCKED);
+
+ // WHEN removing the last package from whitelist
+ whitelist = new String[] {};
+ mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist);
+
+ // THEN the last task should be cleared, and the system should quit LockTask mode
+ verify(tr1).performClearTaskLocked();
+ assertFalse(mLockTaskController.checkLockedTask(tr1));
+ assertEquals(LOCK_TASK_MODE_NONE, mLockTaskController.getLockTaskModeState());
+ verifyLockTaskStopped(times(1));
+ }
+
private TaskRecord getTaskRecord(int lockTaskAuth) {
+ return getTaskRecord(TEST_PACKAGE_NAME, lockTaskAuth);
+ }
+
+ private TaskRecord getTaskRecord(String pkg, int lockTaskAuth) {
TaskRecord tr = mock(TaskRecord.class);
tr.mLockTaskAuth = lockTaskAuth;
tr.intent = new Intent()
- .setComponent(new ComponentName(TEST_PACKAGE_NAME, TEST_CLASS_NAME));
+ .setComponent(ComponentName.createRelative(pkg, TEST_CLASS_NAME));
tr.userId = TEST_USER_ID;
return tr;
}
+ /**
+ * @param isAppAware {@code true} if the app has marked if_whitelisted in its manifest
+ */
+ private TaskRecord getTaskRecordForUpdate(String pkg, boolean isAppAware) {
+ final int authIfWhitelisted = isAppAware
+ ? TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE
+ : TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
+ TaskRecord tr = getTaskRecord(pkg, authIfWhitelisted);
+ doAnswer((invocation) -> {
+ boolean isWhitelisted =
+ mLockTaskController.isPackageWhitelisted(TEST_USER_ID, pkg);
+ tr.mLockTaskAuth = isWhitelisted
+ ? authIfWhitelisted
+ : TaskRecord.LOCK_TASK_AUTH_PINNABLE;
+ return null;
+ }).when(tr).setLockTaskAuth();
+ return tr;
+ }
+
private void verifyLockTaskStarted(int statusBarMask) throws Exception {
// THEN the keyguard should have been disabled
verify(mWindowManager).disableKeyguard(any(IBinder.class), anyString());