summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java17
-rw-r--r--cmds/statsd/src/atoms.proto6
-rw-r--r--core/java/android/net/NetworkTemplate.java12
-rw-r--r--core/java/android/provider/CallLog.java11
-rw-r--r--core/java/android/speech/tts/TextToSpeech.java27
-rw-r--r--core/java/android/view/ImeFocusController.java10
-rw-r--r--core/java/android/view/InsetsAnimationControlImpl.java2
-rw-r--r--core/java/android/view/InsetsController.java10
-rw-r--r--core/java/android/view/InsetsState.java19
-rw-r--r--core/java/android/view/ViewRootImpl.java3
-rw-r--r--core/java/android/view/WindowInsets.java25
-rw-r--r--core/java/android/view/WindowManagerImpl.java2
-rw-r--r--core/java/android/view/WindowManagerPolicyConstants.java7
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java57
-rw-r--r--core/java/android/widget/TextView.java102
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java1
-rw-r--r--core/java/com/android/internal/inputmethod/InputMethodDebug.java8
-rw-r--r--core/java/com/android/internal/inputmethod/StartInputReason.java8
-rw-r--r--core/java/com/android/internal/widget/ResolverDrawerLayout.java17
-rw-r--r--core/res/res/values/attrs.xml7
-rw-r--r--core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java2
-rw-r--r--core/tests/coretests/src/android/view/InsetsControllerTest.java2
-rw-r--r--core/tests/coretests/src/android/view/InsetsStateTest.java36
-rw-r--r--data/etc/privapp-permissions-platform.xml5
-rw-r--r--libs/hwui/DeferredLayerUpdater.cpp3
-rw-r--r--location/java/android/location/GpsStatus.java9
-rw-r--r--location/java/android/location/LocationManager.java5
-rw-r--r--media/java/android/media/MediaCas.java9
-rw-r--r--media/java/android/media/MediaMetrics.java5
-rw-r--r--packages/CarSystemUI/TEST_MAPPING11
-rw-r--r--packages/CarSystemUI/res/layout/system_icons.xml6
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/CarSystemUiTest.java32
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java9
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java22
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/userswitcher/CarStatusBarHeader.java4
-rw-r--r--packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/HvacControllerTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonRoleHolderControllerTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonSelectionStateControllerTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarViewTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/notification/NotificationVisibilityLoggerTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppDetectorTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewControllerTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java2
-rw-r--r--packages/Shell/AndroidManifest.xml5
-rw-r--r--packages/SystemUI/res/layout/qs_footer_impl.xml2
-rw-r--r--packages/SystemUI/res/values/strings.xml21
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java67
-rw-r--r--packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java3
-rw-r--r--packages/WAPPushManager/AndroidManifest.xml2
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java12
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java3
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java12
-rw-r--r--services/core/java/com/android/server/am/AppExitInfoTracker.java2
-rwxr-xr-xservices/core/java/com/android/server/audio/AudioService.java56
-rw-r--r--services/core/java/com/android/server/audio/AudioServiceEvents.java64
-rw-r--r--services/core/java/com/android/server/audio/PlaybackActivityMonitor.java17
-rw-r--r--services/core/java/com/android/server/audio/RecordingActivityMonitor.java19
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssLocationProvider.java2
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java40
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java15
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java3
-rw-r--r--services/core/java/com/android/server/pm/Settings.java2
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java12
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java12
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java7
-rw-r--r--services/core/java/com/android/server/wm/BarController.java17
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java225
-rw-r--r--services/core/java/com/android/server/wm/Letterbox.java33
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java8
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotController.java5
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java12
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java6
-rw-r--r--services/incremental/IncrementalService.cpp15
-rw-r--r--services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java15
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java49
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java99
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java18
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java8
-rwxr-xr-xtelephony/java/android/telephony/CarrierConfigManager.java11
-rw-r--r--tests/net/java/android/net/NetworkTemplateTest.kt7
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java55
108 files changed, 1430 insertions, 305 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index f36084386f48..0cadbfd23dba 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -456,7 +456,7 @@ public class AppStandbyController implements AppStandbyInternal {
mSystemServicesReady = true;
// Offload to handler thread to avoid boot time impact.
- mHandler.post(mInjector::updatePowerWhitelistCache);
+ mHandler.post(AppStandbyController.this::updatePowerWhitelistCache);
boolean userFileExists;
synchronized (mAppIdleLock) {
@@ -1684,6 +1684,14 @@ public class AppStandbyController implements AppStandbyInternal {
}
}
+ private void updatePowerWhitelistCache() {
+ if (mInjector.getBootPhase() < PHASE_SYSTEM_SERVICES_READY) {
+ return;
+ }
+ mInjector.updatePowerWhitelistCache();
+ postCheckIdleStates(UserHandle.USER_ALL);
+ }
+
private class PackageReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
@@ -1999,10 +2007,7 @@ public class AppStandbyController implements AppStandbyInternal {
}
}
- private void updatePowerWhitelistCache() {
- if (mBootPhase < PHASE_SYSTEM_SERVICES_READY) {
- return;
- }
+ void updatePowerWhitelistCache() {
try {
// Don't call out to DeviceIdleController with the lock held.
final String[] whitelistedPkgs =
@@ -2204,7 +2209,7 @@ public class AppStandbyController implements AppStandbyInternal {
break;
case PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED:
if (mSystemServicesReady) {
- mHandler.post(mInjector::updatePowerWhitelistCache);
+ mHandler.post(AppStandbyController.this::updatePowerWhitelistCache);
}
break;
}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 7a016522d597..36b46c3d03a3 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -5178,6 +5178,12 @@ message DataUsageBytesTransfer {
// record is combined across opportunistic data subscriptions.
// See {@link SubscriptionManager#setOpportunistic}.
optional DataSubscriptionState opportunistic_data_sub = 10;
+
+ // Indicate whether NR is connected, server side could use this with RAT type to determine if
+ // the record is for 5G NSA (Non Stand Alone) mode, where the primary cell is still LTE and
+ // network allocates a secondary 5G cell so telephony reports RAT = LTE along with NR state as
+ // connected.
+ optional bool is_nr_connected = 11;
}
/**
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index eba7ff348328..7234eb1d81cd 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -87,6 +87,15 @@ public class NetworkTemplate implements Parcelable {
* @hide
*/
public static final int NETWORK_TYPE_ALL = -1;
+ /**
+ * Virtual RAT type to represent 5G NSA (Non Stand Alone) mode, where the primary cell is
+ * still LTE and network allocates a secondary 5G cell so telephony reports RAT = LTE along
+ * with NR state as connected. This should not be overlapped with any of the
+ * {@code TelephonyManager.NETWORK_TYPE_*} constants.
+ *
+ * @hide
+ */
+ public static final int NETWORK_TYPE_5G_NSA = -2;
private static boolean isKnownMatchRule(final int rule) {
switch (rule) {
@@ -475,6 +484,9 @@ public class NetworkTemplate implements Parcelable {
return TelephonyManager.NETWORK_TYPE_LTE;
case TelephonyManager.NETWORK_TYPE_NR:
return TelephonyManager.NETWORK_TYPE_NR;
+ // Virtual RAT type for 5G NSA mode, see {@link NetworkTemplate#NETWORK_TYPE_5G_NSA}.
+ case NetworkTemplate.NETWORK_TYPE_5G_NSA:
+ return NetworkTemplate.NETWORK_TYPE_5G_NSA;
default:
return TelephonyManager.NETWORK_TYPE_UNKNOWN;
}
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index a0e92b398c4e..276f16216b4d 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -99,6 +99,13 @@ public class CallLog {
public static final String LIMIT_PARAM_KEY = "limit";
/**
+ * Form of {@link #CONTENT_URI} which limits the query results to a single result.
+ */
+ private static final Uri CONTENT_URI_LIMIT_1 = CONTENT_URI.buildUpon()
+ .appendQueryParameter(LIMIT_PARAM_KEY, "1")
+ .build();
+
+ /**
* Query parameter used to specify the starting record to return.
* <p>
* TYPE: integer
@@ -932,11 +939,11 @@ public class CallLog {
Cursor c = null;
try {
c = resolver.query(
- CONTENT_URI,
+ CONTENT_URI_LIMIT_1,
new String[] {NUMBER},
TYPE + " = " + OUTGOING_TYPE,
null,
- DEFAULT_SORT_ORDER + " LIMIT 1");
+ DEFAULT_SORT_ORDER);
if (c == null || !c.moveToFirst()) {
return "";
}
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index c861fa774de8..408e8504f408 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -60,6 +60,19 @@ import java.util.Set;
* notified of the completion of the initialization.<br>
* When you are done using the TextToSpeech instance, call the {@link #shutdown()} method
* to release the native resources used by the TextToSpeech engine.
+ *
+ * Apps targeting Android 11 that use text-to-speech should declare {@link
+ * TextToSpeech.Engine#INTENT_ACTION_TTS_SERVICE} in the <code><queries></code> elements of their
+ * manifest:
+ *
+ * <code>
+ * <queries>
+ * ...
+ * <intent>
+ * <action android:name="android.intent.action.TTS_SERVICE" />
+ * </intent>
+ * </queries>
+ * </code>
*/
public class TextToSpeech {
@@ -239,6 +252,20 @@ public class TextToSpeech {
* through {@link TextToSpeech#getFeatures(java.util.Locale)}.
* </li>
* </ul>
+ *
+ * Apps targeting Android 11 that use text-to-speech should declare {@link
+ * #INTENT_ACTION_TTS_SERVICE} in the <code><queries></code> elements of their
+ * manifest:
+ *
+ * <code>
+ * <queries>
+ * ...
+ * <intent>
+ * <action android:name="android.intent.action.TTS_SERVICE" />
+ * </intent>
+ * </queries>
+ * </code>
+
*/
public class Engine {
diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java
index ad43f9556d8d..92772c1d7a44 100644
--- a/core/java/android/view/ImeFocusController.java
+++ b/core/java/android/view/ImeFocusController.java
@@ -125,10 +125,10 @@ public final class ImeFocusController {
final View viewForWindowFocus = focusedView != null ? focusedView : mViewRootImpl.mView;
onViewFocusChanged(viewForWindowFocus, true);
- // Starting new input when the next focused view is same as served view but the
- // editor is not aligned with the same editor or editor is inactive.
- final boolean nextFocusIsServedView = mServedView != null && mServedView == focusedView;
- if (nextFocusIsServedView && !immDelegate.isSameEditorAndAcceptingText(focusedView)) {
+ // Starting new input when the next focused view is same as served view but the currently
+ // active connection (if any) is not associated with it.
+ final boolean nextFocusIsServedView = mServedView == viewForWindowFocus;
+ if (nextFocusIsServedView && !immDelegate.hasActiveConnection(viewForWindowFocus)) {
forceFocus = true;
}
@@ -254,7 +254,7 @@ public final class ImeFocusController {
void setCurrentRootView(ViewRootImpl rootView);
boolean isCurrentRootView(ViewRootImpl rootView);
boolean isRestartOnNextWindowFocus(boolean reset);
- boolean isSameEditorAndAcceptingText(View view);
+ boolean hasActiveConnection(View view);
}
public View getServedView() {
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index 31da83ad5137..69220722fc05 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -308,7 +308,7 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
false /* isScreenRound */,
false /* alwaysConsumeSystemBars */, null /* displayCutout */,
LayoutParams.SOFT_INPUT_ADJUST_RESIZE /* legacySoftInputMode*/,
- 0 /* legacySystemUiFlags */, typeSideMap)
+ 0 /* legacyWindowFlags */, 0 /* legacySystemUiFlags */, typeSideMap)
.getInsets(mTypes);
}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index a679b3740fd9..c383bc7a4d70 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -501,6 +501,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
private PendingControlRequest mPendingImeControlRequest;
private int mLastLegacySoftInputMode;
+ private int mLastLegacyWindowFlags;
private int mLastLegacySystemUiFlags;
private DisplayCutout mLastDisplayCutout;
private boolean mStartingAnimation;
@@ -569,8 +570,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
WindowInsets insets = state.calculateInsets(mFrame, mState /* ignoringVisibilityState*/,
mLastInsets.isRound(), mLastInsets.shouldAlwaysConsumeSystemBars(),
- mLastDisplayCutout, mLastLegacySoftInputMode, mLastLegacySystemUiFlags,
- null /* typeSideMap */);
+ mLastDisplayCutout, mLastLegacySoftInputMode, mLastLegacyWindowFlags,
+ mLastLegacySystemUiFlags, null /* typeSideMap */);
mHost.dispatchWindowInsetsAnimationProgress(insets, mUnmodifiableTmpRunningAnims);
if (DEBUG) {
for (WindowInsetsAnimation anim : mUnmodifiableTmpRunningAnims) {
@@ -706,13 +707,14 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
@VisibleForTesting
public WindowInsets calculateInsets(boolean isScreenRound,
boolean alwaysConsumeSystemBars, DisplayCutout cutout,
- int legacySoftInputMode, int legacySystemUiFlags) {
+ int legacySoftInputMode, int legacyWindowFlags, int legacySystemUiFlags) {
mLastLegacySoftInputMode = legacySoftInputMode;
+ mLastLegacyWindowFlags = legacyWindowFlags;
mLastLegacySystemUiFlags = legacySystemUiFlags;
mLastDisplayCutout = cutout;
mLastInsets = mState.calculateInsets(mFrame, null /* ignoringVisibilityState*/,
isScreenRound, alwaysConsumeSystemBars, cutout,
- legacySoftInputMode, legacySystemUiFlags,
+ legacySoftInputMode, legacyWindowFlags, legacySystemUiFlags,
null /* typeSideMap */);
return mLastInsets;
}
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 91e7591193f1..6b0b509932a8 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -22,13 +22,14 @@ import static android.view.ViewRootImpl.NEW_INSETS_MODE_IME;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
import static android.view.ViewRootImpl.sNewInsetsMode;
import static android.view.WindowInsets.Type.MANDATORY_SYSTEM_GESTURES;
-import static android.view.WindowInsets.Type.SIZE;
import static android.view.WindowInsets.Type.SYSTEM_GESTURES;
import static android.view.WindowInsets.Type.displayCutout;
import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsets.Type.indexOf;
import static android.view.WindowInsets.Type.isVisibleInsetsType;
+import static android.view.WindowInsets.Type.statusBars;
import static android.view.WindowInsets.Type.systemBars;
+import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
@@ -38,7 +39,6 @@ import android.graphics.Insets;
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseIntArray;
import android.view.WindowInsets.Type;
@@ -171,7 +171,7 @@ public class InsetsState implements Parcelable {
*/
public WindowInsets calculateInsets(Rect frame, @Nullable InsetsState ignoringVisibilityState,
boolean isScreenRound, boolean alwaysConsumeSystemBars, DisplayCutout cutout,
- int legacySoftInputMode, int legacySystemUiFlags,
+ int legacySoftInputMode, int legacyWindowFlags, int legacySystemUiFlags,
@Nullable @InternalInsetsSide SparseIntArray typeSideMap) {
Insets[] typeInsetsMap = new Insets[Type.SIZE];
Insets[] typeMaxInsetsMap = new Insets[Type.SIZE];
@@ -218,10 +218,17 @@ public class InsetsState implements Parcelable {
}
}
final int softInputAdjustMode = legacySoftInputMode & SOFT_INPUT_MASK_ADJUST;
+
+ @InsetsType int compatInsetsTypes = systemBars() | displayCutout();
+ if (softInputAdjustMode == SOFT_INPUT_ADJUST_RESIZE) {
+ compatInsetsTypes |= ime();
+ }
+ if ((legacyWindowFlags & FLAG_FULLSCREEN) != 0) {
+ compatInsetsTypes &= ~statusBars();
+ }
+
return new WindowInsets(typeInsetsMap, typeMaxInsetsMap, typeVisibilityMap, isScreenRound,
- alwaysConsumeSystemBars, cutout, softInputAdjustMode == SOFT_INPUT_ADJUST_RESIZE
- ? systemBars() | displayCutout() | ime()
- : systemBars() | displayCutout(),
+ alwaysConsumeSystemBars, cutout, compatInsetsTypes,
sNewInsetsMode == NEW_INSETS_MODE_FULL
&& (legacySystemUiFlags & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0);
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index fefe564787ca..7453f21d379b 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2265,7 +2265,8 @@ public final class ViewRootImpl implements ViewParent,
mLastWindowInsets = mInsetsController.calculateInsets(
mContext.getResources().getConfiguration().isScreenRound(),
mAttachInfo.mAlwaysConsumeSystemBars, mPendingDisplayCutout.get(),
- mWindowAttributes.softInputMode, (mWindowAttributes.systemUiVisibility
+ mWindowAttributes.softInputMode, mWindowAttributes.flags,
+ (mWindowAttributes.systemUiVisibility
| mWindowAttributes.subtreeSystemUiVisibility));
Rect visibleInsets = mInsetsController.calculateVisibleInsets(
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 4d6b72f96aab..5e94758b003c 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -17,7 +17,6 @@
package android.view;
-import static android.view.WindowInsets.Type.CAPTION_BAR;
import static android.view.WindowInsets.Type.DISPLAY_CUTOUT;
import static android.view.WindowInsets.Type.FIRST;
import static android.view.WindowInsets.Type.IME;
@@ -95,7 +94,7 @@ public final class WindowInsets {
private final boolean mStableInsetsConsumed;
private final boolean mDisplayCutoutConsumed;
- private final int mCompatInsetTypes;
+ private final int mCompatInsetsTypes;
private final boolean mCompatIgnoreVisibility;
/**
@@ -150,8 +149,8 @@ public final class WindowInsets {
@Nullable Insets[] typeMaxInsetsMap,
boolean[] typeVisibilityMap,
boolean isRound,
- boolean alwaysConsumeSystemBars, DisplayCutout displayCutout, int compatInsetTypes,
- boolean compatIgnoreVisibility) {
+ boolean alwaysConsumeSystemBars, DisplayCutout displayCutout,
+ @InsetsType int compatInsetsTypes, boolean compatIgnoreVisibility) {
mSystemWindowInsetsConsumed = typeInsetsMap == null;
mTypeInsetsMap = mSystemWindowInsetsConsumed
? new Insets[SIZE]
@@ -165,7 +164,7 @@ public final class WindowInsets {
mTypeVisibilityMap = typeVisibilityMap;
mIsRound = isRound;
mAlwaysConsumeSystemBars = alwaysConsumeSystemBars;
- mCompatInsetTypes = compatInsetTypes;
+ mCompatInsetsTypes = compatInsetsTypes;
mCompatIgnoreVisibility = compatIgnoreVisibility;
mDisplayCutoutConsumed = displayCutout == null;
@@ -183,7 +182,7 @@ public final class WindowInsets {
src.mStableInsetsConsumed ? null : src.mTypeMaxInsetsMap,
src.mTypeVisibilityMap, src.mIsRound,
src.mAlwaysConsumeSystemBars, displayCutoutCopyConstructorArgument(src),
- src.mCompatInsetTypes,
+ src.mCompatInsetsTypes,
src.mCompatIgnoreVisibility);
}
@@ -310,11 +309,11 @@ public final class WindowInsets {
@NonNull
public Insets getSystemWindowInsets() {
Insets result = mCompatIgnoreVisibility
- ? getInsetsIgnoringVisibility(mCompatInsetTypes & ~ime())
- : getInsets(mCompatInsetTypes);
+ ? getInsetsIgnoringVisibility(mCompatInsetsTypes & ~ime())
+ : getInsets(mCompatInsetsTypes);
// We can't query max insets for IME, so we need to add it manually after.
- if ((mCompatInsetTypes & ime()) != 0 && mCompatIgnoreVisibility) {
+ if ((mCompatInsetsTypes & ime()) != 0 && mCompatIgnoreVisibility) {
result = Insets.max(result, getInsets(ime()));
}
return result;
@@ -503,7 +502,7 @@ public final class WindowInsets {
mTypeVisibilityMap,
mIsRound, mAlwaysConsumeSystemBars,
null /* displayCutout */,
- mCompatInsetTypes, mCompatIgnoreVisibility);
+ mCompatInsetsTypes, mCompatIgnoreVisibility);
}
@@ -554,7 +553,7 @@ public final class WindowInsets {
mTypeVisibilityMap,
mIsRound, mAlwaysConsumeSystemBars,
displayCutoutCopyConstructorArgument(this),
- mCompatInsetTypes, mCompatIgnoreVisibility);
+ mCompatInsetsTypes, mCompatIgnoreVisibility);
}
// TODO(b/119190588): replace @code with @link below
@@ -627,7 +626,7 @@ public final class WindowInsets {
@Deprecated
@NonNull
public Insets getStableInsets() {
- return getInsets(mTypeMaxInsetsMap, mCompatInsetTypes);
+ return getInsets(mTypeMaxInsetsMap, mCompatInsetsTypes);
}
/**
@@ -939,7 +938,7 @@ public final class WindowInsets {
: mDisplayCutout == null
? DisplayCutout.NO_CUTOUT
: mDisplayCutout.inset(left, top, right, bottom),
- mCompatInsetTypes, mCompatIgnoreVisibility);
+ mCompatInsetsTypes, mCompatIgnoreVisibility);
}
@Override
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 28a18da37b3e..2fe7c021bb21 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -276,7 +276,7 @@ public final class WindowManagerImpl implements WindowManager {
if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) {
return insetsState.calculateInsets(bounds, null /* ignoringVisibilityState*/,
isScreenRound, alwaysConsumeSystemBars, displayCutout.get(),
- SOFT_INPUT_ADJUST_NOTHING,
+ SOFT_INPUT_ADJUST_NOTHING, attrs.flags,
SYSTEM_UI_FLAG_VISIBLE, null /* typeSideMap */);
} else {
return new WindowInsets.Builder()
diff --git a/core/java/android/view/WindowManagerPolicyConstants.java b/core/java/android/view/WindowManagerPolicyConstants.java
index 492ab6f8a3d5..8c355202b63f 100644
--- a/core/java/android/view/WindowManagerPolicyConstants.java
+++ b/core/java/android/view/WindowManagerPolicyConstants.java
@@ -49,6 +49,13 @@ public interface WindowManagerPolicyConstants {
int PRESENCE_INTERNAL = 1 << 0;
int PRESENCE_EXTERNAL = 1 << 1;
+ // Alternate bars position values
+ int ALT_BAR_UNKNOWN = -1;
+ int ALT_BAR_LEFT = 1 << 0;
+ int ALT_BAR_RIGHT = 1 << 1;
+ int ALT_BAR_BOTTOM = 1 << 2;
+ int ALT_BAR_TOP = 1 << 3;
+
// Navigation bar position values
int NAV_BAR_INVALID = -1;
int NAV_BAR_LEFT = 1 << 0;
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 37b352940ee4..0d21673dfc71 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -19,8 +19,8 @@ package android.view.inputmethod;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
-import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_EDITOR;
-import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR;
+import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION;
+import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION;
import android.annotation.DrawableRes;
import android.annotation.NonNull;
@@ -89,6 +89,7 @@ import com.android.internal.view.InputBindResult;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Collections;
@@ -610,14 +611,13 @@ public final class InputMethodManager {
@Override
public void startInputAsyncOnWindowFocusGain(View focusedView,
@SoftInputModeFlags int softInputMode, int windowFlags, boolean forceNewFocus) {
- final boolean forceNewFocus1 = forceNewFocus;
final int startInputFlags = getStartInputFlags(focusedView, 0);
final ImeFocusController controller = getFocusController();
if (controller == null) {
return;
}
- if (controller.checkFocus(forceNewFocus1, false)) {
+ if (controller.checkFocus(forceNewFocus, false)) {
// We need to restart input on the current focus view. This
// should be done in conjunction with telling the system service
// about the window gaining focus, to help make the transition
@@ -633,15 +633,15 @@ public final class InputMethodManager {
// we'll just do a window focus gain and call it a day.
try {
View servedView = controller.getServedView();
- boolean nextFocusSameEditor = servedView != null && servedView == focusedView
- && isSameEditorAndAcceptingText(focusedView);
+ boolean nextFocusHasConnection = servedView != null && servedView == focusedView
+ && hasActiveConnection(focusedView);
if (DEBUG) {
Log.v(TAG, "Reporting focus gain, without startInput"
- + ", nextFocusIsServedView=" + nextFocusSameEditor);
+ + ", nextFocusIsServedView=" + nextFocusHasConnection);
}
final int startInputReason =
- nextFocusSameEditor ? WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR
- : WINDOW_FOCUS_GAIN_REPORT_WITHOUT_EDITOR;
+ nextFocusHasConnection ? WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION
+ : WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION;
mService.startInputOrWindowGainedFocus(
startInputReason, mClient,
focusedView.getWindowToken(), startInputFlags, softInputMode,
@@ -701,33 +701,24 @@ public final class InputMethodManager {
}
/**
- * For {@link ImeFocusController} to check if the given focused view aligns with the same
- * editor and the editor is active to accept the text input.
+ * Checks whether the active input connection (if any) is for the given view.
*
- * TODO(b/160968797): Remove this method and move mCurrentTextBoxAttritube to
+ * TODO(b/160968797): Remove this method and move mServedInputConnectionWrapper to
* ImeFocusController.
- * In the long-term, we should make mCurrentTextBoxAtrtribue as per-window base instance,
- * so that we we can directly check if the current focused view aligned with the same editor
- * in the window without using this checking.
*
- * Note that this method is only use for fixing start new input may ignored issue
+ * Note that this method is only intended for restarting input after focus gain
* (e.g. b/160391516), DO NOT leverage this method to do another check.
*/
- public boolean isSameEditorAndAcceptingText(View view) {
+ @Override
+ public boolean hasActiveConnection(View view) {
synchronized (mH) {
- if (!hasServedByInputMethodLocked(view) || mCurrentTextBoxAttribute == null) {
+ if (!hasServedByInputMethodLocked(view)) {
return false;
}
- final EditorInfo ic = mCurrentTextBoxAttribute;
- // This sameEditor checking is based on using object hash comparison to check if
- // some fields of the current EditorInfo (e.g. autoFillId, OpPackageName) the
- // hash code is same as the given focused view.
- final boolean sameEditor = view.onCheckIsTextEditor() && view.getId() == ic.fieldId
- && view.getAutofillId() == ic.autofillId
- && view.getContext().getOpPackageName() == ic.packageName;
- return sameEditor && mServedInputConnectionWrapper != null
- && mServedInputConnectionWrapper.isActive();
+ return mServedInputConnectionWrapper != null
+ && mServedInputConnectionWrapper.isActive()
+ && mServedInputConnectionWrapper.mServedView.get() == view;
}
}
}
@@ -980,11 +971,13 @@ public final class InputMethodManager {
private static class ControlledInputConnectionWrapper extends IInputConnectionWrapper {
private final InputMethodManager mParentInputMethodManager;
+ private final WeakReference<View> mServedView;
- public ControlledInputConnectionWrapper(final Looper mainLooper, final InputConnection conn,
- final InputMethodManager inputMethodManager) {
+ ControlledInputConnectionWrapper(Looper mainLooper, InputConnection conn,
+ InputMethodManager inputMethodManager, View servedView) {
super(mainLooper, conn);
mParentInputMethodManager = inputMethodManager;
+ mServedView = new WeakReference<>(servedView);
}
@Override
@@ -1007,6 +1000,7 @@ public final class InputMethodManager {
+ "connection=" + getInputConnection()
+ " finished=" + isFinished()
+ " mParentInputMethodManager.mActive=" + mParentInputMethodManager.mActive
+ + " mServedView=" + mServedView.get()
+ "}";
}
}
@@ -1187,7 +1181,8 @@ public final class InputMethodManager {
mMainLooper = looper;
mH = new H(looper);
mDisplayId = displayId;
- mIInputContext = new ControlledInputConnectionWrapper(looper, mDummyInputConnection, this);
+ mIInputContext = new ControlledInputConnectionWrapper(looper, mDummyInputConnection, this,
+ null);
}
/**
@@ -1968,7 +1963,7 @@ public final class InputMethodManager {
icHandler = ic.getHandler();
}
servedContext = new ControlledInputConnectionWrapper(
- icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this);
+ icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this, view);
} else {
servedContext = null;
missingMethodFlags = 0;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 226f57976ec8..e16bf5a18808 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -395,6 +395,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private static final int EMS = LINES;
private static final int PIXELS = 2;
+ // Maximum text length for single line input.
+ private static final int MAX_LENGTH_FOR_SINGLE_LINE_EDIT_TEXT = 5000;
+ private InputFilter.LengthFilter mSingleLineLengthFilter = null;
+
private static final RectF TEMP_RECTF = new RectF();
/** @hide */
@@ -1589,7 +1593,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// Same as setSingleLine(), but make sure the transformation method and the maximum number
// of lines of height are unchanged for multi-line TextViews.
setInputTypeSingleLine(singleLine);
- applySingleLine(singleLine, singleLine, singleLine);
+ applySingleLine(singleLine, singleLine, singleLine,
+ // Does not apply automated max length filter since length filter will be resolved
+ // later in this function.
+ false
+ );
if (singleLine && getKeyListener() == null && ellipsize == ELLIPSIZE_NOT_SET) {
ellipsize = ELLIPSIZE_END;
@@ -1633,7 +1641,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
setTransformationMethod(PasswordTransformationMethod.getInstance());
}
- if (maxlength >= 0) {
+ // For addressing b/145128646
+ // For the performance reason, we limit characters for single line text field.
+ if (bufferType == BufferType.EDITABLE && singleLine && maxlength == -1) {
+ mSingleLineLengthFilter = new InputFilter.LengthFilter(
+ MAX_LENGTH_FOR_SINGLE_LINE_EDIT_TEXT);
+ }
+
+ if (mSingleLineLengthFilter != null) {
+ setFilters(new InputFilter[] { mSingleLineLengthFilter });
+ } else if (maxlength >= 0) {
setFilters(new InputFilter[] { new InputFilter.LengthFilter(maxlength) });
} else {
setFilters(NO_FILTERS);
@@ -6590,7 +6607,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (mSingleLine != singleLine || forceUpdate) {
// Change single line mode, but only change the transformation if
// we are not in password mode.
- applySingleLine(singleLine, !isPassword, true);
+ applySingleLine(singleLine, !isPassword, true, true);
}
if (!isSuggestionsEnabled()) {
@@ -10229,6 +10246,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* Note that the default conditions are not necessarily those that were in effect prior this
* method, and you may want to reset these properties to your custom values.
*
+ * Note that due to performance reasons, by setting single line for the EditText, the maximum
+ * text length is set to 5000 if no other character limitation are applied.
+ *
* @attr ref android.R.styleable#TextView_singleLine
*/
@android.view.RemotableViewMethod
@@ -10236,7 +10256,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// Could be used, but may break backward compatibility.
// if (mSingleLine == singleLine) return;
setInputTypeSingleLine(singleLine);
- applySingleLine(singleLine, true, true);
+ applySingleLine(singleLine, true, true, true);
}
/**
@@ -10256,14 +10276,40 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
private void applySingleLine(boolean singleLine, boolean applyTransformation,
- boolean changeMaxLines) {
+ boolean changeMaxLines, boolean changeMaxLength) {
mSingleLine = singleLine;
+
if (singleLine) {
setLines(1);
setHorizontallyScrolling(true);
if (applyTransformation) {
setTransformationMethod(SingleLineTransformationMethod.getInstance());
}
+
+ if (!changeMaxLength) return;
+
+ // Single line length filter is only applicable editable text.
+ if (mBufferType != BufferType.EDITABLE) return;
+
+ final InputFilter[] prevFilters = getFilters();
+ for (InputFilter filter: getFilters()) {
+ // We don't add LengthFilter if already there.
+ if (filter instanceof InputFilter.LengthFilter) return;
+ }
+
+ if (mSingleLineLengthFilter == null) {
+ mSingleLineLengthFilter = new InputFilter.LengthFilter(
+ MAX_LENGTH_FOR_SINGLE_LINE_EDIT_TEXT);
+ }
+
+ final InputFilter[] newFilters = new InputFilter[prevFilters.length + 1];
+ System.arraycopy(prevFilters, 0, newFilters, 0, prevFilters.length);
+ newFilters[prevFilters.length] = mSingleLineLengthFilter;
+
+ setFilters(newFilters);
+
+ // Since filter doesn't apply to existing text, trigger filter by setting text.
+ setText(getText());
} else {
if (changeMaxLines) {
setMaxLines(Integer.MAX_VALUE);
@@ -10272,6 +10318,47 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (applyTransformation) {
setTransformationMethod(null);
}
+
+ if (!changeMaxLength) return;
+
+ // Single line length filter is only applicable editable text.
+ if (mBufferType != BufferType.EDITABLE) return;
+
+ final InputFilter[] prevFilters = getFilters();
+ if (prevFilters.length == 0) return;
+
+ // Short Circuit: if mSingleLineLengthFilter is not allocated, nobody sets automated
+ // single line char limit filter.
+ if (mSingleLineLengthFilter == null) return;
+
+ // If we need to remove mSingleLineLengthFilter, we need to allocate another array.
+ // Since filter list is expected to be small and want to avoid unnecessary array
+ // allocation, check if there is mSingleLengthFilter first.
+ int targetIndex = -1;
+ for (int i = 0; i < prevFilters.length; ++i) {
+ if (prevFilters[i] == mSingleLineLengthFilter) {
+ targetIndex = i;
+ break;
+ }
+ }
+ if (targetIndex == -1) return; // not found. Do nothing.
+
+ if (prevFilters.length == 1) {
+ setFilters(NO_FILTERS);
+ return;
+ }
+
+ // Create new array which doesn't include mSingleLengthFilter.
+ final InputFilter[] newFilters = new InputFilter[prevFilters.length - 1];
+ System.arraycopy(prevFilters, 0, newFilters, 0, targetIndex);
+ System.arraycopy(
+ prevFilters,
+ targetIndex + 1,
+ newFilters,
+ targetIndex,
+ prevFilters.length - targetIndex - 1);
+ setFilters(newFilters);
+ mSingleLineLengthFilter = null;
}
}
@@ -10900,17 +10987,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* not among the handles.
*/
boolean isFromPrimePointer(MotionEvent event, boolean fromHandleView) {
+ boolean res = true;
if (mPrimePointerId == NO_POINTER_ID) {
mPrimePointerId = event.getPointerId(0);
mIsPrimePointerFromHandleView = fromHandleView;
} else if (mPrimePointerId != event.getPointerId(0)) {
- return mIsPrimePointerFromHandleView && fromHandleView;
+ res = mIsPrimePointerFromHandleView && fromHandleView;
}
if (event.getActionMasked() == MotionEvent.ACTION_UP
|| event.getActionMasked() == MotionEvent.ACTION_CANCEL) {
mPrimePointerId = -1;
}
- return true;
+ return res;
}
@Override
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index fbf050ad08f6..3a89dcd96487 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -3134,6 +3134,7 @@ public class ChooserActivity extends ResolverActivity implements
// ends up disabled. That's because at some point the old tab's vertical scrolling is
// disabled and the new tab's is enabled. For context, see b/159997845
setVerticalScrollEnabled(true);
+ mResolverDrawerLayout.scrollNestedScrollableChildBackToTop();
}
@Override
diff --git a/core/java/com/android/internal/inputmethod/InputMethodDebug.java b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
index 085cdfcf9462..37f68233db53 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodDebug.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
@@ -46,10 +46,10 @@ public final class InputMethodDebug {
return "UNSPECIFIED";
case StartInputReason.WINDOW_FOCUS_GAIN:
return "WINDOW_FOCUS_GAIN";
- case StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR:
- return "WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR";
- case StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_EDITOR:
- return "WINDOW_FOCUS_GAIN_REPORT_WITHOUT_EDITOR";
+ case StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION:
+ return "WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION";
+ case StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION:
+ return "WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION";
case StartInputReason.APP_CALLED_RESTART_INPUT_API:
return "APP_CALLED_RESTART_INPUT_API";
case StartInputReason.CHECK_FOCUS:
diff --git a/core/java/com/android/internal/inputmethod/StartInputReason.java b/core/java/com/android/internal/inputmethod/StartInputReason.java
index 946ce858c12d..2ba708dd9312 100644
--- a/core/java/com/android/internal/inputmethod/StartInputReason.java
+++ b/core/java/com/android/internal/inputmethod/StartInputReason.java
@@ -30,8 +30,8 @@ import java.lang.annotation.Retention;
@IntDef(value = {
StartInputReason.UNSPECIFIED,
StartInputReason.WINDOW_FOCUS_GAIN,
- StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR,
- StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_EDITOR,
+ StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION,
+ StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION,
StartInputReason.APP_CALLED_RESTART_INPUT_API,
StartInputReason.CHECK_FOCUS,
StartInputReason.BOUND_TO_IMMS,
@@ -54,13 +54,13 @@ public @interface StartInputReason {
* view and its input connection remains. {@link android.view.inputmethod.InputMethodManager}
* just reports this window focus change event to sync IME input target for system.
*/
- int WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR = 2;
+ int WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION = 2;
/**
* {@link android.view.Window} gained focus but there is no {@link android.view.View} that is
* eligible to have IME focus. {@link android.view.inputmethod.InputMethodManager} just reports
* this window focus change event for logging.
*/
- int WINDOW_FOCUS_GAIN_REPORT_WITHOUT_EDITOR = 3;
+ int WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION = 3;
/**
* {@link android.view.inputmethod.InputMethodManager#restartInput(android.view.View)} is
* either explicitly called by the application or indirectly called by some Framework class
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index 3f708f84750c..90eeabb47e9a 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -464,11 +464,7 @@ public class ResolverDrawerLayout extends ViewGroup {
smoothScrollTo(mCollapsibleHeight + mUncollapsibleHeight, yvel);
mDismissOnScrollerFinished = true;
} else {
- if (isNestedListChildScrolled()) {
- mNestedListChild.smoothScrollToPosition(0);
- } else if (isNestedRecyclerChildScrolled()) {
- mNestedRecyclerChild.smoothScrollToPosition(0);
- }
+ scrollNestedScrollableChildBackToTop();
smoothScrollTo(yvel < 0 ? 0 : mCollapsibleHeight, yvel);
}
}
@@ -493,6 +489,17 @@ public class ResolverDrawerLayout extends ViewGroup {
return handled;
}
+ /**
+ * Scroll nested scrollable child back to top if it has been scrolled.
+ */
+ public void scrollNestedScrollableChildBackToTop() {
+ if (isNestedListChildScrolled()) {
+ mNestedListChild.smoothScrollToPosition(0);
+ } else if (isNestedRecyclerChildScrolled()) {
+ mNestedRecyclerChild.smoothScrollToPosition(0);
+ }
+ }
+
private void onSecondaryPointerUp(MotionEvent ev) {
final int pointerIndex = ev.getActionIndex();
final int pointerId = ev.getPointerId(pointerIndex);
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 8a4676dec6b3..2f1bcdc76afb 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1259,7 +1259,12 @@
<!-- Can be combined with <var>text</var> and its variations to
allow multiple lines of text in the field. If this flag is not set,
the text field will be constrained to a single line. Corresponds to
- {@link android.text.InputType#TYPE_TEXT_FLAG_MULTI_LINE}. -->
+ {@link android.text.InputType#TYPE_TEXT_FLAG_MULTI_LINE}.
+
+ Note: If this flag is not set and the text field doesn't have max length limit, the
+ framework automatically set maximum length of the characters to 5000 for the
+ performance reasons.
+ -->
<flag name="textMultiLine" value="0x00020001" />
<!-- Can be combined with <var>text</var> and its variations to
indicate that though the regular text view should not be multiple
diff --git a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
index bfcf52af80bf..eb695258142a 100644
--- a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
@@ -86,7 +86,7 @@ public class ImeInsetsSourceConsumerTest {
false,
new DisplayCutout(
Insets.of(10, 10, 10, 10), rect, rect, rect, rect),
- SOFT_INPUT_ADJUST_RESIZE, 0);
+ SOFT_INPUT_ADJUST_RESIZE, 0, 0);
mImeConsumer = (ImeInsetsSourceConsumer) mController.getSourceConsumer(ITYPE_IME);
});
}
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index c36f1067149e..801cd4ddb94e 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -165,7 +165,7 @@ public class InsetsControllerTest {
false,
new DisplayCutout(
Insets.of(10, 10, 10, 10), rect, rect, rect, rect),
- SOFT_INPUT_ADJUST_RESIZE, 0);
+ SOFT_INPUT_ADJUST_RESIZE, 0, 0);
mController.onFrameChanged(new Rect(0, 0, 100, 100));
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index 5260ef83cc4f..c7d835ca7c7e 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -29,6 +29,7 @@ import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsets.Type.navigationBars;
import static android.view.WindowInsets.Type.statusBars;
+import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
@@ -77,7 +78,7 @@ public class InsetsStateTest {
mState.getSource(ITYPE_IME).setVisible(true);
SparseIntArray typeSideMap = new SparseIntArray();
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_RESIZE, 0, typeSideMap);
+ false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_RESIZE, 0, 0, typeSideMap);
assertEquals(Insets.of(0, 100, 0, 100), insets.getSystemWindowInsets());
assertEquals(Insets.of(0, 100, 0, 100), insets.getInsets(Type.all()));
assertEquals(ISIDE_TOP, typeSideMap.get(ITYPE_STATUS_BAR));
@@ -96,7 +97,7 @@ public class InsetsStateTest {
mState.getSource(ITYPE_IME).setFrame(new Rect(0, 100, 100, 300));
mState.getSource(ITYPE_IME).setVisible(true);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_RESIZE, 0, null);
+ false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_RESIZE, 0, 0, null);
assertEquals(100, insets.getStableInsetBottom());
assertEquals(Insets.of(0, 0, 0, 100), insets.getInsetsIgnoringVisibility(Type.systemBars()));
assertEquals(Insets.of(0, 0, 0, 200), insets.getSystemWindowInsets());
@@ -115,7 +116,7 @@ public class InsetsStateTest {
mState.getSource(ITYPE_NAVIGATION_BAR).setFrame(new Rect(80, 0, 100, 300));
mState.getSource(ITYPE_NAVIGATION_BAR).setVisible(true);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- false, DisplayCutout.NO_CUTOUT, 0, 0, null);
+ false, DisplayCutout.NO_CUTOUT, 0, 0, 0, null);
assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets());
assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(Type.statusBars()));
assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(Type.navigationBars()));
@@ -131,7 +132,7 @@ public class InsetsStateTest {
mState.getSource(ITYPE_IME).setFrame(new Rect(0, 200, 100, 300));
mState.getSource(ITYPE_IME).setVisible(true);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, 0, null);
+ false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, 0, 0, null);
assertEquals(0, insets.getSystemWindowInsetBottom());
assertEquals(100, insets.getInsets(ime()).bottom);
assertTrue(insets.isVisible(ime()));
@@ -147,11 +148,28 @@ public class InsetsStateTest {
mState.getSource(ITYPE_IME).setFrame(new Rect(0, 200, 100, 300));
mState.getSource(ITYPE_IME).setVisible(true);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING,
+ false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, 0,
SYSTEM_UI_FLAG_LAYOUT_STABLE, null);
assertEquals(100, insets.getSystemWindowInsetTop());
insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, false,
- DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING,
+ DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, 0,
+ 0 /* legacySystemUiFlags */, null);
+ assertEquals(0, insets.getSystemWindowInsetTop());
+ }
+ }
+
+ @Test
+ public void testCalculateInsets_systemUiFlagLayoutStable_windowFlagFullscreen() {
+ try (final InsetsModeSession session =
+ new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_FULL)) {
+ mState.getSource(ITYPE_STATUS_BAR).setFrame(new Rect(0, 0, 100, 100));
+ mState.getSource(ITYPE_STATUS_BAR).setVisible(false);
+ WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
+ false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, FLAG_FULLSCREEN,
+ SYSTEM_UI_FLAG_LAYOUT_STABLE, null);
+ assertEquals(0, insets.getSystemWindowInsetTop());
+ insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, false,
+ DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, 0,
0 /* legacySystemUiFlags */, null);
assertEquals(0, insets.getSystemWindowInsetTop());
}
@@ -195,7 +213,7 @@ public class InsetsStateTest {
mState.getSource(ITYPE_EXTRA_NAVIGATION_BAR).setFrame(new Rect(80, 0, 100, 300));
mState.getSource(ITYPE_EXTRA_NAVIGATION_BAR).setVisible(true);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- false, DisplayCutout.NO_CUTOUT, 0, 0, null);
+ false, DisplayCutout.NO_CUTOUT, 0, 0, 0, null);
assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets());
assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(Type.statusBars()));
assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(Type.navigationBars()));
@@ -211,7 +229,7 @@ public class InsetsStateTest {
mState.getSource(ITYPE_NAVIGATION_BAR).setFrame(new Rect(80, 0, 100, 300));
mState.getSource(ITYPE_NAVIGATION_BAR).setVisible(true);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- false, DisplayCutout.NO_CUTOUT, 0, 0, null);
+ false, DisplayCutout.NO_CUTOUT, 0, 0, 0, null);
assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets());
assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(Type.statusBars()));
assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(Type.navigationBars()));
@@ -226,7 +244,7 @@ public class InsetsStateTest {
mState.getSource(ITYPE_IME).setVisible(true);
mState.removeSource(ITYPE_IME);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, false,
- DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_RESIZE, 0, null);
+ DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_RESIZE, 0, 0, null);
assertEquals(0, insets.getSystemWindowInsetBottom());
}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index c710bed29361..5cdcaba6ce48 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -160,6 +160,7 @@ applications that come with the platform
<permission name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/>
<permission name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
<permission name="android.permission.DUMP"/>
+ <permission name="android.permission.HANDLE_CAR_MODE_CHANGES"/>
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
<permission name="android.permission.LOCAL_MAC_ADDRESS"/>
<permission name="android.permission.MANAGE_USERS"/>
@@ -426,6 +427,10 @@ applications that come with the platform
<permission name="android.permission.CAPTURE_AUDIO_OUTPUT" />
<!-- Permissions required for CTS test - AdbManagerTest -->
<permission name="android.permission.MANAGE_DEBUGGING" />
+ <!-- Permissions required for ATS tests - AtsCarHostTestCases, AtsCarDeviceApp -->
+ <permission name="android.car.permission.CAR_DRIVING_STATE" />
+ <!-- Permissions required for ATS tests - AtsDeviceInfo, AtsAudioDeviceTestCases -->
+ <permission name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME" />
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 5a50245a3765..67d8c07e61de 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -149,6 +149,9 @@ void DeferredLayerUpdater::apply() {
sk_sp<SkImage> layerImage = mImageSlots[slot].createIfNeeded(
hardwareBuffer, dataspace, newContent,
mRenderState.getRenderThread().getGrContext());
+ // unref to match the ref added by ASurfaceTexture_dequeueBuffer. eglCreateImageKHR
+ // (invoked by createIfNeeded) will add a ref to the AHardwareBuffer.
+ AHardwareBuffer_release(hardwareBuffer);
if (layerImage.get()) {
SkMatrix textureTransform;
mat4(transformMatrix).copyTo(textureTransform);
diff --git a/location/java/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.java
index 496885cd1f37..6a689756a1c0 100644
--- a/location/java/android/location/GpsStatus.java
+++ b/location/java/android/location/GpsStatus.java
@@ -151,6 +151,15 @@ public final class GpsStatus {
return status;
}
+ /**
+ * Builds an empty GpsStatus.
+ *
+ * @hide
+ */
+ static GpsStatus createEmpty() {
+ return new GpsStatus();
+ }
+
private GpsStatus() {
}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 241e9399be0a..2a2aaea035ff 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -1922,12 +1922,17 @@ public class LocationManager {
GnssStatus gnssStatus = mGnssStatusListenerManager.getGnssStatus();
int ttff = mGnssStatusListenerManager.getTtff();
+
+ // even though this method is marked nullable, there are legacy applications that expect
+ // this to never return null, so avoid breaking those apps
if (gnssStatus != null) {
if (status == null) {
status = GpsStatus.create(gnssStatus, ttff);
} else {
status.setStatus(gnssStatus, ttff);
}
+ } else if (status == null) {
+ status = GpsStatus.createEmpty();
}
return status;
}
diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java
index 590def4d4ced..98ca2f9c4253 100644
--- a/media/java/android/media/MediaCas.java
+++ b/media/java/android/media/MediaCas.java
@@ -34,7 +34,6 @@ import android.media.tv.tunerresourcemanager.ResourceClientProfile;
import android.media.tv.tunerresourcemanager.TunerResourceManager;
import android.os.Bundle;
import android.os.Handler;
-import android.os.HandlerExecutor;
import android.os.HandlerThread;
import android.os.IHwBinder;
import android.os.Looper;
@@ -50,6 +49,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -392,7 +392,10 @@ public final class MediaCas implements AutoCloseable {
@Override
public void onReclaimResources() {
synchronized (mSessionMap) {
- mSessionMap.forEach((casSession, sessionResourceHandle) -> casSession.close());
+ List<Session> sessionList = new ArrayList<>(mSessionMap.keySet());
+ for (Session casSession: sessionList) {
+ casSession.close();
+ }
}
mEventHandler.sendMessage(mEventHandler.obtainMessage(
EventHandler.MSG_CAS_RESOURCE_LOST));
@@ -734,7 +737,7 @@ public final class MediaCas implements AutoCloseable {
ResourceClientProfile profile =
new ResourceClientProfile(tvInputServiceSessionId, priorityHint);
mTunerResourceManager.registerClientProfile(
- profile, new HandlerExecutor(mEventHandler), mResourceListener, clientId);
+ profile, context.getMainExecutor(), mResourceListener, clientId);
mClientId = clientId[0];
}
}
diff --git a/media/java/android/media/MediaMetrics.java b/media/java/android/media/MediaMetrics.java
index f6f482dd0cd3..eaf86bb3936c 100644
--- a/media/java/android/media/MediaMetrics.java
+++ b/media/java/android/media/MediaMetrics.java
@@ -53,6 +53,7 @@ public class MediaMetrics {
public static final String AUDIO_SERVICE = AUDIO + SEPARATOR + "service";
public static final String AUDIO_VOLUME = AUDIO + SEPARATOR + "volume";
public static final String AUDIO_VOLUME_EVENT = AUDIO_VOLUME + SEPARATOR + "event";
+ public static final String AUDIO_MODE = AUDIO + SEPARATOR + "mode";
}
/**
@@ -140,6 +141,10 @@ public class MediaMetrics {
public static final Key<String> REQUEST =
createKey("request", String.class);
+ // For audio mode
+ public static final Key<String> REQUESTED_MODE =
+ createKey("requestedMode", String.class); // audio_mode
+
// For Bluetooth
public static final Key<String> SCO_AUDIO_MODE =
createKey("scoAudioMode", String.class);
diff --git a/packages/CarSystemUI/TEST_MAPPING b/packages/CarSystemUI/TEST_MAPPING
index 6056ddfc0bc7..c18a12aeb2aa 100644
--- a/packages/CarSystemUI/TEST_MAPPING
+++ b/packages/CarSystemUI/TEST_MAPPING
@@ -8,5 +8,16 @@
}
]
}
+ ],
+
+ "carsysui-presubmit": [
+ {
+ "name": "CarSystemUITests",
+ "options" : [
+ {
+ "include-annotation": "com.android.systemui.car.CarSystemUiTest"
+ }
+ ]
+ }
]
}
diff --git a/packages/CarSystemUI/res/layout/system_icons.xml b/packages/CarSystemUI/res/layout/system_icons.xml
index a7dd65eab550..d23579294ce8 100644
--- a/packages/CarSystemUI/res/layout/system_icons.xml
+++ b/packages/CarSystemUI/res/layout/system_icons.xml
@@ -31,10 +31,4 @@
android:gravity="center_vertical"
android:orientation="horizontal"
/>
-
- <com.android.systemui.BatteryMeterView
- android:id="@+id/battery"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- />
</LinearLayout> \ No newline at end of file
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarSystemUiTest.java b/packages/CarSystemUI/src/com/android/systemui/car/CarSystemUiTest.java
new file mode 100644
index 000000000000..5f593b06c511
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/CarSystemUiTest.java
@@ -0,0 +1,32 @@
+/*
+ * 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 com.android.systemui.car;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotates that a test class should be run as part of CarSystemUI presubmit
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@Documented
+public @interface CarSystemUiTest {
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
index 37dfce4e16ce..35b2080dddf9 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
@@ -16,10 +16,12 @@
package com.android.systemui.car.navigationbar;
+import static android.view.InsetsState.ITYPE_BOTTOM_GESTURES;
import static android.view.InsetsState.ITYPE_CLIMATE_BAR;
import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
+import static android.view.InsetsState.ITYPE_TOP_GESTURES;
import static android.view.InsetsState.containsType;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
@@ -368,13 +370,15 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
height,
- WindowManager.LayoutParams.TYPE_STATUS_BAR,
+ WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
PixelFormat.TRANSLUCENT);
lp.setTitle("TopCarNavigationBar");
+ lp.providesInsetsTypes = new int[]{ITYPE_STATUS_BAR, ITYPE_TOP_GESTURES};
+ lp.setFitInsetsTypes(0);
lp.windowAnimations = 0;
lp.gravity = Gravity.TOP;
mWindowManager.addView(mTopNavigationBarWindow, lp);
@@ -388,13 +392,14 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
height,
- WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
+ WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
PixelFormat.TRANSLUCENT);
lp.setTitle("BottomCarNavigationBar");
+ lp.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR, ITYPE_BOTTOM_GESTURES};
lp.windowAnimations = 0;
lp.gravity = Gravity.BOTTOM;
mWindowManager.addView(mBottomNavigationBarWindow, lp);
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java
index 029d4c7fa2fb..0ced4021ce38 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java
@@ -16,7 +16,10 @@
package com.android.systemui.car.navigationbar;
+import static android.view.WindowInsets.Type.systemBars;
+
import android.content.Context;
+import android.graphics.Insets;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
@@ -79,9 +82,28 @@ public class CarNavigationBarView extends LinearLayout {
@Override
public WindowInsets onApplyWindowInsets(WindowInsets windowInsets) {
+ applyMargins(windowInsets.getInsets(systemBars()));
return windowInsets;
}
+ private void applyMargins(Insets insets) {
+ final int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ View child = getChildAt(i);
+ if (child.getLayoutParams() instanceof LayoutParams) {
+ LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ if (lp.rightMargin != insets.right || lp.leftMargin != insets.left
+ || lp.topMargin != insets.top || lp.bottomMargin != insets.bottom) {
+ lp.rightMargin = insets.right;
+ lp.leftMargin = insets.left;
+ lp.topMargin = insets.top;
+ lp.bottomMargin = insets.bottom;
+ child.requestLayout();
+ }
+ }
+ }
+ }
+
// Used to forward touch events even if the touch was initiated from a child component
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/CarStatusBarHeader.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/CarStatusBarHeader.java
index bab67154e75d..0a677bfaa742 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/CarStatusBarHeader.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/CarStatusBarHeader.java
@@ -26,7 +26,6 @@ import android.widget.LinearLayout;
import androidx.annotation.IdRes;
import com.android.settingslib.Utils;
-import com.android.systemui.BatteryMeterView;
import com.android.systemui.R;
import com.android.systemui.plugins.DarkIconDispatcher;
@@ -49,10 +48,7 @@ public class CarStatusBarHeader extends LinearLayout {
float intensity = colorForeground == Color.WHITE ? 0f : 1f;
Rect tintArea = new Rect(0, 0, 0, 0);
- applyDarkness(R.id.battery, tintArea, intensity, colorForeground);
applyDarkness(R.id.clock, tintArea, intensity, colorForeground);
-
- ((BatteryMeterView) findViewById(R.id.battery)).setForceShowPercent(true);
}
private void applyDarkness(@IdRes int id, Rect tintArea, float intensity, int color) {
diff --git a/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java b/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java
index fe59cbf20a13..d769cacadf1d 100644
--- a/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java
@@ -33,6 +33,7 @@ import androidx.test.internal.runner.ClassPathScanner.ExternalClassNameFilter;
import com.android.systemui.SysuiBaseFragmentTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarSystemUiTest;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -55,6 +56,7 @@ import java.util.Collections;
* test suite causes errors, such as the incorrect settings provider being cached.
* For an example, see {@link com.android.systemui.DependencyTest}.
*/
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@SmallTest
public class AAAPlusPlusVerifySysuiRequiredTestPropertiesTest extends SysuiTestCase {
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/HvacControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/HvacControllerTest.java
index 7996170ba7d6..e179ef1ce2a4 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/HvacControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/HvacControllerTest.java
@@ -32,6 +32,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.car.CarServiceProvider;
+import com.android.systemui.car.CarSystemUiTest;
import org.junit.Before;
import org.junit.Test;
@@ -39,6 +40,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
index 189e240169c3..62dc23624520 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
@@ -41,6 +41,7 @@ import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.car.CarServiceProvider;
+import com.android.systemui.car.CarSystemUiTest;
import com.android.systemui.car.navigationbar.CarNavigationBarController;
import com.android.systemui.car.window.OverlayViewGlobalStateController;
import com.android.systemui.keyguard.DismissCallbackRegistry;
@@ -59,6 +60,7 @@ import org.mockito.MockitoAnnotations;
import dagger.Lazy;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonRoleHolderControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonRoleHolderControllerTest.java
index a57736bb3502..4b8268052324 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonRoleHolderControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonRoleHolderControllerTest.java
@@ -39,6 +39,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.car.CarDeviceProvisionedController;
+import com.android.systemui.car.CarSystemUiTest;
import com.android.systemui.tests.R;
import org.junit.Before;
@@ -49,6 +50,7 @@ import org.mockito.MockitoAnnotations;
import java.util.List;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonSelectionStateControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonSelectionStateControllerTest.java
index 893057e222a9..f623c26d12b6 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonSelectionStateControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonSelectionStateControllerTest.java
@@ -28,6 +28,7 @@ import android.widget.LinearLayout;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarSystemUiTest;
import com.android.systemui.tests.R;
import org.junit.Before;
@@ -38,6 +39,7 @@ import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.List;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java
index e84e42c77245..dec8b8ecdfb4 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java
@@ -31,6 +31,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarSystemUiTest;
import com.android.systemui.car.hvac.HvacController;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -41,6 +42,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java
index 0caa86f0eab2..d9edfa960858 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java
@@ -45,6 +45,7 @@ import com.android.internal.view.AppearanceRegion;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.car.CarDeviceProvisionedController;
+import com.android.systemui.car.CarSystemUiTest;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.AutoHideController;
import com.android.systemui.statusbar.phone.LightBarController;
@@ -63,6 +64,7 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarViewTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarViewTest.java
index 19e394f69af4..47fd8201d197 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarViewTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarViewTest.java
@@ -30,6 +30,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarSystemUiTest;
import org.junit.After;
import org.junit.Before;
@@ -38,6 +39,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java
index bcaa5e9a03ee..173f5487c728 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java
@@ -37,6 +37,7 @@ import android.widget.LinearLayout;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarSystemUiTest;
import com.android.systemui.statusbar.AlphaOptimizedImageView;
import com.android.systemui.tests.R;
@@ -45,6 +46,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java
index ccaeb458fe54..384888ab42c3 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java
@@ -30,6 +30,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.car.CarDeviceProvisionedController;
+import com.android.systemui.car.CarSystemUiTest;
import com.android.systemui.car.window.OverlayViewGlobalStateController;
import org.junit.Before;
@@ -38,6 +39,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/NotificationVisibilityLoggerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/NotificationVisibilityLoggerTest.java
index 89dac58cd2a7..d51aeb18135d 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/NotificationVisibilityLoggerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/NotificationVisibilityLoggerTest.java
@@ -37,6 +37,7 @@ import com.android.car.notification.NotificationDataManager;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarSystemUiTest;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -49,6 +50,7 @@ import org.mockito.MockitoAnnotations;
import java.util.Collections;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppDetectorTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppDetectorTest.java
index 77620f3fb345..421e2109356d 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppDetectorTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppDetectorTest.java
@@ -37,6 +37,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.car.CarDeviceProvisionedController;
+import com.android.systemui.car.CarSystemUiTest;
import org.junit.Before;
import org.junit.Test;
@@ -44,6 +45,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java
index 73f9f6a55afc..20576e9ec11f 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java
@@ -35,6 +35,7 @@ import android.view.DisplayInfo;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarSystemUiTest;
import org.junit.Before;
import org.junit.Test;
@@ -46,6 +47,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java
index 797dbf515b7e..2e9d43b595a1 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java
@@ -36,6 +36,7 @@ import android.view.ViewGroup;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarSystemUiTest;
import com.android.systemui.car.window.OverlayViewGlobalStateController;
import org.junit.Before;
@@ -44,6 +45,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java
index a808e2d40e26..de6feb64391f 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java
@@ -25,6 +25,7 @@ import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import com.android.systemui.car.CarServiceProvider;
+import com.android.systemui.car.CarSystemUiTest;
import org.junit.Before;
import org.junit.Test;
@@ -32,6 +33,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java
index 232df2eced39..31f1170c9603 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java
@@ -35,11 +35,13 @@ import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarSystemUiTest;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java
index 45a05ac69bd7..7311cdb68a3c 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java
@@ -39,6 +39,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.car.CarDeviceProvisionedController;
+import com.android.systemui.car.CarSystemUiTest;
import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.tests.R;
@@ -52,6 +53,7 @@ import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.List;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewControllerTest.java
index c24a3b52e348..e784761f6d5d 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewControllerTest.java
@@ -29,6 +29,7 @@ import android.view.ViewGroup;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarSystemUiTest;
import com.android.systemui.tests.R;
import org.junit.Before;
@@ -39,6 +40,7 @@ import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java
index cba42e5a9be4..20f9bc8ec1cb 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java
@@ -32,6 +32,7 @@ import android.view.ViewStub;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarSystemUiTest;
import com.android.systemui.car.navigationbar.CarNavigationBarController;
import com.android.systemui.tests.R;
@@ -44,6 +45,7 @@ import org.mockito.MockitoAnnotations;
import java.util.Arrays;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 570c2ab3efd1..3100e2fce085 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -317,6 +317,11 @@
<!-- Permissions required for CTS test - AdbManagerTest -->
<uses-permission android:name="android.permission.MANAGE_DEBUGGING" />
+ <!-- Permissions required for ATS tests - AtsCarHostTestCases, AtsCarDeviceApp -->
+ <uses-permission android:name="android.car.permission.CAR_DRIVING_STATE" />
+ <!-- Permissions required for ATS tests - AtsDeviceInfo, AtsAudioDeviceTestCases -->
+ <uses-permission android:name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME" />
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index 5c00af5705e9..436188a83d4f 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -62,7 +62,7 @@
android:gravity="center_vertical"
android:focusable="true"
android:singleLine="true"
- android:ellipsize="end"
+ android:ellipsize="marquee"
android:textAppearance="@style/TextAppearance.QS.Status"
android:layout_marginEnd="4dp"
android:visibility="gone"/>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index db45a60ab7c0..f51cffcdfb5c 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2404,17 +2404,26 @@
<!-- Title for notification & dialog that the user's phone last shut down because it got too hot. [CHAR LIMIT=40] -->
<string name="thermal_shutdown_title">Phone turned off due to heat</string>
- <!-- Message body for notification that user's phone last shut down because it got too hot. [CHAR LIMIT=100] -->
- <string name="thermal_shutdown_message">Your phone is now running normally</string>
- <!-- Text body for dialog alerting user that their phone last shut down because it got too hot. [CHAR LIMIT=450] -->
+ <!-- Message body for notification that user's phone last shut down because it got too hot. [CHAR LIMIT=120] -->
+ <string name="thermal_shutdown_message">Your phone is now running normally.\nTap for more info</string>
+ <!-- Text body for dialog alerting user that their phone last shut down because it got too hot. [CHAR LIMIT=500] -->
<string name="thermal_shutdown_dialog_message">Your phone was too hot, so it turned off to cool down. Your phone is now running normally.\n\nYour phone may get too hot if you:\n\t&#8226; Use resource-intensive apps (such as gaming, video, or navigation apps)\n\t&#8226; Download or upload large files\n\t&#8226; Use your phone in high temperatures</string>
+ <!-- Text help link for care instructions for overheating devices [CHAR LIMIT=40] -->
+ <string name="thermal_shutdown_dialog_help_text">See care steps</string>
+ <!-- URL for care instructions for overheating devices -->
+ <string name="thermal_shutdown_dialog_help_url" translatable="false"></string>
<!-- Title for notification (and dialog) that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=30] -->
<string name="high_temp_title">Phone is getting warm</string>
- <!-- Message body for notification that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=100] -->
- <string name="high_temp_notif_message">Some features limited while phone cools down</string>
- <!-- Text body for dialog alerting user that their phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=300] -->
+ <!-- Message body for notification that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=120] -->
+ <string name="high_temp_notif_message">Some features limited while phone cools down.\nTap for more info</string>
+ <!-- Text body for dialog alerting user that their phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=350] -->
<string name="high_temp_dialog_message">Your phone will automatically try to cool down. You can still use your phone, but it may run slower.\n\nOnce your phone has cooled down, it will run normally.</string>
+ <!-- Text help link for care instructions for overheating devices [CHAR LIMIT=40] -->
+ <string name="high_temp_dialog_help_text">See care steps</string>
+ <!-- URL for care instructions for overheating devices -->
+ <string name="high_temp_dialog_help_url" translatable="false"></string>
+
<!-- Title for alarm dialog alerting user the usb adapter has reached a certain temperature that should disconnect charging cable immediately. [CHAR LIMIT=30] -->
<string name="high_temp_alarm_title">Unplug charger</string>
<!-- Text body for dialog alerting user the usb adapter has reached a certain temperature that should disconnect charging cable immediately. [CHAR LIMIT=300] -->
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 6f103b020814..e252195da136 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -207,12 +207,6 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
/** Whether or not the BubbleStackView has been added to the WindowManager. */
private boolean mAddedToWindowManager = false;
- /**
- * Value from {@link NotificationShadeWindowController#getForceHasTopUi()} when we forced top UI
- * due to expansion. We'll restore this value when the stack collapses.
- */
- private boolean mHadTopUi = false;
-
// Listens to user switch so bubbles can be saved and restored.
private final NotificationLockscreenUserManager mNotifUserManager;
@@ -1303,7 +1297,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
// Collapsing? Do this first before remaining steps.
if (update.expandedChanged && !update.expanded) {
mStackView.setExpanded(false);
- mNotificationShadeWindowController.setForceHasTopUi(mHadTopUi);
+ mNotificationShadeWindowController.setRequestTopUi(false, TAG);
}
// Do removals, if any.
@@ -1393,8 +1387,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
if (update.expandedChanged && update.expanded) {
if (mStackView != null) {
mStackView.setExpanded(true);
- mHadTopUi = mNotificationShadeWindowController.getForceHasTopUi();
- mNotificationShadeWindowController.setForceHasTopUi(true);
+ mNotificationShadeWindowController.setRequestTopUi(true, TAG);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index b2e91643bed2..ef51abb1404d 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -2129,7 +2129,6 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
private boolean mShowing;
private float mScrimAlpha;
private ResetOrientationData mResetOrientationData;
- private boolean mHadTopUi;
private final NotificationShadeWindowController mNotificationShadeWindowController;
private final NotificationShadeDepthController mDepthController;
private final SysUiState mSysUiState;
@@ -2397,8 +2396,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
public void show() {
super.show();
mShowing = true;
- mHadTopUi = mNotificationShadeWindowController.getForceHasTopUi();
- mNotificationShadeWindowController.setForceHasTopUi(true);
+ mNotificationShadeWindowController.setRequestTopUi(true, TAG);
mSysUiState.setFlag(SYSUI_STATE_GLOBAL_ACTIONS_SHOWING, true)
.commitUpdate(mContext.getDisplayId());
@@ -2499,7 +2497,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
dismissOverflow(true);
dismissPowerOptions(true);
if (mControlsUiController != null) mControlsUiController.hide();
- mNotificationShadeWindowController.setForceHasTopUi(mHadTopUi);
+ mNotificationShadeWindowController.setRequestTopUi(false, TAG);
mDepthController.updateGlobalDialogVisibility(0, null /* view */);
mSysUiState.setFlag(SYSUI_STATE_GLOBAL_ACTIONS_SHOWING, false)
.commitUpdate(mContext.getDisplayId());
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
index ead17867844a..72019315139b 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
@@ -21,7 +21,6 @@ import android.animation.Animator;
import android.animation.RectEvaluator;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
-import android.content.Context;
import android.graphics.Rect;
import android.view.SurfaceControl;
@@ -56,13 +55,15 @@ public class PipAnimationController {
public static final int TRANSITION_DIRECTION_TO_PIP = 2;
public static final int TRANSITION_DIRECTION_TO_FULLSCREEN = 3;
public static final int TRANSITION_DIRECTION_TO_SPLIT_SCREEN = 4;
+ public static final int TRANSITION_DIRECTION_REMOVE_STACK = 5;
@IntDef(prefix = { "TRANSITION_DIRECTION_" }, value = {
TRANSITION_DIRECTION_NONE,
TRANSITION_DIRECTION_SAME,
TRANSITION_DIRECTION_TO_PIP,
TRANSITION_DIRECTION_TO_FULLSCREEN,
- TRANSITION_DIRECTION_TO_SPLIT_SCREEN
+ TRANSITION_DIRECTION_TO_SPLIT_SCREEN,
+ TRANSITION_DIRECTION_REMOVE_STACK
})
@Retention(RetentionPolicy.SOURCE)
public @interface TransitionDirection {}
@@ -88,7 +89,7 @@ public class PipAnimationController {
});
@Inject
- PipAnimationController(Context context, PipSurfaceTransactionHelper helper) {
+ PipAnimationController(PipSurfaceTransactionHelper helper) {
mSurfaceTransactionHelper = helper;
}
@@ -338,6 +339,10 @@ public class PipAnimationController {
@Override
void onStartTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) {
+ if (getTransitionDirection() == TRANSITION_DIRECTION_REMOVE_STACK) {
+ // while removing the pip stack, no extra work needs to be done here.
+ return;
+ }
getSurfaceTransactionHelper()
.resetScale(tx, leash, getDestinationBounds())
.crop(tx, leash, getDestinationBounds())
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index 0141dee04086..c4152fa9a4e7 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -24,6 +24,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static com.android.systemui.pip.PipAnimationController.ANIM_TYPE_ALPHA;
import static com.android.systemui.pip.PipAnimationController.ANIM_TYPE_BOUNDS;
import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_NONE;
+import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_REMOVE_STACK;
import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_SAME;
import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_FULLSCREEN;
import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
@@ -337,23 +338,32 @@ public class PipTaskOrganizer extends TaskOrganizer implements
+ " mInPip=" + mInPip + " mExitingPip=" + mExitingPip + " mToken=" + mToken);
return;
}
- getUpdateHandler().post(() -> {
- try {
- // Reset the task bounds first to ensure the activity configuration is reset as well
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.setBounds(mToken, null);
- WindowOrganizer.applyTransaction(wct);
-
- ActivityTaskManager.getService().removeStacksInWindowingModes(
- new int[]{ WINDOWING_MODE_PINNED });
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to remove PiP", e);
- }
- });
+
+ // removePipImmediately is expected when the following animation finishes.
+ mUpdateHandler.post(() -> mPipAnimationController
+ .getAnimator(mLeash, mLastReportedBounds, 1f, 0f)
+ .setTransitionDirection(TRANSITION_DIRECTION_REMOVE_STACK)
+ .setPipAnimationCallback(mPipAnimationCallback)
+ .setDuration(mEnterExitAnimationDuration)
+ .start());
mInitialState.remove(mToken.asBinder());
mExitingPip = true;
}
+ private void removePipImmediately() {
+ try {
+ // Reset the task bounds first to ensure the activity configuration is reset as well
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.setBounds(mToken, null);
+ WindowOrganizer.applyTransaction(wct);
+
+ ActivityTaskManager.getService().removeStacksInWindowingModes(
+ new int[]{ WINDOWING_MODE_PINNED });
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to remove PiP", e);
+ }
+ }
+
@Override
public void onTaskAppeared(ActivityManager.RunningTaskInfo info, SurfaceControl leash) {
Objects.requireNonNull(info, "Requires RunningTaskInfo");
@@ -803,7 +813,10 @@ public class PipTaskOrganizer extends TaskOrganizer implements
+ "directly");
}
mLastReportedBounds.set(destinationBounds);
- if (isInPipDirection(direction) && type == ANIM_TYPE_ALPHA) {
+ if (direction == TRANSITION_DIRECTION_REMOVE_STACK) {
+ removePipImmediately();
+ return;
+ } else if (isInPipDirection(direction) && type == ANIM_TYPE_ALPHA) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 10b04c0129e4..6abbbbeaa397 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -24,6 +24,7 @@ import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioAttributes;
@@ -376,13 +377,15 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
return;
}
mHighTempWarning = true;
+ final String message = mContext.getString(R.string.high_temp_notif_message);
final Notification.Builder nb =
new Notification.Builder(mContext, NotificationChannels.ALERTS)
.setSmallIcon(R.drawable.ic_device_thermostat_24)
.setWhen(0)
.setShowWhen(false)
.setContentTitle(mContext.getString(R.string.high_temp_title))
- .setContentText(mContext.getString(R.string.high_temp_notif_message))
+ .setContentText(message)
+ .setStyle(new Notification.BigTextStyle().bigText(message))
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setContentIntent(pendingBroadcast(ACTION_CLICKED_TEMP_WARNING))
.setDeleteIntent(pendingBroadcast(ACTION_DISMISSED_TEMP_WARNING))
@@ -402,6 +405,23 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
d.setPositiveButton(com.android.internal.R.string.ok, null);
d.setShowForAllUsers(true);
d.setOnDismissListener(dialog -> mHighTempDialog = null);
+ final String url = mContext.getString(R.string.high_temp_dialog_help_url);
+ if (!url.isEmpty()) {
+ d.setNeutralButton(R.string.high_temp_dialog_help_text,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ final Intent helpIntent =
+ new Intent(Intent.ACTION_VIEW)
+ .setData(Uri.parse(url))
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ Dependency.get(ActivityStarter.class).startActivity(helpIntent,
+ true /* dismissShade */, resultCode -> {
+ mHighTempDialog = null;
+ });
+ }
+ });
+ }
d.show();
mHighTempDialog = d;
}
@@ -420,19 +440,38 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
d.setPositiveButton(com.android.internal.R.string.ok, null);
d.setShowForAllUsers(true);
d.setOnDismissListener(dialog -> mThermalShutdownDialog = null);
+ final String url = mContext.getString(R.string.thermal_shutdown_dialog_help_url);
+ if (!url.isEmpty()) {
+ d.setNeutralButton(R.string.thermal_shutdown_dialog_help_text,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ final Intent helpIntent =
+ new Intent(Intent.ACTION_VIEW)
+ .setData(Uri.parse(url))
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ Dependency.get(ActivityStarter.class).startActivity(helpIntent,
+ true /* dismissShade */, resultCode -> {
+ mThermalShutdownDialog = null;
+ });
+ }
+ });
+ }
d.show();
mThermalShutdownDialog = d;
}
@Override
public void showThermalShutdownWarning() {
+ final String message = mContext.getString(R.string.thermal_shutdown_message);
final Notification.Builder nb =
new Notification.Builder(mContext, NotificationChannels.ALERTS)
.setSmallIcon(R.drawable.ic_device_thermostat_24)
.setWhen(0)
.setShowWhen(false)
.setContentTitle(mContext.getString(R.string.thermal_shutdown_title))
- .setContentText(mContext.getString(R.string.thermal_shutdown_message))
+ .setContentText(message)
+ .setStyle(new Notification.BigTextStyle().bigText(message))
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setContentIntent(pendingBroadcast(ACTION_CLICKED_THERMAL_SHUTDOWN_WARNING))
.setDeleteIntent(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index c4bb4e86e41e..6e4ab9a3323a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -78,6 +78,8 @@ public class QSFooterImpl extends FrameLayout implements QSFooter,
private SettingsButton mSettingsButton;
protected View mSettingsContainer;
private PageIndicator mPageIndicator;
+ private TextView mBuildText;
+ private boolean mShouldShowBuildText;
private boolean mQsDisabled;
private QSPanel mQsPanel;
@@ -147,6 +149,7 @@ public class QSFooterImpl extends FrameLayout implements QSFooter,
mActionsContainer = findViewById(R.id.qs_footer_actions_container);
mEditContainer = findViewById(R.id.qs_footer_actions_edit_container);
+ mBuildText = findViewById(R.id.build);
// RenderThread is doing more harm than good when touching the header (to expand quick
// settings), so disable it for this view
@@ -162,16 +165,19 @@ public class QSFooterImpl extends FrameLayout implements QSFooter,
}
private void setBuildText() {
- TextView v = findViewById(R.id.build);
- if (v == null) return;
+ if (mBuildText == null) return;
if (DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)) {
- v.setText(mContext.getString(
+ mBuildText.setText(mContext.getString(
com.android.internal.R.string.bugreport_status,
Build.VERSION.RELEASE_OR_CODENAME,
Build.ID));
- v.setVisibility(View.VISIBLE);
+ // Set as selected for marquee before its made visible, then it won't be announced when
+ // it's made visible.
+ mBuildText.setSelected(true);
+ mShouldShowBuildText = true;
} else {
- v.setVisibility(View.GONE);
+ mShouldShowBuildText = false;
+ mBuildText.setSelected(false);
}
}
@@ -321,6 +327,8 @@ public class QSFooterImpl extends FrameLayout implements QSFooter,
mMultiUserSwitch.setVisibility(showUserSwitcher() ? View.VISIBLE : View.INVISIBLE);
mEditContainer.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE);
mSettingsButton.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE);
+
+ mBuildText.setVisibility(mExpanded && mShouldShowBuildText ? View.VISIBLE : View.GONE);
}
private boolean showUserSwitcher() {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index d9d46605f209..570a4bb3cd12 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -197,7 +197,9 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
return;
}
mView.setHidden(mKeyguardStateController.isShowing());
- mImePositionProcessor.updateAdjustForIme();
+ if (!mKeyguardStateController.isShowing()) {
+ mImePositionProcessor.updateAdjustForIme();
+ }
}
@Override
@@ -316,7 +318,7 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
}
private void update(Configuration configuration) {
- final boolean isDividerHidden = mView != null && mView.isHidden();
+ final boolean isDividerHidden = mView != null && mKeyguardStateController.isShowing();
removeDivider();
addDivider(configuration);
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java
index 89f4a94ac877..5aeca5e07bdd 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java
@@ -138,18 +138,20 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
}
@Override
- public void onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
- boolean imeShouldShow, SurfaceControl.Transaction t) {
+ @ImeAnimationFlags
+ public int onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
+ boolean imeShouldShow, boolean imeIsFloating, SurfaceControl.Transaction t) {
mHiddenTop = hiddenTop;
mShownTop = shownTop;
mTargetShown = imeShouldShow;
if (!isDividerVisible()) {
- return;
+ return 0;
}
final boolean splitIsVisible = !getView().isHidden();
mSecondaryHasFocus = getSecondaryHasFocus(displayId);
final boolean targetAdjusted = splitIsVisible && imeShouldShow && mSecondaryHasFocus
- && !getLayout().mDisplayLayout.isLandscape() && !mSplits.mDivider.isMinimized();
+ && !imeIsFloating && !getLayout().mDisplayLayout.isLandscape()
+ && !mSplits.mDivider.isMinimized();
if (mLastAdjustTop < 0) {
mLastAdjustTop = imeShouldShow ? hiddenTop : shownTop;
} else if (mLastAdjustTop != (imeShouldShow ? mShownTop : mHiddenTop)) {
@@ -167,7 +169,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
if (mPaused) {
mPausedTargetAdjusted = targetAdjusted;
if (DEBUG) Slog.d(TAG, " ime starting but paused " + dumpState());
- return;
+ return (targetAdjusted || mAdjusted) ? IME_ANIMATION_NO_ALPHA : 0;
}
mTargetAdjusted = targetAdjusted;
updateDimTargets();
@@ -186,6 +188,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
} else {
mAdjustedWhileHidden = true;
}
+ return (mTargetAdjusted || mAdjusted) ? IME_ANIMATION_NO_ALPHA : 0;
}
private void updateImeAdjustState() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
index c87b9986ca55..91cc8963b947 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
@@ -41,8 +41,8 @@ import com.android.systemui.statusbar.notification.row.StackScrollerDecorView
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.SectionProvider
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.children
-import com.android.systemui.util.takeUntil
import com.android.systemui.util.foldToSparseArray
+import com.android.systemui.util.takeUntil
import javax.inject.Inject
/**
@@ -166,6 +166,9 @@ class NotificationSectionsManager @Inject internal constructor(
peopleHubSubscription?.unsubscribe()
peopleHubSubscription = null
peopleHeaderView = reinflateView(peopleHeaderView, layoutInflater, R.layout.people_strip)
+ .apply {
+ setOnHeaderClickListener(View.OnClickListener { onGentleHeaderClick() })
+ }
if (ENABLE_SNOOZED_CONVERSATION_HUB) {
peopleHubSubscription = peopleHubViewAdapter.bindView(peopleHubViewBoundary)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
index 8f77a1d776e4..b13e7fb839ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
@@ -93,6 +93,8 @@ class PeopleHubView(context: Context, attrs: AttributeSet) :
}
}
+ fun setOnHeaderClickListener(listener: OnClickListener) = label.setOnClickListener(listener)
+
private inner class PersonDataListenerImpl(val avatarView: ImageView) :
DataListener<PersonViewModel?> {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java
index 5164440c1463..bc73be19ab59 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java
@@ -61,6 +61,8 @@ import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
import java.util.function.Consumer;
import javax.inject.Inject;
@@ -432,7 +434,7 @@ public class NotificationShadeWindowController implements Callback, Dumpable,
}
private void applyHasTopUi(State state) {
- mHasTopUiChanged = state.mForceHasTopUi || isExpanded(state);
+ mHasTopUiChanged = !state.mComponentsForcingTopUi.isEmpty() || isExpanded(state);
}
private void applyNotTouchable(State state) {
@@ -635,12 +637,17 @@ public class NotificationShadeWindowController implements Callback, Dumpable,
apply(mCurrentState);
}
- public boolean getForceHasTopUi() {
- return mCurrentState.mForceHasTopUi;
- }
-
- public void setForceHasTopUi(boolean forceHasTopUi) {
- mCurrentState.mForceHasTopUi = forceHasTopUi;
+ /**
+ * SystemUI may need top-ui to avoid jank when performing animations. After the
+ * animation is performed, the component should remove itself from the list of features that
+ * are forcing SystemUI to be top-ui.
+ */
+ public void setRequestTopUi(boolean requestTopUi, String componentTag) {
+ if (requestTopUi) {
+ mCurrentState.mComponentsForcingTopUi.add(componentTag);
+ } else {
+ mCurrentState.mComponentsForcingTopUi.remove(componentTag);
+ }
apply(mCurrentState);
}
@@ -663,7 +670,7 @@ public class NotificationShadeWindowController implements Callback, Dumpable,
boolean mBackdropShowing;
boolean mWallpaperSupportsAmbientMode;
boolean mNotTouchable;
- boolean mForceHasTopUi;
+ Set<String> mComponentsForcingTopUi = new HashSet<>();
/**
* The {@link StatusBar} state from the status bar.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index c14a5ef328aa..b65bd45ce11c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -213,7 +213,6 @@ import com.android.systemui.statusbar.notification.stack.NotificationListContain
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.phone.dagger.StatusBarPhoneModule;
import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
@@ -2397,18 +2396,31 @@ public class StatusBar extends SystemUI implements DemoMode,
new WirelessChargingAnimation.Callback() {
@Override
public void onAnimationStarting() {
+ mNotificationShadeWindowController.setRequestTopUi(true, TAG);
CrossFadeHelper.fadeOut(mNotificationPanelViewController.getView(), 1);
}
@Override
public void onAnimationEnded() {
CrossFadeHelper.fadeIn(mNotificationPanelViewController.getView());
+ mNotificationShadeWindowController.setRequestTopUi(false, TAG);
}
}, mDozing).show(animationDelay);
} else {
// workspace
WirelessChargingAnimation.makeWirelessChargingAnimation(mContext, null,
- transmittingBatteryLevel, batteryLevel, null, false).show(animationDelay);
+ transmittingBatteryLevel, batteryLevel,
+ new WirelessChargingAnimation.Callback() {
+ @Override
+ public void onAnimationStarting() {
+ mNotificationShadeWindowController.setRequestTopUi(true, TAG);
+ }
+
+ @Override
+ public void onAnimationEnded() {
+ mNotificationShadeWindowController.setRequestTopUi(false, TAG);
+ }
+ }, false).show(animationDelay);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 18a7adda3f7d..cf83603997c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -284,6 +284,9 @@ public class MobileSignalController extends SignalController<
mNetworkToIconLookup.put(toDisplayIconKey(
TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE),
TelephonyIcons.NR_5G_PLUS);
+ mNetworkToIconLookup.put(toIconKey(
+ TelephonyManager.NETWORK_TYPE_NR),
+ TelephonyIcons.NR_5G);
}
private String getIconKey() {
@@ -306,9 +309,9 @@ public class MobileSignalController extends SignalController<
case TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO:
return toIconKey(TelephonyManager.NETWORK_TYPE_LTE) + "_CA_Plus";
case TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA:
- return "5G";
+ return toIconKey(TelephonyManager.NETWORK_TYPE_NR);
case TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE:
- return "5G_Plus";
+ return toIconKey(TelephonyManager.NETWORK_TYPE_NR) + "_Plus";
default:
return "unsupported";
}
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
index 3402a52f056a..89f469a438a9 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
@@ -19,6 +19,7 @@ package com.android.systemui.wm;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
+import android.annotation.IntDef;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Point;
@@ -136,12 +137,16 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
}
}
- private void dispatchStartPositioning(int displayId, int hiddenTop, int shownTop,
- boolean show, SurfaceControl.Transaction t) {
+ @ImePositionProcessor.ImeAnimationFlags
+ private int dispatchStartPositioning(int displayId, int hiddenTop, int shownTop,
+ boolean show, boolean isFloating, SurfaceControl.Transaction t) {
synchronized (mPositionProcessors) {
+ int flags = 0;
for (ImePositionProcessor pp : mPositionProcessors) {
- pp.onImeStartPositioning(displayId, hiddenTop, shownTop, show, t);
+ flags |= pp.onImeStartPositioning(
+ displayId, hiddenTop, shownTop, show, isFloating, t);
}
+ return flags;
}
}
@@ -184,6 +189,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
int mRotation = Surface.ROTATION_0;
boolean mImeShowing = false;
final Rect mImeFrame = new Rect();
+ boolean mAnimateAlpha = true;
PerDisplay(int displayId, int initialRotation) {
mDisplayId = displayId;
@@ -273,15 +279,29 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
return mImeFrame.top + (int) surfaceOffset;
}
+ private boolean calcIsFloating(InsetsSource imeSource) {
+ final Rect frame = imeSource.getFrame();
+ if (frame.height() == 0) {
+ return true;
+ }
+ // Some Floating Input Methods will still report a frame, but the frame is actually
+ // a nav-bar inset created by WM and not part of the IME (despite being reported as
+ // an IME inset). For now, we assume that no non-floating IME will be <= this nav bar
+ // frame height so any reported frame that is <= nav-bar frame height is assumed to
+ // be floating.
+ return frame.height() <= mSystemWindows.mDisplayController.getDisplayLayout(mDisplayId)
+ .navBarFrameHeight();
+ }
+
private void startAnimation(final boolean show, final boolean forceRestart) {
final InsetsSource imeSource = mInsetsState.getSource(InsetsState.ITYPE_IME);
if (imeSource == null || mImeSourceControl == null) {
return;
}
final Rect newFrame = imeSource.getFrame();
- final boolean isFloating = newFrame.height() == 0 && show;
+ final boolean isFloating = calcIsFloating(imeSource) && show;
if (isFloating) {
- // This is likely a "floating" or "expanded" IME, so to get animations, just
+ // This is a "floating" or "expanded" IME, so to get animations, just
// pretend the ime has some size just below the screen.
mImeFrame.set(newFrame);
final int floatingInset = (int) (
@@ -334,7 +354,8 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
SurfaceControl.Transaction t = mTransactionPool.acquire();
float value = (float) animation.getAnimatedValue();
t.setPosition(mImeSourceControl.getLeash(), x, value);
- final float alpha = isFloating ? (value - hiddenY) / (shownY - hiddenY) : 1.f;
+ final float alpha = (mAnimateAlpha || isFloating)
+ ? (value - hiddenY) / (shownY - hiddenY) : 1.f;
t.setAlpha(mImeSourceControl.getLeash(), alpha);
dispatchPositionChanged(mDisplayId, imeTop(value), t);
t.apply();
@@ -347,16 +368,18 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
public void onAnimationStart(Animator animation) {
SurfaceControl.Transaction t = mTransactionPool.acquire();
t.setPosition(mImeSourceControl.getLeash(), x, startY);
- final float alpha = isFloating ? (startY - hiddenY) / (shownY - hiddenY) : 1.f;
- t.setAlpha(mImeSourceControl.getLeash(), alpha);
if (DEBUG) {
Slog.d(TAG, "onAnimationStart d:" + mDisplayId + " top:"
+ imeTop(hiddenY) + "->" + imeTop(shownY)
+ " showing:" + (mAnimationDirection == DIRECTION_SHOW));
}
- dispatchStartPositioning(mDisplayId, imeTop(hiddenY),
- imeTop(shownY), mAnimationDirection == DIRECTION_SHOW,
- t);
+ int flags = dispatchStartPositioning(mDisplayId, imeTop(hiddenY),
+ imeTop(shownY), mAnimationDirection == DIRECTION_SHOW, isFloating, t);
+ mAnimateAlpha = (flags & ImePositionProcessor.IME_ANIMATION_NO_ALPHA) == 0;
+ final float alpha = (mAnimateAlpha || isFloating)
+ ? (startY - hiddenY) / (shownY - hiddenY)
+ : 1.f;
+ t.setAlpha(mImeSourceControl.getLeash(), alpha);
if (mAnimationDirection == DIRECTION_SHOW) {
t.show(mImeSourceControl.getLeash());
}
@@ -419,15 +442,33 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
*/
public interface ImePositionProcessor {
/**
+ * Indicates that ime shouldn't animate alpha. It will always be opaque. Used when stuff
+ * behind the IME shouldn't be visible (for example during split-screen adjustment where
+ * there is nothing behind the ime).
+ */
+ int IME_ANIMATION_NO_ALPHA = 1;
+
+ /** @hide */
+ @IntDef(prefix = { "IME_ANIMATION_" }, value = {
+ IME_ANIMATION_NO_ALPHA,
+ })
+ @interface ImeAnimationFlags {}
+
+ /**
* Called when the IME position is starting to animate.
*
* @param hiddenTop The y position of the top of the IME surface when it is hidden.
* @param shownTop The y position of the top of the IME surface when it is shown.
* @param showing {@code true} when we are animating from hidden to shown, {@code false}
* when animating from shown to hidden.
+ * @param isFloating {@code true} when the ime is a floating ime (doesn't inset).
+ * @return flags that may alter how ime itself is animated (eg. no-alpha).
*/
- default void onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
- boolean showing, SurfaceControl.Transaction t) {}
+ @ImeAnimationFlags
+ default int onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
+ boolean showing, boolean isFloating, SurfaceControl.Transaction t) {
+ return 0;
+ }
/**
* Called when the ime position changed. This is expected to be a synchronous call on the
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java
index cfec1c07ff1d..a341f3050ea6 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java
@@ -79,6 +79,7 @@ public class DisplayLayout {
private final Rect mStableInsets = new Rect();
private boolean mHasNavigationBar = false;
private boolean mHasStatusBar = false;
+ private int mNavBarFrameHeight = 0;
/**
* Create empty layout.
@@ -146,6 +147,7 @@ public class DisplayLayout {
if (mHasStatusBar) {
convertNonDecorInsetsToStableInsets(res, mStableInsets, mWidth, mHeight, mHasStatusBar);
}
+ mNavBarFrameHeight = getNavigationBarFrameHeight(res, mWidth > mHeight);
}
/**
@@ -214,6 +216,11 @@ public class DisplayLayout {
return mWidth > mHeight;
}
+ /** Get the navbar frame height (used by ime). */
+ public int navBarFrameHeight() {
+ return mNavBarFrameHeight;
+ }
+
/** Gets the orientation of this layout */
public int getOrientation() {
return (mWidth > mHeight) ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
@@ -483,6 +490,7 @@ public class DisplayLayout {
} else {
return res.getDimensionPixelSize(R.dimen.navigation_bar_width_car_mode);
}
+
} else {
if (navBarSide == NAV_BAR_BOTTOM) {
return res.getDimensionPixelSize(landscape
@@ -493,4 +501,11 @@ public class DisplayLayout {
}
}
}
+
+ /** @see com.android.server.wm.DisplayPolicy#getNavigationBarFrameHeight */
+ public static int getNavigationBarFrameHeight(Resources res, boolean landscape) {
+ return res.getDimensionPixelSize(landscape
+ ? R.dimen.navigation_bar_frame_height_landscape
+ : R.dimen.navigation_bar_frame_height);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
index 536cae4380c4..c9c111198f4c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
@@ -61,8 +61,7 @@ public class PipAnimationControllerTest extends SysuiTestCase {
@Before
public void setUp() throws Exception {
mPipAnimationController = new PipAnimationController(
- mContext, new PipSurfaceTransactionHelper(mContext,
- mock(ConfigurationController.class)));
+ new PipSurfaceTransactionHelper(mContext, mock(ConfigurationController.class)));
mLeash = new SurfaceControl.Builder()
.setContainerLayer()
.setName("FakeLeash")
diff --git a/packages/WAPPushManager/AndroidManifest.xml b/packages/WAPPushManager/AndroidManifest.xml
index 14e6e91e3a25..a75fb2d47bbd 100644
--- a/packages/WAPPushManager/AndroidManifest.xml
+++ b/packages/WAPPushManager/AndroidManifest.xml
@@ -23,6 +23,8 @@
<permission android:name="com.android.smspush.WAPPUSH_MANAGER_BIND"
android:protectionLevel="signatureOrSystem" />
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+
<original-package android:name="com.android.smspush" />
<application
android:allowClearUserData="false">
diff --git a/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
index 19248ca54611..c25dd37bc7d9 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
@@ -31,9 +31,16 @@ import com.android.server.inputmethod.InputMethodManagerInternal;
import java.util.Optional;
import java.util.function.Consumer;
-
/**
- * Controls the interaction with the IME for the inline suggestion sessions.
+ * Controls the interaction with the IME for the {@link AutofillInlineSuggestionsRequestSession}s.
+ *
+ * <p>The class maintains the inline suggestion session with the autofill service. There is at most
+ * one active inline suggestion session at any given corresponding to one focused view.
+ * New sessions are created only when {@link #onCreateInlineSuggestionsRequestLocked} is called.</p>
+ *
+ * <p>The class manages the interaction between the {@link com.android.server.autofill.Session} and
+ * the inline suggestion session whenever inline suggestions can be provided. All calls to the
+ * inline suggestion session must be made through this controller.</p>
*/
final class AutofillInlineSessionController {
@NonNull
@@ -66,7 +73,6 @@ final class AutofillInlineSessionController {
mUiCallback = callback;
}
-
/**
* Requests the IME to create an {@link InlineSuggestionsRequest} for {@code autofillId}.
*
diff --git a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
index b2daae48bb0e..84fbe9a75a18 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
@@ -364,6 +364,9 @@ final class AutofillInlineSuggestionsRequestSession {
}
}
+ /**
+ * Internal implementation of {@link IInlineSuggestionsRequestCallback}.
+ */
private static final class InlineSuggestionsRequestCallbackImpl extends
IInlineSuggestionsRequestCallback.Stub {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 56953708e383..3f867f656c24 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -18,7 +18,6 @@ package com.android.server.am;
import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST;
import static android.os.Process.NFC_UID;
import static android.os.Process.ROOT_UID;
@@ -1361,13 +1360,12 @@ public final class ActiveServices {
+ String.format("0x%08X", manifestType)
+ " in service element of manifest file");
}
- if ((foregroundServiceType & FOREGROUND_SERVICE_TYPE_LOCATION) != 0
- && !r.mAllowWhileInUsePermissionInFgs) {
- // If the foreground service is not started from TOP process, do not allow it to
- // have location capability, this prevents BG started FGS to have while-in-use
- // location permission.
+ // If the foreground service is not started from TOP process, do not allow it to
+ // have while-in-use location/camera/microphone access.
+ if (!r.mAllowWhileInUsePermissionInFgs) {
Slog.w(TAG,
- "BG started FGS can not have location capability: service "
+ "Foreground service started from background can not have "
+ + "location/camera/microphone access: service "
+ r.shortInstanceName);
}
}
diff --git a/services/core/java/com/android/server/am/AppExitInfoTracker.java b/services/core/java/com/android/server/am/AppExitInfoTracker.java
index 02fb34e73f7f..374c215fc6d0 100644
--- a/services/core/java/com/android/server/am/AppExitInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppExitInfoTracker.java
@@ -522,7 +522,7 @@ public final class AppExitInfoTracker {
AppExitInfoContainer container = records.get(filterUid);
if (container != null) {
mTmpInfoList.clear();
- results.addAll(container.toListLocked(mTmpInfoList, filterPid));
+ list.addAll(container.toListLocked(mTmpInfoList, filterPid));
}
return AppExitInfoTracker.FOREACH_ACTION_NONE;
});
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 5e908b26fafa..c4eca605206d 100755
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -283,6 +283,7 @@ public class AudioService extends IAudioService.Stub
private static final int MSG_HDMI_VOLUME_CHECK = 28;
private static final int MSG_PLAYBACK_CONFIG_CHANGE = 29;
private static final int MSG_BROADCAST_MICROPHONE_MUTE = 30;
+ private static final int MSG_CHECK_MODE_FOR_UID = 31;
// start of messages handled under wakelock
// these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
// and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
@@ -3679,12 +3680,14 @@ public class AudioService extends IAudioService.Stub
private final IBinder mCb; // To be notified of client's death
private final int mPid;
private final int mUid;
+ private String mPackage;
private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
- SetModeDeathHandler(IBinder cb, int pid, int uid) {
+ SetModeDeathHandler(IBinder cb, int pid, int uid, String caller) {
mCb = cb;
mPid = pid;
mUid = uid;
+ mPackage = caller;
}
public void binderDied() {
@@ -3722,6 +3725,10 @@ public class AudioService extends IAudioService.Stub
public int getUid() {
return mUid;
}
+
+ public String getPackage() {
+ return mPackage;
+ }
}
/** @see AudioManager#setMode(int) */
@@ -3803,6 +3810,9 @@ public class AudioService extends IAudioService.Stub
hdlr = h;
// Remove from client list so that it is re-inserted at top of list
iter.remove();
+ if (hdlr.getMode() == AudioSystem.MODE_IN_COMMUNICATION) {
+ mAudioHandler.removeEqualMessages(MSG_CHECK_MODE_FOR_UID, hdlr);
+ }
try {
hdlr.getBinder().unlinkToDeath(hdlr, 0);
if (cb != hdlr.getBinder()) {
@@ -3833,7 +3843,7 @@ public class AudioService extends IAudioService.Stub
}
} else {
if (hdlr == null) {
- hdlr = new SetModeDeathHandler(cb, pid, uid);
+ hdlr = new SetModeDeathHandler(cb, pid, uid, caller);
}
// Register for client death notification
try {
@@ -3880,6 +3890,7 @@ public class AudioService extends IAudioService.Stub
// Note: newModeOwnerPid is always 0 when actualMode is MODE_NORMAL
mModeLogger.log(
new PhoneStateEvent(caller, pid, mode, newModeOwnerPid, actualMode));
+
int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
int device = getDeviceForStream(streamType);
int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
@@ -3890,6 +3901,16 @@ public class AudioService extends IAudioService.Stub
// change of mode may require volume to be re-applied on some devices
updateAbsVolumeMultiModeDevices(oldMode, actualMode);
+
+ if (actualMode == AudioSystem.MODE_IN_COMMUNICATION) {
+ sendMsg(mAudioHandler,
+ MSG_CHECK_MODE_FOR_UID,
+ SENDMSG_QUEUE,
+ 0,
+ 0,
+ hdlr,
+ CHECK_MODE_FOR_UID_PERIOD_MS);
+ }
}
return newModeOwnerPid;
}
@@ -6374,6 +6395,35 @@ public class AudioService extends IAudioService.Stub
case MSG_BROADCAST_MICROPHONE_MUTE:
mSystemServer.sendMicrophoneMuteChangedIntent();
break;
+
+ case MSG_CHECK_MODE_FOR_UID:
+ synchronized (mDeviceBroker.mSetModeLock) {
+ if (msg.obj == null) {
+ break;
+ }
+ // If the app corresponding to this mode death handler object is not
+ // capturing or playing audio anymore after 3 seconds, remove it
+ // from the stack. Otherwise, check again in 3 seconds.
+ SetModeDeathHandler h = (SetModeDeathHandler) msg.obj;
+ if (mSetModeDeathHandlers.indexOf(h) < 0) {
+ break;
+ }
+ if (mRecordMonitor.isRecordingActiveForUid(h.getUid())
+ || mPlaybackMonitor.isPlaybackActiveForUid(h.getUid())) {
+ sendMsg(mAudioHandler,
+ MSG_CHECK_MODE_FOR_UID,
+ SENDMSG_QUEUE,
+ 0,
+ 0,
+ h,
+ CHECK_MODE_FOR_UID_PERIOD_MS);
+ break;
+ }
+ // For now just log the fact that an app is hogging the audio mode.
+ // TODO(b/160260850): remove abusive app from audio mode stack.
+ mModeLogger.log(new PhoneStateEvent(h.getPackage(), h.getPid()));
+ }
+ break;
}
}
}
@@ -7017,6 +7067,8 @@ public class AudioService extends IAudioService.Stub
private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000; // 1 minute polling interval
private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed
+ // check playback or record activity every 3 seconds for UIDs owning mode IN_COMMUNICATION
+ private static final int CHECK_MODE_FOR_UID_PERIOD_MS = 3000;
private int safeMediaVolumeIndex(int device) {
if (!mSafeMediaVolumeDevices.contains(device)) {
diff --git a/services/core/java/com/android/server/audio/AudioServiceEvents.java b/services/core/java/com/android/server/audio/AudioServiceEvents.java
index f3ff02f3aedc..0eb5a5d1fb48 100644
--- a/services/core/java/com/android/server/audio/AudioServiceEvents.java
+++ b/services/core/java/com/android/server/audio/AudioServiceEvents.java
@@ -27,28 +27,82 @@ import com.android.server.audio.AudioDeviceInventory.WiredDeviceConnectionState;
public class AudioServiceEvents {
final static class PhoneStateEvent extends AudioEventLogger.Event {
+ static final int MODE_SET = 0;
+ static final int MODE_IN_COMMUNICATION_TIMEOUT = 1;
+
+ final int mOp;
final String mPackage;
final int mOwnerPid;
final int mRequesterPid;
final int mRequestedMode;
final int mActualMode;
+ /** used for MODE_SET */
PhoneStateEvent(String callingPackage, int requesterPid, int requestedMode,
int ownerPid, int actualMode) {
+ mOp = MODE_SET;
mPackage = callingPackage;
mRequesterPid = requesterPid;
mRequestedMode = requestedMode;
mOwnerPid = ownerPid;
mActualMode = actualMode;
+ logMetricEvent();
+ }
+
+ /** used for MODE_IN_COMMUNICATION_TIMEOUT */
+ PhoneStateEvent(String callingPackage, int ownerPid) {
+ mOp = MODE_IN_COMMUNICATION_TIMEOUT;
+ mPackage = callingPackage;
+ mOwnerPid = ownerPid;
+ mRequesterPid = 0;
+ mRequestedMode = 0;
+ mActualMode = 0;
+ logMetricEvent();
}
@Override
public String eventToString() {
- return new StringBuilder("setMode(").append(AudioSystem.modeToString(mRequestedMode))
- .append(") from package=").append(mPackage)
- .append(" pid=").append(mRequesterPid)
- .append(" selected mode=").append(AudioSystem.modeToString(mActualMode))
- .append(" by pid=").append(mOwnerPid).toString();
+ switch (mOp) {
+ case MODE_SET:
+ return new StringBuilder("setMode(")
+ .append(AudioSystem.modeToString(mRequestedMode))
+ .append(") from package=").append(mPackage)
+ .append(" pid=").append(mRequesterPid)
+ .append(" selected mode=")
+ .append(AudioSystem.modeToString(mActualMode))
+ .append(" by pid=").append(mOwnerPid).toString();
+ case MODE_IN_COMMUNICATION_TIMEOUT:
+ return new StringBuilder("mode IN COMMUNICATION timeout")
+ .append(" for package=").append(mPackage)
+ .append(" pid=").append(mOwnerPid).toString();
+ default: return new StringBuilder("FIXME invalid op:").append(mOp).toString();
+ }
+ }
+
+ /**
+ * Audio Analytics unique Id.
+ */
+ private static final String mMetricsId = MediaMetrics.Name.AUDIO_MODE;
+
+ private void logMetricEvent() {
+ switch (mOp) {
+ case MODE_SET:
+ new MediaMetrics.Item(mMetricsId)
+ .set(MediaMetrics.Property.EVENT, "set")
+ .set(MediaMetrics.Property.REQUESTED_MODE,
+ AudioSystem.modeToString(mRequestedMode))
+ .set(MediaMetrics.Property.MODE, AudioSystem.modeToString(mActualMode))
+ .set(MediaMetrics.Property.CALLING_PACKAGE, mPackage)
+ .record();
+ return;
+ case MODE_IN_COMMUNICATION_TIMEOUT:
+ new MediaMetrics.Item(mMetricsId)
+ .set(MediaMetrics.Property.EVENT, "inCommunicationTimeout")
+ .set(MediaMetrics.Property.CALLING_PACKAGE, mPackage)
+ .record();
+ return;
+ default: return;
+ }
}
}
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index 98f409ea98e7..a5778836aa6e 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -366,6 +366,23 @@ public final class PlaybackActivityMonitor
releasePlayer(piid, 0);
}
+ /**
+ * Returns true if a player belonging to the app with given uid is active.
+ *
+ * @param uid the app uid
+ * @return true if a player is active, false otherwise
+ */
+ public boolean isPlaybackActiveForUid(int uid) {
+ synchronized (mPlayerLock) {
+ for (AudioPlaybackConfiguration apc : mPlayers.values()) {
+ if (apc.isActive() && apc.getClientUid() == uid) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
protected void dump(PrintWriter pw) {
// players
pw.println("\nPlaybackActivityMonitor dump time: "
diff --git a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
index 32c6cc32a78d..ea0107ecfd23 100644
--- a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
@@ -215,6 +215,25 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin
dispatchCallbacks(updateSnapshot(AudioManager.RECORD_CONFIG_EVENT_RELEASE, riid, null));
}
+ /**
+ * Returns true if a recorder belonging to the app with given uid is active.
+ *
+ * @param uid the app uid
+ * @return true if a recorder is active, false otherwise
+ */
+ public boolean isRecordingActiveForUid(int uid) {
+ synchronized (mRecordStates) {
+ for (RecordingState state : mRecordStates) {
+ // Note: isActiveConfiguration() == true => state.getConfig() != null
+ if (state.isActiveConfiguration()
+ && state.getConfig().getClientUid() == uid) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
private void dispatchCallbacks(List<AudioRecordingConfiguration> configs) {
if (configs == null) { // null means "no changes"
return;
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index 85544d0a1b02..a6a607e4ce66 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -718,7 +718,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
GnssSatelliteBlacklistHelper gnssSatelliteBlacklistHelper =
new GnssSatelliteBlacklistHelper(mContext,
mLooper, this);
- mHandler.post(gnssSatelliteBlacklistHelper::updateSatelliteBlacklist);
mGnssBatchingProvider = new GnssBatchingProvider();
mGnssGeofenceProvider = new GnssGeofenceProvider();
@@ -746,6 +745,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
setAllowed(true);
sendMessage(INITIALIZE_HANDLER, 0, null);
+ mHandler.post(gnssSatelliteBlacklistHelper::updateSatelliteBlacklist);
}
/**
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 87f0fb14ee33..d6557f6410ec 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -3910,11 +3910,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private void updateRulesForAppIdleParoleUL() {
final boolean paroled = mAppStandby.isInParole();
final boolean enableChain = !paroled;
- enableFirewallChainUL(FIREWALL_CHAIN_STANDBY, enableChain);
int ruleCount = mUidFirewallStandbyRules.size();
+ final SparseIntArray blockedUids = new SparseIntArray();
for (int i = 0; i < ruleCount; i++) {
final int uid = mUidFirewallStandbyRules.keyAt(i);
+ if (!isUidValidForBlacklistRulesUL(uid)) {
+ continue;
+ }
int oldRules = mUidRules.get(uid);
if (enableChain) {
// Chain wasn't enabled before and the other power-related
@@ -3926,13 +3929,24 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// Skip if it had no restrictions to begin with
if ((oldRules & MASK_ALL_NETWORKS) == 0) continue;
}
- final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldRules, paroled);
+ final boolean isUidIdle = !paroled && isUidIdle(uid);
+ if (isUidIdle && !mPowerSaveTempWhitelistAppIds.get(UserHandle.getAppId(uid))
+ && !isUidForegroundOnRestrictPowerUL(uid)) {
+ mUidFirewallStandbyRules.put(uid, FIREWALL_RULE_DENY);
+ blockedUids.put(uid, FIREWALL_RULE_DENY);
+ } else {
+ mUidFirewallStandbyRules.put(uid, FIREWALL_RULE_DEFAULT);
+ }
+ final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldRules,
+ isUidIdle);
if (newUidRules == RULE_NONE) {
mUidRules.delete(uid);
} else {
mUidRules.put(uid, newUidRules);
}
}
+ setUidFirewallRulesUL(FIREWALL_CHAIN_STANDBY, blockedUids,
+ enableChain ? CHAIN_TOGGLE_ENABLE : CHAIN_TOGGLE_DISABLE);
}
/**
@@ -4400,7 +4414,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private void updateRulesForPowerRestrictionsUL(int uid) {
final int oldUidRules = mUidRules.get(uid, RULE_NONE);
- final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldUidRules, false);
+ final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldUidRules,
+ isUidIdle(uid));
if (newUidRules == RULE_NONE) {
mUidRules.delete(uid);
@@ -4414,33 +4429,33 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
*
* @param uid the uid of the app to update rules for
* @param oldUidRules the current rules for the uid, in order to determine if there's a change
- * @param paroled whether to ignore idle state of apps and only look at other restrictions
+ * @param isUidIdle whether uid is idle or not
*
* @return the new computed rules for the uid
*/
@GuardedBy("mUidRulesFirstLock")
- private int updateRulesForPowerRestrictionsUL(int uid, int oldUidRules, boolean paroled) {
+ private int updateRulesForPowerRestrictionsUL(int uid, int oldUidRules, boolean isUidIdle) {
if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) {
Trace.traceBegin(Trace.TRACE_TAG_NETWORK,
"updateRulesForPowerRestrictionsUL: " + uid + "/" + oldUidRules + "/"
- + (paroled ? "P" : "-"));
+ + (isUidIdle ? "I" : "-"));
}
try {
- return updateRulesForPowerRestrictionsULInner(uid, oldUidRules, paroled);
+ return updateRulesForPowerRestrictionsULInner(uid, oldUidRules, isUidIdle);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
}
}
@GuardedBy("mUidRulesFirstLock")
- private int updateRulesForPowerRestrictionsULInner(int uid, int oldUidRules, boolean paroled) {
+ private int updateRulesForPowerRestrictionsULInner(int uid, int oldUidRules,
+ boolean isUidIdle) {
if (!isUidValidForBlacklistRulesUL(uid)) {
if (LOGD) Slog.d(TAG, "no need to update restrict power rules for uid " + uid);
return RULE_NONE;
}
- final boolean isIdle = !paroled && isUidIdle(uid);
- final boolean restrictMode = isIdle || mRestrictPower || mDeviceIdleMode;
+ final boolean restrictMode = isUidIdle || mRestrictPower || mDeviceIdleMode;
final boolean isForeground = isUidForegroundOnRestrictPowerUL(uid);
final boolean isWhitelisted = isWhitelistedFromPowerSaveUL(uid, mDeviceIdleMode);
@@ -4463,7 +4478,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
if (LOGV) {
Log.v(TAG, "updateRulesForPowerRestrictionsUL(" + uid + ")"
- + ", isIdle: " + isIdle
+ + ", isIdle: " + isUidIdle
+ ", mRestrictPower: " + mRestrictPower
+ ", mDeviceIdleMode: " + mDeviceIdleMode
+ ", isForeground=" + isForeground
@@ -5273,6 +5288,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@Override
public void onTempPowerSaveWhitelistChange(int appId, boolean added) {
synchronized (mUidRulesFirstLock) {
+ if (!mSystemReady) {
+ return;
+ }
mLogger.tempPowerSaveWlChanged(appId, added);
if (added) {
mPowerSaveTempWhitelistAppIds.put(appId, true);
diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
index a0ab5eae7315..cb1c7e4fd0de 100644
--- a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
+++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
@@ -16,11 +16,13 @@
package com.android.server.net;
+import static android.net.NetworkTemplate.NETWORK_TYPE_5G_NSA;
import static android.net.NetworkTemplate.getCollapsedRatType;
import android.annotation.NonNull;
import android.content.Context;
import android.telephony.Annotation;
+import android.telephony.NetworkRegistrationInfo;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
@@ -195,7 +197,18 @@ public class NetworkStatsSubscriptionsMonitor extends
@Override
public void onServiceStateChanged(@NonNull ServiceState ss) {
- final int networkType = ss.getDataNetworkType();
+ // In 5G SA (Stand Alone) mode, the primary cell itself will be 5G hence telephony
+ // would report RAT = 5G_NR.
+ // However, in 5G NSA (Non Stand Alone) mode, the primary cell is still LTE and
+ // network allocates a secondary 5G cell so telephony reports RAT = LTE along with
+ // NR state as connected. In such case, attributes the data usage to NR.
+ // See b/160727498.
+ final boolean is5GNsa = (ss.getDataNetworkType() == TelephonyManager.NETWORK_TYPE_LTE
+ || ss.getDataNetworkType() == TelephonyManager.NETWORK_TYPE_LTE_CA)
+ && ss.getNrState() == NetworkRegistrationInfo.NR_STATE_CONNECTED;
+
+ final int networkType =
+ (is5GNsa ? NETWORK_TYPE_5G_NSA : ss.getDataNetworkType());
final int collapsedRatType = getCollapsedRatType(networkType);
if (collapsedRatType == mLastCollapsedRatType) return;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index a2d0eaedbd44..b4ab57fa4dc8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -25539,7 +25539,8 @@ public class PackageManagerService extends IPackageManager.Stub
private void applyMimeGroupChanges(String packageName, String mimeGroup) {
if (mComponentResolver.updateMimeGroup(packageName, mimeGroup)) {
- clearPackagePreferredActivities(packageName, UserHandle.USER_ALL);
+ Binder.withCleanCallingIdentity(() ->
+ clearPackagePreferredActivities(packageName, UserHandle.USER_ALL));
}
mPmInternal.writeSettings(false);
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 936ba7f3b097..3de2dc2fdef3 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -1407,7 +1407,7 @@ public final class Settings {
if (pa.mPref.getParseError() == null) {
final PreferredIntentResolver resolver = editPreferredActivitiesLPw(userId);
ArrayList<PreferredActivity> pal = resolver.findFilters(pa);
- if (pal == null || pal.size() == 0) {
+ if (pal == null || pal.size() == 0 || pa.mPref.mAlways) {
resolver.addFilter(pa);
}
} else {
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 8868a6c2e6d8..b9431a6968f9 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -141,6 +141,10 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
@IntDef({NAV_BAR_LEFT, NAV_BAR_RIGHT, NAV_BAR_BOTTOM})
@interface NavigationBarPosition {}
+ @Retention(SOURCE)
+ @IntDef({ALT_BAR_UNKNOWN, ALT_BAR_LEFT, ALT_BAR_RIGHT, ALT_BAR_BOTTOM, ALT_BAR_TOP})
+ @interface AltBarPosition {}
+
/**
* Pass this event to the user / app. To be returned from
* {@link #interceptKeyBeforeQueueing}.
@@ -396,14 +400,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
return false;
}
- /**
- * Returns true if the window has a letterbox and any part of that letterbox overlaps with
- * the given {@code rect}.
- */
- default boolean isLetterboxedOverlappingWith(Rect rect) {
- return false;
- }
-
/** @return the current windowing mode of this window. */
int getWindowingMode();
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 dbdef2368c7c..8979d8c6ba10 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -1145,6 +1145,15 @@ public class StatsPullAtomService extends SystemService {
private void addDataUsageBytesTransferAtoms(@NonNull NetworkStatsExt statsExt,
@NonNull List<StatsEvent> pulledData) {
+
+ // Workaround for 5G NSA mode, see {@link NetworkTemplate#NETWORK_TYPE_5G_NSA}.
+ // 5G NSA mode means the primary cell is LTE with a secondary connection to an
+ // NR cell. To mitigate risk, NetworkStats is currently storing this state as
+ // a fake RAT type rather than storing the boolean separately.
+ final boolean is5GNsa = statsExt.ratType == NetworkTemplate.NETWORK_TYPE_5G_NSA;
+ // Report NR connected in 5G non-standalone mode, or if the RAT type is NR to begin with.
+ final boolean isNR = is5GNsa || statsExt.ratType == TelephonyManager.NETWORK_TYPE_NR;
+
final NetworkStats.Entry entry = new NetworkStats.Entry(); // for recycling
for (int i = 0; i < statsExt.stats.size(); i++) {
statsExt.stats.getValues(i, entry);
@@ -1156,7 +1165,7 @@ public class StatsPullAtomService extends SystemService {
.writeLong(entry.rxPackets)
.writeLong(entry.txBytes)
.writeLong(entry.txPackets)
- .writeInt(statsExt.ratType)
+ .writeInt(is5GNsa ? TelephonyManager.NETWORK_TYPE_LTE : statsExt.ratType)
// Fill information about subscription, these cannot be null since invalid data
// would be filtered when adding into subInfo list.
.writeString(statsExt.subInfo.mcc)
@@ -1165,6 +1174,7 @@ public class StatsPullAtomService extends SystemService {
.writeInt(statsExt.subInfo.isOpportunistic
? DATA_USAGE_BYTES_TRANSFER__OPPORTUNISTIC_DATA_SUB__OPPORTUNISTIC
: DATA_USAGE_BYTES_TRANSFER__OPPORTUNISTIC_DATA_SUB__NOT_OPPORTUNISTIC)
+ .writeBoolean(isNR)
.build();
pulledData.add(e);
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 40e558c09965..3e9377ed0664 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1395,6 +1395,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
/**
+ * @see Letterbox#notIntersectsOrFullyContains(Rect)
+ */
+ boolean letterboxNotIntersectsOrFullyContains(Rect rect) {
+ return mLetterbox == null || mLetterbox.notIntersectsOrFullyContains(rect);
+ }
+
+ /**
* @return {@code true} if there is a letterbox and any part of that letterbox overlaps with
* the given {@code rect}.
*/
diff --git a/services/core/java/com/android/server/wm/BarController.java b/services/core/java/com/android/server/wm/BarController.java
index 123fb6c9d8e3..c1447553ba31 100644
--- a/services/core/java/com/android/server/wm/BarController.java
+++ b/services/core/java/com/android/server/wm/BarController.java
@@ -19,6 +19,7 @@ package com.android.server.wm;
import static com.android.server.wm.BarControllerProto.STATE;
import static com.android.server.wm.BarControllerProto.TRANSIENT_STATE;
+import android.annotation.NonNull;
import android.app.StatusBarManager;
import android.graphics.Rect;
import android.os.Handler;
@@ -169,13 +170,23 @@ public class BarController {
return vis;
}
+ private Rect getContentFrame(@NonNull WindowState win) {
+ final Rect rotatedContentFrame = win.mToken.getFixedRotationBarContentFrame(mWindowType);
+ return rotatedContentFrame != null ? rotatedContentFrame : mContentFrame;
+ }
+
+ boolean isLightAppearanceAllowed(WindowState win) {
+ if (win == null) {
+ return true;
+ }
+ return !win.isLetterboxedOverlappingWith(getContentFrame(win));
+ }
+
boolean isTransparentAllowed(WindowState win) {
if (win == null) {
return true;
}
- final Rect rotatedContentFrame = win.mToken.getFixedRotationBarContentFrame(mWindowType);
- final Rect contentFrame = rotatedContentFrame != null ? rotatedContentFrame : mContentFrame;
- return !win.isLetterboxedOverlappingWith(contentFrame);
+ return win.letterboxNotIntersectsOrFullyContains(getContentFrame(win));
}
boolean setBarShowingLw(final boolean show) {
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 5ae6f80b262d..6a90f2994238 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -102,6 +102,11 @@ import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManagerGlobal.ADD_OKAY;
import static android.view.WindowManagerPolicyConstants.ACTION_HDMI_PLUGGED;
+import static android.view.WindowManagerPolicyConstants.ALT_BAR_BOTTOM;
+import static android.view.WindowManagerPolicyConstants.ALT_BAR_LEFT;
+import static android.view.WindowManagerPolicyConstants.ALT_BAR_RIGHT;
+import static android.view.WindowManagerPolicyConstants.ALT_BAR_TOP;
+import static android.view.WindowManagerPolicyConstants.ALT_BAR_UNKNOWN;
import static android.view.WindowManagerPolicyConstants.EXTRA_HDMI_PLUGGED_STATE;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
@@ -314,6 +319,17 @@ public class DisplayPolicy {
private int[] mNavigationBarHeightForRotationInCarMode = new int[4];
private int[] mNavigationBarWidthForRotationInCarMode = new int[4];
+ // Alternative status bar for when flexible insets mapping is used to place the status bar on
+ // another side of the screen.
+ private WindowState mStatusBarAlt = null;
+ @WindowManagerPolicy.AltBarPosition
+ private int mStatusBarAltPosition = ALT_BAR_UNKNOWN;
+ // Alternative navigation bar for when flexible insets mapping is used to place the navigation
+ // bar elsewhere on the screen.
+ private WindowState mNavigationBarAlt = null;
+ @WindowManagerPolicy.AltBarPosition
+ private int mNavigationBarAltPosition = ALT_BAR_UNKNOWN;
+
/** See {@link #getNavigationBarFrameHeight} */
private int[] mNavigationBarFrameHeightForRotationDefault = new int[4];
@@ -431,7 +447,7 @@ public class DisplayPolicy {
case MSG_REQUEST_TRANSIENT_BARS:
synchronized (mLock) {
WindowState targetBar = (msg.arg1 == MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS)
- ? mStatusBar : mNavigationBar;
+ ? getStatusBar() : getNavigationBar();
if (targetBar != null) {
requestTransientBars(targetBar);
}
@@ -494,6 +510,7 @@ public class DisplayPolicy {
if (mStatusBar != null) {
requestTransientBars(mStatusBar);
}
+ checkAltBarSwipeForTransientBars(ALT_BAR_TOP);
}
}
@@ -504,6 +521,7 @@ public class DisplayPolicy {
&& mNavigationBarPosition == NAV_BAR_BOTTOM) {
requestTransientBars(mNavigationBar);
}
+ checkAltBarSwipeForTransientBars(ALT_BAR_BOTTOM);
}
}
@@ -520,6 +538,7 @@ public class DisplayPolicy {
excludedRegion)) {
requestTransientBars(mNavigationBar);
}
+ checkAltBarSwipeForTransientBars(ALT_BAR_RIGHT);
}
excludedRegion.recycle();
}
@@ -537,6 +556,7 @@ public class DisplayPolicy {
excludedRegion)) {
requestTransientBars(mNavigationBar);
}
+ checkAltBarSwipeForTransientBars(ALT_BAR_LEFT);
}
excludedRegion.recycle();
}
@@ -638,6 +658,15 @@ public class DisplayPolicy {
mHandler.post(mGestureNavigationSettingsObserver::register);
}
+ private void checkAltBarSwipeForTransientBars(@WindowManagerPolicy.AltBarPosition int pos) {
+ if (mStatusBarAlt != null && mStatusBarAltPosition == pos) {
+ requestTransientBars(mStatusBarAlt);
+ }
+ if (mNavigationBarAlt != null && mNavigationBarAltPosition == pos) {
+ requestTransientBars(mNavigationBarAlt);
+ }
+ }
+
void systemReady() {
mSystemGestures.systemReady();
if (mService.mPointerLocationEnabled) {
@@ -899,6 +928,14 @@ public class DisplayPolicy {
}
break;
}
+
+ // Check if alternate bars positions were updated.
+ if (mStatusBarAlt == win) {
+ mStatusBarAltPosition = getAltBarPosition(attrs);
+ }
+ if (mNavigationBarAlt == win) {
+ mNavigationBarAltPosition = getAltBarPosition(attrs);
+ }
}
/**
@@ -938,10 +975,9 @@ public class DisplayPolicy {
mContext.enforcePermission(
android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
"DisplayPolicy");
- if (mStatusBar != null) {
- if (mStatusBar.isAlive()) {
- return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
- }
+ if ((mStatusBar != null && mStatusBar.isAlive())
+ || (mStatusBarAlt != null && mStatusBarAlt.isAlive())) {
+ return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
}
break;
case TYPE_NOTIFICATION_SHADE:
@@ -958,10 +994,9 @@ public class DisplayPolicy {
mContext.enforcePermission(
android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
"DisplayPolicy");
- if (mNavigationBar != null) {
- if (mNavigationBar.isAlive()) {
- return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
- }
+ if ((mNavigationBar != null && mNavigationBar.isAlive())
+ || (mNavigationBarAlt != null && mNavigationBarAlt.isAlive())) {
+ return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
}
break;
case TYPE_NAVIGATION_BAR_PANEL:
@@ -993,6 +1028,23 @@ public class DisplayPolicy {
android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
"DisplayPolicy");
enforceSingleInsetsTypeCorrespondingToWindowType(attrs.providesInsetsTypes);
+
+ for (@InternalInsetsType int insetType : attrs.providesInsetsTypes) {
+ switch (insetType) {
+ case ITYPE_STATUS_BAR:
+ if ((mStatusBar != null && mStatusBar.isAlive())
+ || (mStatusBarAlt != null && mStatusBarAlt.isAlive())) {
+ return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
+ }
+ break;
+ case ITYPE_NAVIGATION_BAR:
+ if ((mNavigationBar != null && mNavigationBar.isAlive())
+ || (mNavigationBarAlt != null && mNavigationBarAlt.isAlive())) {
+ return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
+ }
+ break;
+ }
+ }
}
return ADD_OKAY;
}
@@ -1084,7 +1136,19 @@ public class DisplayPolicy {
break;
default:
if (attrs.providesInsetsTypes != null) {
- for (int insetsType : attrs.providesInsetsTypes) {
+ for (@InternalInsetsType int insetsType : attrs.providesInsetsTypes) {
+ switch (insetsType) {
+ case ITYPE_STATUS_BAR:
+ mStatusBarAlt = win;
+ mStatusBarController.setWindow(mStatusBarAlt);
+ mStatusBarAltPosition = getAltBarPosition(attrs);
+ break;
+ case ITYPE_NAVIGATION_BAR:
+ mNavigationBarAlt = win;
+ mNavigationBarController.setWindow(mNavigationBarAlt);
+ mNavigationBarAltPosition = getAltBarPosition(attrs);
+ break;
+ }
mDisplayContent.setInsetProvider(insetsType, win, null);
}
}
@@ -1092,6 +1156,22 @@ public class DisplayPolicy {
}
}
+ @WindowManagerPolicy.AltBarPosition
+ private int getAltBarPosition(WindowManager.LayoutParams params) {
+ switch (params.gravity) {
+ case Gravity.LEFT:
+ return ALT_BAR_LEFT;
+ case Gravity.RIGHT:
+ return ALT_BAR_RIGHT;
+ case Gravity.BOTTOM:
+ return ALT_BAR_BOTTOM;
+ case Gravity.TOP:
+ return ALT_BAR_TOP;
+ default:
+ return ALT_BAR_UNKNOWN;
+ }
+ }
+
TriConsumer<DisplayFrames, WindowState, Rect> getImeSourceFrameProvider() {
return (displayFrames, windowState, inOutFrame) -> {
if (mNavigationBar != null && navigationBarPosition(displayFrames.mDisplayWidth,
@@ -1132,12 +1212,14 @@ public class DisplayPolicy {
* @param win The window being removed.
*/
void removeWindowLw(WindowState win) {
- if (mStatusBar == win) {
+ if (mStatusBar == win || mStatusBarAlt == win) {
mStatusBar = null;
+ mStatusBarAlt = null;
mStatusBarController.setWindow(null);
mDisplayContent.setInsetProvider(ITYPE_STATUS_BAR, null, null);
- } else if (mNavigationBar == win) {
+ } else if (mNavigationBar == win || mNavigationBarAlt == win) {
mNavigationBar = null;
+ mNavigationBarAlt = null;
mNavigationBarController.setWindow(null);
mDisplayContent.setInsetProvider(ITYPE_NAVIGATION_BAR, null, null);
} else if (mNotificationShade == win) {
@@ -1163,7 +1245,7 @@ public class DisplayPolicy {
}
WindowState getStatusBar() {
- return mStatusBar;
+ return mStatusBar != null ? mStatusBar : mStatusBarAlt;
}
WindowState getNotificationShade() {
@@ -1171,7 +1253,7 @@ public class DisplayPolicy {
}
WindowState getNavigationBar() {
- return mNavigationBar;
+ return mNavigationBar != null ? mNavigationBar : mNavigationBarAlt;
}
/**
@@ -1233,6 +1315,46 @@ public class DisplayPolicy {
return R.anim.dock_left_enter;
}
}
+ } else if (win == mStatusBarAlt || win == mNavigationBarAlt) {
+ if (win.getAttrs().windowAnimations != 0) {
+ return ANIMATION_STYLEABLE;
+ }
+
+ int pos = (win == mStatusBarAlt) ? mStatusBarAltPosition : mNavigationBarAltPosition;
+
+ boolean isExitOrHide = transit == TRANSIT_EXIT || transit == TRANSIT_HIDE;
+ boolean isEnterOrShow = transit == TRANSIT_ENTER || transit == TRANSIT_SHOW;
+
+ switch (pos) {
+ case ALT_BAR_LEFT:
+ if (isExitOrHide) {
+ return R.anim.dock_left_exit;
+ } else if (isEnterOrShow) {
+ return R.anim.dock_left_enter;
+ }
+ break;
+ case ALT_BAR_RIGHT:
+ if (isExitOrHide) {
+ return R.anim.dock_right_exit;
+ } else if (isEnterOrShow) {
+ return R.anim.dock_right_enter;
+ }
+ break;
+ case ALT_BAR_BOTTOM:
+ if (isExitOrHide) {
+ return R.anim.dock_bottom_exit;
+ } else if (isEnterOrShow) {
+ return R.anim.dock_bottom_enter;
+ }
+ break;
+ case ALT_BAR_TOP:
+ if (isExitOrHide) {
+ return R.anim.dock_top_exit;
+ } else if (isEnterOrShow) {
+ return R.anim.dock_top_enter;
+ }
+ break;
+ }
}
if (transit == TRANSIT_PREVIEW_DONE) {
@@ -1591,7 +1713,7 @@ public class DisplayPolicy {
mInputConsumer = null;
Slog.v(TAG, INPUT_CONSUMER_NAVIGATION + " dismissed.");
}
- } else if (mInputConsumer == null && mStatusBar != null && canHideNavigationBar()) {
+ } else if (mInputConsumer == null && getStatusBar() != null && canHideNavigationBar()) {
mInputConsumer = mDisplayContent.getInputMonitor().createInputConsumer(
mHandler.getLooper(),
INPUT_CONSUMER_NAVIGATION,
@@ -2677,10 +2799,10 @@ public class DisplayPolicy {
mDreamingLockscreen = mService.mPolicy.isKeyguardShowingAndNotOccluded();
}
- if (mStatusBar != null) {
+ if (getStatusBar() != null) {
if (DEBUG_LAYOUT) Slog.i(TAG, "force=" + mForceStatusBar
+ " top=" + mTopFullscreenOpaqueWindowState);
- final boolean forceShowStatusBar = (mStatusBar.getAttrs().privateFlags
+ final boolean forceShowStatusBar = (getStatusBar().getAttrs().privateFlags
& PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR) != 0;
final boolean notificationShadeForcesShowingNavigation =
mNotificationShade != null
@@ -3166,6 +3288,16 @@ public class DisplayPolicy {
return mNavigationBarPosition;
}
+ @WindowManagerPolicy.AltBarPosition
+ int getAlternateStatusBarPosition() {
+ return mStatusBarAltPosition;
+ }
+
+ @WindowManagerPolicy.AltBarPosition
+ int getAlternateNavBarPosition() {
+ return mNavigationBarAltPosition;
+ }
+
/**
* A new window has been focused.
*/
@@ -3275,7 +3407,7 @@ public class DisplayPolicy {
// keys, we let it keep controlling the visibility.
final boolean lastFocusCanReceiveKeys =
(mLastFocusedWindow != null && mLastFocusedWindow.canReceiveKeys());
- winCandidate = isKeyguardShowing() ? mNotificationShade
+ winCandidate = isKeyguardShowing() && !isKeyguardOccluded() ? mNotificationShade
: lastFocusCanReceiveKeys ? mLastFocusedWindow
: mTopFullscreenOpaqueWindowState;
if (winCandidate == null) {
@@ -3327,8 +3459,8 @@ public class DisplayPolicy {
final boolean isFullscreen = (visibility & (View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)) != 0
|| (PolicyControl.getWindowFlags(win, win.mAttrs) & FLAG_FULLSCREEN) != 0
- || (mStatusBar != null && insetsPolicy.isHidden(ITYPE_STATUS_BAR))
- || (mNavigationBar != null && insetsPolicy.isHidden(
+ || (getStatusBar() != null && insetsPolicy.isHidden(ITYPE_STATUS_BAR))
+ || (getNavigationBar() != null && insetsPolicy.isHidden(
ITYPE_NAVIGATION_BAR));
final int behavior = win.mAttrs.insetsFlags.behavior;
final boolean isImmersive = (visibility & (View.SYSTEM_UI_FLAG_IMMERSIVE
@@ -3420,17 +3552,22 @@ public class DisplayPolicy {
WindowState opaqueOrDimming) {
final boolean onKeyguard = isKeyguardShowing() && !isKeyguardOccluded();
final WindowState statusColorWin = onKeyguard ? mNotificationShade : opaqueOrDimming;
- if (statusColorWin != null && (statusColorWin == opaque || onKeyguard)) {
- // If the top fullscreen-or-dimming window is also the top fullscreen, respect
- // its light flag.
- appearance &= ~APPEARANCE_LIGHT_STATUS_BARS;
- final int legacyAppearance = InsetsFlags.getAppearance(
- PolicyControl.getSystemUiVisibility(statusColorWin, null));
- appearance |= (statusColorWin.mAttrs.insetsFlags.appearance | legacyAppearance)
- & APPEARANCE_LIGHT_STATUS_BARS;
- } else if (statusColorWin != null && statusColorWin.isDimming()) {
- // Otherwise if it's dimming, clear the light flag.
- appearance &= ~APPEARANCE_LIGHT_STATUS_BARS;
+ if (statusColorWin != null) {
+ if (statusColorWin == opaque || onKeyguard) {
+ // If the top fullscreen-or-dimming window is also the top fullscreen, respect
+ // its light flag.
+ appearance &= ~APPEARANCE_LIGHT_STATUS_BARS;
+ final int legacyAppearance = InsetsFlags.getAppearance(
+ PolicyControl.getSystemUiVisibility(statusColorWin, null));
+ appearance |= (statusColorWin.mAttrs.insetsFlags.appearance | legacyAppearance)
+ & APPEARANCE_LIGHT_STATUS_BARS;
+ } else if (statusColorWin.isDimming()) {
+ // Otherwise if it's dimming, clear the light flag.
+ appearance &= ~APPEARANCE_LIGHT_STATUS_BARS;
+ }
+ if (!mStatusBarController.isLightAppearanceAllowed(statusColorWin)) {
+ appearance &= ~APPEARANCE_LIGHT_STATUS_BARS;
+ }
}
return appearance;
}
@@ -3495,8 +3632,7 @@ public class DisplayPolicy {
return vis;
}
- @VisibleForTesting
- static int updateLightNavigationBarAppearanceLw(int appearance, WindowState opaque,
+ private int updateLightNavigationBarAppearanceLw(int appearance, WindowState opaque,
WindowState opaqueOrDimming, WindowState imeWindow, WindowState navColorWin) {
if (navColorWin != null) {
@@ -3509,6 +3645,9 @@ public class DisplayPolicy {
// Clear the light flag for dimming window.
appearance &= ~APPEARANCE_LIGHT_NAVIGATION_BARS;
}
+ if (!mNavigationBarController.isLightAppearanceAllowed(navColorWin)) {
+ appearance &= ~APPEARANCE_LIGHT_NAVIGATION_BARS;
+ }
}
return appearance;
}
@@ -3583,7 +3722,7 @@ public class DisplayPolicy {
final boolean hideNavBarSysui =
(vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
- final boolean transientStatusBarAllowed = mStatusBar != null
+ final boolean transientStatusBarAllowed = getStatusBar() != null
&& (notificationShadeHasFocus || (!mForceShowSystemBars
&& (hideStatusBarWM || (hideStatusBarSysui && immersiveSticky))));
@@ -3741,7 +3880,7 @@ public class DisplayPolicy {
// TODO(b/118118435): Remove this after migration
private boolean isImmersiveMode(int vis) {
final int flags = View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
- return mNavigationBar != null
+ return getNavigationBar() != null
&& (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
&& (vis & flags) != 0
&& canHideNavigationBar();
@@ -3749,7 +3888,7 @@ public class DisplayPolicy {
private boolean isImmersiveMode(WindowState win) {
final int behavior = win.mAttrs.insetsFlags.behavior;
- return mNavigationBar != null
+ return getNavigationBar() != null
&& canHideNavigationBar()
&& (behavior == BEHAVIOR_SHOW_BARS_BY_SWIPE
|| behavior == BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE)
@@ -3830,8 +3969,8 @@ public class DisplayPolicy {
public void takeScreenshot(int screenshotType, int source) {
if (mScreenshotHelper != null) {
mScreenshotHelper.takeScreenshot(screenshotType,
- mStatusBar != null && mStatusBar.isVisibleLw(),
- mNavigationBar != null && mNavigationBar.isVisibleLw(),
+ getStatusBar() != null && getStatusBar().isVisibleLw(),
+ getNavigationBar() != null && getNavigationBar().isVisibleLw(),
source, mHandler, null /* completionConsumer */);
}
}
@@ -3869,6 +4008,11 @@ public class DisplayPolicy {
if (mStatusBar != null) {
pw.print(prefix); pw.print("mStatusBar="); pw.print(mStatusBar);
}
+ if (mStatusBarAlt != null) {
+ pw.print(prefix); pw.print("mStatusBarAlt="); pw.print(mStatusBarAlt);
+ pw.print(prefix); pw.print("mStatusBarAltPosition=");
+ pw.println(mStatusBarAltPosition);
+ }
if (mNotificationShade != null) {
pw.print(prefix); pw.print("mExpandedPanel="); pw.print(mNotificationShade);
}
@@ -3880,6 +4024,11 @@ public class DisplayPolicy {
pw.print(prefix); pw.print("mNavigationBarPosition=");
pw.println(mNavigationBarPosition);
}
+ if (mNavigationBarAlt != null) {
+ pw.print(prefix); pw.print("mNavigationBarAlt="); pw.println(mNavigationBarAlt);
+ pw.print(prefix); pw.print("mNavigationBarAltPosition=");
+ pw.println(mNavigationBarAltPosition);
+ }
if (mFocusedWindow != null) {
pw.print(prefix); pw.print("mFocusedWindow="); pw.println(mFocusedWindow);
}
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
index a685886da032..28dcbcdf3cc7 100644
--- a/services/core/java/com/android/server/wm/Letterbox.java
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -77,10 +77,10 @@ public class Letterbox {
mOuter.set(outer);
mInner.set(inner);
- mTop.layout(outer.left, outer.top, inner.right, inner.top, surfaceOrigin);
- mLeft.layout(outer.left, inner.top, inner.left, outer.bottom, surfaceOrigin);
- mBottom.layout(inner.left, inner.bottom, outer.right, outer.bottom, surfaceOrigin);
- mRight.layout(inner.right, outer.top, outer.right, inner.bottom, surfaceOrigin);
+ mTop.layout(outer.left, outer.top, outer.right, inner.top, surfaceOrigin);
+ mLeft.layout(outer.left, outer.top, inner.left, outer.bottom, surfaceOrigin);
+ mBottom.layout(outer.left, inner.bottom, outer.right, outer.bottom, surfaceOrigin);
+ mRight.layout(inner.right, outer.top, outer.right, outer.bottom, surfaceOrigin);
}
@@ -101,6 +101,31 @@ public class Letterbox {
}
/**
+ * Returns {@code true} if the letterbox does not overlap with the bar, or the letterbox can
+ * fully cover the window frame.
+ *
+ * @param rect The area of the window frame.
+ */
+ boolean notIntersectsOrFullyContains(Rect rect) {
+ int emptyCount = 0;
+ int noOverlappingCount = 0;
+ for (LetterboxSurface surface : mSurfaces) {
+ final Rect surfaceRect = surface.mLayoutFrameGlobal;
+ if (surfaceRect.isEmpty()) {
+ // empty letterbox
+ emptyCount++;
+ } else if (!Rect.intersects(surfaceRect, rect)) {
+ // no overlapping
+ noOverlappingCount++;
+ } else if (surfaceRect.contains(rect)) {
+ // overlapping and covered
+ return true;
+ }
+ }
+ return (emptyCount + noOverlappingCount) == mSurfaces.length;
+ }
+
+ /**
* Returns true if any part of the letterbox overlaps with the given {@code rect}.
*/
public boolean isOverlappingWith(Rect rect) {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 4700864c03bc..84a389349204 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2300,8 +2300,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
- boolean resumedOnDisplay = false;
final DisplayContent display = getChildAt(displayNdx);
+ if (display.shouldSleep()) {
+ continue;
+ }
+
+ boolean resumedOnDisplay = 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) {
@@ -2390,7 +2394,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// 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();
+ stack.resumeTopActivityUncheckedLocked(null, null);
}
// The visibility update must not be called before resuming the top, so the
// display orientation can be updated first if needed. Otherwise there may
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index c2021303c11c..e85049cad2f4 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -615,8 +615,9 @@ class TaskSnapshotController {
static Rect getSystemBarInsets(Rect frame, InsetsState state) {
return state.calculateInsets(frame, null /* ignoringVisibilityState */,
false /* isScreenRound */, false /* alwaysConsumeSystemBars */,
- null /* displayCutout */, 0 /* legacySoftInputMode */, 0 /* legacySystemUiFlags */,
- null /* typeSideMap */).getInsets(WindowInsets.Type.systemBars()).toRect();
+ null /* displayCutout */, 0 /* legacySoftInputMode */, 0 /* legacyWindowFlags */,
+ 0 /* legacySystemUiFlags */, null /* typeSideMap */).getInsets(
+ WindowInsets.Type.systemBars()).toRect();
}
void dump(PrintWriter pw, String prefix) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 371d6b56f687..b7ac54f3470e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2163,6 +2163,10 @@ public class WindowManagerService extends IWindowManager.Stub
throw new IllegalArgumentException(
"Window type can not be changed after the window is added.");
}
+ if (!Arrays.equals(win.mAttrs.providesInsetsTypes, attrs.providesInsetsTypes)) {
+ throw new IllegalArgumentException(
+ "Insets types can not be changed after the window is added.");
+ }
// Odd choice but less odd than embedding in copyFrom()
if ((attrs.privateFlags & WindowManager.LayoutParams.PRIVATE_FLAG_PRESERVE_GEOMETRY)
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 26bcf3b285ec..f0c2a74958d6 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2170,6 +2170,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
if (isInputMethodTarget()) {
dc.computeImeTarget(true /* updateImeTarget */);
}
+ if (dc.mInputMethodInputTarget == this) {
+ dc.setInputMethodInputTarget(null);
+ }
if (dc.mInputMethodControlTarget == this) {
dc.updateImeControlTarget();
}
@@ -3797,7 +3800,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return mActivityRecord.getBounds().equals(mTmpRect);
}
- @Override
+ /**
+ * @see Letterbox#notIntersectsOrFullyContains(Rect)
+ */
+ boolean letterboxNotIntersectsOrFullyContains(Rect rect) {
+ return mActivityRecord == null
+ || mActivityRecord.letterboxNotIntersectsOrFullyContains(rect);
+ }
+
public boolean isLetterboxedOverlappingWith(Rect rect) {
return mActivityRecord != null && mActivityRecord.isLetterboxOverlappingWith(rect);
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 508d2d477067..da45300ed318 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1592,12 +1592,6 @@ class WindowStateAnimator {
if (mSurfaceController != null) {
mSurfaceController.detachChildren();
}
- // If the children are detached, it means the app is exiting. We don't want to tear the
- // content down too early, otherwise we could end up with a flicker. By preserving the
- // current surface, we ensure the content remains on screen until the window is completely
- // removed. It also ensures that the old surface is cleaned up when started again since it
- // forces mSurfaceController to be set to null.
- preserveSurfaceLocked();
}
void setOffsetPositionForStackResize(boolean offsetPositionForStackResize) {
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 3450c3ae9fb3..a5f0d045948c 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -1422,6 +1422,11 @@ static long elapsedMcs(Duration start, Duration end) {
}
// Extract lib files from zip, create new files in incfs and write data to them
+// Lib files should be placed next to the APK file in the following matter:
+// Example:
+// /path/to/base.apk
+// /path/to/lib/arm/first.so
+// /path/to/lib/arm/second.so
bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_view apkFullPath,
std::string_view libDirRelativePath,
std::string_view abi, bool extractNativeLibs) {
@@ -1433,9 +1438,13 @@ bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_
return false;
}
+ const auto targetLibPathRelativeToStorage =
+ path::join(path::dirname(normalizePathToStorage(*ifs, storage, apkFullPath)),
+ libDirRelativePath);
+
// First prepare target directories if they don't exist yet
- if (auto res = makeDirs(*ifs, storage, libDirRelativePath, 0755)) {
- LOG(ERROR) << "Failed to prepare target lib directory " << libDirRelativePath
+ if (auto res = makeDirs(*ifs, storage, targetLibPathRelativeToStorage, 0755)) {
+ LOG(ERROR) << "Failed to prepare target lib directory " << targetLibPathRelativeToStorage
<< " errno: " << res;
return false;
}
@@ -1486,7 +1495,7 @@ bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_
auto startFileTs = Clock::now();
const auto libName = path::basename(fileName);
- auto targetLibPath = path::join(libDirRelativePath, libName);
+ auto targetLibPath = path::join(targetLibPathRelativeToStorage, libName);
const auto targetLibPathAbsolute = normalizePathToStorage(*ifs, storage, targetLibPath);
// If the extract file already exists, skip
if (access(targetLibPathAbsolute.c_str(), F_OK) == 0) {
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 1a04d2ff8c29..4dec7a1a0ab9 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -218,6 +218,10 @@ public class AppStandbyControllerTests {
}
@Override
+ void updatePowerWhitelistCache() {
+ }
+
+ @Override
boolean isRestrictedBucketEnabled() {
return mIsRestrictedBucketEnabled;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index b4f2a6c9c6c3..85736ab11e65 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -887,6 +887,21 @@ public class DisplayContentTests extends WindowTestsBase {
}
@Test
+ public void testInputMethodInputTarget_isClearedWhenWindowStateIsRemoved() throws Exception {
+ final DisplayContent dc = createNewDisplay();
+
+ WindowState app = createWindow(null, TYPE_BASE_APPLICATION, dc, "app");
+
+ dc.mInputMethodInputTarget = app;
+ assertEquals(app, dc.computeImeControlTarget());
+
+ app.removeImmediately();
+
+ assertNull(dc.mInputMethodInputTarget);
+ assertNull(dc.computeImeControlTarget());
+ }
+
+ @Test
public void testComputeImeControlTarget() throws Exception {
final DisplayContent dc = createNewDisplay();
dc.setRemoteInsetsController(createDisplayWindowInsetsController());
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 278de56dfea0..2f3afbcb6d72 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -40,8 +40,13 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DEC
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
+import static android.view.WindowManagerPolicyConstants.ALT_BAR_BOTTOM;
+import static android.view.WindowManagerPolicyConstants.ALT_BAR_LEFT;
+import static android.view.WindowManagerPolicyConstants.ALT_BAR_RIGHT;
+import static android.view.WindowManagerPolicyConstants.ALT_BAR_TOP;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
@@ -60,6 +65,7 @@ import android.util.Pair;
import android.util.SparseArray;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
+import android.view.Gravity;
import android.view.InsetsState;
import android.view.WindowInsets.Side;
import android.view.WindowInsets.Type;
@@ -147,6 +153,8 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
@Test
public void addingWindow_withInsetsTypes() {
+ mDisplayPolicy.removeWindowLw(mStatusBarWindow); // Removes the existing one.
+
WindowState win = createWindow(null, TYPE_STATUS_BAR_SUB_PANEL, "StatusBarSubPanel");
win.mAttrs.providesInsetsTypes = new int[]{ITYPE_STATUS_BAR, ITYPE_TOP_GESTURES};
win.getFrameLw().set(0, 0, 500, 100);
@@ -196,6 +204,47 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
}
@Test
+ public void addingWindow_variousGravities_alternateBarPosUpdated() {
+ mDisplayPolicy.removeWindowLw(mNavBarWindow); // Removes the existing one.
+
+ WindowState win1 = createWindow(null, TYPE_NAVIGATION_BAR_PANEL, "NavBarPanel1");
+ win1.mAttrs.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR};
+ win1.mAttrs.gravity = Gravity.TOP;
+ win1.getFrameLw().set(0, 0, 200, 500);
+ addWindow(win1);
+
+ assertEquals(mDisplayPolicy.getAlternateNavBarPosition(), ALT_BAR_TOP);
+ mDisplayPolicy.removeWindowLw(win1);
+
+ WindowState win2 = createWindow(null, TYPE_NAVIGATION_BAR_PANEL, "NavBarPanel2");
+ win2.mAttrs.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR};
+ win2.mAttrs.gravity = Gravity.BOTTOM;
+ win2.getFrameLw().set(0, 0, 200, 500);
+ addWindow(win2);
+
+ assertEquals(mDisplayPolicy.getAlternateNavBarPosition(), ALT_BAR_BOTTOM);
+ mDisplayPolicy.removeWindowLw(win2);
+
+ WindowState win3 = createWindow(null, TYPE_NAVIGATION_BAR_PANEL, "NavBarPanel3");
+ win3.mAttrs.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR};
+ win3.mAttrs.gravity = Gravity.LEFT;
+ win3.getFrameLw().set(0, 0, 200, 500);
+ addWindow(win3);
+
+ assertEquals(mDisplayPolicy.getAlternateNavBarPosition(), ALT_BAR_LEFT);
+ mDisplayPolicy.removeWindowLw(win3);
+
+ WindowState win4 = createWindow(null, TYPE_NAVIGATION_BAR_PANEL, "NavBarPanel4");
+ win4.mAttrs.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR};
+ win4.mAttrs.gravity = Gravity.RIGHT;
+ win4.getFrameLw().set(0, 0, 200, 500);
+ addWindow(win4);
+
+ assertEquals(mDisplayPolicy.getAlternateNavBarPosition(), ALT_BAR_RIGHT);
+ mDisplayPolicy.removeWindowLw(win4);
+ }
+
+ @Test
public void layoutWindowLw_fitStatusBars() {
mWindow.mAttrs.setFitInsetsTypes(Type.statusBars());
addWindow(mWindow);
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
index bf84aecdb6a0..2f3004bf6832 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
@@ -16,8 +16,8 @@
package com.android.server.wm;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
@@ -60,6 +60,103 @@ public class LetterboxTest {
assertTrue(mLetterbox.isOverlappingWith(new Rect(0, 0, 1, 1)));
}
+ private static final int TOP_BAR = 0x1;
+ private static final int BOTTOM_BAR = 0x2;
+ private static final int LEFT_BAR = 0x4;
+ private static final int RIGHT_BAR = 0x8;
+ @Test
+ public void testNotIntersectsOrFullyContains_usesGlobalCoordinates() {
+ final Rect outer = new Rect(0, 0, 10, 50);
+ final Point surfaceOrig = new Point(1000, 2000);
+
+ final Rect topBar = new Rect(0, 0, 10, 2);
+ final Rect bottomBar = new Rect(0, 45, 10, 50);
+ final Rect leftBar = new Rect(0, 0, 2, 50);
+ final Rect rightBar = new Rect(8, 0, 10, 50);
+
+ final LetterboxLayoutVerifier verifier =
+ new LetterboxLayoutVerifier(outer, surfaceOrig, mLetterbox);
+ verifier.setBarRect(topBar, bottomBar, leftBar, rightBar);
+
+ // top
+ verifier.setInner(0, 2, 10, 50).verifyPositions(TOP_BAR | BOTTOM_BAR, BOTTOM_BAR);
+ // bottom
+ verifier.setInner(0, 0, 10, 45).verifyPositions(TOP_BAR | BOTTOM_BAR, TOP_BAR);
+ // left
+ verifier.setInner(2, 0, 10, 50).verifyPositions(LEFT_BAR | RIGHT_BAR, RIGHT_BAR);
+ // right
+ verifier.setInner(0, 0, 8, 50).verifyPositions(LEFT_BAR | RIGHT_BAR, LEFT_BAR);
+ // top + bottom
+ verifier.setInner(0, 2, 10, 45).verifyPositions(TOP_BAR | BOTTOM_BAR, 0);
+ // left + right
+ verifier.setInner(2, 0, 8, 50).verifyPositions(LEFT_BAR | RIGHT_BAR, 0);
+ // top + left
+ verifier.setInner(2, 2, 10, 50).verifyPositions(TOP_BAR | LEFT_BAR, 0);
+ // top + left + right
+ verifier.setInner(2, 2, 8, 50).verifyPositions(TOP_BAR | LEFT_BAR | RIGHT_BAR, 0);
+ // left + right + bottom
+ verifier.setInner(2, 0, 8, 45).verifyPositions(LEFT_BAR | RIGHT_BAR | BOTTOM_BAR, 0);
+ // all
+ verifier.setInner(2, 2, 8, 45)
+ .verifyPositions(TOP_BAR | BOTTOM_BAR | LEFT_BAR | RIGHT_BAR, 0);
+ }
+
+ private static class LetterboxLayoutVerifier {
+ final Rect mOuter;
+ final Rect mInner = new Rect();
+ final Point mSurfaceOrig;
+ final Letterbox mLetterbox;
+ final Rect mTempRect = new Rect();
+
+ final Rect mTop = new Rect();
+ final Rect mBottom = new Rect();
+ final Rect mLeft = new Rect();
+ final Rect mRight = new Rect();
+
+ LetterboxLayoutVerifier(Rect outer, Point surfaceOrig, Letterbox letterbox) {
+ mOuter = new Rect(outer);
+ mSurfaceOrig = new Point(surfaceOrig);
+ mLetterbox = letterbox;
+ }
+
+ LetterboxLayoutVerifier setInner(int left, int top, int right, int bottom) {
+ mInner.set(left, top, right, bottom);
+ mLetterbox.layout(mOuter, mInner, mSurfaceOrig);
+ return this;
+ }
+
+ void setBarRect(Rect top, Rect bottom, Rect left, Rect right) {
+ mTop.set(top);
+ mBottom.set(bottom);
+ mLeft.set(left);
+ mRight.set(right);
+ }
+
+ void verifyPositions(int allowedPos, int noOverlapPos) {
+ assertEquals(mLetterbox.notIntersectsOrFullyContains(mTop),
+ (allowedPos & TOP_BAR) != 0);
+ assertEquals(mLetterbox.notIntersectsOrFullyContains(mBottom),
+ (allowedPos & BOTTOM_BAR) != 0);
+ assertEquals(mLetterbox.notIntersectsOrFullyContains(mLeft),
+ (allowedPos & LEFT_BAR) != 0);
+ assertEquals(mLetterbox.notIntersectsOrFullyContains(mRight),
+ (allowedPos & RIGHT_BAR) != 0);
+
+ mTempRect.set(mTop.left, mTop.top, mTop.right, mTop.bottom + 1);
+ assertEquals(mLetterbox.notIntersectsOrFullyContains(mTempRect),
+ (noOverlapPos & TOP_BAR) != 0);
+ mTempRect.set(mLeft.left, mLeft.top, mLeft.right + 1, mLeft.bottom);
+ assertEquals(mLetterbox.notIntersectsOrFullyContains(mTempRect),
+ (noOverlapPos & LEFT_BAR) != 0);
+ mTempRect.set(mRight.left - 1, mRight.top, mRight.right, mRight.bottom);
+ assertEquals(mLetterbox.notIntersectsOrFullyContains(mTempRect),
+ (noOverlapPos & RIGHT_BAR) != 0);
+ mTempRect.set(mBottom.left, mBottom.top - 1, mBottom.right, mBottom.bottom);
+ assertEquals(mLetterbox.notIntersectsOrFullyContains(mTempRect),
+ (noOverlapPos & BOTTOM_BAR) != 0);
+ }
+ }
+
@Test
public void testSurfaceOrigin_applied() {
mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
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 51db099676b0..c848736a64c2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -896,6 +896,24 @@ public class RootActivityContainerTests extends ActivityTestsBase {
assertEquals(taskDisplayArea.getTopStack(), taskDisplayArea.getRootHomeTask());
}
+ @Test
+ public void testResumeFocusedStackOnSleepingDisplay() {
+ // Create an activity on secondary display.
+ final TestDisplayContent secondDisplay = addNewDisplayContentAt(
+ DisplayContent.POSITION_TOP);
+ final ActivityStack stack = secondDisplay.getDefaultTaskDisplayArea()
+ .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final ActivityRecord activity = new ActivityBuilder(mService).setStack(stack).build();
+ spyOn(activity);
+ spyOn(stack);
+
+ // Cannot resumed activities on secondary display if the display should sleep.
+ doReturn(true).when(secondDisplay).shouldSleep();
+ mRootWindowContainer.resumeFocusedStacksTopActivities();
+ verify(stack, never()).resumeTopActivityUncheckedLocked(any(), any());
+ verify(activity, never()).makeActiveIfNeeded(any());
+ }
+
/**
* Mock {@link RootWindowContainer#resolveHomeActivity} for returning consistent activity
* info for test cases.
diff --git a/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java b/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java
index 31a102ae3bad..ef74861e9422 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java
@@ -25,8 +25,8 @@ import static android.view.Gravity.BOTTOM;
import static android.view.Gravity.LEFT;
import static android.view.Gravity.RIGHT;
import static android.view.Gravity.TOP;
-import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
-import static android.view.InsetsState.ITYPE_STATUS_BAR;
+import static android.view.InsetsState.ITYPE_CLIMATE_BAR;
+import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
@@ -190,7 +190,7 @@ public class ScreenDecorWindowTests {
@Test
public void testProvidesInsetsTypes() {
- int[] providesInsetsTypes = new int[]{ITYPE_STATUS_BAR};
+ int[] providesInsetsTypes = new int[]{ITYPE_CLIMATE_BAR};
final View win = createWindow("StatusBarSubPanel", TOP, MATCH_PARENT, mDecorThickness, RED,
FLAG_LAYOUT_IN_SCREEN, 0, providesInsetsTypes);
@@ -199,7 +199,7 @@ public class ScreenDecorWindowTests {
private View createDecorWindow(int gravity, int width, int height) {
int[] providesInsetsTypes =
- new int[]{gravity == TOP ? ITYPE_STATUS_BAR : ITYPE_NAVIGATION_BAR};
+ new int[]{gravity == TOP ? ITYPE_CLIMATE_BAR : ITYPE_EXTRA_NAVIGATION_BAR};
return createWindow("decorWindow", gravity, width, height, RED,
FLAG_LAYOUT_IN_SCREEN, PRIVATE_FLAG_IS_SCREEN_DECOR, providesInsetsTypes);
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 318b15293d8d..52f1e37e69f4 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2345,6 +2345,16 @@ public class CarrierConfigManager {
"call_forwarding_blocks_while_roaming_string_array";
/**
+ * Call forwarding number prefixes defined by {@link
+ * #KEY_CALL_FORWARDING_BLOCKS_WHILE_ROAMING_STRING_ARRAY} which will be allowed while the
+ * device is reporting that it is roaming and IMS is registered over LTE or Wi-Fi.
+ * By default this value is {@code true}.
+ * @hide
+ */
+ public static final String KEY_SUPPORT_IMS_CALL_FORWARDING_WHILE_ROAMING_BOOL =
+ "support_ims_call_forwarding_while_roaming_bool";
+
+ /**
* The day of the month (1-31) on which the data cycle rolls over.
* <p>
* If the current month does not have this day, the cycle will roll over at
@@ -4174,6 +4184,7 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_SHOW_VIDEO_CALL_CHARGES_ALERT_DIALOG_BOOL, false);
sDefaults.putStringArray(KEY_CALL_FORWARDING_BLOCKS_WHILE_ROAMING_STRING_ARRAY,
null);
+ sDefaults.putBoolean(KEY_SUPPORT_IMS_CALL_FORWARDING_WHILE_ROAMING_BOOL, true);
sDefaults.putInt(KEY_LTE_EARFCNS_RSRP_BOOST_INT, 0);
sDefaults.putStringArray(KEY_BOOSTED_LTE_EARFCNS_STRING_ARRAY, null);
sDefaults.putBoolean(KEY_USE_ONLY_RSRP_FOR_LTE_SIGNAL_BAR_BOOL, false);
diff --git a/tests/net/java/android/net/NetworkTemplateTest.kt b/tests/net/java/android/net/NetworkTemplateTest.kt
index 5dd0fda4da28..9ba56e44fe88 100644
--- a/tests/net/java/android/net/NetworkTemplateTest.kt
+++ b/tests/net/java/android/net/NetworkTemplateTest.kt
@@ -26,6 +26,7 @@ import android.net.NetworkStats.METERED_ALL
import android.net.NetworkStats.ROAMING_ALL
import android.net.NetworkTemplate.MATCH_MOBILE
import android.net.NetworkTemplate.MATCH_WIFI
+import android.net.NetworkTemplate.NETWORK_TYPE_5G_NSA
import android.net.NetworkTemplate.NETWORK_TYPE_ALL
import android.net.NetworkTemplate.buildTemplateMobileWithRatType
import android.telephony.TelephonyManager
@@ -145,11 +146,13 @@ class NetworkTemplateTest {
assertParcelSane(templateWifi, 8)
}
- // Verify NETWORK_TYPE_ALL does not conflict with TelephonyManager#NETWORK_TYPE_* constants.
+ // Verify NETWORK_TYPE_* constants in NetworkTemplate do not conflict with
+ // TelephonyManager#NETWORK_TYPE_* constants.
@Test
- fun testNetworkTypeAll() {
+ fun testNetworkTypeConstants() {
for (ratType in TelephonyManager.getAllNetworkTypes()) {
assertNotEquals(NETWORK_TYPE_ALL, ratType)
+ assertNotEquals(NETWORK_TYPE_5G_NSA, ratType)
}
}
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
index 058856dcd6fb..c91dfecf041b 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
@@ -17,6 +17,7 @@
package com.android.server.net;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.eq;
@@ -29,7 +30,9 @@ import static org.mockito.Mockito.when;
import android.annotation.NonNull;
import android.content.Context;
+import android.net.NetworkTemplate;
import android.os.Looper;
+import android.telephony.NetworkRegistrationInfo;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
@@ -61,7 +64,6 @@ public final class NetworkStatsSubscriptionsMonitorTest {
private static final String TEST_IMSI3 = "466929999999999";
@Mock private Context mContext;
- @Mock private PhoneStateListener mPhoneStateListener;
@Mock private SubscriptionManager mSubscriptionManager;
@Mock private TelephonyManager mTelephonyManager;
@Mock private Delegate mDelegate;
@@ -215,4 +217,55 @@ public final class NetworkStatsSubscriptionsMonitorTest {
verify(mTelephonyManager, times(2)).listen(any(), eq(PhoneStateListener.LISTEN_NONE));
assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
}
+
+
+ @Test
+ public void test5g() {
+ mMonitor.start();
+ // Insert sim1, verify RAT type is NETWORK_TYPE_UNKNOWN, and never get any callback
+ // before changing RAT type. Also capture listener for later use.
+ addTestSub(TEST_SUBID1, TEST_IMSI1);
+ assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+ final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor =
+ ArgumentCaptor.forClass(RatTypeListener.class);
+ verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor.capture(),
+ eq(PhoneStateListener.LISTEN_SERVICE_STATE));
+ final RatTypeListener listener = CollectionUtils
+ .find(ratTypeListenerCaptor.getAllValues(), it -> it.getSubId() == TEST_SUBID1);
+ assertNotNull(listener);
+
+ // Set RAT type to 5G NSA (non-standalone) mode, verify the monitor outputs
+ // NETWORK_TYPE_5G_NSA.
+ final ServiceState serviceState = mock(ServiceState.class);
+ when(serviceState.getDataNetworkType()).thenReturn(TelephonyManager.NETWORK_TYPE_LTE);
+ when(serviceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED);
+ listener.onServiceStateChanged(serviceState);
+ assertRatTypeChangedForSub(TEST_IMSI1, NetworkTemplate.NETWORK_TYPE_5G_NSA);
+ reset(mDelegate);
+
+ // Set RAT type to LTE without NR connected, the RAT type should be downgraded to LTE.
+ when(serviceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_NONE);
+ listener.onServiceStateChanged(serviceState);
+ assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_LTE);
+ reset(mDelegate);
+
+ // Verify NR connected with other RAT type does not take effect.
+ when(serviceState.getDataNetworkType()).thenReturn(TelephonyManager.NETWORK_TYPE_UMTS);
+ when(serviceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED);
+ listener.onServiceStateChanged(serviceState);
+ assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
+ reset(mDelegate);
+
+ // Set RAT type to 5G standalone mode, the RAT type should be NR.
+ setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1,
+ TelephonyManager.NETWORK_TYPE_NR);
+ assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_NR);
+ reset(mDelegate);
+
+ // Set NR state to none in standalone mode does not change anything.
+ when(serviceState.getDataNetworkType()).thenReturn(TelephonyManager.NETWORK_TYPE_NR);
+ when(serviceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_NONE);
+ listener.onServiceStateChanged(serviceState);
+ assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_NR);
+ }
}