Merge "Use display windowing mode if undefined" into rvc-dev
diff --git a/api/test-current.txt b/api/test-current.txt
index 4eeaaf87..03f4dc5 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -3522,6 +3522,32 @@
}
+package android.service.watchdog {
+
+ public abstract class ExplicitHealthCheckService extends android.app.Service {
+ ctor public ExplicitHealthCheckService();
+ method public final void notifyHealthCheckPassed(@NonNull String);
+ method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
+ method public abstract void onCancelHealthCheck(@NonNull String);
+ method @NonNull public abstract java.util.List<java.lang.String> onGetRequestedPackages();
+ method @NonNull public abstract java.util.List<android.service.watchdog.ExplicitHealthCheckService.PackageConfig> onGetSupportedPackages();
+ method public abstract void onRequestHealthCheck(@NonNull String);
+ method public void setCallback(@Nullable android.os.RemoteCallback);
+ field public static final String BIND_PERMISSION = "android.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE";
+ field public static final String SERVICE_INTERFACE = "android.service.watchdog.ExplicitHealthCheckService";
+ }
+
+ public static final class ExplicitHealthCheckService.PackageConfig implements android.os.Parcelable {
+ ctor public ExplicitHealthCheckService.PackageConfig(@NonNull String, long);
+ method public int describeContents();
+ method public long getHealthCheckTimeoutMillis();
+ method @NonNull public String getPackageName();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.service.watchdog.ExplicitHealthCheckService.PackageConfig> CREATOR;
+ }
+
+}
+
package android.telecom {
public final class Call {
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index c7dbf77..bd15264 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -8697,13 +8697,12 @@
// Name of the package accessing app op
optional string package_name = 2;
- // operation string id per OPSTR_ constants in AppOpsManager.java
- optional string op = 3;
+ // deprecated - set to empty string
+ optional string op_deprecated = 3 [deprecated = true];
// attribution_tag; provided by developer when accessing related API, limited at 50 chars by
- // API.
- // Attributions must be provided through manifest using <attribution> tag available in R and
- // above.
+ // API. Attributions must be provided through manifest using <attribution> tag available in R
+ // and above.
optional string attribution_tag = 4;
// message related to app op access, limited to 600 chars by API
@@ -8718,6 +8717,9 @@
// sampling strategy used to collect this message
optional SamplingStrategy sampling_strategy = 6;
+
+ // operation id
+ optional android.app.AppOpEnum op = 7 [default = APP_OP_NONE];
}
/*
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 9c1fb41..b7fb280 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -1195,18 +1195,24 @@
/**
* Remove all rows that match one of specified UIDs.
+ * This mutates the original structure in place.
* @hide
*/
public void removeUids(int[] uids) {
- int nextOutputEntry = 0;
- for (int i = 0; i < size; i++) {
- if (!ArrayUtils.contains(uids, uid[i])) {
- maybeCopyEntry(nextOutputEntry, i);
- nextOutputEntry++;
- }
- }
+ filter(e -> !ArrayUtils.contains(uids, e.uid));
+ }
- size = nextOutputEntry;
+ /**
+ * Remove all rows that match one of specified UIDs.
+ * @return the result object.
+ * @hide
+ */
+ @NonNull
+ public NetworkStats removeEmptyEntries() {
+ final NetworkStats ret = this.clone();
+ ret.filter(e -> e.rxBytes != 0 || e.rxPackets != 0 || e.txBytes != 0 || e.txPackets != 0
+ || e.operations != 0);
+ return ret;
}
/**
diff --git a/core/java/android/service/watchdog/ExplicitHealthCheckService.java b/core/java/android/service/watchdog/ExplicitHealthCheckService.java
index 9950143..b1647fe 100644
--- a/core/java/android/service/watchdog/ExplicitHealthCheckService.java
+++ b/core/java/android/service/watchdog/ExplicitHealthCheckService.java
@@ -21,7 +21,9 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.app.Service;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -64,6 +66,7 @@
* </pre>
* @hide
*/
+@TestApi
@SystemApi
public abstract class ExplicitHealthCheckService extends Service {
@@ -159,6 +162,15 @@
}
/**
+ * Sets {@link RemoteCallback}, for testing purpose.
+ *
+ * @hide
+ */
+ @TestApi
+ public void setCallback(@Nullable RemoteCallback callback) {
+ mCallback = callback;
+ }
+ /**
* Implementors should call this to notify the system when explicit health check passes
* for {@code packageName};
*/
@@ -183,6 +195,7 @@
*
* @hide
*/
+ @TestApi
@SystemApi
public static final class PackageConfig implements Parcelable {
private static final long DEFAULT_HEALTH_CHECK_TIMEOUT_MILLIS = TimeUnit.HOURS.toMillis(1);
@@ -263,7 +276,7 @@
}
@Override
- public void writeToParcel(Parcel parcel, int flags) {
+ public void writeToParcel(@SuppressLint({"MissingNullability"}) Parcel parcel, int flags) {
parcel.writeString(mPackageName);
parcel.writeLong(mHealthCheckTimeoutMillis);
}
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index b753704..07cf415 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -25,6 +25,12 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
+ "-2101985723": {
+ "message": "Failed looking up window session=%s callers=%s",
+ "level": "WARN",
+ "group": "WM_ERROR",
+ "at": "com\/android\/server\/wm\/WindowManagerService.java"
+ },
"-2072089308": {
"message": "Attempted to add window with token that is a sub-window: %s. Aborting.",
"level": "WARN",
@@ -655,12 +661,6 @@
"group": "WM_DEBUG_SCREEN_ON",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "-747671114": {
- "message": "Failed looking up window callers=%s",
- "level": "WARN",
- "group": "WM_ERROR",
- "at": "com\/android\/server\/wm\/WindowManagerService.java"
- },
"-714291355": {
"message": "Losing delayed focus: %s",
"level": "INFO",
diff --git a/packages/SystemUI/res-keyguard/values-ky/strings.xml b/packages/SystemUI/res-keyguard/values-ky/strings.xml
index 022726e..d956a79 100644
--- a/packages/SystemUI/res-keyguard/values-ky/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ky/strings.xml
@@ -98,7 +98,7 @@
<string name="kg_password_pin_failed" msgid="5136259126330604009">"SIM-картанын PIN-кодун ачуу кыйрады!"</string>
<string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM-картанын PUK-кодун ачуу кыйрады!"</string>
<string name="kg_pin_accepted" msgid="1625501841604389716">"Код кабыл алынды!"</string>
- <string name="keyguard_carrier_default" msgid="6359808469637388586">"Байланыш жок."</string>
+ <string name="keyguard_carrier_default" msgid="6359808469637388586">"Интернет жок."</string>
<string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Киргизүү ыкмасын өзгөртүү"</string>
<string name="airplane_mode" msgid="2528005343938497866">"Учак режими"</string>
<string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Жаңыртууга даярдоо үчүн PIN код талап кылынат"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pl/strings.xml b/packages/SystemUI/res-keyguard/values-pl/strings.xml
index 34633d3..5f1df3e 100644
--- a/packages/SystemUI/res-keyguard/values-pl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pl/strings.xml
@@ -54,7 +54,7 @@
<string name="keyguard_accessibility_sim_pin_area" msgid="6272116591533888062">"Miejsce na kod PIN karty SIM"</string>
<string name="keyguard_accessibility_sim_puk_area" msgid="5537294043180237374">"Miejsce na kod PUK karty SIM"</string>
<string name="keyguard_accessibility_next_alarm" msgid="4492876946798984630">"Następny alarm ustawiony na: <xliff:g id="ALARM">%1$s</xliff:g>"</string>
- <string name="keyboardview_keycode_delete" msgid="8489719929424895174">"Usuwanie"</string>
+ <string name="keyboardview_keycode_delete" msgid="8489719929424895174">"Usuń"</string>
<string name="disable_carrier_button_text" msgid="7153361131709275746">"Wyłącz eSIM"</string>
<string name="error_disable_esim_title" msgid="3802652622784813119">"Nie można wyłączyć karty eSIM"</string>
<string name="error_disable_esim_msg" msgid="2441188596467999327">"Nie można wyłączyć karty eSIM z powodu błędu."</string>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 6fd3bb2..4462c72 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -26,6 +26,7 @@
import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NAV_BAR_HANDLE_FORCE_OPAQUE;
import static com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
@@ -56,6 +57,8 @@
import android.content.res.Configuration;
import android.database.ContentObserver;
import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.hardware.display.DisplayManager;
import android.inputmethodservice.InputMethodService;
import android.net.Uri;
import android.os.Binder;
@@ -71,6 +74,7 @@
import android.text.TextUtils;
import android.util.Log;
import android.view.Display;
+import android.view.Gravity;
import android.view.InsetsState.InternalInsetsType;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -104,6 +108,7 @@
import com.android.systemui.recents.Recents;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
+import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.AutoHideUiElement;
import com.android.systemui.statusbar.CommandQueue;
@@ -133,7 +138,7 @@
* on clicks and view states of the nav bar.
*/
public class NavigationBarFragment extends LifecycleFragment implements Callbacks,
- NavigationModeController.ModeChangedListener {
+ NavigationModeController.ModeChangedListener, DisplayManager.DisplayListener {
public static final String TAG = "NavigationBar";
private static final boolean DEBUG = false;
@@ -141,6 +146,8 @@
private static final String EXTRA_DISABLE2_STATE = "disabled2_state";
private static final String EXTRA_APPEARANCE = "appearance";
private static final String EXTRA_TRANSIENT_STATE = "transient_state";
+ private static final String FIXED_ROTATION_TRANSFORM_SETTING_NAME = "fixed_rotation_transform";
+
/** Allow some time inbetween the long press for back and recents. */
private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200;
@@ -199,6 +206,23 @@
private boolean mIsOnDefaultDisplay;
public boolean mHomeBlockedThisTouch;
+ /**
+ * When user is QuickSwitching between apps of different orientations, we'll draw a fake
+ * home handle on the orientation they originally touched down to start their swipe
+ * gesture to indicate to them that they can continue in that orientation without having to
+ * rotate the phone
+ * The secondary handle will show when we get
+ * {@link OverviewProxyListener#onQuickSwitchToNewTask(int)} callback with the
+ * original handle hidden and we'll flip the visibilities once the
+ * {@link #mTasksFrozenListener} fires
+ */
+ private NavigationHandle mOrientationHandle;
+ private WindowManager.LayoutParams mOrientationParams;
+ private boolean mFrozenTasks;
+ private int mStartingQuickSwitchRotation;
+ private int mCurrentRotation;
+ private boolean mFixedRotationEnabled;
+
/** Only for default display */
@Nullable
private AssistHandleViewController mAssistHandlerViewController;
@@ -249,6 +273,12 @@
}
@Override
+ public void onQuickSwitchToNewTask(@Surface.Rotation int rotation) {
+ mStartingQuickSwitchRotation = rotation;
+ orientSecondaryHomeHandle();
+ }
+
+ @Override
public void startAssistant(Bundle bundle) {
mAssistManager.startAssist(bundle);
}
@@ -271,6 +301,22 @@
}
};
+ private TaskStackChangeListener mTasksFrozenListener = new TaskStackChangeListener() {
+ @Override
+ public void onRecentTaskListFrozenChanged(boolean frozen) {
+ mFrozenTasks = frozen;
+ orientSecondaryHomeHandle();
+ }
+ };
+
+ private NavigationBarTransitions.DarkIntensityListener mOrientationHandleIntensityListener =
+ new NavigationBarTransitions.DarkIntensityListener() {
+ @Override
+ public void onDarkIntensity(float darkIntensity) {
+ mOrientationHandle.setDarkIntensity(darkIntensity);
+ }
+ };
+
private final ContextButtonListener mRotationButtonListener = (button, visible) -> {
if (visible) {
// If the button will actually become visible and the navbar is about to hide,
@@ -294,6 +340,14 @@
}
};
+ private final ContentObserver mFixedRotationObserver = new ContentObserver(
+ new Handler(Looper.getMainLooper())) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ updatedFixedRotation();
+ }
+ };
+
private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener =
new DeviceConfig.OnPropertiesChangedListener() {
@Override
@@ -351,6 +405,10 @@
Settings.Secure.getUriFor(Settings.Secure.ASSISTANT),
false /* notifyForDescendants */, mAssistContentObserver, UserHandle.USER_ALL);
+ mContentResolver.registerContentObserver(
+ Settings.Global.getUriFor(FIXED_ROTATION_TRANSFORM_SETTING_NAME),
+ false /* notifyForDescendants */, mFixedRotationObserver, UserHandle.USER_ALL);
+
if (savedInstanceState != null) {
mDisabledFlags1 = savedInstanceState.getInt(EXTRA_DISABLE_STATE, 0);
mDisabledFlags2 = savedInstanceState.getInt(EXTRA_DISABLE2_STATE, 0);
@@ -376,6 +434,7 @@
mNavigationModeController.removeListener(this);
mAccessibilityManagerWrapper.removeCallback(mAccessibilityListener);
mContentResolver.unregisterContentObserver(mAssistContentObserver);
+ mContentResolver.unregisterContentObserver(mFixedRotationObserver);
DeviceConfig.removeOnPropertiesChangedListener(mOnPropertiesChangedListener);
}
@@ -406,6 +465,7 @@
}
mNavigationBarView.setNavigationIconHints(mNavigationIconHints);
mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
+ updatedFixedRotation();
prepareNavigationBarView();
checkNavBarModes();
@@ -442,6 +502,9 @@
new AssistHandleViewController(mHandler, mNavigationBarView);
getBarTransitions().addDarkIntensityListener(mAssistHandlerViewController);
}
+
+ initSecondaryHomeHandleForRotation();
+ ActivityManagerWrapper.getInstance().registerTaskStackListener(mTasksFrozenListener);
}
@Override
@@ -458,6 +521,13 @@
}
mOverviewProxyService.removeCallback(mOverviewProxyListener);
mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver);
+ ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTasksFrozenListener);
+ if (mOrientationHandle != null) {
+ resetSecondaryHandle();
+ getContext().getSystemService(DisplayManager.class).unregisterDisplayListener(this);
+ getBarTransitions().removeDarkIntensityListener(mOrientationHandleIntensityListener);
+ mWindowManager.removeView(mOrientationHandle);
+ }
}
@Override
@@ -490,6 +560,88 @@
repositionNavigationBar();
}
+ private void initSecondaryHomeHandleForRotation() {
+ if (!canShowSecondaryHandle()) {
+ return;
+ }
+
+ getContext().getSystemService(DisplayManager.class)
+ .registerDisplayListener(this, new Handler(Looper.getMainLooper()));
+
+ mOrientationHandle = new VerticalNavigationHandle(getContext());
+
+ getBarTransitions().addDarkIntensityListener(mOrientationHandleIntensityListener);
+ mOrientationParams = new WindowManager.LayoutParams(0, 0,
+ WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
+ | WindowManager.LayoutParams.FLAG_SLIPPERY,
+ PixelFormat.TRANSLUCENT);
+ mWindowManager.addView(mOrientationHandle, mOrientationParams);
+ mOrientationHandle.setVisibility(View.GONE);
+ }
+
+ private void orientSecondaryHomeHandle() {
+ if (!canShowSecondaryHandle()) {
+ return;
+ }
+
+ if (!mFrozenTasks) {
+ resetSecondaryHandle();
+ } else {
+ int deltaRotation = deltaRotation(mCurrentRotation, mStartingQuickSwitchRotation);
+ int height = 0;
+ int width = 0;
+ Rect dispSize = mWindowManager.getCurrentWindowMetrics().getBounds();
+ switch (deltaRotation) {
+ case Surface.ROTATION_90:
+ case Surface.ROTATION_270:
+ height = dispSize.height();
+ width = getResources()
+ .getDimensionPixelSize(R.dimen.navigation_bar_height);
+ break;
+ case Surface.ROTATION_180:
+ case Surface.ROTATION_0:
+ // TODO(b/152683657): Need to determine best UX for this
+ resetSecondaryHandle();
+ return;
+ }
+
+ mOrientationParams.gravity =
+ deltaRotation == Surface.ROTATION_90 ? Gravity.LEFT : Gravity.RIGHT;
+ mOrientationParams.height = height;
+ mOrientationParams.width = width;
+ mWindowManager.updateViewLayout(mOrientationHandle, mOrientationParams);
+ mNavigationBarView.setVisibility(View.GONE);
+ mOrientationHandle.setVisibility(View.VISIBLE);
+ }
+ }
+
+ private void resetSecondaryHandle() {
+ if (mOrientationHandle != null) {
+ // Case where nav mode is changed w/o ever invoking a quickstep
+ // mOrientedHandle is initialized lazily
+ mOrientationHandle.setVisibility(View.GONE);
+ }
+ mNavigationBarView.setVisibility(View.VISIBLE);
+ }
+
+ private int deltaRotation(int oldRotation, int newRotation) {
+ int delta = newRotation - oldRotation;
+ if (delta < 0) delta += 4;
+ return delta;
+ }
+
+ private void updatedFixedRotation() {
+ mFixedRotationEnabled = Settings.Global.getInt(getContext().getContentResolver(),
+ FIXED_ROTATION_TRANSFORM_SETTING_NAME, 0) != 0;
+ if (!canShowSecondaryHandle()) {
+ resetSecondaryHandle();
+ }
+ }
+
@Override
public void dump(String prefix, FileDescriptor fd, PrintWriter pw, String[] args) {
if (mNavigationBarView != null) {
@@ -1112,6 +1264,10 @@
mNavBarMode = mode;
updateScreenPinningGestures();
+ if (!canShowSecondaryHandle()) {
+ resetSecondaryHandle();
+ }
+
// Workaround for b/132825155, for secondary users, we currently don't receive configuration
// changes on overlay package change since SystemUI runs for the system user. In this case,
// trigger a new configuration change to ensure that the nav bar is updated in the same way.
@@ -1156,6 +1312,34 @@
private final AccessibilityServicesStateChangeListener mAccessibilityListener =
this::updateAccessibilityServicesState;
+ @Override
+ public void onDisplayAdded(int displayId) {
+
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+
+ }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ if (!canShowSecondaryHandle()) {
+ return;
+ }
+
+ int rotation = getContext().getResources().getConfiguration()
+ .windowConfiguration.getRotation();
+ if (rotation != mCurrentRotation) {
+ mCurrentRotation = rotation;
+ orientSecondaryHomeHandle();
+ }
+ }
+
+ private boolean canShowSecondaryHandle() {
+ return mFixedRotationEnabled && mNavBarMode == NAV_BAR_MODE_GESTURAL;
+ }
+
private final Consumer<Integer> mRotationWatcher = rotation -> {
if (mNavigationBarView != null
&& mNavigationBarView.needsReorient(rotation)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java
index abceb11..b874795 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java
@@ -32,11 +32,11 @@
public class NavigationHandle extends View implements ButtonInterface {
- private final Paint mPaint = new Paint();
+ protected final Paint mPaint = new Paint();
private @ColorInt final int mLightColor;
private @ColorInt final int mDarkColor;
- private final int mRadius;
- private final int mBottom;
+ protected final int mRadius;
+ protected final int mBottom;
private boolean mRequiresInvalidate;
public NavigationHandle(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/VerticalNavigationHandle.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/VerticalNavigationHandle.java
new file mode 100644
index 0000000..a15ca95
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/VerticalNavigationHandle.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.graphics.Canvas;
+
+import com.android.systemui.R;
+
+/** Temporarily shown view when using QuickSwitch to switch between apps of different rotations */
+public class VerticalNavigationHandle extends NavigationHandle {
+ private final int mWidth;
+
+ public VerticalNavigationHandle(Context context) {
+ super(context);
+ mWidth = context.getResources().getDimensionPixelSize(R.dimen.navigation_home_handle_width);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ int left;
+ int top;
+ int bottom;
+ int right;
+
+ int radiusOffset = mRadius * 2;
+ right = getWidth() - mBottom;
+ top = getHeight() / 2 - (mWidth / 2); /* (height of screen / 2) - (height of bar / 2) */
+ left = getWidth() - mBottom - radiusOffset;
+ bottom = getHeight() / 2 + (mWidth / 2);
+ canvas.drawRoundRect(left, top, right, bottom, mRadius, mRadius, mPaint);
+ }
+}
diff --git a/packages/VpnDialogs/res/values-ky/strings.xml b/packages/VpnDialogs/res/values-ky/strings.xml
index 4e2f698..23c9be8 100644
--- a/packages/VpnDialogs/res/values-ky/strings.xml
+++ b/packages/VpnDialogs/res/values-ky/strings.xml
@@ -26,7 +26,7 @@
<string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> байт / <xliff:g id="NUMBER_1">%2$s</xliff:g> пакет"</string>
<string name="always_on_disconnected_title" msgid="1906740176262776166">"Ар дайым күйүк VPN\'ге туташа албай жатат"</string>
<string name="always_on_disconnected_message" msgid="555634519845992917">"<xliff:g id="VPN_APP_0">%1$s</xliff:g> тармагына ар дайым туташып турсун деп жөндөлгөн, бирок учурда телефонуңуз ага туташа албай жатат. <xliff:g id="VPN_APP_1">%1$s</xliff:g> тармагына кайра туташканга чейин телефонуңуз жалпыга ачык тармакты пайдаланып турат."</string>
- <string name="always_on_disconnected_message_lockdown" msgid="4232225539869452120">"<xliff:g id="VPN_APP">%1$s</xliff:g> тармагына ар дайым туташып турсун деп жөндөлгөн, бирок учурда телефонуңуз ага туташа албай жатат. VPN тармагына кайра туташмайынча, Интернет байланышыңыз жок болот."</string>
+ <string name="always_on_disconnected_message_lockdown" msgid="4232225539869452120">"<xliff:g id="VPN_APP">%1$s</xliff:g> тармагына ар дайым туташып турсун деп жөндөлгөн, бирок учурда телефонуңуз ага туташа албай жатат. VPN тармагына кайра туташмайынча, Интернет жок болот."</string>
<string name="always_on_disconnected_message_separator" msgid="3310614409322581371">" "</string>
<string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"VPN жөндөөлөрүн өзгөртүү"</string>
<string name="configure" msgid="4905518375574791375">"Конфигурациялоо"</string>
diff --git a/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values-ta/strings.xml b/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values-ta/strings.xml
new file mode 100644
index 0000000..c896ee3
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values-ta/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="display_cutout_emulation_overlay" msgid="7305489596221077240">"பஞ்ச் ஹோல் கட்அவுட்"</string>
+</resources>
diff --git a/services/core/java/android/os/UserManagerInternal.java b/services/core/java/android/os/UserManagerInternal.java
index aedafbb..94f5741 100644
--- a/services/core/java/android/os/UserManagerInternal.java
+++ b/services/core/java/android/os/UserManagerInternal.java
@@ -23,6 +23,8 @@
import android.content.pm.UserInfo;
import android.graphics.Bitmap;
+import com.android.server.pm.RestrictionsSet;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -57,21 +59,18 @@
* Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to set
* restrictions enforced by the user.
*
- * @param originatingUserId user id of the user where the restriction originated.
- * @param restrictions a bundle of user restrictions.
- * @param restrictionOwnerType determines which admin {@code userId} corresponds to.
- * The admin can be either
- * {@link UserManagerInternal#OWNER_TYPE_DEVICE_OWNER},
- * {@link UserManagerInternal#OWNER_TYPE_PROFILE_OWNER},
- * {@link UserManagerInternal#OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE}
- * or {@link UserManagerInternal#OWNER_TYPE_NO_OWNER}.
- * If the admin is a DEVICE_OWNER or a PROFILE_OWNER_ORG_OWNED_DEVICE then
- * a restriction may be applied globally depending on which restriction it is,
- * otherwise it will be applied just on the current user.
- * @see OwnerType
+ * @param originatingUserId user id of the user where the restrictions originated.
+ * @param global a bundle of global user restrictions. Global restrictions are
+ * restrictions that apply device-wide: to the managed profile,
+ * primary profile and secondary users and any profile created in
+ * any secondary user.
+ * @param local a restriction set of local user restrictions. The key is the user
+ * id of the user whom the restrictions are targeting.
+ * @param isDeviceOwner whether {@code originatingUserId} corresponds to device owner
+ * user id.
*/
public abstract void setDevicePolicyUserRestrictions(int originatingUserId,
- @Nullable Bundle restrictions, @OwnerType int restrictionOwnerType);
+ @Nullable Bundle global, @Nullable RestrictionsSet local, boolean isDeviceOwner);
/**
* Returns the "base" user restrictions.
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 8e6ef75..31bccea 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -5853,10 +5853,6 @@
if (pkg == null) {
return false;
}
- if (pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.Q) {
- return false;
- }
-
String[] requestedPermissions = pkg.requestedPermissions;
if (requestedPermissions == null) {
return false;
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index d2443fa..323ffcf 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1716,27 +1716,6 @@
}
}
- private void setDevicePolicyUserRestrictionsInner(@UserIdInt int originatingUserId,
- @Nullable Bundle restrictions,
- @UserManagerInternal.OwnerType int restrictionOwnerType) {
- final Bundle global = new Bundle();
- final Bundle local = new Bundle();
-
- // Sort restrictions into local and global ensuring they don't overlap.
- UserRestrictionsUtils.sortToGlobalAndLocal(restrictions, restrictionOwnerType, global,
- local);
- boolean isDeviceOwner = restrictionOwnerType == UserManagerInternal.OWNER_TYPE_DEVICE_OWNER;
-
- RestrictionsSet localRestrictionsSet;
- if (UserRestrictionsUtils.isEmpty(local)) {
- localRestrictionsSet = new RestrictionsSet();
- } else {
- localRestrictionsSet = new RestrictionsSet(originatingUserId, local);
- }
- setDevicePolicyUserRestrictionsInner(originatingUserId, global, localRestrictionsSet,
- isDeviceOwner);
- }
-
/**
* See {@link UserManagerInternal#setDevicePolicyUserRestrictions}
*/
@@ -4754,10 +4733,10 @@
private class LocalService extends UserManagerInternal {
@Override
public void setDevicePolicyUserRestrictions(@UserIdInt int originatingUserId,
- @Nullable Bundle restrictions,
- @OwnerType int restrictionOwnerType) {
+ @NonNull Bundle global, @NonNull RestrictionsSet local,
+ boolean isDeviceOwner) {
UserManagerService.this.setDevicePolicyUserRestrictionsInner(originatingUserId,
- restrictions, restrictionOwnerType);
+ global, local, isDeviceOwner);
}
@Override
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index eec6e02..c0502b8 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -233,6 +233,13 @@
);
/**
+ * Special user restrictions that profile owner of an organization-owned managed profile can
+ * set on the parent profile instance to apply them on the personal profile.
+ */
+ private static final Set<String> PROFILE_OWNER_ORGANIZATION_OWNED_LOCAL_RESTRICTIONS =
+ Sets.newArraySet();
+
+ /**
* User restrictions that default to {@code true} for managed profile owners.
*
* NB: {@link UserManager#DISALLOW_INSTALL_UNKNOWN_SOURCES} is also set by default but it is
@@ -416,7 +423,8 @@
* @return true if a restriction is settable by profile owner of an organization owned device.
*/
public static boolean canProfileOwnerOfOrganizationOwnedDeviceChange(String restriction) {
- return PROFILE_OWNER_ORGANIZATION_OWNED_GLOBAL_RESTRICTIONS.contains(restriction);
+ return PROFILE_OWNER_ORGANIZATION_OWNED_GLOBAL_RESTRICTIONS.contains(restriction)
+ || PROFILE_OWNER_ORGANIZATION_OWNED_LOCAL_RESTRICTIONS.contains(restriction);
}
/**
@@ -427,31 +435,9 @@
}
/**
- * Takes restrictions that can be set by device owner, and sort them into what should be applied
- * globally and what should be applied only on the current user.
- */
- public static void sortToGlobalAndLocal(@Nullable Bundle in,
- @UserManagerInternal.OwnerType int restrictionOwnerType, @NonNull Bundle global,
- @NonNull Bundle local) {
- if (in == null || in.size() == 0) {
- return;
- }
- for (String key : in.keySet()) {
- if (!in.getBoolean(key)) {
- continue;
- }
- if (isGlobal(restrictionOwnerType, key)) {
- global.putBoolean(key, true);
- } else {
- local.putBoolean(key, true);
- }
- }
- }
-
- /**
* Whether given user restriction should be enforced globally.
*/
- private static boolean isGlobal(@UserManagerInternal.OwnerType int restrictionOwnerType,
+ public static boolean isGlobal(@UserManagerInternal.OwnerType int restrictionOwnerType,
String key) {
return ((restrictionOwnerType == UserManagerInternal.OWNER_TYPE_DEVICE_OWNER) && (
PRIMARY_USER_ONLY_RESTRICTIONS.contains(key) || GLOBAL_RESTRICTIONS.contains(key)))
@@ -463,6 +449,14 @@
}
/**
+ * Whether given user restriction should be enforced locally.
+ */
+ public static boolean isLocal(@UserManagerInternal.OwnerType int restrictionOwnerType,
+ String key) {
+ return !isGlobal(restrictionOwnerType, key);
+ }
+
+ /**
* @return true if two Bundles contain the same user restriction.
* A null bundle and an empty bundle are considered to be equal.
*/
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 24ab89b..e9da2c4 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -3039,7 +3039,7 @@
e.writeInt(message.getUid());
e.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
e.writeString(message.getPackageName());
- e.writeString(message.getOp());
+ e.writeString("");
if (message.getAttributionTag() == null) {
e.writeString("");
} else {
@@ -3047,6 +3047,7 @@
}
e.writeString(message.getMessage());
e.writeInt(message.getSamplingStrategy());
+ e.writeInt(AppOpsManager.strOpToOp(message.getOp()));
pulledData.add(e.build());
} catch (Throwable t) {
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index ddf166e..63952b0 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -1904,7 +1904,7 @@
final WallpaperData fallback =
new WallpaperData(wallpaper.userId, getWallpaperDir(wallpaper.userId),
WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
- ensureSaneWallpaperData(fallback, DEFAULT_DISPLAY);
+ ensureSaneWallpaperData(fallback);
bindWallpaperComponentLocked(mImageWallpaper, true, false, fallback, reply);
mWaitingForUnlock = true;
}
@@ -2425,7 +2425,7 @@
if (cropHint == null) {
cropHint = new Rect(0, 0, 0, 0);
} else {
- if (cropHint.isEmpty()
+ if (cropHint.width() < 0 || cropHint.height() < 0
|| cropHint.left < 0
|| cropHint.top < 0) {
throw new IllegalArgumentException("Invalid crop rect supplied: " + cropHint);
@@ -3077,7 +3077,7 @@
wallpaper = new WallpaperData(userId, getWallpaperDir(userId),
WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
mLockWallpaperMap.put(userId, wallpaper);
- ensureSaneWallpaperData(wallpaper, DEFAULT_DISPLAY);
+ ensureSaneWallpaperData(wallpaper);
} else {
// sanity fallback: we're in bad shape, but establishing a known
// valid system+lock WallpaperData will keep us from dying.
@@ -3085,7 +3085,7 @@
wallpaper = new WallpaperData(userId, getWallpaperDir(userId),
WALLPAPER, WALLPAPER_CROP);
mWallpaperMap.put(userId, wallpaper);
- ensureSaneWallpaperData(wallpaper, DEFAULT_DISPLAY);
+ ensureSaneWallpaperData(wallpaper);
}
}
}
@@ -3196,10 +3196,10 @@
}
ensureSaneWallpaperDisplaySize(wpdData, DEFAULT_DISPLAY);
- ensureSaneWallpaperData(wallpaper, DEFAULT_DISPLAY);
+ ensureSaneWallpaperData(wallpaper);
WallpaperData lockWallpaper = mLockWallpaperMap.get(userId);
if (lockWallpaper != null) {
- ensureSaneWallpaperData(lockWallpaper, DEFAULT_DISPLAY);
+ ensureSaneWallpaperData(lockWallpaper);
}
}
@@ -3215,15 +3215,11 @@
}
}
- private void ensureSaneWallpaperData(WallpaperData wallpaper, int displayId) {
- final DisplayData size = getDisplayDataOrCreate(displayId);
-
- if (displayId == DEFAULT_DISPLAY) {
- // crop, if not previously specified
- if (wallpaper.cropHint.width() <= 0
- || wallpaper.cropHint.height() <= 0) {
- wallpaper.cropHint.set(0, 0, size.mWidth, size.mHeight);
- }
+ private void ensureSaneWallpaperData(WallpaperData wallpaper) {
+ // Only overwrite cropHint if the rectangle is invalid.
+ if (wallpaper.cropHint.width() < 0
+ || wallpaper.cropHint.height() < 0) {
+ wallpaper.cropHint.set(0, 0, 0, 0);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index c1c8440..a66741c 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -7411,7 +7411,17 @@
*/
boolean isResumedActivityOnDisplay() {
final DisplayContent display = getDisplay();
- return display != null && this == display.mTaskContainers.getResumedActivity();
+ if (display == null) {
+ return false;
+ }
+ for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+ final ActivityRecord resumedActivity = taskDisplayArea.getFocusedActivity();
+ if (resumedActivity != null) {
+ return resumedActivity == this;
+ }
+ }
+ return false;
}
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index a446720..f5eba96 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -1119,8 +1119,8 @@
@Override
public boolean isAttached() {
- final DisplayContent display = getDisplay();
- return display != null && !display.isRemoved();
+ final TaskDisplayArea taskDisplayArea = getDisplayArea();
+ return taskDisplayArea != null && !taskDisplayArea.isRemoved();
}
// TODO: Should each user have there own stacks?
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 8af8624..02601ff 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -385,15 +385,15 @@
private final MoveTaskToFullscreenHelper mMoveTaskToFullscreenHelper =
new MoveTaskToFullscreenHelper();
private class MoveTaskToFullscreenHelper {
- private DisplayContent mToDisplay;
+ private TaskDisplayArea mToDisplayArea;
private boolean mOnTop;
private Task mTopTask;
private boolean mSchedulePictureInPictureModeChange;
- void process(ActivityStack fromStack, DisplayContent toDisplay, boolean onTop,
+ void process(ActivityStack fromStack, TaskDisplayArea toDisplayArea, boolean onTop,
boolean schedulePictureInPictureModeChange) {
mSchedulePictureInPictureModeChange = schedulePictureInPictureModeChange;
- mToDisplay = toDisplay;
+ mToDisplayArea = toDisplayArea;
mOnTop = onTop;
mTopTask = fromStack.getTopMostTask();
@@ -401,7 +401,7 @@
MoveTaskToFullscreenHelper::processLeafTask, this, PooledLambda.__(Task.class));
fromStack.forAllLeafTasks(c, false /* traverseTopToBottom */);
c.recycle();
- mToDisplay = null;
+ mToDisplayArea = null;
mTopTask = null;
}
@@ -411,19 +411,18 @@
task.getActivityType())) {
final ActivityStack stack = (ActivityStack) task;
stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
- if (mToDisplay.getDisplayId() != stack.getDisplayId()) {
- stack.reparent(mToDisplay.getDefaultTaskDisplayArea(), mOnTop);
+ if (mToDisplayArea.getDisplayId() != stack.getDisplayId()) {
+ stack.reparent(mToDisplayArea, mOnTop);
} else if (mOnTop) {
- mToDisplay.mTaskContainers.positionStackAtTop(stack,
- false /* includingParents */);
+ mToDisplayArea.positionStackAtTop(stack, false /* includingParents */);
} else {
- mToDisplay.mTaskContainers.positionStackAtBottom(stack);
+ mToDisplayArea.positionStackAtBottom(stack);
}
return;
}
- final ActivityStack toStack = mToDisplay.mTaskContainers.getOrCreateStack(
- null, mTmpOptions, task, task.getActivityType(), mOnTop);
+ final ActivityStack toStack = mToDisplayArea.getOrCreateStack(null, mTmpOptions, task,
+ task.getActivityType(), mOnTop);
if (task == toStack) {
// The task was reused as the root task.
return;
@@ -1418,7 +1417,7 @@
mRootWindowContainer.getLaunchStack(null, options, task, ON_TOP);
if (stack != currentStack) {
- moveHomeStackToFrontIfNeeded(flags, stack.getDisplay(), reason);
+ moveHomeStackToFrontIfNeeded(flags, stack.getDisplayArea(), reason);
task.reparent(stack, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE, DEFER_RESUME,
reason);
currentStack = stack;
@@ -1437,7 +1436,7 @@
}
if (!reparented) {
- moveHomeStackToFrontIfNeeded(flags, currentStack.getDisplay(), reason);
+ moveHomeStackToFrontIfNeeded(flags, currentStack.getDisplayArea(), reason);
}
final ActivityRecord r = task.getTopNonFinishingActivity();
@@ -1451,15 +1450,16 @@
currentStack, forceNonResizeable);
}
- private void moveHomeStackToFrontIfNeeded(int flags, DisplayContent display, String reason) {
- final ActivityStack focusedStack = display.getFocusedStack();
+ private void moveHomeStackToFrontIfNeeded(int flags, TaskDisplayArea taskDisplayArea,
+ String reason) {
+ final ActivityStack focusedStack = taskDisplayArea.getFocusedStack();
- if ((display.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
+ if ((taskDisplayArea.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
&& (flags & ActivityManager.MOVE_TASK_WITH_HOME) != 0)
|| (focusedStack != null && focusedStack.isActivityTypeRecents())) {
- // We move home stack to front when we are on a fullscreen display and caller has
+ // We move home stack to front when we are on a fullscreen display area and caller has
// requested the home activity to move with it. Or the previous stack is recents.
- display.mTaskContainers.moveHomeStackToFront(reason);
+ taskDisplayArea.moveHomeStackToFront(reason);
}
}
@@ -1511,15 +1511,15 @@
mService.deferWindowLayout();
try {
final int windowingMode = fromStack.getWindowingMode();
- final DisplayContent toDisplay =
- mRootWindowContainer.getDisplayContent(toDisplayId);
+ final TaskDisplayArea toDisplayArea = mRootWindowContainer
+ .getDisplayContent(toDisplayId).getDefaultTaskDisplayArea();
if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
// We are moving all tasks from the docked stack to the fullscreen stack,
// which is dismissing the docked stack, so resize all other stacks to
// fullscreen here already so we don't end up with resize trashing.
- for (int i = toDisplay.getStackCount() - 1; i >= 0; --i) {
- final ActivityStack otherStack = toDisplay.getStackAt(i);
+ for (int i = toDisplayArea.getStackCount() - 1; i >= 0; --i) {
+ final ActivityStack otherStack = toDisplayArea.getStackAt(i);
if (!otherStack.inSplitScreenSecondaryWindowingMode()) {
continue;
}
@@ -1535,7 +1535,7 @@
if (fromStack.hasChild()) {
mTmpOptions.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
mMoveTaskToFullscreenHelper.process(
- fromStack, toDisplay, onTop, schedulePictureInPictureModeChange);
+ fromStack, toDisplayArea, onTop, schedulePictureInPictureModeChange);
}
mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
@@ -1546,6 +1546,7 @@
}
void moveTasksToFullscreenStackLocked(ActivityStack fromStack, boolean onTop) {
+ // TODO(b/153089193): Support moving within the same task display area
mWindowManager.inSurfaceTransaction(() ->
moveTasksToFullscreenStackInSurfaceTransaction(fromStack, DEFAULT_DISPLAY, onTop));
}
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 0a0049d..d777f3f 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -189,9 +189,10 @@
mSupervisor.beginDeferResume();
final ActivityStack homeStack;
try {
+ // TODO(multi-display-area): Support starting home in a task display area
// Make sure home stack exist on display.
- homeStack = display.mTaskContainers.getOrCreateStack(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_HOME, ON_TOP);
+ homeStack = display.getDefaultTaskDisplayArea().getOrCreateStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
} finally {
mSupervisor.endDeferResume();
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 85517a4..7931cd5 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2060,20 +2060,53 @@
* activity type. Null is no compatible stack on the display.
*/
ActivityStack getStack(int windowingMode, int activityType) {
- return mTaskContainers.getStack(windowingMode, activityType);
+ for (int tdaNdx = getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final ActivityStack stack = getTaskDisplayAreaAt(tdaNdx)
+ .getStack(windowingMode, activityType);
+ if (stack != null) {
+ return stack;
+ }
+ }
+ return null;
+ }
+
+ protected int getTaskDisplayAreaCount() {
+ // TODO(multi-display-area): Report actual display area count
+ return 1;
+ }
+
+ protected TaskDisplayArea getTaskDisplayAreaAt(int index) {
+ // TODO(multi-display-area): Report actual display area values
+ return mTaskContainers;
+ }
+
+ ActivityStack getStack(int rootTaskId) {
+ for (int tdaNdx = getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final ActivityStack stack = getTaskDisplayAreaAt(tdaNdx).getStack(rootTaskId);
+ if (stack != null) {
+ return stack;
+ }
+ }
+ return null;
}
protected int getStackCount() {
- return mTaskContainers.mChildren.size();
- }
-
- protected ActivityStack getStackAt(int index) {
- return mTaskContainers.mChildren.get(index);
+ int totalStackCount = 0;
+ for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
+ totalStackCount += getTaskDisplayAreaAt(i).getStackCount();
+ }
+ return totalStackCount;
}
@VisibleForTesting
ActivityStack getTopStack() {
- return mTaskContainers.getTopStack();
+ for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
+ final ActivityStack stack = getTaskDisplayAreaAt(i).getTopStack();
+ if (stack != null) {
+ return stack;
+ }
+ }
+ return null;
}
/**
@@ -2449,7 +2482,7 @@
final PooledConsumer c = PooledLambda.obtainConsumer(
DisplayContent::processTaskForTouchExcludeRegion, this,
PooledLambda.__(Task.class), focusedTask, delta);
- mTaskContainers.forAllTasks(c);
+ forAllTasks(c);
c.recycle();
// If we removed the focused task above, add it back and only leave its
@@ -2630,9 +2663,8 @@
}
void prepareFreezingTaskBounds() {
- for (int stackNdx = mTaskContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = mTaskContainers.getChildAt(stackNdx);
- stack.prepareFreezingTaskBounds();
+ for (int tdaNdx = getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ getTaskDisplayAreaAt(tdaNdx).prepareFreezingTaskBounds();
}
}
@@ -2738,8 +2770,8 @@
final ActivityStack focusedStack = getFocusedStack();
if (focusedStack != null) {
proto.write(FOCUSED_ROOT_TASK_ID, focusedStack.getRootTaskId());
- final ActivityRecord focusedActivity = focusedStack.getDisplay().mTaskContainers
- .getResumedActivity();
+ final ActivityRecord focusedActivity = focusedStack.getDisplayArea()
+ .getFocusedActivity();
if (focusedActivity != null) {
focusedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY);
}
@@ -2797,13 +2829,6 @@
if (mLastFocus != mCurrentFocus) {
pw.print(" mLastFocus="); pw.println(mLastFocus);
}
- if (mTaskContainers.mPreferredTopFocusableStack != null) {
- pw.println(prefix + "mPreferredTopFocusableStack="
- + mTaskContainers.mPreferredTopFocusableStack);
- }
- if (mTaskContainers.mLastFocusedStack != null) {
- pw.println(prefix + "mLastFocusedStack=" + mTaskContainers.mLastFocusedStack);
- }
if (mLosingFocus.size() > 0) {
pw.println();
pw.println(" Windows losing focus:");
@@ -2837,10 +2862,9 @@
}
pw.println();
- pw.println(prefix + "Application tokens in top down Z order:");
- for (int stackNdx = mTaskContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = mTaskContainers.getChildAt(stackNdx);
- stack.dump(pw, prefix + " ", dumpAll);
+ pw.println(prefix + "Task display areas in top down Z order:");
+ for (int tdaNdx = getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ getTaskDisplayAreaAt(tdaNdx).dump(pw, prefix + " ", dumpAll);
}
pw.println();
@@ -4002,7 +4026,9 @@
}
// Initialize state of exiting applications.
- mTaskContainers.setExitingTokensHasVisible(hasVisible);
+ for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
+ getTaskDisplayAreaAt(i).setExitingTokensHasVisible(hasVisible);
+ }
}
void removeExistingTokensIfPossible() {
@@ -4014,7 +4040,9 @@
}
// Time to remove any exiting applications?
- mTaskContainers.removeExistingAppTokensIfPossible();
+ for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
+ getTaskDisplayAreaAt(i).removeExistingAppTokensIfPossible();
+ }
}
@Override
@@ -4475,7 +4503,9 @@
}
void assignStackOrdering() {
- mTaskContainers.assignStackOrdering(getPendingTransaction());
+ for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
+ getTaskDisplayAreaAt(i).assignStackOrdering(getPendingTransaction());
+ }
}
/**
@@ -5002,13 +5032,15 @@
|| windowingMode == WINDOWING_MODE_MULTI_WINDOW);
}
- ActivityStack createStack(int windowingMode, int activityType, boolean onTop) {
- return mTaskContainers.createStack(windowingMode, activityType, onTop, null /* info */,
- null /* intent */, false /* createdByOrganizer */);
- }
-
+ @Nullable
ActivityStack getFocusedStack() {
- return mTaskContainers.getFocusedStack();
+ for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
+ final ActivityStack stack = getTaskDisplayAreaAt(i).getFocusedStack();
+ if (stack != null) {
+ return stack;
+ }
+ }
+ return null;
}
/**
@@ -5016,11 +5048,15 @@
* ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
*/
void removeStacksInWindowingModes(int... windowingModes) {
- mTaskContainers.removeStacksInWindowingModes(windowingModes);
+ for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
+ getTaskDisplayAreaAt(i).removeStacksInWindowingModes(windowingModes);
+ }
}
void removeStacksWithActivityTypes(int... activityTypes) {
- mTaskContainers.removeStacksWithActivityTypes(activityTypes);
+ for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
+ getTaskDisplayAreaAt(i).removeStacksWithActivityTypes(activityTypes);
+ }
}
ActivityRecord topRunningActivity() {
@@ -5037,7 +5073,14 @@
* @return The top running activity. {@code null} if none is available.
*/
ActivityRecord topRunningActivity(boolean considerKeyguardState) {
- return mTaskContainers.topRunningActivity(considerKeyguardState);
+ for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
+ final ActivityRecord activity = getTaskDisplayAreaAt(i)
+ .topRunningActivity(considerKeyguardState);
+ if (activity != null) {
+ return activity;
+ }
+ }
+ return null;
}
boolean updateDisplayOverrideConfigurationLocked() {
@@ -5149,7 +5192,7 @@
// The display may be about to rotate seamlessly, and the animation of closing apps may
// still animate in old rotation. So make sure the outdated animation won't show on the
// rotated display.
- mTaskContainers.forAllActivities(a -> {
+ forAllActivities(a -> {
if (a.nowVisible && a != mFixedRotationLaunchingApp
&& a.getWindowConfiguration().getRotation() != newRotation) {
final WindowContainer<?> w = a.getAnimatingContainer();
@@ -5210,40 +5253,17 @@
void remove() {
mRemoving = true;
- final boolean destroyContentOnRemoval = shouldDestroyContentOnRemove();
ActivityStack lastReparentedStack = null;
- mTaskContainers.mPreferredTopFocusableStack = null;
- // Stacks could be reparented from the removed display to other display. While
- // reparenting the last stack of the removed display, the remove display is ready to be
- // released (no more ActivityStack). But, we cannot release it at that moment or the
- // related WindowContainer will also be removed. So, we set display as removed after
- // reparenting stack finished.
- final TaskDisplayArea toTaskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
mRootWindowContainer.mStackSupervisor.beginDeferResume();
try {
- int numStacks = getStackCount();
- // Keep the order from bottom to top.
- for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
- final ActivityStack stack = getStackAt(stackNdx);
- // Always finish non-standard type stacks.
- if (destroyContentOnRemoval || !stack.isActivityTypeStandardOrUndefined()) {
- stack.finishAllActivitiesImmediately();
- } else {
- // If default display is in split-window mode, set windowing mode of the stack
- // to split-screen secondary. Otherwise, set the windowing mode to undefined by
- // default to let stack inherited the windowing mode from the new display.
- final int windowingMode = toTaskDisplayArea.isSplitScreenModeActivated()
- ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
- : WINDOWING_MODE_UNDEFINED;
- stack.reparent(toTaskDisplayArea, true /* onTop */);
- stack.setWindowingMode(windowingMode);
- lastReparentedStack = stack;
+ int numTaskContainers = getTaskDisplayAreaCount();
+ for (int tdaNdx = 0; tdaNdx < numTaskContainers; tdaNdx++) {
+ final ActivityStack lastReparentedStackFromArea = getTaskDisplayAreaAt(tdaNdx)
+ .remove();
+ if (lastReparentedStackFromArea != null) {
+ lastReparentedStack = lastReparentedStackFromArea;
}
- // Stacks may be removed from this display. Ensure each stack will be processed and
- // the loop will end.
- stackNdx -= numStacks - getStackCount();
- numStacks = getStackCount();
}
} finally {
mRootWindowContainer.mStackSupervisor.endDeferResume();
@@ -5270,12 +5290,27 @@
return;
}
- final ActivityStack stack = getStackCount() == 1 ? getStackAt(0) : null;
- if (stack != null && stack.isActivityTypeHome() && !stack.hasChild()) {
- // Release this display if an empty home stack is the only thing left.
- // Since it is the last stack, this display will be released along with the stack
- // removal.
- stack.removeIfPossible();
+ // Check if all task display areas have only the empty home stacks left.
+ boolean onlyEmptyHomeStacksLeft = true;
+ for (int tdaNdx = getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final TaskDisplayArea taskDisplayArea = getTaskDisplayAreaAt(tdaNdx);
+ if (taskDisplayArea.getStackCount() != 1) {
+ onlyEmptyHomeStacksLeft = false;
+ break;
+ }
+ final ActivityStack stack = taskDisplayArea.getStackAt(0);
+ if (!stack.isActivityTypeHome() || stack.hasChild()) {
+ onlyEmptyHomeStacksLeft = false;
+ break;
+ }
+ }
+ if (onlyEmptyHomeStacksLeft) {
+ // Release this display if only empty home stack(s) are left. This display will be
+ // released along with the stack(s) removal.
+ for (int tdaNdx = getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final ActivityStack s = getTaskDisplayAreaAt(tdaNdx).getStackAt(0);
+ s.removeIfPossible();
+ }
} else if (getTopStack() == null) {
removeIfPossible();
mRootWindowContainer.mStackSupervisor
@@ -5334,10 +5369,9 @@
void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
boolean preserveWindows, boolean notifyClients) {
- for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = getStackAt(stackNdx);
- stack.ensureActivitiesVisible(starting, configChanges, preserveWindows,
- notifyClients);
+ for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
+ getTaskDisplayAreaAt(i).ensureActivitiesVisible(starting, configChanges,
+ preserveWindows, notifyClients);
}
}
@@ -5350,13 +5384,18 @@
}
void setDisplayToSingleTaskInstance() {
- final int childCount = getStackCount();
- if (childCount > 1) {
+ final int taskDisplayAreaCount = getTaskDisplayAreaCount();
+ if (taskDisplayAreaCount > 1) {
+ throw new IllegalArgumentException(
+ "Display already has multiple task display areas. display=" + this);
+ }
+ final int stackCount = getDefaultTaskDisplayArea().getStackCount();
+ if (stackCount > 1) {
throw new IllegalArgumentException("Display already has multiple stacks. display="
+ this);
}
- if (childCount > 0) {
- final ActivityStack stack = getStackAt(0);
+ if (stackCount > 0) {
+ final ActivityStack stack = getDefaultTaskDisplayArea().getStackAt(0);
if (stack.getChildCount() > 1) {
throw new IllegalArgumentException("Display stack already has multiple tasks."
+ " display=" + this + " stack=" + stack);
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 264da9f..caaa173 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -3247,7 +3247,7 @@
final int dockedAppearance = updateLightStatusBarAppearanceLw(0 /* vis */,
mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState);
final boolean inSplitScreen =
- mService.mRoot.getDefaultDisplay().mTaskContainers.isSplitScreenModeActivated();
+ mService.mRoot.getDefaultTaskDisplayArea().isSplitScreenModeActivated();
if (inSplitScreen) {
mService.getStackBounds(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD,
mDockedStackBounds);
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 57a54d0..f672394 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -529,11 +529,14 @@
* occlusion state.
*/
private ActivityStack getStackForControllingOccluding(DisplayContent display) {
- for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = display.getStackAt(stackNdx);
- if (stack != null && stack.isFocusableAndVisible()
- && !stack.inPinnedWindowingMode()) {
- return stack;
+ for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+ if (stack != null && stack.isFocusableAndVisible()
+ && !stack.inPinnedWindowingMode()) {
+ return stack;
+ }
}
}
return null;
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 84229f0..6fda117 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -340,7 +340,7 @@
// Make leashes for each of the visible/target tasks and add it to the recents animation to
// be started
- // TODO(multi-display-area): Support Recents on multiple task display areas
+ // TODO(b/153090560): Support Recents on multiple task display areas
final ArrayList<Task> visibleTasks = mDisplayContent.getDefaultTaskDisplayArea()
.getVisibleTasks();
final ActivityStack targetStack = mDisplayContent.getDefaultTaskDisplayArea()
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 2eeda4d..e1ef76f 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1643,7 +1643,9 @@
displayId = DEFAULT_DISPLAY;
}
- final ActivityRecord r = getDisplayContent(displayId).mTaskContainers.getHomeActivity();
+ // TODO(multi-display-area): Resume home on the right task container
+ final ActivityRecord r = getDisplayContent(displayId).getDefaultTaskDisplayArea()
+ .getHomeActivity();
final String myReason = reason + " resumeHomeActivity";
// Only resume home activity if isn't finishing.
@@ -1800,19 +1802,23 @@
final ArrayList<IBinder> topActivityTokens = new ArrayList<>();
final ActivityStack topFocusedStack = getTopDisplayFocusedStack();
// Traverse all displays.
- for (int i = getChildCount() - 1; i >= 0; i--) {
- final DisplayContent display = getChildAt(i);
- // Traverse all stacks on a display.
- for (int j = display.getStackCount() - 1; j >= 0; --j) {
- final ActivityStack stack = display.getStackAt(j);
- // Get top activity from a visible stack and add it to the list.
- if (stack.shouldBeVisible(null /* starting */)) {
- final ActivityRecord top = stack.getTopNonFinishingActivity();
- if (top != null) {
- if (stack == topFocusedStack) {
- topActivityTokens.add(0, top.appToken);
- } else {
- topActivityTokens.add(top.appToken);
+ for (int dNdx = getChildCount() - 1; dNdx >= 0; dNdx--) {
+ final DisplayContent display = getChildAt(dNdx);
+ for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final TaskDisplayArea taskDisplayArea =
+ display.getTaskDisplayAreaAt(tdaNdx);
+ // Traverse all stacks on a display area.
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+ // Get top activity from a visible stack and add it to the list.
+ if (stack.shouldBeVisible(null /* starting */)) {
+ final ActivityRecord top = stack.getTopNonFinishingActivity();
+ if (top != null) {
+ if (stack == topFocusedStack) {
+ topActivityTokens.add(0, top.appToken);
+ } else {
+ topActivityTokens.add(top.appToken);
+ }
}
}
}
@@ -1844,10 +1850,13 @@
// focus order.
for (int i = getChildCount() - 1; i >= 0; --i) {
final DisplayContent display = getChildAt(i);
- final ActivityRecord resumedActivityOnDisplay = display.mTaskContainers
- .getResumedActivity();
- if (resumedActivityOnDisplay != null) {
- return resumedActivityOnDisplay;
+ for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+ final ActivityRecord resumedActivityOnTaskContainer = taskDisplayArea
+ .getFocusedActivity();
+ if (resumedActivityOnTaskContainer != null) {
+ return resumedActivityOnTaskContainer;
+ }
}
}
return null;
@@ -1867,16 +1876,19 @@
WindowProcessController fgApp = null;
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
final DisplayContent display = getChildAt(displayNdx);
- for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = display.getStackAt(stackNdx);
- if (isTopDisplayFocusedStack(stack)) {
- final ActivityRecord resumedActivity = stack.getResumedActivity();
- if (resumedActivity != null) {
- fgApp = resumedActivity.app;
- } else if (stack.mPausingActivity != null) {
- fgApp = stack.mPausingActivity.app;
+ for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+ if (isTopDisplayFocusedStack(stack)) {
+ final ActivityRecord resumedActivity = stack.getResumedActivity();
+ if (resumedActivity != null) {
+ fgApp = resumedActivity.app;
+ } else if (stack.mPausingActivity != null) {
+ fgApp = stack.mPausingActivity.app;
+ }
+ break;
}
- break;
}
}
}
@@ -1992,9 +2004,12 @@
mStackSupervisor.mStartingUsers.add(uss);
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
final DisplayContent display = getChildAt(displayNdx);
- for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = display.getStackAt(stackNdx);
- stack.switchUser(userId);
+ for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+ stack.switchUser(userId);
+ }
}
}
@@ -2196,13 +2211,17 @@
ActivityStack focusedStack = getTopDisplayFocusedStack();
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
final DisplayContent display = getChildAt(displayNdx);
- // It is possible that request to finish activity might also remove its task and stack,
- // so we need to be careful with indexes in the loop and check child count every time.
- for (int stackNdx = 0; stackNdx < display.getStackCount(); ++stackNdx) {
- final ActivityStack stack = display.getStackAt(stackNdx);
- final Task t = stack.finishTopCrashedActivityLocked(app, reason);
- if (stack == focusedStack || finishedTask == null) {
- finishedTask = t;
+ for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+ // It is possible that request to finish activity might also remove its task and
+ // stack, so we need to be careful with indexes in the loop and check child count
+ // every time.
+ for (int stackNdx = 0; stackNdx < display.getStackCount(); ++stackNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(stackNdx);
+ final Task t = stack.finishTopCrashedActivityLocked(app, reason);
+ if (stack == focusedStack || finishedTask == null) {
+ finishedTask = t;
+ }
}
}
}
@@ -2229,26 +2248,29 @@
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
boolean resumedOnDisplay = false;
final DisplayContent display = getChildAt(displayNdx);
- for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = display.getStackAt(stackNdx);
- final ActivityRecord topRunningActivity = stack.topRunningActivity();
- if (!stack.isFocusableAndVisible() || topRunningActivity == null) {
- continue;
- }
- if (stack == targetStack) {
- // Simply update the result for targetStack because the targetStack had
- // already resumed in above. We don't want to resume it again, especially in
- // some cases, it would cause a second launch failure if app process was dead.
- resumedOnDisplay |= result;
- continue;
- }
- if (display.mTaskContainers.isTopStack(stack)
- && topRunningActivity.isState(RESUMED)) {
- // Kick off any lingering app transitions form the MoveTaskToFront operation,
- // but only consider the top task and stack on that display.
- stack.executeAppTransition(targetOptions);
- } else {
- resumedOnDisplay |= topRunningActivity.makeActiveIfNeeded(target);
+ for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+ final ActivityRecord topRunningActivity = stack.topRunningActivity();
+ if (!stack.isFocusableAndVisible() || topRunningActivity == null) {
+ continue;
+ }
+ if (stack == targetStack) {
+ // Simply update the result for targetStack because the targetStack had
+ // already resumed in above. We don't want to resume it again, especially in
+ // some cases, it would cause a second launch failure if app process was
+ // dead.
+ resumedOnDisplay |= result;
+ continue;
+ }
+ if (taskDisplayArea.isTopStack(stack) && topRunningActivity.isState(RESUMED)) {
+ // Kick off any lingering app transitions form the MoveTaskToFront
+ // operation, but only consider the top task and stack on that display.
+ stack.executeAppTransition(targetOptions);
+ } else {
+ resumedOnDisplay |= topRunningActivity.makeActiveIfNeeded(target);
+ }
}
}
if (!resumedOnDisplay) {
@@ -2284,32 +2306,37 @@
}
// Set the sleeping state of the stacks on the display.
- for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = display.getStackAt(stackNdx);
- if (displayShouldSleep) {
- stack.goToSleepIfPossible(false /* shuttingDown */);
- } else {
- // When the display which can only contain one task turns on, start a special
- // transition. {@link AppTransitionController#handleAppTransitionReady} later
- // picks up the transition, and schedules
- // {@link ITaskStackListener#onSingleTaskDisplayDrawn} callback which is
- // triggered after contents are drawn on the display.
- if (display.isSingleTaskInstance()) {
- display.mDisplayContent.prepareAppTransition(
- TRANSIT_SHOW_SINGLE_TASK_DISPLAY, false);
- }
- stack.awakeFromSleepingLocked();
- if (display.isSingleTaskInstance()) {
- display.executeAppTransition();
- }
- if (stack.isFocusedStackOnDisplay()
- && !mStackSupervisor.getKeyguardController()
- .isKeyguardOrAodShowing(display.mDisplayId)) {
- // If the keyguard is unlocked - resume immediately.
- // It is possible that the display will not be awake at the time we
- // process the keyguard going away, which can happen before the sleep token
- // is released. As a result, it is important we resume the activity here.
- resumeFocusedStacksTopActivities();
+ for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+ if (displayShouldSleep) {
+ stack.goToSleepIfPossible(false /* shuttingDown */);
+ } else {
+ // When the display which can only contain one task turns on, start a
+ // special transition.
+ // {@link AppTransitionController#handleAppTransitionReady} later picks up
+ // the transition, and schedules
+ // {@link ITaskStackListener#onSingleTaskDisplayDrawn} callback which is
+ // triggered after contents are drawn on the display.
+ if (display.isSingleTaskInstance()) {
+ display.mDisplayContent.prepareAppTransition(
+ TRANSIT_SHOW_SINGLE_TASK_DISPLAY, false);
+ }
+ stack.awakeFromSleepingLocked();
+ if (display.isSingleTaskInstance()) {
+ display.executeAppTransition();
+ }
+ if (stack.isFocusedStackOnDisplay()
+ && !mStackSupervisor.getKeyguardController()
+ .isKeyguardOrAodShowing(display.mDisplayId)) {
+ // If the keyguard is unlocked - resume immediately.
+ // It is possible that the display will not be awake at the time we
+ // process the keyguard going away, which can happen before the sleep
+ // token is released. As a result, it is important we resume the
+ // activity here.
+ resumeFocusedStacksTopActivities();
+ }
}
}
}
@@ -2318,7 +2345,7 @@
protected ActivityStack getStack(int stackId) {
for (int i = getChildCount() - 1; i >= 0; --i) {
- final ActivityStack stack = getChildAt(i).mTaskContainers.getStack(stackId);
+ final ActivityStack stack = getChildAt(i).getStack(stackId);
if (stack != null) {
return stack;
}
@@ -2414,9 +2441,12 @@
if (displayId == INVALID_DISPLAY) {
for (int displayNdx = 0; displayNdx < getChildCount(); ++displayNdx) {
final DisplayContent display = getChildAt(displayNdx);
- for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = display.getStackAt(stackNdx);
- list.add(getStackInfo(stack));
+ for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+ list.add(getStackInfo(stack));
+ }
}
}
return list;
@@ -2425,9 +2455,12 @@
if (display == null) {
return list;
}
- for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = display.getStackAt(stackNdx);
- list.add(getStackInfo(stack));
+ for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+ list.add(getStackInfo(stack));
+ }
}
return list;
}
@@ -2646,19 +2679,21 @@
boolean allSleep = true;
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
final DisplayContent display = getChildAt(displayNdx);
- for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- // Stacks and activities could be removed while putting activities to sleep if
- // the app process was gone. This prevents us getting exception by accessing an
- // invalid stack index.
- if (stackNdx >= display.getStackCount()) {
- continue;
- }
-
- final ActivityStack stack = display.getStackAt(stackNdx);
- if (allowDelay) {
- allSleep &= stack.goToSleepIfPossible(shuttingDown);
- } else {
- stack.goToSleep();
+ for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ // Stacks and activities could be removed while putting activities to sleep if
+ // the app process was gone. This prevents us getting exception by accessing an
+ // invalid stack index.
+ if (sNdx >= taskDisplayArea.getStackCount()) {
+ continue;
+ }
+ final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+ if (allowDelay) {
+ allSleep &= stack.goToSleepIfPossible(shuttingDown);
+ } else {
+ stack.goToSleep();
+ }
}
}
}
@@ -2910,14 +2945,17 @@
windowingMode = options != null ? options.getLaunchWindowingMode()
: r.getWindowingMode();
}
- windowingMode = displayContent.mTaskContainers.validateWindowingMode(windowingMode, r,
- candidateTask, r.getActivityType());
// Return the topmost valid stack on the display.
- for (int i = displayContent.getStackCount() - 1; i >= 0; --i) {
- final ActivityStack stack = displayContent.getStackAt(i);
- if (isValidLaunchStack(stack, r, windowingMode)) {
- return stack;
+ for (int tdaNdx = displayContent.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final TaskDisplayArea taskDisplayArea = displayContent.getTaskDisplayAreaAt(tdaNdx);
+ final int validatedWindowingMode = taskDisplayArea
+ .validateWindowingMode(windowingMode, r, candidateTask, r.getActivityType());
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+ if (isValidLaunchStack(stack, r, validatedWindowingMode)) {
+ return stack;
+ }
}
}
@@ -3034,9 +3072,12 @@
boolean hasVisibleActivities = false;
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
final DisplayContent display = getChildAt(displayNdx);
- for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = display.getStackAt(stackNdx);
- hasVisibleActivities |= stack.handleAppDied(app);
+ for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+ hasVisibleActivities |= stack.handleAppDied(app);
+ }
}
}
return hasVisibleActivities;
@@ -3147,10 +3188,14 @@
void finishVoiceTask(IVoiceInteractionSession session) {
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
final DisplayContent display = getChildAt(displayNdx);
- final int numStacks = display.getStackCount();
- for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
- final ActivityStack stack = display.getStackAt(stackNdx);
- stack.finishVoiceTask(session);
+ int numTaskContainers = display.getTaskDisplayAreaCount();
+ for (int tdaNdx = 0; tdaNdx < numTaskContainers; tdaNdx++) {
+ final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+ final int numStacks = display.getStackCount();
+ for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(stackNdx);
+ stack.finishVoiceTask(session);
+ }
}
}
}
@@ -3214,14 +3259,17 @@
boolean foundResumed = false;
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
final DisplayContent display = getChildAt(displayNdx);
- for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = display.getStackAt(stackNdx);
- final ActivityRecord r = stack.getResumedActivity();
- if (r != null) {
- if (!r.nowVisible) {
- return false;
+ for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+ final ActivityRecord r = stack.getResumedActivity();
+ if (r != null) {
+ if (!r.nowVisible) {
+ return false;
+ }
+ foundResumed = true;
}
- foundResumed = true;
}
}
}
@@ -3232,16 +3280,19 @@
boolean pausing = true;
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
final DisplayContent display = getChildAt(displayNdx);
- for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = display.getStackAt(stackNdx);
- final ActivityRecord r = stack.mPausingActivity;
- if (r != null && !r.isState(PAUSED, STOPPED, STOPPING)) {
- if (DEBUG_STATES) {
- Slog.d(TAG_STATES,
- "allPausedActivitiesComplete: r=" + r + " state=" + r.getState());
- pausing = false;
- } else {
- return false;
+ for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+ final ActivityRecord r = stack.mPausingActivity;
+ if (r != null && !r.isState(PAUSED, STOPPED, STOPPING)) {
+ if (DEBUG_STATES) {
+ Slog.d(TAG_STATES, "allPausedActivitiesComplete: r=" + r
+ + " state=" + r.getState());
+ pausing = false;
+ } else {
+ return false;
+ }
}
}
}
@@ -3297,9 +3348,11 @@
void cancelInitializingActivities() {
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
final DisplayContent display = getChildAt(displayNdx);
- for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = display.getStackAt(stackNdx);
- stack.cancelInitializingActivities();
+ for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ taskDisplayArea.getStackAt(sNdx).cancelInitializingActivities();
+ }
}
}
}
@@ -3402,20 +3455,23 @@
}
if (!sendHint) { // targetActivity != null
- // Send power hint when the activity's process is different than the current resumed
- // activity on all displays, or if there are no resumed activities in the system.
+ // Send power hint when the activity's process is different than the current top resumed
+ // activity on all display areas, or if there are no resumed activities in the system.
boolean noResumedActivities = true;
boolean allFocusedProcessesDiffer = true;
for (int displayNdx = 0; displayNdx < getChildCount(); ++displayNdx) {
- final DisplayContent displayContent = getChildAt(displayNdx);
- final ActivityRecord resumedActivity = displayContent.mTaskContainers
- .getResumedActivity();
- final WindowProcessController resumedActivityProcess =
- resumedActivity == null ? null : resumedActivity.app;
+ final DisplayContent dc = getChildAt(displayNdx);
+ for (int tdaNdx = dc.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final TaskDisplayArea taskDisplayArea = dc.getTaskDisplayAreaAt(tdaNdx);
+ final ActivityRecord resumedActivity = taskDisplayArea.getFocusedActivity();
+ final WindowProcessController resumedActivityProcess =
+ resumedActivity == null ? null : resumedActivity.app;
- noResumedActivities &= resumedActivityProcess == null;
- if (resumedActivityProcess != null) {
- allFocusedProcessesDiffer &= !resumedActivityProcess.equals(targetActivity.app);
+ noResumedActivities &= resumedActivityProcess == null;
+ if (resumedActivityProcess != null) {
+ allFocusedProcessesDiffer &= !resumedActivityProcess.equals(
+ targetActivity.app);
+ }
}
}
sendHint = noResumedActivities || allFocusedProcessesDiffer;
@@ -3462,10 +3518,13 @@
int numDisplays = getChildCount();
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
final DisplayContent display = getChildAt(displayNdx);
- for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = display.getStackAt(stackNdx);
- if (!dumpVisibleStacksOnly || stack.shouldBeVisible(null)) {
- activities.addAll(stack.getDumpActivitiesLocked(name));
+ for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+ if (!dumpVisibleStacksOnly || stack.shouldBeVisible(null)) {
+ activities.addAll(stack.getDumpActivitiesLocked(name));
+ }
}
}
}
@@ -3505,14 +3564,21 @@
DisplayContent displayContent = getChildAt(displayNdx);
pw.print("Display #"); pw.print(displayContent.mDisplayId);
pw.println(" (activities from top to bottom):");
- for (int stackNdx = displayContent.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = displayContent.getStackAt(stackNdx);
- pw.println();
- printed = stack.dump(fd, pw, dumpAll, dumpClient, dumpPackage, needSep);
- needSep = printed;
+ for (int tdaNdx = displayContent.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final TaskDisplayArea taskDisplayArea = displayContent.getTaskDisplayAreaAt(tdaNdx);
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+ pw.println();
+ printed = stack.dump(fd, pw, dumpAll, dumpClient, dumpPackage, needSep);
+ needSep = printed;
+ }
}
- printThisActivity(pw, displayContent.mTaskContainers.getResumedActivity(), dumpPackage,
- needSep, " ResumedActivity:");
+ pw.println(" (resumed activities in task display areas from top to bottom):");
+ for (int tdaNdx = displayContent.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final TaskDisplayArea taskDisplayArea = displayContent.getTaskDisplayAreaAt(tdaNdx);
+ printThisActivity(pw, taskDisplayArea.getFocusedActivity(), dumpPackage, needSep,
+ " ResumedActivity:");
+ }
}
printed |= dumpHistoryList(fd, pw, mStackSupervisor.mFinishingActivities, " ",
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 726528c..1bc72449 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -63,6 +63,7 @@
import com.android.internal.util.function.pooled.PooledPredicate;
import com.android.server.protolog.common.ProtoLog;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -134,6 +135,12 @@
*/
private ArrayList<OnStackOrderChangedListener> mStackOrderChangedCallbacks = new ArrayList<>();
+ /**
+ * The task display area is removed from the system and we are just waiting for all activities
+ * on it to be finished before removing this object.
+ */
+ private boolean mRemoved;
+
TaskDisplayArea(DisplayContent displayContent, WindowManagerService service) {
super(service, Type.ANY, "TaskContainers", FEATURE_TASK_CONTAINER);
mDisplayContent = displayContent;
@@ -990,7 +997,7 @@
return candidate;
}
- ActivityRecord getResumedActivity() {
+ ActivityRecord getFocusedActivity() {
final ActivityStack focusedStack = getFocusedStack();
if (focusedStack == null) {
return null;
@@ -1576,7 +1583,7 @@
}
boolean isRemoved() {
- return mDisplayContent.isRemoved();
+ return mRemoved;
}
/**
@@ -1613,4 +1620,82 @@
interface OnStackOrderChangedListener {
void onStackOrderChanged(ActivityStack stack);
}
+
+ void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
+ boolean preserveWindows, boolean notifyClients) {
+ for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+ final ActivityStack stack = getStackAt(stackNdx);
+ stack.ensureActivitiesVisible(starting, configChanges, preserveWindows,
+ notifyClients);
+ }
+ }
+
+ void prepareFreezingTaskBounds() {
+ for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+ final ActivityStack stack = getChildAt(stackNdx);
+ stack.prepareFreezingTaskBounds();
+ }
+ }
+
+ /**
+ * Removes the stacks in the node applying the content removal node from the display.
+ * @return last reparented stack, or {@code null} if the stacks had to be destroyed.
+ */
+ ActivityStack remove() {
+ mPreferredTopFocusableStack = null;
+ // TODO(b/153090332): Allow setting content removal mode per task display area
+ final boolean destroyContentOnRemoval = mDisplayContent.shouldDestroyContentOnRemove();
+ final TaskDisplayArea toDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
+ ActivityStack lastReparentedStack = null;
+
+ // Stacks could be reparented from the removed display area to other display area. After
+ // reparenting the last stack of the removed display area, the display area becomes ready to
+ // be released (no more ActivityStack-s). But, we cannot release it at that moment or the
+ // related WindowContainer will also be removed. So, we set display area as removed after
+ // reparenting stack finished.
+ // Keep the order from bottom to top.
+ int numStacks = getStackCount();
+ for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
+ final ActivityStack stack = getStackAt(stackNdx);
+ // Always finish non-standard type stacks.
+ if (destroyContentOnRemoval || !stack.isActivityTypeStandardOrUndefined()) {
+ stack.finishAllActivitiesImmediately();
+ } else {
+ // If default display is in split-window mode, set windowing mode of the
+ // stack to split-screen secondary. Otherwise, set the windowing mode to
+ // undefined by default to let stack inherited the windowing mode from the
+ // new display.
+ final int windowingMode = toDisplayArea.isSplitScreenModeActivated()
+ ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
+ : WINDOWING_MODE_UNDEFINED;
+ stack.reparent(toDisplayArea, true /* onTop */);
+ stack.setWindowingMode(windowingMode);
+ lastReparentedStack = stack;
+ }
+ // Stacks may be removed from this display. Ensure each stack will be processed
+ // and the loop will end.
+ stackNdx -= numStacks - getStackCount();
+ numStacks = getStackCount();
+ }
+ mRemoved = true;
+
+ return lastReparentedStack;
+ }
+
+
+ @Override
+ void dump(PrintWriter pw, String prefix, boolean dumpAll) {
+ pw.println(prefix + "TaskDisplayArea " + getName());
+ if (mPreferredTopFocusableStack != null) {
+ pw.println(prefix + " mPreferredTopFocusableStack=" + mPreferredTopFocusableStack);
+ }
+ if (mLastFocusedStack != null) {
+ pw.println(prefix + " mLastFocusedStack=" + mLastFocusedStack);
+ }
+ pw.println(prefix + " Application tokens in top down Z order:");
+ for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+ final ActivityStack stack = getChildAt(stackNdx);
+ stack.dump(pw, prefix + " ", dumpAll);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index e6757e1..da4401a 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -705,14 +705,19 @@
private void adjustBoundsToAvoidConflictInDisplay(@NonNull DisplayContent display,
@NonNull Rect inOutBounds) {
final List<Rect> taskBoundsToCheck = new ArrayList<>();
- for (int i = 0; i < display.getStackCount(); ++i) {
- final ActivityStack stack = display.getStackAt(i);
- if (!stack.inFreeformWindowingMode()) {
- continue;
- }
+ int numTaskContainers = display.getTaskDisplayAreaCount();
+ for (int tdaNdx = 0; tdaNdx < numTaskContainers; tdaNdx++) {
+ final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+ int numStacks = taskDisplayArea.getStackCount();
+ for (int sNdx = 0; sNdx < numStacks; ++sNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+ if (!stack.inFreeformWindowingMode()) {
+ continue;
+ }
- for (int j = 0; j < stack.getChildCount(); ++j) {
- taskBoundsToCheck.add(stack.getChildAt(j).getBounds());
+ for (int j = 0; j < stack.getChildCount(); ++j) {
+ taskBoundsToCheck.add(stack.getChildAt(j).getBounds());
+ }
}
}
adjustBoundsToAvoidConflict(display.getBounds(), taskBoundsToCheck, inOutBounds);
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 30fa052..75f2e1f 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -477,26 +477,27 @@
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
- TaskDisplayArea taskDisplayArea =
- mService.mRootWindowContainer.getDisplayContent(displayId).mTaskContainers;
- if (taskDisplayArea == null) {
+ TaskDisplayArea defaultTaskDisplayArea = mService.mRootWindowContainer
+ .getDisplayContent(displayId).getDefaultTaskDisplayArea();
+ if (defaultTaskDisplayArea == null) {
return;
}
Task task = token == null
? null : WindowContainer.fromBinder(token.asBinder()).asTask();
if (task == null) {
- taskDisplayArea.mLaunchRootTask = null;
+ defaultTaskDisplayArea.mLaunchRootTask = null;
return;
}
if (!task.mCreatedByOrganizer) {
throw new IllegalArgumentException("Attempt to set task not created by "
+ "organizer as launch root task=" + task);
}
- if (task.getDisplayArea() != taskDisplayArea) {
+ if (task.getDisplayArea() == null
+ || task.getDisplayArea().getDisplayId() != displayId) {
throw new RuntimeException("Can't set launch root for display " + displayId
+ " to task on display " + task.getDisplayContent().getDisplayId());
}
- taskDisplayArea.mLaunchRootTask = task;
+ task.getDisplayArea().mLaunchRootTask = task;
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -557,13 +558,16 @@
throw new IllegalArgumentException("Display " + displayId + " doesn't exist");
}
ArrayList<RunningTaskInfo> out = new ArrayList<>();
- for (int i = dc.getStackCount() - 1; i >= 0; --i) {
- final Task task = dc.getStackAt(i);
- if (activityTypes != null
- && !ArrayUtils.contains(activityTypes, task.getActivityType())) {
- continue;
+ for (int tdaNdx = dc.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final TaskDisplayArea taskDisplayArea = dc.getTaskDisplayAreaAt(tdaNdx);
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ final Task task = taskDisplayArea.getStackAt(sNdx);
+ if (activityTypes != null
+ && !ArrayUtils.contains(activityTypes, task.getActivityType())) {
+ continue;
+ }
+ out.add(task.getTaskInfo());
}
- out.add(task.getTaskInfo());
}
return out;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 687af64..a1e0eb7 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -5317,7 +5317,8 @@
throw new IllegalArgumentException(
"Requested window " + client + " does not exist");
}
- ProtoLog.w(WM_ERROR, "Failed looking up window callers=%s", Debug.getCallers(3));
+ ProtoLog.w(WM_ERROR, "Failed looking up window session=%s callers=%s", session,
+ Debug.getCallers(3));
return null;
}
if (session != null && win.mSession != session) {
@@ -5325,7 +5326,8 @@
throw new IllegalArgumentException("Requested window " + client + " is in session "
+ win.mSession + ", not " + session);
}
- ProtoLog.w(WM_ERROR, "Failed looking up window callers=%s", Debug.getCallers(3));
+ ProtoLog.w(WM_ERROR, "Failed looking up window session=%s callers=%s", session,
+ Debug.getCallers(3));
return null;
}
@@ -6049,11 +6051,21 @@
pw.print(" mHasPermanentDpad="); pw.println(mHasPermanentDpad);
mRoot.dumpTopFocusedDisplayId(pw);
mRoot.forAllDisplays(dc -> {
+ final int displayId = dc.getDisplayId();
final WindowState inputMethodTarget = dc.mInputMethodTarget;
if (inputMethodTarget != null) {
- pw.print(" mInputMethodTarget in display# "); pw.print(dc.getDisplayId());
+ pw.print(" mInputMethodTarget in display# "); pw.print(displayId);
pw.print(' '); pw.println(inputMethodTarget);
}
+ if (mAccessibilityController != null) {
+ final Region magnificationRegion = new Region();
+ mAccessibilityController.getMagnificationRegionLocked(displayId,
+ magnificationRegion);
+ pw.print(" mMagnificationRegion in display# ");
+ pw.print(displayId);
+ pw.print(' ');
+ pw.println(magnificationRegion);
+ }
});
pw.print(" mInTouchMode="); pw.println(mInTouchMode);
pw.print(" mLastDisplayFreezeDuration=");
@@ -7318,7 +7330,7 @@
@Override
public boolean isStackVisibleLw(int windowingMode) {
- // TODO(multi-display-area): Support multiple task display areas & displays
+ // TODO(b/153090332): Support multiple task display areas & displays
final TaskDisplayArea tc = mRoot.getDefaultTaskDisplayArea();
return tc.isStackVisible(windowingMode);
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 8e7585a..9baa126 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -3439,13 +3439,23 @@
getMergedConfiguration(mLastReportedConfiguration);
mLastConfigReportedToClient = true;
+ final boolean reportOrientation = mReportOrientationChanged;
+ // Always reset these states first, so if {@link IWindow#resized} fails, this
+ // window won't be added to {@link WindowManagerService#mResizingWindows} and set
+ // {@link #mOrientationChanging} to true again by {@link #updateResizingWindowIfNeeded}
+ // that may cause WINDOW_FREEZE_TIMEOUT because resizing the client keeps failing.
+ mReportOrientationChanged = false;
+ mDragResizingChangeReported = true;
+ mWinAnimator.mSurfaceResized = false;
+ mWindowFrames.resetInsetsChanged();
+
final Rect frame = mWindowFrames.mCompatFrame;
final Rect contentInsets = mWindowFrames.mLastContentInsets;
final Rect visibleInsets = mWindowFrames.mLastVisibleInsets;
final Rect stableInsets = mWindowFrames.mLastStableInsets;
final MergedConfiguration mergedConfiguration = mLastReportedConfiguration;
final boolean reportDraw = mWinAnimator.mDrawState == DRAW_PENDING;
- final boolean forceRelayout = mReportOrientationChanged || isDragResizeChanged();
+ final boolean forceRelayout = reportOrientation || isDragResizeChanged();
final int displayId = getDisplayId();
final DisplayCutout displayCutout = getWmDisplayCutout().getDisplayCutout();
@@ -3454,25 +3464,17 @@
mergedConfiguration, getBackdropFrame(frame), forceRelayout,
getDisplayContent().getDisplayPolicy().areSystemBarsForcedShownLw(this),
displayId, new DisplayCutout.ParcelableWrapper(displayCutout));
- mDragResizingChangeReported = true;
if (mWmService.mAccessibilityController != null) {
mWmService.mAccessibilityController.onSomeWindowResizedOrMovedLocked(displayId);
}
updateLocationInParentDisplayIfNeeded();
-
- mWindowFrames.resetInsetsChanged();
- mWinAnimator.mSurfaceResized = false;
- mReportOrientationChanged = false;
} catch (RemoteException e) {
+ // Cancel orientation change of this window to avoid blocking unfreeze display.
setOrientationChanging(false);
mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
- mWmService.mDisplayFreezeTime);
- // We are assuming the hosting process is dead or in a zombie state.
- Slog.w(TAG, "Failed to report 'resized' to the client of " + this
- + ", removing this window.");
- mWmService.mPendingRemove.add(this);
- mWmService.mWindowPlacerLocked.requestTraversal();
+ Slog.w(TAG, "Failed to report 'resized' to " + this + " due to " + e);
}
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index eed39e1..d1c47d9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -87,6 +87,9 @@
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
+import static android.os.UserManagerInternal.OWNER_TYPE_DEVICE_OWNER;
+import static android.os.UserManagerInternal.OWNER_TYPE_PROFILE_OWNER;
+import static android.os.UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE;
import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
import static android.provider.Telephony.Carriers.DPC_URI;
@@ -284,6 +287,7 @@
import com.android.server.devicepolicy.DevicePolicyManagerService.ActiveAdmin.TrustAgentInfo;
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.net.NetworkPolicyManagerInternal;
+import com.android.server.pm.RestrictionsSet;
import com.android.server.pm.UserRestrictionsUtils;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.storage.DeviceStorageMonitorInternal;
@@ -322,6 +326,7 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
+import java.util.function.Predicate;
/**
* Implementation of the device policy APIs.
@@ -1828,6 +1833,50 @@
info = deviceAdminInfo;
}
+ Bundle addSyntheticRestrictions(Bundle restrictions) {
+ if (disableCamera) {
+ restrictions.putBoolean(UserManager.DISALLOW_CAMERA, true);
+ } else {
+ restrictions.remove(UserManager.DISALLOW_CAMERA);
+ }
+ return restrictions;
+ }
+
+ static Bundle removeDeprecatedRestrictions(Bundle restrictions) {
+ for (String deprecatedRestriction: DEPRECATED_USER_RESTRICTIONS) {
+ restrictions.remove(deprecatedRestriction);
+ }
+ return restrictions;
+ }
+
+ static Bundle filterRestrictions(Bundle restrictions, Predicate<String> filter) {
+ Bundle result = new Bundle();
+ for (String key : restrictions.keySet()) {
+ if (!restrictions.getBoolean(key)) {
+ continue;
+ }
+ if (filter.test(key)) {
+ result.putBoolean(key, true);
+ }
+ }
+ return result;
+ }
+
+ Bundle getEffectiveRestrictions() {
+ return addSyntheticRestrictions(
+ removeDeprecatedRestrictions(ensureUserRestrictions()));
+ }
+
+ Bundle getLocalUserRestrictions(int adminType) {
+ return filterRestrictions(getEffectiveRestrictions(),
+ key -> UserRestrictionsUtils.isLocal(adminType, key));
+ }
+
+ Bundle getGlobalUserRestrictions(int adminType) {
+ return filterRestrictions(getEffectiveRestrictions(),
+ key -> UserRestrictionsUtils.isGlobal(adminType, key));
+ }
+
void dump(IndentingPrintWriter pw) {
pw.print("uid="); pw.println(getUid());
pw.print("testOnlyAdmin=");
@@ -2772,7 +2821,7 @@
Settings.Secure.UNKNOWN_SOURCES_DEFAULT_REVERSED, 0, userId) != 0) {
profileOwner.ensureUserRestrictions().putBoolean(
UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true);
- saveUserRestrictionsLocked(userId, /* parent = */ false);
+ saveUserRestrictionsLocked(userId);
mInjector.settingsSecurePutIntForUser(
Settings.Secure.UNKNOWN_SOURCES_DEFAULT_REVERSED, 0, userId);
}
@@ -2803,7 +2852,7 @@
}
admin.defaultEnabledRestrictionsAlreadySet.addAll(restrictionsToSet);
Slog.i(LOG_TAG, "Enabled the following restrictions by default: " + restrictionsToSet);
- saveUserRestrictionsLocked(userId, /* parent = */ false);
+ saveUserRestrictionsLocked(userId);
}
}
@@ -8222,9 +8271,9 @@
}
}
// Tell the user manager that the restrictions have changed.
- final int affectedUserId = parent ? getProfileParentId(userHandle) : userHandle;
- pushUserRestrictions(affectedUserId);
+ pushUserRestrictions(userHandle);
+ final int affectedUserId = parent ? getProfileParentId(userHandle) : userHandle;
if (SecurityLog.isLoggingEnabled()) {
SecurityLog.writeEvent(SecurityLog.TAG_CAMERA_POLICY_SET,
who.getPackageName(), userHandle, affectedUserId, disabled ? 1 : 0);
@@ -10806,10 +10855,14 @@
"Cannot use the parent instance in Device Owner mode");
}
} else {
- if (!(UserRestrictionsUtils.canProfileOwnerChange(key, userHandle) || (
- isProfileOwnerOfOrganizationOwnedDevice(activeAdmin) && parent
- && UserRestrictionsUtils.canProfileOwnerOfOrganizationOwnedDeviceChange(
- key)))) {
+ boolean profileOwnerCanChangeOnItself = !parent
+ && UserRestrictionsUtils.canProfileOwnerChange(key, userHandle);
+ boolean orgOwnedProfileOwnerCanChangesGlobally = parent
+ && isProfileOwnerOfOrganizationOwnedDevice(activeAdmin)
+ && UserRestrictionsUtils
+ .canProfileOwnerOfOrganizationOwnedDeviceChange(key);
+
+ if (!profileOwnerCanChangeOnItself && !orgOwnedProfileOwnerCanChangesGlobally) {
throw new SecurityException("Profile owner cannot set user restriction " + key);
}
}
@@ -10821,7 +10874,7 @@
} else {
restrictions.remove(key);
}
- saveUserRestrictionsLocked(userHandle, parent);
+ saveUserRestrictionsLocked(userHandle);
}
final int eventId = enabledFromThisOwner
? DevicePolicyEnums.ADD_USER_RESTRICTION
@@ -10839,91 +10892,65 @@
}
}
- private void saveUserRestrictionsLocked(int userId, boolean parent) {
+ private void saveUserRestrictionsLocked(int userId) {
saveSettingsLocked(userId);
- pushUserRestrictions(parent ? getProfileParentId(userId) : userId);
+ pushUserRestrictions(userId);
sendChangedNotification(userId);
}
- private void pushUserRestrictions(int userId) {
+ /**
+ * Pushes the user restrictions originating from a specific user.
+ *
+ * If called by the profile owner of an organization-owned device, the global and local
+ * user restrictions will be an accumulation of the global user restrictions from the profile
+ * owner active admin and its parent active admin. The key of the local user restrictions set
+ * will be the target user id.
+ */
+ private void pushUserRestrictions(int originatingUserId) {
+ final Bundle global;
+ final RestrictionsSet local = new RestrictionsSet();
+ final boolean isDeviceOwner;
synchronized (getLockObject()) {
- final boolean isDeviceOwner = mOwners.isDeviceOwnerUserId(userId);
- Bundle userRestrictions = null;
- final int restrictionOwnerType;
- final int originatingUserId;
-
+ isDeviceOwner = mOwners.isDeviceOwnerUserId(originatingUserId);
if (isDeviceOwner) {
final ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
if (deviceOwner == null) {
return; // Shouldn't happen.
}
- userRestrictions = addOrRemoveDisableCameraRestriction(
- deviceOwner.userRestrictions, deviceOwner);
- restrictionOwnerType = UserManagerInternal.OWNER_TYPE_DEVICE_OWNER;
- originatingUserId = deviceOwner.getUserHandle().getIdentifier();
+ global = deviceOwner.getGlobalUserRestrictions(OWNER_TYPE_DEVICE_OWNER);
+ local.updateRestrictions(originatingUserId, deviceOwner.getLocalUserRestrictions(
+ OWNER_TYPE_DEVICE_OWNER));
} else {
- final ActiveAdmin profileOwnerOfOrganizationOwnedDevice =
- getProfileOwnerOfOrganizationOwnedDeviceLocked(userId);
-
- // If profile owner of an organization owned device, the restrictions will be
- // pushed to the parent instance.
- if (profileOwnerOfOrganizationOwnedDevice != null && !isManagedProfile(userId)) {
- restrictionOwnerType =
- UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE;
- final ActiveAdmin parent = profileOwnerOfOrganizationOwnedDevice
- .getParentActiveAdmin();
- userRestrictions = parent.userRestrictions;
- userRestrictions = addOrRemoveDisableCameraRestriction(userRestrictions,
- parent);
- originatingUserId =
- profileOwnerOfOrganizationOwnedDevice.getUserHandle().getIdentifier();
- } else {
- final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userId);
-
- if (profileOwner != null) {
- userRestrictions = profileOwner.userRestrictions;
- restrictionOwnerType = UserManagerInternal.OWNER_TYPE_PROFILE_OWNER;
- originatingUserId = profileOwner.getUserHandle().getIdentifier();
- } else {
- restrictionOwnerType = UserManagerInternal.OWNER_TYPE_NO_OWNER;
- originatingUserId = userId;
- }
- userRestrictions = addOrRemoveDisableCameraRestriction(
- userRestrictions, userId);
+ final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(originatingUserId);
+ if (profileOwner == null) {
+ return;
+ }
+ global = profileOwner.getGlobalUserRestrictions(OWNER_TYPE_PROFILE_OWNER);
+ local.updateRestrictions(originatingUserId, profileOwner.getLocalUserRestrictions(
+ OWNER_TYPE_PROFILE_OWNER));
+ // Global (device-wide) and local user restrictions set by the profile owner of an
+ // organization-owned device are stored in the parent ActiveAdmin instance.
+ if (isProfileOwnerOfOrganizationOwnedDevice(
+ profileOwner.getUserHandle().getIdentifier())) {
+ // The global restrictions set on the parent ActiveAdmin instance need to be
+ // merged with the global restrictions set on the profile owner ActiveAdmin
+ // instance, since both are to be applied device-wide.
+ UserRestrictionsUtils.merge(global,
+ profileOwner.getParentActiveAdmin().getGlobalUserRestrictions(
+ OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE));
+ // The local restrictions set on the parent ActiveAdmin instance are only to be
+ // applied to the primary user. They therefore need to be added the local
+ // restriction set with the primary user id as the key, in this case the
+ // primary user id is the target user.
+ local.updateRestrictions(
+ getProfileParentId(profileOwner.getUserHandle().getIdentifier()),
+ profileOwner.getParentActiveAdmin().getLocalUserRestrictions(
+ OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE));
}
}
- // Remove deprecated restrictions.
- for (String deprecatedRestriction: DEPRECATED_USER_RESTRICTIONS) {
- userRestrictions.remove(deprecatedRestriction);
- }
- mUserManagerInternal.setDevicePolicyUserRestrictions(originatingUserId,
- userRestrictions, restrictionOwnerType);
}
- }
-
- private Bundle addOrRemoveDisableCameraRestriction(Bundle userRestrictions, ActiveAdmin admin) {
- if (userRestrictions == null) {
- userRestrictions = new Bundle();
- }
- if (admin.disableCamera) {
- userRestrictions.putBoolean(UserManager.DISALLOW_CAMERA, true);
- } else {
- userRestrictions.remove(UserManager.DISALLOW_CAMERA);
- }
- return userRestrictions;
- }
-
- private Bundle addOrRemoveDisableCameraRestriction(Bundle userRestrictions, int userId) {
- if (userRestrictions == null) {
- userRestrictions = new Bundle();
- }
- if (getCameraDisabled(/* who= */ null, userId, /* mergeDeviceOwnerRestriction= */
- false)) {
- userRestrictions.putBoolean(UserManager.DISALLOW_CAMERA, true);
- } else {
- userRestrictions.remove(UserManager.DISALLOW_CAMERA);
- }
- return userRestrictions;
+ mUserManagerInternal.setDevicePolicyUserRestrictions(originatingUserId, global, local,
+ isDeviceOwner);
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index fe47cea..d780370 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -83,7 +83,6 @@
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
-import android.os.UserManagerInternal;
import android.platform.test.annotations.Presubmit;
import android.provider.Settings;
import android.security.KeyChain;
@@ -1170,7 +1169,6 @@
() -> dpm.clearDeviceOwnerApp(admin1.getPackageName()));
when(getServices().userManager.isUserUnlocked(anyInt())).thenReturn(true);
- reset(getServices().userManagerInternal);
dpm.clearDeviceOwnerApp(admin1.getPackageName());
// Now DO shouldn't be set.
@@ -1181,9 +1179,8 @@
MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
- eq(UserHandle.USER_SYSTEM),
- MockUtils.checkUserRestrictions(),
- eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
+ eq(UserHandle.USER_SYSTEM), MockUtils.checkUserRestrictions(),
+ MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM), eq(true));
verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
null, UserHandle.USER_SYSTEM);
@@ -1745,15 +1742,16 @@
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER),
- eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
+ MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM), eq(true));
reset(getServices().userManagerInternal);
dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
- MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS,
- UserManager.DISALLOW_ADD_USER),
- eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
+ MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER),
+ MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM,
+ UserManager.DISALLOW_OUTGOING_CALLS),
+ eq(true));
reset(getServices().userManagerInternal);
DpmTestUtils.assertRestrictions(
@@ -1770,8 +1768,10 @@
dpm.clearUserRestriction(admin1, UserManager.DISALLOW_ADD_USER);
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
- MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
- eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
+ MockUtils.checkUserRestrictions(),
+ MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM,
+ UserManager.DISALLOW_OUTGOING_CALLS),
+ eq(true));
reset(getServices().userManagerInternal);
DpmTestUtils.assertRestrictions(
@@ -1787,7 +1787,7 @@
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
MockUtils.checkUserRestrictions(),
- eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
+ MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM), eq(true));
reset(getServices().userManagerInternal);
assertNoDeviceOwnerRestrictions();
@@ -1801,7 +1801,7 @@
eq(UserHandle.USER_SYSTEM),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME,
UserManager.DISALLOW_UNMUTE_MICROPHONE),
- eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
+ MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM), eq(true));
reset(getServices().userManagerInternal);
dpm.clearUserRestriction(admin1, UserManager.DISALLOW_ADJUST_VOLUME);
@@ -1813,7 +1813,7 @@
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER),
- eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
+ MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM), eq(true));
reset(getServices().userManagerInternal);
dpm.addUserRestriction(admin1, UserManager.DISALLOW_FUN);
@@ -1821,7 +1821,7 @@
eq(UserHandle.USER_SYSTEM),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
UserManager.DISALLOW_ADD_USER),
- eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
+ MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM), eq(true));
reset(getServices().userManagerInternal);
dpm.setCameraDisabled(admin1, true);
@@ -1830,7 +1830,7 @@
// DISALLOW_CAMERA will be applied globally.
MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
UserManager.DISALLOW_ADD_USER, UserManager.DISALLOW_CAMERA),
- eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
+ MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM), eq(true));
reset(getServices().userManagerInternal);
}
@@ -1887,17 +1887,19 @@
dpm.addUserRestriction(admin1, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
eq(DpmMockContext.CALLER_USER_HANDLE),
- MockUtils.checkUserRestrictions(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES),
- eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER));
- reset(getServices().userManagerInternal);
+ MockUtils.checkUserRestrictions(),
+ MockUtils.checkUserRestrictions(DpmMockContext.CALLER_USER_HANDLE,
+ UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES),
+ eq(false));
dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
eq(DpmMockContext.CALLER_USER_HANDLE),
- MockUtils.checkUserRestrictions(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
+ MockUtils.checkUserRestrictions(),
+ MockUtils.checkUserRestrictions(DpmMockContext.CALLER_USER_HANDLE,
+ UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
UserManager.DISALLOW_OUTGOING_CALLS),
- eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER));
- reset(getServices().userManagerInternal);
+ eq(false));
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(
@@ -1918,9 +1920,10 @@
dpm.clearUserRestriction(admin1, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
eq(DpmMockContext.CALLER_USER_HANDLE),
- MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
- eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER));
- reset(getServices().userManagerInternal);
+ MockUtils.checkUserRestrictions(),
+ MockUtils.checkUserRestrictions(DpmMockContext.CALLER_USER_HANDLE,
+ UserManager.DISALLOW_OUTGOING_CALLS),
+ eq(false));
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(
@@ -1940,8 +1943,7 @@
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
eq(DpmMockContext.CALLER_USER_HANDLE),
MockUtils.checkUserRestrictions(),
- eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER));
- reset(getServices().userManagerInternal);
+ MockUtils.checkUserRestrictions(DpmMockContext.CALLER_USER_HANDLE), eq(false));
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(),
@@ -1956,21 +1958,25 @@
// DISALLOW_ADJUST_VOLUME and DISALLOW_UNMUTE_MICROPHONE can be set by PO too, even
// though when DO sets them they'll be applied globally.
dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADJUST_VOLUME);
- reset(getServices().userManagerInternal);
+
dpm.addUserRestriction(admin1, UserManager.DISALLOW_UNMUTE_MICROPHONE);
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
eq(DpmMockContext.CALLER_USER_HANDLE),
- MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME,
+ MockUtils.checkUserRestrictions(),
+ MockUtils.checkUserRestrictions(DpmMockContext.CALLER_USER_HANDLE,
+ UserManager.DISALLOW_ADJUST_VOLUME,
UserManager.DISALLOW_UNMUTE_MICROPHONE),
- eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER));
- reset(getServices().userManagerInternal);
+ eq(false));
dpm.setCameraDisabled(admin1, true);
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
eq(DpmMockContext.CALLER_USER_HANDLE),
- MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME,
- UserManager.DISALLOW_UNMUTE_MICROPHONE, UserManager.DISALLOW_CAMERA),
- eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER));
+ MockUtils.checkUserRestrictions(),
+ MockUtils.checkUserRestrictions(DpmMockContext.CALLER_USER_HANDLE,
+ UserManager.DISALLOW_ADJUST_VOLUME,
+ UserManager.DISALLOW_UNMUTE_MICROPHONE,
+ UserManager.DISALLOW_CAMERA),
+ eq(false));
reset(getServices().userManagerInternal);
// TODO Make sure restrictions are written to the file.
@@ -2004,15 +2010,14 @@
);
public void testSetUserRestriction_asPoOfOrgOwnedDevice() throws Exception {
- final int MANAGED_PROFILE_USER_ID = DpmMockContext.CALLER_USER_HANDLE;
final int MANAGED_PROFILE_ADMIN_UID =
- UserHandle.getUid(MANAGED_PROFILE_USER_ID, DpmMockContext.SYSTEM_UID);
+ UserHandle.getUid(DpmMockContext.CALLER_USER_HANDLE, DpmMockContext.SYSTEM_UID);
mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
- when(getServices().userManager.getProfileParent(MANAGED_PROFILE_USER_ID))
+ when(getServices().userManager.getProfileParent(DpmMockContext.CALLER_USER_HANDLE))
.thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
for (String restriction : PROFILE_OWNER_ORGANIZATION_OWNED_GLOBAL_RESTRICTIONS) {
@@ -2021,16 +2026,20 @@
parentDpm.setCameraDisabled(admin1, true);
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
- eq(MANAGED_PROFILE_USER_ID),
+ eq(DpmMockContext.CALLER_USER_HANDLE),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA),
- eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE));
- reset(getServices().userManagerInternal);
+ MockUtils.checkUserRestrictions(DpmMockContext.CALLER_USER_HANDLE),
+ eq(false));
+ DpmTestUtils.assertRestrictions(
+ DpmTestUtils.newRestrictions(UserManager.DISALLOW_CAMERA),
+ parentDpm.getUserRestrictions(admin1)
+ );
parentDpm.setCameraDisabled(admin1, false);
- verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
- eq(MANAGED_PROFILE_USER_ID),
- MockUtils.checkUserRestrictions(),
- eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE));
+ DpmTestUtils.assertRestrictions(
+ DpmTestUtils.newRestrictions(),
+ parentDpm.getUserRestrictions(admin1)
+ );
reset(getServices().userManagerInternal);
}
@@ -2039,13 +2048,13 @@
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
eq(DpmMockContext.CALLER_USER_HANDLE),
MockUtils.checkUserRestrictions(restriction),
- eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE));
+ MockUtils.checkUserRestrictions(DpmMockContext.CALLER_USER_HANDLE),
+ eq(false));
parentDpm.clearUserRestriction(admin1, restriction);
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(),
parentDpm.getUserRestrictions(admin1)
);
- reset(getServices().userManagerInternal);
}
public void testNoDefaultEnabledUserRestrictions() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
index 09a6819..15f3ed1 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
@@ -15,10 +15,6 @@
*/
package com.android.server.devicepolicy;
-import com.google.common.base.Objects;
-
-import com.android.server.pm.UserRestrictionsUtils;
-
import android.content.ComponentName;
import android.content.Intent;
import android.os.BaseBundle;
@@ -26,6 +22,11 @@
import android.os.UserHandle;
import android.util.ArraySet;
+import com.android.server.pm.RestrictionsSet;
+import com.android.server.pm.UserRestrictionsUtils;
+
+import com.google.common.base.Objects;
+
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
@@ -106,11 +107,14 @@
}
public static Bundle checkUserRestrictions(String... keys) {
- final Bundle expected = DpmTestUtils.newRestrictions(java.util.Objects.requireNonNull(keys));
+ final Bundle expected = DpmTestUtils.newRestrictions(
+ java.util.Objects.requireNonNull(keys));
final Matcher<Bundle> m = new BaseMatcher<Bundle>() {
@Override
public boolean matches(Object item) {
- if (item == null) return false;
+ if (item == null) {
+ return false;
+ }
return UserRestrictionsUtils.areEqual((Bundle) item, expected);
}
@@ -122,6 +126,26 @@
return MockitoHamcrest.argThat(m);
}
+ public static RestrictionsSet checkUserRestrictions(int userId, String... keys) {
+ final RestrictionsSet expected = DpmTestUtils.newRestrictions(userId,
+ java.util.Objects.requireNonNull(keys));
+ final Matcher<RestrictionsSet> m = new BaseMatcher<RestrictionsSet>() {
+ @Override
+ public boolean matches(Object item) {
+ if (item == null) return false;
+ RestrictionsSet actual = (RestrictionsSet) item;
+ return UserRestrictionsUtils.areEqual(expected.getRestrictions(userId),
+ actual.getRestrictions(userId));
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("User restrictions=" + getRestrictionsAsString(expected));
+ }
+ };
+ return MockitoHamcrest.argThat(m);
+ }
+
public static Set<String> checkApps(String... adminApps) {
final Matcher<Set<String>> m = new BaseMatcher<Set<String>>() {
@Override
@@ -146,6 +170,23 @@
return MockitoHamcrest.argThat(m);
}
+ private static String getRestrictionsAsString(RestrictionsSet r) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("{");
+
+ if (r != null) {
+ String sep = "";
+ for (int i = 0; i < r.size(); i++) {
+ sb.append(sep);
+ sep = ",";
+ sb.append(
+ String.format("%s= %s", r.keyAt(i), getRestrictionsAsString(r.valueAt(i))));
+ }
+ }
+ sb.append("}");
+ return sb.toString();
+ }
+
private static String getRestrictionsAsString(Bundle b) {
final StringBuilder sb = new StringBuilder();
sb.append("[");
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
index 1c2313e..dc181a9 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
@@ -22,7 +22,6 @@
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
-import android.os.UserManagerInternal;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.SparseArray;
@@ -118,135 +117,6 @@
UserManager.DISALLOW_ADJUST_VOLUME, user));
}
- public void testSortToGlobalAndLocal() {
- final Bundle local = new Bundle();
- final Bundle global = new Bundle();
-
- UserRestrictionsUtils.sortToGlobalAndLocal(null,
- UserManagerInternal.OWNER_TYPE_PROFILE_OWNER,
- global, local);
- assertEquals(0, global.size());
- assertEquals(0, local.size());
-
- UserRestrictionsUtils.sortToGlobalAndLocal(Bundle.EMPTY,
- UserManagerInternal.OWNER_TYPE_PROFILE_OWNER,
- global, local);
- assertEquals(0, global.size());
- assertEquals(0, local.size());
-
- // Restrictions set by DO.
- UserRestrictionsUtils.sortToGlobalAndLocal(newRestrictions(
- UserManager.DISALLOW_ADJUST_VOLUME,
- UserManager.DISALLOW_UNMUTE_MICROPHONE,
- UserManager.DISALLOW_USB_FILE_TRANSFER,
- UserManager.DISALLOW_CONFIG_TETHERING,
- UserManager.DISALLOW_OUTGOING_BEAM,
- UserManager.DISALLOW_APPS_CONTROL,
- UserManager.ENSURE_VERIFY_APPS,
- UserManager.DISALLOW_CAMERA
- ), UserManagerInternal.OWNER_TYPE_DEVICE_OWNER,
- global, local);
-
-
- assertRestrictions(newRestrictions(
- // This one is global no matter who sets it.
- UserManager.ENSURE_VERIFY_APPS,
-
- // These can be set by PO too, but when DO sets them, they're global.
- UserManager.DISALLOW_ADJUST_VOLUME,
- UserManager.DISALLOW_UNMUTE_MICROPHONE,
-
- // These can only be set by DO.
- UserManager.DISALLOW_USB_FILE_TRANSFER,
- UserManager.DISALLOW_CONFIG_TETHERING,
-
- // This can be set by DO or PO of organisation owned device
- UserManager.DISALLOW_CAMERA
- ), global);
-
- assertRestrictions(newRestrictions(
- // They can be set by both DO/PO.
- UserManager.DISALLOW_OUTGOING_BEAM,
- UserManager.DISALLOW_APPS_CONTROL
- ), local);
-
- local.clear();
- global.clear();
-
- // Restrictions set by PO.
- UserRestrictionsUtils.sortToGlobalAndLocal(newRestrictions(
- UserManager.DISALLOW_ADJUST_VOLUME,
- UserManager.DISALLOW_UNMUTE_MICROPHONE,
- UserManager.DISALLOW_USB_FILE_TRANSFER,
- UserManager.DISALLOW_CONFIG_TETHERING,
- UserManager.DISALLOW_OUTGOING_BEAM,
- UserManager.DISALLOW_APPS_CONTROL,
- UserManager.ENSURE_VERIFY_APPS,
- UserManager.DISALLOW_CAMERA
- ), UserManagerInternal.OWNER_TYPE_PROFILE_OWNER,
- global, local);
-
- assertRestrictions(newRestrictions(
- // This one is global no matter who sets it.
- UserManager.ENSURE_VERIFY_APPS
- ), global);
-
- assertRestrictions(newRestrictions(
- // These can be set by PO too, but when PO sets them, they're local.
- UserManager.DISALLOW_ADJUST_VOLUME,
- UserManager.DISALLOW_UNMUTE_MICROPHONE,
-
- // They can be set by both DO/PO.
- UserManager.DISALLOW_OUTGOING_BEAM,
- UserManager.DISALLOW_APPS_CONTROL,
-
- // These can only be set by DO.
- UserManager.DISALLOW_USB_FILE_TRANSFER,
- UserManager.DISALLOW_CONFIG_TETHERING,
-
- // This can be set by DO or PO of organisation owned device
- UserManager.DISALLOW_CAMERA
- ), local);
-
- local.clear();
- global.clear();
-
- // Restrictions set by PO of organisation owned device
- UserRestrictionsUtils.sortToGlobalAndLocal(newRestrictions(
- UserManager.DISALLOW_CONFIG_DATE_TIME
- ), UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE,
- global, local);
-
- assertRestrictions(newRestrictions(
- // This user restriction is global when set by PO of org owned device
- UserManager.DISALLOW_CONFIG_DATE_TIME
- ), global);
- assertEquals(0, local.size());
- }
-
- public void testSortToLocalAndGlobalWithCameraDisabled() {
- final Bundle local = new Bundle();
- final Bundle global = new Bundle();
-
- UserRestrictionsUtils.sortToGlobalAndLocal(newRestrictions(UserManager.DISALLOW_CAMERA),
- UserManagerInternal.OWNER_TYPE_DEVICE_OWNER, global, local);
- assertRestrictions(newRestrictions(UserManager.DISALLOW_CAMERA), global);
- assertEquals(0, local.size());
- global.clear();
-
- UserRestrictionsUtils.sortToGlobalAndLocal(newRestrictions(UserManager.DISALLOW_CAMERA),
- UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE, global,
- local);
- assertRestrictions(newRestrictions(UserManager.DISALLOW_CAMERA), global);
- assertEquals(0, local.size());
- global.clear();
-
- UserRestrictionsUtils.sortToGlobalAndLocal(newRestrictions(UserManager.DISALLOW_CAMERA),
- UserManagerInternal.OWNER_TYPE_PROFILE_OWNER, global, local);
- assertEquals(0, global.size());
- assertRestrictions(newRestrictions(UserManager.DISALLOW_CAMERA), local);
- }
-
public void testMoveRestriction() {
SparseArray<RestrictionsSet> localRestrictions = new SparseArray<>();
RestrictionsSet globalRestrictions = new RestrictionsSet();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 1cca207..bdba4b6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -495,9 +495,12 @@
}
private void assertNoTasks(DisplayContent display) {
- for (int i = display.getStackCount() - 1; i >= 0; --i) {
- final ActivityStack stack = display.getStackAt(i);
- assertFalse(stack.hasChild());
+ for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+ assertFalse(stack.hasChild());
+ }
}
}
@@ -1042,10 +1045,14 @@
// move everything to secondary because test expects this but usually sysui
// does it.
DisplayContent dc = mService.mRootWindowContainer.getDisplayContent(mDisplayId);
- for (int i = dc.getStackCount() - 1; i >= 0; --i) {
- if (!WindowConfiguration.isSplitScreenWindowingMode(
- dc.getStackAt(i).getWindowingMode())) {
- dc.getStackAt(i).reparent(mSecondary, POSITION_BOTTOM);
+ for (int tdaNdx = dc.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final TaskDisplayArea taskDisplayArea = dc.getTaskDisplayAreaAt(tdaNdx);
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+ if (!WindowConfiguration.isSplitScreenWindowingMode(
+ stack.getWindowingMode())) {
+ stack.reparent(mSecondary, POSITION_BOTTOM);
+ }
}
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index d9c3ace..add4e9c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -686,8 +686,8 @@
mRecentTasks.setOnlyTestVisibleRange();
mRecentTasks.setParameters(-1 /* min */, 3 /* max */, -1 /* ms */);
- final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
- final Task alwaysOnTopTask = display.createStack(WINDOWING_MODE_MULTI_WINDOW,
+ final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
+ final Task alwaysOnTopTask = taskDisplayArea.createStack(WINDOWING_MODE_MULTI_WINDOW,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
alwaysOnTopTask.setAlwaysOnTop(true);
@@ -862,8 +862,8 @@
final ActivityStack homeStack = mTaskContainer.getRootHomeTask();
final DisplayContent otherDisplay = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
- final ActivityStack otherDisplayStack = otherDisplay.createStack(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final ActivityStack otherDisplayStack = otherDisplay.getDefaultTaskDisplayArea()
+ .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
// Add a number of tasks (beyond the max) on each display, ensure that the tasks are not
// removed
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index 48d4e70..b648346 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -349,8 +349,8 @@
// Create Recents on secondary display.
final TestDisplayContent secondDisplay = addNewDisplayContentAt(
DisplayContent.POSITION_TOP);
- final ActivityStack stack = secondDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_RECENTS, true /* onTop */);
+ final ActivityStack stack = secondDisplay.getDefaultTaskDisplayArea()
+ .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS, true /* onTop */);
final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
new ActivityBuilder(mService).setTask(task).build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
index 2dbfd06..62d311a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
@@ -627,9 +627,12 @@
private List<Task> getTasksCreatedByOrganizer(DisplayContent dc) {
ArrayList<Task> out = new ArrayList<>();
- for (int i = dc.getStackCount() - 1; i >= 0; --i) {
- final Task t = dc.getStackAt(i);
- if (t.mCreatedByOrganizer) out.add(t);
+ for (int tdaNdx = dc.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final TaskDisplayArea taskDisplayArea = dc.getTaskDisplayAreaAt(tdaNdx);
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ final Task t = taskDisplayArea.getStackAt(sNdx);
+ if (t.mCreatedByOrganizer) out.add(t);
+ }
}
return out;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index 50584c6..519ac78 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -354,7 +354,7 @@
spyOn(parentWindowContainer);
parentWindowContainer.setBounds(fullScreenBounds);
doReturn(parentWindowContainer).when(task).getParent();
- doReturn(display.mTaskContainers).when(task).getDisplayArea();
+ doReturn(display.getDefaultTaskDisplayArea()).when(task).getDisplayArea();
doReturn(stack).when(task).getStack();
doReturn(true).when(parentWindowContainer).handlesOrientationChangeFromDescendant();
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 820d381..71b35b6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -40,6 +40,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doThrow;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
@@ -47,6 +48,8 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
@@ -55,6 +58,7 @@
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
@@ -65,6 +69,7 @@
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.util.Size;
import android.view.DisplayCutout;
@@ -568,6 +573,36 @@
}
@Test
+ public void testReportResizedWithRemoteException() {
+ final WindowState win = mChildAppWindowAbove;
+ makeWindowVisible(win, win.getParentWindow());
+ win.mLayoutSeq = win.getDisplayContent().mLayoutSeq;
+ win.updateResizingWindowIfNeeded();
+
+ assertThat(mWm.mResizingWindows).contains(win);
+ assertTrue(win.getOrientationChanging());
+
+ mWm.mResizingWindows.remove(win);
+ spyOn(win.mClient);
+ try {
+ doThrow(new RemoteException("test")).when(win.mClient).resized(any() /* frame */,
+ any() /* contentInsets */, any() /* visibleInsets */, any() /* stableInsets */,
+ anyBoolean() /* reportDraw */, any() /* mergedConfig */,
+ any() /* backDropFrame */, anyBoolean() /* forceLayout */,
+ anyBoolean() /* alwaysConsumeSystemBars */, anyInt() /* displayId */,
+ any() /* displayCutout */);
+ } catch (RemoteException ignored) {
+ }
+ win.reportResized();
+ win.updateResizingWindowIfNeeded();
+
+ // Even "resized" throws remote exception, it is still considered as reported. So the window
+ // shouldn't be resized again (which may block unfreeze in real case).
+ assertThat(mWm.mResizingWindows).doesNotContain(win);
+ assertFalse(win.getOrientationChanging());
+ }
+
+ @Test
public void testGetTransformationMatrix() {
final int PARENT_WINDOW_OFFSET = 1;
final int DISPLAY_IN_PARENT_WINDOW_OFFSET = 2;
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index 316a83a..6e9dc8e 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -55,6 +55,10 @@
import androidx.core.os.BuildCompat;
import androidx.test.runner.AndroidJUnit4;
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -67,6 +71,9 @@
private static final String TEST_SSID = "TEST_SSID";
private static final String DIFFERENT_TEST_SSID = "DIFFERENT_TEST_SSID";
+ @Rule
+ public DevSdkIgnoreRule mDevSdkIgnoreRule = new DevSdkIgnoreRule();
+
private boolean isAtLeastR() {
// BuildCompat.isAtLeastR() is used to check the Android version before releasing Android R.
// Build.VERSION.SDK_INT > Build.VERSION_CODES.Q is used to check the Android version after
@@ -441,7 +448,7 @@
return range;
}
- @Test
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
public void testSetAdministratorUids() {
NetworkCapabilities nc =
new NetworkCapabilities().setAdministratorUids(new int[] {2, 1, 3});
@@ -449,7 +456,7 @@
assertArrayEquals(new int[] {1, 2, 3}, nc.getAdministratorUids());
}
- @Test
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
public void testSetAdministratorUidsWithDuplicates() {
try {
new NetworkCapabilities().setAdministratorUids(new int[] {1, 1});
@@ -510,6 +517,12 @@
assertFalse(nc2.appliesToUid(12));
assertTrue(nc1.appliesToUid(22));
assertTrue(nc2.appliesToUid(22));
+ }
+
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+ public void testCombineCapabilities_AdministratorUids() {
+ final NetworkCapabilities nc1 = new NetworkCapabilities();
+ final NetworkCapabilities nc2 = new NetworkCapabilities();
final int[] adminUids = {3, 6, 12};
nc1.setAdministratorUids(adminUids);
@@ -518,7 +531,7 @@
assertArrayEquals(nc2.getAdministratorUids(), adminUids);
final int[] adminUidsOtherOrder = {3, 12, 6};
- nc1.setAdministratorUids(adminUids);
+ nc1.setAdministratorUids(adminUidsOtherOrder);
assertTrue(nc2.equalsAdministratorUids(nc1));
final int[] adminUids2 = {11, 1, 12, 3, 6};
diff --git a/tests/net/common/java/android/net/netstats/NetworkStatsApiTest.kt b/tests/net/common/java/android/net/netstats/NetworkStatsApiTest.kt
new file mode 100644
index 0000000..9119d62
--- /dev/null
+++ b/tests/net/common/java/android/net/netstats/NetworkStatsApiTest.kt
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.netstats
+
+import android.net.NetworkStats
+import android.net.NetworkStats.DEFAULT_NETWORK_NO
+import android.net.NetworkStats.DEFAULT_NETWORK_YES
+import android.net.NetworkStats.Entry
+import android.net.NetworkStats.IFACE_VT
+import android.net.NetworkStats.METERED_NO
+import android.net.NetworkStats.METERED_YES
+import android.net.NetworkStats.ROAMING_NO
+import android.net.NetworkStats.ROAMING_YES
+import android.net.NetworkStats.SET_DEFAULT
+import android.net.NetworkStats.SET_FOREGROUND
+import android.net.NetworkStats.TAG_NONE
+import android.os.Build
+import androidx.test.filters.SmallTest
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
+import com.android.testutils.assertFieldCountEquals
+import com.android.testutils.assertNetworkStatsEquals
+import com.android.testutils.assertParcelingIsLossless
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import kotlin.test.assertEquals
+
+@RunWith(JUnit4::class)
+@SmallTest
+class NetworkStatsApiTest {
+ @Rule
+ @JvmField
+ val ignoreRule = DevSdkIgnoreRule()
+
+ private val testStatsEmpty = NetworkStats(0L, 0)
+
+ // stats1 and stats2 will have some entries with common keys, which are expected to
+ // be merged if performing add on these 2 stats.
+ private val testStats1 = NetworkStats(0L, 0)
+ // Entries which only appear in set1.
+ .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 20, 3, 57, 40, 3))
+ .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
+ METERED_NO, ROAMING_YES, DEFAULT_NETWORK_NO, 31, 7, 24, 5, 8))
+ .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
+ METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 25, 3, 47, 8, 2))
+ .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 37, 52, 1, 10, 4))
+ // Entries which are common for set1 and set2.
+ .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 101, 2, 103, 4, 5))
+ .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 17, 2, 11, 1, 0))
+ .addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 40, 1, 0, 0, 8))
+ .addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 1, 6, 2, 0))
+
+ private val testStats2 = NetworkStats(0L, 0)
+ // Entries which are common for set1 and set2.
+ .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 15, 2, 31, 1))
+ .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 13, 61, 10, 1, 45))
+ .addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 11, 2, 3, 4, 7))
+ .addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 4, 3, 2, 1, 0))
+ // Entry which only appears in set2.
+ .addEntry(Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0))
+
+ // This is a result of adding stats1 and stats2, while the merging of common key items is
+ // subject to test later, this should not be initialized with for a loop to add stats1
+ // and stats2 above.
+ private val testStats3 = NetworkStats(0L, 9)
+ // Entries which are unique either in stats1 or stats2.
+ .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 101, 2, 103, 4, 5))
+ .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
+ METERED_NO, ROAMING_YES, DEFAULT_NETWORK_NO, 31, 7, 24, 5, 8))
+ .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
+ METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 25, 3, 47, 8, 2))
+ .addEntry(Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0))
+ // Entries which are common for stats1 and stats2 are being merged.
+ .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 20, 3, 57, 40, 3))
+ .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 20, 17, 13, 32, 1))
+ .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 50, 113, 11, 11, 49))
+ .addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 51, 3, 3, 4, 15))
+ .addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 7, 4, 8, 3, 0))
+
+ companion object {
+ private const val TEST_IFACE = "test0"
+ private const val TEST_UID1 = 1001
+ private const val TEST_UID2 = 1002
+ }
+
+ @Before
+ fun setUp() {
+ assertEquals(8, testStats1.size())
+ assertEquals(5, testStats2.size())
+ assertEquals(9, testStats3.size())
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.Q)
+ fun testAddEntry() {
+ val expectedEntriesInStats2 = arrayOf(
+ Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 15, 2, 31, 1),
+ Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 13, 61, 10, 1, 45),
+ Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 11, 2, 3, 4, 7),
+ Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 4, 3, 2, 1, 0),
+ Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0))
+
+ // While testStats* are already initialized with addEntry, verify content added
+ // matches expectation.
+ for (i in expectedEntriesInStats2.indices) {
+ val entry = testStats2.getValues(i, null)
+ assertEquals(expectedEntriesInStats2[i], entry)
+ }
+
+ // Verify entry updated with addEntry.
+ val stats = testStats2.addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 12, -5, 7, 0, 9))
+ assertEquals(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 16, -2, 9, 1, 9),
+ stats.getValues(3, null))
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.Q)
+ fun testAdd() {
+ var stats = NetworkStats(0L, 0)
+ assertNetworkStatsEquals(testStatsEmpty, stats)
+ stats = stats.add(testStats2)
+ assertNetworkStatsEquals(testStats2, stats)
+ stats = stats.add(testStats1)
+ // EMPTY + STATS2 + STATS1 = STATS3
+ assertNetworkStatsEquals(testStats3, stats)
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.Q)
+ fun testParcelUnparcel() {
+ assertParcelingIsLossless(testStatsEmpty)
+ assertParcelingIsLossless(testStats1)
+ assertParcelingIsLossless(testStats2)
+ assertFieldCountEquals(15, NetworkStats::class.java)
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.Q)
+ fun testDescribeContents() {
+ assertEquals(0, testStatsEmpty.describeContents())
+ assertEquals(0, testStats1.describeContents())
+ assertEquals(0, testStats2.describeContents())
+ assertEquals(0, testStats3.describeContents())
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.Q)
+ fun testSubtract() {
+ // STATS3 - STATS2 = STATS1
+ assertNetworkStatsEquals(testStats1, testStats3.subtract(testStats2))
+ // STATS3 - STATS1 = STATS2
+ assertNetworkStatsEquals(testStats2, testStats3.subtract(testStats1))
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.Q)
+ fun testMethodsDontModifyReceiver() {
+ listOf(testStatsEmpty, testStats1, testStats2, testStats3).forEach {
+ val origStats = it.clone()
+ it.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 13, 61, 10, 1, 45))
+ it.add(testStats3)
+ it.subtract(testStats1)
+ assertNetworkStatsEquals(origStats, it)
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/net/java/android/net/NetworkStatsTest.java b/tests/net/java/android/net/NetworkStatsTest.java
index e71d599..98f705f 100644
--- a/tests/net/java/android/net/NetworkStatsTest.java
+++ b/tests/net/java/android/net/NetworkStatsTest.java
@@ -503,6 +503,53 @@
}
@Test
+ public void testRemoveEmptyEntries() throws Exception {
+ // Test empty stats.
+ final NetworkStats statsEmpty = new NetworkStats(TEST_START, 3);
+ assertEquals(0, statsEmpty.removeEmptyEntries().size());
+
+ // Test stats with non-zero entry.
+ final NetworkStats statsNonZero = new NetworkStats(TEST_START, 1)
+ .insertEntry(TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 1L, 128L, 0L, 2L, 20L);
+ assertEquals(1, statsNonZero.size());
+ final NetworkStats expectedNonZero = statsNonZero.removeEmptyEntries();
+ assertEquals(1, expectedNonZero.size());
+ assertValues(expectedNonZero, 0, TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 1L, 128L, 0L, 2L, 20L);
+
+ // Test stats with empty entry.
+ final NetworkStats statsZero = new NetworkStats(TEST_START, 1)
+ .insertEntry(TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L);
+ assertEquals(1, statsZero.size());
+ final NetworkStats expectedZero = statsZero.removeEmptyEntries();
+ assertEquals(1, statsZero.size()); // Assert immutable.
+ assertEquals(0, expectedZero.size());
+
+ // Test stats with multiple entries.
+ final NetworkStats statsMultiple = new NetworkStats(TEST_START, 0)
+ .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 2L, 64L, 0L, 2L, 20L)
+ .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 4L, 32L, 0L, 0L, 0L)
+ .insertEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 0L, 0L, 0L, 0L, 0L)
+ .insertEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 0L, 0L, 0L, 0L, 0L)
+ .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L)
+ .insertEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 0L, 8L, 0L, 0L, 0L)
+ .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 4L, 0L, 0L)
+ .insertEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 0L, 0L, 0L, 2L, 0L)
+ .insertEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 0L, 0L, 0L, 0L, 1L);
+ assertEquals(9, statsMultiple.size());
+ final NetworkStats expectedMultiple = statsMultiple.removeEmptyEntries();
+ assertEquals(9, statsMultiple.size()); // Assert immutable.
+ assertEquals(7, expectedMultiple.size());
+ assertValues(expectedMultiple.getTotalIncludingTags(null), 14L, 104L, 4L, 4L, 21L);
+
+ // Test stats with multiple empty entries.
+ assertEquals(statsMultiple.size(), statsMultiple.subtract(statsMultiple).size());
+ assertEquals(0, statsMultiple.subtract(statsMultiple).removeEmptyEntries().size());
+ }
+
+ @Test
public void testClone() throws Exception {
final NetworkStats original = new NetworkStats(TEST_START, 5)
.insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L)