From c4a13e9b0bd089ec23c4e6d16ad06182a4b2fdde Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Mon, 29 Jun 2020 20:23:17 +0900 Subject: [PATCH 1/5] Fix Bundle#getParcelableArray call Because Bundle.getParcelableArray() returns Parcelable[] object, simply casting a return value to a typed array will cause ClassCastException. Bug: 158584842 Bug: 160120833 Test: manually install ArcNotificationTest2 and try inline reply Change-Id: Idd8eaa412925ac826590d44a0db297aacef806d8 --- core/java/android/app/Notification.java | 40 ++++++++++++++----------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 0e3f35e358c0a..79d2a8102358a 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -96,9 +96,9 @@ import com.android.internal.util.ContrastColorUtil; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Objects; @@ -1620,7 +1620,7 @@ public class Notification implements Parcelable * of non-textual RemoteInputs do not access these remote inputs. */ public RemoteInput[] getDataOnlyRemoteInputs() { - return (RemoteInput[]) mExtras.getParcelableArray(EXTRA_DATA_ONLY_INPUTS); + return getParcelableArrayFromBundle(mExtras, EXTRA_DATA_ONLY_INPUTS, RemoteInput.class); } /** @@ -1802,8 +1802,8 @@ public class Notification implements Parcelable checkContextualActionNullFields(); ArrayList dataOnlyInputs = new ArrayList<>(); - RemoteInput[] previousDataInputs = - (RemoteInput[]) mExtras.getParcelableArray(EXTRA_DATA_ONLY_INPUTS); + RemoteInput[] previousDataInputs = getParcelableArrayFromBundle( + mExtras, EXTRA_DATA_ONLY_INPUTS, RemoteInput.class); if (previousDataInputs != null) { for (RemoteInput input : previousDataInputs) { dataOnlyInputs.add(input); @@ -5368,8 +5368,8 @@ public class Notification implements Parcelable big.setViewVisibility(R.id.actions_container, View.GONE); } - RemoteInputHistoryItem[] replyText = (RemoteInputHistoryItem[]) - mN.extras.getParcelableArray(EXTRA_REMOTE_INPUT_HISTORY_ITEMS); + RemoteInputHistoryItem[] replyText = getParcelableArrayFromBundle( + mN.extras, EXTRA_REMOTE_INPUT_HISTORY_ITEMS, RemoteInputHistoryItem.class); if (validRemoteInput && replyText != null && replyText.length > 0 && !TextUtils.isEmpty(replyText[0].getText()) && p.maxRemoteInputHistory > 0) { @@ -8155,8 +8155,9 @@ public class Notification implements Parcelable if (mBuilder.mActions.size() > 0) { maxRows--; } - RemoteInputHistoryItem[] remoteInputHistory = (RemoteInputHistoryItem[]) - mBuilder.mN.extras.getParcelableArray(EXTRA_REMOTE_INPUT_HISTORY_ITEMS); + RemoteInputHistoryItem[] remoteInputHistory = getParcelableArrayFromBundle( + mBuilder.mN.extras, EXTRA_REMOTE_INPUT_HISTORY_ITEMS, + RemoteInputHistoryItem.class); if (remoteInputHistory != null && remoteInputHistory.length > NUMBER_OF_HISTORY_ALLOWED_UNTIL_REDUCTION) { // Let's remove some messages to make room for the remote input history. @@ -9579,8 +9580,8 @@ public class Notification implements Parcelable mFlags = wearableBundle.getInt(KEY_FLAGS, DEFAULT_FLAGS); mDisplayIntent = wearableBundle.getParcelable(KEY_DISPLAY_INTENT); - Notification[] pages = getNotificationArrayFromBundle( - wearableBundle, KEY_PAGES); + Notification[] pages = getParcelableArrayFromBundle( + wearableBundle, KEY_PAGES, Notification.class); if (pages != null) { Collections.addAll(mPages, pages); } @@ -10838,17 +10839,22 @@ public class Notification implements Parcelable } /** - * Get an array of Notification objects from a parcelable array bundle field. + * Get an array of Parcelable objects from a parcelable array bundle field. * Update the bundle to have a typed array so fetches in the future don't need * to do an array copy. */ - private static Notification[] getNotificationArrayFromBundle(Bundle bundle, String key) { - Parcelable[] array = bundle.getParcelableArray(key); - if (array instanceof Notification[] || array == null) { - return (Notification[]) array; + @Nullable + private static T[] getParcelableArrayFromBundle( + Bundle bundle, String key, Class itemClass) { + final Parcelable[] array = bundle.getParcelableArray(key); + final Class arrayClass = Array.newInstance(itemClass, 0).getClass(); + if (arrayClass.isInstance(array) || array == null) { + return (T[]) array; + } + final T[] typedArray = (T[]) Array.newInstance(itemClass, array.length); + for (int i = 0; i < array.length; i++) { + typedArray[i] = (T) array[i]; } - Notification[] typedArray = Arrays.copyOf(array, array.length, - Notification[].class); bundle.putParcelableArray(key, typedArray); return typedArray; } From 626e4c54a2af041d5ef0fe7234f578d193eb7847 Mon Sep 17 00:00:00 2001 From: Tim Peng Date: Wed, 1 Jul 2020 16:29:37 +0800 Subject: [PATCH 2/5] Unable to show correct device icon in Output Switcher -Media framework does not report "TYPE_GROUP" when selecting a group of Chromecast devices or the StaticGroup -MediaRouter2Info::getType() does not provide correct types for group and video -Add "getDrawableResIdByFeature()" to get correct type icon -Use MediaRouter2Info::getFeatures() to get device type -Designer updates the video icon Bug: 160113560 Test: make -j50 RunSettingsLibRoboTests Change-Id: I1c8e9c2729013b9ee49b664e40c04550f315a516 --- .../res/drawable/ic_media_display_device.xml | 16 ++++------ .../settingslib/media/InfoMediaDevice.java | 21 +++++++++++++- .../media/InfoMediaDeviceTest.java | 29 +++++++++++++++++++ 3 files changed, 55 insertions(+), 11 deletions(-) diff --git a/packages/SettingsLib/res/drawable/ic_media_display_device.xml b/packages/SettingsLib/res/drawable/ic_media_display_device.xml index 78b4e2a23d45a..54fec782c7d12 100644 --- a/packages/SettingsLib/res/drawable/ic_media_display_device.xml +++ b/packages/SettingsLib/res/drawable/ic_media_display_device.xml @@ -15,16 +15,12 @@ limitations under the License. --> + android:width="18dp" + android:height="18dp" + android:viewportWidth="18" + android:viewportHeight="18"> \ No newline at end of file diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java index ea71e52dc9c97..949b2456042cd 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java @@ -15,6 +15,8 @@ */ package com.android.settingslib.media; +import static android.media.MediaRoute2Info.FEATURE_REMOTE_GROUP_PLAYBACK; +import static android.media.MediaRoute2Info.FEATURE_REMOTE_VIDEO_PLAYBACK; import static android.media.MediaRoute2Info.TYPE_GROUP; import static android.media.MediaRoute2Info.TYPE_REMOTE_SPEAKER; import static android.media.MediaRoute2Info.TYPE_REMOTE_TV; @@ -29,6 +31,8 @@ import androidx.annotation.VisibleForTesting; import com.android.settingslib.R; import com.android.settingslib.bluetooth.BluetoothUtils; +import java.util.List; + /** * InfoMediaDevice extends MediaDevice to represents wifi device. */ @@ -62,7 +66,7 @@ public class InfoMediaDevice extends MediaDevice { @Override public Drawable getIconWithoutBackground() { - return mContext.getDrawable(getDrawableResId()); + return mContext.getDrawable(getDrawableResIdByFeature()); } @VisibleForTesting @@ -83,6 +87,21 @@ public class InfoMediaDevice extends MediaDevice { return resId; } + @VisibleForTesting + int getDrawableResIdByFeature() { + int resId; + final List features = mRouteInfo.getFeatures(); + if (features.contains(FEATURE_REMOTE_GROUP_PLAYBACK)) { + resId = R.drawable.ic_media_group_device; + } else if (features.contains(FEATURE_REMOTE_VIDEO_PLAYBACK)) { + resId = R.drawable.ic_media_display_device; + } else { + resId = R.drawable.ic_media_speaker_device; + } + + return resId; + } + @Override public String getId() { return MediaDeviceUtils.getId(mRouteInfo); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java index 49b236a2188f4..c45b7f333fa1a 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java @@ -16,6 +16,9 @@ package com.android.settingslib.media; +import static android.media.MediaRoute2Info.FEATURE_REMOTE_AUDIO_PLAYBACK; +import static android.media.MediaRoute2Info.FEATURE_REMOTE_GROUP_PLAYBACK; +import static android.media.MediaRoute2Info.FEATURE_REMOTE_VIDEO_PLAYBACK; import static android.media.MediaRoute2Info.TYPE_GROUP; import static android.media.MediaRoute2Info.TYPE_REMOTE_SPEAKER; import static android.media.MediaRoute2Info.TYPE_REMOTE_TV; @@ -38,6 +41,8 @@ import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; +import java.util.ArrayList; + @RunWith(RobolectricTestRunner.class) public class InfoMediaDeviceTest { @@ -107,4 +112,28 @@ public class InfoMediaDeviceTest { assertThat(mInfoMediaDevice.getDrawableResId()).isEqualTo(R.drawable.ic_media_group_device); } + + @Test + public void getDrawableResIdByFeature_returnCorrectResId() { + final ArrayList features = new ArrayList<>(); + features.add(FEATURE_REMOTE_VIDEO_PLAYBACK); + when(mRouteInfo.getFeatures()).thenReturn(features); + + assertThat(mInfoMediaDevice.getDrawableResIdByFeature()).isEqualTo( + R.drawable.ic_media_display_device); + + features.clear(); + features.add(FEATURE_REMOTE_AUDIO_PLAYBACK); + when(mRouteInfo.getFeatures()).thenReturn(features); + + assertThat(mInfoMediaDevice.getDrawableResIdByFeature()).isEqualTo( + R.drawable.ic_media_speaker_device); + + features.clear(); + features.add(FEATURE_REMOTE_GROUP_PLAYBACK); + when(mRouteInfo.getFeatures()).thenReturn(features); + + assertThat(mInfoMediaDevice.getDrawableResIdByFeature()).isEqualTo( + R.drawable.ic_media_group_device); + } } From 35ff45dab416e93d99b4d1b21f0a2d39baaa3b56 Mon Sep 17 00:00:00 2001 From: Ming-Shin Lu Date: Thu, 2 Jul 2020 15:40:31 +0800 Subject: [PATCH 3/5] Fix Keyboard stays on while startSeamlessRotation InsetsSourceProvider#startSemlessRotation will be called and cancel on-going insets animation to revoke the insets control. The idea is preventing the frame of insets animation will be drawn while the rotation is not yet stable, and re-apply the revoked control again once the rotation finished. However, since the IME insets control / control target / leash has been cleared after animation cancelled, there is no way to update the revoked IME control target again, and also cannot have a direct signal to request visible for client side after finished rotation, that will casue IME surface stays on and client can't control the IME inets visiblity. As the issue case which seamless rotation happens during launch fixed portrait rotation app from launcher in landscape mode, since seamless rotation animation doesn't well support the target window which controlled IME insets is animating, we should skip seamless rotation for this case. Fix: 158924696 Test: manual as below steps: 1. Enable "Allow Home screen rotation" from Launcher -> Home Settings and "Auto-rotate" from quick settings. 2. Open Snapchat in portrait > open a conversation > open keyboard. 3. Tap Home button > rotate device from portrait to landscape. 4. Tap Snapchat icon in landscape > the keyboard is automatically displayed 5. Tap the back key in the lower left corner of the device. 6. Expect keyboard should hide after the back key pressed. Change-Id: I7d4685a0b85ec3db9b7e1c266030817da3dde812 --- services/core/java/com/android/server/wm/WindowState.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index f1acee5031d87..47e0355671522 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -26,6 +26,7 @@ import static android.app.WindowConfiguration.isSplitScreenWindowingMode; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.os.PowerManager.DRAW_WAKE_LOCK; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; +import static android.view.InsetsState.ITYPE_IME; import static android.view.SurfaceControl.Transaction; import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; @@ -756,6 +757,12 @@ class WindowState extends WindowContainer implements WindowManagerP oldRotation = mPendingSeamlessRotate.getOldRotation(); } + // Skip performing seamless rotation when the controlled insets is IME with visible state. + if (mControllableInsetProvider != null + && mControllableInsetProvider.getSource().getType() == ITYPE_IME) { + return; + } + if (mForceSeamlesslyRotate || requested) { if (mControllableInsetProvider != null) { mControllableInsetProvider.startSeamlessRotation(); From fc0cdd85265a1a2c1466502172c8db3a05eee517 Mon Sep 17 00:00:00 2001 From: Louis Chang Date: Fri, 3 Jul 2020 10:54:40 +0800 Subject: [PATCH 4/5] Do not count AOD showing changes as keyguard's AOD status changed after keyguard was set as going away, which reset mKeyguardGoingAway back to false and put activities to sleep. Bug: 158640144 Test: Unlock keyguard during AOD2 Change-Id: I9335045668f90d477d19dada0185447bfa3cb2a7 --- .../java/com/android/server/wm/KeyguardController.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java index 4c10d5819c104..9c535e4a41d7e 100644 --- a/services/core/java/com/android/server/wm/KeyguardController.java +++ b/services/core/java/com/android/server/wm/KeyguardController.java @@ -133,10 +133,11 @@ class KeyguardController { * Update the Keyguard showing state. */ void setKeyguardShown(boolean keyguardShowing, boolean aodShowing) { - // If keyguard is going away, but SystemUI aborted the transition, need to reset state. - final boolean keyguardChanged = keyguardShowing != mKeyguardShowing - || mKeyguardGoingAway && keyguardShowing; final boolean aodChanged = aodShowing != mAodShowing; + // If keyguard is going away, but SystemUI aborted the transition, need to reset state. + // Do not reset keyguardChanged status if this is aodChanged. + final boolean keyguardChanged = (keyguardShowing != mKeyguardShowing) + || (mKeyguardGoingAway && keyguardShowing && !aodChanged); if (!keyguardChanged && !aodChanged) { return; } From 52853711c603e305f1d93630625d328b0e45278b Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Fri, 3 Jul 2020 14:51:11 -0700 Subject: [PATCH 5/5] Import translations. DO NOT MERGE Auto-generated-cl: translation import Change-Id: Ib1619e9a7013c7564dd9431f15d9cc49720eb6e9 --- packages/SettingsLib/res/values-es-rUS/strings.xml | 2 +- packages/SettingsLib/res/values-gl/strings.xml | 2 +- packages/SettingsLib/res/values-mn/strings.xml | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml index c27973f8bc86f..287a1aca2fbd2 100644 --- a/packages/SettingsLib/res/values-es-rUS/strings.xml +++ b/packages/SettingsLib/res/values-es-rUS/strings.xml @@ -22,7 +22,7 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "No se pueden buscar las redes." "Ninguna" - "Guardada" + "Guardado" "Desconectado" "Inhabilitada" "Error de configuración IP" diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml index 3e8b1c1b9cde1..f9d57c453f696 100644 --- a/packages/SettingsLib/res/values-gl/strings.xml +++ b/packages/SettingsLib/res/values-gl/strings.xml @@ -37,7 +37,7 @@ "Sen acceso a Internet" "Gardada por %1$s" "Conectouse automaticamente a través de %1$s" - "Conectada automaticamente a través dun provedor de valoración de rede" + "Conectada automaticamente a través dun provedor de valoración de redes" "Conectado a través de %1$s" "Wifi conectada a través de %1$s" "Dispoñible a través de %1$s" diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml index 08cf5f9fd5a98..8407db6d3a087 100644 --- a/packages/SettingsLib/res/values-mn/strings.xml +++ b/packages/SettingsLib/res/values-mn/strings.xml @@ -211,8 +211,8 @@ "Алдаа" "Wireless debugging" "Боломжтой төхөөрөмжүүдийг харах болох ашиглахын тулд wireless debugging-г асаана уу" - "Хурдан хариу үйлдлийн кодоор төхөөрөмжийг хослуул" - "Хурдан хариу үйлдлийн кодын сканнер ашиглан шинэ төхөөрөмжүүдийг хослуулна уу" + "QR кодоор төхөөрөмжийг хослуул" + "QR кодын сканнер ашиглан шинэ төхөөрөмжүүдийг хослуулна уу" "Хослуулах кодоор төхөөрөмжийг хослуулна уу" "Зургаан оронтой кодыг ашиглан шинэ төхөөрөмжүүдийг хослуулна уу" "Хослуулсан төхөөрөмжүүд" @@ -226,12 +226,12 @@ "Wi‑Fi хослуулах код" "Хослуулалт амжилтгүй боллоо" "Төхөөрөмжийг ижил сүлжээнд холбосон эсэхийг шалгана уу." - "Хурдан хариу үйлдлийн кодыг скан хийж Wi-Fi-р төхөөрөмжийг хослуулна уу" + "QR кодыг скан хийж Wi-Fi-р төхөөрөмжийг хослуулна уу" "Төхөөрөмжийг хослуулж байна…" - "Төхөөрөмжийг хослуулж чадсангүй. Хурдан хариу үйлдлийн код буруу эсвэл төхөөрөмжийг ижил сүлжээнд холбоогүй байна." + "Төхөөрөмжийг хослуулж чадсангүй. QR код буруу эсвэл төхөөрөмжийг ижил сүлжээнд холбоогүй байна." "IP хаяг ба порт" - "Хурдан хариу үйлдлийн кодыг скан хийх" - "Хурдан хариу үйлдлийн кодыг скан хийж Wi-Fi-р төхөөрөмжийг хослуулна уу" + "QR кодыг скан хийх" + "QR кодыг скан хийж Wi-Fi-р төхөөрөмжийг хослуулна уу" "Wi-Fi сүлжээнд холбогдоно уу" "adb, дебаг хийх, dev" "Алдаа мэдээлэх товчлол"