diff options
90 files changed, 1815 insertions, 502 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index ca04536af4c0..4e1bcc1bcfb8 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -123,7 +123,6 @@ import android.provider.Settings; import android.renderscript.RenderScriptCacheDir; import android.security.NetworkSecurityPolicy; import android.security.net.config.NetworkSecurityConfigProvider; -import android.service.voice.VoiceInteractionSession; import android.system.ErrnoException; import android.system.OsConstants; import android.system.StructStat; @@ -5627,6 +5626,16 @@ public final class ActivityThread extends ClientTransactionHandler { } } + /** + * Updates the application info. + * + * This only works in the system process. Must be called on the main thread. + */ + public void handleSystemApplicationInfoChanged(@NonNull ApplicationInfo ai) { + Preconditions.checkState(mSystemThread, "Must only be called in the system process"); + handleApplicationInfoChanged(ai); + } + @VisibleForTesting(visibility = PACKAGE) public void handleApplicationInfoChanged(@NonNull final ApplicationInfo ai) { // Updates triggered by package installation go through a package update diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index 66ddf21790fe..6178b2bf5817 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -1033,6 +1033,8 @@ public class Binder implements IBinder { Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e); } } else { + // Clear the parcel before writing the exception + reply.setDataSize(0); reply.setDataPosition(0); reply.writeException(e); } 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/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/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/util/MemoryIntArray.java b/core/java/android/util/MemoryIntArray.java index 80b16075cdf6..7d287e38ba86 100644 --- a/core/java/android/util/MemoryIntArray.java +++ b/core/java/android/util/MemoryIntArray.java @@ -175,12 +175,10 @@ public final class MemoryIntArray implements Parcelable, Closeable { @Override public void writeToParcel(Parcel parcel, int flags) { - ParcelFileDescriptor pfd = ParcelFileDescriptor.adoptFd(mFd); - try { - // Don't let writing to a parcel to close our fd - plz - parcel.writeParcelable(pfd, flags & ~Parcelable.PARCELABLE_WRITE_RETURN_VALUE); - } finally { - pfd.detachFd(); + try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromFd(mFd)) { + parcel.writeParcelable(pfd, flags); + } catch (IOException ex) { + throw new RuntimeException(ex); } } diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java index 616c4b51eca0..b7dd88bcedc6 100644 --- a/core/java/android/widget/TextClock.java +++ b/core/java/android/widget/TextClock.java @@ -175,6 +175,9 @@ public class TextClock extends TextView { if (mTimeZone == null && Intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) { final String timeZone = intent.getStringExtra("time-zone"); createTime(timeZone); + } else if (!mShouldRunTicker && (Intent.ACTION_TIME_TICK.equals(intent.getAction()) + || Intent.ACTION_TIME_CHANGED.equals(intent.getAction()))) { + return; } onTimeChanged(); } @@ -642,12 +645,9 @@ public class TextClock extends TextView { */ @UnsupportedAppUsage private void onTimeChanged() { - // mShouldRunTicker always equals the last value passed into onVisibilityAggregated - if (mShouldRunTicker) { - mTime.setTimeInMillis(System.currentTimeMillis()); - setText(DateFormat.format(mFormat, mTime)); - setContentDescription(DateFormat.format(mDescFormat, mTime)); - } + mTime.setTimeInMillis(System.currentTimeMillis()); + setText(DateFormat.format(mFormat, mTime)); + setContentDescription(DateFormat.format(mDescFormat, mTime)); } /** @hide */ diff --git a/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java b/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java index 3fddfc8a4602..04ad7e9ee8a7 100644 --- a/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java +++ b/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java @@ -99,9 +99,13 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator } List<AppTarget> appTargets = new ArrayList<>(); for (ResolvedComponentInfo target : targets) { - appTargets.add(new AppTarget.Builder(new AppTargetId(target.name.flattenToString())) - .setTarget(target.name.getPackageName(), mUser) - .setClassName(target.name.getClassName()).build()); + appTargets.add( + new AppTarget.Builder( + new AppTargetId(target.name.flattenToString()), + target.name.getPackageName(), + mUser) + .setClassName(target.name.getClassName()) + .build()); } mAppPredictor.sortTargets(appTargets, Executors.newSingleThreadExecutor(), sortedAppTargets -> { 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/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index e524216d5c55..ad99cce6132c 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -314,6 +314,8 @@ applications that come with the platform <permission name="android.permission.SET_WALLPAPER" /> <permission name="android.permission.SET_WALLPAPER_COMPONENT" /> <permission name="android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE" /> + <!-- Permission required to test ExplicitHealthCheckServiceImpl. --> + <permission name="android.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE"/> </privapp-permissions> <privapp-permissions package="com.android.statementservice"> diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java index 297153d09eca..32f2fc22acad 100644 --- a/graphics/java/android/graphics/drawable/GradientDrawable.java +++ b/graphics/java/android/graphics/drawable/GradientDrawable.java @@ -1930,11 +1930,11 @@ public class GradientDrawable extends Drawable { public float[] mTempPositions; // no need to copy @UnsupportedAppUsage public float[] mPositions; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917) + @UnsupportedAppUsage(trackingBug = 124050917) public int mStrokeWidth = -1; // if >= 0 use stroking. - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917) + @UnsupportedAppUsage(trackingBug = 124050917) public float mStrokeDashWidth = 0.0f; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917) + @UnsupportedAppUsage(trackingBug = 124050917) public float mStrokeDashGap = 0.0f; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917) public float mRadius = 0.0f; // use this if mRadiusArray is null 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/res/drawable/notification_handle_bar.xml b/packages/CarSystemUI/res/drawable/notification_handle_bar.xml new file mode 100644 index 000000000000..5ed7499952ed --- /dev/null +++ b/packages/CarSystemUI/res/drawable/notification_handle_bar.xml @@ -0,0 +1,26 @@ +<?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. +--> +<ripple + xmlns:android="http://schemas.android.com/apk/res/android" + android:color="@android:color/white"> + <item> + <shape android:shape="rectangle"> + <corners android:radius="@dimen/clear_all_button_radius"/> + <solid android:color="@android:color/white"/> + </shape> + </item> +</ripple>
\ No newline at end of file diff --git a/packages/CarSystemUI/res/layout/notification_center_activity.xml b/packages/CarSystemUI/res/layout/notification_center_activity.xml index 5c915b874dde..55b0d875de41 100644 --- a/packages/CarSystemUI/res/layout/notification_center_activity.xml +++ b/packages/CarSystemUI/res/layout/notification_center_activity.xml @@ -23,24 +23,27 @@ android:background="@color/notification_shade_background_color"> <View - android:id="@+id/glass_pane" - android:layout_width="match_parent" - android:layout_height="match_parent" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent" - android:translationZ="2dp" - /> + android:id="@+id/glass_pane" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:translationZ="2dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + /> <androidx.recyclerview.widget.RecyclerView android:id="@+id/notifications" android:layout_width="0dp" android:layout_height="0dp" android:orientation="vertical" - app:layout_constraintTop_toTopOf="parent" + android:paddingStart="@dimen/notification_shade_list_padding_bottom" app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent"/> + app:layout_constraintTop_toTopOf="parent"/> + + <include layout="@layout/notification_handle_bar"/> </com.android.car.notification.CarNotificationView> diff --git a/packages/CarSystemUI/res/layout/notification_handle_bar.xml b/packages/CarSystemUI/res/layout/notification_handle_bar.xml new file mode 100644 index 000000000000..99c3a02091db --- /dev/null +++ b/packages/CarSystemUI/res/layout/notification_handle_bar.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** +** 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. +*/ +--> + +<merge xmlns:android="http://schemas.android.com/apk/res/android"> + <View + android:id="@+id/handle_bar" + android:layout_width="match_parent" + android:layout_height="@dimen/notification_shade_handle_bar_height" + android:layout_marginBottom="@dimen/notification_shade_handle_bar_margin_bottom" + android:layout_marginEnd="@dimen/notification_shade_handle_bar_margin_start" + android:layout_marginStart="@dimen/notification_shade_handle_bar_margin_end" + android:layout_marginTop="@dimen/notification_shade_handle_bar_margin_top" + android:background="@drawable/notification_handle_bar"/> +</merge>
\ No newline at end of file diff --git a/packages/CarSystemUI/res/values/colors.xml b/packages/CarSystemUI/res/values/colors.xml index 83ec3514c01a..0d69fbba5b63 100644 --- a/packages/CarSystemUI/res/values/colors.xml +++ b/packages/CarSystemUI/res/values/colors.xml @@ -34,7 +34,7 @@ <drawable name="system_bar_background">@color/status_bar_background_color</drawable> <!-- The background color of the notification shade --> - <color name="notification_shade_background_color">#99000000</color> + <color name="notification_shade_background_color">#DD000000</color> <!-- The color of the dividing line between grouped notifications. --> <color name="notification_divider_color">@*android:color/notification_action_list</color> diff --git a/packages/CarSystemUI/res/values/dimens.xml b/packages/CarSystemUI/res/values/dimens.xml index 8789c8a924b3..0358357b9c1a 100644 --- a/packages/CarSystemUI/res/values/dimens.xml +++ b/packages/CarSystemUI/res/values/dimens.xml @@ -88,4 +88,14 @@ <dimen name="car_volume_item_divider_width">1dp</dimen> <dimen name="car_volume_item_divider_margin_end">@*android:dimen/car_padding_4</dimen> <dimen name="car_volume_item_corner_radius">@*android:dimen/car_radius_3</dimen> + + <!-- Car notification shade--> + <dimen name="notification_shade_handle_bar_height">10dp</dimen> + <dimen name="notification_shade_handle_bar_radius">20dp</dimen> + <dimen name="notification_shade_handle_bar_margin_start">500dp</dimen> + <dimen name="notification_shade_handle_bar_margin_end">500dp</dimen> + <dimen name="notification_shade_handle_bar_margin_top">20dp</dimen> + <dimen name="notification_shade_handle_bar_margin_bottom">10dp</dimen> + <dimen name="notification_shade_list_padding_bottom">0dp</dimen> + </resources> 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 9b6ab06c4708..54e468eed75d 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -131,6 +131,8 @@ public class CarStatusBar extends StatusBar implements // The container for the notifications. private CarNotificationView mNotificationView; private RecyclerView mNotificationList; + // The handler bar view at the bottom of notification shade. + private View mHandleBar; // The controller for the notification view. private NotificationViewController mNotificationViewController; // The state of if the notification list is currently showing the bottom. @@ -464,6 +466,7 @@ public class CarStatusBar extends StatusBar implements mNotificationView = mStatusBarWindow.findViewById(R.id.notification_view); View glassPane = mStatusBarWindow.findViewById(R.id.glass_pane); + mHandleBar = mStatusBarWindow.findViewById(R.id.handle_bar); mNotificationView.setClickHandlerFactory(mNotificationClickHandlerFactory); mNotificationView.setNotificationDataManager(mNotificationDataManager); @@ -521,7 +524,7 @@ public class CarStatusBar extends StatusBar implements boolean handled = closeGestureDetector.onTouchEvent(event); boolean isTracking = mIsTracking; - Rect rect = mNotificationList.getClipBounds(); + Rect rect = mNotificationView.getClipBounds(); float clippedHeight = 0; if (rect != null) { clippedHeight = rect.bottom; @@ -609,7 +612,7 @@ public class CarStatusBar extends StatusBar implements to = mNotificationView.getHeight(); } - Rect rect = mNotificationList.getClipBounds(); + Rect rect = mNotificationView.getClipBounds(); if (rect != null) { float from = rect.bottom; animate(from, to, velocity, isClosing); @@ -653,7 +656,7 @@ public class CarStatusBar extends StatusBar implements if (isClosing) { mStatusBarWindowController.setPanelVisible(false); mNotificationView.setVisibility(View.INVISIBLE); - mNotificationList.setClipBounds(null); + mNotificationView.setClipBounds(null); mNotificationViewController.setIsInForeground(false); // let the status bar know that the panel is closed setPanelExpanded(false); @@ -1012,8 +1015,12 @@ public class CarStatusBar extends StatusBar implements Rect clipBounds = new Rect(); clipBounds.set(0, 0, mNotificationView.getWidth(), height); // Sets the clip region on the notification list view. - mNotificationList.setClipBounds(clipBounds); - + mNotificationView.setClipBounds(clipBounds); + if (mHandleBar != null) { + ViewGroup.MarginLayoutParams lp = + (ViewGroup.MarginLayoutParams) mHandleBar.getLayoutParams(); + mHandleBar.setTranslationY(height - mHandleBar.getHeight() - lp.bottomMargin); + } if (mNotificationView.getHeight() > 0) { // Calculates the alpha value for the background based on how much of the notification // shade is visible to the user. When the notification shade is completely open then @@ -1095,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; @@ -1134,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/watchdog/ExplicitHealthCheckServiceImpl.java b/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImpl.java index 765e9f95216d..670b419a8aa3 100644 --- a/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImpl.java +++ b/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImpl.java @@ -39,9 +39,9 @@ public final class ExplicitHealthCheckServiceImpl extends ExplicitHealthCheckSer // TODO: Add build dependency on NetworkStack stable AIDL so we can stop hard coding class name private static final String NETWORK_STACK_CONNECTOR_CLASS = "android.net.INetworkStackConnector"; - private static final String PROPERTY_WATCHDOG_REQUEST_TIMEOUT_MILLIS = + public static final String PROPERTY_WATCHDOG_REQUEST_TIMEOUT_MILLIS = "watchdog_request_timeout_millis"; - private static final long DEFAULT_REQUEST_TIMEOUT_MILLIS = + public static final long DEFAULT_REQUEST_TIMEOUT_MILLIS = TimeUnit.HOURS.toMillis(1); // Modified only #onCreate, using concurrent collection to ensure thread visibility private final Map<String, ExplicitHealthChecker> mSupportedCheckers = new ConcurrentHashMap<>(); diff --git a/packages/ExtServices/tests/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImplTest.java b/packages/ExtServices/tests/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImplTest.java new file mode 100644 index 000000000000..a9cb63e2a200 --- /dev/null +++ b/packages/ExtServices/tests/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImplTest.java @@ -0,0 +1,201 @@ +/* + * 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 android.ext.services.watchdog; + +import static android.service.watchdog.ExplicitHealthCheckService.EXTRA_REQUESTED_PACKAGES; +import static android.service.watchdog.ExplicitHealthCheckService.EXTRA_SUPPORTED_PACKAGES; +import static android.service.watchdog.ExplicitHealthCheckService.PackageConfig; + +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeFalse; + +import android.Manifest; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.os.RemoteCallback; +import android.service.watchdog.ExplicitHealthCheckService; +import android.service.watchdog.IExplicitHealthCheckService; + +import androidx.test.InstrumentationRegistry; +import androidx.test.rule.ServiceTestRule; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; + +/** + * Contains the base tests that does not rely on the specific algorithm implementation. + */ +public class ExplicitHealthCheckServiceImplTest { + private static final String NETWORK_STACK_CONNECTOR_CLASS = + "android.net.INetworkStackConnector"; + + private final Context mContext = InstrumentationRegistry.getContext(); + private IExplicitHealthCheckService mService; + private String mNetworkStackPackageName; + + @Rule + public ServiceTestRule mServiceTestRule; + + @Before + public void setUp() throws Exception { + InstrumentationRegistry + .getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity( + Manifest.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE); + + mServiceTestRule = new ServiceTestRule(); + mService = IExplicitHealthCheckService.Stub.asInterface( + mServiceTestRule.bindService(getExtServiceIntent())); + mNetworkStackPackageName = getNetworkStackPackage(); + assumeFalse(mNetworkStackPackageName == null); + } + + @After + public void tearDown() { + InstrumentationRegistry + .getInstrumentation() + .getUiAutomation() + .dropShellPermissionIdentity(); + } + + @Test + public void testHealthCheckSupportedPackage() throws Exception { + List<PackageConfig> supportedPackages = new ArrayList<>(); + CountDownLatch latch = new CountDownLatch(1); + + mService.getSupportedPackages(new RemoteCallback(result -> { + supportedPackages.addAll(result.getParcelableArrayList(EXTRA_SUPPORTED_PACKAGES)); + latch.countDown(); + })); + latch.await(); + + // TODO: Support DeviceConfig changes for the health check timeout + assertThat(supportedPackages).hasSize(1); + assertThat(supportedPackages.get(0).getPackageName()) + .isEqualTo(mNetworkStackPackageName); + assertThat(supportedPackages.get(0).getHealthCheckTimeoutMillis()) + .isEqualTo(ExplicitHealthCheckServiceImpl.DEFAULT_REQUEST_TIMEOUT_MILLIS); + } + + @Test + public void testHealthCheckRequests() throws Exception { + List<String> requestedPackages = new ArrayList<>(); + CountDownLatch latch1 = new CountDownLatch(1); + CountDownLatch latch2 = new CountDownLatch(1); + CountDownLatch latch3 = new CountDownLatch(1); + + // Initially, no health checks requested + mService.getRequestedPackages(new RemoteCallback(result -> { + requestedPackages.addAll(result.getParcelableArrayList(EXTRA_REQUESTED_PACKAGES)); + latch1.countDown(); + })); + + // Verify that no health checks requested + latch1.await(); + assertThat(requestedPackages).isEmpty(); + + // Then request health check + mService.request(mNetworkStackPackageName); + + // Verify that health check is requested for network stack + mService.getRequestedPackages(new RemoteCallback(result -> { + requestedPackages.addAll(result.getParcelableArrayList(EXTRA_REQUESTED_PACKAGES)); + latch2.countDown(); + })); + latch2.await(); + assertThat(requestedPackages).hasSize(1); + assertThat(requestedPackages.get(0)).isEqualTo(mNetworkStackPackageName); + + // Then cancel health check + requestedPackages.clear(); + mService.cancel(mNetworkStackPackageName); + + // Verify that health check is cancelled for network stack + mService.getRequestedPackages(new RemoteCallback(result -> { + requestedPackages.addAll(result.getParcelableArrayList(EXTRA_REQUESTED_PACKAGES)); + latch3.countDown(); + })); + latch3.await(); + assertThat(requestedPackages).isEmpty(); + } + + private String getNetworkStackPackage() { + Intent intent = new Intent(NETWORK_STACK_CONNECTOR_CLASS); + ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); + if (comp != null) { + return comp.getPackageName(); + } else { + // On Go devices, or any device that does not ship the network stack module. + // The network stack will live in system_server process, so no need to monitor. + return null; + } + } + + private Intent getExtServiceIntent() { + ComponentName component = getExtServiceComponentNameLocked(); + if (component == null) { + fail("Health check service not found"); + } + Intent intent = new Intent(); + intent.setComponent(component); + return intent; + } + + private ComponentName getExtServiceComponentNameLocked() { + ServiceInfo serviceInfo = getExtServiceInfoLocked(); + if (serviceInfo == null) { + return null; + } + + final ComponentName name = new ComponentName(serviceInfo.packageName, serviceInfo.name); + if (!Manifest.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE + .equals(serviceInfo.permission)) { + return null; + } + return name; + } + + private ServiceInfo getExtServiceInfoLocked() { + final String packageName = + mContext.getPackageManager().getServicesSystemSharedLibraryPackageName(); + if (packageName == null) { + return null; + } + + final Intent intent = new Intent(ExplicitHealthCheckService.SERVICE_INTERFACE); + intent.setPackage(packageName); + final ResolveInfo resolveInfo = mContext.getPackageManager().resolveService(intent, + PackageManager.GET_SERVICES | PackageManager.GET_META_DATA); + if (resolveInfo == null || resolveInfo.serviceInfo == null) { + return null; + } + return resolveInfo.serviceInfo; + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/Estimate.kt b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/Estimate.kt index 786139ffc790..b2e75ea6867f 100644 --- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/Estimate.kt +++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/Estimate.kt @@ -77,5 +77,17 @@ class Estimate( Settings.Global.putLong(resolver, Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME, System.currentTimeMillis()) } + + /** + * Returns when the estimate was last updated as an Instant + */ + @JvmStatic + fun getLastCacheUpdateTime(context: Context): Instant { + return Instant.ofEpochMilli( + Settings.Global.getLong( + context.contentResolver, + Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME, + -1)) + } } } 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/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 0fa415522f6b..aba88ab14387 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -198,6 +198,9 @@ <!-- Permission required to test ContentResolver caching. --> <uses-permission android:name="android.permission.CACHE_CONTENT" /> + <!-- Permission required to test ExplicitHealthCheckServiceImpl. --> + <uses-permission android:name="android.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE" /> + <application android:label="@string/app_label" android:defaultToDeviceProtectedStorage="true" android:directBootAware="true"> 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/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml index 087e0bd8089f..4b672ee0733f 100644 --- a/packages/SystemUI/res/layout/notification_info.xml +++ b/packages/SystemUI/res/layout/notification_info.xml @@ -228,7 +228,7 @@ asked for it --> android:focusable="true"> <ImageView android:id="@+id/alert_icon" - android:src="@drawable/ic_notification_interruptive" + android:src="@drawable/ic_notifications_alert" android:background="@android:color/transparent" android:layout_gravity="center" android:layout_width="wrap_content" @@ -249,6 +249,7 @@ asked for it --> android:text="@string/notification_alert_title"/> <TextView android:id="@+id/alert_summary" + android:visibility="gone" android:paddingTop="@dimen/notification_importance_button_padding" android:text="@string/notification_channel_summary_default" android:layout_width="match_parent" @@ -271,7 +272,7 @@ asked for it --> android:focusable="true"> <ImageView android:id="@+id/silence_icon" - android:src="@drawable/ic_notification_gentle" + android:src="@drawable/ic_notifications_silence" android:background="@android:color/transparent" android:layout_gravity="center" android:layout_width="wrap_content" @@ -292,6 +293,7 @@ asked for it --> android:text="@string/notification_silence_title"/> <TextView android:id="@+id/silence_summary" + android:visibility="gone" android:paddingTop="@dimen/notification_importance_button_padding" android:text="@string/notification_channel_summary_default" android:layout_width="match_parent" diff --git a/packages/SystemUI/res/layout/quick_settings_header_info.xml b/packages/SystemUI/res/layout/quick_settings_header_info.xml index d0783a047895..3582d391271c 100644 --- a/packages/SystemUI/res/layout/quick_settings_header_info.xml +++ b/packages/SystemUI/res/layout/quick_settings_header_info.xml @@ -14,7 +14,7 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License --> -<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/header_text_container" android:layout_width="match_parent" android:layout_height="@dimen/qs_header_tooltip_height" @@ -23,19 +23,12 @@ android:paddingEnd="@dimen/status_bar_padding_end" android:theme="@style/QSHeaderTheme"> - <LinearLayout - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:layout_gravity="start|center_vertical" - android:gravity="center_vertical"> - - <LinearLayout + <com.android.systemui.qs.QSHeaderInfoLayout android:id="@+id/status_container" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:layout_gravity="start|center_vertical" + android:layout_width="match_parent" android:layout_weight="1" - android:gravity="center_vertical" > + android:layout_height="match_parent" + android:gravity="start" > <LinearLayout android:id = "@+id/alarm_container" @@ -98,21 +91,14 @@ android:textAppearance="@style/TextAppearance.QS.Status" android:visibility="gone"/> </LinearLayout> - </LinearLayout> - - <View - android:minWidth="@dimen/qs_status_separator" - android:layout_width="0dp" - android:layout_height="match_parent" - android:layout_weight="1"/> - + </com.android.systemui.qs.QSHeaderInfoLayout> <include layout="@layout/qs_carrier_group" android:id="@+id/carrier_group" android:layout_width="wrap_content" android:layout_height="match_parent" + android:layout_marginStart="@dimen/qs_status_separator" android:layout_gravity="end|center_vertical" android:focusable="false"/> - </LinearLayout> -</FrameLayout> +</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 2b210064023b..0c3c597a7b3a 100644 --- a/packages/SystemUI/res/layout/status_bar_notification_section_header.xml +++ b/packages/SystemUI/res/layout/status_bar_notification_section_header.xml @@ -43,7 +43,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" - android:layout_marginLeft="@dimen/notification_section_header_padding_left" + android:layout_marginStart="@dimen/notification_section_header_padding_left" android:text="@string/notification_section_header_gentle" android:textSize="12sp" android:textColor="@color/notification_section_header_label_color" @@ -52,9 +52,10 @@ android:id="@+id/btn_clear_all" android:layout_width="@dimen/notification_section_header_height" android:layout_height="@dimen/notification_section_header_height" - android:layout_marginRight="4dp" + 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 c95dbfeac17e..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> @@ -1118,10 +1121,10 @@ <string name="manage_notifications_text">Manage</string> <!-- Section title for notifications that do not vibrate or make noise. [CHAR LIMIT=40] --> - <string name="notification_section_header_gentle">Gentle notifications</string> + <string name="notification_section_header_gentle">Silent notifications</string> <!-- Content description for accessibility: Tapping this button will dismiss all gentle notifications [CHAR LIMIT=NONE] --> - <string name="accessibility_notification_section_header_gentle_clear_all">Clear all gentle notifications</string> + <string name="accessibility_notification_section_header_gentle_clear_all">Clear all silent notifications</string> <!-- The text to show in the notifications shade when dnd is suppressing notifications. [CHAR LIMIT=100] --> <string name="dnd_suppressing_shade_text">Notifications paused by Do Not Disturb</string> @@ -1656,13 +1659,13 @@ <string name="inline_minimize_button">Minimize</string> <!-- Notification inline controls: button to show notifications silently, without alerting the user [CHAR_LIMIT=35] --> - <string name="inline_silent_button_silent">Gentle</string> + <string name="inline_silent_button_silent">Silent</string> <!-- Notification inline controls: button to continue showing notifications silently [CHAR_LIMIT=35] --> <string name="inline_silent_button_stay_silent">Stay silent</string> <!-- Notification inline controls: button to make notifications alert the user [CHAR_LIMIT=35] --> - <string name="inline_silent_button_alert">Interruptive</string> + <string name="inline_silent_button_alert">Alerting</string> <!-- Notification inline controls: button to continue alerting the user when notifications arrive [CHAR_LIMIT=35] --> <string name="inline_silent_button_keep_alerting">Keep alerting</string> @@ -2375,7 +2378,7 @@ <string name="auto_saver_title">Tap to schedule Battery Saver</string> <!-- The content of the notification to suggest enabling automatic battery saver. [CHAR LIMIT=NONE]--> - <string name="auto_saver_text">Turn on automatically when battery is at <xliff:g id="percentage">%d</xliff:g>%%</string> + <string name="auto_saver_text">Turn on when battery is likely to run out</string> <!-- An action on the notification to suggest enabling automatic battery saver: Do not turn on automatic battery saver. [CHAR LIMIT=NONE]--> <string name="no_auto_saver_action">No thanks</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/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl index b826b30f3245..77bb5141d1e0 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl @@ -73,6 +73,12 @@ interface ISystemUiProxy { void onAssistantProgress(float progress) = 12; /** + * Proxies the assistant gesture fling velocity (in pixels per millisecond) upon completion. + * Velocity is 0 for drag gestures. + */ + void onAssistantGestureCompletion(float velocity) = 18; + + /** * Start the assistant. */ void startAssistant(in Bundle bundle) = 13; 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/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java index a3b2c95fa087..51bd9f86230a 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java @@ -203,6 +203,14 @@ public class AssistManager implements ConfigurationChangedReceiver { // intentional no-op, vendor's AssistManager implementation should override if needed. } + /** Called when the user has invoked the assistant with the incoming velocity, in pixels per + * millisecond. For invocations without a velocity (e.g. slow drag), the velocity is set to + * zero. + */ + public void onAssistantGestureCompletion(float velocity) { + // intentional no-op, vendor's AssistManager implementation should override if needed. + } + public void hideAssist() { mAssistUtils.hideCurrentSession(); } 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/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java index f6cd199f076e..4982dd49fecb 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java @@ -118,6 +118,8 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { private static final String SETTINGS_ACTION_OPEN_BATTERY_SAVER_SETTING = "android.settings.BATTERY_SAVER_SETTINGS"; + public static final String BATTERY_SAVER_SCHEDULE_SCREEN_INTENT_ACTION = + "com.android.settings.BATTERY_SAVER_SCHEDULE_SETTINGS"; private static final String BATTERY_SAVER_DESCRIPTION_URL_KEY = "url"; @@ -152,16 +154,18 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { private SystemUIDialog mThermalShutdownDialog; @VisibleForTesting SystemUIDialog mUsbHighTempDialog; private BatteryStateSnapshot mCurrentBatterySnapshot; + private ActivityStarter mActivityStarter; /** */ @Inject - public PowerNotificationWarnings(Context context) { + public PowerNotificationWarnings(Context context, ActivityStarter activityStarter) { mContext = context; mNoMan = mContext.getSystemService(NotificationManager.class); mPowerMan = (PowerManager) context.getSystemService(Context.POWER_SERVICE); mKeyguard = mContext.getSystemService(KeyguardManager.class); mReceiver.init(); + mActivityStarter = activityStarter; } @Override @@ -172,7 +176,6 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { pw.print("mShowing="); pw.println(SHOWING_STRINGS[mShowing]); pw.print("mSaverConfirmation="); pw.println(mSaverConfirmation != null ? "not null" : null); pw.print("mSaverEnabledConfirmation="); - pw.println(mSaverEnabledConfirmation != null ? "not null" : null); pw.print("mHighTempWarning="); pw.println(mHighTempWarning); pw.print("mHighTempDialog="); pw.println(mHighTempDialog != null ? "not null" : null); pw.print("mThermalShutdownDialog="); @@ -305,8 +308,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { .setWhen(0) .setShowWhen(false) .setContentTitle(mContext.getString(R.string.auto_saver_title)) - .setContentText(mContext.getString(R.string.auto_saver_text, - getLowBatteryAutoTriggerDefaultLevel())); + .setContentText(mContext.getString(R.string.auto_saver_text)); nb.setContentIntent(pendingBroadcast(ACTION_ENABLE_AUTO_SAVER)); nb.setDeleteIntent(pendingBroadcast(ACTION_DISMISS_AUTO_SAVER_SUGGESTION)); nb.addAction(0, @@ -673,51 +675,14 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { return builder; } - private void showAutoSaverEnabledConfirmation() { - if (mSaverEnabledConfirmation != null) return; - - // Open the Battery Saver setting page. - final Intent actionBatterySaverSetting = - new Intent(SETTINGS_ACTION_OPEN_BATTERY_SAVER_SETTING) - .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - - final SystemUIDialog d = new SystemUIDialog(mContext); - d.setTitle(R.string.auto_saver_enabled_title); - d.setMessage(mContext.getString(R.string.auto_saver_enabled_text, - getLowBatteryAutoTriggerDefaultLevel())); - - // "Got it". Just close the dialog. Automatic battery has been enabled already. - d.setPositiveButton(R.string.auto_saver_okay_action, - (dialog, which) -> onAutoSaverEnabledConfirmationClosed()); - - // "Settings" -> Opens the battery saver settings activity. - d.setNeutralButton(R.string.open_saver_setting_action, (dialog, which) -> { - mContext.startActivity(actionBatterySaverSetting); - onAutoSaverEnabledConfirmationClosed(); - }); - d.setShowForAllUsers(true); - d.setOnDismissListener((dialog) -> onAutoSaverEnabledConfirmationClosed()); - d.show(); - mSaverEnabledConfirmation = d; - } - - private void onAutoSaverEnabledConfirmationClosed() { - mSaverEnabledConfirmation = null; - } - private void setSaverMode(boolean mode, boolean needFirstTimeWarning) { BatterySaverUtils.setPowerSaveMode(mContext, mode, needFirstTimeWarning); } - private void scheduleAutoBatterySaver() { - int autoTriggerThreshold = mContext.getResources().getInteger( - com.android.internal.R.integer.config_lowBatteryWarningLevel); - if (autoTriggerThreshold == 0) { - autoTriggerThreshold = 15; - } - - BatterySaverUtils.ensureAutoBatterySaver(mContext, autoTriggerThreshold); - showAutoSaverEnabledConfirmation(); + private void startBatterySaverSchedulePage() { + Intent intent = new Intent(BATTERY_SAVER_SCHEDULE_SCREEN_INTENT_ACTION); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + mActivityStarter.startActivity(intent, true /* dismissShade */); } private final class Receiver extends BroadcastReceiver { @@ -771,7 +736,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { dismissAutoSaverSuggestion(); } else if (ACTION_ENABLE_AUTO_SAVER.equals(action)) { dismissAutoSaverSuggestion(); - scheduleAutoBatterySaver(); + startBatterySaverSchedulePage(); } else if (ACTION_AUTO_SAVER_NO_THANKS.equals(action)) { dismissAutoSaverSuggestion(); BatterySaverUtils.suppressAutoBatterySaver(context); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHeaderInfoLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/QSHeaderInfoLayout.kt new file mode 100644 index 000000000000..86f54a97043f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/QSHeaderInfoLayout.kt @@ -0,0 +1,123 @@ +/* + * 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.qs + +import android.content.Context +import android.util.AttributeSet +import android.view.View +import android.widget.FrameLayout +import com.android.systemui.R + +/** + * Container for the Next Alarm and Ringer status texts in [QuickStatusBarHeader]. + * + * If both elements are visible, it splits the available space according to the following rules: + * * If both views add up to less than the total space, they take all the space they need. + * * If both views are larger than half the space, each view takes half the space. + * * Otherwise, the smaller view takes the space it needs and the larger one takes all remaining + * space. + */ +class QSHeaderInfoLayout @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyle: Int = 0, + defStyleRes: Int = 0 +) : FrameLayout(context, attrs, defStyle, defStyleRes) { + + private lateinit var alarmContainer: View + private lateinit var ringerContainer: View + private lateinit var statusSeparator: View + + override fun onFinishInflate() { + super.onFinishInflate() + alarmContainer = findViewById(R.id.alarm_container) + ringerContainer = findViewById(R.id.ringer_container) + statusSeparator = findViewById(R.id.status_separator) + } + + override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { + // At most one view is there + if (statusSeparator.visibility == View.GONE) super.onLayout(changed, l, t, r, b) + else { + val alarmWidth = alarmContainer.measuredWidth + val separatorWidth = statusSeparator.measuredWidth + val ringerWidth = ringerContainer.measuredWidth + val availableSpace = (r - l) - separatorWidth + var left = l + if (alarmWidth < availableSpace / 2) { + alarmContainer.layout(left, t, left + alarmWidth, b) + left += alarmWidth + statusSeparator.layout(left, t, left + separatorWidth, b) + left += separatorWidth + ringerContainer.layout(left, t, left + Math.min(ringerWidth, r - left), b) + } else if (ringerWidth < availableSpace / 2) { + val alarmAllocation = Math.min(availableSpace - ringerWidth, alarmWidth) + alarmContainer.layout(left, t, left + alarmAllocation, b) + left += alarmWidth + statusSeparator.layout(left, t, left + separatorWidth, b) + left += separatorWidth + ringerContainer.layout(left, t, left + ringerWidth, b) + } else { + alarmContainer.layout(left, t, left + availableSpace / 2, b) + left += availableSpace / 2 + statusSeparator.layout(left, t, left + separatorWidth, b) + ringerContainer.layout(r - availableSpace / 2, t, r, b) + } + } + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure( + MeasureSpec.makeMeasureSpec( + MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.AT_MOST), + heightMeasureSpec) + val width = MeasureSpec.getSize(widthMeasureSpec) + // Once we measure the views, using as much space as they need, we need to remeasure them + // assigning them their final width. This is because TextViews decide whether to MARQUEE + // after onMeasure. + if (statusSeparator.visibility != View.GONE) { + val alarmWidth = alarmContainer.measuredWidth + val separatorWidth = statusSeparator.measuredWidth + val ringerWidth = ringerContainer.measuredWidth + val availableSpace = MeasureSpec.getSize(width) - separatorWidth + if (alarmWidth < availableSpace / 2) { + measureChild( + ringerContainer, + MeasureSpec.makeMeasureSpec( + Math.min(ringerWidth, availableSpace - alarmWidth), + MeasureSpec.AT_MOST), + heightMeasureSpec) + } else if (ringerWidth < availableSpace / 2) { + measureChild(alarmContainer, + MeasureSpec.makeMeasureSpec( + Math.min(alarmWidth, availableSpace - ringerWidth), + MeasureSpec.AT_MOST), + heightMeasureSpec) + } else { + measureChild( + alarmContainer, + MeasureSpec.makeMeasureSpec(availableSpace / 2, MeasureSpec.AT_MOST), + heightMeasureSpec) + measureChild( + ringerContainer, + MeasureSpec.makeMeasureSpec(availableSpace / 2, MeasureSpec.AT_MOST), + heightMeasureSpec) + } + } + setMeasuredDimension(width, measuredHeight) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index ce3c04e6c6be..984274817fef 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -321,6 +321,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements } mRingerModeIcon.setVisibility(ringerVisible ? View.VISIBLE : View.GONE); mRingerModeTextView.setVisibility(ringerVisible ? View.VISIBLE : View.GONE); + mRingerContainer.setVisibility(ringerVisible ? View.VISIBLE : View.GONE); return isOriginalVisible != ringerVisible || !Objects.equals(originalRingerText, mRingerModeTextView.getText()); @@ -337,6 +338,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements } mNextAlarmIcon.setVisibility(alarmVisible ? View.VISIBLE : View.GONE); mNextAlarmTextView.setVisibility(alarmVisible ? View.VISIBLE : View.GONE); + mNextAlarmContainer.setVisibility(alarmVisible ? View.VISIBLE : View.GONE); return isOriginalVisible != alarmVisible || !Objects.equals(originalAlarmText, mNextAlarmTextView.getText()); diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index 51d259bbcd6f..738f893e98b3 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -271,6 +271,19 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis } @Override + public void onAssistantGestureCompletion(float velocity) { + if (!verifyCaller("onAssistantGestureCompletion")) { + return; + } + long token = Binder.clearCallingIdentity(); + try { + mHandler.post(() -> notifyAssistantGestureCompletion(velocity)); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override public void startAssistant(Bundle bundle) { if (!verifyCaller("startAssistant")) { return; @@ -684,6 +697,12 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis } } + private void notifyAssistantGestureCompletion(float velocity) { + for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { + mConnectionCallbacks.get(i).onAssistantGestureCompletion(velocity); + } + } + private void notifyStartAssistant(Bundle bundle) { for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { mConnectionCallbacks.get(i).startAssistant(bundle); @@ -732,6 +751,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis default void onQuickScrubStarted() {} default void onBackButtonAlphaChanged(float alpha, boolean animate) {} default void onAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {} + default void onAssistantGestureCompletion(float velocity) {} default void startAssistant(Bundle bundle) {} } } 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/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java index 942f56689170..e4e8c80867b1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java @@ -94,6 +94,8 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G private static final int BUTTON_ANIM_TIME_MS = 200; + private static final boolean SHOW_BUTTON_SUMMARY = false; + private INotificationManager mINotificationManager; private PackageManager mPm; private MetricsLogger mMetricsLogger; @@ -580,25 +582,27 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G transition.setDuration(BUTTON_ANIM_TIME_MS); TransitionManager.beginDelayedTransition(this, transition); } - if (blockState == ACTION_ALERT) { - TextView view = findViewById(R.id.alert_summary); - view.setVisibility(VISIBLE); - findViewById(R.id.silence_summary).setVisibility(GONE); - view.setText(R.string.notification_channel_summary_default); - } else { - TextView view = findViewById(R.id.silence_summary); - view.setVisibility(VISIBLE); - findViewById(R.id.alert_summary).setVisibility(GONE); - if (mShowInStatusBar) { - if (mShowOnLockscreen) { - view.setText(R.string.notification_channel_summary_low_status_lock); + if (SHOW_BUTTON_SUMMARY) { + if (blockState == ACTION_ALERT) { + TextView view = findViewById(R.id.alert_summary); + view.setVisibility(VISIBLE); + findViewById(R.id.silence_summary).setVisibility(GONE); + view.setText(R.string.notification_channel_summary_default); + } else { + TextView view = findViewById(R.id.silence_summary); + view.setVisibility(VISIBLE); + findViewById(R.id.alert_summary).setVisibility(GONE); + if (mShowInStatusBar) { + if (mShowOnLockscreen) { + view.setText(R.string.notification_channel_summary_low_status_lock); + } else { + view.setText(R.string.notification_channel_summary_low_status); + } + } else if (mShowOnLockscreen) { + view.setText(R.string.notification_channel_summary_low_lock); } else { - view.setText(R.string.notification_channel_summary_low_status); + view.setText(R.string.notification_channel_summary_low); } - } else if (mShowOnLockscreen) { - view.setText(R.string.notification_channel_summary_low_lock); - } else { - view.setText(R.string.notification_channel_summary_low); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java index 82599f02ddf1..5747bb122fc4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java @@ -28,6 +28,8 @@ import android.view.View; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.R; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -40,18 +42,22 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvider { private final NotificationStackScrollLayout mParent; private final ActivityStarter mActivityStarter; + private final StatusBarStateController mStatusBarStateController; private final boolean mUseMultipleSections; private SectionHeaderView mGentleHeader; private boolean mGentleHeaderVisible = false; + @Nullable private ExpandableNotificationRow mFirstGentleNotif; @Nullable private View.OnClickListener mOnClearGentleNotifsClickListener; NotificationSectionsManager( NotificationStackScrollLayout parent, ActivityStarter activityStarter, + StatusBarStateController statusBarStateController, boolean useMultipleSections) { mParent = parent; mActivityStarter = activityStarter; + mStatusBarStateController = statusBarStateController; mUseMultipleSections = useMultipleSections; } @@ -92,7 +98,7 @@ class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvide @Override public boolean beginsSection(View view) { - return view == mGentleHeader; + return view == getFirstLowPriorityChild(); } /** @@ -104,6 +110,7 @@ class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvide return; } + mFirstGentleNotif = null; int firstGentleNotifIndex = -1; final int n = mParent.getChildCount(); @@ -114,6 +121,7 @@ class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvide ExpandableNotificationRow row = (ExpandableNotificationRow) child; if (!row.getEntry().isHighPriority()) { firstGentleNotifIndex = i; + mFirstGentleNotif = row; break; } } @@ -126,9 +134,12 @@ class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvide } private void adjustGentleHeaderVisibilityAndPosition(int firstGentleNotifIndex) { + final boolean showGentleHeader = + firstGentleNotifIndex != -1 + && mStatusBarStateController.getState() != StatusBarState.KEYGUARD; final int currentHeaderIndex = mParent.indexOfChild(mGentleHeader); - if (firstGentleNotifIndex == -1) { + if (!showGentleHeader) { if (mGentleHeaderVisible) { mGentleHeaderVisible = false; mParent.removeView(mGentleHeader); @@ -208,7 +219,11 @@ class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvide @Nullable private ActivatableNotificationView getFirstLowPriorityChild() { - return mGentleHeaderVisible ? mGentleHeader : null; + if (mGentleHeaderVisible) { + return mGentleHeader; + } else { + return mFirstGentleNotif; + } } @Nullable 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 de187f1de1cc..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 @@ -518,7 +518,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd NotificationRoundnessManager notificationRoundnessManager, AmbientPulseManager ambientPulseManager, DynamicPrivacyController dynamicPrivacyController, - ActivityStarter activityStarter) { + ActivityStarter activityStarter, + StatusBarStateController statusBarStateController) { super(context, attrs, 0, 0); Resources res = getResources(); @@ -534,6 +535,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd new NotificationSectionsManager( this, activityStarter, + statusBarStateController, NotificationUtils.useNewInterruptionModel(context)); mSectionsManager.inflateViews(context); mSectionsManager.setOnClearGentleNotifsClickListener(v -> { @@ -913,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()); } @@ -4378,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/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java index 58c931190c83..afb63ab0ebcf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java @@ -37,6 +37,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.systemui.SysuiTestCase; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.util.NotificationChannels; import org.junit.Before; @@ -57,7 +58,8 @@ public class PowerNotificationWarningsTest extends SysuiTestCase { public void setUp() throws Exception { // Test Instance. mContext.addMockSystemService(NotificationManager.class, mMockNotificationManager); - mPowerNotificationWarnings = new PowerNotificationWarnings(mContext); + ActivityStarter starter = mDependency.injectMockDependency(ActivityStarter.class); + mPowerNotificationWarnings = new PowerNotificationWarnings(mContext, starter); BatteryStateSnapshot snapshot = new BatteryStateSnapshot(100, false, false, 1, BatteryManager.BATTERY_HEALTH_GOOD, 5, 15); mPowerNotificationWarnings.updateSnapshot(snapshot); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java index 67c4a92bbb02..b99958a07ced 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java @@ -38,6 +38,8 @@ import androidx.test.filters.SmallTest; import com.android.systemui.ActivityStarterDelegate; import com.android.systemui.SysuiTestCase; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import org.junit.Before; @@ -57,17 +59,24 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { @Mock private NotificationStackScrollLayout mNssl; @Mock private ActivityStarterDelegate mActivityStarterDelegate; + @Mock private StatusBarStateController mStatusBarStateController; private NotificationSectionsManager mSectionsManager; @Before public void setUp() { - mSectionsManager = new NotificationSectionsManager(mNssl, mActivityStarterDelegate, true); + mSectionsManager = + new NotificationSectionsManager( + mNssl, + mActivityStarterDelegate, + mStatusBarStateController, + true); // Required in order for the header inflation to work properly when(mNssl.generateLayoutParams(any(AttributeSet.class))) .thenReturn(new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); mSectionsManager.inflateViews(mContext); when(mNssl.indexOfChild(any(View.class))).thenReturn(-1); + when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE); } @Test @@ -185,6 +194,49 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { verify(mNssl).addView(mSectionsManager.getGentleHeaderView(), 1); } + @Test + public void testHeaderNotShownOnLockscreen() { + // GIVEN a stack of HI and LO notifs on the lockscreen + when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD); + setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.HIPRI, ChildType.LOPRI); + + // WHEN we update the section headers + mSectionsManager.updateSectionBoundaries(); + + // Then the section header is not added + verify(mNssl, never()).addView(eq(mSectionsManager.getGentleHeaderView()), anyInt()); + } + + @Test + public void testHeaderShownWhenEnterLockscreen() { + // GIVEN a stack of HI and LO notifs on the lockscreen + when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD); + setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.HIPRI, ChildType.LOPRI); + mSectionsManager.updateSectionBoundaries(); + + // WHEN we unlock + when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE); + mSectionsManager.updateSectionBoundaries(); + + // Then the section header is added + verify(mNssl).addView(mSectionsManager.getGentleHeaderView(), 3); + } + + @Test + public void testHeaderHiddenWhenEnterLockscreen() { + // GIVEN a stack of HI and LO notifs on the shade + when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE_LOCKED); + setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.HIPRI, ChildType.LOPRI); + mSectionsManager.updateSectionBoundaries(); + + // WHEN we go back to the keyguard + when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD); + mSectionsManager.updateSectionBoundaries(); + + // Then the section header is removed + verify(mNssl).removeView(eq(mSectionsManager.getGentleHeaderView())); + } + private enum ChildType { HEADER, HIPRI, LOPRI } private void setStackState(ChildType... children) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index 09b8062390bd..56265d08c131 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -153,7 +153,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { true /* allowLongPress */, mNotificationRoundnessManager, new AmbientPulseManager(mContext), mock(DynamicPrivacyController.class), - mock(ActivityStarterDelegate.class)); + mock(ActivityStarterDelegate.class), + mock(StatusBarStateController.class)); mStackScroller = spy(mStackScrollerInternal); mStackScroller.setShelf(notificationShelf); mStackScroller.setStatusBar(mBar); 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 fc355b7cce2f..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,8 +3595,14 @@ 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_DEFAULT; + return Zygote.MOUNT_EXTERNAL_NONE; } // Determine if caller is holding runtime permission @@ -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/Watchdog.java b/services/core/java/com/android/server/Watchdog.java index a7fb99f8b004..e097d85293ab 100644 --- a/services/core/java/com/android/server/Watchdog.java +++ b/services/core/java/com/android/server/Watchdog.java @@ -617,9 +617,13 @@ public class Watchdog extends Thread { // deadlock and the watchdog as a whole to be ineffective) Thread dropboxThread = new Thread("watchdogWriteToDropbox") { public void run() { - mActivity.addErrorToDropBox( - "watchdog", null, "system_server", null, null, null, - subject, null, stack, null); + // If a watched thread hangs before init() is called, we don't have a + // valid mActivity. So we can't log the error to dropbox. + if (mActivity != null) { + mActivity.addErrorToDropBox( + "watchdog", null, "system_server", null, null, null, + subject, null, stack, null); + } StatsLog.write(StatsLog.SYSTEM_SERVER_WATCHDOG_OCCURRED, subject); } }; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index ea71a3b2e17e..a809d2194256 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -33,6 +33,7 @@ import static android.app.AppOpsManager.OP_NONE; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.pm.ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT; import static android.content.pm.PackageManager.GET_PROVIDERS; +import static android.content.pm.PackageManager.GET_SHARED_LIBRARY_FILES; import static android.content.pm.PackageManager.MATCH_ALL; import static android.content.pm.PackageManager.MATCH_ANY_USER; import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING; @@ -18566,6 +18567,21 @@ public class ActivityManagerService extends IActivityManager.Stub } } + /** + * Synchronously update the system ActivityThread, bypassing any deferred threading so any + * resources and overlaid values are available immediately. + */ + public void updateSystemUiContext() { + PackageManagerInternal packageManagerInternal; + synchronized (this) { + packageManagerInternal = getPackageManagerInternalLocked(); + } + + ApplicationInfo ai = packageManagerInternal.getApplicationInfo("android", + GET_SHARED_LIBRARY_FILES, Binder.getCallingUid(), UserHandle.USER_SYSTEM); + ActivityThread.currentActivityThread().handleSystemApplicationInfoChanged(ai); + } + void updateApplicationInfoLocked(@NonNull List<String> packagesToUpdate, int userId) { final boolean updateFrameworkRes = packagesToUpdate.contains("android"); if (updateFrameworkRes) { 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/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 6d0137551729..99341d1c96ae 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -254,6 +254,9 @@ public final class DisplayManagerService extends SystemService { // device). private Point mStableDisplaySize = new Point(); + // Whether the system has finished booting or not. + private boolean mSystemReady; + // The top inset of the default display. // This gets persisted so that the boot animation knows how to transition from the display's // full size to the size configured by the user. Right now we only persist and animate the top @@ -330,6 +333,8 @@ public final class DisplayManagerService extends SystemService { mCurrentUserId = UserHandle.USER_SYSTEM; ColorSpace[] colorSpaces = SurfaceControl.getCompositionColorSpaces(); mWideColorSpace = colorSpaces[1]; + + mSystemReady = false; } public void setupSchedulerPolicies() { @@ -418,6 +423,10 @@ public final class DisplayManagerService extends SystemService { synchronized (mSyncRoot) { mSafeMode = safeMode; mOnlyCore = onlyCore; + mSystemReady = true; + // Just in case the top inset changed before the system was ready. At this point, any + // relevant configuration should be in place. + recordTopInsetLocked(mLogicalDisplays.get(Display.DEFAULT_DISPLAY)); } mDisplayModeDirector.setListener(new AllowedDisplayModeObserver()); @@ -1057,7 +1066,10 @@ public final class DisplayManagerService extends SystemService { } private void recordTopInsetLocked(@Nullable LogicalDisplay d) { - if (d == null) { + // We must only persist the inset after boot has completed, otherwise we will end up + // overwriting the persisted value before the masking flag has been loaded from the + // resource overlay. + if (!mSystemReady || d == null) { return; } int topInset = d.getInsets().top; diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index b2315c7b7314..f28bce5d5e7b 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -966,8 +966,9 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } private void updateEnabled() { - // Generally follow location setting - boolean enabled = mContext.getSystemService(LocationManager.class).isLocationEnabled(); + // Generally follow location setting for current user + boolean enabled = mContext.getSystemService(LocationManager.class) + .isLocationEnabledForUser(UserHandle.CURRENT); // ... but disable if PowerManager overrides enabled &= !mDisableGpsForPowerManager; 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/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index e42ed3b03139..4e1cac905178 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -36,6 +36,7 @@ import android.content.res.Configuration; import android.content.res.Resources.Theme; import android.database.sqlite.SQLiteCompatibilityWalFlags; import android.database.sqlite.SQLiteGlobal; +import android.hardware.display.DisplayManagerInternal; import android.net.NetworkStackClient; import android.os.BaseBundle; import android.os.Binder; @@ -790,6 +791,12 @@ public final class SystemServer { mSystemServiceManager.startService(new SensorPrivacyService(mSystemContext)); traceEnd(); + if (SystemProperties.getInt("persist.sys.displayinset.top", 0) > 0) { + // DisplayManager needs the overlay immediately. + mActivityManagerService.updateSystemUiContext(); + LocalServices.getService(DisplayManagerInternal.class).onOverlayChanged(); + } + // The sensor service needs access to package manager service, app ops // service, and permissions service, therefore we start it after them. // Start sensor service in a separate thread. Completion should be checked 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 = |