diff options
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 = |