Merge "Revert "Use the SubId in the TM.getNetworkType if Valid"" into qt-dev
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index ca04536a..4e1bcc1 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -123,7 +123,6 @@
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 @@
}
}
+ /**
+ * 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 66ddf21..6178b2b 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -1033,6 +1033,8 @@
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/util/MemoryIntArray.java b/core/java/android/util/MemoryIntArray.java
index 80b1607..7d287e3 100644
--- a/core/java/android/util/MemoryIntArray.java
+++ b/core/java/android/util/MemoryIntArray.java
@@ -175,12 +175,10 @@
@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 616c4b5..b7dd88b 100644
--- a/core/java/android/widget/TextClock.java
+++ b/core/java/android/widget/TextClock.java
@@ -175,6 +175,9 @@
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 @@
*/
@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 3fddfc8..04ad7e9 100644
--- a/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java
+++ b/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java
@@ -99,9 +99,13 @@
}
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 37678dd..5b917cc 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/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index e524216..ad99cce 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -314,6 +314,8 @@
<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 297153d..32f2fc2 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -1930,11 +1930,11 @@
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 a8f313b..dc3041f 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -400,7 +400,7 @@
/**
* 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 @@
/**
* 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 2f03d26..a82c78f 100644
--- a/media/java/android/media/audiopolicy/AudioMix.java
+++ b/media/java/android/media/audiopolicy/AudioMix.java
@@ -91,6 +91,20 @@
*/
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 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 @@
return mRouteFlags;
}
- AudioFormat getFormat() {
+ /** @hide */
+ public AudioFormat getFormat() {
return mFormat;
}
@@ -182,6 +206,31 @@
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 @@
}
}
}
+ 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 ed2fdae..c4afd95 100644
--- a/media/java/android/media/audiopolicy/AudioMixingRule.java
+++ b/media/java/android/media/audiopolicy/AudioMixingRule.java
@@ -365,6 +365,10 @@
/**
* 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 0000000..5ed7499
--- /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 5c915b8..55b0d87 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 0000000..99c3a02
--- /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 83ec351..0d69fbb 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 8789c8a..0358357b 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 9b6ab06..54e468ee 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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
@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 @@
@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 ea7b378..06c5294 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.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 @@
@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();
+ DynamicSystemManager dynSystem =
+ (DynamicSystemManager) context.getSystemService(Context.DYNAMIC_SYSTEM_SERVICE);
- Log.d(TAG, "Broadcast received: " + action);
+ boolean isInUse = (dynSystem != null) && dynSystem.isInUse();
- if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
- Intent startServiceIntent = new Intent(
- context, DynamicSystemInstallationService.class);
-
- 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 b0e28a0..077f7ec 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
@@ -37,7 +37,7 @@
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 765e9f9..670b419 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 @@
// 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 0000000..a9cb63e
--- /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 786139f..b2e75ea 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 @@
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/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 0fa4155..aba88ab 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 c471b3830..0000000
--- 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 15f14d8..8b34080 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 5b93edd..db40c4f 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 0000000..ea6d900
--- /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 087e0bd..4b672ee0 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -228,7 +228,7 @@
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 @@
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 @@
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 @@
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 d0783a0..3582d39 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 2b21006..0c3c597 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 e25faa2..addc10a 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 6d7e205..490473ce 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 b49b612..fb226c7 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 c95dbfe..9831250 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 59ed5ce..04cd30c 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 b826b30..77bb514 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 @@
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/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index a3b2c95..51bd9f8 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 @@
// 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/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 3b652b7..e7948b5 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 @@
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 @@
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 @@
// 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 50419b9..bec90d2 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 @@
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 @@
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 @@
*/
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 4674a1f..ae8043f 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 @@
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/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index f6cd199..4982dd4 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 @@
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 @@
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 @@
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 @@
.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 @@
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 @@
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 0000000..86f54a9
--- /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 ce3c04e..9842748 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 @@
}
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 @@
}
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 51d259b..738f893 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 @@
}
@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 @@
}
}
+ 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 @@
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/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index 942f566..e4e8c80 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 @@
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 @@
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);
- } else {
- view.setText(R.string.notification_channel_summary_low_status);
- }
- } else if (mShowOnLockscreen) {
- view.setText(R.string.notification_channel_summary_low_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 {
- view.setText(R.string.notification_channel_summary_low);
+ 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);
+ }
}
}
}
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 82599f0..5747bb1 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 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 @@
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 @@
@Override
public boolean beginsSection(View view) {
- return view == mGentleHeader;
+ return view == getFirstLowPriorityChild();
}
/**
@@ -104,6 +110,7 @@
return;
}
+ mFirstGentleNotif = null;
int firstGentleNotifIndex = -1;
final int n = mParent.getChildCount();
@@ -114,6 +121,7 @@
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
if (!row.getEntry().isHighPriority()) {
firstGentleNotifIndex = i;
+ mFirstGentleNotif = row;
break;
}
}
@@ -126,9 +134,12 @@
}
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 @@
@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 de187f1..2651d4b 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 @@
NotificationRoundnessManager notificationRoundnessManager,
AmbientPulseManager ambientPulseManager,
DynamicPrivacyController dynamicPrivacyController,
- ActivityStarter activityStarter) {
+ ActivityStarter activityStarter,
+ StatusBarStateController statusBarStateController) {
super(context, attrs, 0, 0);
Resources res = getResources();
@@ -534,6 +535,7 @@
new NotificationSectionsManager(
this,
activityStarter,
+ statusBarStateController,
NotificationUtils.useNewInterruptionModel(context));
mSectionsManager.inflateViews(context);
mSectionsManager.setOnClearGentleNotifsClickListener(v -> {
@@ -913,7 +915,8 @@
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 @@
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 4569b66..0f711922 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 @@
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 @@
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 @@
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/usb/UsbContaminantActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbContaminantActivity.java
index ecf608b..aec14be 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 @@
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 @@
}
@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 @@
} 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 58c9311..afb63ab 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 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 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 67c4a92..b99958a 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 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 @@
@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 @@
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 09b8062..56265d0 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 @@
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/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java
index 9d979a6..f92d0e0 100644
--- a/services/core/java/com/android/server/DynamicSystemService.java
+++ b/services/core/java/com/android/server/DynamicSystemService.java
@@ -152,7 +152,18 @@
@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 fc355b7..1fb29a6 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -3580,7 +3580,7 @@
return Zygote.MOUNT_EXTERNAL_NONE;
}
if (mPmInternal.isInstantApp(packageName, UserHandle.getUserId(uid))) {
- return Zygote.MOUNT_EXTERNAL_DEFAULT;
+ return Zygote.MOUNT_EXTERNAL_NONE;
}
// Determine if caller is holding runtime permission
diff --git a/services/core/java/com/android/server/SystemServerInitThreadPool.java b/services/core/java/com/android/server/SystemServerInitThreadPool.java
index 1ce65561..ff6a537 100644
--- a/services/core/java/com/android/server/SystemServerInitThreadPool.java
+++ b/services/core/java/com/android/server/SystemServerInitThreadPool.java
@@ -45,7 +45,8 @@
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 a7fb99f..e097d85 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -617,9 +617,13 @@
// 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 ea71a3b..a809d21 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.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 @@
}
}
+ /**
+ * 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/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 4cde931..86832f4 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 @@
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 @@
* as those policy do not modify the audio routing.
*/
private boolean isPolicyRegisterAllowed(AudioPolicyConfig policyConfig,
- IMediaProjection projection) {
+ boolean hasFocusAccess,
+ boolean isVolumeController,
+ IMediaProjection projection) {
- boolean isLoopbackRenderPolicy = policyConfig.getMixes().stream().allMatch(
- mix -> mix.getRouteFlags() == (mix.ROUTE_FLAG_RENDER | mix.ROUTE_FLAG_LOOP_BACK));
+ boolean requireValidProjection = false;
+ boolean requireCaptureAudioOrMediaOutputPerm = false;
+ boolean requireModifyRouting = false;
- 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;
+ 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 6d01375..99341d1 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 @@
// 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 @@
mCurrentUserId = UserHandle.USER_SYSTEM;
ColorSpace[] colorSpaces = SurfaceControl.getCompositionColorSpaces();
mWideColorSpace = colorSpaces[1];
+
+ mSystemReady = false;
}
public void setupSchedulerPolicies() {
@@ -418,6 +423,10 @@
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 @@
}
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 b2315c7..f28bce5 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 @@
}
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/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index e42ed3b..4e1cac9 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.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 @@
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/telephony/java/android/telephony/ims/ImsSsInfo.java b/telephony/java/android/telephony/ims/ImsSsInfo.java
index 18e7530..9912ece 100644
--- a/telephony/java/android/telephony/ims/ImsSsInfo.java
+++ b/telephony/java/android/telephony/ims/ImsSsInfo.java
@@ -250,6 +250,8 @@
out.writeInt(mStatus);
out.writeString(mIcbNum);
out.writeInt(mProvisionStatus);
+ out.writeInt(mClirInterrogationStatus);
+ out.writeInt(mClirOutgoingState);
}
@Override
@@ -273,6 +275,8 @@
mStatus = in.readInt();
mIcbNum = in.readString();
mProvisionStatus = in.readInt();
+ mClirInterrogationStatus = in.readInt();
+ mClirOutgoingState = in.readInt();
}
public static final @android.annotation.NonNull Creator<ImsSsInfo> CREATOR =