summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/content/ClipboardManager.java19
-rw-r--r--core/java/android/content/IClipboard.aidl17
-rw-r--r--core/java/android/content/res/ResourcesImpl.java7
-rw-r--r--core/java/android/os/storage/StorageManagerInternal.java8
-rw-r--r--core/java/android/preference/SeekBarVolumizer.java2
-rw-r--r--core/java/android/provider/MediaStore.java2
-rw-r--r--core/java/android/provider/Settings.java15
-rw-r--r--core/java/android/service/contentcapture/ContentCaptureService.java4
-rw-r--r--core/java/android/service/notification/Adjustment.java14
-rw-r--r--core/java/android/service/notification/NotificationAssistantService.java9
-rw-r--r--core/java/android/service/wallpaper/Android.bp12
-rw-r--r--core/java/android/service/wallpaper/AndroidManifest.xml22
-rw-r--r--core/java/android/widget/TextView.java31
-rw-r--r--core/res/res/values/strings.xml2
-rw-r--r--core/tests/bugreports/src/android/server/bugreports/BugreportManagerTest.java12
-rw-r--r--libs/androidfw/AssetManager2.cpp2
-rw-r--r--media/java/android/media/AudioAttributes.java10
-rw-r--r--media/java/android/media/audiopolicy/AudioMix.java57
-rw-r--r--media/java/android/media/audiopolicy/AudioMixingRule.java4
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java6
-rw-r--r--packages/DynamicSystemInstallationService/src/com/android/dynsystem/BootCompletedReceiver.java25
-rw-r--r--packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java2
-rw-r--r--packages/ExtServices/src/android/ext/services/notification/Assistant.java12
-rw-r--r--packages/SettingsProvider/res/values/defaults.xml3
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java21
-rw-r--r--packages/SystemUI/res/drawable-night/status_bar_notification_section_header_clear_btn.xml25
-rw-r--r--packages/SystemUI/res/drawable/status_bar_notification_section_header_clear_btn.xml2
-rw-r--r--packages/SystemUI/res/layout/bubble_expanded_view.xml5
-rw-r--r--packages/SystemUI/res/layout/contaminant_dialog.xml87
-rw-r--r--packages/SystemUI/res/layout/status_bar_notification_section_header.xml1
-rw-r--r--packages/SystemUI/res/values-night/colors.xml1
-rw-r--r--packages/SystemUI/res/values/colors.xml1
-rw-r--r--packages/SystemUI/res/values/dimens.xml2
-rw-r--r--packages/SystemUI/res/values/strings.xml5
-rw-r--r--packages/SystemUI/res/values/styles.xml18
-rw-r--r--packages/SystemUI/src/com/android/systemui/ImageWallpaper.java220
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java230
-rw-r--r--packages/SystemUI/src/com/android/systemui/glwallpaper/GLWallpaperRenderer.java87
-rw-r--r--packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java72
-rw-r--r--packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java116
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/UsbContaminantActivity.java50
-rw-r--r--proto/src/metrics_constants/metrics_constants.proto3
-rw-r--r--services/core/java/com/android/server/DynamicSystemService.java13
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java64
-rw-r--r--services/core/java/com/android/server/SystemServerInitThreadPool.java3
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java13
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java82
-rw-r--r--services/core/java/com/android/server/clipboard/ClipboardService.java239
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java3
-rw-r--r--services/core/java/com/android/server/notification/NotificationRecord.java24
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java2
-rw-r--r--services/core/java/com/android/server/pm/permission/TEST_MAPPING17
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java31
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java8
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java85
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java14
-rw-r--r--telecomm/java/android/telecom/ConnectionService.java4
-rw-r--r--telecomm/java/android/telecom/ConnectionServiceAdapter.java4
-rw-r--r--telecomm/java/android/telecom/ConnectionServiceAdapterServant.java14
-rw-r--r--telecomm/java/android/telecom/RemoteConnectionService.java2
-rw-r--r--telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl3
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java34
-rw-r--r--telephony/java/android/telephony/ims/ImsSsInfo.java4
75 files changed, 1547 insertions, 472 deletions
diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java
index 8760efeafd8c..dc1c700f5d08 100644
--- a/core/java/android/content/ClipboardManager.java
+++ b/core/java/android/content/ClipboardManager.java
@@ -103,7 +103,7 @@ public class ClipboardManager extends android.text.ClipboardManager {
try {
Preconditions.checkNotNull(clip);
clip.prepareToLeaveProcess(true);
- mService.setPrimaryClip(clip, mContext.getOpPackageName());
+ mService.setPrimaryClip(clip, mContext.getOpPackageName(), mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -116,7 +116,7 @@ public class ClipboardManager extends android.text.ClipboardManager {
*/
public void clearPrimaryClip() {
try {
- mService.clearPrimaryClip(mContext.getOpPackageName());
+ mService.clearPrimaryClip(mContext.getOpPackageName(), mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -132,7 +132,7 @@ public class ClipboardManager extends android.text.ClipboardManager {
*/
public @Nullable ClipData getPrimaryClip() {
try {
- return mService.getPrimaryClip(mContext.getOpPackageName());
+ return mService.getPrimaryClip(mContext.getOpPackageName(), mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -149,7 +149,8 @@ public class ClipboardManager extends android.text.ClipboardManager {
*/
public @Nullable ClipDescription getPrimaryClipDescription() {
try {
- return mService.getPrimaryClipDescription(mContext.getOpPackageName());
+ return mService.getPrimaryClipDescription(mContext.getOpPackageName(),
+ mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -163,7 +164,7 @@ public class ClipboardManager extends android.text.ClipboardManager {
*/
public boolean hasPrimaryClip() {
try {
- return mService.hasPrimaryClip(mContext.getOpPackageName());
+ return mService.hasPrimaryClip(mContext.getOpPackageName(), mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -174,7 +175,8 @@ public class ClipboardManager extends android.text.ClipboardManager {
if (mPrimaryClipChangedListeners.isEmpty()) {
try {
mService.addPrimaryClipChangedListener(
- mPrimaryClipChangedServiceListener, mContext.getOpPackageName());
+ mPrimaryClipChangedServiceListener, mContext.getOpPackageName(),
+ mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -189,7 +191,8 @@ public class ClipboardManager extends android.text.ClipboardManager {
if (mPrimaryClipChangedListeners.isEmpty()) {
try {
mService.removePrimaryClipChangedListener(
- mPrimaryClipChangedServiceListener);
+ mPrimaryClipChangedServiceListener, mContext.getOpPackageName(),
+ mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -226,7 +229,7 @@ public class ClipboardManager extends android.text.ClipboardManager {
@Deprecated
public boolean hasText() {
try {
- return mService.hasClipboardText(mContext.getOpPackageName());
+ return mService.hasClipboardText(mContext.getOpPackageName(), mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/content/IClipboard.aidl b/core/java/android/content/IClipboard.aidl
index 135a4363ef21..0d5a46016f19 100644
--- a/core/java/android/content/IClipboard.aidl
+++ b/core/java/android/content/IClipboard.aidl
@@ -26,17 +26,18 @@ import android.content.IOnPrimaryClipChangedListener;
* {@hide}
*/
interface IClipboard {
- void setPrimaryClip(in ClipData clip, String callingPackage);
- void clearPrimaryClip(String callingPackage);
- ClipData getPrimaryClip(String pkg);
- ClipDescription getPrimaryClipDescription(String callingPackage);
- boolean hasPrimaryClip(String callingPackage);
+ void setPrimaryClip(in ClipData clip, String callingPackage, int userId);
+ void clearPrimaryClip(String callingPackage, int userId);
+ ClipData getPrimaryClip(String pkg, int userId);
+ ClipDescription getPrimaryClipDescription(String callingPackage, int userId);
+ boolean hasPrimaryClip(String callingPackage, int userId);
void addPrimaryClipChangedListener(in IOnPrimaryClipChangedListener listener,
- String callingPackage);
- void removePrimaryClipChangedListener(in IOnPrimaryClipChangedListener listener);
+ String callingPackage, int userId);
+ void removePrimaryClipChangedListener(in IOnPrimaryClipChangedListener listener,
+ String callingPackage, int userId);
/**
* Returns true if the clipboard contains text; false otherwise.
*/
- boolean hasClipboardText(String callingPackage);
+ boolean hasClipboardText(String callingPackage, int userId);
}
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 633966c38786..794be9e202be 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -1390,11 +1390,9 @@ public class ResourcesImpl {
@StyleableRes int[] attrs,
@AttrRes int defStyleAttr,
@StyleRes int defStyleRes) {
- Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "obtainStyledAttributes");
- TypedArray array;
synchronized (mKey) {
final int len = attrs.length;
- array = TypedArray.obtain(wrapper.getResources(), len);
+ final TypedArray array = TypedArray.obtain(wrapper.getResources(), len);
// XXX note that for now we only work with compiled XML files.
// To support generic XML files we will need to manually parse
@@ -1405,9 +1403,8 @@ public class ResourcesImpl {
array.mDataAddress, array.mIndicesAddress);
array.mTheme = wrapper;
array.mXml = parser;
+ return array;
}
- Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
- return array;
}
@NonNull
diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java
index 942bf94b1db6..14c299d11a94 100644
--- a/core/java/android/os/storage/StorageManagerInternal.java
+++ b/core/java/android/os/storage/StorageManagerInternal.java
@@ -16,6 +16,7 @@
package android.os.storage;
+import android.annotation.Nullable;
import android.os.IVold;
/**
@@ -101,4 +102,11 @@ public abstract class StorageManagerInternal {
* @param listener The listener that will be notified on reset events.
*/
public abstract void addResetListener(ResetListener listener);
+
+ /**
+ * Notified when any app op changes so that storage mount points can be updated if the app op
+ * affects them.
+ */
+ public abstract void onAppOpsChanged(int code, int uid,
+ @Nullable String packageName, int mode);
}
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index 02f99258395c..2b3a2ab05e82 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -591,7 +591,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
private void registerVolumeGroupCb() {
if (mVolumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) {
mAudioManager.registerVolumeGroupCallback(Runnable::run, mVolumeGroupCallback);
- mLastProgress = mAudioManager.getVolumeIndexForAttributes(mAttributes);
+ updateSlider();
}
}
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 23937d6c85a6..2a590ce5a65e 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -1077,7 +1077,7 @@ public final class MediaStore {
* Relative path of this media item within the storage device where it
* is persisted. For example, an item stored at
* {@code /storage/0000-0000/DCIM/Vacation/IMG1024.JPG} would have a
- * path of {@code DCIM/Vacation}.
+ * path of {@code DCIM/Vacation/}.
* <p>
* This value should only be used for organizational purposes, and you
* should not attempt to construct or access a raw filesystem path using
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 185d4a219556..8096eb110a1c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8836,6 +8836,15 @@ public final class Settings {
public static final String AWARE_ENABLED = "aware_enabled";
private static final Validator AWARE_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
+ /**
+ * Controls whether aware_lock is enabled.
+ * @hide
+ */
+ public static final String AWARE_LOCK_ENABLED = "aware_lock_enabled";
+
+ private static final Validator AWARE_LOCK_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
/**
* This are the settings to be backed up.
*
@@ -8970,7 +8979,8 @@ public final class Settings {
SILENCE_CALL_GESTURE_COUNT,
SILENCE_TIMER_GESTURE_COUNT,
DARK_MODE_DIALOG_SEEN,
- GLOBAL_ACTIONS_PANEL_ENABLED
+ GLOBAL_ACTIONS_PANEL_ENABLED,
+ AWARE_LOCK_ENABLED
};
/**
@@ -9157,6 +9167,7 @@ public final class Settings {
VALIDATORS.put(DARK_MODE_DIALOG_SEEN, BOOLEAN_VALIDATOR);
VALIDATORS.put(UI_NIGHT_MODE, UI_NIGHT_MODE_VALIDATOR);
VALIDATORS.put(GLOBAL_ACTIONS_PANEL_ENABLED, GLOBAL_ACTIONS_PANEL_ENABLED_VALIDATOR);
+ VALIDATORS.put(AWARE_LOCK_ENABLED, AWARE_LOCK_ENABLED_VALIDATOR);
}
/**
@@ -15382,4 +15393,4 @@ public final class Settings {
}
return packages[0];
}
-}
+} \ No newline at end of file
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index 08d9733ac815..397a6cdf3bee 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -162,7 +162,7 @@ public abstract class ContentCaptureService extends Service {
@Override
public void onDataRemovalRequest(DataRemovalRequest request) {
mHandler.sendMessage(
- obtainMessage(ContentCaptureService::handleOnUserDataRemovalRequest,
+ obtainMessage(ContentCaptureService::handleOnDataRemovalRequest,
ContentCaptureService.this, request));
}
@@ -503,7 +503,7 @@ public abstract class ContentCaptureService extends Service {
onDestroyContentCaptureSession(new ContentCaptureSessionId(sessionId));
}
- private void handleOnUserDataRemovalRequest(@NonNull DataRemovalRequest request) {
+ private void handleOnDataRemovalRequest(@NonNull DataRemovalRequest request) {
onDataRemovalRequest(request);
}
diff --git a/core/java/android/service/notification/Adjustment.java b/core/java/android/service/notification/Adjustment.java
index e81ce7f85ac1..aa11445079cd 100644
--- a/core/java/android/service/notification/Adjustment.java
+++ b/core/java/android/service/notification/Adjustment.java
@@ -16,6 +16,7 @@
package android.service.notification;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.StringDef;
import android.annotation.SystemApi;
import android.annotation.TestApi;
@@ -48,6 +49,7 @@ public final class Adjustment implements Parcelable {
private final CharSequence mExplanation;
private final Bundle mSignals;
private final int mUser;
+ @Nullable private String mIssuer;
/** @hide */
@StringDef (prefix = { "KEY_" }, value = {
@@ -183,6 +185,7 @@ public final class Adjustment implements Parcelable {
}
mSignals = in.readBundle();
mUser = in.readInt();
+ mIssuer = in.readString();
}
public static final @android.annotation.NonNull Creator<Adjustment> CREATOR = new Creator<Adjustment>() {
@@ -251,6 +254,7 @@ public final class Adjustment implements Parcelable {
}
dest.writeBundle(mSignals);
dest.writeInt(mUser);
+ dest.writeString(mIssuer);
}
@Override
@@ -259,4 +263,14 @@ public final class Adjustment implements Parcelable {
+ "mSignals=" + mSignals
+ '}';
}
+
+ /** @hide */
+ public void setIssuer(@Nullable String issuer) {
+ mIssuer = issuer;
+ }
+
+ /** @hide */
+ public @Nullable String getIssuer() {
+ return mIssuer;
+ }
}
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index cafeb87691bd..3699156d1550 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -236,6 +236,7 @@ public abstract class NotificationAssistantService extends NotificationListenerS
public final void adjustNotification(@NonNull Adjustment adjustment) {
if (!isBound()) return;
try {
+ setAdjustmentIssuer(adjustment);
getNotificationInterface().applyEnqueuedAdjustmentFromAssistant(mWrapper, adjustment);
} catch (android.os.RemoteException ex) {
Log.v(TAG, "Unable to contact notification manager", ex);
@@ -253,6 +254,9 @@ public abstract class NotificationAssistantService extends NotificationListenerS
public final void adjustNotifications(@NonNull List<Adjustment> adjustments) {
if (!isBound()) return;
try {
+ for (Adjustment adjustment : adjustments) {
+ setAdjustmentIssuer(adjustment);
+ }
getNotificationInterface().applyAdjustmentsFromAssistant(mWrapper, adjustments);
} catch (android.os.RemoteException ex) {
Log.v(TAG, "Unable to contact notification manager", ex);
@@ -366,6 +370,10 @@ public abstract class NotificationAssistantService extends NotificationListenerS
}
}
+ private void setAdjustmentIssuer(Adjustment adjustment) {
+ adjustment.setIssuer(getOpPackageName() + "/" + getClass().getName());
+ }
+
private final class MyHandler extends Handler {
public static final int MSG_ON_NOTIFICATION_ENQUEUED = 1;
public static final int MSG_ON_NOTIFICATION_SNOOZED = 2;
@@ -389,6 +397,7 @@ public abstract class NotificationAssistantService extends NotificationListenerS
NotificationChannel channel = (NotificationChannel) args.arg2;
args.recycle();
Adjustment adjustment = onNotificationEnqueued(sbn, channel);
+ setAdjustmentIssuer(adjustment);
if (adjustment != null) {
if (!isBound()) {
Log.w(TAG, "MSG_ON_NOTIFICATION_ENQUEUED: service not bound, skip.");
diff --git a/core/java/android/service/wallpaper/Android.bp b/core/java/android/service/wallpaper/Android.bp
new file mode 100644
index 000000000000..aa6123f5a983
--- /dev/null
+++ b/core/java/android/service/wallpaper/Android.bp
@@ -0,0 +1,12 @@
+android_library {
+
+ name: "WallpaperSharedLib",
+ srcs: [
+ "*.java",
+ "I*.aidl",
+ ],
+
+ // Enforce that the library is built against java 8 so that there are
+ // no compatibility issues with launcher
+ java_version: "1.8",
+}
diff --git a/core/java/android/service/wallpaper/AndroidManifest.xml b/core/java/android/service/wallpaper/AndroidManifest.xml
new file mode 100644
index 000000000000..f1bdb76409fb
--- /dev/null
+++ b/core/java/android/service/wallpaper/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.service.wallpaper">
+
+ <uses-sdk android:minSdkVersion="29" />
+</manifest>
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 17c56c3f216a..a9e183ad5bf2 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -11244,13 +11244,23 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Nullable
final TextServicesManager getTextServicesManagerForUser() {
+ return getServiceManagerForUser("android", TextServicesManager.class);
+ }
+
+ @Nullable
+ final ClipboardManager getClipboardManagerForUser() {
+ return getServiceManagerForUser(getContext().getPackageName(), ClipboardManager.class);
+ }
+
+ @Nullable
+ final <T> T getServiceManagerForUser(String packageName, Class<T> managerClazz) {
if (mTextOperationUser == null) {
- return getContext().getSystemService(TextServicesManager.class);
+ return getContext().getSystemService(managerClazz);
}
try {
- return getContext().createPackageContextAsUser(
- "android", 0 /* flags */, mTextOperationUser)
- .getSystemService(TextServicesManager.class);
+ Context context = getContext().createPackageContextAsUser(
+ packageName, 0 /* flags */, mTextOperationUser);
+ return context.getSystemService(managerClazz);
} catch (PackageManager.NameNotFoundException e) {
return null;
}
@@ -12540,8 +12550,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
&& mEditor != null && mEditor.mKeyListener != null
&& getSelectionStart() >= 0
&& getSelectionEnd() >= 0
- && ((ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE))
- .hasPrimaryClip());
+ && getClipboardManagerForUser().hasPrimaryClip());
}
boolean canPasteAsPlainText() {
@@ -12549,9 +12558,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return false;
}
- final ClipData clipData =
- ((ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE))
- .getPrimaryClip();
+ final ClipData clipData = getClipboardManagerForUser().getPrimaryClip();
final ClipDescription description = clipData.getDescription();
final boolean isPlainType = description.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN);
final CharSequence text = clipData.getItemAt(0).getText();
@@ -12594,8 +12601,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* Paste clipboard content between min and max positions.
*/
private void paste(int min, int max, boolean withFormatting) {
- ClipboardManager clipboard =
- (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
+ ClipboardManager clipboard = getClipboardManagerForUser();
ClipData clip = clipboard.getPrimaryClip();
if (clip != null) {
boolean didFirst = false;
@@ -12638,8 +12644,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@CheckResult
private boolean setPrimaryClip(ClipData clip) {
- ClipboardManager clipboard =
- (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
+ ClipboardManager clipboard = getClipboardManagerForUser();
try {
clipboard.setPrimaryClip(clip);
} catch (Throwable t) {
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 37678dd42512..5b917cc4fdf1 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3614,7 +3614,7 @@
<!-- Message of notification shown when contaminant is detected on the USB port. [CHAR LIMIT=NONE] -->
<string name="usb_contaminant_detected_message">USB port is automatically disabled. Tap to learn more.</string>
<!-- Title of notification shown when contaminant is no longer detected on the USB port. [CHAR LIMIT=NONE] -->
- <string name="usb_contaminant_not_detected_title">Safe to use USB port</string>
+ <string name="usb_contaminant_not_detected_title">OK to use USB port</string>
<!-- Message of notification shown when contaminant is no longer detected on the USB port. [CHAR LIMIT=NONE] -->
<string name="usb_contaminant_not_detected_message">Phone no longer detects liquid or debris.</string>
diff --git a/core/tests/bugreports/src/android/server/bugreports/BugreportManagerTest.java b/core/tests/bugreports/src/android/server/bugreports/BugreportManagerTest.java
index 220f854c337a..c72707db9560 100644
--- a/core/tests/bugreports/src/android/server/bugreports/BugreportManagerTest.java
+++ b/core/tests/bugreports/src/android/server/bugreports/BugreportManagerTest.java
@@ -88,7 +88,9 @@ public class BugreportManagerTest {
@Test
public void normalFlow_wifi() throws Exception {
BugreportCallbackImpl callback = new BugreportCallbackImpl();
- mBrm.startBugreport(mBugreportFd, mScreenshotFd, wifi(), mExecutor, callback);
+ // wifi bugreport does not take screenshot
+ mBrm.startBugreport(mBugreportFd, null /*screenshotFd = null*/, wifi(),
+ mExecutor, callback);
waitTillDoneOrTimeout(callback);
assertThat(callback.isDone()).isTrue();
@@ -99,13 +101,15 @@ public class BugreportManagerTest {
// of mBugreportFd.
assertThat(callback.getErrorCode()).isEqualTo(
BugreportCallback.BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
- assertFdsAreClosed(mBugreportFd, mScreenshotFd);
+ assertFdsAreClosed(mBugreportFd);
}
@Test
public void normalFlow_interactive() throws Exception {
BugreportCallbackImpl callback = new BugreportCallbackImpl();
- mBrm.startBugreport(mBugreportFd, mScreenshotFd, interactive(), mExecutor, callback);
+ // interactive bugreport does not take screenshot
+ mBrm.startBugreport(mBugreportFd, null /*screenshotFd = null*/, interactive(),
+ mExecutor, callback);
waitTillDoneOrTimeout(callback);
assertThat(callback.isDone()).isTrue();
@@ -113,7 +117,7 @@ public class BugreportManagerTest {
assertThat(callback.hasReceivedProgress()).isTrue();
assertThat(callback.getErrorCode()).isEqualTo(
BugreportCallback.BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
- assertFdsAreClosed(mBugreportFd, mScreenshotFd);
+ assertFdsAreClosed(mBugreportFd);
}
@Test
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 1b515ad41e68..d20aecaaf0f6 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -778,8 +778,6 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
}
const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>& child_resids) {
- ATRACE_NAME("AssetManager::GetBag");
-
auto cached_iter = cached_bags_.find(resid);
if (cached_iter != cached_bags_.end()) {
return cached_iter->second.get();
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index a8f313b9df8a..dc3041fb4878 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -400,7 +400,7 @@ public final class AudioAttributes implements Parcelable {
/**
* Indicates that the audio may be captured by any app.
*
- * For privacy, the following usages can not be recorded: VOICE_COMMUNICATION*,
+ * For privacy, the following usages cannot be recorded: VOICE_COMMUNICATION*,
* USAGE_NOTIFICATION*, USAGE_ASSISTANCE* and USAGE_ASSISTANT.
*
* On {@link android.os.Build.VERSION_CODES#Q}, this means only {@link #USAGE_UNKNOWN},
@@ -413,11 +413,11 @@ public final class AudioAttributes implements Parcelable {
/**
* Indicates that the audio may only be captured by system apps.
*
- * System apps can capture for many purposes like accessibility, user guidance...
+ * System apps can capture for many purposes like accessibility, live captions, user guidance...
* but abide to the following restrictions:
- * - the audio can not leave the device
- * - the audio can not be passed to a third party app
- * - the audio can not be recorded at a higher quality then 16kHz 16bit mono
+ * - the audio cannot leave the device
+ * - the audio cannot be passed to a third party app
+ * - the audio cannot be recorded at a higher quality than 16kHz 16bit mono
*
* See {@link Builder#setAllowedCapturePolicy}.
*/
diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java
index 2f03d26830f2..a82c78fad271 100644
--- a/media/java/android/media/audiopolicy/AudioMix.java
+++ b/media/java/android/media/audiopolicy/AudioMix.java
@@ -91,6 +91,20 @@ public class AudioMix {
*/
public static final int ROUTE_FLAG_LOOP_BACK = 0x1 << 1;
+ /**
+ * An audio mix behavior where the targeted audio is played unaffected but a copy is
+ * accessible for capture through {@link AudioRecord}.
+ *
+ * Only capture of playback is supported, not capture of capture.
+ * Use concurrent capture instead to capture what is captured by other apps.
+ *
+ * The captured audio is an approximation of the played audio.
+ * Effects and volume are not applied, and track are mixed with different delay then in the HAL.
+ * As a result, this API is not suitable for echo cancelling.
+ * @hide
+ */
+ public static final int ROUTE_FLAG_LOOP_BACK_RENDER = ROUTE_FLAG_LOOP_BACK | ROUTE_FLAG_RENDER;
+
private static final int ROUTE_FLAG_SUPPORTED = ROUTE_FLAG_RENDER | ROUTE_FLAG_LOOP_BACK;
// MIX_TYPE_* values to keep in sync with frameworks/av/include/media/AudioPolicy.h
@@ -125,6 +139,15 @@ public class AudioMix {
*/
public static final int MIX_STATE_MIXING = 1;
+ /** Maximum sampling rate for privileged playback capture*/
+ private static final int PRIVILEDGED_CAPTURE_MAX_SAMPLE_RATE = 16000;
+
+ /** Maximum channel number for privileged playback capture*/
+ private static final int PRIVILEDGED_CAPTURE_MAX_CHANNEL_NUMBER = 1;
+
+ /** Maximum channel number for privileged playback capture*/
+ private static final int PRIVILEDGED_CAPTURE_MAX_BYTES_PER_SAMPLE = 2;
+
/**
* The current mixing state.
* @return one of {@link #MIX_STATE_DISABLED}, {@link #MIX_STATE_IDLE},
@@ -140,7 +163,8 @@ public class AudioMix {
return mRouteFlags;
}
- AudioFormat getFormat() {
+ /** @hide */
+ public AudioFormat getFormat() {
return mFormat;
}
@@ -182,6 +206,31 @@ public class AudioMix {
return true;
}
+ /** @return an error string if the format would not allow Privileged playbackCapture
+ * null otherwise
+ * @hide */
+ public static String canBeUsedForPrivilegedCapture(AudioFormat format) {
+ int sampleRate = format.getSampleRate();
+ if (sampleRate > PRIVILEDGED_CAPTURE_MAX_SAMPLE_RATE || sampleRate <= 0) {
+ return "Privileged audio capture sample rate " + sampleRate
+ + " can not be over " + PRIVILEDGED_CAPTURE_MAX_SAMPLE_RATE + "kHz";
+ }
+ int channelCount = format.getChannelCount();
+ if (channelCount > PRIVILEDGED_CAPTURE_MAX_CHANNEL_NUMBER || channelCount <= 0) {
+ return "Privileged audio capture channel count " + channelCount + " can not be over "
+ + PRIVILEDGED_CAPTURE_MAX_CHANNEL_NUMBER;
+ }
+ int encoding = format.getEncoding();
+ if (!format.isPublicEncoding(encoding) || !format.isEncodingLinearPcm(encoding)) {
+ return "Privileged audio capture encoding " + encoding + "is not linear";
+ }
+ if (format.getBytesPerSample(encoding) > PRIVILEDGED_CAPTURE_MAX_BYTES_PER_SAMPLE) {
+ return "Privileged audio capture encoding " + encoding + " can not be over "
+ + PRIVILEDGED_CAPTURE_MAX_BYTES_PER_SAMPLE + " bytes per sample";
+ }
+ return null;
+ }
+
/** @hide */
@Override
public boolean equals(Object o) {
@@ -390,6 +439,12 @@ public class AudioMix {
}
}
}
+ if (mRule.allowPrivilegedPlaybackCapture()) {
+ String error = AudioMix.canBeUsedForPrivilegedCapture(mFormat);
+ if (error != null) {
+ throw new IllegalArgumentException(error);
+ }
+ }
return new AudioMix(mRule, mFormat, mRouteFlags, mCallbackFlags, mDeviceSystemType,
mDeviceAddress);
}
diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java
index ed2fdae71fb0..c4afd95be9ac 100644
--- a/media/java/android/media/audiopolicy/AudioMixingRule.java
+++ b/media/java/android/media/audiopolicy/AudioMixingRule.java
@@ -365,6 +365,10 @@ public class AudioMixingRule {
/**
* Set if the audio of app that opted out of audio playback capture should be captured.
*
+ * Caller of this method with <code>true</code>, MUST abide to the restriction listed in
+ * {@link ALLOW_CAPTURE_BY_SYSTEM}, including but not limited to the captured audio
+ * can not leave the capturing app, and the quality is limited to 16k mono.
+ *
* The permission {@link CAPTURE_AUDIO_OUTPUT} or {@link CAPTURE_MEDIA_OUTPUT} is needed
* to ignore the opt-out.
*
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 7cf725d443e9..54e468eed75d 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -1102,9 +1102,6 @@ public class CarStatusBar extends StatusBar implements
@Override
public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX,
float distanceY) {
- if (!mNotificationListAtBottomAtTimeOfTouch && !mNotificationListAtBottom) {
- return false;
- }
// should not clip while scroll to the bottom of the list.
if (!mNotificationListAtBottomAtTimeOfTouch) {
return false;
@@ -1141,7 +1138,8 @@ public class CarStatusBar extends StatusBar implements
@Override
public boolean onFling(MotionEvent event1, MotionEvent event2,
float velocityX, float velocityY) {
- if (!mNotificationListAtBottomAtTimeOfTouch && !mNotificationListAtBottom) {
+ // should not fling if the touch does not start when view is at the bottom of the list.
+ if (!mNotificationListAtBottomAtTimeOfTouch) {
return false;
}
if (Math.abs(event1.getX() - event2.getX()) > SWIPE_MAX_OFF_PATH
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/BootCompletedReceiver.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/BootCompletedReceiver.java
index ea7b378eb607..06c52942e671 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/BootCompletedReceiver.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/BootCompletedReceiver.java
@@ -22,8 +22,8 @@ import android.content.Intent;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.image.DynamicSystemClient;
+import android.os.image.DynamicSystemManager;
import android.util.FeatureFlagUtils;
-import android.util.Log;
/**
@@ -37,21 +37,26 @@ public class BootCompletedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- if (!featureFlagEnabled()) {
+ String action = intent.getAction();
+
+ if (!Intent.ACTION_BOOT_COMPLETED.equals(action)) {
return;
}
- String action = intent.getAction();
-
- Log.d(TAG, "Broadcast received: " + action);
+ DynamicSystemManager dynSystem =
+ (DynamicSystemManager) context.getSystemService(Context.DYNAMIC_SYSTEM_SERVICE);
- if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
- Intent startServiceIntent = new Intent(
- context, DynamicSystemInstallationService.class);
+ boolean isInUse = (dynSystem != null) && dynSystem.isInUse();
- startServiceIntent.setAction(DynamicSystemClient.ACTION_NOTIFY_IF_IN_USE);
- context.startServiceAsUser(startServiceIntent, UserHandle.SYSTEM);
+ if (!isInUse && !featureFlagEnabled()) {
+ return;
}
+
+ Intent startServiceIntent = new Intent(
+ context, DynamicSystemInstallationService.class);
+
+ startServiceIntent.setAction(DynamicSystemClient.ACTION_NOTIFY_IF_IN_USE);
+ context.startServiceAsUser(startServiceIntent, UserHandle.SYSTEM);
}
private boolean featureFlagEnabled() {
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
index b0e28a029436..077f7ecd3e46 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
@@ -37,7 +37,7 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
private static final String TAG = "InstallationAsyncTask";
- private static final int READ_BUFFER_SIZE = 1 << 19;
+ private static final int READ_BUFFER_SIZE = 1 << 13;
private class InvalidImageUrlException extends RuntimeException {
private InvalidImageUrlException(String message) {
diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
index 73c789516754..69aa0f917a5d 100644
--- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java
+++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
@@ -301,13 +301,17 @@ public class Assistant extends NotificationAssistantService {
sbn, ranking.getChannel(), mSmsHelper);
String key = getKey(
sbn.getPackageName(), sbn.getUserId(), ranking.getChannel().getId());
- ChannelImpressions ci = mkeyToImpressions.getOrDefault(key,
- createChannelImpressionsWithThresholds());
- if (ranking.getImportance() > IMPORTANCE_MIN && ci.shouldTriggerBlock()) {
+ boolean shouldTriggerBlock;
+ synchronized (mkeyToImpressions) {
+ ChannelImpressions ci = mkeyToImpressions.getOrDefault(key,
+ createChannelImpressionsWithThresholds());
+ mkeyToImpressions.put(key, ci);
+ shouldTriggerBlock = ci.shouldTriggerBlock();
+ }
+ if (ranking.getImportance() > IMPORTANCE_MIN && shouldTriggerBlock) {
adjustNotification(createNegativeAdjustment(
sbn.getPackageName(), sbn.getKey(), sbn.getUserId()));
}
- mkeyToImpressions.put(key, ci);
mLiveNotifications.put(sbn.getKey(), entry);
mAgingHelper.onNotificationPosted(entry);
}
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index dd72d5779c19..05246a42dedc 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -235,4 +235,7 @@
<!-- Default for Settings.Secure.SILENCE_GESTURE -->
<bool name="def_silence_gesture">false</bool>
+
+ <!-- Default for Settings.Secure.AWARE_LOCK_ENABLED -->
+ <bool name="def_aware_lock_enabled">false</bool>
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 6558c87aaf3a..f7132e368e94 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -3237,7 +3237,7 @@ public class SettingsProvider extends ContentProvider {
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 180;
+ private static final int SETTINGS_VERSION = 181;
private final int mUserId;
@@ -4401,6 +4401,25 @@ public class SettingsProvider extends ContentProvider {
currentVersion = 180;
}
+ if (currentVersion == 180) {
+ // Version 180: Set the default value for Secure Settings: AWARE_LOCK_ENABLED
+
+ final SettingsState secureSettings = getSecureSettingsLocked(userId);
+
+ final Setting awareLockEnabled = secureSettings.getSettingLocked(
+ Secure.AWARE_LOCK_ENABLED);
+
+ if (awareLockEnabled.isNull()) {
+ final boolean defAwareLockEnabled = getContext().getResources().getBoolean(
+ R.bool.def_aware_lock_enabled);
+ secureSettings.insertSettingLocked(
+ Secure.AWARE_LOCK_ENABLED, defAwareLockEnabled ? "1" : "0",
+ null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+ }
+
+ currentVersion = 181;
+ }
+
// vXXX: Add new settings above this point.
if (currentVersion != newVersion) {
diff --git a/packages/SystemUI/res/drawable-night/status_bar_notification_section_header_clear_btn.xml b/packages/SystemUI/res/drawable-night/status_bar_notification_section_header_clear_btn.xml
deleted file mode 100644
index c471b38306d5..000000000000
--- a/packages/SystemUI/res/drawable-night/status_bar_notification_section_header_clear_btn.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="40dp"
- android:height="40dp"
- android:viewportWidth="40"
- android:viewportHeight="40">
- <path
- android:fillColor="#9AA0A6"
- android:pathData="M24.6667 16.2733L23.7267 15.3333L20 19.06L16.2734 15.3333L15.3334 16.2733L19.06 20L15.3334 23.7266L16.2734 24.6666L20 20.94L23.7267 24.6666L24.6667 23.7266L20.94 20L24.6667 16.2733Z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/status_bar_notification_section_header_clear_btn.xml b/packages/SystemUI/res/drawable/status_bar_notification_section_header_clear_btn.xml
index 15f14d8af89b..8b3408048848 100644
--- a/packages/SystemUI/res/drawable/status_bar_notification_section_header_clear_btn.xml
+++ b/packages/SystemUI/res/drawable/status_bar_notification_section_header_clear_btn.xml
@@ -20,6 +20,6 @@
android:viewportWidth="40"
android:viewportHeight="40">
<path
- android:fillColor="#5F6368"
+ android:fillColor="@color/notification_section_clear_all_btn_color"
android:pathData="M24.6667 16.2733L23.7267 15.3333L20 19.06L16.2734 15.3333L15.3334 16.2733L19.06 20L15.3334 23.7267L16.2734 24.6667L20 20.94L23.7267 24.6667L24.6667 23.7267L20.94 20L24.6667 16.2733Z"/>
</vector>
diff --git a/packages/SystemUI/res/layout/bubble_expanded_view.xml b/packages/SystemUI/res/layout/bubble_expanded_view.xml
index 5b93edd1e6b3..db40c4fde053 100644
--- a/packages/SystemUI/res/layout/bubble_expanded_view.xml
+++ b/packages/SystemUI/res/layout/bubble_expanded_view.xml
@@ -30,11 +30,12 @@
<com.android.systemui.statusbar.AlphaOptimizedButton
style="@android:style/Widget.Material.Button.Borderless"
android:id="@+id/settings_button"
- android:layout_gravity="end"
+ android:layout_gravity="start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="true"
android:text="@string/manage_bubbles_text"
- android:textColor="?attr/wallpaperTextColor"/>
+ android:textColor="?attr/wallpaperTextColor"
+ />
</com.android.systemui.bubbles.BubbleExpandedView>
diff --git a/packages/SystemUI/res/layout/contaminant_dialog.xml b/packages/SystemUI/res/layout/contaminant_dialog.xml
new file mode 100644
index 000000000000..ea6d900e8fa7
--- /dev/null
+++ b/packages/SystemUI/res/layout/contaminant_dialog.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/layout/alert_dialog.xml
+**
+** Copyright 2019, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/parentPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="18dp"
+ android:paddingBottom="18dp"
+ android:textAlignment="center"
+ android:fontFamily="google-sans-medium"
+ android:textSize="20sp"
+ android:textStyle="bold"
+ android:textColor="?android:attr/textColorPrimary"/>
+
+ <TextView
+ android:id="@+id/message"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="24dp"
+ android:paddingRight="24dp"
+ android:paddingBottom="24dp"
+ android:textAlignment="center"
+ android:textSize="16sp"
+ android:fontFamily="roboto-regular"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingBottom="8dp"
+ android:focusable="true">
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="2dp"
+ android:background="@android:drawable/divider_horizontal_bright" />
+
+ <TextView
+ android:id="@+id/learnMore"
+ style="@style/USBContaminant.UserAction" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="2dp"
+ android:background="@android:drawable/divider_horizontal_bright" />
+
+ <TextView
+ android:id="@+id/enableUsb"
+ style="@style/USBContaminant.UserAction" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="2dp"
+ android:background="@android:drawable/divider_horizontal_bright" />
+
+ <TextView
+ android:id="@+id/gotIt"
+ style="@style/USBContaminant.UserAction" />
+
+ </LinearLayout>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_section_header.xml b/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
index 744c181bb0de..0c3c597a7b3a 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
@@ -55,6 +55,7 @@
android:layout_marginEnd="4dp"
android:src="@drawable/status_bar_notification_section_header_clear_btn"
android:contentDescription="@string/accessibility_notification_section_header_gentle_clear_all"
+ android:scaleType="center"
/>
</LinearLayout>
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index e25faa28d658..addc10aaeff6 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -50,6 +50,7 @@
<color name="notification_guts_button_color">@color/GM2_blue_200</color>
<color name="notification_section_header_label_color">@color/GM2_grey_200</color>
+ <color name="notification_section_clear_all_btn_color">@color/GM2_grey_500</color>
<color name="notification_channel_dialog_separator">@color/GM2_grey_700</color>
<!-- The color of the background in the top part of QSCustomizer -->
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 6d7e20594912..490473ce003a 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -98,6 +98,7 @@
<color name="notification_guts_button_color">@color/GM2_blue_700</color>
<color name="notification_section_header_label_color">@color/GM2_grey_900</color>
+ <color name="notification_section_clear_all_btn_color">@color/GM2_grey_700</color>
<!-- The divider view for the notification channel editor half-shelf -->
<color name="notification_channel_dialog_separator">@color/GM2_grey_200</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index b49b6121a13f..fb226c7540bb 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -701,7 +701,7 @@
<!-- The top padding of the clear all button -->
<dimen name="clear_all_padding_top">12dp</dimen>
- <dimen name="notification_section_header_height">40dp</dimen>
+ <dimen name="notification_section_header_height">48dp</dimen>
<dimen name="notification_section_header_padding_left">16dp</dimen>
<!-- Largest size an avatar might need to be drawn in the user picker, status bar, or
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index fcf1b5e85914..98312505b80d 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -166,7 +166,7 @@
<string name="usb_contaminant_title">USB port disabled</string>
<!-- Message of USB contaminant presence dialog [CHAR LIMIT=NONE] -->
- <string name="usb_contaminant_message">To protect your device from liquid or debris, the USB port is disabled and won\u2019t detect any accessories.\n\nYou\u2019ll be notified when it\u2019s safe to use the USB port again.</string>
+ <string name="usb_contaminant_message">To protect your device from liquid or debris, the USB port is disabled and won\u2019t detect any accessories.\n\nYou\u2019ll be notified when it\u2019s okay to use the USB port again.</string>
<!-- Toast for enabling ports from USB contaminant dialog [CHAR LIMIT=NONE] -->
<string name="usb_port_enabled">USB port enabled to detect chargers and accessories</string>
@@ -174,6 +174,9 @@
<!-- Button text to disable contaminant detection [CHAR LIMIT=NONE] -->
<string name="usb_disable_contaminant_detection">Enable USB</string>
+ <!-- Button text to disable contaminant detection [CHAR LIMIT=NONE] -->
+ <string name="learn_more">Learn more</string>
+
<!-- Checkbox label for application compatibility mode ON (zooming app to look like it's running
on a phone). [CHAR LIMIT=25] -->
<string name="compat_mode_on">Zoom to fill screen</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 59ed5cea2169..04cd30cdb86a 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -572,4 +572,22 @@
<item name="android:backgroundDimEnabled">true</item>
<item name="android:windowCloseOnTouchOutside">true</item>
</style>
+
+ <!-- USB Contaminant dialog -->
+ <style name ="USBContaminant" />
+
+ <style name ="USBContaminant.UserAction">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:fontFamily">roboto-regular</item>
+ <item name="android:paddingLeft">16dp</item>
+ <item name="android:paddingTop">16dp</item>
+ <item name="android:paddingRight">24dp</item>
+ <item name="android:paddingBottom">16dp</item>
+ <item name="android:textAlignment">viewStart</item>
+ <item name="android:textSize">16sp</item>
+ <item name="android:clickable">true</item>
+ <item name="android:background">?android:attr/selectableItemBackground</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ </style>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index ed2a6b59d153..2be5743a84cd 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -16,13 +16,22 @@
package com.android.systemui;
+import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Rect;
-import android.opengl.GLSurfaceView;
import android.service.wallpaper.WallpaperService;
+import android.util.Log;
+import android.util.Size;
import android.view.SurfaceHolder;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.glwallpaper.EglHelper;
+import com.android.systemui.glwallpaper.GLWallpaperRenderer;
import com.android.systemui.glwallpaper.ImageWallpaperRenderer;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.phone.DozeParameters;
/**
* Default built-in wallpaper that simply shows a static image.
@@ -30,112 +39,183 @@ import com.android.systemui.glwallpaper.ImageWallpaperRenderer;
@SuppressWarnings({"UnusedDeclaration"})
public class ImageWallpaper extends WallpaperService {
private static final String TAG = ImageWallpaper.class.getSimpleName();
+ // We delayed destroy render context that subsequent render requests have chance to cancel it.
+ // This is to avoid destroying then recreating render context in a very short time.
+ private static final int DELAY_FINISH_RENDERING = 1000;
@Override
public Engine onCreateEngine() {
return new GLEngine(this);
}
- class GLEngine extends Engine {
- private GLWallpaperSurfaceView mWallpaperSurfaceView;
+ class GLEngine extends Engine implements GLWallpaperRenderer.SurfaceProxy, StateListener {
+ // Surface is rejected if size below a threshold on some devices (ie. 8px on elfin)
+ // set min to 64 px (CTS covers this), please refer to ag/4867989 for detail.
+ @VisibleForTesting
+ static final int MIN_SURFACE_WIDTH = 64;
+ @VisibleForTesting
+ static final int MIN_SURFACE_HEIGHT = 64;
+
+ private GLWallpaperRenderer mRenderer;
+ private EglHelper mEglHelper;
+ private StatusBarStateController mController;
+ private final Runnable mFinishRenderingTask = this::finishRendering;
+ private final boolean mNeedTransition;
+ private boolean mNeedRedraw;
GLEngine(Context context) {
- mWallpaperSurfaceView = new GLWallpaperSurfaceView(context);
- mWallpaperSurfaceView.setRenderer(
- new ImageWallpaperRenderer(context, mWallpaperSurfaceView));
- mWallpaperSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
- setOffsetNotificationsEnabled(true);
+ mNeedTransition = ActivityManager.isHighEndGfx()
+ && !DozeParameters.getInstance(context).getDisplayNeedsBlanking();
+
+ // We will preserve EGL context when we are in lock screen or aod
+ // to avoid janking in following transition, we need to release when back to home.
+ mController = Dependency.get(StatusBarStateController.class);
+ if (mController != null) {
+ mController.addCallback(this /* StateListener */);
+ }
+ mEglHelper = new EglHelper();
+ mRenderer = new ImageWallpaperRenderer(context, this /* SurfaceProxy */);
}
@Override
- public void onAmbientModeChanged(boolean inAmbientMode, long animationDuration) {
- if (mWallpaperSurfaceView != null) {
- mWallpaperSurfaceView.notifyAmbientModeChanged(inAmbientMode, animationDuration);
- }
+ public void onCreate(SurfaceHolder surfaceHolder) {
+ setFixedSizeAllowed(true);
+ setOffsetNotificationsEnabled(false);
+ updateSurfaceSize();
+ }
+
+ private void updateSurfaceSize() {
+ SurfaceHolder holder = getSurfaceHolder();
+ Size frameSize = mRenderer.reportSurfaceSize();
+ int width = Math.max(MIN_SURFACE_WIDTH, frameSize.getWidth());
+ int height = Math.max(MIN_SURFACE_HEIGHT, frameSize.getHeight());
+ holder.setFixedSize(width, height);
}
@Override
- public void onOffsetsChanged(float xOffset, float yOffset, float xOffsetStep,
- float yOffsetStep, int xPixelOffset, int yPixelOffset) {
- if (mWallpaperSurfaceView != null) {
- mWallpaperSurfaceView.notifyOffsetsChanged(xOffset, yOffset);
- }
+ public void onAmbientModeChanged(boolean inAmbientMode, long animationDuration) {
+ mRenderer.updateAmbientMode(inAmbientMode,
+ (mNeedTransition || animationDuration != 0) ? animationDuration : 0);
}
@Override
public void onDestroy() {
- if (mWallpaperSurfaceView != null) {
- mWallpaperSurfaceView.onPause();
+ if (mController != null) {
+ mController.removeCallback(this /* StateListener */);
}
+ mController = null;
+ mRenderer.finish();
+ mRenderer = null;
+ mEglHelper.finish();
+ mEglHelper = null;
+ getSurfaceHolder().getSurface().hwuiDestroy();
}
- private class GLWallpaperSurfaceView extends GLSurfaceView implements ImageGLView {
- private WallpaperStatusListener mWallpaperStatusListener;
+ @Override
+ public void onSurfaceCreated(SurfaceHolder holder) {
+ mEglHelper.init(holder);
+ mRenderer.onSurfaceCreated();
+ }
- GLWallpaperSurfaceView(Context context) {
- super(context);
- setEGLContextClientVersion(2);
- }
+ @Override
+ public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ mRenderer.onSurfaceChanged(width, height);
+ mNeedRedraw = true;
+ }
- @Override
- public SurfaceHolder getHolder() {
- return getSurfaceHolder();
+ @Override
+ public void onSurfaceRedrawNeeded(SurfaceHolder holder) {
+ if (mNeedRedraw) {
+ preRender();
+ requestRender();
+ postRender();
+ mNeedRedraw = false;
}
+ }
- @Override
- public void setRenderer(Renderer renderer) {
- super.setRenderer(renderer);
- mWallpaperStatusListener = (WallpaperStatusListener) renderer;
+ @Override
+ public SurfaceHolder getHolder() {
+ return getSurfaceHolder();
+ }
+
+ @Override
+ public void onStatePostChange() {
+ // When back to home, we try to release EGL, which is preserved in lock screen or aod.
+ if (mController.getState() == StatusBarState.SHADE) {
+ scheduleFinishRendering();
}
+ }
- private void notifyAmbientModeChanged(boolean inAmbient, long duration) {
- if (mWallpaperStatusListener != null) {
- mWallpaperStatusListener.onAmbientModeChanged(inAmbient, duration);
+ @Override
+ public void preRender() {
+ boolean contextRecreated = false;
+ Rect frame = getSurfaceHolder().getSurfaceFrame();
+ getMainThreadHandler().removeCallbacks(mFinishRenderingTask);
+
+ // Check if we need to recreate egl context.
+ if (!mEglHelper.hasEglContext()) {
+ mEglHelper.destroyEglSurface();
+ if (!mEglHelper.createEglContext()) {
+ Log.w(TAG, "recreate egl context failed!");
+ } else {
+ contextRecreated = true;
}
}
- private void notifyOffsetsChanged(float xOffset, float yOffset) {
- if (mWallpaperStatusListener != null) {
- mWallpaperStatusListener.onOffsetsChanged(
- xOffset, yOffset, getHolder().getSurfaceFrame());
+ // Check if we need to recreate egl surface.
+ if (mEglHelper.hasEglContext() && !mEglHelper.hasEglSurface()) {
+ if (!mEglHelper.createEglSurface(getSurfaceHolder())) {
+ Log.w(TAG, "recreate egl surface failed!");
}
}
- @Override
- public void render() {
- requestRender();
+ // If we recreate egl context, notify renderer to setup again.
+ if (mEglHelper.hasEglContext() && mEglHelper.hasEglSurface() && contextRecreated) {
+ mRenderer.onSurfaceCreated();
+ mRenderer.onSurfaceChanged(frame.width(), frame.height());
}
}
- }
- /**
- * A listener to trace status of image wallpaper.
- */
- public interface WallpaperStatusListener {
-
- /**
- * Called back while ambient mode changes.
- * @param inAmbientMode true if is in ambient mode, false otherwise.
- * @param duration the duration of animation.
- */
- void onAmbientModeChanged(boolean inAmbientMode, long duration);
-
- /**
- * Called back while wallpaper offsets.
- * @param xOffset The offset portion along x.
- * @param yOffset The offset portion along y.
- */
- void onOffsetsChanged(float xOffset, float yOffset, Rect frame);
- }
+ @Override
+ public void requestRender() {
+ Rect frame = getSurfaceHolder().getSurfaceFrame();
+ boolean readyToRender = mEglHelper.hasEglContext() && mEglHelper.hasEglSurface()
+ && frame.width() > 0 && frame.height() > 0;
+
+ if (readyToRender) {
+ mRenderer.onDrawFrame();
+ if (!mEglHelper.swapBuffer()) {
+ Log.e(TAG, "drawFrame failed!");
+ }
+ } else {
+ Log.e(TAG, "requestRender: not ready, has context=" + mEglHelper.hasEglContext()
+ + ", has surface=" + mEglHelper.hasEglSurface()
+ + ", frame=" + frame);
+ }
+ }
- /**
- * An abstraction for view of GLRenderer.
- */
- public interface ImageGLView {
+ @Override
+ public void postRender() {
+ scheduleFinishRendering();
+ }
- /**
- * Ask the view to render.
- */
- void render();
+ private void scheduleFinishRendering() {
+ getMainThreadHandler().removeCallbacks(mFinishRenderingTask);
+ getMainThreadHandler().postDelayed(mFinishRenderingTask, DELAY_FINISH_RENDERING);
+ }
+
+ private void finishRendering() {
+ if (mEglHelper != null) {
+ mEglHelper.destroyEglSurface();
+ if (!needPreserveEglContext()) {
+ mEglHelper.destroyEglContext();
+ }
+ }
+ }
+
+ private boolean needPreserveEglContext() {
+ return mNeedTransition && mController != null
+ && mController.getState() == StatusBarState.KEYGUARD;
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java b/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
index 8c070835f69e..ea08c335b31d 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
@@ -136,7 +136,11 @@ final class PhoneStateMonitor {
}
private boolean isLauncherShowing(ActivityManager.RunningTaskInfo runningTaskInfo) {
- return runningTaskInfo.topActivity.equals(mDefaultHome);
+ if (runningTaskInfo == null) {
+ return false;
+ } else {
+ return runningTaskInfo.topActivity.equals(mDefaultHome);
+ }
}
private boolean isAppImmersive() {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 3b652b724c2b..e7948b5149a0 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -174,8 +174,9 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
mPointerDrawable = new ShapeDrawable(TriangleShape.create(
- mPointerWidth, mPointerHeight, false /* pointUp */));
+ mPointerWidth, mPointerHeight, true /* pointUp */));
mPointerView.setBackground(mPointerDrawable);
+ mPointerView.setVisibility(GONE);
mSettingsIconHeight = getContext().getResources().getDimensionPixelSize(
R.dimen.bubble_expanded_header_height);
@@ -186,8 +187,14 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
true /* singleTaskInstance */);
addView(mActivityView);
- // Make sure pointer is below activity view
- bringChildToFront(mPointerView);
+ // Expanded stack layout, top to bottom:
+ // Expanded view container
+ // ==> bubble row
+ // ==> expanded view
+ // ==> activity view
+ // ==> manage button
+ bringChildToFront(mActivityView);
+ bringChildToFront(mSettingsIcon);
applyThemeAttrs();
@@ -444,6 +451,7 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
// Adjust for the pointer size
x -= (mPointerView.getWidth() / 2f);
mPointerView.setTranslationX(x);
+ mPointerView.setVisibility(VISIBLE);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 50419b9aa767..bec90d2edad1 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -176,6 +176,7 @@ public class BubbleStackView extends FrameLayout {
private int mExpandedViewPadding;
private int mExpandedAnimateXDistance;
private int mExpandedAnimateYDistance;
+ private int mPointerHeight;
private int mStatusBarHeight;
private int mPipDismissHeight;
private int mImeOffset;
@@ -303,6 +304,8 @@ public class BubbleStackView extends FrameLayout {
res.getDimensionPixelSize(R.dimen.bubble_expanded_animate_x_distance);
mExpandedAnimateYDistance =
res.getDimensionPixelSize(R.dimen.bubble_expanded_animate_y_distance);
+ mPointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height);
+
mStatusBarHeight =
res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
mPipDismissHeight = mContext.getResources().getDimensionPixelSize(
@@ -1282,15 +1285,16 @@ public class BubbleStackView extends FrameLayout {
*/
int getMaxExpandedHeight() {
int expandedY = (int) mExpandedAnimationController.getExpandedY();
- return expandedY - getStatusBarHeight();
+ // PIP dismiss view uses FLAG_LAYOUT_IN_SCREEN so we need to subtract the bottom inset
+ int pipDismissHeight = mPipDismissHeight - getBottomInset();
+ return mDisplaySize.y - expandedY - mBubbleSize - pipDismissHeight;
}
/**
* Calculates the y position of the expanded view when it is expanded.
*/
float getYPositionForExpandedView() {
- return mExpandedAnimationController.getExpandedY()
- - mExpandedBubble.expandedView.getExpandedSize() - mBubblePadding;
+ return getStatusBarHeight() + mBubbleSize + mBubblePadding + mPointerHeight;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
index 4674a1f20360..ae8043f86cdd 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
@@ -301,13 +301,11 @@ public class ExpandedAnimationController
return 0;
}
final WindowInsets insets = mLayout.getRootWindowInsets();
- int keyboardHeight = insets.getSystemWindowInsetBottom()
- - insets.getStableInsetBottom();
- float bottomInset = keyboardHeight > 0
- ? keyboardHeight
- : (mPipDismissHeight - insets.getStableInsetBottom());
- // Stable insets are excluded from display size, so we must subtract it
- return mDisplaySize.y - mBubbleSizePx - mBubblePaddingPx - bottomInset;
+ return mBubblePaddingPx + Math.max(
+ mStatusBarHeight,
+ insets.getDisplayCutout() != null
+ ? insets.getDisplayCutout().getSafeInsetTop()
+ : 0);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
index 30f6e1affe0a..87d90adceba5 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
@@ -156,10 +156,7 @@ public class FragmentHostManager {
*/
protected void onConfigurationChanged(Configuration newConfig) {
if (mConfigChanges.applyNewConfig(mContext.getResources())) {
- // Save the old state.
- Parcelable p = destroyFragmentHost();
- // Generate a new fragment host and restore its state.
- createFragmentHost(p);
+ reloadFragments();
} else {
mFragments.dispatchConfigurationChanged(newConfig);
}
@@ -217,6 +214,13 @@ public class FragmentHostManager {
Dependency.get(FragmentService.class).removeAndDestroy(view);
}
+ public void reloadFragments() {
+ // Save the old state.
+ Parcelable p = destroyFragmentHost();
+ // Generate a new fragment host and restore its state.
+ createFragmentHost(p);
+ }
+
class HostCallbacks extends FragmentHostCallback<FragmentHostManager> {
public HostCallbacks() {
super(mContext, FragmentHostManager.this.mHandler, 0);
@@ -293,13 +297,6 @@ public class FragmentHostManager {
reloadFragments();
}
- private void reloadFragments() {
- // Save the old state.
- Parcelable p = destroyFragmentHost();
- // Generate a new fragment host and restore its state.
- createFragmentHost(p);
- }
-
Fragment instantiate(Context context, String className, Bundle arguments) {
Context extensionContext = mExtensionLookup.get(className);
if (extensionContext != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java
new file mode 100644
index 000000000000..b66cc4f83412
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.glwallpaper;
+
+import static android.opengl.EGL14.EGL_ALPHA_SIZE;
+import static android.opengl.EGL14.EGL_BLUE_SIZE;
+import static android.opengl.EGL14.EGL_CONFIG_CAVEAT;
+import static android.opengl.EGL14.EGL_CONTEXT_CLIENT_VERSION;
+import static android.opengl.EGL14.EGL_DEFAULT_DISPLAY;
+import static android.opengl.EGL14.EGL_DEPTH_SIZE;
+import static android.opengl.EGL14.EGL_GREEN_SIZE;
+import static android.opengl.EGL14.EGL_NONE;
+import static android.opengl.EGL14.EGL_NO_CONTEXT;
+import static android.opengl.EGL14.EGL_NO_DISPLAY;
+import static android.opengl.EGL14.EGL_NO_SURFACE;
+import static android.opengl.EGL14.EGL_OPENGL_ES2_BIT;
+import static android.opengl.EGL14.EGL_RED_SIZE;
+import static android.opengl.EGL14.EGL_RENDERABLE_TYPE;
+import static android.opengl.EGL14.EGL_STENCIL_SIZE;
+import static android.opengl.EGL14.EGL_SUCCESS;
+import static android.opengl.EGL14.eglChooseConfig;
+import static android.opengl.EGL14.eglCreateContext;
+import static android.opengl.EGL14.eglCreateWindowSurface;
+import static android.opengl.EGL14.eglDestroyContext;
+import static android.opengl.EGL14.eglDestroySurface;
+import static android.opengl.EGL14.eglGetDisplay;
+import static android.opengl.EGL14.eglGetError;
+import static android.opengl.EGL14.eglInitialize;
+import static android.opengl.EGL14.eglMakeCurrent;
+import static android.opengl.EGL14.eglSwapBuffers;
+import static android.opengl.EGL14.eglTerminate;
+
+import android.opengl.EGLConfig;
+import android.opengl.EGLContext;
+import android.opengl.EGLDisplay;
+import android.opengl.EGLSurface;
+import android.opengl.GLUtils;
+import android.util.Log;
+import android.view.SurfaceHolder;
+
+/**
+ * A helper class to handle EGL management.
+ */
+public class EglHelper {
+ private static final String TAG = EglHelper.class.getSimpleName();
+
+ private EGLDisplay mEglDisplay;
+ private EGLConfig mEglConfig;
+ private EGLContext mEglContext;
+ private EGLSurface mEglSurface;
+
+ /**
+ * Initialize EGL and prepare EglSurface.
+ * @param surfaceHolder surface holder.
+ * @return true if EglSurface is ready.
+ */
+ public boolean init(SurfaceHolder surfaceHolder) {
+ mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ if (mEglDisplay == EGL_NO_DISPLAY) {
+ Log.w(TAG, "eglGetDisplay failed: " + GLUtils.getEGLErrorString(eglGetError()));
+ return false;
+ }
+
+ if (!eglInitialize(mEglDisplay, null, 0, null, 0)) {
+ Log.w(TAG, "eglInitialize failed: " + GLUtils.getEGLErrorString(eglGetError()));
+ return false;
+ }
+
+ mEglConfig = chooseEglConfig();
+ if (mEglConfig == null) {
+ Log.w(TAG, "eglConfig not initialized!");
+ return false;
+ }
+
+ if (!createEglContext()) {
+ Log.w(TAG, "Can't create EGLContext!");
+ return false;
+ }
+
+ if (!createEglSurface(surfaceHolder)) {
+ Log.w(TAG, "Can't create EGLSurface!");
+ return false;
+ }
+
+ return true;
+ }
+
+ private EGLConfig chooseEglConfig() {
+ int[] configsCount = new int[1];
+ EGLConfig[] configs = new EGLConfig[1];
+ int[] configSpec = getConfig();
+ if (!eglChooseConfig(mEglDisplay, configSpec, 0, configs, 0, 1, configsCount, 0)) {
+ Log.w(TAG, "eglChooseConfig failed: " + GLUtils.getEGLErrorString(eglGetError()));
+ return null;
+ } else {
+ if (configsCount[0] <= 0) {
+ Log.w(TAG, "eglChooseConfig failed, invalid configs count: " + configsCount[0]);
+ return null;
+ } else {
+ return configs[0];
+ }
+ }
+ }
+
+ private int[] getConfig() {
+ return new int[] {
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_DEPTH_SIZE, 0,
+ EGL_STENCIL_SIZE, 0,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_CONFIG_CAVEAT, EGL_NONE,
+ EGL_NONE
+ };
+ }
+
+ /**
+ * Prepare an EglSurface.
+ * @param surfaceHolder surface holder.
+ * @return true if EglSurface is ready.
+ */
+ public boolean createEglSurface(SurfaceHolder surfaceHolder) {
+ mEglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig, surfaceHolder, null, 0);
+ if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) {
+ Log.w(TAG, "createWindowSurface failed: " + GLUtils.getEGLErrorString(eglGetError()));
+ return false;
+ }
+
+ if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
+ Log.w(TAG, "eglMakeCurrent failed: " + GLUtils.getEGLErrorString(eglGetError()));
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Destroy EglSurface.
+ */
+ public void destroyEglSurface() {
+ if (hasEglSurface()) {
+ eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ eglDestroySurface(mEglDisplay, mEglSurface);
+ mEglSurface = null;
+ }
+ }
+
+ /**
+ * Check if we have a valid EglSurface.
+ * @return true if EglSurface is ready.
+ */
+ public boolean hasEglSurface() {
+ return mEglSurface != null && mEglSurface != EGL_NO_SURFACE;
+ }
+
+ /**
+ * Prepare EglContext.
+ * @return true if EglContext is ready.
+ */
+ public boolean createEglContext() {
+ int[] attrib_list = new int[] {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
+ mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, attrib_list, 0);
+ if (mEglContext == EGL_NO_CONTEXT) {
+ Log.w(TAG, "eglCreateContext failed: " + GLUtils.getEGLErrorString(eglGetError()));
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Destroy EglContext.
+ */
+ public void destroyEglContext() {
+ if (hasEglContext()) {
+ eglDestroyContext(mEglDisplay, mEglContext);
+ mEglContext = null;
+ }
+ }
+
+ /**
+ * Check if we have EglContext.
+ * @return true if EglContext is ready.
+ */
+ public boolean hasEglContext() {
+ return mEglContext != null;
+ }
+
+ /**
+ * Swap buffer to display.
+ * @return true if swap successfully.
+ */
+ public boolean swapBuffer() {
+ boolean status = eglSwapBuffers(mEglDisplay, mEglSurface);
+ int error = eglGetError();
+ if (error != EGL_SUCCESS) {
+ Log.w(TAG, "eglSwapBuffers failed: " + GLUtils.getEGLErrorString(error));
+ }
+ return status;
+ }
+
+ /**
+ * Destroy EglSurface and EglContext, then terminate EGL.
+ */
+ public void finish() {
+ if (hasEglSurface()) {
+ destroyEglSurface();
+ }
+ if (hasEglContext()) {
+ destroyEglContext();
+ }
+ eglTerminate(mEglDisplay);
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/GLWallpaperRenderer.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/GLWallpaperRenderer.java
new file mode 100644
index 000000000000..8cc17b626946
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/GLWallpaperRenderer.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.glwallpaper;
+
+import android.util.Size;
+import android.view.SurfaceHolder;
+
+/**
+ * A renderer which is responsible for making OpenGL calls to render a frame.
+ */
+public interface GLWallpaperRenderer {
+
+ /**
+ * Called when the surface is created or recreated.
+ */
+ void onSurfaceCreated();
+
+ /**
+ * Called when the surface changed size.
+ * @param width surface width.
+ * @param height surface height.
+ */
+ void onSurfaceChanged(int width, int height);
+
+ /**
+ * Called to draw the current frame.
+ */
+ void onDrawFrame();
+
+ /**
+ * Notify ambient mode is changed.
+ * @param inAmbientMode true if in ambient mode.
+ * @param duration duration of transition.
+ */
+ void updateAmbientMode(boolean inAmbientMode, long duration);
+
+ /**
+ * Ask renderer to report the surface size it needs.
+ */
+ Size reportSurfaceSize();
+
+ /**
+ * Called when no need to render any more.
+ */
+ void finish();
+
+ /**
+ * A proxy which owns surface holder.
+ */
+ interface SurfaceProxy {
+
+ /**
+ * Get surface holder.
+ * @return surface holder.
+ */
+ SurfaceHolder getHolder();
+
+ /**
+ * Ask proxy to start rendering frame to surface.
+ */
+ void requestRender();
+
+ /**
+ * Ask proxy to prepare render context.
+ */
+ void preRender();
+
+ /**
+ * Ask proxy to destroy render context.
+ */
+ void postRender();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java
index d935466757de..4be7623f90f2 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java
@@ -195,76 +195,4 @@ class ImageGLWallpaper {
glUniform1i(mUniTexture, 0);
}
- /**
- * This method adjust s(x-axis), t(y-axis) texture coordinates
- * to prevent the wallpaper from being stretched.
- * The adjustment happens if either the width or height of the bitmap is larger than
- * corresponding size of the surface.
- * If both width and height are larger than corresponding size of the surface,
- * the adjustment will happen at both s, t side.
- *
- * @param bitmapWidth The width of the bitmap.
- * @param bitmapHeight The height of the bitmap.
- * @param surfaceWidth The width of the surface.
- * @param surfaceHeight The height of the surface.
- * @param xOffset The offset amount along s axis.
- * @param yOffset The offset amount along t axis.
- */
- void adjustTextureCoordinates(int bitmapWidth, int bitmapHeight,
- int surfaceWidth, int surfaceHeight, float xOffset, float yOffset) {
- float[] coordinates = TEXTURES.clone();
-
- if (bitmapWidth > surfaceWidth) {
- // Calculate the new s pos in pixels.
- float pixelS = (float) Math.round((bitmapWidth - surfaceWidth) * xOffset);
- // Calculate the s pos in texture coordinate.
- float coordinateS = pixelS / bitmapWidth;
- // Calculate the percentage occupied by the surface width in bitmap width.
- float surfacePercentageW = (float) surfaceWidth / bitmapWidth;
- // Need also consider the case if bitmap height is smaller than surface height.
- if (bitmapHeight < surfaceHeight) {
- // We will narrow the surface percentage to keep aspect ratio.
- surfacePercentageW *= (float) bitmapHeight / surfaceHeight;
- }
- // Determine the final s pos, also limit the legal s pos to prevent from out of range.
- float s = coordinateS + surfacePercentageW > 1f ? 1f - surfacePercentageW : coordinateS;
- // Traverse the s pos in texture coordinates array and adjust the s pos accordingly.
- for (int i = 0; i < coordinates.length; i += 2) {
- // indices 2, 4 and 6 are the end of s coordinates.
- if (i == 2 || i == 4 || i == 6) {
- coordinates[i] = Math.min(1f, s + surfacePercentageW);
- } else {
- coordinates[i] = s;
- }
- }
- }
-
- if (bitmapHeight > surfaceHeight) {
- // Calculate the new t pos in pixels.
- float pixelT = (float) Math.round((bitmapHeight - surfaceHeight) * yOffset);
- // Calculate the t pos in texture coordinate.
- float coordinateT = pixelT / bitmapHeight;
- // Calculate the percentage occupied by the surface height in bitmap height.
- float surfacePercentageH = (float) surfaceHeight / bitmapHeight;
- // Need also consider the case if bitmap width is smaller than surface width.
- if (bitmapWidth < surfaceWidth) {
- // We will narrow the surface percentage to keep aspect ratio.
- surfacePercentageH *= (float) bitmapWidth / surfaceWidth;
- }
- // Determine the final t pos, also limit the legal t pos to prevent from out of range.
- float t = coordinateT + surfacePercentageH > 1f ? 1f - surfacePercentageH : coordinateT;
- // Traverse the t pos in texture coordinates array and adjust the t pos accordingly.
- for (int i = 1; i < coordinates.length; i += 2) {
- // indices 1, 3 and 11 are the end of t coordinates.
- if (i == 1 || i == 3 || i == 11) {
- coordinates[i] = Math.min(1f, t + surfacePercentageH);
- } else {
- coordinates[i] = t;
- }
- }
- }
-
- mTextureBuffer.put(coordinates);
- mTextureBuffer.position(0);
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java
index 5914236ab349..6a1f24afe620 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java
@@ -56,11 +56,18 @@ class ImageRevealHelper {
@Override
public void onAnimationEnd(Animator animation) {
- if (!mIsCanceled) {
- mAwake = !mAwake;
+ if (!mIsCanceled && mRevealListener != null) {
+ mRevealListener.onRevealEnd();
}
mIsCanceled = false;
}
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ if (mRevealListener != null) {
+ mRevealListener.onRevealStart();
+ }
+ }
});
}
@@ -74,10 +81,6 @@ class ImageRevealHelper {
return mReveal;
}
- public boolean isAwake() {
- return mAwake;
- }
-
void updateAwake(boolean awake, long duration) {
mAwake = awake;
mAnimator.setDuration(duration);
@@ -93,5 +96,15 @@ class ImageRevealHelper {
* Called back while reveal status changes.
*/
void onRevealStateChanged();
+
+ /**
+ * Called back while reveal starts.
+ */
+ void onRevealStart();
+
+ /**
+ * Called back while reveal ends.
+ */
+ void onRevealEnd();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java
index 5bbfe84b6319..433e460ccfe8 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java
+++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java
@@ -26,23 +26,17 @@ import android.app.WallpaperManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Rect;
-import android.opengl.GLSurfaceView;
-import android.os.Build;
import android.util.Log;
import android.util.MathUtils;
+import android.util.Size;
-import com.android.systemui.ImageWallpaper;
-import com.android.systemui.ImageWallpaper.ImageGLView;
import com.android.systemui.R;
-import javax.microedition.khronos.egl.EGLConfig;
-import javax.microedition.khronos.opengles.GL10;
-
/**
* A GL renderer for image wallpaper.
*/
-public class ImageWallpaperRenderer implements GLSurfaceView.Renderer,
- ImageWallpaper.WallpaperStatusListener, ImageRevealHelper.RevealStateListener {
+public class ImageWallpaperRenderer implements GLWallpaperRenderer,
+ ImageRevealHelper.RevealStateListener {
private static final String TAG = ImageWallpaperRenderer.class.getSimpleName();
private static final float SCALE_VIEWPORT_MIN = 0.98f;
private static final float SCALE_VIEWPORT_MAX = 1f;
@@ -52,62 +46,61 @@ public class ImageWallpaperRenderer implements GLSurfaceView.Renderer,
private final ImageGLWallpaper mWallpaper;
private final ImageProcessHelper mImageProcessHelper;
private final ImageRevealHelper mImageRevealHelper;
- private final ImageGLView mGLView;
- private float mXOffset = 0f;
- private float mYOffset = 0f;
- private int mWidth = 0;
- private int mHeight = 0;
+ private SurfaceProxy mProxy;
+ private Rect mSurfaceSize;
private Bitmap mBitmap;
- private int mBitmapWidth = 0;
- private int mBitmapHeight = 0;
- public ImageWallpaperRenderer(Context context, ImageGLView glView) {
+ public ImageWallpaperRenderer(Context context, SurfaceProxy proxy) {
mWallpaperManager = context.getSystemService(WallpaperManager.class);
if (mWallpaperManager == null) {
Log.w(TAG, "WallpaperManager not available");
}
+ mProxy = proxy;
mProgram = new ImageGLProgram(context);
mWallpaper = new ImageGLWallpaper(mProgram);
mImageProcessHelper = new ImageProcessHelper();
mImageRevealHelper = new ImageRevealHelper(this);
- mGLView = glView;
- if (mWallpaperManager != null) {
- mBitmap = mWallpaperManager.getBitmap();
- mBitmapWidth = mBitmap.getWidth();
- mBitmapHeight = mBitmap.getHeight();
+ if (loadBitmap()) {
// Compute threshold of the image, this is an async work.
mImageProcessHelper.start(mBitmap);
- mWallpaperManager.forgetLoadedWallpaper();
}
}
@Override
- public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ public void onSurfaceCreated() {
glClearColor(0f, 0f, 0f, 1.0f);
mProgram.useGLProgram(
R.raw.image_wallpaper_vertex_shader, R.raw.image_wallpaper_fragment_shader);
+
+ if (!loadBitmap()) {
+ Log.w(TAG, "reload bitmap failed!");
+ }
+
mWallpaper.setup(mBitmap);
mBitmap = null;
}
+ private boolean loadBitmap() {
+ if (mWallpaperManager != null && mBitmap == null) {
+ mBitmap = mWallpaperManager.getBitmap();
+ mWallpaperManager.forgetLoadedWallpaper();
+ if (mBitmap != null) {
+ mSurfaceSize = new Rect(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
+ }
+ }
+ return mBitmap != null;
+ }
+
@Override
- public void onSurfaceChanged(GL10 gl, int width, int height) {
+ public void onSurfaceChanged(int width, int height) {
glViewport(0, 0, width, height);
- if (Build.IS_DEBUGGABLE) {
- Log.d(TAG, "onSurfaceChanged: width=" + width + ", height=" + height
- + ", xOffset=" + mXOffset + ", yOffset=" + mYOffset);
- }
- mWidth = width;
- mHeight = height;
- mWallpaper.adjustTextureCoordinates(
- mBitmapWidth, mBitmapHeight, width, height, mXOffset, mYOffset);
}
@Override
- public void onDrawFrame(GL10 gl) {
+ public void onDrawFrame() {
float threshold = mImageProcessHelper.getThreshold();
float reveal = mImageRevealHelper.getReveal();
@@ -122,50 +115,45 @@ public class ImageWallpaperRenderer implements GLSurfaceView.Renderer,
mWallpaper.draw();
}
+ @Override
+ public void updateAmbientMode(boolean inAmbientMode, long duration) {
+ mImageRevealHelper.updateAwake(!inAmbientMode, duration);
+ }
+
+ @Override
+ public Size reportSurfaceSize() {
+ return new Size(mSurfaceSize.width(), mSurfaceSize.height());
+ }
+
+ @Override
+ public void finish() {
+ mProxy = null;
+ }
+
private void scaleViewport(float reveal) {
+ int width = mSurfaceSize.width();
+ int height = mSurfaceSize.height();
// Interpolation between SCALE_VIEWPORT_MAX and SCALE_VIEWPORT_MIN by reveal.
float vpScaled = MathUtils.lerp(SCALE_VIEWPORT_MAX, SCALE_VIEWPORT_MIN, reveal);
// Calculate the offset amount from the lower left corner.
float offset = (SCALE_VIEWPORT_MAX - vpScaled) / 2;
// Change the viewport.
- glViewport((int) (mWidth * offset), (int) (mHeight * offset),
- (int) (mWidth * vpScaled), (int) (mHeight * vpScaled));
+ glViewport((int) (width * offset), (int) (height * offset),
+ (int) (width * vpScaled), (int) (height * vpScaled));
}
@Override
- public void onAmbientModeChanged(boolean inAmbientMode, long duration) {
- mImageRevealHelper.updateAwake(!inAmbientMode, duration);
- requestRender();
+ public void onRevealStateChanged() {
+ mProxy.requestRender();
}
@Override
- public void onOffsetsChanged(float xOffset, float yOffset, Rect frame) {
- if (frame == null || (xOffset == mXOffset && yOffset == mYOffset)) {
- return;
- }
-
- int width = frame.width();
- int height = frame.height();
- mXOffset = xOffset;
- mYOffset = yOffset;
-
- if (Build.IS_DEBUGGABLE) {
- Log.d(TAG, "onOffsetsChanged: width=" + width + ", height=" + height
- + ", xOffset=" + mXOffset + ", yOffset=" + mYOffset);
- }
- mWallpaper.adjustTextureCoordinates(
- mBitmapWidth, mBitmapHeight, width, height, mXOffset, mYOffset);
- requestRender();
+ public void onRevealStart() {
+ mProxy.preRender();
}
@Override
- public void onRevealStateChanged() {
- requestRender();
- }
-
- private void requestRender() {
- if (mGLView != null) {
- mGLView.render();
- }
+ public void onRevealEnd() {
+ mProxy.postRender();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index d8070cdf53d5..5d4172dcc68a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -525,6 +525,7 @@ public class NotificationLockscreenUserManagerImpl implements
setLockscreenPublicMode(isProfilePublic, userId);
mUsersWithSeperateWorkChallenge.put(userId, needsSeparateChallenge);
}
+ getEntryManager().updateNotifications();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index b79d9694735f..2651d4b04588 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -915,7 +915,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
if (child.getVisibility() != View.GONE
&& child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- if ((row.isPinned() || row.isHeadsUpAnimatingAway()) && row.getTranslation() < 0) {
+ if ((row.isPinned() || row.isHeadsUpAnimatingAway()) && row.getTranslation() < 0
+ && row.getProvider().shouldShowGutsOnSnapOpen()) {
top = Math.min(top, row.getTranslationY());
bottom = Math.max(bottom, row.getTranslationY() + row.getActualHeight());
}
@@ -4380,6 +4381,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
mStackScrollAlgorithm.setIsExpanded(isExpanded);
mAmbientState.setShadeExpanded(isExpanded);
mStateAnimator.setShadeExpanded(isExpanded);
+ mSwipeHelper.setIsExpanded(isExpanded);
if (changed) {
if (!mIsExpanded) {
mGroupManager.collapseAllGroups();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
index 4569b66d65f7..0f71192277df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
@@ -48,6 +48,7 @@ class NotificationSwipeHelper extends SwipeHelper
private static final long SWIPE_MENU_TIMING = 200;
private NotificationMenuRowPlugin mCurrMenuRow;
+ private boolean mIsExpanded;
public NotificationSwipeHelper(int swipeDirection, NotificationCallback callback,
Context context, NotificationMenuRowPlugin.OnMenuEventListener menuListener) {
@@ -97,6 +98,10 @@ class NotificationSwipeHelper extends SwipeHelper
return mFalsingCheck;
}
+ public void setIsExpanded(boolean isExpanded) {
+ mIsExpanded = isExpanded;
+ }
+
@Override
protected void onChildSnappedBack(View animView, float targetLeft) {
if (mCurrMenuRow != null && targetLeft == 0) {
@@ -200,7 +205,9 @@ class NotificationSwipeHelper extends SwipeHelper
boolean slowSwipedFarEnough = swipedEnoughToShowMenu(menuRow) && isSlowSwipe;
boolean isFastNonDismissGesture =
gestureFastEnough && !gestureTowardsMenu && !isDismissGesture;
- boolean isMenuRevealingGestureAwayFromMenu = slowSwipedFarEnough || isFastNonDismissGesture;
+ boolean isAbleToShowMenu = menuRow.shouldShowGutsOnSnapOpen() || mIsExpanded;
+ boolean isMenuRevealingGestureAwayFromMenu = slowSwipedFarEnough
+ || (isFastNonDismissGesture && isAbleToShowMenu);
int menuSnapTarget = menuRow.getMenuSnapTarget();
boolean isNonFalseMenuRevealingGesture =
!isFalseGesture(ev) && isMenuRevealingGestureAwayFromMenu;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 1429718d5d9c..e7dab8e81133 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -979,6 +979,17 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
public void onNavigationModeChanged(int mode) {
mNavBarMode = mode;
updateScreenPinningGestures();
+
+ // Workaround for b/132825155, for secondary users, we currently don't receive configuration
+ // changes on overlay package change since SystemUI runs for the system user. In this case,
+ // trigger a new configuration change to ensure that the nav bar is updated in the same way.
+ int userId = ActivityManagerWrapper.getInstance().getCurrentUserId();
+ if (userId != UserHandle.USER_SYSTEM) {
+ mHandler.post(() -> {
+ FragmentHostManager fragmentHost = FragmentHostManager.get(mNavigationBarView);
+ fragmentHost.reloadFragments();
+ });
+ }
}
public void disableAnimationsDuringHide(long delay) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 3146595f3592..28b673fc85cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -3133,7 +3133,6 @@ public class StatusBar extends SystemUI implements DemoMode,
// If the state didn't change, we may still need to update public mode
mLockscreenUserManager.updatePublicMode();
- mEntryManager.updateNotifications();
}
if (mStatusBarStateController.leaveOpenOnKeyguardHide()) {
if (!mStatusBarStateController.isKeyguardRequested()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
index 0865eb6ae7d2..6691f7a759f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
@@ -111,6 +111,7 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks,
}
protected void onWorkChallengeChanged() {
+ mLockscreenUserManager.updatePublicMode();
if (mPendingWorkRemoteInputView != null
&& !mLockscreenUserManager.isAnyProfilePublicMode()) {
// Expand notification panel and the notification row, then click on remote input view
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbContaminantActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbContaminantActivity.java
index ecf608beb91c..aec14be9c39e 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbContaminantActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbContaminantActivity.java
@@ -16,30 +16,33 @@
package com.android.systemui.usb;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
+import android.app.Activity;
import android.content.Intent;
import android.hardware.usb.ParcelableUsbPort;
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbPort;
import android.os.Bundle;
import android.util.Log;
+import android.view.View;
import android.view.Window;
import android.view.WindowManager;
+import android.widget.TextView;
import android.widget.Toast;
-import com.android.internal.app.AlertActivity;
-import com.android.internal.app.AlertController;
import com.android.systemui.R;
/**
* Activity that alerts the user when contaminant is detected on USB port.
*/
-public class UsbContaminantActivity extends AlertActivity
- implements DialogInterface.OnClickListener {
+public class UsbContaminantActivity extends Activity implements View.OnClickListener {
private static final String TAG = "UsbContaminantActivity";
private UsbPort mUsbPort;
+ private TextView mLearnMore;
+ private TextView mGotIt;
+ private TextView mEnableUsb;
+ private TextView mTitle;
+ private TextView mMessage;
@Override
public void onCreate(Bundle icicle) {
@@ -47,22 +50,30 @@ public class UsbContaminantActivity extends AlertActivity
window.addSystemFlags(WindowManager.LayoutParams
.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
window.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(icicle);
+ setContentView(R.layout.contaminant_dialog);
Intent intent = getIntent();
ParcelableUsbPort port = intent.getParcelableExtra(UsbManager.EXTRA_PORT);
mUsbPort = port.getUsbPort(getSystemService(UsbManager.class));
- final AlertController.AlertParams ap = mAlertParams;
- ap.mTitle = getString(R.string.usb_contaminant_title);
- ap.mMessage = getString(R.string.usb_contaminant_message);
- ap.mNegativeButtonText = getString(android.R.string.ok);
- ap.mNeutralButtonText = getString(R.string.usb_disable_contaminant_detection);
- ap.mNegativeButtonListener = this;
- ap.mNeutralButtonListener = this;
+ mLearnMore = findViewById(R.id.learnMore);
+ mEnableUsb = findViewById(R.id.enableUsb);
+ mGotIt = findViewById(R.id.gotIt);
+ mTitle = findViewById(R.id.title);
+ mMessage = findViewById(R.id.message);
- setupAlert();
+ mTitle.setText(getString(R.string.usb_contaminant_title));
+ mMessage.setText(getString(R.string.usb_contaminant_message));
+ mEnableUsb.setText(getString(R.string.usb_disable_contaminant_detection));
+ mGotIt.setText(getString(R.string.got_it));
+ mLearnMore.setText(getString(R.string.learn_more));
+
+ mEnableUsb.setOnClickListener(this);
+ mGotIt.setOnClickListener(this);
+ mLearnMore.setOnClickListener(this);
}
@Override
@@ -71,8 +82,8 @@ public class UsbContaminantActivity extends AlertActivity
}
@Override
- public void onClick(DialogInterface dialog, int which) {
- if (which == AlertDialog.BUTTON_NEUTRAL) {
+ public void onClick(View v) {
+ if (v == mEnableUsb) {
try {
mUsbPort.enableContaminantDetection(false);
Toast.makeText(this, R.string.usb_port_enabled,
@@ -80,6 +91,13 @@ public class UsbContaminantActivity extends AlertActivity
} catch (Exception e) {
Log.e(TAG, "Unable to notify Usb service", e);
}
+ } else if (v == mLearnMore) {
+ final Intent intent = new Intent();
+ intent.setClassName("com.android.settings",
+ "com.android.settings.HelpTrampoline");
+ intent.putExtra(Intent.EXTRA_TEXT,
+ "help_url_usb_contaminant_detected");
+ startActivity(intent);
}
finish();
}
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index c59b16cf3e4c..4131e799c5da 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -7365,6 +7365,9 @@ message MetricsEvent {
// OS: Q
FIELD_EMERGENCY_DIALER_DISCONNECT_CAUSE = 1739;
+ // Custom tag for NotificationItem. Hash of the NAS that made adjustments.
+ FIELD_NOTIFICATION_ASSISTANT_SERVICE_HASH = 1740;
+
// ---- Skipping ahead to avoid conflicts between master and release branches.
// ---- End Q Constants, all Q constants go above this line ----
diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java
index 9d979a6701c7..f92d0e0ff6f1 100644
--- a/services/core/java/com/android/server/DynamicSystemService.java
+++ b/services/core/java/com/android/server/DynamicSystemService.java
@@ -152,7 +152,18 @@ public class DynamicSystemService extends IDynamicSystemService.Stub implements
@Override
public boolean isInUse() throws RemoteException {
- return getGsiService().isGsiRunning();
+ boolean gsidWasRunning = "running".equals(SystemProperties.get("init.svc.gsid"));
+ boolean isInUse = false;
+
+ try {
+ isInUse = getGsiService().isGsiRunning();
+ } finally {
+ if (!gsidWasRunning && !isInUse) {
+ SystemProperties.set("ctl.stop", "gsid");
+ }
+ }
+
+ return isInUse;
}
@Override
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 1fb29a677983..bf56bc03b197 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -96,6 +96,7 @@ import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.UserManagerInternal;
import android.os.storage.DiskInfo;
import android.os.storage.IObbActionListener;
import android.os.storage.IStorageEventListener;
@@ -3242,7 +3243,22 @@ class StorageManagerService extends IStorageManager.Stub
public void opChanged(int op, int uid, String packageName) throws RemoteException {
if (!ENABLE_ISOLATED_STORAGE) return;
- remountUidExternalStorage(uid, getMountMode(uid, packageName));
+ if (op == OP_REQUEST_INSTALL_PACKAGES) {
+ // Only handling the case when the appop is denied. The other cases will be
+ // handled in the synchronous callback from AppOpsService.
+ if (packageName != null && mIAppOpsService.checkOperation(
+ OP_REQUEST_INSTALL_PACKAGES, uid, packageName) != MODE_ALLOWED) {
+ try {
+ ActivityManager.getService().killUid(
+ UserHandle.getAppId(uid), UserHandle.getUserId(uid),
+ "OP_REQUEST_INSTALL_PACKAGES is denied");
+ } catch (RemoteException e) {
+ // same process - should not happen
+ }
+ }
+ } else {
+ remountUidExternalStorage(uid, getMountMode(uid, packageName));
+ }
}
};
@@ -3579,6 +3595,12 @@ class StorageManagerService extends IStorageManager.Stub
if (Process.isIsolated(uid)) {
return Zygote.MOUNT_EXTERNAL_NONE;
}
+
+ final String[] packagesForUid = mIPackageManager.getPackagesForUid(uid);
+ if (packageName == null) {
+ packageName = packagesForUid[0];
+ }
+
if (mPmInternal.isInstantApp(packageName, UserHandle.getUserId(uid))) {
return Zygote.MOUNT_EXTERNAL_NONE;
}
@@ -3601,8 +3623,18 @@ class StorageManagerService extends IStorageManager.Stub
// runtime permission; this is a firm CDD requirement
final boolean hasInstall = mIPackageManager.checkUidPermission(INSTALL_PACKAGES,
uid) == PERMISSION_GRANTED;
- final boolean hasInstallOp = mIAppOpsService.checkOperation(OP_REQUEST_INSTALL_PACKAGES,
- uid, packageName) == MODE_ALLOWED;
+ boolean hasInstallOp = false;
+ // OP_REQUEST_INSTALL_PACKAGES is granted/denied per package but vold can't
+ // update mountpoints of a specific package. So, check the appop for all packages
+ // sharing the uid and allow same level of storage access for all packages even if
+ // one of the packages has the appop granted.
+ for (String uidPackageName : packagesForUid) {
+ if (mIAppOpsService.checkOperation(
+ OP_REQUEST_INSTALL_PACKAGES, uid, uidPackageName) == MODE_ALLOWED) {
+ hasInstallOp = true;
+ break;
+ }
+ }
if ((hasInstall || hasInstallOp) && hasWrite) {
return Zygote.MOUNT_EXTERNAL_WRITE;
}
@@ -3870,6 +3902,14 @@ class StorageManagerService extends IStorageManager.Stub
if (ENABLE_ISOLATED_STORAGE) {
return getMountMode(uid, packageName);
}
+ try {
+ if (packageName == null) {
+ final String[] packagesForUid = mIPackageManager.getPackagesForUid(uid);
+ packageName = packagesForUid[0];
+ }
+ } catch (RemoteException e) {
+ // Should not happen - same process
+ }
// No locking - CopyOnWriteArrayList
int mountMode = Integer.MAX_VALUE;
for (ExternalStorageMountPolicy policy : mPolicies) {
@@ -3918,5 +3958,23 @@ class StorageManagerService extends IStorageManager.Stub
}
return true;
}
+
+ public void onAppOpsChanged(int code, int uid,
+ @Nullable String packageName, int mode) {
+ if (mode == MODE_ALLOWED && (code == OP_READ_EXTERNAL_STORAGE
+ || code == OP_WRITE_EXTERNAL_STORAGE
+ || code == OP_REQUEST_INSTALL_PACKAGES)) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ final UserManagerInternal userManagerInternal =
+ LocalServices.getService(UserManagerInternal.class);
+ if (userManagerInternal.isUserInitialized(UserHandle.getUserId(uid))) {
+ onExternalStoragePolicyChanged(uid, packageName);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/SystemServerInitThreadPool.java b/services/core/java/com/android/server/SystemServerInitThreadPool.java
index 1ce655618028..ff6a5375565a 100644
--- a/services/core/java/com/android/server/SystemServerInitThreadPool.java
+++ b/services/core/java/com/android/server/SystemServerInitThreadPool.java
@@ -45,7 +45,8 @@ public class SystemServerInitThreadPool {
private static SystemServerInitThreadPool sInstance;
- private ExecutorService mService = ConcurrentUtils.newFixedThreadPool(4,
+ private ExecutorService mService = ConcurrentUtils.newFixedThreadPool(
+ Runtime.getRuntime().availableProcessors(),
"system-server-init-thread", Process.THREAD_PRIORITY_FOREGROUND);
private List<String> mPendingTasks = new ArrayList<>();
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 448e7738203a..3bed9c3dc7e1 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -1314,6 +1314,7 @@ public class AppOpsService extends IAppOpsService.Stub {
}
if (callbackSpecs == null) {
+ notifyOpChangedSync(code, uid, null, mode);
return;
}
@@ -1335,6 +1336,16 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
}
+
+ notifyOpChangedSync(code, uid, null, mode);
+ }
+
+ private void notifyOpChangedSync(int code, int uid, @NonNull String packageName, int mode) {
+ final StorageManagerInternal storageManagerInternal =
+ LocalServices.getService(StorageManagerInternal.class);
+ if (storageManagerInternal != null) {
+ storageManagerInternal.onAppOpsChanged(code, uid, packageName, mode);
+ }
}
/**
@@ -1438,6 +1449,8 @@ public class AppOpsService extends IAppOpsService.Stub {
AppOpsService::notifyOpChanged,
this, repCbs, code, uid, packageName));
}
+
+ notifyOpChangedSync(code, uid, packageName, mode);
}
private void notifyOpChanged(ArraySet<ModeCallback> callbacks, int code,
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 4cde931d2ef5..86832f444ff0 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -6698,7 +6698,10 @@ public class AudioService extends IAudioService.Stub
boolean isVolumeController, IMediaProjection projection) {
AudioSystem.setDynamicPolicyCallback(mDynPolicyCallback);
- if (!isPolicyRegisterAllowed(policyConfig, projection)) {
+ if (!isPolicyRegisterAllowed(policyConfig,
+ isFocusPolicy || isTestFocusPolicy || hasFocusListener,
+ isVolumeController,
+ projection)) {
Slog.w(TAG, "Permission denied to register audio policy for pid "
+ Binder.getCallingPid() + " / uid " + Binder.getCallingUid()
+ ", need MODIFY_AUDIO_ROUTING or MediaProjection that can project audio");
@@ -6739,42 +6742,71 @@ public class AudioService extends IAudioService.Stub
* as those policy do not modify the audio routing.
*/
private boolean isPolicyRegisterAllowed(AudioPolicyConfig policyConfig,
- IMediaProjection projection) {
-
- boolean isLoopbackRenderPolicy = policyConfig.getMixes().stream().allMatch(
- mix -> mix.getRouteFlags() == (mix.ROUTE_FLAG_RENDER | mix.ROUTE_FLAG_LOOP_BACK));
-
- if (isLoopbackRenderPolicy) {
- boolean allowPrivilegedPlaybackCapture = policyConfig.getMixes().stream().anyMatch(
- mix -> mix.getRule().allowPrivilegedPlaybackCapture());
- if (allowPrivilegedPlaybackCapture
- && !(hasPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT)
- || hasPermission(android.Manifest.permission.CAPTURE_MEDIA_OUTPUT))) {
- // Opt-out can not be bypassed without a system permission
- return false;
+ boolean hasFocusAccess,
+ boolean isVolumeController,
+ IMediaProjection projection) {
+
+ boolean requireValidProjection = false;
+ boolean requireCaptureAudioOrMediaOutputPerm = false;
+ boolean requireModifyRouting = false;
+
+ if (hasFocusAccess || isVolumeController) {
+ requireModifyRouting |= true;
+ } else if (policyConfig.getMixes().isEmpty()) {
+ // An empty policy could be used to lock the focus or add mixes later
+ requireModifyRouting |= true;
+ }
+ for (AudioMix mix : policyConfig.getMixes()) {
+ // If mix is requesting a privileged capture
+ if (mix.getRule().allowPrivilegedPlaybackCapture()) {
+ // then it must have CAPTURE_MEDIA_OUTPUT or CAPTURE_AUDIO_OUTPUT permission
+ requireCaptureAudioOrMediaOutputPerm |= true;
+ // and its format must be low quality enough
+ String error = mix.canBeUsedForPrivilegedCapture(mix.getFormat());
+ if (error != null) {
+ Log.e(TAG, error);
+ return false;
+ }
}
- if (canProjectAudio(projection)) {
- // Policy that do not modify the audio routing only need an audio projection
- return true;
+ // If mix is RENDER|LOOPBACK, then an audio MediaProjection is enough
+ // otherwise MODIFY_AUDIO_ROUTING permission is required
+ if (mix.getRouteFlags() == mix.ROUTE_FLAG_LOOP_BACK_RENDER && projection != null) {
+ requireValidProjection |= true;
+ } else {
+ requireModifyRouting |= true;
}
}
- boolean hasPermissionModifyAudioRouting =
- (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
- android.Manifest.permission.MODIFY_AUDIO_ROUTING));
- if (hasPermissionModifyAudioRouting) {
- return true;
+ if (requireCaptureAudioOrMediaOutputPerm
+ && !callerHasPermission(android.Manifest.permission.CAPTURE_MEDIA_OUTPUT)
+ && !callerHasPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT)) {
+ Log.e(TAG, "Privileged audio capture requires CAPTURE_MEDIA_OUTPUT or "
+ + "CAPTURE_AUDIO_OUTPUT system permission");
+ return false;
}
- return false;
+
+ if (requireValidProjection && !canProjectAudio(projection)) {
+ return false;
+ }
+
+ if (requireModifyRouting
+ && !callerHasPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)) {
+ Log.e(TAG, "Can not capture audio without MODIFY_AUDIO_ROUTING");
+ return false;
+ }
+
+ return true;
}
- private boolean hasPermission(String permission) {
- return PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(permission);
+
+ private boolean callerHasPermission(String permission) {
+ return mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED;
}
/** @return true if projection is a valid MediaProjection that can project audio. */
private boolean canProjectAudio(IMediaProjection projection) {
if (projection == null) {
+ Log.e(TAG, "MediaProjection is null");
return false;
}
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index d28482ef82ab..af25ad56a2a7 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -16,11 +16,14 @@
package com.android.server.clipboard;
+import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
+
+import android.Manifest;
import android.annotation.Nullable;
-import android.app.ActivityManager;
+import android.annotation.UserIdInt;
+import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
import android.app.AppOpsManager;
-import android.app.IActivityManager;
import android.app.IUriGrantsManager;
import android.app.KeyguardManager;
import android.app.UriGrantsManager;
@@ -145,6 +148,11 @@ class HostClipboardMonitor implements Runnable {
/**
* Implementation of the clipboard for copy and paste.
+ * <p>
+ * Caution: exception for clipboard data and isInternalSysWindowAppWithWindowFocus, any of data
+ * is accessed by userId or uid should be in * the try segment between
+ * Binder.clearCallingIdentity and Binder.restoreCallingIdentity.
+ * </p>
*/
public class ClipboardService extends SystemService {
@@ -152,7 +160,7 @@ public class ClipboardService extends SystemService {
private static final boolean IS_EMULATOR =
SystemProperties.getBoolean("ro.kernel.qemu", false);
- private final IActivityManager mAm;
+ private final ActivityManagerInternal mAmInternal;
private final IUriGrantsManager mUgm;
private final UriGrantsManagerInternal mUgmInternal;
private final WindowManagerInternal mWm;
@@ -173,7 +181,7 @@ public class ClipboardService extends SystemService {
public ClipboardService(Context context) {
super(context);
- mAm = ActivityManager.getService();
+ mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
mUgm = UriGrantsManager.getService();
mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
mWm = LocalServices.getService(WindowManagerInternal.class);
@@ -244,6 +252,87 @@ public class ClipboardService extends SystemService {
}
}
+ /**
+ * To check if the application has granted the INTERNAL_SYSTEM_WINDOW permission and window
+ * focus.
+ * <p>
+ * All of applications granted INTERNAL_SYSTEM_WINDOW has the risk to leak clip information to
+ * the other user because INTERNAL_SYSTEM_WINDOW is signature level. i.e. platform key. Because
+ * some of applications have both of INTERNAL_SYSTEM_WINDOW and INTERACT_ACROSS_USERS_FULL at
+ * the same time, that means they show the same window to all of users.
+ * </p><p>
+ * Unfortunately, all of applications with INTERNAL_SYSTEM_WINDOW starts very early and then
+ * the real window show is belong to user 0 rather user X. The result of
+ * WindowManager.isUidFocused checking user X window is false.
+ * </p>
+ * @return true if the app granted INTERNAL_SYSTEM_WINDOW permission.
+ */
+ private boolean isInternalSysWindowAppWithWindowFocus(String callingPackage) {
+ // Shell can access the clipboard for testing purposes.
+ if (mPm.checkPermission(Manifest.permission.INTERNAL_SYSTEM_WINDOW,
+ callingPackage) == PackageManager.PERMISSION_GRANTED) {
+ if (mWm.isUidFocused(Binder.getCallingUid())) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * To get the validate current userId.
+ * <p>
+ * The intending userId needs to be validated by ActivityManagerInternal.handleIncomingUser.
+ * To check if the uid of the process have the permission to run as the userId.
+ * e.x. INTERACT_ACROSS_USERS_FULL or INTERACT_ACROSS_USERS permission granted.
+ * </p>
+ * <p>
+ * The application with the granted INTERNAL_SYSTEM_WINDOW permission should run as the output
+ * of ActivityManagerInternal.handleIncomingUser rather the userId of Binder.getCAllingUid().
+ * To use the userId of Binder.getCallingUid() is the root cause that leaks the information
+ * comes from user 0 to user X.
+ * </p>
+ *
+ * @param packageName the package name of the calling side
+ * @param userId the userId passed by the calling side
+ * @return return the intending userId that has been validated by ActivityManagerInternal.
+ */
+ @UserIdInt
+ private int getIntendingUserId(String packageName, @UserIdInt int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getUserId(callingUid);
+ if (!UserManager.supportsMultipleUsers() || callingUserId == userId) {
+ return callingUserId;
+ }
+
+ int intendingUserId = callingUserId;
+ intendingUserId = mAmInternal.handleIncomingUser(Binder.getCallingPid(),
+ Binder.getCallingUid(), userId, false /* allow all */, ALLOW_FULL_ONLY,
+ "checkClipboardServiceCallingUser", packageName);
+
+ return intendingUserId;
+ }
+
+ /**
+ * To get the current running uid who is intend to run as.
+ * In ording to distinguish the nameing and reducing the confusing names, the client client
+ * side pass userId that is intend to run as,
+ * @return return IntentingUid = validated intenting userId +
+ * UserHandle.getAppId(Binder.getCallingUid())
+ */
+ private int getIntendingUid(String packageName, @UserIdInt int userId) {
+ return UserHandle.getUid(getIntendingUserId(packageName, userId),
+ UserHandle.getAppId(Binder.getCallingUid()));
+ }
+
+ /**
+ * To handle the difference between userId and intendingUserId, uid and intendingUid.
+ *
+ * userId means that comes from the calling side and should be validated by
+ * ActivityManagerInternal.handleIncomingUser.
+ * After validation of ActivityManagerInternal.handleIncomingUser, the userId is called
+ * 'intendingUserId' and the uid is called 'intendingUid'.
+ */
private class ClipboardImpl extends IClipboard.Stub {
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
@@ -260,92 +349,112 @@ public class ClipboardService extends SystemService {
}
@Override
- public void setPrimaryClip(ClipData clip, String callingPackage) {
+ public void setPrimaryClip(ClipData clip, String callingPackage, @UserIdInt int userId) {
synchronized (this) {
if (clip == null || clip.getItemCount() <= 0) {
throw new IllegalArgumentException("No items");
}
- final int callingUid = Binder.getCallingUid();
+ final int intendingUid = getIntendingUid(callingPackage, userId);
+ final int intendingUserId = UserHandle.getUserId(intendingUid);
if (!clipboardAccessAllowed(AppOpsManager.OP_WRITE_CLIPBOARD, callingPackage,
- callingUid)) {
+ intendingUid, intendingUserId)) {
return;
}
- checkDataOwnerLocked(clip, callingUid);
- setPrimaryClipInternal(clip, callingUid);
+ checkDataOwnerLocked(clip, intendingUid);
+ setPrimaryClipInternal(clip, intendingUid);
}
}
@Override
- public void clearPrimaryClip(String callingPackage) {
+ public void clearPrimaryClip(String callingPackage, @UserIdInt int userId) {
synchronized (this) {
- final int callingUid = Binder.getCallingUid();
+ final int intendingUid = getIntendingUid(callingPackage, userId);
+ final int intendingUserId = UserHandle.getUserId(intendingUid);
if (!clipboardAccessAllowed(AppOpsManager.OP_WRITE_CLIPBOARD, callingPackage,
- callingUid)) {
+ intendingUid, intendingUserId)) {
return;
}
- setPrimaryClipInternal(null, callingUid);
+ setPrimaryClipInternal(null, intendingUid);
}
}
@Override
- public ClipData getPrimaryClip(String pkg) {
+ public ClipData getPrimaryClip(String pkg, @UserIdInt int userId) {
synchronized (this) {
+ final int intendingUid = getIntendingUid(pkg, userId);
+ final int intendingUserId = UserHandle.getUserId(intendingUid);
if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, pkg,
- Binder.getCallingUid()) || isDeviceLocked()) {
+ intendingUid, intendingUserId)
+ || isDeviceLocked(intendingUserId)) {
return null;
}
- addActiveOwnerLocked(Binder.getCallingUid(), pkg);
- return getClipboard().primaryClip;
+ addActiveOwnerLocked(intendingUid, pkg);
+ return getClipboard(intendingUserId).primaryClip;
}
}
@Override
- public ClipDescription getPrimaryClipDescription(String callingPackage) {
+ public ClipDescription getPrimaryClipDescription(String callingPackage,
+ @UserIdInt int userId) {
synchronized (this) {
+ final int intendingUid = getIntendingUid(callingPackage, userId);
+ final int intendingUserId = UserHandle.getUserId(intendingUid);
if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage,
- Binder.getCallingUid()) || isDeviceLocked()) {
+ intendingUid, intendingUserId)
+ || isDeviceLocked(intendingUserId)) {
return null;
}
- PerUserClipboard clipboard = getClipboard();
- return clipboard.primaryClip != null ? clipboard.primaryClip.getDescription() : null;
+ PerUserClipboard clipboard = getClipboard(intendingUserId);
+ return clipboard.primaryClip != null
+ ? clipboard.primaryClip.getDescription() : null;
}
}
@Override
- public boolean hasPrimaryClip(String callingPackage) {
+ public boolean hasPrimaryClip(String callingPackage, @UserIdInt int userId) {
synchronized (this) {
+ final int intendingUid = getIntendingUid(callingPackage, userId);
+ final int intendingUserId = UserHandle.getUserId(intendingUid);
if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage,
- Binder.getCallingUid()) || isDeviceLocked()) {
+ intendingUid, intendingUserId)
+ || isDeviceLocked(intendingUserId)) {
return false;
}
- return getClipboard().primaryClip != null;
+ return getClipboard(intendingUserId).primaryClip != null;
}
}
@Override
public void addPrimaryClipChangedListener(IOnPrimaryClipChangedListener listener,
- String callingPackage) {
+ String callingPackage, @UserIdInt int userId) {
synchronized (this) {
- getClipboard().primaryClipListeners.register(listener,
- new ListenerInfo(Binder.getCallingUid(), callingPackage));
+ final int intendingUid = getIntendingUid(callingPackage, userId);
+ final int intendingUserId = UserHandle.getUserId(intendingUid);
+ getClipboard(intendingUserId).primaryClipListeners.register(listener,
+ new ListenerInfo(intendingUid, callingPackage));
}
}
@Override
- public void removePrimaryClipChangedListener(IOnPrimaryClipChangedListener listener) {
+ public void removePrimaryClipChangedListener(IOnPrimaryClipChangedListener listener,
+ String callingPackage, @UserIdInt int userId) {
synchronized (this) {
- getClipboard().primaryClipListeners.unregister(listener);
+ final int intendingUserId = getIntendingUserId(callingPackage, userId);
+ getClipboard(intendingUserId).primaryClipListeners.unregister(listener);
}
}
@Override
- public boolean hasClipboardText(String callingPackage) {
+ public boolean hasClipboardText(String callingPackage, int userId) {
synchronized (this) {
+ final int intendingUid = getIntendingUid(callingPackage, userId);
+ final int intendingUserId = UserHandle.getUserId(intendingUid);
if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage,
- Binder.getCallingUid()) || isDeviceLocked()) {
+ intendingUid, intendingUserId)
+ || isDeviceLocked(intendingUserId)) {
return false;
}
- PerUserClipboard clipboard = getClipboard();
+ PerUserClipboard clipboard = getClipboard(intendingUserId);
if (clipboard.primaryClip != null) {
CharSequence text = clipboard.primaryClip.getItemAt(0).getText();
return text != null && text.length() > 0;
@@ -355,11 +464,7 @@ public class ClipboardService extends SystemService {
}
};
- private PerUserClipboard getClipboard() {
- return getClipboard(UserHandle.getCallingUserId());
- }
-
- private PerUserClipboard getClipboard(int userId) {
+ private PerUserClipboard getClipboard(@UserIdInt int userId) {
synchronized (mClipboards) {
PerUserClipboard puc = mClipboards.get(userId);
if (puc == null) {
@@ -370,7 +475,7 @@ public class ClipboardService extends SystemService {
}
}
- List<UserInfo> getRelatedProfiles(int userId) {
+ List<UserInfo> getRelatedProfiles(@UserIdInt int userId) {
final List<UserInfo> related;
final long origId = Binder.clearCallingIdentity();
try {
@@ -397,7 +502,7 @@ public class ClipboardService extends SystemService {
}
}
- void setPrimaryClipInternal(@Nullable ClipData clip, int callingUid) {
+ void setPrimaryClipInternal(@Nullable ClipData clip, int uid) {
// Push clipboard to host, if any
if (mHostClipboardMonitor != null) {
if (clip == null) {
@@ -412,8 +517,8 @@ public class ClipboardService extends SystemService {
}
// Update this user
- final int userId = UserHandle.getUserId(callingUid);
- setPrimaryClipInternal(getClipboard(userId), clip, callingUid);
+ final int userId = UserHandle.getUserId(uid);
+ setPrimaryClipInternal(getClipboard(userId), clip, uid);
// Update related users
List<UserInfo> related = getRelatedProfiles(userId);
@@ -426,11 +531,15 @@ public class ClipboardService extends SystemService {
// primary clip in related users to prevent pasting stale content.
if (!canCopy) {
clip = null;
+ } else if (clip == null) {
+ // do nothing for canCopy == true and clip == null case
+ // To prevent from NPE happen in 'new ClipData(clip)' when run
+ // android.content.cts.ClipboardManagerTest#testClearPrimaryClip
} else {
// We want to fix the uris of the related user's clip without changing the
// uris of the current user's clip.
// So, copy the ClipData, and then copy all the items, so that nothing
- // is shared in memmory.
+ // is shared in memory.
clip = new ClipData(clip);
for (int i = clip.getItemCount() - 1; i >= 0; i--) {
clip.setItemAt(i, new ClipData.Item(clip.getItemAt(i)));
@@ -443,7 +552,7 @@ public class ClipboardService extends SystemService {
final boolean canCopyIntoProfile = !hasRestriction(
UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, id);
if (canCopyIntoProfile) {
- setPrimaryClipInternal(getClipboard(id), clip, callingUid);
+ setPrimaryClipInternal(getClipboard(id), clip, uid);
}
}
}
@@ -452,7 +561,7 @@ public class ClipboardService extends SystemService {
}
void setPrimaryClipInternal(PerUserClipboard clipboard, @Nullable ClipData clip,
- int callingUid) {
+ int uid) {
revokeUris(clipboard);
clipboard.activePermissionOwners.clear();
if (clip == null && clipboard.primaryClip == null) {
@@ -460,7 +569,7 @@ public class ClipboardService extends SystemService {
}
clipboard.primaryClip = clip;
if (clip != null) {
- clipboard.primaryClipUid = callingUid;
+ clipboard.primaryClipUid = uid;
} else {
clipboard.primaryClipUid = android.os.Process.NOBODY_UID;
}
@@ -479,7 +588,7 @@ public class ClipboardService extends SystemService {
clipboard.primaryClipListeners.getBroadcastCookie(i);
if (clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, li.mPackageName,
- li.mUid)) {
+ li.mUid, UserHandle.getUserId(li.mUid))) {
clipboard.primaryClipListeners.getBroadcastItem(i)
.dispatchPrimaryClipChanged();
}
@@ -494,13 +603,12 @@ public class ClipboardService extends SystemService {
}
}
- private boolean isDeviceLocked() {
- int callingUserId = UserHandle.getCallingUserId();
+ private boolean isDeviceLocked(@UserIdInt int userId) {
final long token = Binder.clearCallingIdentity();
try {
final KeyguardManager keyguardManager = getContext().getSystemService(
KeyguardManager.class);
- return keyguardManager != null && keyguardManager.isDeviceLocked(callingUserId);
+ return keyguardManager != null && keyguardManager.isDeviceLocked(userId);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -585,7 +693,7 @@ public class ClipboardService extends SystemService {
} finally {
Binder.restoreCallingIdentity(oldIdentity);
}
- PerUserClipboard clipboard = getClipboard();
+ PerUserClipboard clipboard = getClipboard(UserHandle.getUserId(uid));
if (clipboard.primaryClip != null && !clipboard.activePermissionOwners.contains(pkg)) {
final int N = clipboard.primaryClip.getItemCount();
for (int i=0; i<N; i++) {
@@ -630,9 +738,10 @@ public class ClipboardService extends SystemService {
}
}
- private boolean clipboardAccessAllowed(int op, String callingPackage, int callingUid) {
+ private boolean clipboardAccessAllowed(int op, String callingPackage, int uid,
+ @UserIdInt int userId) {
// Check the AppOp.
- if (mAppOps.noteOp(op, callingUid, callingPackage) != AppOpsManager.MODE_ALLOWED) {
+ if (mAppOps.noteOp(op, uid, callingPackage) != AppOpsManager.MODE_ALLOWED) {
return false;
}
// Shell can access the clipboard for testing purposes.
@@ -641,7 +750,6 @@ public class ClipboardService extends SystemService {
return true;
}
// The default IME is always allowed to access the clipboard.
- int userId = UserHandle.getUserId(callingUid);
String defaultIme = Settings.Secure.getStringForUser(getContext().getContentResolver(),
Settings.Secure.DEFAULT_INPUT_METHOD, userId);
if (!TextUtils.isEmpty(defaultIme)) {
@@ -654,16 +762,31 @@ public class ClipboardService extends SystemService {
switch (op) {
case AppOpsManager.OP_READ_CLIPBOARD:
// Clipboard can only be read by applications with focus..
- boolean allowed = mWm.isUidFocused(callingUid);
+ // or the application have the INTERNAL_SYSTEM_WINDOW and INTERACT_ACROSS_USERS_FULL
+ // at the same time. e.x. SystemUI. It needs to check the window focus of
+ // Binder.getCallingUid(). Without checking, the user X can't copy any thing from
+ // INTERNAL_SYSTEM_WINDOW to the other applications.
+ boolean allowed = mWm.isUidFocused(uid)
+ || isInternalSysWindowAppWithWindowFocus(callingPackage);
if (!allowed && mContentCaptureInternal != null) {
// ...or the Content Capture Service
- allowed = mContentCaptureInternal.isContentCaptureServiceForUser(callingUid,
- userId);
+ // The uid parameter of mContentCaptureInternal.isContentCaptureServiceForUser
+ // is used to check if the uid has the permission BIND_CONTENT_CAPTURE_SERVICE.
+ // if the application has the permission, let it to access user's clipboard.
+ // To passed synthesized uid user#10_app#systemui may not tell the real uid.
+ // userId must pass intending userId. i.e. user#10.
+ allowed = mContentCaptureInternal.isContentCaptureServiceForUser(
+ Binder.getCallingUid(), userId);
}
if (!allowed && mAutofillInternal != null) {
// ...or the Augmented Autofill Service
- allowed = mAutofillInternal.isAugmentedAutofillServiceForUser(callingUid,
- userId);
+ // The uid parameter of mAutofillInternal.isAugmentedAutofillServiceForUser
+ // is used to check if the uid has the permission BIND_AUTOFILL_SERVICE.
+ // if the application has the permission, let it to access user's clipboard.
+ // To passed synthesized uid user#10_app#systemui may not tell the real uid.
+ // userId must pass intending userId. i.e. user#10.
+ allowed = mAutofillInternal.isAugmentedAutofillServiceForUser(
+ Binder.getCallingUid(), userId);
}
if (!allowed) {
Slog.e(TAG, "Denying clipboard access to " + callingPackage
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 13b4ab927c59..82bf00301499 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -310,7 +310,6 @@ public class NotificationManagerService extends SystemService {
static final boolean ENABLE_BLOCKED_TOASTS = true;
static final String[] DEFAULT_ALLOWED_ADJUSTMENTS = new String[] {
- Adjustment.KEY_IMPORTANCE,
Adjustment.KEY_CONTEXTUAL_ACTIONS,
Adjustment.KEY_TEXT_REPLIES};
@@ -7344,7 +7343,7 @@ public class NotificationManagerService extends SystemService {
static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
private static final String ATT_USER_SET = "user_set";
- private static final String TAG_ALLOWED_ADJUSTMENT_TYPES = "allowed_adjustments";
+ private static final String TAG_ALLOWED_ADJUSTMENT_TYPES = "q_allowed_adjustments";
private static final String ATT_TYPES = "types";
private final Object mLock = new Object();
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 4ed24ec7971b..4e9b4f75237b 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -1268,6 +1268,22 @@ public final class NotificationRecord {
}
}
+ // Returns the name of the NAS that made adjustments. By policy, there must only ever be one.
+ // If this is violated, the NAS that first sent an adjustment is returned.
+ private @Nullable String getAdjustmentIssuer() {
+ synchronized (mAdjustments) {
+ for (Adjustment adjustment : mAdjustments) {
+ if (adjustment.getSignals().isEmpty()) {
+ continue;
+ }
+ if (adjustment.getIssuer() != null) {
+ return adjustment.getIssuer();
+ }
+ }
+ }
+ return null;
+ }
+
public LogMaker getLogMaker(long now) {
LogMaker lm = sbn.getLogMaker()
.addTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_IMPORTANCE, mImportance)
@@ -1297,6 +1313,14 @@ public final class NotificationRecord {
lm.addTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_ASST,
mAssistantImportance);
}
+ // Log the issuer of any adjustments that may have affected this notification. We only log
+ // the hash here as NotificationItem events are frequent, and the number of NAS
+ // implementations (and hence the chance of collisions) is low.
+ String adjustmentIssuer = getAdjustmentIssuer();
+ if (adjustmentIssuer != null) {
+ lm.addTaggedData(MetricsEvent.FIELD_NOTIFICATION_ASSISTANT_SERVICE_HASH,
+ adjustmentIssuer.hashCode());
+ }
return lm;
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index b2ba2904cabc..2b7691b87de9 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -2091,7 +2091,7 @@ public class PermissionManagerService {
return;
}
- if (bp.isHardOrSoftRestricted()
+ if (bp.isHardRestricted()
&& (flags & PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) == 0) {
Log.e(TAG, "Cannot grant restricted non-exempt permission "
+ permName + " for package " + packageName);
diff --git a/services/core/java/com/android/server/pm/permission/TEST_MAPPING b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
index ff7c699eb130..9efb6692e373 100644
--- a/services/core/java/com/android/server/pm/permission/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
@@ -29,6 +29,23 @@
]
},
{
+ "name": "CtsPermission2TestCases",
+ "options": [
+ {
+ "include-filter": "android.permission.cts.SharedUidPermissionsTest"
+ },
+ {
+ "include-filter": "android.permission.cts.RestrictedPermissionsTest"
+ },
+ {
+ "include-filter": "android.permission.cts.PermissionMaxSdkVersionTest"
+ },
+ {
+ "include-filter": "android.permission.cts.PrivappPermissionsTest"
+ }
+ ]
+ },
+ {
"name": "CtsStatsdHostTestCases",
"options": [
{
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index d77ea6e41cc2..55159c3f33f1 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -51,6 +51,8 @@ import android.os.Parcel;
import android.os.RemoteCallback;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
@@ -104,6 +106,7 @@ public class VoiceInteractionManagerService extends SystemService {
final ArraySet<Integer> mLoadedKeyphraseIds = new ArraySet<>();
ShortcutServiceInternal mShortcutServiceInternal;
SoundTriggerInternal mSoundTriggerInternal;
+ private boolean mAllowInstantService;
private final RemoteCallbackList<IVoiceInteractionSessionListener>
mVoiceInteractionSessionListeners = new RemoteCallbackList<>();
@@ -170,6 +173,14 @@ public class VoiceInteractionManagerService extends SystemService {
mServiceStub.switchUser(userHandle);
}
+ // Called by Shell cmd
+ void setAllowInstantService(boolean allowed) {
+ Log.i(TAG, "setAllowInstantService(): " + allowed);
+ mContext.enforceCallingPermission(Manifest.permission.MANAGE_BIND_INSTANT_SERVICE,
+ "setAllowInstantService");
+ mAllowInstantService = allowed;
+ }
+
class LocalService extends VoiceInteractionManagerInternal {
@Override
public void startLocalVoiceInteraction(IBinder callingActivity, Bundle options) {
@@ -223,6 +234,7 @@ public class VoiceInteractionManagerService extends SystemService {
new IVoiceInteractionSessionShowCallback.Stub() {
@Override
public void onFailed() {
+ Slog.w(TAG, "startLocalVoiceInteraction() failed");
}
@Override
@@ -271,7 +283,10 @@ public class VoiceInteractionManagerService extends SystemService {
}
public void initForUser(int userHandle) {
- if (DEBUG) Slog.d(TAG, "**************** initForUser user=" + userHandle);
+ if (DEBUG) {
+ Slog.d(TAG, "**************** initForUser user=" + userHandle
+ + ", allowInstantService=" + mAllowInstantService);
+ }
String curInteractorStr = Settings.Secure.getStringForUser(
mContext.getContentResolver(),
Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle);
@@ -430,6 +445,7 @@ public class VoiceInteractionManagerService extends SystemService {
if (!mSafeMode) {
String curService = Settings.Secure.getStringForUser(
mResolver, Settings.Secure.VOICE_INTERACTION_SERVICE, mCurUser);
+ if (DEBUG) Log.d(TAG, "Service for user " + mCurUser + ": " + curService);
ComponentName serviceComponent = null;
ServiceInfo serviceInfo = null;
if (curService != null && !curService.isEmpty()) {
@@ -466,7 +482,8 @@ public class VoiceInteractionManagerService extends SystemService {
}
if (hasComponent) {
setImplLocked(new VoiceInteractionManagerServiceImpl(mContext,
- UiThread.getHandler(), this, mCurUser, serviceComponent));
+ UiThread.getHandler(), this, mCurUser, serviceComponent,
+ mAllowInstantService));
mImpl.startLocked();
} else {
setImplLocked(null);
@@ -1227,16 +1244,26 @@ public class VoiceInteractionManagerService extends SystemService {
synchronized (this) {
pw.println("VOICE INTERACTION MANAGER (dumpsys voiceinteraction)");
pw.println(" mEnableService: " + mEnableService);
+ pw.println(" mAllowInstantService: " + mAllowInstantService);
if (mImpl == null) {
pw.println(" (No active implementation)");
return;
}
mImpl.dumpLocked(fd, pw, args);
}
+
mSoundTriggerInternal.dump(fd, pw, args);
}
@Override
+ public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+ String[] args, ShellCallback callback, ResultReceiver resultReceiver)
+ throws RemoteException {
+ new VoiceInteractionManagerServiceShellCommand(VoiceInteractionManagerService.this)
+ .exec(this, in, out, err, args, callback, resultReceiver);
+ }
+
+ @Override
public void setUiHints(IVoiceInteractionService service, Bundle hints) {
synchronized (this) {
enforceIsCurrentVoiceInteractionService(service);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 2a5b70bf77f2..4881ade954c1 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -29,7 +29,6 @@ import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.IActivityManager;
import android.app.IActivityTaskManager;
-import android.app.IApplicationThread;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -48,7 +47,6 @@ import android.service.voice.IVoiceInteractionService;
import android.service.voice.IVoiceInteractionSession;
import android.service.voice.VoiceInteractionService;
import android.service.voice.VoiceInteractionServiceInfo;
-import android.util.Pair;
import android.util.PrintWriterPrinter;
import android.util.Slog;
import android.view.IWindowManager;
@@ -82,6 +80,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
final VoiceInteractionServiceInfo mInfo;
final ComponentName mSessionComponentName;
final IWindowManager mIWindowManager;
+ final boolean mAllowInstant;
boolean mBound = false;
IVoiceInteractionService mService;
@@ -127,7 +126,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
VoiceInteractionManagerServiceImpl(Context context, Handler handler,
VoiceInteractionManagerService.VoiceInteractionManagerServiceStub stub,
- int userHandle, ComponentName service) {
+ int userHandle, ComponentName service, boolean allowInstant) {
mContext = context;
mHandler = handler;
mServiceStub = stub;
@@ -135,6 +134,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
mComponent = service;
mAm = ActivityManager.getService();
mAtm = ActivityTaskManager.getService();
+ mAllowInstant = allowInstant;
VoiceInteractionServiceInfo info;
try {
info = new VoiceInteractionServiceInfo(context.getPackageManager(), service, mUser);
@@ -169,7 +169,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
if (mActiveSession == null) {
mActiveSession = new VoiceInteractionSessionConnection(mServiceStub,
mSessionComponentName, mUser, mContext, this,
- mInfo.getServiceInfo().applicationInfo.uid, mHandler);
+ mInfo.getServiceInfo().applicationInfo.uid, mHandler, mAllowInstant);
}
List<IBinder> activityTokens = null;
if (activityToken != null) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java
new file mode 100644
index 000000000000..de1191fe842a
--- /dev/null
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.voiceinteraction;
+
+import android.annotation.NonNull;
+import android.os.ShellCommand;
+
+import java.io.PrintWriter;
+
+final class VoiceInteractionManagerServiceShellCommand extends ShellCommand {
+
+ private final VoiceInteractionManagerService mService;
+
+ VoiceInteractionManagerServiceShellCommand(@NonNull VoiceInteractionManagerService service) {
+ this.mService = service;
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(cmd);
+ }
+ final PrintWriter pw = getOutPrintWriter();
+ switch (cmd) {
+ case "set bind-instant-service-allowed":
+ case "set":
+ return requestSet(pw);
+ default:
+ return handleDefaultCommands(cmd);
+ }
+ }
+
+ @Override
+ public void onHelp() {
+ try (PrintWriter pw = getOutPrintWriter();) {
+ pw.println("VoiceInteraction Service (voiceinteraction) commands:");
+ pw.println(" help");
+ pw.println(" Prints this help text.");
+ pw.println("");
+ pw.println(" set bind-instant-service-allowed [true | false]");
+ pw.println(" Sets whether binding to services provided by instant apps is allowed");
+ pw.println("");
+ }
+ }
+
+ private int requestSet(@NonNull PrintWriter pw) {
+ final String what = getNextArgRequired();
+
+ switch(what) {
+ case "bind-instant-service-allowed":
+ return setBindInstantService(pw);
+ default:
+ pw.println("Invalid set: " + what);
+ return -1;
+ }
+ }
+
+ private int setBindInstantService(@NonNull PrintWriter pw) {
+ final String mode = getNextArgRequired();
+ switch (mode.toLowerCase()) {
+ case "true":
+ mService.setAllowInstantService(true);
+ return 0;
+ case "false":
+ mService.setAllowInstantService(false);
+ return 0;
+ default:
+ pw.println("Invalid mode: " + mode);
+ return -1;
+ }
+ }
+}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index f16dec6fb670..3c470449dc2c 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -138,7 +138,8 @@ final class VoiceInteractionSessionConnection implements ServiceConnection,
};
public VoiceInteractionSessionConnection(Object lock, ComponentName component, int user,
- Context context, Callback callback, int callingUid, Handler handler) {
+ Context context, Callback callback, int callingUid, Handler handler,
+ boolean allowInstant) {
mLock = lock;
mSessionComponentName = component;
mUser = user;
@@ -159,10 +160,13 @@ final class VoiceInteractionSessionConnection implements ServiceConnection,
mPermissionOwner = permOwner;
mBindIntent = new Intent(VoiceInteractionService.SERVICE_INTERFACE);
mBindIntent.setComponent(mSessionComponentName);
- mBound = mContext.bindServiceAsUser(mBindIntent, this,
- Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY
- | Context.BIND_ALLOW_OOM_MANAGEMENT
- | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS, new UserHandle(mUser));
+ int flags = Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY
+ | Context.BIND_ALLOW_OOM_MANAGEMENT
+ | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS;
+ if (allowInstant) {
+ flags |= Context.BIND_ALLOW_INSTANT;
+ }
+ mBound = mContext.bindServiceAsUser(mBindIntent, this, flags, new UserHandle(mUser));
if (mBound) {
try {
mIWindowManager.addWindowToken(mToken, TYPE_VOICE_INTERACTION, DEFAULT_DISPLAY);
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 49b34b38c663..c66e92b5e099 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -1937,6 +1937,8 @@ public abstract class ConnectionService extends Service {
return;
}
+ String callingPackage = getOpPackageName();
+
mAdapter.queryRemoteConnectionServices(new RemoteServiceCallback.Stub() {
@Override
public void onResult(
@@ -1965,7 +1967,7 @@ public abstract class ConnectionService extends Service {
}
}.prepare());
}
- });
+ }, callingPackage);
}
/**
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapter.java b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
index 6c3f4f34ff2d..3acd83a41396 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapter.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
@@ -316,11 +316,11 @@ final class ConnectionServiceAdapter implements DeathRecipient {
/**
* Retrieves a list of remote connection services usable to place calls.
*/
- void queryRemoteConnectionServices(RemoteServiceCallback callback) {
+ void queryRemoteConnectionServices(RemoteServiceCallback callback, String callingPackage) {
// Only supported when there is only one adapter.
if (mAdapters.size() == 1) {
try {
- mAdapters.iterator().next().queryRemoteConnectionServices(callback,
+ mAdapters.iterator().next().queryRemoteConnectionServices(callback, callingPackage,
Log.getExternalSession());
} catch (RemoteException e) {
Log.e(this, e, "Exception trying to query for remote CSs");
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
index f99b218bd9b9..b28158913dc4 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
@@ -186,8 +186,13 @@ final class ConnectionServiceAdapterServant {
break;
}
case MSG_QUERY_REMOTE_CALL_SERVICES:
- mDelegate.queryRemoteConnectionServices((RemoteServiceCallback) msg.obj,
- null /*Session.Info*/);
+ SomeArgs args2 = (SomeArgs) msg.obj;
+ try {
+ mDelegate.queryRemoteConnectionServices((RemoteServiceCallback) args2.arg1,
+ (String) args2.arg2, null /*Session.Info*/);
+ } finally {
+ args2.recycle();
+ }
break;
case MSG_SET_VIDEO_STATE:
mDelegate.setVideoState((String) msg.obj, msg.arg1, null /*Session.Info*/);
@@ -468,7 +473,10 @@ final class ConnectionServiceAdapterServant {
@Override
public void queryRemoteConnectionServices(RemoteServiceCallback callback,
- Session.Info sessionInfo) {
+ String callingPackage, Session.Info sessionInfo) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callback;
+ args.arg2 = callingPackage;
mHandler.obtainMessage(MSG_QUERY_REMOTE_CALL_SERVICES, callback).sendToTarget();
}
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index 744544eb01f1..1e73bd61d68e 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -288,7 +288,7 @@ final class RemoteConnectionService {
@Override
public void queryRemoteConnectionServices(RemoteServiceCallback callback,
- Session.Info sessionInfo) {
+ String callingPackage, Session.Info sessionInfo) {
// Not supported from remote connection service.
}
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
index 76ac88e9fbaa..9cf098c75177 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
@@ -78,7 +78,8 @@ oneway interface IConnectionServiceAdapter {
void onPostDialChar(String callId, char nextChar, in Session.Info sessionInfo);
- void queryRemoteConnectionServices(RemoteServiceCallback callback, in Session.Info sessionInfo);
+ void queryRemoteConnectionServices(RemoteServiceCallback callback, String callingPackage,
+ in Session.Info sessionInfo);
void setVideoProvider(String callId, IVideoProvider videoProvider, in Session.Info sessionInfo);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index b722b79240dd..dab1e6f4abde 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2446,7 +2446,21 @@ public class TelephonyManager {
* @return the NETWORK_TYPE_xxxx for current data connection.
*/
public @NetworkType int getNetworkType() {
- return getDataNetworkType();
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getNetworkType();
+ } else {
+ // This can happen when the ITelephony interface is not up yet.
+ return NETWORK_TYPE_UNKNOWN;
+ }
+ } catch(RemoteException ex) {
+ // This shouldn't happen in the normal case
+ return NETWORK_TYPE_UNKNOWN;
+ } catch (NullPointerException ex) {
+ // This could happen before phone restarts due to crashing
+ return NETWORK_TYPE_UNKNOWN;
+ }
}
/**
@@ -2477,9 +2491,23 @@ public class TelephonyManager {
* @hide
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+ @UnsupportedAppUsage
public int getNetworkType(int subId) {
- return getDataNetworkType(subId);
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getNetworkTypeForSubscriber(subId, getOpPackageName());
+ } else {
+ // This can happen when the ITelephony interface is not up yet.
+ return NETWORK_TYPE_UNKNOWN;
+ }
+ } catch (RemoteException ex) {
+ // This shouldn't happen in the normal case
+ return NETWORK_TYPE_UNKNOWN;
+ } catch (NullPointerException ex) {
+ // This could happen before phone restarts due to crashing
+ return NETWORK_TYPE_UNKNOWN;
+ }
}
/**
diff --git a/telephony/java/android/telephony/ims/ImsSsInfo.java b/telephony/java/android/telephony/ims/ImsSsInfo.java
index 18e7530a790e..9912eced0543 100644
--- a/telephony/java/android/telephony/ims/ImsSsInfo.java
+++ b/telephony/java/android/telephony/ims/ImsSsInfo.java
@@ -250,6 +250,8 @@ public final class ImsSsInfo implements Parcelable {
out.writeInt(mStatus);
out.writeString(mIcbNum);
out.writeInt(mProvisionStatus);
+ out.writeInt(mClirInterrogationStatus);
+ out.writeInt(mClirOutgoingState);
}
@Override
@@ -273,6 +275,8 @@ public final class ImsSsInfo implements Parcelable {
mStatus = in.readInt();
mIcbNum = in.readString();
mProvisionStatus = in.readInt();
+ mClirInterrogationStatus = in.readInt();
+ mClirOutgoingState = in.readInt();
}
public static final @android.annotation.NonNull Creator<ImsSsInfo> CREATOR =