diff options
126 files changed, 3239 insertions, 274 deletions
diff --git a/Android.bp b/Android.bp index 429a0c471645..1762197eb9ed 100755 --- a/Android.bp +++ b/Android.bp @@ -246,6 +246,7 @@ java_library { "com.android.sysprop.init", "com.android.sysprop.localization", "PlatformProperties", + "vendor.lineage.touch-V1.0-java", ], sdk_version: "core_platform", installable: false, diff --git a/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java b/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java index caf7e7f4a4ed..7ec603de40fd 100644 --- a/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java +++ b/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java @@ -73,6 +73,8 @@ public interface DeviceIdleInternal { boolean isAppOnWhitelist(int appid); + int[] getPowerSaveWhitelistSystemAppIds(); + int[] getPowerSaveWhitelistUserAppIds(); int[] getPowerSaveTempWhitelistAppIds(); diff --git a/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java b/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java index fab5b5fd6933..606f0df0dfda 100644 --- a/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java +++ b/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java @@ -109,6 +109,12 @@ public class AppStateTrackerImpl implements AppStateTracker { final SparseBooleanArray mActiveUids = new SparseBooleanArray(); /** + * System exemption list in the device idle controller. + */ + @GuardedBy("mLock") + private int[] mPowerExemptSystemAppIds = new int[0]; + + /** * System except-idle + user exemption list in the device idle controller. */ @GuardedBy("mLock") @@ -1075,6 +1081,7 @@ public class AppStateTrackerImpl implements AppStateTracker { * Called by device idle controller to update the power save exemption lists. */ public void setPowerSaveExemptionListAppIds( + int[] powerSaveExemptionListSystemAppIdArray, int[] powerSaveExemptionListExceptIdleAppIdArray, int[] powerSaveExemptionListUserAppIdArray, int[] tempExemptionListAppIdArray) { @@ -1082,6 +1089,7 @@ public class AppStateTrackerImpl implements AppStateTracker { final int[] previousExemptionList = mPowerExemptAllAppIds; final int[] previousTempExemptionList = mTempExemptAppIds; + mPowerExemptSystemAppIds = powerSaveExemptionListSystemAppIdArray; mPowerExemptAllAppIds = powerSaveExemptionListExceptIdleAppIdArray; mTempExemptAppIds = tempExemptionListAppIdArray; mPowerExemptUserAppIds = powerSaveExemptionListUserAppIdArray; @@ -1302,6 +1310,18 @@ public class AppStateTrackerImpl implements AppStateTracker { } /** + * @return whether or not a UID is in either the user defined power-save exemption list or the + system full exemption list (not including except-idle) + */ + public boolean isUidPowerSaveIdleExempt(int uid) { + final int appId = UserHandle.getAppId(uid); + synchronized (mLock) { + return ArrayUtils.contains(mPowerExemptUserAppIds, appId) + || ArrayUtils.contains(mPowerExemptSystemAppIds, appId); + } + } + + /** * @return whether a UID is in the temp power-save exemption list or not. * * Note clients normally shouldn't need to access it. It's only for dumpsys. @@ -1338,6 +1358,9 @@ public class AppStateTrackerImpl implements AppStateTracker { pw.print("Active uids: "); dumpUids(pw, mActiveUids); + pw.print("System exemption list appids: "); + pw.println(Arrays.toString(mPowerExemptSystemAppIds)); + pw.print("Except-idle + user exemption list appids: "); pw.println(Arrays.toString(mPowerExemptAllAppIds)); @@ -1415,6 +1438,10 @@ public class AppStateTrackerImpl implements AppStateTracker { } } + for (int appId : mPowerExemptSystemAppIds) { + proto.write(AppStateTrackerProto.POWER_SAVE_SYSTEM_EXEMPT_APP_IDS, appId); + } + for (int appId : mPowerExemptAllAppIds) { proto.write(AppStateTrackerProto.POWER_SAVE_EXEMPT_APP_IDS, appId); } diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java index 40d1b4c9b267..40a51bd3470a 100644 --- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java +++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java @@ -563,6 +563,12 @@ public class DeviceIdleController extends SystemService private final SparseBooleanArray mPowerSaveWhitelistSystemAppIds = new SparseBooleanArray(); /** + * Current system app IDs that are in the complete power save white list. This array can + * be shared with others because it will not be modified once set. + */ + private int[] mPowerSaveWhitelistSystemAppIdArray = new int[0]; + + /** * App IDs that have been white-listed to opt out of power save restrictions, except * for device idle modes. */ @@ -2089,6 +2095,11 @@ public class DeviceIdleController extends SystemService return DeviceIdleController.this.isAppOnWhitelistInternal(appid); } + @Override + public int[] getPowerSaveWhitelistSystemAppIds() { + return DeviceIdleController.this.getPowerSaveSystemWhitelistAppIds(); + } + /** * Returns the array of app ids whitelisted by user. Take care not to * modify this, as it is a reference to the original copy. But the reference @@ -2271,6 +2282,12 @@ public class DeviceIdleController extends SystemService } } + int[] getPowerSaveSystemWhitelistAppIds() { + synchronized (this) { + return mPowerSaveWhitelistSystemAppIdArray; + } + } + int[] getPowerSaveWhitelistUserAppIds() { synchronized (this) { return mPowerSaveWhitelistUserAppIdArray; @@ -2281,6 +2298,16 @@ public class DeviceIdleController extends SystemService return new File(Environment.getDataDirectory(), "system"); } + /** Returns the keys of a SparseBooleanArray, paying no attention to its values. */ + private static int[] keysToIntArray(final SparseBooleanArray sparseArray) { + final int size = sparseArray.size(); + final int[] array = new int[size]; + for (int i = 0; i < size; i++) { + array[i] = sparseArray.keyAt(i); + } + return array; + } + @Override public void onStart() { final PackageManager pm = getContext().getPackageManager(); @@ -2317,6 +2344,7 @@ public class DeviceIdleController extends SystemService } catch (PackageManager.NameNotFoundException e) { } } + mPowerSaveWhitelistSystemAppIdArray = keysToIntArray(mPowerSaveWhitelistSystemAppIds); mConstants = mInjector.getConstants(this); @@ -4222,6 +4250,7 @@ public class DeviceIdleController extends SystemService private void passWhiteListsToForceAppStandbyTrackerLocked() { mAppStateTracker.setPowerSaveExemptionListAppIds( + mPowerSaveWhitelistSystemAppIdArray, mPowerSaveWhitelistExceptIdleAppIdArray, mPowerSaveWhitelistUserAppIdArray, mTempWhitelistAppIdArray); diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java index 37ce0d29d0e1..a65e86d888de 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java @@ -2861,7 +2861,7 @@ public class AlarmManagerService extends SystemService { } else if (workSource == null && (UserHandle.isCore(callingUid) || UserHandle.isSameApp(callingUid, mSystemUiUid) || ((mAppStateTracker != null) - && mAppStateTracker.isUidPowerSaveUserExempt(callingUid)))) { + && mAppStateTracker.isUidPowerSaveIdleExempt(callingUid)))) { flags |= FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED; flags &= ~(FLAG_ALLOW_WHILE_IDLE | FLAG_PRIORITIZE); } diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java index abbe177c5d49..01f0b30cc48a 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java @@ -74,6 +74,7 @@ public final class DeviceIdleJobsController extends StateController { * True when in device idle mode, so we don't want to schedule any jobs. */ private boolean mDeviceIdleMode; + private int[] mPowerSaveWhitelistSystemAppIds; private int[] mDeviceIdleWhitelistAppIds; private int[] mPowerSaveTempWhitelistAppIds; @@ -133,6 +134,8 @@ public final class DeviceIdleJobsController extends StateController { mLocalDeviceIdleController = LocalServices.getService(DeviceIdleInternal.class); mDeviceIdleWhitelistAppIds = mLocalDeviceIdleController.getPowerSaveWhitelistUserAppIds(); + mPowerSaveWhitelistSystemAppIds = + mLocalDeviceIdleController.getPowerSaveWhitelistSystemAppIds(); mPowerSaveTempWhitelistAppIds = mLocalDeviceIdleController.getPowerSaveTempWhitelistAppIds(); mDeviceIdleUpdateFunctor = new DeviceIdleUpdateFunctor(); @@ -196,8 +199,9 @@ public final class DeviceIdleJobsController extends StateController { * Checks if the given job's scheduling app id exists in the device idle user whitelist. */ boolean isWhitelistedLocked(JobStatus job) { - return Arrays.binarySearch(mDeviceIdleWhitelistAppIds, - UserHandle.getAppId(job.getSourceUid())) >= 0; + final int appId = UserHandle.getAppId(job.getSourceUid()); + return Arrays.binarySearch(mDeviceIdleWhitelistAppIds, appId) >= 0 + || Arrays.binarySearch(mPowerSaveWhitelistSystemAppIds, appId) >= 0; } /** diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java index 3c0a724b9ff7..5bde079d085e 100644 --- a/core/java/android/app/StatusBarManager.java +++ b/core/java/android/app/StatusBarManager.java @@ -231,6 +231,8 @@ public class StatusBarManager { public static final int CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER = 2; /** @hide */ public static final int CAMERA_LAUNCH_SOURCE_QUICK_AFFORDANCE = 3; + /** @hide */ + public static final int CAMERA_LAUNCH_SOURCE_SCREEN_GESTURE = 4; /** * Session flag for {@link #registerSessionListener} indicating the listener diff --git a/core/java/android/app/admin/SystemUpdateInfo.java b/core/java/android/app/admin/SystemUpdateInfo.java index b88bf76c96ca..fdf2b3f54311 100644 --- a/core/java/android/app/admin/SystemUpdateInfo.java +++ b/core/java/android/app/admin/SystemUpdateInfo.java @@ -132,7 +132,7 @@ public final class SystemUpdateInfo implements Parcelable { out.startTag(null, tag); out.attributeLong(null, ATTR_RECEIVED_TIME, mReceivedTime); out.attributeInt(null, ATTR_SECURITY_PATCH_STATE, mSecurityPatchState); - out.attribute(null, ATTR_ORIGINAL_BUILD , Build.FINGERPRINT); + out.attribute(null, ATTR_ORIGINAL_BUILD , Build.VERSION.INCREMENTAL); out.endTag(null, tag); } @@ -141,7 +141,7 @@ public final class SystemUpdateInfo implements Parcelable { public static SystemUpdateInfo readFromXml(TypedXmlPullParser parser) { // If an OTA has been applied (build fingerprint has changed), discard stale info. final String buildFingerprint = parser.getAttributeValue(null, ATTR_ORIGINAL_BUILD ); - if (!Build.FINGERPRINT.equals(buildFingerprint)) { + if (!Build.VERSION.INCREMENTAL.equals(buildFingerprint)) { return null; } try { diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 336bd4b60b59..149659f858b6 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -5091,6 +5091,15 @@ public class Intent implements Parcelable, Cloneable { public static final String ACTION_SHOW_FOREGROUND_SERVICE_MANAGER = "android.intent.action.SHOW_FOREGROUND_SERVICE_MANAGER"; + /** + * Broadcast action: notify the system that the user has performed a gesture on the screen + * to launch the camera. Broadcast should be protected to receivers holding the + * {@link Manifest.permission#STATUS_BAR_SERVICE} permission. + * @hide + */ + public static final String ACTION_SCREEN_CAMERA_GESTURE = + "android.intent.action.SCREEN_CAMERA_GESTURE"; + // --------------------------------------------------------------------- // --------------------------------------------------------------------- // Standard intent categories (see addCategory()). diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java index 76f857bd91b7..f0b251f66022 100644 --- a/core/java/android/os/BatteryManager.java +++ b/core/java/android/os/BatteryManager.java @@ -163,6 +163,13 @@ public class BatteryManager { @SystemApi public static final String EXTRA_EVENT_TIMESTAMP = "android.os.extra.EVENT_TIMESTAMP"; + /** + * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}: + * boolean value to indicate OEM fast charging + * {@hide} + */ + public static final String EXTRA_OEM_FAST_CHARGER = "oem_fast_charger"; + // values for "status" field in the ACTION_BATTERY_CHANGED Intent public static final int BATTERY_STATUS_UNKNOWN = Constants.BATTERY_STATUS_UNKNOWN; public static final int BATTERY_STATUS_CHARGING = Constants.BATTERY_STATUS_CHARGING; diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java index edfcb3d6f12a..0621ebc9d942 100644 --- a/core/java/android/os/FileUtils.java +++ b/core/java/android/os/FileUtils.java @@ -1299,11 +1299,13 @@ public final class FileUtils { public static long roundStorageSize(long size) { long val = 1; long pow = 1; - while ((val * pow) < size) { + long pow1024 = 1; + while ((val * pow1024) < size) { val <<= 1; if (val > 512) { val = 1; pow *= 1000; + pow1024 *= 1024; } } return val * pow; diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java index ac2156e9e46e..580e632b8d96 100644 --- a/core/java/android/os/Trace.java +++ b/core/java/android/os/Trace.java @@ -160,6 +160,10 @@ public final class Trace { @UnsupportedAppUsage @SystemApi(client = MODULE_LIBRARIES) public static boolean isTagEnabled(long traceTag) { + if (!Build.IS_DEBUGGABLE) { + return false; + } + long tags = nativeGetEnabledTags(); return (tags & traceTag) != 0; } diff --git a/core/java/android/os/UpdateEngine.java b/core/java/android/os/UpdateEngine.java index b7e3068a437c..16bb78e345ba 100644 --- a/core/java/android/os/UpdateEngine.java +++ b/core/java/android/os/UpdateEngine.java @@ -462,6 +462,17 @@ public class UpdateEngine { } /** + * @hide + */ + public void setPerformanceMode(boolean enable) { + try { + mUpdateEngine.setPerformanceMode(enable); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Unbinds the last bound callback function. */ public boolean unbind() { diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index d107972f909f..7e99af2ce4f1 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5155,6 +5155,12 @@ public final class Settings { public static final String ANIMATOR_DURATION_SCALE = Global.ANIMATOR_DURATION_SCALE; /** + * Whether or not to vibrate when a touchscreen gesture is detected + * @hide + */ + public static final String TOUCHSCREEN_GESTURE_HAPTIC_FEEDBACK = "touchscreen_gesture_haptic_feedback"; + + /** * Control whether the accelerometer will be used to change screen * orientation. If 0, it will not be used unless explicitly requested * by the application; if 1, it will be used by default unless explicitly @@ -5517,6 +5523,12 @@ public final class Settings { public static final String DESKTOP_MODE = "desktop_mode"; /** + * Enable statusbar double tap gesture to put device to sleep + * @hide + */ + public static final String DOUBLE_TAP_SLEEP_GESTURE = "double_tap_sleep_gesture"; + + /** * IMPORTANT: If you add a new public settings you also have to add it to * PUBLIC_SETTINGS below. If the new setting is hidden you have to add * it to PRIVATE_SETTINGS below. Also add a validator that can validate @@ -11115,6 +11127,12 @@ public final class Settings { public static void setLocationProviderEnabled(ContentResolver cr, String provider, boolean enabled) { } + + /** + * Whether to show swipe up hint in gestural nav mode + * @hide + */ + public static final String NAVIGATION_BAR_HINT = "navigation_bar_hint"; } /** diff --git a/core/java/android/security/net/config/PinSet.java b/core/java/android/security/net/config/PinSet.java index d3c975eb3101..e1942e513510 100644 --- a/core/java/android/security/net/config/PinSet.java +++ b/core/java/android/security/net/config/PinSet.java @@ -19,6 +19,7 @@ package android.security.net.config; import android.util.ArraySet; import java.util.Collections; import java.util.Set; +import java.util.stream.Collectors; /** @hide */ public final class PinSet { @@ -26,6 +27,7 @@ public final class PinSet { new PinSet(Collections.<Pin>emptySet(), Long.MAX_VALUE); public final long expirationTime; public final Set<Pin> pins; + private final Set<String> algorithms; public PinSet(Set<Pin> pins, long expirationTime) { if (pins == null) { @@ -33,14 +35,12 @@ public final class PinSet { } this.pins = pins; this.expirationTime = expirationTime; + this.algorithms = pins.stream() + .map(pin -> pin.digestAlgorithm) + .collect(Collectors.toCollection(ArraySet::new)); } Set<String> getPinAlgorithms() { - // TODO: Cache this. - Set<String> algorithms = new ArraySet<String>(); - for (Pin pin : pins) { - algorithms.add(pin.digestAlgorithm); - } return algorithms; } } diff --git a/core/java/android/text/style/TextAppearanceSpan.java b/core/java/android/text/style/TextAppearanceSpan.java index adb379a397b7..0987142e3973 100644 --- a/core/java/android/text/style/TextAppearanceSpan.java +++ b/core/java/android/text/style/TextAppearanceSpan.java @@ -29,6 +29,8 @@ import android.text.ParcelableSpan; import android.text.TextPaint; import android.text.TextUtils; +import com.android.internal.graphics.fonts.DynamicMetrics; + /** * Sets the text appearance using the given * {@link android.R.styleable#TextAppearance TextAppearance} attributes. @@ -487,17 +489,17 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl styledTypeface = null; } + Typeface finalTypeface = null; if (styledTypeface != null) { - final Typeface readyTypeface; if (mTextFontWeight >= 0) { final int weight = Math.min(FontStyle.FONT_WEIGHT_MAX, mTextFontWeight); final boolean italic = (style & Typeface.ITALIC) != 0; - readyTypeface = ds.setTypeface(Typeface.create(styledTypeface, weight, italic)); + finalTypeface = ds.setTypeface(Typeface.create(styledTypeface, weight, italic)); } else { - readyTypeface = styledTypeface; + finalTypeface = styledTypeface; } - int fake = style & ~readyTypeface.getStyle(); + int fake = style & ~finalTypeface.getStyle(); if ((fake & Typeface.BOLD) != 0) { ds.setFakeBoldText(true); @@ -507,7 +509,7 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl ds.setTextSkewX(-0.25f); } - ds.setTypeface(readyTypeface); + ds.setTypeface(finalTypeface); } if (mTextSize > 0) { @@ -526,6 +528,12 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl ds.setLetterSpacing(mLetterSpacing); } + if ((!mHasLetterSpacing || mLetterSpacing == 0.0f) && + mTextSize > 0 && finalTypeface != null && + finalTypeface.isSystemFont()) { + ds.setLetterSpacing(DynamicMetrics.calcTracking(mTextSize)); + } + if (mFontFeatureSettings != null) { ds.setFontFeatureSettings(mFontFeatureSettings); } diff --git a/core/java/android/util/BoostFramework.java b/core/java/android/util/BoostFramework.java index 7bab65a86802..b5a740c501ab 100644 --- a/core/java/android/util/BoostFramework.java +++ b/core/java/android/util/BoostFramework.java @@ -68,7 +68,6 @@ public class BoostFramework { private static Method sperfHintAcqRelFunc = null; private static Method sperfHintRenewFunc = null; private static Method sPerfEventFunc = null; - private static Method sPerfGetPerfHalVerFunc = null; private static Method sPerfSyncRequest = null; private static Method sIOPStart = null; @@ -287,15 +286,6 @@ public class BoostFramework { sperfHintRenewFunc = sPerfClass.getMethod("perfHintRenew", argClasses); try { - argClasses = new Class[] {}; - sPerfGetPerfHalVerFunc = sPerfClass.getMethod("perfGetHalVer", argClasses); - - } catch (Exception e) { - Log.i(TAG, "BoostFramework() : Exception_1 = perfGetHalVer not supported"); - sPerfGetPerfHalVerFunc = null; - } - - try { argClasses = new Class[] {int.class, int.class, String.class, int.class, String.class}; sUXEngineEvents = sPerfClass.getDeclaredMethod("perfUXEngine_events", argClasses); @@ -398,14 +388,6 @@ public class BoostFramework { /** @hide */ public double getPerfHalVersion() { double retVal = PERF_HAL_V22; - try { - if (sPerfGetPerfHalVerFunc != null) { - Object ret = sPerfGetPerfHalVerFunc.invoke(mPerf); - retVal = (double)ret; - } - } catch(Exception e) { - Log.e(TAG,"Exception " + e); - } return retVal; } diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 7010350005b6..a2c992e3f4d5 100755 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -689,6 +689,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te private int mMinimumVelocity; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124051740) private int mMaximumVelocity; + private int mDecacheThreshold; private float mVelocityScale = 1.0f; final boolean[] mIsScrap = new boolean[1]; @@ -1017,6 +1018,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } mMinimumVelocity = configuration.getScaledMinimumFlingVelocity(); mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); + mDecacheThreshold = mMaximumVelocity / 2; mOverscrollDistance = configuration.getScaledOverscrollDistance(); mOverflingDistance = configuration.getScaledOverflingDistance(); @@ -4889,7 +4891,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te // Keep the fling alive a little longer postDelayed(this, FLYWHEEL_TIMEOUT); } else { - endFling(); + endFling(false); // Don't disable the scrolling cache right after it was enabled mTouchMode = TOUCH_MODE_SCROLL; reportScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL); } @@ -4905,6 +4907,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te // Use AbsListView#fling(int) instead @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) void start(int initialVelocity) { + if (Math.abs(initialVelocity) > mDecacheThreshold) { + // For long flings, scrolling cache causes stutter, so don't use it + clearScrollingCache(); + } + int initialY = initialVelocity < 0 ? Integer.MAX_VALUE : 0; mLastFlingY = initialY; mScroller.setInterpolator(null); @@ -4985,6 +4992,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te // To interrupt a fling early you should use smoothScrollBy(0,0) instead @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) void endFling() { + endFling(true); + } + + void endFling(boolean clearCache) { mTouchMode = TOUCH_MODE_REST; removeCallbacks(this); @@ -4993,7 +5004,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te if (!mSuppressIdleStateChangeCall) { reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); } - clearScrollingCache(); + if (clearCache) + clearScrollingCache(); mScroller.abortAnimation(); if (mFlingStrictSpan != null) { diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 7d59d26b5121..1c4a770b0a7a 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -206,6 +206,7 @@ import android.widget.RemoteViews.RemoteView; import com.android.internal.accessibility.util.AccessibilityUtils; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.graphics.fonts.DynamicMetrics; import com.android.internal.inputmethod.EditableInputConnection; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; @@ -4270,6 +4271,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener setLetterSpacing(attributes.mLetterSpacing); } + if ((!attributes.mHasLetterSpacing || attributes.mLetterSpacing == 0.0f) && + DynamicMetrics.shouldModifyFont(mTextPaint.getTypeface())) { + setLetterSpacing(DynamicMetrics.calcTracking(mTextPaint.getTextSize())); + } + if (attributes.mFontFeatureSettings != null) { setFontFeatureSettings(attributes.mFontFeatureSettings); } diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 09c1efb2c638..6d7f5d6cd5f4 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -1416,15 +1416,18 @@ public class ChooserActivity extends ResolverActivity implements final ViewGroup actionRow = (ViewGroup) contentPreviewLayout.findViewById(R.id.chooser_action_row); + String action = targetIntent.getAction(); + //TODO: addActionButton(actionRow, createCopyButton()); if (shouldNearbyShareBeIncludedAsActionButton()) { addActionButton(actionRow, createNearbyButton(targetIntent)); } - addActionButton(actionRow, createEditButton(targetIntent)); + if (!Intent.ACTION_SEND_MULTIPLE.equals(action)) { + addActionButton(actionRow, createEditButton(targetIntent)); + } mPreviewCoord = new ContentPreviewCoordinator(contentPreviewLayout, false); - String action = targetIntent.getAction(); if (Intent.ACTION_SEND.equals(action)) { Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM, android.net.Uri.class); if (!validForContentPreview(uri)) { diff --git a/core/java/com/android/internal/graphics/fonts/DynamicMetrics.java b/core/java/com/android/internal/graphics/fonts/DynamicMetrics.java new file mode 100644 index 000000000000..5d723fd5f364 --- /dev/null +++ b/core/java/com/android/internal/graphics/fonts/DynamicMetrics.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2022 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.internal.graphics.fonts; + +import android.app.ActivityThread; +import android.content.ComponentCallbacks; +import android.content.Context; +import android.content.res.Configuration; +import android.graphics.Typeface; + +public class DynamicMetrics { + // https://rsms.me/inter/dynmetrics/ + private static final float A = -0.0223f; + private static final float B = 0.185f; + private static final float C = -0.1745f; + + private static float sDensity = 0.0f; + + // Precalculated tracking LUT up to 32 dp, in steps of 0.5 dp to minimize rounding errors. + // Sizes are close enough that we can cast them to ints for lookup. + // In most cases, we should never have to calculate tracking at runtime because of this. + private static final float[] TRACKING_LUT = { + /* 0.0dp */ 0.1627f, + /* 0.5dp */ 0.147242871675558f, + /* 1.0dp */ 0.1330772180324039f, + /* 1.5dp */ 0.12009513371985438f, + /* 2.0dp */ 0.10819772909994156f, + /* 2.5dp */ 0.09729437696617904f, + /* 3.0dp */ 0.08730202220051463f, + /* 3.5dp */ 0.0781445491098568f, + /* 4.0dp */ 0.06975220162292829f, + /* 4.5dp */ 0.062061051930857966f, + /* 5.0dp */ 0.055012513523938045f, + /* 5.5dp */ 0.04855289491515605f, + /* 6.0dp */ 0.04263299065103837f, + /* 6.5dp */ 0.03720770649437408f, + /* 7.0dp */ 0.032235715923688846f, + /* 7.5dp */ 0.027679145332890072f, + /* 8.0dp */ 0.02350328553312564f, + /* 8.5dp */ 0.019676327359252226f, + /* 9.0dp */ 0.016169119366923862f, + /* 9.5dp */ 0.012954945774584309f, + /* 10.0dp */ 0.010009322958860013f, + /* 10.5dp */ 0.007309812953179257f, + /* 11.0dp */ 0.004835852528962955f, + /* 11.5dp */ 0.002568596557431524f, + /* 12.0dp */ 0.0004907744588531701f, + /* 12.5dp */ -0.0014134413542490412f, + /* 13.0dp */ -0.0031585560420509667f, + /* 13.5dp */ -0.004757862828932768f, + /* 14.0dp */ -0.006223544263193034f, + /* 14.5dp */ -0.007566765016306747f, + /* 15.0dp */ -0.008797756928615424f, + /* 15.5dp */ -0.00992589694927596f, + /* 16.0dp */ -0.010959778564167369f, + /* 16.5dp */ -0.01190727725584982f, + /* 17.0dp */ -0.012775610494210232f, + /* 17.5dp */ -0.013571392714766779f, + /* 18.0dp */ -0.014300685703423587f, + /* 18.5dp */ -0.014969044771476151f, + /* 19.0dp */ -0.01558156107260065f, + /* 19.5dp */ -0.01614290038417221f, + /* 20.0dp */ -0.016657338648324763f, + /* 20.5dp */ -0.017128794543482675f, + /* 21.0dp */ -0.01756085933447426f, + /* 21.5dp */ -0.017956824228607303f, + /* 22.0dp */ -0.018319705446088512f, + /* 22.5dp */ -0.018652267195758174f, + /* 23.0dp */ -0.01895704273115516f, + /* 23.5dp */ -0.01923635364730468f, + /* 24.0dp */ -0.019492327565219923f, + /* 24.5dp */ -0.01972691433882746f, + /* 25.0dp */ -0.019941900907770843f, + /* 25.5dp */ -0.02013892490923212f, + /* 26.0dp */ -0.020319487152457818f, + /* 26.5dp */ -0.02048496305101277f, + /* 27.0dp */ -0.020636613099845737f, + /* 27.5dp */ -0.02077559247697482f, + /* 28.0dp */ -0.020902959842932358f, + /* 28.5dp */ -0.021019685404998267f, + /* 29.0dp */ -0.021126658307650148f, + /* 29.5dp */ -0.0212246934055262f, + /* 30.0dp */ -0.02131453747049323f, + /* 30.5dp */ -0.02139687488010142f, + /* 31.0dp */ -0.021472332830757092f, + /* 31.5dp */ -0.0215414861153242f, + /* 32.0dp */ -0.02160486150154747f, + }; + + private static final ComponentCallbacks callbacks = new ComponentCallbacks() { + @Override + public void onConfigurationChanged(Configuration newConfig) { + sDensity = getDensity(); + } + + @Override + public void onLowMemory() {} + }; + + private DynamicMetrics() {} + + public static float calcTracking(float sizePx) { + if (sDensity == 0.0f) { + Context context = ActivityThread.currentApplication(); + if (context == null) { + return 0.0f; + } + + sDensity = getDensity(); + context.registerComponentCallbacks(callbacks); + } + + // Pixels -> sp + float sizeDp = sizePx / sDensity; + int lutIndex = (int) (sizeDp * 2); // 0.5dp steps + + // Precalculated lookup + if (lutIndex < TRACKING_LUT.length) { + return TRACKING_LUT[lutIndex]; + } + + return A + B * (float) Math.exp(C * sizeDp); + } + + public static boolean shouldModifyFont(Typeface typeface) { + return typeface == null || typeface.isSystemFont(); + } + + private static float getDensity() { + Context context = ActivityThread.currentApplication(); + if (context == null) { + return 1.0f; + } + + return context.getResources().getDisplayMetrics().scaledDensity; + } +} diff --git a/core/java/com/android/internal/ice/hardware/HIDLHelper.java b/core/java/com/android/internal/ice/hardware/HIDLHelper.java new file mode 100644 index 000000000000..a596c0e5e3da --- /dev/null +++ b/core/java/com/android/internal/ice/hardware/HIDLHelper.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2019 The LineageOS 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.internal.ice.hardware; + +import android.util.Range; + +import java.util.ArrayList; + +class HIDLHelper { + + static TouchscreenGesture[] fromHIDLGestures( + ArrayList<vendor.lineage.touch.V1_0.Gesture> gestures) { + int size = gestures.size(); + TouchscreenGesture[] r = new TouchscreenGesture[size]; + for (int i = 0; i < size; i++) { + vendor.lineage.touch.V1_0.Gesture g = gestures.get(i); + r[i] = new TouchscreenGesture(g.id, g.name, g.keycode); + } + return r; + } + + static vendor.lineage.touch.V1_0.Gesture toHIDLGesture(TouchscreenGesture gesture) { + vendor.lineage.touch.V1_0.Gesture g = new vendor.lineage.touch.V1_0.Gesture(); + g.id = gesture.id; + g.name = gesture.name; + g.keycode = gesture.keycode; + return g; + } + +} diff --git a/core/java/com/android/internal/ice/hardware/LineageHardwareManager.java b/core/java/com/android/internal/ice/hardware/LineageHardwareManager.java new file mode 100644 index 000000000000..1c0797784183 --- /dev/null +++ b/core/java/com/android/internal/ice/hardware/LineageHardwareManager.java @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2015-2016 The CyanogenMod Project + * 2017-2019 The LineageOS 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.internal.ice.hardware; + +import android.content.Context; +import android.hidl.base.V1_0.IBase; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.ArrayMap; +import android.util.Log; +import android.util.Range; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; + +import com.android.internal.ice.hardware.HIDLHelper; + +import vendor.lineage.touch.V1_0.IGloveMode; +import vendor.lineage.touch.V1_0.IKeyDisabler; +import vendor.lineage.touch.V1_0.IStylusMode; +import vendor.lineage.touch.V1_0.ITouchscreenGesture; + +import java.io.UnsupportedEncodingException; +import java.lang.IllegalArgumentException; +import java.lang.reflect.Field; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.NoSuchElementException; + +/** + * Manages access to LineageOS hardware extensions + * + * <p> + * This manager requires the HARDWARE_ABSTRACTION_ACCESS permission. + * <p> + * To get the instance of this class, utilize LineageHardwareManager#getInstance(Context context) + */ +public final class LineageHardwareManager { + private static final String TAG = "LineageHardwareManager"; + + // The VisibleForTesting annotation is to ensure Proguard doesn't remove these + // fields, as they might be used via reflection. When the @Keep annotation in + // the support library is properly handled in the platform, we should change this. + + /** + * High touch sensitivity for touch panels + */ + @VisibleForTesting + public static final int FEATURE_HIGH_TOUCH_SENSITIVITY = 0x10; + + /** + * Hardware navigation key disablement + */ + @VisibleForTesting + public static final int FEATURE_KEY_DISABLE = 0x20; + + /** + * Touchscreen hovering + */ + @VisibleForTesting + public static final int FEATURE_TOUCH_HOVERING = 0x800; + + /** + * Touchscreen gesture + */ + @VisibleForTesting + public static final int FEATURE_TOUCHSCREEN_GESTURES = 0x80000; + + private static final List<Integer> BOOLEAN_FEATURES = Arrays.asList( + FEATURE_HIGH_TOUCH_SENSITIVITY, + FEATURE_KEY_DISABLE, + FEATURE_TOUCH_HOVERING + ); + + private static LineageHardwareManager sLineageHardwareManagerInstance; + + private Context mContext; + + // HIDL hals + private HashMap<Integer, IBase> mHIDLMap = new HashMap<Integer, IBase>(); + + /** + * @hide to prevent subclassing from outside of the framework + */ + private LineageHardwareManager(Context context) { + Context appContext = context.getApplicationContext(); + if (appContext != null) { + mContext = appContext; + } else { + mContext = context; + } + } + + /** + * Determine if a Lineage Hardware feature is supported on this device + * + * @param feature The Lineage Hardware feature to query + * + * @return true if the feature is supported, false otherwise. + */ + public boolean isSupported(int feature) { + return isSupportedHIDL(feature); + } + + private boolean isSupportedHIDL(int feature) { + if (!mHIDLMap.containsKey(feature)) { + mHIDLMap.put(feature, getHIDLService(feature)); + } + return mHIDLMap.get(feature) != null; + } + + private IBase getHIDLService(int feature) { + try { + switch (feature) { + case FEATURE_HIGH_TOUCH_SENSITIVITY: + return IGloveMode.getService(true); + case FEATURE_KEY_DISABLE: + return IKeyDisabler.getService(true); + case FEATURE_TOUCH_HOVERING: + return IStylusMode.getService(true); + case FEATURE_TOUCHSCREEN_GESTURES: + return ITouchscreenGesture.getService(true); + } + } catch (NoSuchElementException | RemoteException e) { + } + return null; + } + + /** + * Get or create an instance of the {@link com.android.internal.custom.hardware.LineageHardwareManager} + * @param context + * @return {@link LineageHardwareManager} + */ + public static LineageHardwareManager getInstance(Context context) { + if (sLineageHardwareManagerInstance == null) { + sLineageHardwareManagerInstance = new LineageHardwareManager(context); + } + return sLineageHardwareManagerInstance; + } + + /** + * Determine if the given feature is enabled or disabled. + * + * Only used for features which have simple enable/disable controls. + * + * @param feature the Lineage Hardware feature to query + * + * @return true if the feature is enabled, false otherwise. + */ + public boolean get(int feature) { + if (!BOOLEAN_FEATURES.contains(feature)) { + throw new IllegalArgumentException(feature + " is not a boolean"); + } + + try { + if (isSupportedHIDL(feature)) { + IBase obj = mHIDLMap.get(feature); + switch (feature) { + case FEATURE_HIGH_TOUCH_SENSITIVITY: + IGloveMode gloveMode = (IGloveMode) obj; + return gloveMode.isEnabled(); + case FEATURE_KEY_DISABLE: + IKeyDisabler keyDisabler = (IKeyDisabler) obj; + return keyDisabler.isEnabled(); + case FEATURE_TOUCH_HOVERING: + IStylusMode stylusMode = (IStylusMode) obj; + return stylusMode.isEnabled(); + } + } + } catch (RemoteException e) { + } + return false; + } + + /** + * Enable or disable the given feature + * + * Only used for features which have simple enable/disable controls. + * + * @param feature the Lineage Hardware feature to set + * @param enable true to enable, false to disale + * + * @return true if the feature is enabled, false otherwise. + */ + public boolean set(int feature, boolean enable) { + if (!BOOLEAN_FEATURES.contains(feature)) { + throw new IllegalArgumentException(feature + " is not a boolean"); + } + + try { + if (isSupportedHIDL(feature)) { + IBase obj = mHIDLMap.get(feature); + switch (feature) { + case FEATURE_HIGH_TOUCH_SENSITIVITY: + IGloveMode gloveMode = (IGloveMode) obj; + return gloveMode.setEnabled(enable); + case FEATURE_KEY_DISABLE: + IKeyDisabler keyDisabler = (IKeyDisabler) obj; + return keyDisabler.setEnabled(enable); + case FEATURE_TOUCH_HOVERING: + IStylusMode stylusMode = (IStylusMode) obj; + return stylusMode.setEnabled(enable); + } + } + } catch (RemoteException e) { + } + return false; + } + + /** + * @return a list of available touchscreen gestures on the devices + */ + public TouchscreenGesture[] getTouchscreenGestures() { + try { + if (isSupportedHIDL(FEATURE_TOUCHSCREEN_GESTURES)) { + ITouchscreenGesture touchscreenGesture = (ITouchscreenGesture) + mHIDLMap.get(FEATURE_TOUCHSCREEN_GESTURES); + return HIDLHelper.fromHIDLGestures(touchscreenGesture.getSupportedGestures()); + } + } catch (RemoteException e) { + } + return null; + } + + /** + * @return true if setting the activation status was successful + */ + public boolean setTouchscreenGestureEnabled( + TouchscreenGesture gesture, boolean state) { + try { + if (isSupportedHIDL(FEATURE_TOUCHSCREEN_GESTURES)) { + ITouchscreenGesture touchscreenGesture = (ITouchscreenGesture) + mHIDLMap.get(FEATURE_TOUCHSCREEN_GESTURES); + return touchscreenGesture.setGestureEnabled( + HIDLHelper.toHIDLGesture(gesture), state); + } + } catch (RemoteException e) { + } + return false; + } +} diff --git a/core/java/com/android/internal/ice/hardware/TouchscreenGesture.aidl b/core/java/com/android/internal/ice/hardware/TouchscreenGesture.aidl new file mode 100644 index 000000000000..e922eee9a1b6 --- /dev/null +++ b/core/java/com/android/internal/ice/hardware/TouchscreenGesture.aidl @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2016 The CyanogenMod Project + * 2017 The LineageOS 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.internal.ice.hardware; + +parcelable TouchscreenGesture; diff --git a/core/java/com/android/internal/ice/hardware/TouchscreenGesture.java b/core/java/com/android/internal/ice/hardware/TouchscreenGesture.java new file mode 100644 index 000000000000..166dd3223d2c --- /dev/null +++ b/core/java/com/android/internal/ice/hardware/TouchscreenGesture.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2016 The CyanogenMod Project + * 2017 The LineageOS 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.internal.ice.hardware; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Touchscreen gestures API + * + * A device may implement several touchscreen gestures for use while + * the display is turned off, such as drawing alphabets and shapes. + * These gestures can be interpreted by userspace to activate certain + * actions and launch certain apps, such as to skip music tracks, + * to turn on the flashlight, or to launch the camera app. + * + * This *should always* be supported by the hardware directly. + * A lot of recent touch controllers have a firmware option for this. + * + * This API provides support for enumerating the gestures + * supported by the touchscreen. + * + * A TouchscreenGesture is referenced by it's identifier and carries an + * associated name (up to the user to translate this value). + */ +public class TouchscreenGesture implements Parcelable { + + public final int id; + public final String name; + public final int keycode; + + public TouchscreenGesture(int id, String name, int keycode) { + this.id = id; + this.name = name; + this.keycode = keycode; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeInt(id); + parcel.writeString(name); + parcel.writeInt(keycode); + } + + /** @hide */ + public static final Parcelable.Creator<TouchscreenGesture> CREATOR = + new Parcelable.Creator<TouchscreenGesture>() { + + public TouchscreenGesture createFromParcel(Parcel in) { + return new TouchscreenGesture(in.readInt(), in.readString(), in.readInt()); + } + + @Override + public TouchscreenGesture[] newArray(int size) { + return new TouchscreenGesture[size]; + } + }; +} diff --git a/core/java/com/android/internal/notification/SystemNotificationChannels.java b/core/java/com/android/internal/notification/SystemNotificationChannels.java index 681b46a01c8d..89e6d1f50307 100644 --- a/core/java/com/android/internal/notification/SystemNotificationChannels.java +++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java @@ -113,7 +113,7 @@ public class SystemNotificationChannels { final NotificationChannel developerImportant = new NotificationChannel( DEVELOPER_IMPORTANT, context.getString(R.string.notification_channel_developer_important), - NotificationManager.IMPORTANCE_HIGH); + NotificationManager.IMPORTANCE_MIN); developer.setBlockable(true); channelsList.add(developerImportant); diff --git a/core/java/com/android/internal/os/DeviceKeyHandler.java b/core/java/com/android/internal/os/DeviceKeyHandler.java new file mode 100644 index 000000000000..8902337f3ebb --- /dev/null +++ b/core/java/com/android/internal/os/DeviceKeyHandler.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2012 The CyanogenMod 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.internal.os; + +import android.view.KeyEvent; + +public interface DeviceKeyHandler { + + /** + * Invoked when an unknown key was detected by the system, letting the device handle + * this special keys prior to pass the key to the active app. + * + * @param event The key event to be handled + * @return null if event is consumed, KeyEvent to be handled otherwise + */ + public KeyEvent handleKeyEvent(KeyEvent event); +} diff --git a/core/proto/android/server/appstatetracker.proto b/core/proto/android/server/appstatetracker.proto index f5583d4f476f..0d0fb097d963 100644 --- a/core/proto/android/server/appstatetracker.proto +++ b/core/proto/android/server/appstatetracker.proto @@ -25,7 +25,7 @@ option java_multiple_files = true; // Dump from com.android.server.AppStateTracker. // -// Next ID: 14 +// Next ID: 15 message AppStateTrackerProto { option (.android.msg_privacy).dest = DEST_AUTOMATIC; @@ -41,6 +41,9 @@ message AppStateTrackerProto { // UIDs currently in the foreground. repeated int32 foreground_uids = 11; + // App ids that are in power-save system exemption list. + repeated int32 power_save_system_exempt_app_ids = 14; + // App ids that are in power-save exemption list. repeated int32 power_save_exempt_app_ids = 3; diff --git a/core/res/res/drawable/toast_frame.xml b/core/res/res/drawable/toast_frame.xml index a8cdef6d05f1..34987394b2ec 100644 --- a/core/res/res/drawable/toast_frame.xml +++ b/core/res/res/drawable/toast_frame.xml @@ -17,7 +17,7 @@ --> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> - <solid android:color="?android:attr/colorSurface" /> + <solid android:color="?android:attr/colorBackgroundFloating" /> <corners android:radius="28dp" /> </shape> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index ee8f3e5c2d25..b350a5dc49ab 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -856,11 +856,11 @@ <integer name="config_defaultNightDisplayCustomEndTime">21600000</integer> <!-- Minimum color temperature, in Kelvin, supported by Night display. --> - <integer name="config_nightDisplayColorTemperatureMin">2596</integer> + <integer name="config_nightDisplayColorTemperatureMin">1600</integer> <!-- Default color temperature, in Kelvin, to tint the screen when Night display is activated. --> - <integer name="config_nightDisplayColorTemperatureDefault">2850</integer> + <integer name="config_nightDisplayColorTemperatureDefault">2650</integer> <!-- Maximum color temperature, in Kelvin, supported by Night display. --> <integer name="config_nightDisplayColorTemperatureMax">4082</integer> diff --git a/core/res/res/values/ice_config.xml b/core/res/res/values/ice_config.xml new file mode 100644 index 000000000000..6016dc84e9a2 --- /dev/null +++ b/core/res/res/values/ice_config.xml @@ -0,0 +1,51 @@ +<!-- + Copyright (C) 2022 Project ICE + + 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. +--> +<resources> + <!-- The list of components which should be automatically disabled for a specific device. + Note: this MUST not be used to randomly disable components, ask for approval first! --> + <string-array name="config_deviceDisabledComponents" translatable="false"> + </string-array> + + <!-- The list of components which should be automatically disabled for all devices. --> + <string-array name="config_globallyDisabledComponents" translatable="false"> + </string-array> + + <!-- The list of components which should be forced to be enabled. --> + <string-array name="config_forceEnabledComponents" translatable="false"> + </string-array> + + <!-- Paths to the libraries that contain device specific key handlers --> + <string-array name="config_deviceKeyHandlerLibs" translatable="false"> + </string-array> + + <!-- Names of the key handler classes --> + <string-array name="config_deviceKeyHandlerClasses" translatable="false"> + </string-array> + + <!-- Path to fast charging status file to detect whether an oem fast charger is active --> + <string name="config_oemFastChargerStatusPath" translatable="false"></string> + + <!-- Expected value from fast charging status file --> + <string name="config_oemFastChargerStatusValue" translatable="false">1</string> + + <!-- Whether device has an alert slider --> + <bool name="config_hasAlertSlider" translatable="false">false</bool> + + <!-- The location of the device's alert slider: + 0: Left side + 1: Right side --> + <integer name="config_alertSliderLocation">0</integer> +</resources> diff --git a/core/res/res/values/ice_symbols.xml b/core/res/res/values/ice_symbols.xml new file mode 100644 index 000000000000..394ebe9a115c --- /dev/null +++ b/core/res/res/values/ice_symbols.xml @@ -0,0 +1,35 @@ +<!-- + Copyright (C) 2022 Project ICE + + 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. +--> +<resources> + <!-- Package Manager --> + <java-symbol type="array" name="config_deviceDisabledComponents" /> + <java-symbol type="array" name="config_globallyDisabledComponents" /> + <java-symbol type="array" name="config_forceEnabledComponents" /> + + <!-- Device keyhandlers --> + <java-symbol type="array" name="config_deviceKeyHandlerLibs" /> + <java-symbol type="array" name="config_deviceKeyHandlerClasses" /> + + <!-- Path to fast charging status file to detect whether an oem fast charger is active --> + <java-symbol type="string" name="config_oemFastChargerStatusPath" /> + + <!-- Expected value from fast charging status file --> + <java-symbol type="string" name="config_oemFastChargerStatusValue" /> + + <!-- Alert Slider --> + <java-symbol type="bool" name="config_hasAlertSlider" /> + <java-symbol type="integer" name="config_alertSliderLocation" /> +</resources> diff --git a/data/fonts/Android.bp b/data/fonts/Android.bp index f90a74d939f4..81716878df3a 100644 --- a/data/fonts/Android.bp +++ b/data/fonts/Android.bp @@ -30,16 +30,6 @@ license { } prebuilt_font { - name: "DroidSansMono.ttf", - src: "DroidSansMono.ttf", - required: [ - // Roboto-Regular.ttf provides DroidSans.ttf as a symlink to itself - // Roboto-Regular.ttf provides DroidSans-Bold.ttf as a symlink to itself - "Roboto-Regular.ttf", - ], -} - -prebuilt_font { name: "AndroidClock.ttf", src: "AndroidClock.ttf", } diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml index f8c015f28a50..af451169e549 100644 --- a/data/fonts/fonts.xml +++ b/data/fonts/fonts.xml @@ -25,88 +25,92 @@ <!-- first font is default --> <family name="sans-serif"> <font weight="100" style="normal">Roboto-Regular.ttf - <axis tag="ital" stylevalue="0" /> + <axis tag="slnt" stylevalue="0" /> <axis tag="wdth" stylevalue="100" /> <axis tag="wght" stylevalue="100" /> </font> <font weight="200" style="normal">Roboto-Regular.ttf - <axis tag="ital" stylevalue="0" /> + <axis tag="slnt" stylevalue="0" /> <axis tag="wdth" stylevalue="100" /> <axis tag="wght" stylevalue="200" /> </font> <font weight="300" style="normal">Roboto-Regular.ttf - <axis tag="ital" stylevalue="0" /> + <axis tag="slnt" stylevalue="0" /> <axis tag="wdth" stylevalue="100" /> <axis tag="wght" stylevalue="300" /> </font> - <font weight="400" style="normal">RobotoStatic-Regular.ttf</font> + <font weight="400" style="normal">Roboto-Regular.ttf + <axis tag="slnt" stylevalue="0" /> + <axis tag="wdth" stylevalue="100" /> + <axis tag="wght" stylevalue="400" /> + </font> <font weight="500" style="normal">Roboto-Regular.ttf - <axis tag="ital" stylevalue="0" /> + <axis tag="slnt" stylevalue="0" /> <axis tag="wdth" stylevalue="100" /> <axis tag="wght" stylevalue="500" /> </font> <font weight="600" style="normal">Roboto-Regular.ttf - <axis tag="ital" stylevalue="0" /> + <axis tag="slnt" stylevalue="0" /> <axis tag="wdth" stylevalue="100" /> <axis tag="wght" stylevalue="600" /> </font> <font weight="700" style="normal">Roboto-Regular.ttf - <axis tag="ital" stylevalue="0" /> + <axis tag="slnt" stylevalue="0" /> <axis tag="wdth" stylevalue="100" /> <axis tag="wght" stylevalue="700" /> </font> <font weight="800" style="normal">Roboto-Regular.ttf - <axis tag="ital" stylevalue="0" /> + <axis tag="slnt" stylevalue="0" /> <axis tag="wdth" stylevalue="100" /> <axis tag="wght" stylevalue="800" /> </font> <font weight="900" style="normal">Roboto-Regular.ttf - <axis tag="ital" stylevalue="0" /> + <axis tag="slnt" stylevalue="0" /> <axis tag="wdth" stylevalue="100" /> <axis tag="wght" stylevalue="900" /> </font> <font weight="100" style="italic">Roboto-Regular.ttf - <axis tag="ital" stylevalue="1" /> + <axis tag="slnt" stylevalue="-10" /> <axis tag="wdth" stylevalue="100" /> <axis tag="wght" stylevalue="100" /> </font> <font weight="200" style="italic">Roboto-Regular.ttf - <axis tag="ital" stylevalue="1" /> + <axis tag="slnt" stylevalue="-10" /> <axis tag="wdth" stylevalue="100" /> <axis tag="wght" stylevalue="200" /> </font> <font weight="300" style="italic">Roboto-Regular.ttf - <axis tag="ital" stylevalue="1" /> + <axis tag="slnt" stylevalue="-10" /> <axis tag="wdth" stylevalue="100" /> <axis tag="wght" stylevalue="300" /> </font> <font weight="400" style="italic">Roboto-Regular.ttf - <axis tag="ital" stylevalue="1" /> + <axis tag="slnt" stylevalue="-10" /> <axis tag="wdth" stylevalue="100" /> <axis tag="wght" stylevalue="400" /> </font> <font weight="500" style="italic">Roboto-Regular.ttf - <axis tag="ital" stylevalue="1" /> + <axis tag="slnt" stylevalue="-10" /> <axis tag="wdth" stylevalue="100" /> <axis tag="wght" stylevalue="500" /> </font> <font weight="600" style="italic">Roboto-Regular.ttf - <axis tag="ital" stylevalue="1" /> + <axis tag="slnt" stylevalue="-10" /> <axis tag="wdth" stylevalue="100" /> <axis tag="wght" stylevalue="600" /> </font> <font weight="700" style="italic">Roboto-Regular.ttf - <axis tag="ital" stylevalue="1" /> + <axis tag="slnt" stylevalue="-10" /> <axis tag="wdth" stylevalue="100" /> <axis tag="wght" stylevalue="700" /> </font> <font weight="800" style="italic">Roboto-Regular.ttf - <axis tag="ital" stylevalue="1" /> + <axis tag="slnt" stylevalue="-10" /> <axis tag="wdth" stylevalue="100" /> <axis tag="wght" stylevalue="800" /> </font> <font weight="900" style="italic">Roboto-Regular.ttf - <axis tag="ital" stylevalue="1" /> + <axis tag="slnt" stylevalue="-10" /> <axis tag="wdth" stylevalue="100" /> <axis tag="wght" stylevalue="900" /> </font> @@ -271,6 +275,98 @@ <alias name="source-sans-pro-semi-bold" to="source-sans-pro" weight="600"/> <!-- fallback fonts --> + <family> + <font weight="100" style="normal">RobotoFallback-VF.ttf + <axis tag="ital" stylevalue="0"/> + <axis tag="wdth" stylevalue="100"/> + <axis tag="wght" stylevalue="100"/> + </font> + <font weight="100" style="italic">RobotoFallback-VF.ttf + <axis tag="ital" stylevalue="1"/> + <axis tag="wdth" stylevalue="100"/> + <axis tag="wght" stylevalue="100"/> + </font> + <font weight="200" style="normal">RobotoFallback-VF.ttf + <axis tag="ital" stylevalue="0"/> + <axis tag="wdth" stylevalue="100"/> + <axis tag="wght" stylevalue="200"/> + </font> + <font weight="200" style="italic">RobotoFallback-VF.ttf + <axis tag="ital" stylevalue="1"/> + <axis tag="wdth" stylevalue="100"/> + <axis tag="wght" stylevalue="200"/> + </font> + <font weight="300" style="normal">RobotoFallback-VF.ttf + <axis tag="ital" stylevalue="0"/> + <axis tag="wdth" stylevalue="100"/> + <axis tag="wght" stylevalue="300"/> + </font> + <font weight="300" style="italic">RobotoFallback-VF.ttf + <axis tag="ital" stylevalue="1"/> + <axis tag="wdth" stylevalue="100"/> + <axis tag="wght" stylevalue="300"/> + </font> + <font weight="400" style="normal">RobotoFallback-VF.ttf + <axis tag="ital" stylevalue="0"/> + <axis tag="wdth" stylevalue="100"/> + <axis tag="wght" stylevalue="400"/> + </font> + <font weight="400" style="italic">RobotoFallback-VF.ttf + <axis tag="ital" stylevalue="1"/> + <axis tag="wdth" stylevalue="100"/> + <axis tag="wght" stylevalue="400"/> + </font> + <font weight="500" style="normal">RobotoFallback-VF.ttf + <axis tag="ital" stylevalue="0"/> + <axis tag="wdth" stylevalue="100"/> + <axis tag="wght" stylevalue="500"/> + </font> + <font weight="500" style="italic">RobotoFallback-VF.ttf + <axis tag="ital" stylevalue="1"/> + <axis tag="wdth" stylevalue="100"/> + <axis tag="wght" stylevalue="500"/> + </font> + <font weight="600" style="normal">RobotoFallback-VF.ttf + <axis tag="ital" stylevalue="0"/> + <axis tag="wdth" stylevalue="100"/> + <axis tag="wght" stylevalue="600"/> + </font> + <font weight="600" style="italic">RobotoFallback-VF.ttf + <axis tag="ital" stylevalue="1"/> + <axis tag="wdth" stylevalue="100"/> + <axis tag="wght" stylevalue="600"/> + </font> + <font weight="700" style="normal">RobotoFallback-VF.ttf + <axis tag="ital" stylevalue="0"/> + <axis tag="wdth" stylevalue="100"/> + <axis tag="wght" stylevalue="700"/> + </font> + <font weight="700" style="italic">RobotoFallback-VF.ttf + <axis tag="ital" stylevalue="1"/> + <axis tag="wdth" stylevalue="100"/> + <axis tag="wght" stylevalue="700"/> + </font> + <font weight="800" style="normal">RobotoFallback-VF.ttf + <axis tag="ital" stylevalue="0"/> + <axis tag="wdth" stylevalue="100"/> + <axis tag="wght" stylevalue="800"/> + </font> + <font weight="800" style="italic">RobotoFallback-VF.ttf + <axis tag="ital" stylevalue="1"/> + <axis tag="wdth" stylevalue="100"/> + <axis tag="wght" stylevalue="800"/> + </font> + <font weight="900" style="normal">RobotoFallback-VF.ttf + <axis tag="ital" stylevalue="0"/> + <axis tag="wdth" stylevalue="100"/> + <axis tag="wght" stylevalue="900"/> + </font> + <font weight="900" style="italic">RobotoFallback-VF.ttf + <axis tag="ital" stylevalue="1"/> + <axis tag="wdth" stylevalue="100"/> + <axis tag="wght" stylevalue="900"/> + </font> + </family> <family lang="und-Arab" variant="elegant"> <font weight="400" style="normal" postScriptName="NotoNaskhArabic"> NotoNaskhArabic-Regular.ttf diff --git a/data/keyboards/Generic.kcm b/data/keyboards/Generic.kcm index fe6eeeb66e40..3c7178022261 100644 --- a/data/keyboards/Generic.kcm +++ b/data/keyboards/Generic.kcm @@ -498,7 +498,7 @@ key PLUS { ### Non-printing keys ### key ESCAPE { - base: none + base: fallback BACK alt, meta: fallback HOME ctrl: fallback MENU } diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index f438a03b1434..6621d1f23166 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -260,7 +260,7 @@ public class Paint { // These flags are always set on a new/reset paint, even if flags 0 is passed. static final int HIDDEN_DEFAULT_PAINT_FLAGS = DEV_KERN_TEXT_FLAG | EMBEDDED_BITMAP_TEXT_FLAG - | FILTER_BITMAP_FLAG; + | FILTER_BITMAP_FLAG | SUBPIXEL_TEXT_FLAG; /** * Font hinter option that disables font hinting. diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index a2f5301e353f..64ac679de31e 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -212,6 +212,8 @@ public class Typeface { private @IntRange(from = 0, to = FontStyle.FONT_WEIGHT_MAX) final int mWeight; + private boolean mIsSystemDefault; + // Value for weight and italic. Indicates the value is resolved by font metadata. // Must be the same as the C++ constant in core/jni/android/graphics/FontFamily.cpp /** @hide */ @@ -237,6 +239,7 @@ public class Typeface { */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private static void setDefault(Typeface t) { + t.mIsSystemDefault = true; synchronized (SYSTEM_FONT_MAP_LOCK) { sDefaultTypeface = t; nativeSetDefault(t.native_instance); @@ -933,7 +936,7 @@ public class Typeface { } } - typeface = new Typeface(nativeCreateFromTypeface(ni, style)); + typeface = new Typeface(nativeCreateFromTypeface(ni, style), family.mIsSystemDefault); styles.put(style, typeface); } return typeface; @@ -1001,7 +1004,8 @@ public class Typeface { } typeface = new Typeface( - nativeCreateFromTypefaceWithExactStyle(base.native_instance, weight, italic)); + nativeCreateFromTypefaceWithExactStyle(base.native_instance, weight, italic), + base.mIsSystemDefault); innerCache.put(key, typeface); } return typeface; @@ -1011,7 +1015,8 @@ public class Typeface { public static Typeface createFromTypefaceWithVariation(@Nullable Typeface family, @NonNull List<FontVariationAxis> axes) { final Typeface base = family == null ? Typeface.DEFAULT : family; - return new Typeface(nativeCreateFromTypefaceWithVariation(base.native_instance, axes)); + return new Typeface(nativeCreateFromTypefaceWithVariation(base.native_instance, axes), + base.mIsSystemDefault); } /** @@ -1174,6 +1179,12 @@ public class Typeface { mCleaner = sRegistry.registerNativeAllocation(this, native_instance); mStyle = nativeGetStyle(ni); mWeight = nativeGetWeight(ni); + mIsSystemDefault = false; + } + + private Typeface(long ni, boolean isSystemDefault) { + this(ni); + mIsSystemDefault = isSystemDefault; } private static Typeface getSystemDefaultTypeface(@NonNull String familyName) { @@ -1189,6 +1200,7 @@ public class Typeface { for (Map.Entry<String, FontFamily[]> entry : fallbacks.entrySet()) { outSystemFontMap.put(entry.getKey(), createFromFamilies(entry.getValue())); } + outSystemFontMap.get("sans-serif").mIsSystemDefault = true; for (int i = 0; i < aliases.size(); ++i) { final FontConfig.Alias alias = aliases.get(i); @@ -1203,7 +1215,8 @@ public class Typeface { } final int weight = alias.getWeight(); final Typeface newFace = weight == 400 ? base : - new Typeface(nativeCreateWeightAlias(base.native_instance, weight)); + new Typeface(nativeCreateWeightAlias(base.native_instance, weight), + base.mIsSystemDefault); outSystemFontMap.put(alias.getName(), newFace); } } @@ -1230,6 +1243,7 @@ public class Typeface { for (Map.Entry<String, Typeface> entry : fontMap.entrySet()) { nativePtrs[i++] = entry.getValue().native_instance; writeString(namesBytes, entry.getKey()); + writeInt(namesBytes, entry.getValue().mIsSystemDefault ? 1 : 0); } int typefacesBytesCount = nativeWriteTypefaces(null, nativePtrs); // int (typefacesBytesCount), typefaces, namesBytes @@ -1271,7 +1285,8 @@ public class Typeface { buffer.position(buffer.position() + typefacesBytesCount); for (long nativePtr : nativePtrs) { String name = readString(buffer); - out.put(name, new Typeface(nativePtr)); + boolean isSystemDefault = buffer.getInt() == 1; + out.put(name, new Typeface(nativePtr, isSystemDefault)); } return nativePtrs; } @@ -1496,6 +1511,11 @@ public class Typeface { return families; } + /** @hide */ + public boolean isSystemFont() { + return mIsSystemDefault; + } + private static native long nativeCreateFromTypeface(long native_instance, int style); private static native long nativeCreateFromTypefaceWithExactStyle( long native_instance, int weight, boolean italic); diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/styles.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/styles.xml index d0b6c4d54bb1..737d6ac69d40 100644 --- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/styles.xml +++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/styles.xml @@ -19,10 +19,12 @@ <item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item> <item name="android:textSize">20dp</item> <item name="android:textColor">@color/settingslib_text_color_primary_device_default</item> + <item name="android:letterSpacing">-0.016657338648324763</item> </style> <style name="CollapsingToolbarTitle.Expanded" parent="CollapsingToolbarTitle.Collapsed"> <item name="android:textSize">36dp</item> <item name="android:textColor">@color/settingslib_text_color_primary_device_default</item> + <item name="android:letterSpacing">-0.02195411335559237</item> </style> -</resources>
\ No newline at end of file +</resources> diff --git a/packages/SettingsLib/res/drawable/ic_4g_plus_mobiledata.xml b/packages/SettingsLib/res/drawable/ic_4g_plus_mobiledata.xml index 1d048ae44049..1272ea7a30e1 100644 --- a/packages/SettingsLib/res/drawable/ic_4g_plus_mobiledata.xml +++ b/packages/SettingsLib/res/drawable/ic_4g_plus_mobiledata.xml @@ -14,20 +14,17 @@ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="19.41dp" - android:height="15dp" - android:viewportWidth="22" - android:viewportHeight="17"> - - <path - android:fillColor="#FFFFFFFF" - android:pathData="M5.32,10.13h1.11v1.03H5.32v2.31H4.11v-2.31H0.35v-0.75l3.7-6.9h1.27V10.13z M1.69,10.13h2.42V5.4L1.69,10.13z" /> + android:width="27dp" + android:height="16dp" + android:viewportWidth="27.0" + android:viewportHeight="16.0"> <path - android:fillColor="#FFFFFFFF" - android:pathData="M14.15,12.24l-0.22,0.27c-0.63,0.73-1.55,1.1-2.76,1.1c-1.08,0-1.92-0.36-2.53-1.07c-0.61-0.71-0.93-1.72-0.94-3.02V7.56 c0-1.39,0.28-2.44,0.84-3.13s1.39-1.04,2.51-1.04c0.95,0,1.69,0.26,2.23,0.79s0.83,1.28,0.89,2.26H12.9 c-0.05-0.62-0.22-1.1-0.52-1.45s-0.74-0.52-1.34-0.52c-0.72,0-1.24,0.23-1.57,0.7S8.97,6.37,8.96,7.4v2.03 c0,1,0.19,1.77,0.57,2.31c0.38,0.54,0.93,0.8,1.65,0.8c0.67,0,1.19-0.16,1.54-0.49l0.18-0.17V9.59h-1.82V8.52h3.07V12.24z" /> + android:fillColor="#FF000000" + android:pathData="M2,10.98V9.81l4.28,-6.83h1.6v6.59h1.19v1.41H7.88V13H6.4v-2.02H2zM3.68,9.57H6.4V5.33H6.31L3.68,9.57z"/> <path - android:fillColor="#FFFFFFFF" - android:pathData="M 19.3 5.74 L 19.3 3.39 L 18 3.39 L 18 5.74 L 15.65 5.74 L 15.65 7.04 L 18 7.04 L 18 9.39 L 19.3 9.39 L 19.3 7.04 L 21.65 7.04 L 21.65 5.74 Z" /> + android:fillColor="#FF000000" + android:pathData="M15,13.22c-0.88,0 -1.66,-0.21 -2.34,-0.64c-0.67,-0.44 -1.2,-1.05 -1.6,-1.83c-0.38,-0.79 -0.57,-1.71 -0.57,-2.76c0,-1.05 0.21,-1.96 0.62,-2.74c0.41,-0.79 0.97,-1.4 1.67,-1.83c0.7,-0.44 1.5,-0.66 2.39,-0.66c1.09,0 2.01,0.25 2.74,0.76c0.75,0.5 1.22,1.21 1.41,2.11l-1.47,0.39c-0.17,-0.56 -0.48,-1 -0.94,-1.32c-0.45,-0.33 -1.03,-0.49 -1.75,-0.49c-0.57,0 -1.09,0.14 -1.57,0.43c-0.48,0.29 -0.85,0.71 -1.13,1.27c-0.28,0.56 -0.42,1.25 -0.42,2.07c0,0.81 0.14,1.5 0.41,2.07c0.28,0.56 0.65,0.98 1.11,1.27c0.47,0.29 0.98,0.43 1.54,0.43c0.57,0 1.06,-0.11 1.47,-0.34c0.42,-0.23 0.75,-0.55 0.99,-0.94c0.25,-0.4 0.41,-0.85 0.46,-1.36h-2.88V7.79h4.37c0,0.87 0,1.74 0,2.6c0,0.87 0,1.74 0,2.6h-1.41v-1.4h-0.08c-0.28,0.49 -0.67,0.88 -1.18,1.18C16.34,13.07 15.73,13.22 15,13.22z"/> <path - android:pathData="M 0 0 H 22 V 17 H 0 V 0 Z" /> + android:fillColor="#FF000000" + android:pathData="M24.62 5.24 24.62 2.89 23.32 2.89 23.32 5.24 20.97 5.24 20.97 6.54 23.32 6.54 23.32 8.89 24.62 8.89 24.62 6.54 26.97 6.54 26.97 5.24Z"/> </vector> diff --git a/packages/SettingsLib/res/drawable/ic_lte_plus_mobiledata.xml b/packages/SettingsLib/res/drawable/ic_lte_plus_mobiledata.xml index e5cdff33fe98..d1f4b6fd818b 100644 --- a/packages/SettingsLib/res/drawable/ic_lte_plus_mobiledata.xml +++ b/packages/SettingsLib/res/drawable/ic_lte_plus_mobiledata.xml @@ -14,23 +14,20 @@ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="22.94dp" - android:height="15dp" - android:viewportWidth="26" - android:viewportHeight="17"> - - <path - android:fillColor="#FFFFFFFF" - android:pathData="M1.59,12.4h3.9v1.07H0.33V3.52h1.26V12.4z" /> + android:width="31dp" + android:height="16dp" + android:viewportWidth="31.0" + android:viewportHeight="16.0"> <path - android:fillColor="#FFFFFFFF" - android:pathData="M11.35,4.6H8.73v8.88H7.48V4.6H4.87V3.52h6.48V4.6z" /> + android:fillColor="#FF000000" + android:pathData="M2,13V2.98h1.53v8.57H8.3V13H2z"/> <path - android:fillColor="#FFFFFFFF" - android:pathData="M17.59,8.88h-3.52v3.53h4.1v1.07h-5.35V3.52h5.28V4.6h-4.03V7.8h3.52V8.88z" /> + android:fillColor="#FF000000" + android:pathData="M11.24,13V4.43H8.19V2.98h7.63v1.46h-3.05V13H11.24z"/> <path - android:fillColor="#FFFFFFFF" - android:pathData="M 23.32 5.74 L 23.32 3.39 L 22.02 3.39 L 22.02 5.74 L 19.67 5.74 L 19.67 7.04 L 22.02 7.04 L 22.02 9.39 L 23.32 9.39 L 23.32 7.04 L 25.67 7.04 L 25.67 5.74 Z" /> + android:fillColor="#FF000000" + android:pathData="M17.41,13V2.98h6.36v1.46h-4.83v2.65h4.4v1.46h-4.4v3.01h4.83V13H17.41z"/> <path - android:pathData="M 0 0 H 26 V 17 H 0 V 0 Z" /> + android:fillColor="#FF000000" + android:pathData="M28.72 5.24 28.72 2.89 27.42 2.89 27.42 5.24 25.07 5.24 25.07 6.54 27.42 6.54 27.42 8.89 28.72 8.89 28.72 6.54 31.07 6.54 31.07 5.24Z"/> </vector> diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java index 132a631e25cc..21fb26976c1b 100644 --- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java +++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java @@ -27,6 +27,7 @@ import static android.os.BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE; import static android.os.BatteryManager.EXTRA_PLUGGED; import static android.os.BatteryManager.EXTRA_PRESENT; import static android.os.BatteryManager.EXTRA_STATUS; +import static android.os.BatteryManager.EXTRA_OEM_FAST_CHARGER; import android.content.Context; import android.content.Intent; @@ -51,15 +52,17 @@ public class BatteryStatus { public final int plugged; public final int health; public final int maxChargingWattage; + public final boolean oemFastChargeStatus; public final boolean present; public BatteryStatus(int status, int level, int plugged, int health, - int maxChargingWattage, boolean present) { + int maxChargingWattage, boolean oemFastChargeStatus, boolean present) { this.status = status; this.level = level; this.plugged = plugged; this.health = health; this.maxChargingWattage = maxChargingWattage; + this.oemFastChargeStatus = oemFastChargeStatus; this.present = present; } @@ -68,6 +71,7 @@ public class BatteryStatus { plugged = batteryChangedIntent.getIntExtra(EXTRA_PLUGGED, 0); level = batteryChangedIntent.getIntExtra(EXTRA_LEVEL, 0); health = batteryChangedIntent.getIntExtra(EXTRA_HEALTH, BATTERY_HEALTH_UNKNOWN); + oemFastChargeStatus = batteryChangedIntent.getBooleanExtra(EXTRA_OEM_FAST_CHARGER, false); present = batteryChangedIntent.getBooleanExtra(EXTRA_PRESENT, true); final int maxChargingMicroAmp = batteryChangedIntent.getIntExtra(EXTRA_MAX_CHARGING_CURRENT, @@ -162,6 +166,9 @@ public class BatteryStatus { * @return the charing speed */ public final int getChargingSpeed(Context context) { + if (oemFastChargeStatus) { + return CHARGING_FAST; + } final int slowThreshold = context.getResources().getInteger( R.integer.config_chargingSlowlyThreshold); final int fastThreshold = context.getResources().getInteger( diff --git a/packages/SystemUI/customization/res/font/clock.xml b/packages/SystemUI/customization/res/font/clock.xml new file mode 100644 index 000000000000..5122fe74719b --- /dev/null +++ b/packages/SystemUI/customization/res/font/clock.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** +** Copyright 2020, 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. +*/ +--> + +<!-- +** AOD/LockScreen Clock font. +** Should include all numeric glyphs in all supported locales. +** Recommended: font with variable width to support AOD => LS animations +--> +<font-family xmlns:android="http://schemas.android.com/apk/res/android"> + <font android:font="@font/google_sans_clock"/> +</font-family>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/font/google_sans_clock.ttf b/packages/SystemUI/customization/res/font/google_sans_clock.ttf Binary files differnew file mode 100644 index 000000000000..5e683a05088c --- /dev/null +++ b/packages/SystemUI/customization/res/font/google_sans_clock.ttf diff --git a/packages/SystemUI/customization/res/layout/clock_default_large.xml b/packages/SystemUI/customization/res/layout/clock_default_large.xml index 0139d50dcfba..415f964a215f 100644 --- a/packages/SystemUI/customization/res/layout/clock_default_large.xml +++ b/packages/SystemUI/customization/res/layout/clock_default_large.xml @@ -23,7 +23,7 @@ android:layout_gravity="center" android:gravity="center_horizontal" android:textSize="@dimen/large_clock_text_size" - android:fontFamily="@*android:string/config_clockFontFamily" + android:fontFamily="@font/clock" android:typeface="monospace" android:elegantTextHeight="false" chargeAnimationDelay="200" diff --git a/packages/SystemUI/customization/res/layout/clock_default_small.xml b/packages/SystemUI/customization/res/layout/clock_default_small.xml index ff6d7f9e2240..eb86ae50cbc9 100644 --- a/packages/SystemUI/customization/res/layout/clock_default_small.xml +++ b/packages/SystemUI/customization/res/layout/clock_default_small.xml @@ -23,7 +23,7 @@ android:layout_gravity="start" android:gravity="start" android:textSize="@dimen/small_clock_text_size" - android:fontFamily="@*android:string/config_clockFontFamily" + android:fontFamily="@font/clock" android:elegantTextHeight="false" android:ellipsize="none" android:singleLine="true" diff --git a/packages/SystemUI/res/drawable-nodpi/udfps_icon_pressed.png b/packages/SystemUI/res/drawable-nodpi/udfps_icon_pressed.png Binary files differnew file mode 100644 index 000000000000..4102e28c1300 --- /dev/null +++ b/packages/SystemUI/res/drawable-nodpi/udfps_icon_pressed.png diff --git a/packages/SystemUI/res/drawable/dialog_tri_state_down_bg.xml b/packages/SystemUI/res/drawable/dialog_tri_state_down_bg.xml new file mode 100644 index 000000000000..7dddc9d0e930 --- /dev/null +++ b/packages/SystemUI/res/drawable/dialog_tri_state_down_bg.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2019 CypherOS + + 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. +--> +<layer-list + xmlns:android="http://schemas.android.com/apk/res/android"> + <item> + <shape> + <solid android:color="#ff1d1d1d" /> + <corners + android:topLeftRadius="@dimen/tri_state_down_top_left_radius" + android:topRightRadius="@dimen/tri_state_down_top_right_radius" + android:bottomLeftRadius="@dimen/tri_state_down_bottom_left_radius" + android:bottomRightRadius="@dimen/tri_state_down_bottom_right_radius" /> + </shape> + </item> +</layer-list>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/dialog_tri_state_middle_bg.xml b/packages/SystemUI/res/drawable/dialog_tri_state_middle_bg.xml new file mode 100644 index 000000000000..7cde6be2808c --- /dev/null +++ b/packages/SystemUI/res/drawable/dialog_tri_state_middle_bg.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2019 CypherOS + + 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. +--> +<layer-list + xmlns:android="http://schemas.android.com/apk/res/android"> + <item> + <shape> + <solid android:color="#ff1d1d1d" /> + <corners + android:topLeftRadius="@dimen/tri_state_mid_top_left_radius" + android:topRightRadius="@dimen/tri_state_mid_top_right_radius" + android:bottomLeftRadius="@dimen/tri_state_mid_bottom_left_radius" + android:bottomRightRadius="@dimen/tri_state_mid_bottom_right_radius" /> + </shape> + </item> +</layer-list>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/dialog_tri_state_up_bg.xml b/packages/SystemUI/res/drawable/dialog_tri_state_up_bg.xml new file mode 100644 index 000000000000..69757a77ee86 --- /dev/null +++ b/packages/SystemUI/res/drawable/dialog_tri_state_up_bg.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2019 CypherOS + + 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. +--> +<layer-list + xmlns:android="http://schemas.android.com/apk/res/android"> + <item> + <shape> + <solid android:color="#ff1d1d1d" /> + <corners + android:topLeftRadius="@dimen/tri_state_up_top_left_radius" + android:topRightRadius="@dimen/tri_state_up_top_right_radius" + android:bottomLeftRadius="@dimen/tri_state_up_bottom_left_radius" + android:bottomRightRadius="@dimen/tri_state_up_bottom_right_radius" /> + </shape> + </item> +</layer-list>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_qs_aod.xml b/packages/SystemUI/res/drawable/ic_qs_aod.xml new file mode 100644 index 000000000000..4bb2d4ac566b --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_aod.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + + <path + android:fillColor="#ffffff" + android:pathData="M17,19 L17,5 L7,5 L7,19 L17,19 M17,1 C18.1046,1,19,1.89543,19,3 L19,21 C19,22.1046,18.1046,23,17,23 L7,23 C5.89,23,5,22.1,5,21 L5,3 C5,1.89,5.89,1,7,1 L17,1 M9,7 L15,7 L15,9 L9,9 L9,7" /> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_caffeine.xml b/packages/SystemUI/res/drawable/ic_qs_caffeine.xml new file mode 100644 index 000000000000..2c3ba974a7e1 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_caffeine.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (c) 2015 The CyanogenMod Project + Copyright (c) 2017 The LineageOS 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="48dp" + android:height="48dp" + android:viewportWidth="24" + android:viewportHeight="24"> + + <path + android:fillColor="#FFFFFFFF" + android:pathData="M2,21H20V19H2M20,8H18V5H20M20,3H4V13A4,4 0 0,0 8,17H14A4,4 0 0,0 18,13V10H20A2,2 0 0,0 22,8V5C22,3.89 21.1,3 20,3Z" /> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_heads_up.xml b/packages/SystemUI/res/drawable/ic_qs_heads_up.xml new file mode 100644 index 000000000000..b107602787c1 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_heads_up.xml @@ -0,0 +1,36 @@ +<!-- +Copyright (C) 2014 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="64dp" + android:height="64dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + + <path + android:pathData="M0,0h24v24H0V0z" /> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M18,16v-5c0-3.07-1.64-5.64-4.5-6.32V4c0-0.83-0.68-1.5-1.51-1.5S10.5,3.17,10.5,4v0.68C7.63,5.36,6,7.92,6,11v5 l-1.3,1.29C4.07,17.92,4.51,19,5.4,19h13.17c0.89,0,1.34-1.08,0.71-1.71L18,16z" /> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M11.99,22c1.1,0,2-0.9,2-2h-4C9.99,21.1,10.88,22,11.99,22z" /> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M6.77,4.73C7.19,4.35,7.2,3.7,6.8,3.3l0,0c-0.38-0.38-1-0.39-1.39-0.02C3.7,4.84,2.52,6.96,2.14,9.34 C2.05,9.95,2.52,10.5,3.14,10.5h0c0.48,0,0.9-0.35,0.98-0.83C4.42,7.73,5.38,6,6.77,4.73z" /> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M18.6,3.28c-0.4-0.37-1.02-0.36-1.4,0.02l0,0c-0.4,0.4-0.38,1.04,0.03,1.42c1.38,1.27,2.35,3,2.65,4.94 c0.07,0.48,0.49,0.83,0.98,0.83c0.61,0,1.09-0.55,0.99-1.16C21.47,6.96,20.3,4.85,18.6,3.28z" /> +</vector> diff --git a/packages/SystemUI/res/drawable/stat_sys_dnd.xml b/packages/SystemUI/res/drawable/stat_sys_dnd.xml index aa352b42cf04..da861eb72845 100644 --- a/packages/SystemUI/res/drawable/stat_sys_dnd.xml +++ b/packages/SystemUI/res/drawable/stat_sys_dnd.xml @@ -17,6 +17,6 @@ */ --> <inset xmlns:android="http://schemas.android.com/apk/res/android" - android:insetLeft="2.5dp" - android:insetRight="2.5dp" + android:insetLeft="0dp" + android:insetRight="0dp" android:drawable="@*android:drawable/ic_qs_dnd" />
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml b/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml index a8f0cc3a1d92..1a0599107f69 100644 --- a/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml +++ b/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml @@ -14,8 +14,8 @@ Copyright (C) 2015 The Android Open Source Project limitations under the License. --> <inset xmlns:android="http://schemas.android.com/apk/res/android" - android:insetLeft="3dp" - android:insetRight="3dp"> + android:insetLeft="0.5dp" + android:insetRight="0.5dp"> <vector android:width="18dp" android:height="18dp" android:viewportWidth="24.0" diff --git a/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml b/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml index 21a4c1703d31..5d196846822a 100644 --- a/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml +++ b/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml @@ -14,6 +14,6 @@ limitations under the License. --> <inset xmlns:android="http://schemas.android.com/apk/res/android" - android:insetLeft="2.5dp" - android:insetRight="2.5dp" - android:drawable="@drawable/ic_volume_ringer_vibrate" />
\ No newline at end of file + android:insetLeft="0dp" + android:insetRight="0dp" + android:drawable="@drawable/ic_volume_ringer_vibrate" /> diff --git a/packages/SystemUI/res/layout-land/volume_dialog.xml b/packages/SystemUI/res/layout-land/volume_dialog.xml index 3b70dc060e84..116877b44eaa 100644 --- a/packages/SystemUI/res/layout-land/volume_dialog.xml +++ b/packages/SystemUI/res/layout-land/volume_dialog.xml @@ -20,8 +20,6 @@ android:id="@+id/volume_dialog_container" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:gravity="right" - android:layout_gravity="right" android:background="@android:color/transparent" android:theme="@style/volume_dialog_theme"> @@ -30,9 +28,8 @@ android:id="@+id/volume_dialog" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:gravity="right" - android:layout_gravity="right" - android:layout_marginRight="@dimen/volume_dialog_panel_transparent_padding_right" + android:paddingLeft="@dimen/volume_dialog_panel_transparent_padding_left" + android:paddingRight="@dimen/volume_dialog_panel_transparent_padding_right" android:orientation="vertical" android:clipToPadding="false" android:clipChildren="false"> @@ -43,8 +40,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" - android:clipChildren="false" - android:gravity="right"> + android:clipChildren="false"> <include layout="@layout/volume_ringer_drawer" /> @@ -149,4 +145,4 @@ android:layout_gravity="bottom | right" android:layout_marginRight="@dimen/volume_tool_tip_right_margin"/> -</FrameLayout>
\ No newline at end of file +</FrameLayout> diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml index b1d3ed05333b..f0f8c0c79b17 100644 --- a/packages/SystemUI/res/layout/qs_footer_impl.xml +++ b/packages/SystemUI/res/layout/qs_footer_impl.xml @@ -64,7 +64,7 @@ android:layout_width="@dimen/qs_footer_action_button_size" android:layout_height="@dimen/qs_footer_action_button_size" android:layout_gravity="center_vertical|end" - android:background="?android:attr/selectableItemBackground" + android:background="?android:attr/actionBarItemBackground" android:clickable="true" android:contentDescription="@string/accessibility_quick_settings_edit" android:focusable="true" diff --git a/packages/SystemUI/res/layout/tri_state_dialog.xml b/packages/SystemUI/res/layout/tri_state_dialog.xml new file mode 100644 index 000000000000..cf3890d59a88 --- /dev/null +++ b/packages/SystemUI/res/layout/tri_state_dialog.xml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2019 CypherOS + + 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:paddingLeft="@dimen/tri_state_dialog_padding" + android:paddingTop="@dimen/tri_state_dialog_padding" + android:paddingRight="@dimen/tri_state_dialog_padding" + android:paddingBottom="@dimen/tri_state_dialog_padding" + android:clipToPadding="false" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentTop="true"> + + <LinearLayout + android:layout_gravity="center|right" + android:orientation="horizontal" + android:id="@+id/tri_state_layout" + android:background="@drawable/dialog_tri_state_middle_bg" + android:layout_width="wrap_content" + android:layout_height="48.0dip" + android:translationZ="@dimen/tri_state_dialog_elevation"> + + <FrameLayout + android:layout_width="54.0dip" + android:layout_height="fill_parent"> + + <ImageView + android:layout_gravity="center" + android:id="@+id/tri_state_icon" + android:layout_marginLeft="2.0dip" + android:layout_width="@dimen/tri_state_dialog_icon_size" + android:layout_height="@dimen/tri_state_dialog_icon_size" /> + </FrameLayout> + + <TextView + android:gravity="center_vertical" + android:id="@+id/tri_state_text" + android:layout_width="wrap_content" + android:layout_height="fill_parent" + style="@style/TriStateUiText" /> + + <FrameLayout + android:layout_width="18.0dip" + android:layout_height="fill_parent" /> + </LinearLayout> +</LinearLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/udfps_view.xml b/packages/SystemUI/res/layout/udfps_view.xml index 257d238f5c54..0fcbfa161ddf 100644 --- a/packages/SystemUI/res/layout/udfps_view.xml +++ b/packages/SystemUI/res/layout/udfps_view.xml @@ -28,4 +28,10 @@ android:layout_width="match_parent" android:layout_height="match_parent"/> + <com.android.systemui.biometrics.UdfpsSurfaceView + android:id="@+id/hbm_view" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:visibility="invisible"/> + </com.android.systemui.biometrics.UdfpsView> diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml index 6a192d4b7e05..c73050575a1c 100644 --- a/packages/SystemUI/res/layout/volume_dialog.xml +++ b/packages/SystemUI/res/layout/volume_dialog.xml @@ -20,8 +20,6 @@ android:id="@+id/volume_dialog_container" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:gravity="right" - android:layout_gravity="right" android:clipToPadding="false" android:theme="@style/volume_dialog_theme"> @@ -30,9 +28,8 @@ android:id="@+id/volume_dialog" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:gravity="right" - android:layout_gravity="right" - android:layout_marginRight="@dimen/volume_dialog_panel_transparent_padding_right" + android:paddingLeft="@dimen/volume_dialog_panel_transparent_padding_left" + android:paddingRight="@dimen/volume_dialog_panel_transparent_padding_right" android:orientation="vertical" android:clipToPadding="false" android:clipChildren="false"> @@ -73,7 +70,6 @@ <include layout="@layout/volume_dnd_icon" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginRight="@dimen/volume_dialog_stream_padding" android:layout_marginTop="6dp"/> </FrameLayout> @@ -145,7 +141,6 @@ android:layout="@layout/volume_tool_tip_view" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="bottom | right" android:layout_marginRight="@dimen/volume_tool_tip_right_margin"/> -</FrameLayout>
\ No newline at end of file +</FrameLayout> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index ca2426854ada..6cfa07467478 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -81,7 +81,7 @@ <!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" --> <string name="quick_settings_tiles_stock" translatable="false"> - internet,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness,qr_code_scanner,onehanded,color_correction,dream + internet,bt,flashlight,dnd,alarm,airplane,nfc,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness,qr_code_scanner,onehanded,color_correction,dream,aod,caffeine,heads_up </string> <!-- The tiles to display in QuickSettings --> diff --git a/packages/SystemUI/res/values/ice_config.xml b/packages/SystemUI/res/values/ice_config.xml new file mode 100644 index 000000000000..563d63f7ac2a --- /dev/null +++ b/packages/SystemUI/res/values/ice_config.xml @@ -0,0 +1,22 @@ +<!-- + Copyright (C) 2022 Project ICE + + 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. +--> +<resources> + <!-- Color of the UDFPS pressed view --> + <color name="config_udfpsColor">#ffffffff</color> + + <!-- Allow devices override audio panel location to the left side --> + <bool name="config_audioPanelOnLeftSide">false</bool> +</resources> diff --git a/packages/SystemUI/res/values/ice_dimens.xml b/packages/SystemUI/res/values/ice_dimens.xml new file mode 100644 index 000000000000..59368978decd --- /dev/null +++ b/packages/SystemUI/res/values/ice_dimens.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2022 Project ICE + + 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. +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Alert Slider --> + <dimen name="tri_state_down_dialog_position">0px</dimen> + <dimen name="tri_state_down_dialog_position_l">0px</dimen> + <dimen name="tri_state_middle_dialog_position">0px</dimen> + <dimen name="tri_state_middle_dialog_position_l">0px</dimen> + <dimen name="tri_state_up_dialog_position">0px</dimen> + <dimen name="tri_state_up_dialog_position_l">0px</dimen> + <dimen name="tri_state_up_dialog_position_deep">0px</dimen> + <dimen name="tri_state_up_dialog_position_deep_land">0px</dimen> + <dimen name="tri_state_dialog_elevation">4.0dip</dimen> + <dimen name="tri_state_dialog_icon_size">24.0dip</dimen> + <dimen name="tri_state_dialog_padding">8.0dip</dimen> + <dimen name="tri_state_down_bottom_left_radius">24.0dip</dimen> + <dimen name="tri_state_down_bottom_right_radius">24.0dip</dimen> + <dimen name="tri_state_down_top_left_radius">24.0dip</dimen> + <dimen name="tri_state_down_top_right_radius">0.0dip</dimen> + <dimen name="tri_state_mid_bottom_left_radius">24.0dip</dimen> + <dimen name="tri_state_mid_bottom_right_radius">24.0dip</dimen> + <dimen name="tri_state_mid_top_left_radius">24.0dip</dimen> + <dimen name="tri_state_mid_top_right_radius">24.0dip</dimen> + <dimen name="tri_state_up_bottom_left_radius">24.0dip</dimen> + <dimen name="tri_state_up_bottom_right_radius">0.0dip</dimen> + <dimen name="tri_state_up_top_left_radius">24.0dip</dimen> + <dimen name="tri_state_up_top_right_radius">24.0dip</dimen> + + <!-- Volume panel --> + <dimen name="volume_dialog_panel_transparent_padding_left">8dp</dimen> +</resources> diff --git a/packages/SystemUI/res/values/ice_strings.xml b/packages/SystemUI/res/values/ice_strings.xml new file mode 100644 index 000000000000..71c70b9ca36b --- /dev/null +++ b/packages/SystemUI/res/values/ice_strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2008 The Android Open Source Project + Copyright (C) 2022 Project ICE + + 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. +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Custom QS tiles --> + <!-- AOD QS tile --> + <string name="quick_settings_aod_label">AOD</string> + <string name="quick_settings_aod_off_powersave_label">AOD off\nBattery saver</string> + + <!-- Caffeine QS tile --> + <string name="quick_settings_caffeine_label">Caffeine</string> + <string name="accessibility_quick_settings_caffeine_off">Caffeine off.</string> + <string name="accessibility_quick_settings_caffeine_on">Caffeine on.</string> + + <!-- Heads up QS tile --> + <string name="quick_settings_heads_up_label">Heads up</string> + <string name="accessibility_quick_settings_heads_up_off">Heads up off.</string> + <string name="accessibility_quick_settings_heads_up_on">Heads up on.</string> +</resources> diff --git a/packages/SystemUI/res/values/ice_styles.xml b/packages/SystemUI/res/values/ice_styles.xml new file mode 100644 index 000000000000..652258a68746 --- /dev/null +++ b/packages/SystemUI/res/values/ice_styles.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2022 Project ICE + + 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. +--> +<resources> + <!-- Alert Slider --> + <style name="TriStateUiText"> + <item name="android:textSize">11.0sp</item> + <item name="android:fontFamily">sans-serif-medium</item> + </style> +</resources> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index dcbdc359a1a8..f051256a684d 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -117,7 +117,6 @@ <style name="TextAppearance.QS.TileLabel"> <item name="android:textSize">@dimen/qs_tile_text_size</item> - <item name="android:letterSpacing">0.01</item> <item name="android:lineHeight">20sp</item> <item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item> </style> @@ -137,7 +136,6 @@ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> <item name="android:textColor">?android:attr/textColorPrimary</item> <item name="android:textSize">14sp</item> - <item name="android:letterSpacing">0.01</item> </style> <style name="TextAppearance.QS.SecurityFooter" parent="@style/TextAppearance.QS.Status"> @@ -592,7 +590,6 @@ <style name="TextAppearance.QSEdit" > <item name="android:textSize">14sp</item> - <item name="android:letterSpacing">0.01</item> <item name="android:lineHeight">20sp</item> <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> <item name="android:textColor">?android:attr/textColorSecondary</item> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java index 62babadc45d8..9793ed72c087 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java @@ -1,10 +1,13 @@ package com.android.keyguard; +import static com.android.systemui.shared.recents.utilities.Utilities.isTablet; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.content.Context; +import android.content.res.Configuration; import android.graphics.Rect; import android.util.AttributeSet; import android.util.Log; @@ -92,6 +95,18 @@ public class KeyguardClockSwitch extends RelativeLayout { super(context, attrs); } + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + if (mDisplayedClockSize != null) { + boolean landscape = newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE; + boolean useLargeClock = mDisplayedClockSize == LARGE && + (!landscape || isTablet(mContext)); + updateClockViews(useLargeClock, /* animate */ true); + } + } + /** * Apply dp changes on font/scale change */ @@ -240,11 +255,14 @@ public class KeyguardClockSwitch extends RelativeLayout { if (mDisplayedClockSize != null && clockSize == mDisplayedClockSize) { return false; } + boolean landscape = getResources().getConfiguration().orientation + == Configuration.ORIENTATION_LANDSCAPE; + boolean useLargeClock = clockSize == LARGE && (!landscape || isTablet(mContext)); // let's make sure clock is changed only after all views were laid out so we can // translate them properly if (mChildrenAreLaidOut) { - updateClockViews(clockSize == LARGE, animate); + updateClockViews(useLargeClock, animate); } mDisplayedClockSize = clockSize; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java index 65a71664e245..31d22eb38a24 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java @@ -49,6 +49,7 @@ import com.android.internal.graphics.ColorUtils; import com.android.settingslib.Utils; import com.android.systemui.R; import com.android.systemui.animation.Interpolators; +import com.android.systemui.keyguard.KeyguardSliceProvider; import com.android.systemui.util.wakelock.KeepAwakeAnimationListener; import java.io.PrintWriter; @@ -445,13 +446,15 @@ public class KeyguardSliceView extends LinearLayout { private void updatePadding() { boolean hasText = !TextUtils.isEmpty(getText()); + boolean isDate = Uri.parse(KeyguardSliceProvider.KEYGUARD_DATE_URI).equals(getTag()); int padding = (int) getContext().getResources() .getDimension(R.dimen.widget_horizontal_padding) / 2; + int iconPadding = (int) mContext.getResources() + .getDimension(R.dimen.widget_icon_padding); // orientation is vertical, so add padding to top & bottom - setPadding(0, padding, 0, hasText ? padding : 0); + setPadding(!isDate ? iconPadding : 0, padding, 0, hasText ? padding : 0); - setCompoundDrawablePadding((int) mContext.getResources() - .getDimension(R.dimen.widget_icon_padding)); + setCompoundDrawablePadding(iconPadding); } @Override diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index ea47496d0986..21372f7759de 100755 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -2195,7 +2195,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } // Take a guess at initial SIM state, battery status and PLMN until we get an update - mBatteryStatus = new BatteryStatus(BATTERY_STATUS_UNKNOWN, 100, 0, 0, 0, true); + mBatteryStatus = new BatteryStatus(BATTERY_STATUS_UNKNOWN, 100, 0, 0, 0, false, true); // Watch for interesting updates final IntentFilter filter = new IntentFilter(); @@ -3476,6 +3476,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab return true; } + // change in oem fast charging while plugged in + if (nowPluggedIn && current.oemFastChargeStatus != old.oemFastChargeStatus) { + return true; + } + // Battery either showed up or disappeared if (wasPresent != nowPresent) { return true; diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIService.java b/packages/SystemUI/src/com/android/systemui/SystemUIService.java index 50e03992df49..9f131446217d 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIService.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIService.java @@ -83,7 +83,7 @@ public class SystemUIService extends Service { throw new RuntimeException(); } - if (Build.IS_DEBUGGABLE) { + if (Build.IS_ENG) { // b/71353150 - looking for leaked binder proxies BinderInternal.nSetBinderProxyCountEnabled(true); BinderInternal.nSetBinderProxyCountWatermarks(1000,900); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt index 4b57d455a137..dd782805cc59 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt @@ -28,6 +28,7 @@ import android.util.AttributeSet import android.view.View import android.view.animation.PathInterpolator import com.android.internal.graphics.ColorUtils +import com.android.settingslib.Utils import com.android.systemui.animation.Interpolators import com.android.systemui.surfaceeffects.ripple.RippleShader @@ -85,7 +86,7 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at } init { - rippleShader.color = 0xffffffff.toInt() // default color + rippleShader.color = Utils.getColorAttr(context, android.R.attr.colorAccent).defaultColor rippleShader.progress = 0f rippleShader.sparkleStrength = RIPPLE_SPARKLE_STRENGTH ripplePaint.shader = rippleShader diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsSurfaceView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsSurfaceView.java new file mode 100644 index 000000000000..2488132b508b --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsSurfaceView.java @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2021 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.biometrics; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.util.Log; +import android.view.Surface; +import android.view.SurfaceHolder; +import android.view.SurfaceView; + +import com.android.systemui.R; + +/** + * Surface View for providing the Global High-Brightness Mode (GHBM) illumination for UDFPS. + */ +public class UdfpsSurfaceView extends SurfaceView implements SurfaceHolder.Callback { + private static final String TAG = "UdfpsSurfaceView"; + + /** + * Notifies {@link UdfpsView} when to enable GHBM illumination. + */ + interface GhbmIlluminationListener { + /** + * @param surface the surface for which GHBM should be enabled. + * @param onDisplayConfigured a runnable that should be run after GHBM is enabled. + */ + void enableGhbm(@NonNull Surface surface, @Nullable Runnable onDisplayConfigured); + } + + @NonNull private final SurfaceHolder mHolder; + @NonNull private final Paint mSensorPaint; + + @Nullable private GhbmIlluminationListener mGhbmIlluminationListener; + @Nullable private Runnable mOnDisplayConfigured; + boolean mAwaitingSurfaceToStartIllumination; + boolean mHasValidSurface; + + private Drawable mUdfpsIconPressed; + + public UdfpsSurfaceView(Context context, AttributeSet attrs) { + super(context, attrs); + + // Make this SurfaceView draw on top of everything else in this window. This allows us to + // 1) Always show the HBM circle on top of everything else, and + // 2) Properly composite this view with any other animations in the same window no matter + // what contents are added in which order to this view hierarchy. + setZOrderOnTop(true); + + mHolder = getHolder(); + mHolder.addCallback(this); + mHolder.setFormat(PixelFormat.RGBA_8888); + + mSensorPaint = new Paint(0 /* flags */); + mSensorPaint.setAntiAlias(true); + mSensorPaint.setColor(context.getColor(R.color.config_udfpsColor)); + mSensorPaint.setStyle(Paint.Style.FILL); + + mUdfpsIconPressed = context.getDrawable(R.drawable.udfps_icon_pressed); + } + + @Override public void surfaceCreated(SurfaceHolder holder) { + mHasValidSurface = true; + if (mAwaitingSurfaceToStartIllumination) { + doIlluminate(mOnDisplayConfigured); + mOnDisplayConfigured = null; + mAwaitingSurfaceToStartIllumination = false; + } + } + + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + // Unused. + } + + @Override public void surfaceDestroyed(SurfaceHolder holder) { + mHasValidSurface = false; + } + + void setGhbmIlluminationListener(@Nullable GhbmIlluminationListener listener) { + mGhbmIlluminationListener = listener; + } + + /** + * Note: there is no corresponding method to stop GHBM illumination. It is expected that + * {@link UdfpsView} will hide this view, which would destroy the surface and remove the + * illumination dot. + */ + void startGhbmIllumination(@Nullable Runnable onDisplayConfigured) { + if (mGhbmIlluminationListener == null) { + Log.e(TAG, "startIllumination | mGhbmIlluminationListener is null"); + return; + } + + if (mHasValidSurface) { + doIlluminate(onDisplayConfigured); + } else { + mAwaitingSurfaceToStartIllumination = true; + mOnDisplayConfigured = onDisplayConfigured; + } + } + + private void doIlluminate(@Nullable Runnable onDisplayConfigured) { + if (mGhbmIlluminationListener == null) { + Log.e(TAG, "doIlluminate | mGhbmIlluminationListener is null"); + return; + } + + mGhbmIlluminationListener.enableGhbm(mHolder.getSurface(), onDisplayConfigured); + } + + /** + * Immediately draws the illumination dot on this SurfaceView's surface. + */ + void drawIlluminationDot(@NonNull RectF sensorRect) { + if (!mHasValidSurface) { + Log.e(TAG, "drawIlluminationDot | the surface is destroyed or was never created."); + return; + } + Canvas canvas = null; + try { + canvas = mHolder.lockCanvas(); + mUdfpsIconPressed.setBounds( + Math.round(sensorRect.left), + Math.round(sensorRect.top), + Math.round(sensorRect.right), + Math.round(sensorRect.bottom) + ); + mUdfpsIconPressed.draw(canvas); + canvas.drawOval(sensorRect, mSensorPaint); + } finally { + // Make sure the surface is never left in a bad state. + if (canvas != null) { + mHolder.unlockCanvasAndPost(canvas); + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt index 4a8877edfa53..97590822a3fb 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt @@ -25,6 +25,7 @@ import android.graphics.RectF import android.util.AttributeSet import android.util.Log import android.view.MotionEvent +import android.view.Surface import android.widget.FrameLayout import com.android.systemui.R import com.android.systemui.doze.DozeReceiver @@ -60,6 +61,8 @@ class UdfpsView( a.getFloat(R.styleable.UdfpsView_sensorTouchAreaCoefficient, 0f) } + private var ghbmView: UdfpsSurfaceView? = null + /** View controller (can be different for enrollment, BiometricPrompt, Keyguard, etc.). */ var animationViewController: UdfpsAnimationViewController<*>? = null @@ -86,6 +89,10 @@ class UdfpsView( return (animationViewController == null || !animationViewController!!.shouldPauseAuth()) } + override fun onFinishInflate() { + ghbmView = findViewById(R.id.hbm_view) + } + override fun dozeTimeTick() { animationViewController?.dozeTimeTick() } @@ -153,12 +160,34 @@ class UdfpsView( fun configureDisplay(onDisplayConfigured: Runnable) { isDisplayConfigured = true animationViewController?.onDisplayConfiguring() - mUdfpsDisplayMode?.enable(onDisplayConfigured) + val gView = ghbmView + if (gView != null) { + gView.setGhbmIlluminationListener(this::doIlluminate) + gView.visibility = VISIBLE + gView.startGhbmIllumination(onDisplayConfigured) + } else { + doIlluminate(null /* surface */, onDisplayConfigured) + } + } + + private fun doIlluminate(surface: Surface?, onDisplayConfigured: Runnable?) { + if (ghbmView != null && surface == null) { + Log.e(TAG, "doIlluminate | surface must be non-null for GHBM") + } + + mUdfpsDisplayMode?.enable { + onDisplayConfigured?.run() + ghbmView?.drawIlluminationDot(RectF(sensorRect)) + } } fun unconfigureDisplay() { isDisplayConfigured = false animationViewController?.onDisplayUnconfigured() + ghbmView?.let { view -> + view.setGhbmIlluminationListener(null) + view.visibility = INVISIBLE + } mUdfpsDisplayMode?.disable(null /* onDisabled */) } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt index 8029ba844850..c4c23124b39e 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt @@ -68,12 +68,6 @@ interface ControlActionCoordinator { fun setValue(cvh: ControlViewHolder, templateId: String, newValue: Float) /** - * Actions may have been put on hold while the device is unlocked. Invoke this action if - * present. - */ - fun runPendingAction(controlId: String) - - /** * User interaction with a control may be blocked for a period of time while actions are being * executed by the application. When the response returns, run this method to enable further * user interaction. diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt index 99a10a33ab0f..d167eecb137d 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt @@ -64,7 +64,6 @@ class ControlActionCoordinatorImpl @Inject constructor( private val featureFlags: FeatureFlags, ) : ControlActionCoordinator { private var dialog: Dialog? = null - private var pendingAction: Action? = null private var actionsInProgress = mutableSetOf<String>() private val isLocked: Boolean get() = !keyguardStateController.isUnlocked() @@ -166,15 +165,6 @@ class ControlActionCoordinatorImpl @Inject constructor( ) } - override fun runPendingAction(controlId: String) { - if (isLocked) return - if (pendingAction?.controlId == controlId) { - showSettingsDialogIfNeeded(pendingAction!!) - pendingAction?.invoke() - pendingAction = null - } - } - @MainThread override fun enableActionOnTouch(controlId: String) { actionsInProgress.remove(controlId) @@ -196,17 +186,11 @@ class ControlActionCoordinatorImpl @Inject constructor( val authRequired = action.authIsRequired || !allowTrivialControls if (keyguardStateController.isShowing() && authRequired) { - if (isLocked) { - broadcastSender.closeSystemDialogs() - - // pending actions will only run after the control state has been refreshed - pendingAction = action - } activityStarter.dismissKeyguardThenExecute({ Log.d(ControlsUiController.TAG, "Device unlocked, invoking controls action") action.invoke() true - }, { pendingAction = null }, true /* afterKeyguardGone */) + }, null, true /* afterKeyguardGone */) } else { showSettingsDialogIfNeeded(action) action.invoke() diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt index 6a9aaf865251..42dcff71bbf8 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt @@ -174,8 +174,6 @@ class ControlViewHolder( controlActionCoordinator.longPress(this@ControlViewHolder) true }) - - controlActionCoordinator.runPendingAction(cws.ci.controlId) } val wasLoading = isLoading diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index b95c3f3c0ee7..18ec037150e6 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -327,11 +327,16 @@ public class DozeTriggers implements DozeMachine.Part { } gentleWakeUp(pulseReason); } else if (isPickup) { + final State state = mMachine.getState(); if (shouldDropPickupEvent()) { mDozeLog.traceSensorEventDropped(pulseReason, "keyguard occluded"); return; } - gentleWakeUp(pulseReason); + if (state == State.DOZE_AOD) { + gentleWakeUp(pulseReason); + } else { + requestPulse(pulseReason, true, null); + } } else if (isUdfpsLongPress) { if (canPulse(mMachine.getState(), true)) { mDozeLog.d("updfsLongPress - setting aodInterruptRunnable to run when " diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index 20ae64cf5985..d12d475f4847 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -300,7 +300,7 @@ object Flags { val MEDIA_TAP_TO_TRANSFER = unreleasedFlag(900, "media_tap_to_transfer", teamfood = true) // TODO(b/254512502): Tracking Bug - val MEDIA_SESSION_ACTIONS = unreleasedFlag(901, "media_session_actions") + val MEDIA_SESSION_ACTIONS = releasedFlag(901, "media_session_actions") // TODO(b/254512726): Tracking Bug val MEDIA_NEARBY_DEVICES = releasedFlag(903, "media_nearby_devices") diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 9d535e7c8458..5546b70ae83e 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -1954,6 +1954,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, if (mLockPatternUtils.isLockScreenDisabled(KeyguardUpdateMonitor.getCurrentUser()) && !lockedOrMissing && !forceShow) { if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off"); + setShowingLocked(false, mAodShowing); + hideLocked(); return; } } @@ -2707,7 +2709,9 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, // only play "unlock" noises if not on a call (since the incall UI // disables the keyguard) if (TelephonyManager.EXTRA_STATE_IDLE.equals(mPhoneState)) { - playSounds(false); + if (mShowing && mDeviceInteractive) { + playSounds(false); + } } setShowingLocked(false); diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java index 59bb2278edfe..84ac3eab9673 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java @@ -18,11 +18,17 @@ package com.android.systemui.navigationbar; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; +import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; import android.annotation.Nullable; +import android.app.ActivityManager; import android.content.Context; +import android.content.om.IOverlayManager; import android.content.res.Configuration; import android.graphics.drawable.Icon; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.provider.Settings; import android.util.AttributeSet; import android.util.Log; import android.util.SparseArray; @@ -43,12 +49,13 @@ import com.android.systemui.navigationbar.buttons.ReverseLinearLayout; import com.android.systemui.navigationbar.buttons.ReverseLinearLayout.ReverseRelativeLayout; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.shared.system.QuickStepContract; +import com.android.systemui.tuner.TunerService; import java.io.PrintWriter; import java.util.Objects; public class NavigationBarInflaterView extends FrameLayout - implements NavigationModeController.ModeChangedListener { + implements NavigationModeController.ModeChangedListener, TunerService.Tunable { private static final String TAG = "NavBarInflater"; @@ -83,6 +90,11 @@ public class NavigationBarInflaterView extends FrameLayout private static final String ABSOLUTE_SUFFIX = "A"; private static final String ABSOLUTE_VERTICAL_CENTERED_SUFFIX = "C"; + private static final String KEY_NAVIGATION_HINT = + Settings.Secure.NAVIGATION_BAR_HINT; + private static final String OVERLAY_NAVIGATION_HIDE_HINT = + "android.ice.overlay.hidenav"; + protected LayoutInflater mLayoutInflater; protected LayoutInflater mLandscapeInflater; @@ -102,6 +114,8 @@ public class NavigationBarInflaterView extends FrameLayout private OverviewProxyService mOverviewProxyService; private int mNavBarMode = NAV_BAR_MODE_3BUTTON; + private boolean mIsHintEnabled; + public NavigationBarInflaterView(Context context, AttributeSet attrs) { super(context, attrs); createInflaters(); @@ -143,12 +157,22 @@ public class NavigationBarInflaterView extends FrameLayout : mOverviewProxyService.shouldShowSwipeUpUI() ? R.string.config_navBarLayoutQuickstep : R.string.config_navBarLayout; + if (!mIsHintEnabled && defaultResource == R.string.config_navBarLayoutHandle) { + return getContext().getString(defaultResource).replace(HOME_HANDLE, ""); + } return getContext().getString(defaultResource); } @Override public void onNavigationModeChanged(int mode) { mNavBarMode = mode; + updateHint(); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + Dependency.get(TunerService.class).addTunable(this, KEY_NAVIGATION_HINT); } @Override @@ -157,6 +181,15 @@ public class NavigationBarInflaterView extends FrameLayout super.onDetachedFromWindow(); } + @Override + public void onTuningChanged(String key, String newValue) { + if (KEY_NAVIGATION_HINT.equals(key)) { + mIsHintEnabled = TunerService.parseIntegerSwitch(newValue, true); + updateHint(); + onLikelyDefaultLayoutChange(); + } + } + public void onLikelyDefaultLayoutChange() { // Reevaluate new layout final String newValue = getDefaultLayout(); @@ -210,6 +243,24 @@ public class NavigationBarInflaterView extends FrameLayout } } + private void updateHint() { + final IOverlayManager iom = IOverlayManager.Stub.asInterface( + ServiceManager.getService(Context.OVERLAY_SERVICE)); + final boolean state = mNavBarMode == NAV_BAR_MODE_GESTURAL && !mIsHintEnabled; + final int userId = ActivityManager.getCurrentUser(); + try { + iom.setEnabled(OVERLAY_NAVIGATION_HIDE_HINT, state, userId); + if (state) { + // As overlays are also used to apply navigation mode, it is needed to set + // our customization overlay to highest priority to ensure it is applied. + iom.setHighestPriority(OVERLAY_NAVIGATION_HIDE_HINT, userId); + } + } catch (IllegalArgumentException | RemoteException e) { + Log.e(TAG, "Failed to " + (state ? "enable" : "disable") + + " overlay " + OVERLAY_NAVIGATION_HIDE_HINT + " for user " + userId); + } + } + private void initiallyFill(ButtonDispatcher buttonDispatcher) { addAll(buttonDispatcher, mHorizontal.findViewById(R.id.ends_group)); addAll(buttonDispatcher, mHorizontal.findViewById(R.id.center_group)); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java index 100853caa2d7..20cf0d67903f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java @@ -660,7 +660,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P final String defaultTileList = res.getString(R.string.quick_settings_tiles_default); tiles.addAll(Arrays.asList(defaultTileList.split(","))); - if (Build.IS_DEBUGGABLE + if (Build.IS_ENG && GarbageMonitor.ADD_MEMORY_TILE_TO_DEFAULT_ON_DEBUGGABLE_BUILDS) { tiles.add(GarbageMonitor.MemoryTile.TILE_SPEC); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index 946fe542741f..dbdbcae6856f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -18,10 +18,12 @@ import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import android.content.Context; +import android.content.Intent; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Color; import android.graphics.Rect; +import android.provider.AlarmClock; import android.util.AttributeSet; import android.util.Pair; import android.view.DisplayCutout; @@ -38,8 +40,10 @@ import androidx.annotation.Nullable; import com.android.internal.policy.SystemBarUtils; import com.android.settingslib.Utils; +import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.battery.BatteryMeterView; +import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider; import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager; import com.android.systemui.statusbar.phone.StatusIconContainer; @@ -66,6 +70,8 @@ public class QuickStatusBarHeader extends FrameLayout { private TouchAnimator mIconsAlphaAnimator; private TouchAnimator mIconsAlphaAnimatorFixed; + private final ActivityStarter mActivityStarter; + protected QuickQSPanel mHeaderQsPanel; private View mDatePrivacyView; private View mDateView; @@ -113,6 +119,7 @@ public class QuickStatusBarHeader extends FrameLayout { public QuickStatusBarHeader(Context context, AttributeSet attrs) { super(context, attrs); + mActivityStarter = Dependency.get(ActivityStarter.class); } /** @@ -144,6 +151,9 @@ public class QuickStatusBarHeader extends FrameLayout { mClockContainer = findViewById(R.id.clock_container); mClockView = findViewById(R.id.clock); + mClockView.setOnClickListener( + v -> mActivityStarter.postStartActivityDismissingKeyguard( + new Intent(AlarmClock.ACTION_SHOW_ALARMS), 0)); mDatePrivacySeparator = findViewById(R.id.space); // Tint for the battery icons are handled in setupHost() mBatteryRemainingIcon = findViewById(R.id.batteryRemainingIcon); @@ -388,10 +398,12 @@ public class QuickStatusBarHeader extends FrameLayout { // Animates the icons and battery indicator from alpha 0 to 1, when the chip is visible mIconsAlphaAnimator = mIconsAlphaAnimatorFixed; mIconsAlphaAnimator.setPosition(mKeyguardExpansionFraction); + setBatteryRemainingOnClick(false); } else { mIconsAlphaAnimator = null; mIconContainer.setAlpha(1); mBatteryRemainingIcon.setAlpha(1); + setBatteryRemainingOnClick(true); } } @@ -552,6 +564,9 @@ public class QuickStatusBarHeader extends FrameLayout { public void updateEverything() { post(() -> setClickable(!mExpanded)); + if (mExpanded) { + setBatteryRemainingOnClick(true); + } } private void setContentMargins(View view, int marginStart, int marginEnd) { @@ -570,4 +585,16 @@ public class QuickStatusBarHeader extends FrameLayout { mStatusIconsView.setScrollY(scrollY); mDatePrivacyView.setScrollY(scrollY); } + + private void setBatteryRemainingOnClick(boolean enable) { + if (enable) { + mBatteryRemainingIcon.setOnClickListener( + v -> mActivityStarter.postStartActivityDismissingKeyguard( + new Intent(Intent.ACTION_POWER_USAGE_SUMMARY), 0)); + mBatteryRemainingIcon.setClickable(true); + } else { + mBatteryRemainingIcon.setOnClickListener(null); + mBatteryRemainingIcon.setClickable(false); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java index 467df1994d44..2ac17179e72a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java @@ -127,8 +127,6 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader protected void onViewAttached() { mPrivacyIconsController.onParentVisible(); mPrivacyIconsController.setChipVisibilityListener(this); - mIconContainer.addIgnoredSlot( - getResources().getString(com.android.internal.R.string.status_bar_alarm_clock)); mIconContainer.setShouldRestrictIcons(false); mStatusBarIconController.addIconGroup(mIconManager); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java index a92c7e3c8554..6b66f71870ba 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java @@ -29,8 +29,10 @@ import com.android.systemui.qs.QSHost; import com.android.systemui.qs.external.CustomTile; import com.android.systemui.qs.tiles.AirplaneModeTile; import com.android.systemui.qs.tiles.AlarmTile; +import com.android.systemui.qs.tiles.AODTile; import com.android.systemui.qs.tiles.BatterySaverTile; import com.android.systemui.qs.tiles.BluetoothTile; +import com.android.systemui.qs.tiles.CaffeineTile; import com.android.systemui.qs.tiles.CameraToggleTile; import com.android.systemui.qs.tiles.CastTile; import com.android.systemui.qs.tiles.CellularTile; @@ -41,6 +43,7 @@ import com.android.systemui.qs.tiles.DeviceControlsTile; import com.android.systemui.qs.tiles.DndTile; import com.android.systemui.qs.tiles.DreamTile; import com.android.systemui.qs.tiles.FlashlightTile; +import com.android.systemui.qs.tiles.HeadsUpTile; import com.android.systemui.qs.tiles.HotspotTile; import com.android.systemui.qs.tiles.InternetTile; import com.android.systemui.qs.tiles.LocationTile; @@ -98,6 +101,9 @@ public class QSFactoryImpl implements QSFactory { private final Provider<QRCodeScannerTile> mQRCodeScannerTileProvider; private final Provider<OneHandedModeTile> mOneHandedModeTileProvider; private final Provider<DreamTile> mDreamTileProvider; + private final Provider<AODTile> mAODTileProvider; + private final Provider<CaffeineTile> mCaffeineTileProvider; + private final Provider<HeadsUpTile> mHeadsUpTileProvider; private final Lazy<QSHost> mQsHostLazy; private final Provider<CustomTile.Builder> mCustomTileBuilderProvider; @@ -135,7 +141,10 @@ public class QSFactoryImpl implements QSFactory { Provider<QRCodeScannerTile> qrCodeScannerTileProvider, Provider<OneHandedModeTile> oneHandedModeTileProvider, Provider<ColorCorrectionTile> colorCorrectionTileProvider, - Provider<DreamTile> dreamTileProvider) { + Provider<DreamTile> dreamTileProvider, + Provider<AODTile> aodTileProvider, + Provider<CaffeineTile> caffeineTileProvider, + Provider<HeadsUpTile> headsUpTileProvider) { mQsHostLazy = qsHostLazy; mCustomTileBuilderProvider = customTileBuilderProvider; @@ -169,6 +178,9 @@ public class QSFactoryImpl implements QSFactory { mOneHandedModeTileProvider = oneHandedModeTileProvider; mColorCorrectionTileProvider = colorCorrectionTileProvider; mDreamTileProvider = dreamTileProvider; + mAODTileProvider = aodTileProvider; + mCaffeineTileProvider = caffeineTileProvider; + mHeadsUpTileProvider = headsUpTileProvider; } /** Creates a tile with a type based on {@code tileSpec} */ @@ -184,8 +196,8 @@ public class QSFactoryImpl implements QSFactory { @Nullable protected QSTileImpl createTileInternal(String tileSpec) { - // Stock tiles. switch (tileSpec) { + // Stock tiles. case "wifi": return mWifiTileProvider.get(); case "internet": @@ -244,6 +256,13 @@ public class QSFactoryImpl implements QSFactory { return mColorCorrectionTileProvider.get(); case "dream": return mDreamTileProvider.get(); + // Additional tiles. + case "aod": + return mAODTileProvider.get(); + case "caffeine": + return mCaffeineTileProvider.get(); + case "heads_up": + return mHeadsUpTileProvider.get(); } // Custom tiles diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AODTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AODTile.java new file mode 100644 index 000000000000..37e5716ce5f5 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AODTile.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2018 The OmniROM Project + * 2020-2021 The LineageOS 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.tiles; + +import android.content.Intent; +import android.os.Handler; +import android.os.Looper; +import android.provider.Settings; +import android.service.quicksettings.Tile; +import android.view.View; + +import androidx.annotation.Nullable; + +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; +import com.android.systemui.plugins.qs.QSTile.BooleanState; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.SettingObserver; +import com.android.systemui.qs.logging.QSLogger; +import com.android.systemui.qs.tileimpl.QSTileImpl; +import com.android.systemui.settings.UserTracker; +import com.android.systemui.statusbar.policy.BatteryController; +import com.android.systemui.util.settings.SecureSettings; + +import javax.inject.Inject; + +public class AODTile extends QSTileImpl<BooleanState> implements + BatteryController.BatteryStateChangeCallback { + + private final Icon mIcon = ResourceIcon.get(R.drawable.ic_qs_aod); + private final BatteryController mBatteryController; + + private final SettingObserver mSetting; + + @Inject + public AODTile( + QSHost host, + @Background Looper backgroundLooper, + @Main Handler mainHandler, + FalsingManager falsingManager, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger, + SecureSettings secureSettings, + BatteryController batteryController, + UserTracker userTracker + ) { + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger); + + mSetting = new SettingObserver(secureSettings, mHandler, Settings.Secure.DOZE_ALWAYS_ON, + userTracker.getUserId()) { + @Override + protected void handleValueChanged(int value, boolean observedChange) { + handleRefreshState(value); + } + }; + + mBatteryController = batteryController; + batteryController.observe(getLifecycle(), this); + } + + @Override + public void onPowerSaveChanged(boolean isPowerSave) { + refreshState(); + } + + @Override + protected void handleDestroy() { + super.handleDestroy(); + mSetting.setListening(false); + } + + @Override + public boolean isAvailable() { + return mContext.getResources().getBoolean( + com.android.internal.R.bool.config_dozeAlwaysOnDisplayAvailable); + } + + @Override + public BooleanState newTileState() { + BooleanState state = new BooleanState(); + state.handlesLongClick = false; + return state; + } + + @Override + public void handleSetListening(boolean listening) { + super.handleSetListening(listening); + mSetting.setListening(listening); + } + + @Override + protected void handleUserSwitch(int newUserId) { + mSetting.setUserId(newUserId); + handleRefreshState(mSetting.getValue()); + } + + @Override + protected void handleClick(@Nullable View view) { + mSetting.setValue(mState.value ? 0 : 1); + } + + @Override + public Intent getLongClickIntent() { + return null; + } + + @Override + public CharSequence getTileLabel() { + if (mBatteryController.isAodPowerSave()) { + return mContext.getString(R.string.quick_settings_aod_off_powersave_label); + } + return mContext.getString(R.string.quick_settings_aod_label); + } + + @Override + protected void handleUpdateState(BooleanState state, Object arg) { + final int value = arg instanceof Integer ? (Integer) arg : mSetting.getValue(); + final boolean enable = value != 0; + if (state.slash == null) { + state.slash = new SlashState(); + } + state.icon = mIcon; + state.value = enable; + state.slash.isSlashed = state.value; + state.label = mContext.getString(R.string.quick_settings_aod_label); + if (mBatteryController.isAodPowerSave()) { + state.state = Tile.STATE_UNAVAILABLE; + } else { + state.state = enable ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE; + } + } + + @Override + public int getMetricsCategory() { + return MetricsEvent.ICE; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CaffeineTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CaffeineTile.java new file mode 100644 index 000000000000..340de5648a1b --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CaffeineTile.java @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2016 The CyanogenMod Project + * Copyright (c) 2017 The LineageOS 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.tiles; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.CountDownTimer; +import android.os.Handler; +import android.os.Looper; +import android.os.PowerManager; +import android.os.SystemClock; +import android.service.quicksettings.Tile; +import android.view.View; + +import androidx.annotation.Nullable; + +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; +import com.android.systemui.plugins.qs.QSTile.BooleanState; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.logging.QSLogger; +import com.android.systemui.qs.tileimpl.QSTileImpl; + +import javax.inject.Inject; + +/** Quick settings tile: Caffeine **/ +public class CaffeineTile extends QSTileImpl<BooleanState> { + + private final Icon mIcon = ResourceIcon.get(R.drawable.ic_qs_caffeine); + + private final PowerManager.WakeLock mWakeLock; + private int mSecondsRemaining; + private int mDuration; + private static int[] DURATIONS = new int[] { + 5 * 60, // 5 min + 10 * 60, // 10 min + 30 * 60, // 30 min + -1, // infinity + }; + private static final int INFINITE_DURATION_INDEX = DURATIONS.length - 1; + private CountDownTimer mCountdownTimer = null; + public long mLastClickTime = -1; + private final Receiver mReceiver = new Receiver(); + + @Inject + public CaffeineTile( + QSHost host, + @Background Looper backgroundLooper, + @Main Handler mainHandler, + FalsingManager falsingManager, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger + ) { + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger); + mWakeLock = mContext.getSystemService(PowerManager.class).newWakeLock( + PowerManager.FULL_WAKE_LOCK, "CaffeineTile"); + mReceiver.init(); + } + + @Override + public BooleanState newTileState() { + return new BooleanState(); + } + + @Override + protected void handleDestroy() { + super.handleDestroy(); + stopCountDown(); + mReceiver.destroy(); + if (mWakeLock.isHeld()) { + mWakeLock.release(); + } + } + + @Override + public void handleSetListening(boolean listening) { + } + + @Override + protected void handleClick(@Nullable View view) { + // If last user clicks < 5 seconds + // we cycle different duration + // otherwise toggle on/off + if (mWakeLock.isHeld() && (mLastClickTime != -1) && + (SystemClock.elapsedRealtime() - mLastClickTime < 5000)) { + // cycle duration + mDuration++; + if (mDuration >= DURATIONS.length) { + // all durations cycled, turn if off + mDuration = -1; + stopCountDown(); + if (mWakeLock.isHeld()) { + mWakeLock.release(); + } + } else { + // change duration + startCountDown(DURATIONS[mDuration]); + if (!mWakeLock.isHeld()) { + mWakeLock.acquire(); + } + } + } else { + // toggle + if (mWakeLock.isHeld()) { + mWakeLock.release(); + stopCountDown(); + } else { + mWakeLock.acquire(); + mDuration = 0; + startCountDown(DURATIONS[mDuration]); + } + } + mLastClickTime = SystemClock.elapsedRealtime(); + refreshState(); + } + + @Override + protected void handleLongClick(@Nullable View view) { + if (mWakeLock.isHeld()) { + if (mDuration == INFINITE_DURATION_INDEX) { + return; + } + } else { + mWakeLock.acquire(); + } + mDuration = INFINITE_DURATION_INDEX; + startCountDown(DURATIONS[INFINITE_DURATION_INDEX]); + refreshState(); + } + + @Override + public Intent getLongClickIntent() { + return null; + } + + @Override + public CharSequence getTileLabel() { + return mContext.getString(R.string.quick_settings_caffeine_label); + } + + @Override + public int getMetricsCategory() { + return MetricsEvent.ICE; + } + + private void startCountDown(long duration) { + stopCountDown(); + mSecondsRemaining = (int)duration; + if (duration == -1) { + // infinity timing, no need to start timer + return; + } + mCountdownTimer = new CountDownTimer(duration * 1000, 1000) { + @Override + public void onTick(long millisUntilFinished) { + mSecondsRemaining = (int) (millisUntilFinished / 1000); + refreshState(); + } + + @Override + public void onFinish() { + if (mWakeLock.isHeld()) + mWakeLock.release(); + refreshState(); + } + + }.start(); + } + + private void stopCountDown() { + if (mCountdownTimer != null) { + mCountdownTimer.cancel(); + mCountdownTimer = null; + } + } + + private String formatValueWithRemainingTime() { + if (mSecondsRemaining == -1) { + return "\u221E"; // infinity + } + return String.format("%02d:%02d", + mSecondsRemaining / 60 % 60, mSecondsRemaining % 60); + } + + @Override + protected void handleUpdateState(BooleanState state, Object arg) { + state.value = mWakeLock.isHeld(); + state.icon = mIcon; + state.label = mContext.getString(R.string.quick_settings_caffeine_label); + if (state.value) { + state.secondaryLabel = formatValueWithRemainingTime(); + state.contentDescription = mContext.getString( + R.string.accessibility_quick_settings_caffeine_on); + state.state = Tile.STATE_ACTIVE; + } else { + state.secondaryLabel = null; + state.contentDescription = mContext.getString( + R.string.accessibility_quick_settings_caffeine_off); + state.state = Tile.STATE_INACTIVE; + } + } + + private final class Receiver extends BroadcastReceiver { + public void init() { + // Register for Intent broadcasts for... + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_SCREEN_OFF); + mContext.registerReceiver(this, filter, null, mHandler); + } + + public void destroy() { + mContext.unregisterReceiver(this); + } + + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (Intent.ACTION_SCREEN_OFF.equals(action)) { + // disable caffeine if user force off (power button) + stopCountDown(); + if (mWakeLock.isHeld()) + mWakeLock.release(); + refreshState(); + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HeadsUpTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HeadsUpTile.java new file mode 100644 index 000000000000..8305d6b5f739 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HeadsUpTile.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2015 The CyanogenMod Project + * Copyright (C) 2017 The LineageOS 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.tiles; + +import android.content.Intent; +import android.os.Handler; +import android.os.Looper; +import android.provider.Settings; +import android.provider.Settings.Global; +import android.service.quicksettings.Tile; +import android.view.View; + +import androidx.annotation.Nullable; + +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; +import com.android.systemui.plugins.qs.QSTile.BooleanState; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.SettingObserver; +import com.android.systemui.qs.logging.QSLogger; +import com.android.systemui.qs.tileimpl.QSTileImpl; +import com.android.systemui.settings.UserTracker; +import com.android.systemui.util.settings.GlobalSettings; + +import javax.inject.Inject; + +/** Quick settings tile: Heads up **/ +public class HeadsUpTile extends QSTileImpl<BooleanState> { + + private final Icon mIcon = ResourceIcon.get(R.drawable.ic_qs_heads_up); + + private static final Intent NOTIFICATION_SETTINGS = + new Intent("android.settings.NOTIFICATION_SETTINGS"); + + private final SettingObserver mSetting; + + @Inject + public HeadsUpTile( + QSHost host, + @Background Looper backgroundLooper, + @Main Handler mainHandler, + FalsingManager falsingManager, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger, + GlobalSettings globalSettings, + UserTracker userTracker + ) { + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger); + + mSetting = new SettingObserver(globalSettings, mHandler, + Global.HEADS_UP_NOTIFICATIONS_ENABLED, userTracker.getUserId()) { + @Override + protected void handleValueChanged(int value, boolean observedChange) { + handleRefreshState(value); + } + }; + } + + @Override + public BooleanState newTileState() { + return new BooleanState(); + } + + @Override + protected void handleClick(@Nullable View view) { + setEnabled(!mState.value); + refreshState(); + } + + @Override + public Intent getLongClickIntent() { + return NOTIFICATION_SETTINGS; + } + + private void setEnabled(boolean enabled) { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED, + enabled ? 1 : 0); + } + + @Override + protected void handleUpdateState(BooleanState state, Object arg) { + final int value = arg instanceof Integer ? (Integer) arg : mSetting.getValue(); + final boolean headsUp = value != 0; + state.value = headsUp; + state.label = mContext.getString(R.string.quick_settings_heads_up_label); + state.icon = mIcon; + if (headsUp) { + state.contentDescription = mContext.getString( + R.string.accessibility_quick_settings_heads_up_on); + state.state = Tile.STATE_ACTIVE; + } else { + state.contentDescription = mContext.getString( + R.string.accessibility_quick_settings_heads_up_off); + state.state = Tile.STATE_INACTIVE; + } + } + + @Override + public CharSequence getTileLabel() { + return mContext.getString(R.string.quick_settings_heads_up_label); + } + + @Override + public int getMetricsCategory() { + return MetricsEvent.ICE; + } + + @Override + public void handleSetListening(boolean listening) { + // Do nothing + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java index a61f0ce0c864..ac07acd5dd2a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java @@ -85,6 +85,7 @@ public class NfcTile extends QSTileImpl<BooleanState> { @Override public void handleSetListening(boolean listening) { super.handleSetListening(listening); + if (mListening == listening) return; mListening = listening; if (mListening) { mBroadcastDispatcher.registerReceiver(mNfcReceiver, @@ -151,7 +152,7 @@ public class NfcTile extends QSTileImpl<BooleanState> { private NfcAdapter getAdapter() { if (mAdapter == null) { try { - mAdapter = NfcAdapter.getDefaultAdapter(mContext); + mAdapter = NfcAdapter.getNfcAdapter(mContext.getApplicationContext()); } catch (UnsupportedOperationException e) { mAdapter = null; } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java index 5716a1d7260c..bd6b62e73868 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java @@ -252,7 +252,7 @@ public class ScreenshotController { // From WizardManagerHelper.java private static final String SETTINGS_SECURE_USER_SETUP_COMPLETE = "user_setup_complete"; - private static final int SCREENSHOT_CORNER_DEFAULT_TIMEOUT_MILLIS = 6000; + private static final int SCREENSHOT_CORNER_DEFAULT_TIMEOUT_MILLIS = 3000; private final WindowContext mContext; private final FeatureFlags mFlags; diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java index e8ceb521b6b0..18b6444912ea 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java @@ -120,8 +120,8 @@ public class ScreenshotView extends FrameLayout implements private static final long SCREENSHOT_TO_CORNER_X_DURATION_MS = 234; private static final long SCREENSHOT_TO_CORNER_Y_DURATION_MS = 500; private static final long SCREENSHOT_TO_CORNER_SCALE_DURATION_MS = 234; - private static final long SCREENSHOT_ACTIONS_EXPANSION_DURATION_MS = 400; - private static final long SCREENSHOT_ACTIONS_ALPHA_DURATION_MS = 100; + private static final long SCREENSHOT_ACTIONS_EXPANSION_DURATION_MS = 300; + private static final long SCREENSHOT_ACTIONS_ALPHA_DURATION_MS = 75; private static final float SCREENSHOT_ACTIONS_START_SCALE_X = .7f; private static final int SWIPE_PADDING_DP = 12; // extra padding around views to allow swipe diff --git a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt index e406be1ea0a3..83c395b5a06f 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt @@ -18,10 +18,12 @@ package com.android.systemui.shade import android.annotation.IdRes import android.app.StatusBarManager +import android.content.Intent import android.content.res.Configuration import android.os.Bundle import android.os.Trace import android.os.Trace.TRACE_TAG_APP +import android.provider.AlarmClock import android.util.Pair import android.view.View import android.view.WindowInsets @@ -40,6 +42,7 @@ import com.android.systemui.demomode.DemoModeController import com.android.systemui.dump.DumpManager import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags +import com.android.systemui.plugins.ActivityStarter import com.android.systemui.qs.ChipVisibilityListener import com.android.systemui.qs.HeaderPrivacyIconsController import com.android.systemui.qs.carrier.QSCarrierGroup @@ -91,7 +94,8 @@ class LargeScreenShadeHeaderController @Inject constructor( private val featureFlags: FeatureFlags, private val qsCarrierGroupControllerBuilder: QSCarrierGroupController.Builder, private val combinedShadeHeadersConstraintManager: CombinedShadeHeadersConstraintManager, - private val demoModeController: DemoModeController + private val demoModeController: DemoModeController, + private val activityStarter: ActivityStarter ) : ViewController<View>(header), Dumpable { companion object { @@ -282,16 +286,21 @@ class LargeScreenShadeHeaderController @Inject constructor( .setQSCarrierGroup(qsCarrierGroup) .build() - if (!combinedHeaders) { - // In the new header, we display alarm icon but we ignore it when not using the new - // headers. - iconContainer.addIgnoredSlot( - context.getString(com.android.internal.R.string.status_bar_alarm_clock) - ) - } if (combinedHeaders) { privacyIconsController.onParentVisible() } + + clock.setOnClickListener { + activityStarter.postStartActivityDismissingKeyguard( + Intent(AlarmClock.ACTION_SHOW_ALARMS), 0 + ) + } + + batteryIcon.setOnClickListener { + activityStarter.postStartActivityDismissingKeyguard( + Intent(Intent.ACTION_POWER_USAGE_SUMMARY), 0 + ) + } } override fun onViewAttached() { diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index 0a4f786dadfe..28f526c5940f 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -80,6 +80,7 @@ import android.transition.TransitionValues; import android.util.IndentingPrintWriter; import android.util.Log; import android.util.MathUtils; +import android.view.GestureDetector; import android.view.InputDevice; import android.view.LayoutInflater; import android.view.MotionEvent; @@ -224,6 +225,7 @@ import com.android.systemui.statusbar.policy.KeyguardUserSwitcherController; import com.android.systemui.statusbar.policy.KeyguardUserSwitcherView; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; import com.android.systemui.statusbar.window.StatusBarWindowStateController; +import com.android.systemui.tuner.TunerService; import com.android.systemui.unfold.SysUIUnfoldComponent; import com.android.systemui.util.Compile; import com.android.systemui.util.LargeScreenUtils; @@ -287,6 +289,10 @@ public final class NotificationPanelViewController implements Dumpable { private static final String COUNTER_PANEL_OPEN = "panel_open"; private static final String COUNTER_PANEL_OPEN_QS = "panel_open_qs"; private static final String COUNTER_PANEL_OPEN_PEEK = "panel_open_peek"; + + private static final String DOUBLE_TAP_SLEEP_GESTURE = + "system:" + Settings.System.DOUBLE_TAP_SLEEP_GESTURE; + private static final Rect M_DUMMY_DIRTY_RECT = new Rect(0, 0, 1, 1); private static final Rect EMPTY_RECT = new Rect(); /** @@ -362,6 +368,7 @@ public final class NotificationPanelViewController implements Dumpable { private final FragmentListener mQsFragmentListener = new QsFragmentListener(); private final AccessibilityDelegate mAccessibilityDelegate = new ShadeAccessibilityDelegate(); private final NotificationGutsManager mGutsManager; + private final TunerService mTunerService; private long mDownTime; private boolean mTouchSlopExceededBeforeDown; @@ -552,6 +559,8 @@ public final class NotificationPanelViewController implements Dumpable { private final NotificationShadeDepthController mDepthController; private final NavigationBarController mNavigationBarController; private final int mDisplayId; + private boolean mDoubleTapToSleepEnabled; + private GestureDetector mDoubleTapGesture; private final KeyguardIndicationController mKeyguardIndicationController; private int mHeadsUpInset; @@ -800,7 +809,8 @@ public final class NotificationPanelViewController implements Dumpable { OccludedToLockscreenTransitionViewModel occludedToLockscreenTransitionViewModel, @Main CoroutineDispatcher mainDispatcher, KeyguardTransitionInteractor keyguardTransitionInteractor, - DumpManager dumpManager) { + DumpManager dumpManager, + TunerService tunerService) { keyguardStateController.addCallback(new KeyguardStateController.Callback() { @Override public void onKeyguardFadingAwayChanged() { @@ -891,6 +901,7 @@ public final class NotificationPanelViewController implements Dumpable { LargeScreenUtils.shouldUseSplitNotificationShade(mResources); mView.setWillNotDraw(!DEBUG_DRAWABLE); mLargeScreenShadeHeaderController = largeScreenShadeHeaderController; + mTunerService = tunerService; mLayoutInflater = layoutInflater; mFeatureFlags = featureFlags; mFalsingCollector = falsingCollector; @@ -933,6 +944,16 @@ public final class NotificationPanelViewController implements Dumpable { }); mBottomAreaShadeAlphaAnimator.setDuration(160); mBottomAreaShadeAlphaAnimator.setInterpolator(Interpolators.ALPHA_OUT); + mDoubleTapGesture = new GestureDetector(mView.getContext(), + new GestureDetector.SimpleOnGestureListener() { + @Override + public boolean onDoubleTap(MotionEvent e) { + if (mPowerManager != null) { + mPowerManager.goToSleep(e.getEventTime()); + } + return true; + } + }); mConversationNotificationManager = conversationNotificationManager; mAuthController = authController; mLockIconViewController = lockIconViewController; @@ -5754,7 +5775,8 @@ public final class NotificationPanelViewController implements Dumpable { positionClockAndNotifications(true /* forceUpdate */); } - private final class ShadeAttachStateChangeListener implements View.OnAttachStateChangeListener { + private final class ShadeAttachStateChangeListener implements View.OnAttachStateChangeListener, + TunerService.Tunable { @Override public void onViewAttachedToWindow(View v) { mFragmentService.getFragmentHostManager(mView) @@ -5762,6 +5784,7 @@ public final class NotificationPanelViewController implements Dumpable { mStatusBarStateController.addCallback(mStatusBarStateListener); mStatusBarStateListener.onStateChanged(mStatusBarStateController.getState()); mConfigurationController.addCallback(mConfigurationListener); + mTunerService.addTunable(this, DOUBLE_TAP_SLEEP_GESTURE); // Theme might have changed between inflating this view and attaching it to the // window, so // force a call to onThemeChanged @@ -5779,6 +5802,14 @@ public final class NotificationPanelViewController implements Dumpable { mStatusBarStateController.removeCallback(mStatusBarStateListener); mConfigurationController.removeCallback(mConfigurationListener); mFalsingManager.removeTapListener(mFalsingTapListener); + mTunerService.removeTunable(this); + } + + @Override + public void onTuningChanged(String key, String newValue) { + if (DOUBLE_TAP_SLEEP_GESTURE.equals(key)) { + mDoubleTapToSleepEnabled = TunerService.parseIntegerSwitch(newValue, true); + } } } @@ -6121,6 +6152,10 @@ public final class NotificationPanelViewController implements Dumpable { return false; } + if (mDoubleTapToSleepEnabled && !mPulsing && !mDozing && mBarState == StatusBarState.KEYGUARD) { + mDoubleTapGesture.onTouchEvent(event); + } + // Make sure the next touch won't the blocked after the current ends. if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { diff --git a/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt b/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt index db700650e46c..41aeff9533a0 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt @@ -59,10 +59,13 @@ class PulsingGestureListener @Inject constructor( ) : GestureDetector.SimpleOnGestureListener(), Dumpable { private var doubleTapEnabled = false private var singleTapEnabled = false + private var doubleTapEnabledNative = false init { - val tunable = Tunable { key: String?, _: String? -> + val tunable = Tunable { key: String?, value: String? -> when (key) { + Settings.Secure.DOUBLE_TAP_TO_WAKE -> + doubleTapEnabledNative = TunerService.parseIntegerSwitch(value, false) Settings.Secure.DOZE_DOUBLE_TAP_GESTURE -> doubleTapEnabled = ambientDisplayConfiguration.doubleTapGestureEnabled( UserHandle.USER_CURRENT) @@ -72,6 +75,7 @@ class PulsingGestureListener @Inject constructor( } } tunerService.addTunable(tunable, + Settings.Secure.DOUBLE_TAP_TO_WAKE, Settings.Secure.DOZE_DOUBLE_TAP_GESTURE, Settings.Secure.DOZE_TAP_SCREEN_GESTURE) @@ -109,7 +113,7 @@ class PulsingGestureListener @Inject constructor( // checks MUST be on the ACTION_UP event. if (e.actionMasked == MotionEvent.ACTION_UP && statusBarStateController.isDozing && - (doubleTapEnabled || singleTapEnabled) && + (doubleTapEnabled || singleTapEnabled || doubleTapEnabledNative) && !falsingManager.isProximityNear && !falsingManager.isFalseDoubleTap ) { @@ -127,6 +131,7 @@ class PulsingGestureListener @Inject constructor( override fun dump(pw: PrintWriter, args: Array<out String>) { pw.println("singleTapEnabled=$singleTapEnabled") pw.println("doubleTapEnabled=$doubleTapEnabled") + pw.println("doubleTapEnabledNative=$doubleTapEnabledNative") pw.println("isDocked=${dockManager.isDocked}") pw.println("isProxCovered=${falsingManager.isProximityNear}") } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index 6a658b6ee047..3301d6907a25 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -304,10 +304,12 @@ public class KeyguardIndicationController { R.id.keyguard_indication_text_bottom); mInitialTextColorState = mTopIndicationView != null ? mTopIndicationView.getTextColors() : ColorStateList.valueOf(Color.WHITE); - mRotateTextViewController = new KeyguardIndicationRotateTextViewController( - mLockScreenIndicationView, - mExecutor, - mStatusBarStateController); + if (mRotateTextViewController == null || !mRotateTextViewController.isAttachedToWindow()) { + mRotateTextViewController = new KeyguardIndicationRotateTextViewController( + mLockScreenIndicationView, + mExecutor, + mStatusBarStateController); + } updateDeviceEntryIndication(false /* animate */); updateOrganizedOwnedDevice(); if (mBroadcastReceiver == null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java index 2dad8e053ee1..3b3a19942736 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java @@ -362,7 +362,10 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_CAMERA_LAUNCH, "com.android.systemui:CAMERA_GESTURE"); } - vibrateForCameraGesture(); + + if (source != StatusBarManager.CAMERA_LAUNCH_SOURCE_SCREEN_GESTURE) { + vibrateForCameraGesture(); + } if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP) { Log.v(CentralSurfaces.TAG, "Camera launch"); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index e29305d54a10..8273a11a94f4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -1470,6 +1470,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); filter.addAction(Intent.ACTION_SCREEN_OFF); + filter.addAction(Intent.ACTION_SCREEN_CAMERA_GESTURE); mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter, null, UserHandle.ALL); } @@ -2562,6 +2563,21 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { finishBarAnimations(); resetUserExpandedStates(); } + else if (Intent.ACTION_SCREEN_CAMERA_GESTURE.equals(action)) { + boolean userSetupComplete = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.USER_SETUP_COMPLETE, 0) != 0; + if (!userSetupComplete) { + if (DEBUG) Log.d(TAG, String.format( + "userSetupComplete = %s, ignoring camera launch gesture.", + userSetupComplete)); + return; + } + + // This gets executed before we will show Keyguard, so post it in order that the + // state is correct. + mMainExecutor.execute(() -> mCommandQueueCallbacks.onCameraLaunchGestureDetected( + StatusBarManager.CAMERA_LAUNCH_SOURCE_SCREEN_GESTURE)); + } Trace.endSection(); } }; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java index 2ec7df9e6f16..a2c8b24248cf 100755 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -344,6 +344,9 @@ public class PhoneStatusBarPolicy mRecordingController.addCallback(this); mCommandQueue.addCallback(this); + + // Get initial user setup state + onUserSetupChanged(); } private String getManagedProfileAccessibilityString() { diff --git a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java index 05e566690f57..29f16c7b924a 100644 --- a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java +++ b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java @@ -272,10 +272,10 @@ public class SystemUIToast implements ToastPlugin.Toast { private static boolean showApplicationIcon(ApplicationInfo appInfo, PackageManager packageManager) { - if (hasFlag(appInfo.flags, FLAG_UPDATED_SYSTEM_APP)) { + if (hasFlag(appInfo.flags, FLAG_UPDATED_SYSTEM_APP | FLAG_SYSTEM)) { return packageManager.getLaunchIntentForPackage(appInfo.packageName) != null; } - return !hasFlag(appInfo.flags, FLAG_SYSTEM); + return true; } private static boolean hasFlag(int flags, int flag) { diff --git a/packages/SystemUI/src/com/android/systemui/tristate/TriStateUiController.java b/packages/SystemUI/src/com/android/systemui/tristate/TriStateUiController.java new file mode 100644 index 000000000000..5fed8858c34d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/tristate/TriStateUiController.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019 Paranoid Android + * + * 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.tristate; + +import com.android.systemui.plugins.Plugin; +import com.android.systemui.plugins.VolumeDialog.Callback; +import com.android.systemui.plugins.annotations.DependsOn; +import com.android.systemui.plugins.annotations.ProvidesInterface; + +@DependsOn(target = Callback.class) +@ProvidesInterface(action = "com.android.systemui.action.PLUGIN_TRI_STATE_UI", version = 1) +public interface TriStateUiController extends Plugin { + + public interface UserActivityListener { + void onTriStateUserActivity(); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/tristate/TriStateUiControllerImpl.java b/packages/SystemUI/src/com/android/systemui/tristate/TriStateUiControllerImpl.java new file mode 100644 index 000000000000..5779cbceba41 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/tristate/TriStateUiControllerImpl.java @@ -0,0 +1,503 @@ +/* + * Copyright 2019 Paranoid Android + * + * 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.tristate; + +import static android.view.Surface.ROTATION_90; +import static android.view.Surface.ROTATION_180; +import static android.view.Surface.ROTATION_270; + +import android.app.Dialog; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.res.ColorStateList; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.drawable.ColorDrawable; +import android.hardware.display.DisplayManagerGlobal; +import android.media.AudioManager; +import android.os.Build; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.provider.Settings; +import android.util.Log; +import android.view.Display; +import android.view.OrientationEventListener; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager.LayoutParams; +import android.widget.ImageView; +import android.widget.TextView; + +import com.android.internal.policy.SystemBarUtils; +import com.android.systemui.Dependency; +import com.android.systemui.R; +import com.android.systemui.tristate.TriStateUiController; +import com.android.systemui.tristate.TriStateUiController.UserActivityListener; +import com.android.systemui.plugins.VolumeDialogController; +import com.android.systemui.plugins.VolumeDialogController.Callbacks; +import com.android.systemui.plugins.VolumeDialogController.State; +import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; + +public class TriStateUiControllerImpl implements ConfigurationListener, TriStateUiController { + + private static String TAG = "TriStateUiControllerImpl"; + + private static final int MSG_DIALOG_SHOW = 1; + private static final int MSG_DIALOG_DISMISS = 2; + private static final int MSG_RESET_SCHEDULE = 3; + private static final int MSG_STATE_CHANGE = 4; + + private static final int MODE_NORMAL = AudioManager.RINGER_MODE_NORMAL; + private static final int MODE_SILENT = AudioManager.RINGER_MODE_SILENT; + private static final int MODE_VIBRATE = AudioManager.RINGER_MODE_VIBRATE; + + private static final int TRI_STATE_UI_POSITION_LEFT = 0; + private static final int TRI_STATE_UI_POSITION_RIGHT = 1; + + private static final int DIALOG_TIMEOUT = 2000; + + private Context mContext; + private final VolumeDialogController mVolumeDialogController; + private final Callbacks mVolumeDialogCallback = new Callbacks() { + @Override + public void onShowRequested(int reason, boolean keyguardLocked, int lockTaskModeState) { } + + @Override + public void onDismissRequested(int reason) { } + + @Override + public void onScreenOff() { } + + @Override + public void onStateChanged(State state) { } + + @Override + public void onLayoutDirectionChanged(int layoutDirection) { } + + @Override + public void onShowVibrateHint() { } + + @Override + public void onShowSilentHint() { } + + @Override + public void onShowSafetyWarning(int flags) { } + + @Override + public void onAccessibilityModeChanged(Boolean showA11yStream) { } + + @Override + public void onCaptionComponentStateChanged( + Boolean isComponentEnabled, Boolean fromTooltip) {} + + @Override + public void onConfigurationChanged() { + updateTheme(); + updateTriStateLayout(); + } + }; + + private int mDensity; + private Dialog mDialog; + private int mDialogPosition; + private ViewGroup mDialogView; + private final H mHandler; + private UserActivityListener mListener; + OrientationEventListener mOrientationListener; + private int mOrientationType = 0; + private boolean mShowing = false; + private int mBackgroundColor = 0; + private int mThemeMode = 0; + private int mIconColor = 0; + private int mTextColor = 0; + private ImageView mTriStateIcon; + private TextView mTriStateText; + private int mTriStateMode = -1; + private Window mWindow; + private LayoutParams mWindowLayoutParams; + private int mWindowType; + + private final BroadcastReceiver mRingerStateReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + updateRingerModeChanged(); + } + }; + + private final class H extends Handler { + private TriStateUiControllerImpl mUiController; + + public H(TriStateUiControllerImpl uiController) { + super(Looper.getMainLooper()); + mUiController = uiController; + } + + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_DIALOG_SHOW: + mUiController.handleShow(); + return; + case MSG_DIALOG_DISMISS: + mUiController.handleDismiss(); + return; + case MSG_RESET_SCHEDULE: + mUiController.handleResetTimeout(); + return; + case MSG_STATE_CHANGE: + mUiController.handleStateChanged(); + return; + default: + return; + } + } + } + + public TriStateUiControllerImpl(Context context) { + mContext = context; + mHandler = new H(this); + mOrientationListener = new OrientationEventListener(mContext, 3) { + @Override + public void onOrientationChanged(int orientation) { + checkOrientationType(); + } + }; + mVolumeDialogController = + (VolumeDialogController) Dependency.get(VolumeDialogController.class); + IntentFilter ringerChanged = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION); + mContext.registerReceiver(mRingerStateReceiver, ringerChanged); + } + + private void checkOrientationType() { + Display display = DisplayManagerGlobal.getInstance().getRealDisplay(0); + if (display != null) { + int rotation = display.getRotation(); + if (rotation != mOrientationType) { + mOrientationType = rotation; + updateTriStateLayout(); + } + } + } + + public void init(int windowType, UserActivityListener listener) { + mWindowType = windowType; + mDensity = mContext.getResources().getConfiguration().densityDpi; + mListener = listener; + ((ConfigurationController) Dependency.get( + ConfigurationController.class)).addCallback(this); + mVolumeDialogController.addCallback(mVolumeDialogCallback, mHandler); + initDialog(); + } + + public void destroy() { + ((ConfigurationController) Dependency.get( + ConfigurationController.class)).removeCallback(this); + mVolumeDialogController.removeCallback(mVolumeDialogCallback); + mContext.unregisterReceiver(mRingerStateReceiver); + } + + private void initDialog() { + if (mDialog != null) { + mDialog.dismiss(); + mDialog = null; + } + mDialog = new Dialog(mContext); + mShowing = false; + mWindow = mDialog.getWindow(); + mWindow.requestFeature(Window.FEATURE_NO_TITLE); + mWindow.setBackgroundDrawable(new ColorDrawable(0)); + mWindow.clearFlags(LayoutParams.FLAG_DIM_BEHIND); + mWindow.addFlags(LayoutParams.FLAG_NOT_FOCUSABLE + | LayoutParams.FLAG_LAYOUT_IN_SCREEN + | LayoutParams.FLAG_NOT_TOUCH_MODAL + | LayoutParams.FLAG_SHOW_WHEN_LOCKED + | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH + | LayoutParams.FLAG_HARDWARE_ACCELERATED); + mDialog.setCanceledOnTouchOutside(false); + mWindowLayoutParams = mWindow.getAttributes(); + mWindowLayoutParams.type = mWindowType; + mWindowLayoutParams.format = -3; + mWindowLayoutParams.setTitle(TriStateUiControllerImpl.class.getSimpleName()); + mWindowLayoutParams.gravity = 53; + mWindowLayoutParams.y = mDialogPosition; + mWindow.setAttributes(mWindowLayoutParams); + mWindow.setSoftInputMode(LayoutParams.SOFT_INPUT_ADJUST_NOTHING); + mDialog.setContentView(R.layout.tri_state_dialog); + mDialogView = (ViewGroup) mDialog.findViewById(R.id.tri_state_layout); + mTriStateIcon = (ImageView) mDialog.findViewById(R.id.tri_state_icon); + mTriStateText = (TextView) mDialog.findViewById(R.id.tri_state_text); + updateTheme(); + } + + public void show() { + mHandler.obtainMessage(MSG_DIALOG_SHOW, 0, 0).sendToTarget(); + } + + private void registerOrientationListener(boolean enable) { + if (mOrientationListener.canDetectOrientation() && enable) { + Log.v(TAG, "Can detect orientation"); + mOrientationListener.enable(); + return; + } + Log.v(TAG, "Cannot detect orientation"); + mOrientationListener.disable(); + } + + private void updateTriStateLayout() { + if (mContext != null) { + int iconId = 0; + int textId = 0; + int bg = 0; + Resources res = mContext.getResources(); + if (res != null) { + int positionY; + int positionY2 = mWindowLayoutParams.y; + int positionX = mWindowLayoutParams.x; + int gravity = mWindowLayoutParams.gravity; + switch (mTriStateMode) { + case MODE_SILENT: + iconId = R.drawable.ic_volume_ringer_mute; + textId = R.string.volume_ringer_status_silent; + break; + case MODE_VIBRATE: + iconId = R.drawable.ic_volume_ringer_vibrate; + textId = R.string.volume_ringer_status_vibrate; + break; + case MODE_NORMAL: + iconId = R.drawable.ic_volume_ringer; + textId = R.string.volume_ringer_status_normal; + break; + } + int triStatePos = res.getInteger( + com.android.internal.R.integer.config_alertSliderLocation); + boolean isTsKeyRight = true; + if (triStatePos == TRI_STATE_UI_POSITION_LEFT) { + isTsKeyRight = false; + } else if (triStatePos == TRI_STATE_UI_POSITION_RIGHT) { + isTsKeyRight = true; + } + switch (mOrientationType) { + case ROTATION_90: + if (isTsKeyRight) { + gravity = 51; + } else { + gravity = 83; + } + positionY2 = res.getDimensionPixelSize( + R.dimen.tri_state_up_dialog_position_deep_land); + if (isTsKeyRight) { + positionY2 += SystemBarUtils.getStatusBarHeight(mContext); + } + if (mTriStateMode == MODE_SILENT) { + positionX = res.getDimensionPixelSize( + R.dimen.tri_state_up_dialog_position_l); + } else if (mTriStateMode == MODE_VIBRATE) { + positionX = res.getDimensionPixelSize( + R.dimen.tri_state_middle_dialog_position_l); + } else if (mTriStateMode == MODE_NORMAL) { + positionX = res.getDimensionPixelSize( + R.dimen.tri_state_down_dialog_position_l); + } + bg = R.drawable.dialog_tri_state_middle_bg; + break; + case ROTATION_180: + if (isTsKeyRight) { + gravity = 83; + } else { + gravity = 85; + } + positionX = res.getDimensionPixelSize( + R.dimen.tri_state_up_dialog_position_deep); + positionY2 = SystemBarUtils.getStatusBarHeight(mContext); + bg = R.drawable.dialog_tri_state_middle_bg; + if (mTriStateMode != MODE_SILENT) { + if (mTriStateMode != MODE_VIBRATE) { + if (mTriStateMode == MODE_NORMAL) { + positionY2 += res.getDimensionPixelSize( + R.dimen.tri_state_down_dialog_position); + break; + } + } + positionY2 += res.getDimensionPixelSize( + R.dimen.tri_state_middle_dialog_position); + break; + } + positionY2 += res.getDimensionPixelSize(R.dimen.tri_state_up_dialog_position); + break; + case ROTATION_270: + if (isTsKeyRight) { + gravity = 85; + } else { + gravity = 53; + } + positionY2 = res.getDimensionPixelSize( + R.dimen.tri_state_up_dialog_position_deep_land); + if (!isTsKeyRight) { + positionY2 += SystemBarUtils.getStatusBarHeight(mContext); + } + if (mTriStateMode == MODE_SILENT) { + positionX = res.getDimensionPixelSize( + R.dimen.tri_state_up_dialog_position_l); + } else if (mTriStateMode == MODE_VIBRATE) { + positionX = res.getDimensionPixelSize( + R.dimen.tri_state_middle_dialog_position_l); + } else if (mTriStateMode == MODE_NORMAL) { + positionX = res.getDimensionPixelSize( + R.dimen.tri_state_down_dialog_position_l); + } + bg = R.drawable.dialog_tri_state_middle_bg; + break; + default: + if (isTsKeyRight) { + gravity = 53; + } else { + gravity = 51; + } + positionX = res.getDimensionPixelSize( + R.dimen.tri_state_up_dialog_position_deep); + if (mTriStateMode != MODE_SILENT) { + if (mTriStateMode != MODE_VIBRATE) { + if (mTriStateMode == MODE_NORMAL) { + positionY2 = res.getDimensionPixelSize( + R.dimen.tri_state_down_dialog_position) + + SystemBarUtils.getStatusBarHeight(mContext); + bg = R.drawable.dialog_tri_state_down_bg; + break; + } + } + positionY2 = res.getDimensionPixelSize( + R.dimen.tri_state_middle_dialog_position) + + SystemBarUtils.getStatusBarHeight(mContext); + bg = R.drawable.dialog_tri_state_middle_bg; + break; + } + positionY2 = res.getDimensionPixelSize( + R.dimen.tri_state_up_dialog_position) + + SystemBarUtils.getStatusBarHeight(mContext); + bg = R.drawable.dialog_tri_state_up_bg; + break; + } + if (mTriStateMode != -1) { + if (mTriStateIcon != null && iconId != 0) { + mTriStateIcon.setImageResource(iconId); + } + if (mTriStateText != null && textId != 0) { + String inputText = res.getString(textId); + if (inputText != null && mTriStateText.length() == inputText.length()) { + StringBuilder sb = new StringBuilder(); + sb.append(inputText); + sb.append(" "); + inputText = sb.toString(); + } + mTriStateText.setText(inputText); + } + if (mDialogView != null && bg != 0) { + mDialogView.setBackgroundDrawable(res.getDrawable(bg)); + } + mDialogPosition = positionY2; + } + positionY = res.getDimensionPixelSize(R.dimen.tri_state_dialog_padding); + mWindowLayoutParams.gravity = gravity; + mWindowLayoutParams.y = positionY2 - positionY; + mWindowLayoutParams.x = positionX - positionY; + mWindow.setAttributes(mWindowLayoutParams); + handleResetTimeout(); + } + } + } + + private void updateRingerModeChanged() { + mHandler.obtainMessage(MSG_STATE_CHANGE, 0, 0).sendToTarget(); + if (mTriStateMode != -1) { + show(); + } + } + + private void handleShow() { + mHandler.removeMessages(MSG_DIALOG_SHOW); + mHandler.removeMessages(MSG_DIALOG_DISMISS); + handleResetTimeout(); + if (!mShowing) { + updateTheme(); + registerOrientationListener(true); + checkOrientationType(); + mShowing = true; + mDialog.show(); + if (mListener != null) { + mListener.onTriStateUserActivity(); + } + } + } + + private void handleDismiss() { + mHandler.removeMessages(MSG_DIALOG_SHOW); + mHandler.removeMessages(MSG_DIALOG_DISMISS); + if (mShowing) { + registerOrientationListener(false); + mShowing = false; + mDialog.dismiss(); + } + } + + private void handleStateChanged() { + AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + int ringerMode = am.getRingerModeInternal(); + if (ringerMode != mTriStateMode) { + mTriStateMode = ringerMode; + updateTriStateLayout(); + if (mListener != null) { + mListener.onTriStateUserActivity(); + } + } + } + + public void handleResetTimeout() { + mHandler.removeMessages(MSG_DIALOG_DISMISS); + mHandler.sendMessageDelayed(mHandler.obtainMessage( + MSG_DIALOG_DISMISS, MSG_RESET_SCHEDULE, 0), (long) DIALOG_TIMEOUT); + if (mListener != null) { + mListener.onTriStateUserActivity(); + } + } + + @Override + public void onDensityOrFontScaleChanged() { + handleDismiss(); + initDialog(); + updateTriStateLayout(); + } + + private void updateTheme() { + // Todo: Add some logic to update the theme only when a new theme is applied + mIconColor = getAttrColor(android.R.attr.colorAccent); + mTextColor = getAttrColor(android.R.attr.textColorPrimary); + mBackgroundColor = getAttrColor(android.R.attr.colorPrimary); + mDialogView.setBackgroundTintList(ColorStateList.valueOf(mBackgroundColor)); + mTriStateIcon.setColorFilter(mIconColor); + mTriStateText.setTextColor(mTextColor); + } + + public int getAttrColor(int attr) { + TypedArray ta = mContext.obtainStyledAttributes(new int[]{attr}); + int colorAccent = ta.getColor(0, 0); + ta.recycle(); + return colorAccent; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java index e8a22ec4fbe7..a56bcacfb3bb 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java +++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java @@ -394,9 +394,8 @@ public class StorageNotification implements CoreStartable { final VolumeRecord rec = mStorageManager.findRecordByUuid(vol.getFsUuid()); final DiskInfo disk = vol.getDisk(); - // Don't annoy when user dismissed in past. (But make sure the disk is adoptable; we - // used to allow snoozing non-adoptable disks too.) - if (rec.isSnoozed() && disk.isAdoptable()) { + // Don't annoy when user dismissed in past. + if (rec.isSnoozed() && (disk.isAdoptable() || disk.isSd())) { return null; } if (disk.isAdoptable() && !rec.isInited() && rec.getType() != VolumeInfo.TYPE_PUBLIC @@ -439,8 +438,12 @@ public class StorageNotification implements CoreStartable { buildUnmountPendingIntent(vol))) .setContentIntent(browseIntent) .setCategory(Notification.CATEGORY_SYSTEM); - // Non-adoptable disks can't be snoozed. - if (disk.isAdoptable()) { + // USB disks notification can be persistent + if (disk.isUsb()) { + builder.setOngoing(true); + } + + if (disk.isAdoptable() || disk.isSd()) { builder.setDeleteIntent(buildSnoozeIntent(vol.getFsUuid())); } diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java index f71d98827e4b..7d086d27fa54 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java @@ -36,6 +36,8 @@ import com.android.systemui.plugins.VolumeDialog; import com.android.systemui.plugins.VolumeDialogController; import com.android.systemui.qs.tiles.DndTile; import com.android.systemui.statusbar.policy.ExtensionController; +import com.android.systemui.tristate.TriStateUiController; +import com.android.systemui.tristate.TriStateUiControllerImpl; import com.android.systemui.tuner.TunerService; import java.io.PrintWriter; @@ -49,7 +51,7 @@ import javax.inject.Inject; */ @SysUISingleton public class VolumeDialogComponent implements VolumeComponent, TunerService.Tunable, - VolumeDialogControllerImpl.UserActivityListener{ + VolumeDialogControllerImpl.UserActivityListener, TriStateUiController.UserActivityListener { public static final String VOLUME_DOWN_SILENT = "sysui_volume_down_silent"; public static final String VOLUME_UP_SILENT = "sysui_volume_up_silent"; @@ -66,6 +68,7 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna protected final Context mContext; private final VolumeDialogControllerImpl mController; + private TriStateUiControllerImpl mTriStateController; private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges( ActivityInfo.CONFIG_FONT_SCALE | ActivityInfo.CONFIG_LOCALE | ActivityInfo.CONFIG_ASSETS_PATHS | ActivityInfo.CONFIG_UI_MODE); @@ -95,6 +98,8 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna mActivityStarter = activityStarter; mController = volumeDialogController; mController.setUserActivityListener(this); + boolean hasAlertSlider = mContext.getResources(). + getBoolean(com.android.internal.R.bool.config_hasAlertSlider); // Allow plugins to reference the VolumeDialogController. pluginDependencyProvider.allowPluginDependency(VolumeDialogController.class); extensionController.newExtension(VolumeDialog.class) @@ -106,6 +111,13 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna } mDialog = dialog; mDialog.init(LayoutParams.TYPE_VOLUME_OVERLAY, mVolumeDialogCallback); + if (hasAlertSlider) { + if (mTriStateController != null) { + mTriStateController.destroy(); + } + mTriStateController = new TriStateUiControllerImpl(mContext); + mTriStateController.init(LayoutParams.TYPE_VOLUME_OVERLAY, this); + } }).build(); applyConfiguration(); tunerService.addTunable(this, VOLUME_DOWN_SILENT, VOLUME_UP_SILENT, @@ -193,6 +205,11 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna mActivityStarter.startActivity(intent, true /* onlyProvisioned */, true /* dismissShade */); } + @Override + public void onTriStateUserActivity() { + onUserActivity(); + } + private final VolumeDialogImpl.Callback mVolumeDialogCallback = new VolumeDialogImpl.Callback() { @Override public void onZenSettingsClicked() { diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index db3fd41cc95b..8d0135634ecf 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -275,6 +275,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, private Consumer<Boolean> mCrossWindowBlurEnabledListener; private BackgroundBlurDrawable mDialogRowsViewBackground; private final InteractionJankMonitor mInteractionJankMonitor; + private boolean mLeftVolumeRocker; public VolumeDialogImpl( Context context, @@ -312,6 +313,8 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, mUseBackgroundBlur = mContext.getResources().getBoolean(R.bool.config_volumeDialogUseBackgroundBlur); mInteractionJankMonitor = interactionJankMonitor; + mLeftVolumeRocker = + mContext.getResources().getBoolean(R.bool.config_audioPanelOnLeftSide); dumpManager.registerDumpable("VolumeDialogImpl", this); @@ -428,7 +431,11 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, lp.format = PixelFormat.TRANSLUCENT; lp.setTitle(VolumeDialogImpl.class.getSimpleName()); lp.windowAnimations = -1; - lp.gravity = mContext.getResources().getInteger(R.integer.volume_dialog_gravity); + if (!isAudioPanelOnLeftSide() || isLandscape()) { + lp.gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL; + } else { + lp.gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL; + } mWindow.setAttributes(lp); mWindow.setLayout(WRAP_CONTENT, WRAP_CONTENT); @@ -439,7 +446,8 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, mDialog.setOnShowListener(dialog -> { mDialogView.getViewTreeObserver().addOnComputeInternalInsetsListener(this); if (!shouldSlideInVolumeTray()) { - mDialogView.setTranslationX(mDialogView.getWidth() / 2.0f); + mDialogView.setTranslationX( + (mDialogView.getWidth() / 2.0f) * (isAudioPanelOnLeftSide() ? -1 : 1)); } mDialogView.setAlpha(0); mDialogView.animate() @@ -668,7 +676,11 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, if (D.BUG) Slog.d(TAG, "Adding row for stream " + stream); VolumeRow row = new VolumeRow(); initRow(row, stream, iconRes, iconMuteRes, important, defaultStream); - mDialogRowsView.addView(row.view); + if (!isAudioPanelOnLeftSide() || isLandscape()) { + mDialogRowsView.addView(row.view, 0); + } else { + mDialogRowsView.addView(row.view); + } mRows.add(row); } @@ -678,7 +690,11 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, final VolumeRow row = mRows.get(i); initRow(row, row.stream, row.iconRes, row.iconMuteRes, row.important, row.defaultStream); - mDialogRowsView.addView(row.view); + if (!isAudioPanelOnLeftSide() || isLandscape()) { + mDialogRowsView.addView(row.view, 0); + } else { + mDialogRowsView.addView(row.view); + } updateVolumeRowH(row); } } @@ -1401,7 +1417,10 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, hideRingerDrawer(); }, 50)); - if (!shouldSlideInVolumeTray()) animator.translationX(mDialogView.getWidth() / 2.0f); + if (!shouldSlideInVolumeTray()) { + animator.translationX( + (mDialogView.getWidth() / 2.0f) * (isAudioPanelOnLeftSide() ? -1 : 1)); + } animator.setListener(getJankListener(getDialogView(), TYPE_DISMISS, mDialogHideAnimationDurationMs)).start(); checkODICaptionsTooltip(true); @@ -2281,6 +2300,10 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, } } + private boolean isAudioPanelOnLeftSide() { + return mLeftVolumeRocker; + } + private static class VolumeRow { private View view; private TextView header; diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt index f580f5e00f67..7c0e627563ef 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt @@ -40,6 +40,7 @@ import com.android.systemui.demomode.DemoModeController import com.android.systemui.dump.DumpManager import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags +import com.android.systemui.plugins.ActivityStarter import com.android.systemui.qs.ChipVisibilityListener import com.android.systemui.qs.HeaderPrivacyIconsController import com.android.systemui.qs.carrier.QSCarrierGroup @@ -143,6 +144,7 @@ class LargeScreenShadeHeaderControllerCombinedTest : SysuiTestCase() { @Mock private lateinit var largeScreenConstraints: ConstraintSet @Mock private lateinit var demoModeController: DemoModeController + @Mock private lateinit var activityStarter: ActivityStarter @JvmField @Rule val mockitoRule = MockitoJUnit.rule() @@ -204,7 +206,8 @@ class LargeScreenShadeHeaderControllerCombinedTest : SysuiTestCase() { featureFlags, qsCarrierGroupControllerBuilder, combinedShadeHeadersConstraintManager, - demoModeController + demoModeController, + activityStarter ) whenever(view.isAttachedToWindow).thenReturn(true) controller.init() diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt index b568122d3fed..a973a70dd0eb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt @@ -19,6 +19,7 @@ import com.android.systemui.demomode.DemoModeController import com.android.systemui.dump.DumpManager import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags +import com.android.systemui.plugins.ActivityStarter import com.android.systemui.qs.HeaderPrivacyIconsController import com.android.systemui.qs.carrier.QSCarrierGroup import com.android.systemui.qs.carrier.QSCarrierGroupController @@ -75,6 +76,7 @@ class LargeScreenShadeHeaderControllerTest : SysuiTestCase() { @Mock private lateinit var mockedContext: Context @Mock private lateinit var demoModeController: DemoModeController + @Mock private lateinit var activityStarter: ActivityStarter @JvmField @Rule val mockitoRule = MockitoJUnit.rule() var viewVisibility = View.GONE @@ -129,7 +131,8 @@ class LargeScreenShadeHeaderControllerTest : SysuiTestCase() { featureFlags, qsCarrierGroupControllerBuilder, combinedShadeHeadersConstraintManager, - demoModeController + demoModeController, + activityStarter ) whenever(view.isAttachedToWindow).thenReturn(true) mLargeScreenShadeHeaderController.init() diff --git a/packages/overlays/Android.mk b/packages/overlays/Android.mk index 69641e69a9f2..4b0ae0abc66c 100644 --- a/packages/overlays/Android.mk +++ b/packages/overlays/Android.mk @@ -25,7 +25,6 @@ LOCAL_REQUIRED_MODULES := \ DisplayCutoutEmulationHoleOverlay \ DisplayCutoutEmulationTallOverlay \ DisplayCutoutEmulationWaterfallOverlay \ - FontNotoSerifSourceOverlay \ NavigationBarMode3ButtonOverlay \ NavigationBarModeGesturalOverlay \ NavigationBarModeGesturalOverlayNarrowBack \ diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto index 3801c2473c11..49f37db67e41 100644 --- a/proto/src/metrics_constants/metrics_constants.proto +++ b/proto/src/metrics_constants/metrics_constants.proto @@ -7437,5 +7437,8 @@ message MetricsEvent { // ---- End Q Constants, all Q constants go above this line ---- // Add new aosp constants above this line. // END OF AOSP CONSTANTS + + // ICE Metrics + ICE = 2772; } } diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java index e282679d8695..771281b7365c 100644 --- a/services/core/java/com/android/server/BatteryService.java +++ b/services/core/java/com/android/server/BatteryService.java @@ -165,6 +165,9 @@ public final class BatteryService extends SystemService { private boolean mBatteryLevelLow; + private boolean mOemFastCharger; + private boolean mLastOemFastCharger; + private long mDischargeStartTime; private int mDischargeStartLevel; @@ -491,6 +494,8 @@ public final class BatteryService extends SystemService { shutdownIfNoPowerLocked(); shutdownIfOverTempLocked(); + mOemFastCharger = isOemFastCharger(); + if (force || (mHealthInfo.batteryStatus != mLastBatteryStatus || mHealthInfo.batteryHealth != mLastBatteryHealth @@ -502,7 +507,8 @@ public final class BatteryService extends SystemService { || mHealthInfo.maxChargingCurrentMicroamps != mLastMaxChargingCurrent || mHealthInfo.maxChargingVoltageMicrovolts != mLastMaxChargingVoltage || mHealthInfo.batteryChargeCounterUah != mLastChargeCounter - || mInvalidCharger != mLastInvalidCharger)) { + || mInvalidCharger != mLastInvalidCharger + || mOemFastCharger != mLastOemFastCharger)) { if (mPlugType != mLastPlugType) { if (mLastPlugType == BATTERY_PLUGGED_NONE) { @@ -676,6 +682,7 @@ public final class BatteryService extends SystemService { mLastChargeCounter = mHealthInfo.batteryChargeCounterUah; mLastBatteryLevelCritical = mBatteryLevelCritical; mLastInvalidCharger = mInvalidCharger; + mLastOemFastCharger = mOemFastCharger; } } @@ -707,9 +714,11 @@ public final class BatteryService extends SystemService { BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE, mHealthInfo.maxChargingVoltageMicrovolts); intent.putExtra(BatteryManager.EXTRA_CHARGE_COUNTER, mHealthInfo.batteryChargeCounterUah); + intent.putExtra(BatteryManager.EXTRA_OEM_FAST_CHARGER, mOemFastCharger); if (DEBUG) { Slog.d(TAG, "Sending ACTION_BATTERY_CHANGED. scale:" + BATTERY_SCALE - + ", info:" + mHealthInfo.toString()); + + ", info:" + mHealthInfo.toString() + + ", mOemFastCharger:" + mOemFastCharger); } mHandler.post(() -> ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL)); @@ -761,6 +770,25 @@ public final class BatteryService extends SystemService { mLastBatteryLevelChangedSentMs = SystemClock.elapsedRealtime(); } + private boolean isOemFastCharger() { + final String path = mContext.getResources().getString( + com.android.internal.R.string.config_oemFastChargerStatusPath); + + if (path.isEmpty()) + return false; + + final String value = mContext.getResources().getString( + com.android.internal.R.string.config_oemFastChargerStatusValue); + + try { + return FileUtils.readTextFile(new File(path), value.length(), null).equals(value); + } catch (IOException e) { + Slog.e(TAG, "Failed to read oem fast charger status path: " + path); + } + + return false; + } + // TODO: Current code doesn't work since "--unplugged" flag in BSS was purposefully removed. private void logBatteryStatsLocked() { IBinder batteryInfoService = ServiceManager.getService(BatteryStats.SERVICE_NAME); diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 1e4d3f7d3de5..26cf38f2fa55 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -1619,6 +1619,8 @@ class StorageManagerService extends IStorageManager.Stub // public API requirement of being in a stable location. if (vol.disk.isAdoptable()) { vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE_FOR_WRITE; + } else if (vol.disk.isSd()) { + vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE_FOR_WRITE; } vol.mountUserId = mCurrentUserId; diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 44b186e1541f..9470a728389f 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -71,6 +71,7 @@ import android.content.pm.PackagePartitions; import android.content.pm.UserInfo; import android.os.BatteryStats; import android.os.Binder; +import android.os.Build; import android.os.Bundle; import android.os.Debug; import android.os.Handler; @@ -761,7 +762,7 @@ class UserController implements Handler.Callback { // purposefully block sending BOOT_COMPLETED until after all // PRE_BOOT receivers are finished to avoid ANR'ing apps final UserInfo info = getUserInfo(userId); - if (!Objects.equals(info.lastLoggedInFingerprint, PackagePartitions.FINGERPRINT) + if (!Objects.equals(info.lastLoggedInFingerprint, Build.VERSION.INCREMENTAL) || SystemProperties.getBoolean("persist.pm.mock-upgrade", false)) { // Suppress double notifications for managed profiles that // were unlocked automatically as part of their parent user being diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java index a6a3db11b729..e9b3e8577fd2 100644 --- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java @@ -1720,9 +1720,17 @@ public class GnssLocationProvider extends AbstractLocationProvider implements mContext.getSystemService(Context.TELEPHONY_SERVICE); int type = AGPS_SETID_TYPE_NONE; String setId = null; + final Boolean isEmergency = mNIHandler.getInEmergency(); + + // Unless we are in an emergency, do not provide sensitive subscriber information + // to SUPL servers. + if (!isEmergency) { + mGnssNative.setAgpsSetId(type, ""); + return; + } int subId = SubscriptionManager.getDefaultDataSubscriptionId(); - if (mNIHandler.getInEmergency() && mNetworkConnectivityHandler.getActiveSubId() >= 0) { + if (isEmergency && mNetworkConnectivityHandler.getActiveSubId() >= 0) { subId = mNetworkConnectivityHandler.getActiveSubId(); } if (SubscriptionManager.isValidSubscriptionId(subId)) { diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 4d44c886fa22..a7b0bc5ae0cd 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -2317,7 +2317,6 @@ public class NotificationManagerService extends SystemService { mAppOps, new SysUiStatsEvent.BuilderFactory(), mShowReviewPermissionsNotification); - mPreferencesHelper.updateFixedImportance(mUm.getUsers()); mRankingHelper = new RankingHelper(getContext(), mRankingHandler, mPreferencesHelper, @@ -2760,6 +2759,9 @@ public class NotificationManagerService extends SystemService { maybeShowInitialReviewPermissionsNotification(); } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { mSnoozeHelper.scheduleRepostsForPersistedNotifications(System.currentTimeMillis()); + } else if (phase == SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY) { + mPreferencesHelper.updateFixedImportance(mUm.getUsers()); + mPreferencesHelper.migrateNotificationPermissions(mUm.getUsers()); } } diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java index 5507158f34da..d7e8c832cdf9 100644 --- a/services/core/java/com/android/server/notification/PreferencesHelper.java +++ b/services/core/java/com/android/server/notification/PreferencesHelper.java @@ -237,7 +237,6 @@ public class PreferencesHelper implements RankingConfig { Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, NotificationManagerService.REVIEW_NOTIF_STATE_SHOULD_SHOW); } - ArrayList<PermissionHelper.PackagePermission> pkgPerms = new ArrayList<>(); synchronized (mPackagePreferences) { while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { tag = parser.getName(); @@ -255,27 +254,18 @@ public class PreferencesHelper implements RankingConfig { String name = parser.getAttributeValue(null, ATT_NAME); if (!TextUtils.isEmpty(name)) { restorePackage(parser, forRestore, userId, name, upgradeForBubbles, - migrateToPermission, pkgPerms); + migrateToPermission); } } } } } - if (migrateToPermission) { - for (PackagePermission p : pkgPerms) { - try { - mPermissionHelper.setNotificationPermission(p); - } catch (Exception e) { - Slog.e(TAG, "could not migrate setting for " + p.packageName, e); - } - } - } } @GuardedBy("mPackagePreferences") private void restorePackage(TypedXmlPullParser parser, boolean forRestore, @UserIdInt int userId, String name, boolean upgradeForBubbles, - boolean migrateToPermission, ArrayList<PermissionHelper.PackagePermission> pkgPerms) { + boolean migrateToPermission) { try { int uid = parser.getAttributeInt(null, ATT_UID, UNKNOWN_UID); if (forRestore) { @@ -382,14 +372,6 @@ public class PreferencesHelper implements RankingConfig { if (migrateToPermission) { r.importance = appImportance; r.migrateToPm = true; - if (r.uid != UNKNOWN_UID) { - // Don't call into permission system until we have a valid uid - PackagePermission pkgPerm = new PackagePermission( - r.pkg, UserHandle.getUserId(r.uid), - r.importance != IMPORTANCE_NONE, - hasUserConfiguredSettings(r)); - pkgPerms.add(pkgPerm); - } } } catch (Exception e) { Slog.w(TAG, "Failed to restore pkg", e); @@ -2679,6 +2661,31 @@ public class PreferencesHelper implements RankingConfig { } } + public void migrateNotificationPermissions(List<UserInfo> users) { + for (UserInfo user : users) { + List<PackageInfo> packages = mPm.getInstalledPackagesAsUser( + PackageManager.PackageInfoFlags.of(PackageManager.MATCH_ALL), + user.getUserHandle().getIdentifier()); + for (PackageInfo pi : packages) { + synchronized (mPackagePreferences) { + PackagePreferences p = getOrCreatePackagePreferencesLocked( + pi.packageName, pi.applicationInfo.uid); + if (p.migrateToPm && p.uid != UNKNOWN_UID) { + try { + PackagePermission pkgPerm = new PackagePermission( + p.pkg, UserHandle.getUserId(p.uid), + p.importance != IMPORTANCE_NONE, + hasUserConfiguredSettings(p)); + mPermissionHelper.setNotificationPermission(pkgPerm); + } catch (Exception e) { + Slog.e(TAG, "could not migrate setting for " + p.pkg, e); + } + } + } + } + } + } + private void updateConfig() { mRankingHandler.requestSort(); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 8b15b2da3dfd..cc6b1258d480 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -862,6 +862,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService final PendingPackageBroadcasts mPendingBroadcasts; + ArrayList<ComponentName> mDisabledComponentsList; + static final int SEND_PENDING_BROADCAST = 1; static final int INIT_COPY = 5; static final int POST_INSTALL = 9; @@ -1494,7 +1496,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService } PackageManagerService m = new PackageManagerService(injector, onlyCore, factoryTest, - PackagePartitions.FINGERPRINT, Build.IS_ENG, Build.IS_USERDEBUG, + Build.VERSION.INCREMENTAL, Build.IS_ENG, Build.IS_USERDEBUG, Build.VERSION.SDK_INT, Build.VERSION.INCREMENTAL); t.traceEnd(); // "create package manager" @@ -1961,7 +1963,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService !buildFingerprint.equals(ver.fingerprint); if (mIsUpgrade) { PackageManagerServiceUtils.logCriticalInfo(Log.INFO, "Upgrading from " - + ver.fingerprint + " to " + PackagePartitions.FINGERPRINT); + + ver.fingerprint + " to " + Build.VERSION.INCREMENTAL); } mInitAppsHelper = new InitAppsHelper(this, mApexManager, mInstallPackageHelper, @@ -2075,8 +2077,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService // allow... it would be nice to have some better way to handle // this situation. if (mIsUpgrade) { - Slog.i(TAG, "Build fingerprint changed from " + ver.fingerprint + " to " - + PackagePartitions.FINGERPRINT + Slog.i(TAG, "Build incremental version changed from " + ver.fingerprint + " to " + + Build.VERSION.INCREMENTAL + "; regranting permissions for internal storage"); } mPermissionManager.onStorageVolumeMounted( @@ -2092,13 +2094,24 @@ public class PackageManagerService implements PackageSender, TestUtilityService } } + // Disable components marked for disabling at build-time + mDisabledComponentsList = new ArrayList<ComponentName>(); + enableComponents(mContext.getResources().getStringArray( + com.android.internal.R.array.config_deviceDisabledComponents), false); + enableComponents(mContext.getResources().getStringArray( + com.android.internal.R.array.config_globallyDisabledComponents), false); + + // Enable components marked for forced-enable at build-time + enableComponents(mContext.getResources().getStringArray( + com.android.internal.R.array.config_forceEnabledComponents), true); + // If this is first boot after an OTA, and a normal boot, then // we need to clear code cache directories. // Note that we do *not* clear the application profiles. These remain valid // across OTAs and are used to drive profile verification (post OTA) and // profile compilation (without waiting to collect a fresh set of profiles). if (mIsUpgrade && !mOnlyCore) { - Slog.i(TAG, "Build fingerprint changed; clearing code caches"); + Slog.i(TAG, "Build incremental version changed; clearing code caches"); for (int i = 0; i < packageSettings.size(); i++) { final PackageSetting ps = packageSettings.valueAt(i); if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, ps.getVolumeUuid())) { @@ -2109,7 +2122,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService | Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES); } } - ver.fingerprint = PackagePartitions.FINGERPRINT; + ver.fingerprint = Build.VERSION.INCREMENTAL; } // Defer the app data fixup until we are done with app data clearing above. @@ -2268,6 +2281,30 @@ public class PackageManagerService implements PackageSender, TestUtilityService Slog.i(TAG, "Fix for b/169414761 is applied"); } + private void enableComponents(String[] components, boolean enable) { + // Disable or enable components marked at build-time + for (String name : components) { + ComponentName cn = ComponentName.unflattenFromString(name); + if (!enable) { + mDisabledComponentsList.add(cn); + } + Slog.v(TAG, "Changing enabled state of " + name + " to " + enable); + String className = cn.getClassName(); + String packageName = cn.getPackageName(); + AndroidPackage pkg = mPackages.get(packageName); + if (pkg == null || !AndroidPackageUtils.hasComponentClassName(pkg, className)) { + Slog.w(TAG, "Unable to change enabled state of " + name + " to " + enable); + continue; + } + PackageSetting pkgSetting = mSettings.getPackageLPr(packageName); + if (enable) { + pkgSetting.enableComponentLPw(className, UserHandle.USER_OWNER); + } else { + pkgSetting.disableComponentLPw(className, UserHandle.USER_OWNER); + } + } + } + @GuardedBy("mLock") void updateInstantAppInstallerLocked(String modifiedPackage) { // we're only interested in updating the installer application when 1) it's not @@ -5637,6 +5674,12 @@ public class PackageManagerService implements PackageSender, TestUtilityService public void setComponentEnabledSetting(ComponentName componentName, int newState, int flags, int userId) { if (!mUserManager.exists(userId)) return; + // Don't allow to enable components marked for disabling at build-time + if (mDisabledComponentsList.contains(componentName)) { + Slog.d(TAG, "Ignoring attempt to set enabled state of disabled component " + + componentName.flattenToString()); + return; + } setEnabledSettings(List.of(new PackageManager.ComponentEnabledSetting(componentName, newState, flags)), userId, null /* callingPackage */); diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index cfd029346340..a9b624653b92 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -445,7 +445,7 @@ public final class Settings implements Watchable, Snappable { public void forceCurrent() { sdkVersion = Build.VERSION.SDK_INT; databaseVersion = CURRENT_DATABASE_VERSION; - fingerprint = PackagePartitions.FINGERPRINT; + fingerprint = Build.VERSION.INCREMENTAL; } } @@ -5527,7 +5527,7 @@ public final class Settings implements Watchable, Snappable { } private String getExtendedFingerprint(long version) { - return PackagePartitions.FINGERPRINT + "?pc_version=" + version; + return Build.VERSION.INCREMENTAL + "?pc_version=" + version; } private static long uniformRandom(double low, double high) { diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index f303fedde567..66901edb1c1d 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -5162,7 +5162,7 @@ public class ShortcutService extends IShortcutService.Stub { // Injection point. String injectBuildFingerprint() { - return Build.FINGERPRINT; + return Build.VERSION.INCREMENTAL; } final void wtf(String message) { diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index c2dd32667bc2..7090881138c7 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -4046,7 +4046,7 @@ public class UserManagerService extends IUserManager.Stub { userInfo.creationTime = getCreationTime(); userInfo.partial = true; userInfo.preCreated = preCreate; - userInfo.lastLoggedInFingerprint = PackagePartitions.FINGERPRINT; + userInfo.lastLoggedInFingerprint = Build.VERSION.INCREMENTAL; if (userTypeDetails.hasBadge() && parentId != UserHandle.USER_NULL) { userInfo.profileBadge = getFreeProfileBadgeLU(parentId, userType); } @@ -5332,7 +5332,7 @@ public class UserManagerService extends IUserManager.Stub { t.traceBegin("onBeforeStartUser-" + userId); final int userSerial = userInfo.serialNumber; // Migrate only if build fingerprints mismatch - boolean migrateAppsData = !PackagePartitions.FINGERPRINT.equals( + boolean migrateAppsData = !Build.VERSION.INCREMENTAL.equals( userInfo.lastLoggedInFingerprint); t.traceBegin("prepareUserData"); mUserDataPreparer.prepareUserData(userId, userSerial, StorageManager.FLAG_STORAGE_DE); @@ -5363,7 +5363,7 @@ public class UserManagerService extends IUserManager.Stub { } final int userSerial = userInfo.serialNumber; // Migrate only if build fingerprints mismatch - boolean migrateAppsData = !PackagePartitions.FINGERPRINT.equals( + boolean migrateAppsData = !Build.VERSION.INCREMENTAL.equals( userInfo.lastLoggedInFingerprint); final TimingsTraceAndSlog t = new TimingsTraceAndSlog(); @@ -5408,7 +5408,7 @@ public class UserManagerService extends IUserManager.Stub { if (now > EPOCH_PLUS_30_YEARS) { userData.info.lastLoggedInTime = now; } - userData.info.lastLoggedInFingerprint = PackagePartitions.FINGERPRINT; + userData.info.lastLoggedInFingerprint = Build.VERSION.INCREMENTAL; scheduleWriteUser(userData); } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 20fb97839926..887dad13f463 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -190,6 +190,7 @@ import com.android.internal.app.AssistUtils; import com.android.internal.inputmethod.SoftInputShowHideReason; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; +import com.android.internal.os.DeviceKeyHandler; import com.android.internal.os.RoSystemProperties; import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.policy.IShortcutService; @@ -218,11 +219,15 @@ import com.android.server.wm.WindowManagerInternal; import com.android.server.wm.WindowManagerInternal.AppTransitionListener; import com.android.server.wm.WindowManagerService; +import dalvik.system.PathClassLoader; + import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; +import java.lang.reflect.Constructor; +import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -601,6 +606,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { private int mCurrentUserId; + private AssistUtils mAssistUtils; + // Maps global key codes to the components that will handle them. private GlobalKeyManager mGlobalKeyManager; @@ -622,6 +629,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { private boolean mLockNowPending = false; + private final List<DeviceKeyHandler> mDeviceKeyHandlers = new ArrayList<>(); + private static final int MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK = 3; private static final int MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK = 4; private static final int MSG_KEYGUARD_DRAWN_COMPLETE = 5; @@ -1307,6 +1316,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + private boolean hasAssistant() { + return mAssistUtils.getAssistComponentForUser(mCurrentUserId) != null; + } + private int getResolvedLongPressOnPowerBehavior() { if (FactoryTest.isLongPressOnPowerOffEnabled()) { return LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM; @@ -1314,7 +1327,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { // If the config indicates the assistant behavior but the device isn't yet provisioned, show // global actions instead. - if (mLongPressOnPowerBehavior == LONG_PRESS_POWER_ASSISTANT && !isDeviceProvisioned()) { + if (mLongPressOnPowerBehavior == LONG_PRESS_POWER_ASSISTANT && + (!isDeviceProvisioned() || !hasAssistant())) { return LONG_PRESS_POWER_GLOBAL_ACTIONS; } @@ -2126,6 +2140,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { mSafeModeEnabledVibePattern = getLongIntArray(mContext.getResources(), com.android.internal.R.array.config_safeModeEnabledVibePattern); + mAssistUtils = new AssistUtils(context); + mGlobalKeyManager = new GlobalKeyManager(mContext); // Controls rotation and the like. @@ -2170,6 +2186,28 @@ public class PhoneWindowManager implements WindowManagerPolicy { mWindowManagerFuncs.onKeyguardShowingAndNotOccludedChanged(); } }); + final String[] deviceKeyHandlerLibs = res.getStringArray( + com.android.internal.R.array.config_deviceKeyHandlerLibs); + final String[] deviceKeyHandlerClasses = res.getStringArray( + com.android.internal.R.array.config_deviceKeyHandlerClasses); + + for (int i = 0; + i < deviceKeyHandlerLibs.length && i < deviceKeyHandlerClasses.length; i++) { + try { + PathClassLoader loader = new PathClassLoader( + deviceKeyHandlerLibs[i], getClass().getClassLoader()); + Class<?> klass = loader.loadClass(deviceKeyHandlerClasses[i]); + Constructor<?> constructor = klass.getConstructor(Context.class); + mDeviceKeyHandlers.add((DeviceKeyHandler) constructor.newInstance(mContext)); + } catch (Exception e) { + Slog.w(TAG, "Could not instantiate device key handler " + + deviceKeyHandlerLibs[i] + " from class " + + deviceKeyHandlerClasses[i], e); + } + } + if (DEBUG_INPUT) { + Slog.d(TAG, "" + mDeviceKeyHandlers.size() + " device key handlers loaded"); + } initKeyCombinationRules(); initSingleKeyGestureRules(); mSideFpsEventHandler = new SideFpsEventHandler(mContext, mHandler, mPowerManager); @@ -3095,6 +3133,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { return key_consumed; } + // Specific device key handling + if (dispatchKeyToKeyHandlers(event)) { + return -1; + } + // Reserve all the META modifier combos for system behavior if ((metaState & KeyEvent.META_META_ON) != 0) { return key_consumed; @@ -3147,6 +3190,23 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + private boolean dispatchKeyToKeyHandlers(KeyEvent event) { + for (DeviceKeyHandler handler : mDeviceKeyHandlers) { + try { + if (DEBUG_INPUT) { + Log.d(TAG, "Dispatching key event " + event + " to handler " + handler); + } + event = handler.handleKeyEvent(event); + if (event == null) { + return true; + } + } catch (Exception e) { + Slog.w(TAG, "Could not dispatch event to device key handler", e); + } + } + return false; + } + // TODO(b/117479243): handle it in InputPolicy /** {@inheritDoc} */ @Override @@ -3862,6 +3922,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { && (!isNavBarVirtKey || mNavBarVirtualKeyHapticFeedbackEnabled) && event.getRepeatCount() == 0; + // Specific device key handling + if (dispatchKeyToKeyHandlers(event)) { + return 0; + } + // Handle special keys. switch (keyCode) { case KeyEvent.KEYCODE_BACK: { diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index dad9584c6722..f817bc4ac1b4 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -115,6 +115,8 @@ public class Notifier { -1); private static final VibrationAttributes HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES = VibrationAttributes.createForUsage(VibrationAttributes.USAGE_HARDWARE_FEEDBACK); + private static final VibrationEffect CHARGING_VIBRATION_DOUBLE_CLICK_EFFECT = + VibrationEffect.createPredefined(VibrationEffect.EFFECT_DOUBLE_CLICK); private final Object mLock = new Object(); @@ -844,8 +846,8 @@ public class Notifier { final boolean vibrate = Settings.Secure.getIntForUser(mContext.getContentResolver(), Settings.Secure.CHARGING_VIBRATION_ENABLED, 1, userId) != 0; if (vibrate) { - mVibrator.vibrate(CHARGING_VIBRATION_EFFECT, - HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES); + mVibrator.vibrate(mVibrator.hasAmplitudeControl() ? CHARGING_VIBRATION_EFFECT : + CHARGING_VIBRATION_DOUBLE_CLICK_EFFECT, HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES); } // play sound diff --git a/services/core/java/com/android/server/textservices/TextServicesManagerService.java b/services/core/java/com/android/server/textservices/TextServicesManagerService.java index cd2b8943ce11..f2106696de29 100644 --- a/services/core/java/com/android/server/textservices/TextServicesManagerService.java +++ b/services/core/java/com/android/server/textservices/TextServicesManagerService.java @@ -43,6 +43,8 @@ import android.service.textservice.SpellCheckerService; import android.text.TextUtils; import android.util.Slog; import android.util.SparseArray; +import android.view.inputmethod.InputMethodManager; +import android.view.inputmethod.InputMethodSubtype; import android.view.textservice.SpellCheckerInfo; import android.view.textservice.SpellCheckerSubtype; import android.view.textservice.SuggestionsInfo; @@ -544,19 +546,37 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { // subtypeHashCode == 0 means spell checker language settings is "auto" - if (systemLocale == null) { + Locale candidateLocale = null; + final InputMethodManager imm = mContext.getSystemService(InputMethodManager.class); + if (imm != null) { + final InputMethodSubtype currentInputMethodSubtype = + imm.getCurrentInputMethodSubtype(); + if (currentInputMethodSubtype != null) { + final String localeString = currentInputMethodSubtype.getLocale(); + if (!TextUtils.isEmpty(localeString)) { + // 1. Use keyboard locale if available in the spell checker + candidateLocale = SubtypeLocaleUtils.constructLocaleFromString(localeString); + } + } + } + if (candidateLocale == null) { + // 2. Use System locale if available in the spell checker + candidateLocale = systemLocale; + } + + if (candidateLocale == null) { return null; } SpellCheckerSubtype firstLanguageMatchingSubtype = null; for (int i = 0; i < sci.getSubtypeCount(); ++i) { final SpellCheckerSubtype scs = sci.getSubtypeAt(i); final Locale scsLocale = scs.getLocaleObject(); - if (Objects.equals(scsLocale, systemLocale)) { + if (Objects.equals(scsLocale, candidateLocale)) { // Exact match wins. return scs; } if (firstLanguageMatchingSubtype == null && scsLocale != null - && TextUtils.equals(systemLocale.getLanguage(), scsLocale.getLanguage())) { + && TextUtils.equals(candidateLocale.getLanguage(), scsLocale.getLanguage())) { // Remember as a fall back candidate firstLanguageMatchingSubtype = scs; } diff --git a/services/core/java/com/android/server/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java index 68f554cb2758..5604fc6c0f39 100644 --- a/services/core/java/com/android/server/webkit/SystemImpl.java +++ b/services/core/java/com/android/server/webkit/SystemImpl.java @@ -219,7 +219,7 @@ public class SystemImpl implements SystemInterface { @Override public boolean systemIsDebuggable() { - return Build.IS_DEBUGGABLE; + return Build.IS_DEBUGGABLE && Build.IS_ENG; } @Override diff --git a/services/core/java/com/android/server/wm/AlertWindowNotification.java b/services/core/java/com/android/server/wm/AlertWindowNotification.java index c589feae56ca..51c93a6293b4 100644 --- a/services/core/java/com/android/server/wm/AlertWindowNotification.java +++ b/services/core/java/com/android/server/wm/AlertWindowNotification.java @@ -24,6 +24,7 @@ import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.provider.Settings.ACTION_MANAGE_APP_OVERLAY_PERMISSION; +import android.annotation.UserIdInt; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; @@ -37,6 +38,7 @@ import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; +import android.os.UserHandle; import com.android.internal.R; import com.android.internal.util.ImageUtils; @@ -53,11 +55,14 @@ class AlertWindowNotification { private String mNotificationTag; private final NotificationManager mNotificationManager; private final String mPackageName; + private final @UserIdInt int mUserId; private boolean mPosted; - AlertWindowNotification(WindowManagerService service, String packageName) { + AlertWindowNotification(WindowManagerService service, String packageName, + @UserIdInt int userId) { mService = service; mPackageName = packageName; + mUserId = userId; mNotificationManager = (NotificationManager) mService.mContext.getSystemService(NOTIFICATION_SERVICE); mNotificationTag = CHANNEL_PREFIX + mPackageName; @@ -100,7 +105,7 @@ class AlertWindowNotification { final Context context = mService.mContext; final PackageManager pm = context.getPackageManager(); - final ApplicationInfo aInfo = getApplicationInfo(pm, mPackageName); + final ApplicationInfo aInfo = getApplicationInfoAsUser(pm, mPackageName, mUserId); final String appName = (aInfo != null) ? pm.getApplicationLabel(aInfo).toString() : mPackageName; @@ -138,6 +143,7 @@ class AlertWindowNotification { final Intent intent = new Intent(ACTION_MANAGE_APP_OVERLAY_PERMISSION, Uri.fromParts("package", packageName, null)); intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK); + intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.of(mUserId)); // Calls into activity manager... return PendingIntent.getActivity(context, mRequestCode, intent, FLAG_CANCEL_CURRENT | FLAG_IMMUTABLE); @@ -168,9 +174,10 @@ class AlertWindowNotification { } - private ApplicationInfo getApplicationInfo(PackageManager pm, String packageName) { + private ApplicationInfo getApplicationInfoAsUser(PackageManager pm, String packageName, + @UserIdInt int userId) { try { - return pm.getApplicationInfo(packageName, 0); + return pm.getApplicationInfoAsUser(packageName, 0, userId); } catch (PackageManager.NameNotFoundException e) { return null; } diff --git a/services/core/java/com/android/server/wm/RemoteDisplayChangeController.java b/services/core/java/com/android/server/wm/RemoteDisplayChangeController.java index 43baebc7255a..e646f14a3e13 100644 --- a/services/core/java/com/android/server/wm/RemoteDisplayChangeController.java +++ b/services/core/java/com/android/server/wm/RemoteDisplayChangeController.java @@ -114,9 +114,15 @@ public class RemoteDisplayChangeController { // timed-out, so run all continue callbacks and clear the list synchronized (mService.mGlobalLock) { for (int i = 0; i < mCallbacks.size(); ++i) { - mCallbacks.get(i).onContinueRemoteDisplayChange(null /* transaction */); + final ContinueRemoteDisplayChangeCallback callback = mCallbacks.get(i); + if (i == mCallbacks.size() - 1) { + // Clear all callbacks before calling the last one, so that if the callback + // itself calls {@link #isWaitingForRemoteDisplayChange()}, it will get + // {@code false}. After all, there is nothing pending after this one. + mCallbacks.clear(); + } + callback.onContinueRemoteDisplayChange(null /* transaction */); } - mCallbacks.clear(); } } diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index fb68fe666c0b..67088e957eb8 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -761,7 +761,8 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { if (mAlertWindowSurfaces.isEmpty()) { cancelAlertWindowNotification(); } else if (mAlertWindowNotification == null){ - mAlertWindowNotification = new AlertWindowNotification(mService, mPackageName); + mAlertWindowNotification = new AlertWindowNotification(mService, mPackageName, + UserHandle.getUserId(mUid)); if (mShowingAlertWindowNotificationAllowed) { mAlertWindowNotification.post(); } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java index 598a22bbde39..c9b264a1875b 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java @@ -676,10 +676,6 @@ public class PreferencesHelperTest extends UiServiceTestCase { compareChannels(ido, mHelper.getNotificationChannel(PKG_O, UID_O, ido.getId(), false)); compareChannels(idp, mHelper.getNotificationChannel(PKG_P, UID_P, idp.getId(), false)); - verify(mPermissionHelper).setNotificationPermission(nMr1Expected); - verify(mPermissionHelper).setNotificationPermission(oExpected); - verify(mPermissionHelper).setNotificationPermission(pExpected); - // verify that we also write a state for review_permissions_notification to eventually // show a notification assertEquals(NotificationManagerService.REVIEW_NOTIF_STATE_SHOULD_SHOW, diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 3edee50216b6..67b67c5bda70 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -9193,7 +9193,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL, false); sDefaults.putString(KEY_OPERATOR_NAME_FILTER_PATTERN_STRING, ""); sDefaults.putString(KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING, ""); - sDefaults.putBoolean(KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL, true); + sDefaults.putBoolean(KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL, false); sDefaults.putInt(KEY_LTE_PLUS_THRESHOLD_BANDWIDTH_KHZ_INT, 20000); sDefaults.putInt(KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT, 0); sDefaults.putBoolean(KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL, false); |