diff options
45 files changed, 681 insertions, 120 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 687b1d4e0bde..f36084386f48 100644 --- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java @@ -463,9 +463,6 @@ public class AppStandbyController implements AppStandbyInternal { userFileExists = mAppIdleHistory.userFileExists(UserHandle.USER_SYSTEM); } - // Offload to handler thread to avoid boottime impact. - mHandler.post(this::loadHeadlessSystemAppCache); - if (mPendingInitializeDefaults || !userFileExists) { initializeDefaultsForSystemApps(UserHandle.USER_SYSTEM); } @@ -475,6 +472,10 @@ public class AppStandbyController implements AppStandbyInternal { } } else if (phase == PHASE_BOOT_COMPLETED) { setChargingState(mInjector.isCharging()); + + // Offload to handler thread after boot completed to avoid boot time impact. This means + // that headless system apps may be put in a lower bucket until boot has completed. + mHandler.post(this::loadHeadlessSystemAppCache); } } diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java index 0c8c9a9c63e0..e4b5d19e67c9 100644 --- a/apex/media/framework/java/android/media/MediaParser.java +++ b/apex/media/framework/java/android/media/MediaParser.java @@ -1227,6 +1227,7 @@ public final class MediaParser { throw new ParsingException(e); } if (result == Extractor.RESULT_END_OF_INPUT) { + mExtractorInput = null; return false; } if (result == Extractor.RESULT_SEEK) { diff --git a/cmds/statsd/src/anomaly/AlarmTracker.cpp b/cmds/statsd/src/anomaly/AlarmTracker.cpp index 5722f923d11e..6d9beb8f718d 100644 --- a/cmds/statsd/src/anomaly/AlarmTracker.cpp +++ b/cmds/statsd/src/anomaly/AlarmTracker.cpp @@ -60,11 +60,11 @@ void AlarmTracker::addSubscription(const Subscription& subscription) { } int64_t AlarmTracker::findNextAlarmSec(int64_t currentTimeSec) { - if (currentTimeSec <= mAlarmSec) { + if (currentTimeSec < mAlarmSec) { return mAlarmSec; } int64_t periodsForward = - ((currentTimeSec - mAlarmSec) * MS_PER_SEC - 1) / mAlarmConfig.period_millis() + 1; + ((currentTimeSec - mAlarmSec) * MS_PER_SEC) / mAlarmConfig.period_millis() + 1; return mAlarmSec + periodsForward * mAlarmConfig.period_millis() / MS_PER_SEC; } diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 02c0763c9d83..12e428ce5674 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -4948,6 +4948,8 @@ message BlobCommitted { ERROR_DURING_COMMIT = 2; // Commit Failed: Digest of the data did not match Blob digest DIGEST_MISMATCH = 3; + // Commit Failed: Allowed count limit exceeded + COUNT_LIMIT_EXCEEDED = 4; } optional Result result = 4; } @@ -4980,6 +4982,8 @@ message BlobLeased{ LEASE_EXPIRY_INVALID = 4; // Lease Failed: Leasee has exceeded the total data lease limit DATA_SIZE_LIMIT_EXCEEDED = 5; + // Leasee Failed: Allowed count limit exceeded + COUNT_LIMIT_EXCEEDED = 6; } optional Result result = 4; } diff --git a/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp b/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp index 322cfaf68a41..64ea219c8465 100644 --- a/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp +++ b/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp @@ -43,23 +43,47 @@ TEST(AlarmTrackerTest, TestTriggerTimestamp) { alarm.set_offset_millis(15 * MS_PER_SEC); alarm.set_period_millis(60 * 60 * MS_PER_SEC); // 1hr int64_t startMillis = 100000000 * MS_PER_SEC; + int64_t nextAlarmTime = startMillis / MS_PER_SEC + 15; AlarmTracker tracker(startMillis, startMillis, alarm, kConfigKey, subscriberAlarmMonitor); - EXPECT_EQ(tracker.mAlarmSec, (int64_t)(startMillis / MS_PER_SEC + 15)); + EXPECT_EQ(tracker.mAlarmSec, nextAlarmTime); uint64_t currentTimeSec = startMillis / MS_PER_SEC + 10; std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> firedAlarmSet = subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec)); EXPECT_TRUE(firedAlarmSet.empty()); tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet); - EXPECT_EQ(tracker.mAlarmSec, (int64_t)(startMillis / MS_PER_SEC + 15)); + EXPECT_EQ(tracker.mAlarmSec, nextAlarmTime); + EXPECT_EQ(tracker.getAlarmTimestampSec(), nextAlarmTime); currentTimeSec = startMillis / MS_PER_SEC + 7000; + nextAlarmTime = startMillis / MS_PER_SEC + 15 + 2 * 60 * 60; firedAlarmSet = subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec)); ASSERT_EQ(firedAlarmSet.size(), 1u); tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet); EXPECT_TRUE(firedAlarmSet.empty()); - EXPECT_EQ(tracker.mAlarmSec, (int64_t)(startMillis / MS_PER_SEC + 15 + 2 * 60 * 60)); + EXPECT_EQ(tracker.mAlarmSec, nextAlarmTime); + EXPECT_EQ(tracker.getAlarmTimestampSec(), nextAlarmTime); + + // Alarm fires exactly on time. + currentTimeSec = startMillis / MS_PER_SEC + 15 + 2 * 60 * 60; + nextAlarmTime = startMillis / MS_PER_SEC + 15 + 3 * 60 * 60; + firedAlarmSet = subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec)); + ASSERT_EQ(firedAlarmSet.size(), 1u); + tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet); + EXPECT_TRUE(firedAlarmSet.empty()); + EXPECT_EQ(tracker.mAlarmSec, nextAlarmTime); + EXPECT_EQ(tracker.getAlarmTimestampSec(), nextAlarmTime); + + // Alarm fires exactly 1 period late. + currentTimeSec = startMillis / MS_PER_SEC + 15 + 4 * 60 * 60; + nextAlarmTime = startMillis / MS_PER_SEC + 15 + 5 * 60 * 60; + firedAlarmSet = subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec)); + ASSERT_EQ(firedAlarmSet.size(), 1u); + tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet); + EXPECT_TRUE(firedAlarmSet.empty()); + EXPECT_EQ(tracker.mAlarmSec, nextAlarmTime); + EXPECT_EQ(tracker.getAlarmTimestampSec(), nextAlarmTime); } } // namespace statsd diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java index 2d2dda04b146..e385cd2b7ecd 100644 --- a/core/java/android/hardware/biometrics/BiometricManager.java +++ b/core/java/android/hardware/biometrics/BiometricManager.java @@ -121,7 +121,7 @@ public class BiometricManager { /** * Any biometric (e.g. fingerprint, iris, or face) on the device that meets or exceeds the - * requirements for <strong>Tier 3</strong> (formerly <strong>Strong</strong>), as defined + * requirements for <strong>Class 3</strong> (formerly <strong>Strong</strong>), as defined * by the Android CDD. * * <p>This corresponds to {@link KeyProperties#AUTH_BIOMETRIC_STRONG} during key generation. @@ -132,7 +132,7 @@ public class BiometricManager { /** * Any biometric (e.g. fingerprint, iris, or face) on the device that meets or exceeds the - * requirements for <strong>Tier 2</strong> (formerly <strong>Weak</strong>), as defined by + * requirements for <strong>Class 2</strong> (formerly <strong>Weak</strong>), as defined by * the Android CDD. * * <p>Note that this is a superset of {@link #BIOMETRIC_STRONG} and is defined such that @@ -142,7 +142,7 @@ public class BiometricManager { /** * Any biometric (e.g. fingerprint, iris, or face) on the device that meets or exceeds the - * requirements for <strong>Tier 1</strong> (formerly <strong>Convenience</strong>), as + * requirements for <strong>Class 1</strong> (formerly <strong>Convenience</strong>), as * defined by the Android CDD. * * <p>This constant is intended for use by {@link android.provider.DeviceConfig} to adjust diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index a30c3c52f42c..8c2358d253be 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -819,7 +819,8 @@ public class ChooserActivity extends ResolverActivity implements if (chooserListAdapter.getCount() == 0) { return; } - if (resultList.isEmpty()) { + if (resultList.isEmpty() + && shouldQueryShortcutManager(chooserListAdapter.getUserHandle())) { // APS may be disabled, so try querying targets ourselves. queryDirectShareTargets(chooserListAdapter, true); return; @@ -2025,6 +2026,26 @@ public class ChooserActivity extends ResolverActivity implements }); } + /** + * Returns {@code false} if {@code userHandle} is the work profile and it's either + * in quiet mode or not running. + */ + private boolean shouldQueryShortcutManager(UserHandle userHandle) { + if (!shouldShowTabs()) { + return true; + } + if (!getWorkProfileUserHandle().equals(userHandle)) { + return true; + } + if (!isUserRunning(userHandle)) { + return false; + } + if (isQuietModeEnabled(userHandle)) { + return false; + } + return true; + } + private void sendChooserTargetRankingScore(List<AppTarget> chooserTargetScores, UserHandle userHandle) { final Message msg = Message.obtain(); @@ -2839,8 +2860,8 @@ public class ChooserActivity extends ResolverActivity implements return; } - // no need to query direct share for work profile when its turned off - if (isQuietModeEnabled(chooserListAdapter.getUserHandle())) { + // no need to query direct share for work profile when its locked or disabled + if (!shouldQueryShortcutManager(chooserListAdapter.getUserHandle())) { getChooserActivityLogger().logSharesheetAppLoadComplete(); return; } @@ -2865,6 +2886,12 @@ public class ChooserActivity extends ResolverActivity implements } @VisibleForTesting + protected boolean isUserRunning(UserHandle userHandle) { + UserManager userManager = getSystemService(UserManager.class); + return userManager.isUserRunning(userHandle); + } + + @VisibleForTesting protected boolean isQuietModeEnabled(UserHandle userHandle) { UserManager userManager = getSystemService(UserManager.class); return userManager.isQuietModeEnabled(userHandle); diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java index 31e6cb9b5591..00b5cb646bca 100644 --- a/core/java/com/android/internal/app/ChooserListAdapter.java +++ b/core/java/com/android/internal/app/ChooserListAdapter.java @@ -917,6 +917,7 @@ public class ChooserListAdapter extends ResolverListAdapter { if (getAppPredictor() != null) { getAppPredictor().unregisterPredictionUpdates(mAppPredictorCallback); getAppPredictor().destroy(); + setAppPredictor(null); } } diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java index 49de7c80057f..0bf10cb710cb 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java @@ -1995,6 +1995,70 @@ public class ChooserActivityTest { isQueryTargetServicesCalledOnWorkProfile[0]); } + @Test + public void testWorkTab_selectingWorkTabWithLockedWorkUser_directShareTargetsNotQueried() { + // enable the work tab feature flag + ResolverActivity.ENABLE_TABBED_VIEW = true; + markWorkProfileUserAvailable(); + List<ResolvedComponentInfo> personalResolvedComponentInfos = + createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10); + List<ResolvedComponentInfo> workResolvedComponentInfos = + createResolvedComponentsForTest(3); + setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos); + sOverrides.isWorkProfileUserRunning = false; + boolean[] isQueryDirectShareCalledOnWorkProfile = new boolean[] { false }; + sOverrides.onQueryDirectShareTargets = chooserListAdapter -> { + isQueryDirectShareCalledOnWorkProfile[0] = + (chooserListAdapter.getUserHandle().getIdentifier() == 10); + return null; + }; + boolean[] isQueryTargetServicesCalledOnWorkProfile = new boolean[] { false }; + sOverrides.onQueryTargetServices = chooserListAdapter -> { + isQueryTargetServicesCalledOnWorkProfile[0] = + (chooserListAdapter.getUserHandle().getIdentifier() == 10); + return null; + }; + Intent sendIntent = createSendTextIntent(); + sendIntent.setType("TestType"); + + mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test")); + waitForIdle(); + onView(withId(R.id.contentPanel)) + .perform(swipeUp()); + onView(withText(R.string.resolver_work_tab)).perform(click()); + waitForIdle(); + + assertFalse("Direct share targets were queried on a locked work profile user", + isQueryDirectShareCalledOnWorkProfile[0]); + assertFalse("Target services were queried on a locked work profile user", + isQueryTargetServicesCalledOnWorkProfile[0]); + } + + @Test + public void testWorkTab_workUserLocked_workTargetsShown() { + // enable the work tab feature flag + ResolverActivity.ENABLE_TABBED_VIEW = true; + markWorkProfileUserAvailable(); + List<ResolvedComponentInfo> personalResolvedComponentInfos = + createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10); + List<ResolvedComponentInfo> workResolvedComponentInfos = + createResolvedComponentsForTest(3); + setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos); + Intent sendIntent = createSendTextIntent(); + sendIntent.setType("TestType"); + sOverrides.isWorkProfileUserRunning = false; + + final ChooserWrapperActivity activity = + mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test")); + waitForIdle(); + onView(withId(R.id.contentPanel)) + .perform(swipeUp()); + onView(withText(R.string.resolver_work_tab)).perform(click()); + waitForIdle(); + + assertEquals(3, activity.getWorkListAdapter().getCount()); + } + private Intent createChooserIntent(Intent intent, Intent[] initialIntents) { Intent chooserIntent = new Intent(); chooserIntent.setAction(Intent.ACTION_CHOOSER); diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java index 0f6b51f82116..b7d6c6196495 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java @@ -227,6 +227,11 @@ public class ChooserWrapperActivity extends ChooserActivity { return sOverrides.isQuietModeEnabled; } + @Override + protected boolean isUserRunning(UserHandle userHandle) { + return sOverrides.isWorkProfileUserRunning; + } + /** * We cannot directly mock the activity created since instrumentation creates it. * <p> @@ -252,6 +257,7 @@ public class ChooserWrapperActivity extends ChooserActivity { public UserHandle workProfileUserHandle; public boolean hasCrossProfileIntents; public boolean isQuietModeEnabled; + public boolean isWorkProfileUserRunning; public AbstractMultiProfilePagerAdapter.Injector multiPagerAdapterInjector; public PackageManager packageManager; @@ -274,6 +280,7 @@ public class ChooserWrapperActivity extends ChooserActivity { workProfileUserHandle = null; hasCrossProfileIntents = true; isQuietModeEnabled = false; + isWorkProfileUserRunning = true; packageManager = null; multiPagerAdapterInjector = new AbstractMultiProfilePagerAdapter.Injector() { @Override diff --git a/data/etc/Android.bp b/data/etc/Android.bp index 1d3a3997d857..fb8b17c1f159 100644 --- a/data/etc/Android.bp +++ b/data/etc/Android.bp @@ -63,6 +63,14 @@ prebuilt_etc { } prebuilt_etc { + name: "privapp_whitelist_com.android.cellbroadcastreceiver", + system_ext_specific: true, + sub_dir: "permissions", + src: "com.android.cellbroadcastreceiver.xml", + filename_from_src: true, +} + +prebuilt_etc { name: "privapp_whitelist_com.android.contacts", product_specific: true, sub_dir: "permissions", diff --git a/data/etc/com.android.cellbroadcastreceiver.xml b/data/etc/com.android.cellbroadcastreceiver.xml new file mode 100644 index 000000000000..dd2df42e442f --- /dev/null +++ b/data/etc/com.android.cellbroadcastreceiver.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> +<permissions> + <privapp-permissions package="com.android.cellbroadcastreceiver"> + <permission name="android.permission.INTERACT_ACROSS_USERS"/> + <permission name="android.permission.MANAGE_USERS"/> + <permission name="android.permission.MODIFY_PHONE_STATE"/> + <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/> + <permission name="android.permission.RECEIVE_EMERGENCY_BROADCAST"/> + <permission name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"/> + </privapp-permissions> +</permissions> diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java index ba87f2bbffb5..87c3bb9ffabe 100644 --- a/media/java/android/media/ImageReader.java +++ b/media/java/android/media/ImageReader.java @@ -200,6 +200,20 @@ public class ImageReader implements AutoCloseable { * </table> * Using other combinations may result in {@link IllegalArgumentException}. * </p> + * <p> + * If the {@link ImageReader} is used as an output target for a {@link + * android.hardware.camera2.CameraDevice}, and if the usage flag contains + * {@link HardwareBuffer#USAGE_VIDEO_ENCODE}, the timestamps of the + * {@link Image images} produced by the {@link ImageReader} won't be in the same timebase as + * {@link android.os.SystemClock#elapsedRealtimeNanos}, even if + * {@link android.hardware.camera2.CameraCharacteristics#SENSOR_INFO_TIMESTAMP_SOURCE} is + * {@link android.hardware.camera2.CameraCharacteristics#SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME}. + * Instead, the timestamps will be roughly in the same timebase as in + * {@link android.os.SystemClock#uptimeMillis}, so that A/V synchronization could work for + * video recording. In this case, the timestamps from the {@link ImageReader} with + * {@link HardwareBuffer#USAGE_VIDEO_ENCODE} usage flag may not be directly comparable with + * timestamps of other streams or capture result metadata. + * </p> * @param width The default width in pixels of the Images that this reader will produce. * @param height The default height in pixels of the Images that this reader will produce. * @param format The format of the Image that this reader will produce. This must be one of the diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp index 4a9da62f2517..936edb3fb005 100644 --- a/media/jni/android_media_ImageWriter.cpp +++ b/media/jni/android_media_ImageWriter.cpp @@ -86,6 +86,14 @@ public: void setBufferHeight(int height) { mHeight = height; } int getBufferHeight() { return mHeight; } + void queueAttachedFlag(bool isAttached) { + Mutex::Autolock l(mAttachedFlagQueueLock); + mAttachedFlagQueue.push_back(isAttached); + } + void dequeueAttachedFlag() { + Mutex::Autolock l(mAttachedFlagQueueLock); + mAttachedFlagQueue.pop_back(); + } private: static JNIEnv* getJNIEnv(bool* needsDetach); static void detachJNI(); @@ -136,6 +144,11 @@ private: }; static BufferDetacher sBufferDetacher; + + // Buffer queue guarantees both producer and consumer side buffer flows are + // in order. See b/19977520. As a result, we can use a queue here. + Mutex mAttachedFlagQueueLock; + std::deque<bool> mAttachedFlagQueue; }; JNIImageWriterContext::BufferDetacher JNIImageWriterContext::sBufferDetacher; @@ -265,11 +278,23 @@ void JNIImageWriterContext::onBufferReleased() { ALOGV("%s: buffer released", __FUNCTION__); bool needsDetach = false; JNIEnv* env = getJNIEnv(&needsDetach); + + bool bufferIsAttached = false; + { + Mutex::Autolock l(mAttachedFlagQueueLock); + if (!mAttachedFlagQueue.empty()) { + bufferIsAttached = mAttachedFlagQueue.front(); + mAttachedFlagQueue.pop_front(); + } else { + ALOGW("onBufferReleased called with no attached flag queued"); + } + } + if (env != NULL) { // Detach the buffer every time when a buffer consumption is done, // need let this callback give a BufferItem, then only detach if it was attached to this - // Writer. Do the detach unconditionally for opaque format now. see b/19977520 - if (mFormat == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) { + // Writer. see b/19977520 + if (mFormat == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED || bufferIsAttached) { sBufferDetacher.detach(mProducer); } @@ -622,10 +647,16 @@ static void ImageWriter_queueImage(JNIEnv* env, jobject thiz, jlong nativeCtx, j return; } - // Finally, queue input buffer + // Finally, queue input buffer. + // + // Because onBufferReleased may be called before queueBuffer() returns, + // queue the "attached" flag before calling queueBuffer. In case + // queueBuffer() fails, remove it from the queue. + ctx->queueAttachedFlag(false); res = anw->queueBuffer(anw.get(), buffer, fenceFd); if (res != OK) { ALOGE("%s: Queue buffer failed: %s (%d)", __FUNCTION__, strerror(-res), res); + ctx->dequeueAttachedFlag(); switch (res) { case NO_INIT: jniThrowException(env, "java/lang/IllegalStateException", @@ -720,10 +751,16 @@ static jint ImageWriter_attachAndQueueImage(JNIEnv* env, jobject thiz, jlong nat } // Step 3. Queue Image. + // + // Because onBufferReleased may be called before queueBuffer() returns, + // queue the "attached" flag before calling queueBuffer. In case + // queueBuffer() fails, remove it from the queue. + ctx->queueAttachedFlag(true); res = anw->queueBuffer(anw.get(), buffer->mGraphicBuffer.get(), /*fenceFd*/ -1); if (res != OK) { ALOGE("%s: Queue buffer failed: %s (%d)", __FUNCTION__, strerror(-res), res); + ctx->dequeueAttachedFlag(); switch (res) { case NO_INIT: jniThrowException(env, "java/lang/IllegalStateException", diff --git a/packages/SystemUI/res/layout/global_actions_power_item.xml b/packages/SystemUI/res/layout/global_actions_power_item.xml index 0d060b63486f..3bf58944423b 100644 --- a/packages/SystemUI/res/layout/global_actions_power_item.xml +++ b/packages/SystemUI/res/layout/global_actions_power_item.xml @@ -26,7 +26,7 @@ android:id="@*android:id/icon" android:layout_width="24dp" android:layout_height="24dp" - android:layout_marginBottom="45dp" + android:layout_marginBottom="@dimen/global_actions_power_dialog_item_bottom_margin" android:scaleType="centerInside" android:tint="@color/control_primary_text" /> <TextView diff --git a/packages/SystemUI/res/layout/media_view.xml b/packages/SystemUI/res/layout/media_view.xml index 6792c647d666..8441282bd46d 100644 --- a/packages/SystemUI/res/layout/media_view.xml +++ b/packages/SystemUI/res/layout/media_view.xml @@ -27,6 +27,14 @@ android:forceHasOverlappingRendering="false" android:background="@drawable/qs_media_background"> + <androidx.constraintlayout.widget.Guideline + android:id="@+id/center_vertical_guideline" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="vertical" + app:layout_constraintGuide_percent="0.5" + /> + <!-- As per Material Design on Biderectionality, this is forced to LTR in code --> <FrameLayout android:id="@+id/notification_media_progress_time" @@ -133,6 +141,7 @@ android:layout_width="@dimen/qs_seamless_icon_size" android:layout_height="@dimen/qs_seamless_icon_size" android:layout_marginEnd="8dp" + android:layout_gravity="center_vertical" android:tint="@color/media_primary_text" android:src="@*android:drawable/ic_media_seamless" /> @@ -140,6 +149,7 @@ android:id="@+id/media_seamless_text" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_gravity="center_vertical" android:fontFamily="@*android:string/config_headlineFontFamily" android:singleLine="true" android:text="@*android:string/ext_media_seamless_action" @@ -156,15 +166,6 @@ android:src="@drawable/ic_cast_connected" android:forceHasOverlappingRendering="false" /> - <androidx.constraintlayout.widget.Barrier - android:id="@+id/media_seamless_barrier" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - app:barrierDirection="start" - app:constraint_referenced_ids="media_seamless,media_seamless_fallback" - app:barrierAllowsGoneWidgets="false" - /> - <!-- Seek Bar --> <!-- As per Material Design on Biderectionality, this is forced to LTR in code --> <SeekBar diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml index 2c08925be496..9e1b66f07758 100644 --- a/packages/SystemUI/res/values-land/dimens.xml +++ b/packages/SystemUI/res/values-land/dimens.xml @@ -44,4 +44,7 @@ <dimen name="biometric_dialog_button_negative_max_width">140dp</dimen> <dimen name="biometric_dialog_button_positive_max_width">116dp</dimen> + + <dimen name="global_actions_power_dialog_item_height">130dp</dimen> + <dimen name="global_actions_power_dialog_item_bottom_margin">35dp</dimen> </resources> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 29a2ad4cba9f..18f79df61e30 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1061,6 +1061,7 @@ <!-- Shutdown and restart actions are larger in power options dialog --> <dimen name="global_actions_power_dialog_item_height">190dp</dimen> <dimen name="global_actions_power_dialog_item_width">255dp</dimen> + <dimen name="global_actions_power_dialog_item_bottom_margin">45dp</dimen> <!-- The maximum offset in either direction that elements are moved horizontally to prevent burn-in on AOD. --> @@ -1268,6 +1269,7 @@ <dimen name="qs_media_padding">16dp</dimen> <dimen name="qs_media_panel_outer_padding">16dp</dimen> <dimen name="qs_media_album_size">52dp</dimen> + <dimen name="qs_center_guideline_padding">10dp</dimen> <dimen name="qs_seamless_icon_size">20dp</dimen> <dimen name="qs_seamless_fallback_icon_size">20dp</dimen> <dimen name="qs_seamless_fallback_top_margin">18dp</dimen> diff --git a/packages/SystemUI/res/xml/media_collapsed.xml b/packages/SystemUI/res/xml/media_collapsed.xml index 811e0e351bd3..0926a9802ff4 100644 --- a/packages/SystemUI/res/xml/media_collapsed.xml +++ b/packages/SystemUI/res/xml/media_collapsed.xml @@ -31,12 +31,12 @@ android:id="@+id/app_name" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginEnd="10dp" + android:layout_marginEnd="@dimen/qs_center_guideline_padding" android:layout_marginStart="10dp" android:layout_marginTop="20dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toEndOf="@id/icon" - app:layout_constraintEnd_toStartOf="@id/media_seamless_barrier" + app:layout_constraintEnd_toStartOf="@id/center_vertical_guideline" app:layout_constraintHorizontal_bias="0" /> @@ -47,8 +47,11 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintWidth_min="60dp" + app:layout_constraintStart_toEndOf="@id/center_vertical_guideline" + app:layout_constraintHorizontal_bias="1" android:layout_marginTop="@dimen/qs_media_panel_outer_padding" android:layout_marginEnd="@dimen/qs_media_panel_outer_padding" + android:layout_marginStart="@dimen/qs_center_guideline_padding" /> <Constraint @@ -57,10 +60,13 @@ android:layout_height="@dimen/qs_seamless_fallback_icon_size" android:layout_marginTop="@dimen/qs_seamless_fallback_top_margin" android:layout_marginEnd="@dimen/qs_seamless_fallback_end_margin" + android:layout_marginStart="@dimen/qs_center_guideline_padding" android:alpha="0.5" android:visibility="gone" + app:layout_constraintHorizontal_bias="1" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" + app:layout_constraintStart_toEndOf="@id/center_vertical_guideline" /> <Constraint diff --git a/packages/SystemUI/res/xml/media_expanded.xml b/packages/SystemUI/res/xml/media_expanded.xml index 8432abcc16cb..dd15d5d8bb4e 100644 --- a/packages/SystemUI/res/xml/media_expanded.xml +++ b/packages/SystemUI/res/xml/media_expanded.xml @@ -31,12 +31,12 @@ android:id="@+id/app_name" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginEnd="10dp" + android:layout_marginEnd="@dimen/qs_center_guideline_padding" android:layout_marginStart="10dp" android:layout_marginTop="20dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toEndOf="@id/icon" - app:layout_constraintEnd_toStartOf="@id/media_seamless_barrier" + app:layout_constraintEnd_toStartOf="@id/center_vertical_guideline" app:layout_constraintHorizontal_bias="0" /> @@ -46,9 +46,12 @@ android:layout_height="wrap_content" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" + app:layout_constraintStart_toEndOf="@id/center_vertical_guideline" + app:layout_constraintHorizontal_bias="1" app:layout_constraintWidth_min="60dp" android:layout_marginTop="@dimen/qs_media_panel_outer_padding" android:layout_marginEnd="@dimen/qs_media_panel_outer_padding" + android:layout_marginStart="@dimen/qs_center_guideline_padding" /> <Constraint @@ -57,10 +60,13 @@ android:layout_height="@dimen/qs_seamless_fallback_icon_size" android:layout_marginTop="@dimen/qs_seamless_fallback_top_margin" android:layout_marginEnd="@dimen/qs_seamless_fallback_end_margin" + android:layout_marginStart="@dimen/qs_center_guideline_padding" android:alpha="0.5" android:visibility="gone" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" + app:layout_constraintStart_toEndOf="@id/center_vertical_guideline" + app:layout_constraintHorizontal_bias="1" /> <Constraint diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index ee31706c0b94..7792afa3d84c 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -251,7 +251,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private boolean mDeviceProvisioned; // Battery status - private BatteryStatus mBatteryStatus; + @VisibleForTesting + BatteryStatus mBatteryStatus; private StrongAuthTracker mStrongAuthTracker; @@ -1698,6 +1699,17 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab .getServiceStateForSubscriber(subId); mHandler.sendMessage( mHandler.obtainMessage(MSG_SERVICE_STATE_CHANGE, subId, 0, serviceState)); + + // Get initial state. Relying on Sticky behavior until API for getting info. + if (mBatteryStatus == null) { + Intent intent = mContext.registerReceiver( + null, + new IntentFilter(Intent.ACTION_BATTERY_CHANGED) + ); + if (intent != null && mBatteryStatus == null) { + mBroadcastReceiver.onReceive(mContext, intent); + } + } }); mHandler.post(this::registerRingerTracker); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java index 2bfe015c2787..1211fb491ced 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java @@ -495,12 +495,9 @@ public class BubbleExpandedView extends LinearLayout { } final float alpha = visibility ? 1f : 0f; - if (alpha == mActivityView.getAlpha()) { - return; - } - mPointerView.setAlpha(alpha); - if (mActivityView != null) { + + if (mActivityView != null && alpha != mActivityView.getAlpha()) { mActivityView.setAlpha(alpha); mActivityView.bringToFront(); } diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestDialog.kt index 15d15e8ffbc7..4ed610675093 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestDialog.kt @@ -41,7 +41,7 @@ import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.util.LifecycleActivity import javax.inject.Inject -class ControlsRequestDialog @Inject constructor( +open class ControlsRequestDialog @Inject constructor( private val controller: ControlsController, private val broadcastDispatcher: BroadcastDispatcher, private val controlsListingController: ControlsListingController @@ -51,7 +51,7 @@ class ControlsRequestDialog @Inject constructor( private const val TAG = "ControlsRequestDialog" } - private lateinit var component: ComponentName + private lateinit var controlComponent: ComponentName private lateinit var control: Control private var dialog: Dialog? = null private val callback = object : ControlsListingController.ControlsListingCallback { @@ -86,7 +86,7 @@ class ControlsRequestDialog @Inject constructor( finish() } - component = intent.getParcelableExtra(Intent.EXTRA_COMPONENT_NAME) ?: run { + controlComponent = intent.getParcelableExtra(Intent.EXTRA_COMPONENT_NAME) ?: run { Log.e(TAG, "Request did not contain componentName") finish() return @@ -103,7 +103,7 @@ class ControlsRequestDialog @Inject constructor( super.onResume() val label = verifyComponentAndGetLabel() if (label == null) { - Log.e(TAG, "The component specified (${component.flattenToString()} " + + Log.e(TAG, "The component specified (${controlComponent.flattenToString()} " + "is not a valid ControlsProviderService") finish() return @@ -127,16 +127,16 @@ class ControlsRequestDialog @Inject constructor( } private fun verifyComponentAndGetLabel(): CharSequence? { - return controlsListingController.getAppLabel(component) + return controlsListingController.getAppLabel(controlComponent) } private fun isCurrentFavorite(): Boolean { - val favorites = controller.getFavoritesForComponent(component) + val favorites = controller.getFavoritesForComponent(controlComponent) return favorites.any { it.controls.any { it.controlId == control.controlId } } } fun createDialog(label: CharSequence): Dialog { - val renderInfo = RenderInfo.lookup(this, component, control.deviceType) + val renderInfo = RenderInfo.lookup(this, controlComponent, control.deviceType) val frame = LayoutInflater.from(this).inflate(R.layout.controls_dialog, null).apply { requireViewById<ImageView>(R.id.icon).apply { setImageDrawable(renderInfo.icon) @@ -170,7 +170,7 @@ class ControlsRequestDialog @Inject constructor( override fun onClick(dialog: DialogInterface?, which: Int) { if (which == Dialog.BUTTON_POSITIVE) { controller.addFavorite( - componentName, + controlComponent, control.structure ?: "", ControlInfo(control.controlId, control.title, control.subtitle, control.deviceType) ) diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt index c073642afa4e..22d6b6bb75c3 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt @@ -128,15 +128,22 @@ class ControlActionCoordinatorImpl @Inject constructor( } private fun bouncerOrRun(action: Action) { - if (!keyguardStateController.isUnlocked()) { - context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) + if (keyguardStateController.isShowing()) { + var closeGlobalActions = !keyguardStateController.isUnlocked() + if (closeGlobalActions) { + context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) - // pending actions will only run after the control state has been refreshed - pendingAction = action + // pending actions will only run after the control state has been refreshed + pendingAction = action + } activityStarter.dismissKeyguardThenExecute({ Log.d(ControlsUiController.TAG, "Device unlocked, invoking controls action") - globalActionsComponent.handleShowGlobalActionsMenu() + if (closeGlobalActions) { + globalActionsComponent.handleShowGlobalActionsMenu() + } else { + action.invoke() + } true }, { pendingAction = null }, true /* afterKeyguardGone */) } else { diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index eed52004923d..b2e91643bed2 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -2637,10 +2637,10 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } private boolean shouldShowControls() { - return (mKeyguardStateController.isUnlocked() || mShowLockScreenCardsAndControls) - && controlsAvailable() - && mLockPatternUtils.getStrongAuthForUser(getCurrentUser().id) - != STRONG_AUTH_REQUIRED_AFTER_BOOT; + boolean showOnLockScreen = mShowLockScreenCardsAndControls && mLockPatternUtils + .getStrongAuthForUser(getCurrentUser().id) != STRONG_AUTH_REQUIRED_AFTER_BOOT; + return controlsAvailable() + && (mKeyguardStateController.isUnlocked() || showOnLockScreen); } private boolean controlsAvailable() { diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt index 5052386e65e1..d6b6660b778c 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt @@ -193,12 +193,15 @@ class MediaDataManager( private fun clearData() { // Called on user change. Remove all current MediaData objects and inform listeners val listenersCopy = listeners.toSet() - mediaEntries.forEach { + val keyCopy = mediaEntries.keys.toMutableList() + // Clear the list first, to make sure callbacks from listeners if we have any entries + // are up to date + mediaEntries.clear() + keyCopy.forEach { listenersCopy.forEach { listener -> - listener.onMediaDataRemoved(it.key) + listener.onMediaDataRemoved(it) } } - mediaEntries.clear() } private fun removeAllForPackage(packageName: String) { diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java index e2feb71735ff..a7dd53e48a81 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java @@ -224,6 +224,16 @@ public class PipTaskOrganizer extends TaskOrganizer implements return new Rect(mLastReportedBounds); } + public Rect getCurrentOrAnimatingBounds() { + PipAnimationController.PipTransitionAnimator animator = + mPipAnimationController.getCurrentAnimator(); + if (animator != null && animator.isRunning()) { + System.out.println("RUNNING ANIM: anim=" + animator.getDestinationBounds() + " last=" + getLastReportedBounds()); + return new Rect(animator.getDestinationBounds()); + } + return getLastReportedBounds(); + } + public boolean isInPip() { return mInPip; } @@ -406,7 +416,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements private void sendOnPipTransitionStarted( @PipAnimationController.TransitionDirection int direction) { - mMainHandler.post(() -> { + runOnMainHandler(() -> { for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) { final PipTransitionCallback callback = mPipTransitionCallbacks.get(i); callback.onPipTransitionStarted(mTaskInfo.baseActivity, direction); @@ -416,7 +426,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements private void sendOnPipTransitionFinished( @PipAnimationController.TransitionDirection int direction) { - mMainHandler.post(() -> { + runOnMainHandler(() -> { for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) { final PipTransitionCallback callback = mPipTransitionCallbacks.get(i); callback.onPipTransitionFinished(mTaskInfo.baseActivity, direction); @@ -426,7 +436,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements private void sendOnPipTransitionCancelled( @PipAnimationController.TransitionDirection int direction) { - mMainHandler.post(() -> { + runOnMainHandler(() -> { for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) { final PipTransitionCallback callback = mPipTransitionCallbacks.get(i); callback.onPipTransitionCanceled(mTaskInfo.baseActivity, direction); @@ -434,6 +444,14 @@ public class PipTaskOrganizer extends TaskOrganizer implements }); } + private void runOnMainHandler(Runnable r) { + if (Looper.getMainLooper() == Looper.myLooper()) { + r.run(); + } else { + mMainHandler.post(r); + } + } + /** * Note that dismissing PiP is now originated from SystemUI, see {@link #exitPip(int)}. * Meanwhile this callback is invoked whenever the task is removed. For instance: @@ -505,15 +523,29 @@ public class PipTaskOrganizer extends TaskOrganizer implements */ @SuppressWarnings("unchecked") public void onMovementBoundsChanged(Rect destinationBoundsOut, boolean fromRotation, - boolean fromImeAdjustment, boolean fromShelfAdjustment) { + boolean fromImeAdjustment, boolean fromShelfAdjustment, + WindowContainerTransaction wct) { final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController.getCurrentAnimator(); if (animator == null || !animator.isRunning() || animator.getTransitionDirection() != TRANSITION_DIRECTION_TO_PIP) { if (mInPip && fromRotation) { - // this could happen if rotation finishes before the animation + // If we are rotating while there is a current animation, immediately cancel the + // animation (remove the listeners so we don't trigger the normal finish resize + // call that should only happen on the update thread) + int direction = animator.getTransitionDirection(); + animator.removeAllUpdateListeners(); + animator.removeAllListeners(); + animator.cancel(); + // Do notify the listeners that this was canceled + sendOnPipTransitionCancelled(direction); mLastReportedBounds.set(destinationBoundsOut); - scheduleFinishResizePip(mLastReportedBounds); + + // Create a reset surface transaction for the new bounds and update the window + // container transaction + final SurfaceControl.Transaction tx = createFinishResizeSurfaceTransaction( + destinationBoundsOut); + prepareFinishResizeTransaction(destinationBoundsOut, direction, tx, wct); } else { // There could be an animation on-going. If there is one on-going, last-reported // bounds isn't yet updated. We'll use the animator's bounds instead. @@ -622,7 +654,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements * {@link #scheduleResizePip}. */ public void scheduleFinishResizePip(Rect destinationBounds) { - scheduleFinishResizePip(destinationBounds, null); + scheduleFinishResizePip(destinationBounds, null /* updateBoundsCallback */); } /** @@ -630,30 +662,36 @@ public class PipTaskOrganizer extends TaskOrganizer implements */ public void scheduleFinishResizePip(Rect destinationBounds, Consumer<Rect> updateBoundsCallback) { - final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); - mSurfaceTransactionHelper - .crop(tx, mLeash, destinationBounds) - .resetScale(tx, mLeash, destinationBounds) - .round(tx, mLeash, mInPip); - scheduleFinishResizePip(tx, destinationBounds, TRANSITION_DIRECTION_NONE, - updateBoundsCallback); + scheduleFinishResizePip(destinationBounds, TRANSITION_DIRECTION_NONE, updateBoundsCallback); } - private void scheduleFinishResizePip(SurfaceControl.Transaction tx, - Rect destinationBounds, @PipAnimationController.TransitionDirection int direction, + private void scheduleFinishResizePip(Rect destinationBounds, + @PipAnimationController.TransitionDirection int direction, Consumer<Rect> updateBoundsCallback) { if (!mInPip) { // can be initiated in other component, ignore if we are no longer in PIP return; } + SomeArgs args = SomeArgs.obtain(); args.arg1 = updateBoundsCallback; - args.arg2 = tx; + args.arg2 = createFinishResizeSurfaceTransaction( + destinationBounds); args.arg3 = destinationBounds; args.argi1 = direction; mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_FINISH_RESIZE, args)); } + private SurfaceControl.Transaction createFinishResizeSurfaceTransaction( + Rect destinationBounds) { + final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); + mSurfaceTransactionHelper + .crop(tx, mLeash, destinationBounds) + .resetScale(tx, mLeash, destinationBounds) + .round(tx, mLeash, mInPip); + return tx; + } + /** * Offset the PiP window by a given offset on Y-axis, triggered also from screen rotation. */ @@ -741,7 +779,15 @@ public class PipTaskOrganizer extends TaskOrganizer implements return; } - final WindowContainerTransaction wct = new WindowContainerTransaction(); + WindowContainerTransaction wct = new WindowContainerTransaction(); + prepareFinishResizeTransaction(destinationBounds, direction, tx, wct); + applyFinishBoundsResize(wct, direction); + } + + private void prepareFinishResizeTransaction(Rect destinationBounds, + @PipAnimationController.TransitionDirection int direction, + SurfaceControl.Transaction tx, + WindowContainerTransaction wct) { final Rect taskBounds; if (isInPipDirection(direction)) { // If we are animating from fullscreen using a bounds animation, then reset the @@ -762,7 +808,6 @@ public class PipTaskOrganizer extends TaskOrganizer implements wct.setBounds(mToken, taskBounds); wct.setBoundsChangeTransaction(mToken, tx); - applyFinishBoundsResize(wct, direction); } /** @@ -819,7 +864,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements } private float getAspectRatioOrDefault(@Nullable PictureInPictureParams params) { - return params == null + return params == null || !params.hasSetAspectRatio() ? mPipBoundsHandler.getDefaultAspectRatio() : params.getAspectRatio(); } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java index 7a18ec361860..1fbe58d28d39 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -36,6 +36,7 @@ import android.util.Log; import android.util.Pair; import android.view.DisplayInfo; import android.view.IPinnedStackController; +import android.view.SurfaceControl; import android.window.WindowContainerTransaction; import com.android.systemui.Dependency; @@ -94,9 +95,12 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio */ private final DisplayChangeController.OnDisplayChangingListener mRotationController = ( int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) -> { + // If there is an animation running (ie. from a shelf offset), then ensure that we calculate + // the bounds for the next orientation using the destination bounds of the animation + // TODO: Techincally this should account for movement animation bounds as well + Rect currentBounds = mPipTaskOrganizer.getCurrentOrAnimatingBounds(); final boolean changed = mPipBoundsHandler.onDisplayRotationChanged(mTmpNormalBounds, - mPipTaskOrganizer.getLastReportedBounds(), mTmpInsetBounds, displayId, fromRotation, - toRotation, t); + currentBounds, mTmpInsetBounds, displayId, fromRotation, toRotation, t); if (changed) { // If the pip was in the offset zone earlier, adjust the new bounds to the bottom of the // movement bounds @@ -116,7 +120,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio } updateMovementBounds(mTmpNormalBounds, true /* fromRotation */, - false /* fromImeAdjustment */, false /* fromShelfAdjustment */); + false /* fromImeAdjustment */, false /* fromShelfAdjustment */, t); } }; @@ -194,7 +198,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio @Override public void onMovementBoundsChanged(boolean fromImeAdjustment) { mHandler.post(() -> updateMovementBounds(null /* toBounds */, - false /* fromRotation */, fromImeAdjustment, false /* fromShelfAdjustment */)); + false /* fromRotation */, fromImeAdjustment, false /* fromShelfAdjustment */, + null /* windowContainerTransaction */)); } @Override @@ -327,7 +332,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio mTouchHandler.onShelfVisibilityChanged(visible, shelfHeight); updateMovementBounds(mPipTaskOrganizer.getLastReportedBounds(), false /* fromRotation */, false /* fromImeAdjustment */, - true /* fromShelfAdjustment */); + true /* fromShelfAdjustment */, null /* windowContainerTransaction */); } }); } @@ -387,15 +392,16 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio } private void updateMovementBounds(@Nullable Rect toBounds, boolean fromRotation, - boolean fromImeAdjustment, boolean fromShelfAdjustment) { + boolean fromImeAdjustment, boolean fromShelfAdjustment, + WindowContainerTransaction wct) { // Populate inset / normal bounds and DisplayInfo from mPipBoundsHandler before // passing to mTouchHandler/mPipTaskOrganizer final Rect outBounds = new Rect(toBounds); mPipBoundsHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds, outBounds, mTmpDisplayInfo); // mTouchHandler would rely on the bounds populated from mPipTaskOrganizer - mPipTaskOrganizer.onMovementBoundsChanged(outBounds, fromRotation, - fromImeAdjustment, fromShelfAdjustment); + mPipTaskOrganizer.onMovementBoundsChanged(outBounds, fromRotation, fromImeAdjustment, + fromShelfAdjustment, wct); mTouchHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds, outBounds, fromImeAdjustment, fromShelfAdjustment, mTmpDisplayInfo.rotation); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index a4d7bad2891f..79f99f459ace 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -480,6 +480,8 @@ public class PipTouchHandler { mSnapAlgorithm.getMovementBounds(curBounds, insetBounds, toMovementBounds, mIsImeShowing ? mImeHeight : 0); final int prevBottom = mMovementBounds.bottom - mMovementBoundsExtraOffsets; + // This is to handle landscape fullscreen IMEs, don't apply the extra offset in this + // case final int toBottom = toMovementBounds.bottom < toMovementBounds.top ? toMovementBounds.bottom : toMovementBounds.bottom - extraOffset; @@ -490,10 +492,16 @@ public class PipTouchHandler { mSavedSnapFraction); } - if ((Math.min(prevBottom, toBottom) - mBottomOffsetBufferPx) <= curBounds.top - && curBounds.top <= (Math.max(prevBottom, toBottom) - + mBottomOffsetBufferPx)) { - mMotionHelper.animateToOffset(curBounds, toBottom - curBounds.top); + if (prevBottom < toBottom) { + // The movement bounds are expanding + if (curBounds.top > prevBottom - mBottomOffsetBufferPx) { + mMotionHelper.animateToOffset(curBounds, toBottom - curBounds.top); + } + } else if (prevBottom > toBottom) { + // The movement bounds are shrinking + if (curBounds.top > toBottom - mBottomOffsetBufferPx) { + mMotionHelper.animateToOffset(curBounds, toBottom - curBounds.top); + } } } } @@ -971,6 +979,8 @@ public class PipTouchHandler { } mShouldHideMenuAfterFling = mMenuState == MENU_STATE_NONE; + // Reset the touch state on up before the fling settles + mTouchState.reset(); mMotionHelper.flingToSnapTarget(vel.x, vel.y, PipTouchHandler.this::updateDismissFraction /* updateAction */, this::flingEndAction /* endAction */); @@ -997,7 +1007,6 @@ public class PipTouchHandler { } private void flingEndAction() { - mTouchState.setAllowTouches(true); if (mShouldHideMenuAfterFling) { // If the menu is not visible, then we can still be showing the activity for the // dismiss overlay, so just finish it after the animation completes diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java index 078c540939aa..66804bef8f53 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java @@ -225,6 +225,8 @@ public class PowerUI extends SystemUI implements CommandQueue.Callbacks { @VisibleForTesting final class Receiver extends BroadcastReceiver { + private boolean mHasReceivedBattery = false; + public void init() { // Register for Intent broadcasts for... IntentFilter filter = new IntentFilter(); @@ -234,6 +236,17 @@ public class PowerUI extends SystemUI implements CommandQueue.Callbacks { filter.addAction(Intent.ACTION_SCREEN_ON); filter.addAction(Intent.ACTION_USER_SWITCHED); mBroadcastDispatcher.registerReceiverWithHandler(this, filter, mHandler); + // Force get initial values. Relying on Sticky behavior until API for getting info. + if (!mHasReceivedBattery) { + // Get initial state + Intent intent = mContext.registerReceiver( + null, + new IntentFilter(Intent.ACTION_BATTERY_CHANGED) + ); + if (intent != null) { + onReceive(mContext, intent); + } + } } @Override @@ -246,6 +259,7 @@ public class PowerUI extends SystemUI implements CommandQueue.Callbacks { } }); } else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) { + mHasReceivedBattery = true; final int oldBatteryLevel = mBatteryLevel; mBatteryLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 100); final int oldBatteryStatus = mBatteryStatus; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java index 6b12e478f627..eba4465018ab 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java @@ -96,6 +96,11 @@ public class QSContainerImpl extends FrameLayout { mAnimateBottomOnNextLayout = true; } }); + mQSPanel.setMediaVisibilityChangedListener((visible) -> { + if (mQSPanel.isShown()) { + mAnimateBottomOnNextLayout = true; + } + }); setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java index 00419e671814..7f3516194298 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java @@ -74,7 +74,8 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC protected boolean mPowerSave; private boolean mAodPowerSave; private boolean mTestmode = false; - private boolean mHasReceivedBattery = false; + @VisibleForTesting + boolean mHasReceivedBattery = false; private Estimate mEstimate; private boolean mFetchingEstimate = false; @@ -102,6 +103,16 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC @Override public void init() { registerReceiver(); + if (!mHasReceivedBattery) { + // Get initial state. Relying on Sticky behavior until API for getting info. + Intent intent = mContext.registerReceiver( + null, + new IntentFilter(Intent.ACTION_BATTERY_CHANGED) + ); + if (intent != null && !mHasReceivedBattery) { + onReceive(mContext, intent); + } + } updatePowerSave(); updateEstimate(); } diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java index bc2a55c8d5c4..7561af770298 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java +++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java @@ -139,13 +139,18 @@ public class UsbDebuggingActivity extends AlertActivity if (mDisconnectedReceiver != null) { mBroadcastDispatcher.unregisterReceiver(mDisconnectedReceiver); } + super.onStop(); + } + + @Override + protected void onDestroy() { // If the ADB service has not yet been notified due to this dialog being closed in some // other way then notify the service to deny the connection to ensure system_server sends // a response to adbd. if (!mServiceNotified) { notifyService(false); } - super.onStop(); + super.onDestroy(); } @Override diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml index 9c94b8693b9f..65e5baa7926a 100644 --- a/packages/SystemUI/tests/AndroidManifest.xml +++ b/packages/SystemUI/tests/AndroidManifest.xml @@ -74,6 +74,11 @@ android:excludeFromRecents="true" android:exported="false" /> + <activity android:name="com.android.systemui.controls.management.TestControlsRequestDialog" + android:exported="false" + android:excludeFromRecents="true" + /> + <provider android:name="androidx.lifecycle.ProcessLifecycleOwnerInitializer" tools:replace="android:authorities" diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index 7bc453ac9aa1..9e056cf16ec7 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -211,6 +211,13 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @Test + public void testInitialBatteryLevelRequested() { + mTestableLooper.processAllMessages(); + + assertThat(mKeyguardUpdateMonitor.mBatteryStatus).isNotNull(); + } + + @Test public void testReceiversRegistered() { verify(mBroadcastDispatcher, atLeastOnce()).registerReceiverWithHandler( eq(mKeyguardUpdateMonitor.mBroadcastReceiver), diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java index 95ff98ae620b..f29f04244901 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java +++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java @@ -67,27 +67,35 @@ public class SysuiTestableContext extends TestableContext { @Override public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { - mRegisteredReceivers.add(receiver); + if (receiver != null) { + mRegisteredReceivers.add(receiver); + } return super.registerReceiver(receiver, filter); } @Override public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler) { - mRegisteredReceivers.add(receiver); + if (receiver != null) { + mRegisteredReceivers.add(receiver); + } return super.registerReceiver(receiver, filter, broadcastPermission, scheduler); } @Override public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user, IntentFilter filter, String broadcastPermission, Handler scheduler) { - mRegisteredReceivers.add(receiver); + if (receiver != null) { + mRegisteredReceivers.add(receiver); + } return super.registerReceiverAsUser(receiver, user, filter, broadcastPermission, scheduler); } @Override public void unregisterReceiver(BroadcastReceiver receiver) { - mRegisteredReceivers.remove(receiver); + if (receiver != null) { + mRegisteredReceivers.remove(receiver); + } super.unregisterReceiver(receiver); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestDialogTest.kt new file mode 100644 index 000000000000..0122db6c4965 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestDialogTest.kt @@ -0,0 +1,145 @@ +/* + * 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.controls.management + +import android.app.Dialog +import android.app.PendingIntent +import android.content.ComponentName +import android.content.IIntentSender +import android.content.Intent +import android.os.UserHandle +import android.service.controls.Control +import android.service.controls.ControlsProviderService +import android.service.controls.DeviceTypes +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import androidx.lifecycle.Lifecycle +import androidx.test.filters.MediumTest +import androidx.test.rule.ActivityTestRule +import androidx.test.runner.intercepting.SingleActivityFactory +import com.android.systemui.SysuiTestCase +import com.android.systemui.broadcast.BroadcastDispatcher +import com.android.systemui.controls.controller.ControlInfo +import com.android.systemui.controls.controller.ControlsController +import com.android.systemui.util.mockito.capture +import com.android.systemui.util.mockito.eq +import org.junit.After +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotEquals +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.Captor +import org.mockito.Mock +import org.mockito.Mockito.`when` +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@MediumTest +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper +class ControlsRequestDialogTest : SysuiTestCase() { + + companion object { + private val CONTROL_COMPONENT = ComponentName.unflattenFromString("TEST_PKG/.TEST_CLS")!! + private const val LABEL = "TEST_LABEL" + + private val USER_ID = UserHandle.USER_SYSTEM + private const val CONTROL_ID = "id" + } + + @Mock + private lateinit var controller: ControlsController + + @Mock + private lateinit var listingController: ControlsListingController + @Mock + private lateinit var broadcastDispatcher: BroadcastDispatcher + @Mock + private lateinit var iIntentSender: IIntentSender + @Captor + private lateinit var captor: ArgumentCaptor<ControlInfo> + + @Rule + @JvmField + var activityRule = ActivityTestRule<TestControlsRequestDialog>( + object : SingleActivityFactory<TestControlsRequestDialog>( + TestControlsRequestDialog::class.java + ) { + override fun create(intent: Intent?): TestControlsRequestDialog { + return TestControlsRequestDialog( + controller, + broadcastDispatcher, + listingController + ) + } + }, false, false) + + private lateinit var control: Control + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + + control = Control.StatelessBuilder(CONTROL_ID, PendingIntent(iIntentSender)) + .setTitle("TITLE") + .setSubtitle("SUBTITLE") + .setDeviceType(DeviceTypes.TYPE_LIGHT) + .setStructure("STRUCTURE") + .build() + + val intent = Intent(mContext, TestControlsRequestDialog::class.java) + intent.putExtra(Intent.EXTRA_USER_ID, USER_ID) + intent.putExtra(Intent.EXTRA_COMPONENT_NAME, CONTROL_COMPONENT) + intent.putExtra(ControlsProviderService.EXTRA_CONTROL, control) + + `when`(controller.currentUserId).thenReturn(USER_ID) + `when`(controller.available).thenReturn(true) + `when`(listingController.getAppLabel(CONTROL_COMPONENT)).thenReturn(LABEL) + `when`(controller.getFavoritesForComponent(CONTROL_COMPONENT)).thenReturn(emptyList()) + + activityRule.launchActivity(intent) + } + + @After + fun tearDown() { + activityRule.finishActivity() + } + + @Test + fun testActivityNotFinished() { + assertNotEquals(Lifecycle.State.DESTROYED, + activityRule.getActivity().lifecycle.currentState) + } + + @Test + fun testDialogAddsCorrectControl() { + activityRule.activity.onClick(null, Dialog.BUTTON_POSITIVE) + + verify(controller) + .addFavorite(eq(CONTROL_COMPONENT), eq(control.structure!!), capture(captor)) + + captor.value.let { + assertEquals(control.controlId, it.controlId) + assertEquals(control.title, it.controlTitle) + assertEquals(control.subtitle, it.controlSubtitle) + assertEquals(control.deviceType, it.deviceType) + } + } +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/TestControlsRequestDialog.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/TestControlsRequestDialog.kt new file mode 100644 index 000000000000..3f6308b18d03 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/TestControlsRequestDialog.kt @@ -0,0 +1,26 @@ +/* + * 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.controls.management + +import com.android.systemui.broadcast.BroadcastDispatcher +import com.android.systemui.controls.controller.ControlsController + +class TestControlsRequestDialog( + controller: ControlsController, + dispatcher: BroadcastDispatcher, + listingController: ControlsListingController +) : ControlsRequestDialog(controller, dispatcher, listingController)
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java index f83fbd478bf3..eca48c8c2ee1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java @@ -59,6 +59,11 @@ public class BatteryControllerTest extends SysuiTestCase { } @Test + public void testBatteryInitialized() { + Assert.assertTrue(mBatteryController.mHasReceivedBattery); + } + + @Test public void testIndependentAODBatterySaver_true() { PowerSaveState state = new PowerSaveState.Builder() .setBatterySaverEnabled(true) diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java index df3b6880fdfb..ed83a644cbfb 100644 --- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java +++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java @@ -878,6 +878,7 @@ public class AdbDebuggingManager { case MESSAGE_ADB_DENY: if (mThread != null) { + Slog.w(TAG, "Denying adb confirmation"); mThread.sendResponse("NO"); logAdbConnectionChanged(null, AdbProtoEnums.USER_DENIED, false); } @@ -887,7 +888,7 @@ public class AdbDebuggingManager { String key = (String) msg.obj; if ("trigger_restart_min_framework".equals( SystemProperties.get("vold.decrypt"))) { - Slog.d(TAG, "Deferring adb confirmation until after vold decrypt"); + Slog.w(TAG, "Deferring adb confirmation until after vold decrypt"); if (mThread != null) { mThread.sendResponse("NO"); logAdbConnectionChanged(key, AdbProtoEnums.DENIED_VOLD_DECRYPT, false); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index e77b361c8c06..c9dbacda368c 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -8086,6 +8086,12 @@ public class ActivityManagerService extends IActivityManager.Stub } int checkContentProviderUriPermission(Uri uri, int userId, int callingUid, int modeFlags) { + if (Thread.holdsLock(mActivityTaskManager.getGlobalLock())) { + Slog.wtf(TAG, new IllegalStateException("Unable to check Uri permission" + + " because caller is holding WM lock; assuming permission denied")); + return PackageManager.PERMISSION_DENIED; + } + final String name = uri.getAuthority(); final long ident = Binder.clearCallingIdentity(); ContentProviderHolder holder = null; diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 31712ef85add..b3786212ea72 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -640,13 +640,10 @@ class ActivityStarter { } // If the caller hasn't already resolved the activity, we're willing - // to do so here, but because that may require acquiring the AM lock - // as part of calculating the NeededUriGrants, we must never hold - // the WM lock here to avoid deadlocking. + // to do so here. If the caller is already holding the WM lock here, + // and we need to check dynamic Uri permissions, then we're forced + // to assume those permissions are denied to avoid deadlocking. if (mRequest.activityInfo == null) { - if (Thread.holdsLock(mService.mGlobalLock)) { - Slog.wtf(TAG, new IllegalStateException("Caller must not hold WM lock")); - } mRequest.resolveActivity(mSupervisor); } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index a7b120942163..748244e1a5c2 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -4515,6 +4515,7 @@ class Task extends WindowContainer<WindowContainer> { */ void setMainWindowSizeChangeTransaction(SurfaceControl.Transaction t) { setMainWindowSizeChangeTransaction(t, this); + forAllWindows(WindowState::requestRedrawForSync, true); } private void setMainWindowSizeChangeTransaction(SurfaceControl.Transaction t, Task origin) { diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 708abe28c806..f1acee5031d8 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -339,7 +339,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP private boolean mDragResizing; private boolean mDragResizingChangeReported = true; private int mResizeMode; - private boolean mResizeForBlastSyncReported; + private boolean mRedrawForSyncReported; /** * Special mode that is intended only for the rounded corner overlay: during rotation @@ -1402,7 +1402,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP || configChanged || dragResizingChanged || mReportOrientationChanged - || requestResizeForBlastSync()) { + || shouldSendRedrawForSync()) { ProtoLog.v(WM_DEBUG_RESIZE, "Resize reasons for w=%s: %s surfaceResized=%b configChanged=%b " + "dragResizingChanged=%b reportOrientationChanged=%b", @@ -3564,7 +3564,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mReportOrientationChanged = false; mDragResizingChangeReported = true; mWinAnimator.mSurfaceResized = false; - mResizeForBlastSyncReported = true; mWindowFrames.resetInsetsChanged(); final Rect frame = mWindowFrames.mCompatFrame; @@ -3572,11 +3571,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP final Rect visibleInsets = mWindowFrames.mLastVisibleInsets; final Rect stableInsets = mWindowFrames.mLastStableInsets; final MergedConfiguration mergedConfiguration = mLastReportedConfiguration; - final boolean reportDraw = mWinAnimator.mDrawState == DRAW_PENDING || useBLASTSync(); - final boolean forceRelayout = reportOrientation || isDragResizeChanged(); + final boolean reportDraw = mWinAnimator.mDrawState == DRAW_PENDING || useBLASTSync() || !mRedrawForSyncReported; + final boolean forceRelayout = reportOrientation || isDragResizeChanged() || !mRedrawForSyncReported; final int displayId = getDisplayId(); final DisplayCutout displayCutout = getWmDisplayCutout().getDisplayCutout(); + mRedrawForSyncReported = true; + try { mClient.resized(frame, contentInsets, visibleInsets, stableInsets, reportDraw, mergedConfiguration, getBackdropFrame(frame), forceRelayout, @@ -5823,7 +5824,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP if (!willSync) { return false; } - mResizeForBlastSyncReported = false; + requestRedrawForSync(); mLocalSyncId = mBLASTSyncEngine.startSyncSet(this); addChildrenToSyncSet(mLocalSyncId); @@ -5884,7 +5885,20 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP notifyBlastSyncTransaction(); } - private boolean requestResizeForBlastSync() { - return useBLASTSync() && !mResizeForBlastSyncReported; + /** + * When using the two WindowOrganizer sync-primitives (BoundsChangeTransaction, BLASTSync) + * it can be a little difficult to predict whether your change will actually trigger redrawing + * on the client side. To ease the burden on shell developers, we force send MSG_RESIZED + * for Windows involved in these Syncs + */ + private boolean shouldSendRedrawForSync() { + final Task task = getTask(); + if (task != null && task.getMainWindowSizeChangeTransaction() != null) + return !mRedrawForSyncReported; + return useBLASTSync() && !mRedrawForSyncReported; + } + + void requestRedrawForSync() { + mRedrawForSyncReported = false; } } diff --git a/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java b/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java index 6b194550cc11..67e1b440e28a 100644 --- a/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java +++ b/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java @@ -120,7 +120,7 @@ public class EventSequenceValidator implements ActivityMetricsLaunchObserver { return; } - Log.i(TAG, String.format("Transition from %s to %s", state, State.INTENT_STARTED)); + Log.d(TAG, String.format("Transition from %s to %s", state, State.INTENT_STARTED)); state = State.INTENT_STARTED; } @@ -138,7 +138,7 @@ public class EventSequenceValidator implements ActivityMetricsLaunchObserver { return; } - Log.i(TAG, String.format("Transition from %s to %s", state, State.INTENT_FAILED)); + Log.d(TAG, String.format("Transition from %s to %s", state, State.INTENT_FAILED)); state = State.INTENT_FAILED; } @@ -156,7 +156,7 @@ public class EventSequenceValidator implements ActivityMetricsLaunchObserver { return; } - Log.i(TAG, String.format("Transition from %s to %s", state, State.ACTIVITY_LAUNCHED)); + Log.d(TAG, String.format("Transition from %s to %s", state, State.ACTIVITY_LAUNCHED)); state = State.ACTIVITY_LAUNCHED; } @@ -174,7 +174,7 @@ public class EventSequenceValidator implements ActivityMetricsLaunchObserver { return; } - Log.i(TAG, String.format("Transition from %s to %s", state, State.ACTIVITY_CANCELLED)); + Log.d(TAG, String.format("Transition from %s to %s", state, State.ACTIVITY_CANCELLED)); state = State.ACTIVITY_CANCELLED; } @@ -194,7 +194,7 @@ public class EventSequenceValidator implements ActivityMetricsLaunchObserver { return; } - Log.i(TAG, String.format("Transition from %s to %s", state, State.ACTIVITY_FINISHED)); + Log.d(TAG, String.format("Transition from %s to %s", state, State.ACTIVITY_FINISHED)); state = State.ACTIVITY_FINISHED; } @@ -215,7 +215,7 @@ public class EventSequenceValidator implements ActivityMetricsLaunchObserver { return; } - Log.i(TAG, String.format("Transition from %s to %s", state, State.REPORT_FULLY_DRAWN)); + Log.d(TAG, String.format("Transition from %s to %s", state, State.REPORT_FULLY_DRAWN)); state = State.REPORT_FULLY_DRAWN; } @@ -238,7 +238,7 @@ public class EventSequenceValidator implements ActivityMetricsLaunchObserver { state = State.UNKNOWN; } ++accIntentStartedEvents; - Log.i(TAG, + Log.d(TAG, String.format("inc AccIntentStartedEvents to %d", accIntentStartedEvents)); } @@ -250,7 +250,7 @@ public class EventSequenceValidator implements ActivityMetricsLaunchObserver { state = State.INIT; } --accIntentStartedEvents; - Log.i(TAG, + Log.d(TAG, String.format("dec AccIntentStartedEvents to %d", accIntentStartedEvents)); } @@ -258,6 +258,6 @@ public class EventSequenceValidator implements ActivityMetricsLaunchObserver { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); new Throwable("EventSequenceValidator#getStackTrace").printStackTrace(pw); - Log.w(TAG, String.format("%s\n%s", log, sw)); + Log.d(TAG, String.format("%s\n%s", log, sw)); } } |