diff options
50 files changed, 856 insertions, 485 deletions
diff --git a/api/current.txt b/api/current.txt index 6253dfd4058c..1623bb8ab108 100644 --- a/api/current.txt +++ b/api/current.txt @@ -8988,8 +8988,8 @@ package android.bluetooth.le { method public android.bluetooth.le.ScanFilter.Builder setManufacturerData(int, byte[], byte[]); method public android.bluetooth.le.ScanFilter.Builder setServiceData(android.os.ParcelUuid, byte[]); method public android.bluetooth.le.ScanFilter.Builder setServiceData(android.os.ParcelUuid, byte[], byte[]); - method public android.bluetooth.le.ScanFilter.Builder setServiceSolicitationUuid(android.os.ParcelUuid); - method public android.bluetooth.le.ScanFilter.Builder setServiceSolicitationUuid(android.os.ParcelUuid, android.os.ParcelUuid); + method @NonNull public android.bluetooth.le.ScanFilter.Builder setServiceSolicitationUuid(@Nullable android.os.ParcelUuid); + method @NonNull public android.bluetooth.le.ScanFilter.Builder setServiceSolicitationUuid(@Nullable android.os.ParcelUuid, @Nullable android.os.ParcelUuid); method public android.bluetooth.le.ScanFilter.Builder setServiceUuid(android.os.ParcelUuid); method public android.bluetooth.le.ScanFilter.Builder setServiceUuid(android.os.ParcelUuid, android.os.ParcelUuid); } diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 12474ce83d11..68a88162a1bb 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -156,7 +156,7 @@ message Atom { KeyValuePairsAtom key_value_pairs_atom = 83 [(allow_from_any_uid) = true]; VibratorStateChanged vibrator_state_changed = 84; DeferredJobStatsReported deferred_job_stats_reported = 85; - ThermalThrottlingStateChanged thermal_throttling = 86; + ThermalThrottlingStateChanged thermal_throttling = 86 [deprecated=true]; BiometricAcquired biometric_acquired = 87; BiometricAuthenticated biometric_authenticated = 88; BiometricErrorOccurred biometric_error_occurred = 89; @@ -270,7 +270,7 @@ message Atom { HiddenApiUsed hidden_api_used = 178 [(allow_from_any_uid) = true]; StyleUIChanged style_ui_changed = 179; PrivacyIndicatorsInteracted privacy_indicators_interacted = - 180 [(log_from_module) = "permissioncontroller"]; + 180 [(log_from_module) = "permissioncontroller"]; AppInstallOnExternalStorageReported app_install_on_external_storage_reported = 181; NetworkStackReported network_stack_reported = 182 [(log_from_module) = "network_stack"]; AppMovedStorageReported app_moved_storage_reported = 183; @@ -280,6 +280,7 @@ message Atom { BluetoothClassOfDeviceReported bluetooth_class_of_device_reported = 187; IntelligenceEventReported intelligence_event_reported = 188 [(log_from_module) = "intelligence"]; + ThermalThrottlingSeverityStateChanged thermal_throttling_severity_state_changed = 189; } // Pulled events will start at field 10000. @@ -409,6 +410,7 @@ message KeyValuePairsAtom { */ /** + * This atom is deprecated starting in Q. Please use ThermalThrottlingSeverityStateChanged. * Logs when the Thermal service HAL notifies the throttling start/stop events. * * Logged from: @@ -426,14 +428,7 @@ message ThermalThrottlingStateChanged { } optional State state = 2; - // Temperature in deci degrees celsius optional float temperature = 3; - - // Severity of throttling - optional android.os.ThrottlingSeverityEnum severity = 4; - - // Thermistor name - optional string sensor_name = 5; } /** @@ -2364,6 +2359,27 @@ message BatteryCausedShutdown { } /** + * Logs when ThermalService receives throttling events. + * + * Logged from: + * frameworks/base/services/core/java/com/android/server/stats/StatsCompanionService.java + */ +message ThermalThrottlingSeverityStateChanged { + // The type of temperature being reported (CPU, GPU, SKIN, etc) + optional android.os.TemperatureTypeEnum sensor_type = 1; + + // The name of the temperature source. Eg. CPU0 + optional string sensor_name = 2; + + // Temperature in tenths of a degree C. + // For BCL, it is decimillivolt, decimilliamps, and percentage * 10. + optional int32 temperature_deci_celsius = 3; + + // Relative severity of the throttling, see enum definition. + optional android.os.ThrottlingSeverityEnum severity = 4; +} + +/** * Logs the duration of a davey (jank of >=700ms) when it occurs * * Logged from: diff --git a/cmds/statsd/src/guardrail/MemoryLeakTrackUtil.cpp b/cmds/statsd/src/guardrail/MemoryLeakTrackUtil.cpp deleted file mode 100644 index 01c75873fdf9..000000000000 --- a/cmds/statsd/src/guardrail/MemoryLeakTrackUtil.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2017, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define DEBUG false // STOPSHIP if true -#include "Log.h" - -#include <sstream> -#include "MemoryLeakTrackUtil.h" - -/* - * The code here originally resided in MediaPlayerService.cpp - */ - -// Figure out the abi based on defined macros. -#if defined(__arm__) -#define ABI_STRING "arm" -#elif defined(__aarch64__) -#define ABI_STRING "arm64" -#elif defined(__mips__) && !defined(__LP64__) -#define ABI_STRING "mips" -#elif defined(__mips__) && defined(__LP64__) -#define ABI_STRING "mips64" -#elif defined(__i386__) -#define ABI_STRING "x86" -#elif defined(__x86_64__) -#define ABI_STRING "x86_64" -#else -#error "Unsupported ABI" -#endif - -extern std::string backtrace_string(const uintptr_t* frames, size_t frame_count); - -namespace android { -namespace os { -namespace statsd { - -extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize, size_t* infoSize, - size_t* totalMemory, size_t* backtraceSize); - -extern "C" void free_malloc_leak_info(uint8_t* info); - -std::string dumpMemInfo(size_t limit) { - uint8_t* info; - size_t overallSize; - size_t infoSize; - size_t totalMemory; - size_t backtraceSize; - get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory, &backtraceSize); - - size_t count; - if (info == nullptr || overallSize == 0 || infoSize == 0 || - (count = overallSize / infoSize) == 0) { - VLOG("no malloc info, libc.debug.malloc.program property should be set"); - return std::string(); - } - - std::ostringstream oss; - oss << totalMemory << " bytes in " << count << " allocations\n"; - oss << " ABI: '" ABI_STRING "'" - << "\n\n"; - if (count > limit) count = limit; - - // The memory is sorted based on total size which is useful for finding - // worst memory offenders. For diffs, sometimes it is preferable to sort - // based on the backtrace. - for (size_t i = 0; i < count; i++) { - struct AllocEntry { - size_t size; // bit 31 is set if this is zygote allocated memory - size_t allocations; - uintptr_t backtrace[]; - }; - - const AllocEntry* const e = (AllocEntry*)(info + i * infoSize); - - oss << (e->size * e->allocations) << " bytes ( " << e->size << " bytes * " << e->allocations - << " allocations )\n"; - oss << backtrace_string(e->backtrace, backtraceSize) << "\n"; - } - oss << "\n"; - free_malloc_leak_info(info); - return oss.str(); -} - -} // namespace statsd -} // namespace os -} // namespace android
\ No newline at end of file diff --git a/cmds/statsd/src/guardrail/MemoryLeakTrackUtil.h b/cmds/statsd/src/guardrail/MemoryLeakTrackUtil.h deleted file mode 100644 index 444ed92cc9bb..000000000000 --- a/cmds/statsd/src/guardrail/MemoryLeakTrackUtil.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2017, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#pragma once - -#include <iostream> - -namespace android { -namespace os { -namespace statsd { -/* - * Dump the heap memory of the calling process, sorted by total size - * (allocation size * number of allocations). - * - * limit is the number of unique allocations to return. - */ -extern std::string dumpMemInfo(size_t limit); - -} // namespace statsd -} // namespace os -} // namespace android
\ No newline at end of file diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 0c6c77f8e36b..d0361b7e1118 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -3165,8 +3165,8 @@ public class Notification implements Parcelable /** * Gets the {@link LocusId} associated with this notification. * - * <p>Used by the device's intelligence services to correlate objects (such as - * {@link ShortcutInfo} and {@link ContentCaptureContext}) that are correlated. + * <p>Used by the Android system to correlate objects (such as + * {@link ShortcutInfo} and {@link ContentCaptureContext}). */ @Nullable public LocusId getLocusId() { @@ -3534,8 +3534,8 @@ public class Notification implements Parcelable * Sets the {@link LocusId} associated with this notification. * * <p>This method should be called when the {@link LocusId} is used in other places (such - * as {@link ShortcutInfo} and {@link ContentCaptureContext}) so the device's intelligence - * services can correlate them. + * as {@link ShortcutInfo} and {@link ContentCaptureContext}) so the Android system can + * correlate them. */ @NonNull public Builder setLocusId(@Nullable LocusId locusId) { diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java index 78140cf65d07..07ba2c6680a9 100644 --- a/core/java/android/bluetooth/le/ScanFilter.java +++ b/core/java/android/bluetooth/le/ScanFilter.java @@ -16,6 +16,7 @@ package android.bluetooth.le; +import android.annotation.NonNull; import android.annotation.Nullable; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; @@ -586,7 +587,8 @@ public final class ScanFilter implements Parcelable { /** * Set filter on service solicitation uuid. */ - public Builder setServiceSolicitationUuid(ParcelUuid serviceSolicitationUuid) { + public @NonNull Builder setServiceSolicitationUuid( + @Nullable ParcelUuid serviceSolicitationUuid) { mServiceSolicitationUuid = serviceSolicitationUuid; return this; } @@ -601,8 +603,9 @@ public final class ScanFilter implements Parcelable { * @throws IllegalArgumentException If {@code serviceSolicitationUuid} is {@code null} but * {@code serviceSolicitationUuidMask} is not {@code null}. */ - public Builder setServiceSolicitationUuid(ParcelUuid serviceSolicitationUuid, - ParcelUuid solicitationUuidMask) { + public @NonNull Builder setServiceSolicitationUuid( + @Nullable ParcelUuid serviceSolicitationUuid, + @Nullable ParcelUuid solicitationUuidMask) { if (mServiceSolicitationUuidMask != null && mServiceSolicitationUuid == null) { throw new IllegalArgumentException( "SolicitationUuid is null while SolicitationUuidMask is not null!"); diff --git a/core/java/android/content/LocusId.java b/core/java/android/content/LocusId.java index 283cea00b192..613765fd826a 100644 --- a/core/java/android/content/LocusId.java +++ b/core/java/android/content/LocusId.java @@ -29,9 +29,8 @@ import java.io.PrintWriter; * backup / restore. * * <p>Locus is a new concept introduced on - * {@link android.os.Build.VERSION_CODES#Q Android Q} and it lets the intelligence service provided - * by the Android System to correlate state between different subsystems such as content capture, - * shortcuts, and notifications. + * {@link android.os.Build.VERSION_CODES#Q Android Q} and it lets the Android system correlate + * state between different subsystems such as content capture, shortcuts, and notifications. * * <p>For example, if your app provides an activiy representing a chat between 2 users * (say {@code A} and {@code B}, this chat state could be represented by: diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 0ea5200d202a..1784d8ad3c6c 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -8447,6 +8447,20 @@ public class PackageParser { // Collect certificates if ((flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0) { collectCertificates(p, apexFile, false); + // Keep legacy mechanism for handling signatures. While this is deprecated, it's + // still part of the public API and needs to be maintained + if (p.mSigningDetails.hasPastSigningCertificates()) { + // Package has included signing certificate rotation information. Return + // the oldest cert so that programmatic checks keep working even if unaware + // of key rotation. + pi.signatures = new Signature[1]; + pi.signatures[0] = p.mSigningDetails.pastSigningCertificates[0]; + } else if (p.mSigningDetails.hasSignatures()) { + // otherwise keep old behavior + int numberOfSigs = p.mSigningDetails.signatures.length; + pi.signatures = new Signature[numberOfSigs]; + System.arraycopy(p.mSigningDetails.signatures, 0, pi.signatures, 0, numberOfSigs); + } if (p.mSigningDetails != SigningDetails.UNKNOWN) { // only return a valid SigningInfo if there is signing information to report pi.signingInfo = new SigningInfo(p.mSigningDetails); diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java index 1f82fa6b57e3..41be38a6e8dd 100644 --- a/core/java/android/content/pm/ShortcutInfo.java +++ b/core/java/android/content/pm/ShortcutInfo.java @@ -991,8 +991,8 @@ public final class ShortcutInfo implements Parcelable { * Sets the {@link LocusId} associated with this shortcut. * * <p>This method should be called when the {@link LocusId} is used in other places (such - * as {@link Notification} and {@link ContentCaptureContext}) so the device's intelligence - * services can correlate them. + * as {@link Notification} and {@link ContentCaptureContext}) so the Android system can + * correlate them. */ @NonNull public Builder setLocusId(@NonNull LocusId locusId) { @@ -1325,8 +1325,8 @@ public final class ShortcutInfo implements Parcelable { /** * Gets the {@link LocusId} associated with this shortcut. * - * <p>Used by the device's intelligence services to correlate objects (such as - * {@link Notification} and {@link ContentCaptureContext}) that are correlated. + * <p>Used by the Android system to correlate objects (such as + * {@link Notification} and {@link ContentCaptureContext}). */ @Nullable public LocusId getLocusId() { diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index 6c498c736854..9215de14c21f 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -267,6 +267,13 @@ public final class DeviceConfig { public static final String NAMESPACE_CONTACTS_PROVIDER = "contacts_provider"; /** + * Namespace for settings ui related features + * + * @hide + */ + public static final String NAMESPACE_SETTINGS_UI = "settings_ui"; + + /** * List of namespaces which can be read without READ_DEVICE_CONFIG permission * * @hide diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 83dc39e94d7a..ac59101d4090 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -12666,6 +12666,45 @@ public final class Settings { public static final String DYNAMIC_POWER_SAVINGS_ENABLED = "dynamic_power_savings_enabled"; /** + * A long value indicating how much longer the system battery is estimated to last in + * millis. See {@link #BATTERY_ESTIMATES_LAST_UPDATE_TIME} for the last time this value + * was updated. + * + * @hide + */ + public static final String TIME_REMAINING_ESTIMATE_MILLIS = + "time_remaining_estimate_millis"; + + /** + * A boolean indicating whether {@link #TIME_REMAINING_ESTIMATE_MILLIS} is based customized + * to the devices usage or using global models. See + * {@link #BATTERY_ESTIMATES_LAST_UPDATE_TIME} for the last time this value was updated. + * + * @hide + */ + public static final String TIME_REMAINING_ESTIMATE_BASED_ON_USAGE = + "time_remaining_estimate_based_on_usage"; + + /** + * A long value indicating how long the system battery takes to deplete from 100% to 0% on + * average based on historical drain rates. See {@link #BATTERY_ESTIMATES_LAST_UPDATE_TIME} + * for the last time this value was updated. + * + * @hide + */ + public static final String AVERAGE_TIME_TO_DISCHARGE = "average_time_to_discharge"; + + /** + * A long indicating the epoch time in milliseconds when + * {@link #TIME_REMAINING_ESTIMATE_MILLIS}, {@link #TIME_REMAINING_ESTIMATE_BASED_ON_USAGE}, + * and {@link #AVERAGE_TIME_TO_DISCHARGE} were last updated. + * + * @hide + */ + public static final String BATTERY_ESTIMATES_LAST_UPDATE_TIME = + "battery_estimates_last_update_time"; + + /** * The max value for {@link #LOW_POWER_MODE_TRIGGER_LEVEL}. If this setting is not set * or the value is 0, the default max will be used. * @@ -13531,6 +13570,28 @@ public final class Settings { private static final Validator AWARE_ALLOWED_VALIDATOR = BOOLEAN_VALIDATOR; /** + * Overrides internal R.integer.config_longPressOnPowerBehavior. + * Allowable values detailed in frameworks/base/core/res/res/values/config.xml. + * Used by PhoneWindowManager. + * @hide + */ + public static final String POWER_BUTTON_LONG_PRESS = + "power_button_long_press"; + private static final Validator POWER_BUTTON_LONG_PRESS_VALIDATOR = + new SettingsValidators.InclusiveIntegerRangeValidator(0, 5); + + /** + * Overrides internal R.integer.config_veryLongPressOnPowerBehavior. + * Allowable values detailed in frameworks/base/core/res/res/values/config.xml. + * Used by PhoneWindowManager. + * @hide + */ + public static final String POWER_BUTTON_VERY_LONG_PRESS = + "power_button_very_long_press"; + private static final Validator POWER_BUTTON_VERY_LONG_PRESS_VALIDATOR = + new SettingsValidators.InclusiveIntegerRangeValidator(0, 1); + + /** * Settings to backup. This is here so that it's in the same place as the settings * keys and easy to update. * @@ -13643,6 +13704,8 @@ public final class Settings { WIFI_PNO_RECENCY_SORTING_ENABLED_VALIDATOR); VALIDATORS.put(WIFI_LINK_PROBING_ENABLED, WIFI_LINK_PROBING_ENABLED_VALIDATOR); VALIDATORS.put(AWARE_ALLOWED, AWARE_ALLOWED_VALIDATOR); + VALIDATORS.put(POWER_BUTTON_LONG_PRESS, POWER_BUTTON_LONG_PRESS_VALIDATOR); + VALIDATORS.put(POWER_BUTTON_VERY_LONG_PRESS, POWER_BUTTON_VERY_LONG_PRESS_VALIDATOR); } /** @@ -14648,6 +14711,7 @@ public final class Settings { */ public static final String TEXT_CLASSIFIER_ACTION_MODEL_PARAMS = "text_classifier_action_model_params"; + } /** diff --git a/core/java/android/view/contentcapture/ContentCaptureContext.java b/core/java/android/view/contentcapture/ContentCaptureContext.java index 94e548fa0eeb..1692051924f4 100644 --- a/core/java/android/view/contentcapture/ContentCaptureContext.java +++ b/core/java/android/view/contentcapture/ContentCaptureContext.java @@ -261,6 +261,7 @@ public final class ContentCaptureContext implements Parcelable { * example). * <li>A unique identifier of the application state (for example, a conversation between * 2 users in a chat app). + * </ul> * * <p>See {@link ContentCaptureManager} for more info about the content capture context. * diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java index 26454c055932..a9770731dbc7 100644 --- a/core/java/android/view/contentcapture/ContentCaptureManager.java +++ b/core/java/android/view/contentcapture/ContentCaptureManager.java @@ -29,7 +29,6 @@ import android.annotation.UiThread; import android.content.ComponentName; import android.content.ContentCaptureOptions; import android.content.Context; -import android.graphics.Canvas; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -51,61 +50,61 @@ import java.util.ArrayList; import java.util.Set; /** - * <p>The {@link ContentCaptureManager} provides additional ways for for apps to - * integrate with the content capture subsystem. + * Content capture is mechanism used to let apps notify the Android system of events associated with + * views. * - * <p>Content capture provides real-time, continuous capture of application activity, display and - * events to an intelligence service that is provided by the Android system. The intelligence - * service then uses that info to mediate and speed user journey through different apps. For - * example, when the user receives a restaurant address in a chat app and switchs to a map app - * to search for that restaurant, the intelligence service could offer an autofill dialog to - * let the user automatically select its address. - * - * <p>Content capture was designed with two major concerns in mind: privacy and performance. - * - * <ul> - * <li><b>Privacy:</b> the intelligence service is a trusted component provided that is provided - * by the device manufacturer and that cannot be changed by the user (although the user can - * globaly disable content capture using the Android Settings app). This service can only use the - * data for in-device machine learning, which is enforced both by process isolation and - * <a href="https://source.android.com/compatibility/cdd">CDD requirements</a>. - * <li><b>Performance:</b> content capture is highly optimized to minimize its impact in the app - * jankiness and overall device system health. For example, its only enabled on apps (or even - * specific activities from an app) that were explicitly whitelisted by the intelligence service, - * and it buffers the events so they are sent in a batch to the service (see - * {@link #isContentCaptureEnabled()} for other cases when its disabled). - * </ul> - * - * <p>In fact, before using this manager, the app developer should check if it's available. Example: - * <code> + * <p>Before using this manager, you should check if it's available. Example: + * <pre><code> * ContentCaptureManager mgr = context.getSystemService(ContentCaptureManager.class); * if (mgr != null && mgr.isContentCaptureEnabled()) { * // ... * } - * </code> + * </code></pre> * - * <p>App developers usually don't need to explicitly interact with content capture, except when the - * app: + * <p>To support content capture, you must notifiy the Android system of the following events: * * <ul> - * <li>Can define a contextual {@link android.content.LocusId} to identify unique state (such as a - * conversation between 2 chat users). - * <li>Can have multiple view hierarchies with different contextual meaning (for example, a - * browser app with multiple tabs, each representing a different URL). - * <li>Contains custom views (that extend View directly and are not provided by the standard - * Android SDK. - * <li>Contains views that provide their own virtual hierarchy (like a web browser that render the - * HTML elements using a Canvas). + * <li>When a visible view is laid out, call + * {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)}. + * <li>When a view becomes invisible or is removed from the view hierarchy, call + * {@link ContentCaptureSession#notifyViewDisappeared(android.view.autofill.AutofillId)}. + * <li>When the view represents text and the text value changed, call {@link + * ContentCaptureSession#notifyViewTextChanged(android.view.autofill.AutofillId, CharSequence)}. * </ul> * + * <p>You can get a blank content capture structure using + * {@link ContentCaptureSession#newViewStructure(View)}, then populate its relevant fields. + * Here's an example of the relevant methods for an {@code EditText}-like view: + * + * <pre><code> + * public class MyEditText extends View { + * + * private void populateContentCaptureStructure(@NonNull ViewStructure structure) { + * structure.setText(getText(), getSelectionStart(), getSelectionEnd()); + * structure.setHint(getHint()); + * structure.setInputType(getInputType()); + * // set other properties like setTextIdEntry(), setTextLines(), setTextStyle(), + * // setMinTextEms(), setMaxTextEms(), setMaxTextLength() + * } + * + * private void onTextChanged() { + * if (isLaidOut() && isTextEditable()) { + * ContentCaptureManager mgr = mContext.getSystemService(ContentCaptureManager.class); + * if (cm != null && cm.isContentCaptureEnabled()) { + * ContentCaptureSession session = getContentCaptureSession(); + * if (session != null) { + * session.notifyViewTextChanged(getAutofillId(), getText()); + * } + * } + * } + * </code></pre> + * * <p>The main integration point with content capture is the {@link ContentCaptureSession}. A "main" - * session is automatically created by the Android System when content capture is enabled for the - * activity and its used by the standard Android views to notify the content capture service of - * events such as views being added, views been removed, and text changed by user input. The session - * could have a {@link ContentCaptureContext} to provide more contextual info about it, such as - * the locus associated with the view hierarchy (see {@link android.content.LocusId} for more info - * about locus). By default, the main session doesn't have a {@code ContentCaptureContext}, but you - * can change it after its created. Example: + * session is automatically created by the Android system when content capture is enabled for the + * activity. The session could have a {@link ContentCaptureContext} to provide more contextual info + * about it, such as the locus associated with the view hierarchy + * (see {@link android.content.LocusId} for more info about locus). By default, the main session + * doesn't have a {@code ContentCaptureContext}, but you can change it after its created. Example: * * <pre><code> * protected void onCreate(Bundle savedInstanceState) { @@ -145,54 +144,6 @@ import java.util.Set; * } * </code></pre> * - * <p>If your activity has custom views (i.e., views that extend {@link View} directly and provide - * just one logical view, not a virtual tree hiearchy) and it provides content that's relevant for - * content capture (as of {@link android.os.Build.VERSION_CODES#Q Android Q}, the only relevant - * content is text), then your view implementation should: - * - * <ul> - * <li>Set it as important for content capture. - * <li>Fill {@link ViewStructure} used for content capture. - * <li>Notify the {@link ContentCaptureSession} when the text is changed by user input. - * </ul> - * - * <p>Here's an example of the relevant methods for an {@code EditText}-like view: - * - * <pre><code> - * public class MyEditText extends View { - * - * public MyEditText(...) { - * if (getImportantForContentCapture() == IMPORTANT_FOR_CONTENT_CAPTURE_AUTO) { - * setImportantForContentCapture(IMPORTANT_FOR_CONTENT_CAPTURE_YES); - * } - * } - * - * public void onProvideContentCaptureStructure(@NonNull ViewStructure structure, int flags) { - * super.onProvideContentCaptureStructure(structure, flags); - * - * structure.setText(getText(), getSelectionStart(), getSelectionEnd()); - * structure.setHint(getHint()); - * structure.setInputType(getInputType()); - * // set other properties like setTextIdEntry(), setTextLines(), setTextStyle(), - * // setMinTextEms(), setMaxTextEms(), setMaxTextLength() - * } - * - * private void onTextChanged() { - * if (isLaidOut() && isImportantForContentCapture() && isTextEditable()) { - * ContentCaptureManager mgr = mContext.getSystemService(ContentCaptureManager.class); - * if (cm != null && cm.isContentCaptureEnabled()) { - * ContentCaptureSession session = getContentCaptureSession(); - * if (session != null) { - * session.notifyViewTextChanged(getAutofillId(), getText()); - * } - * } - * } - * </code></pre> - * - * <p>If your view provides its own virtual hierarchy (for example, if it's a browser that draws - * the HTML using {@link Canvas} or native libraries in a different render process), then the view - * is also responsible to notify the session when the virtual elements appear and disappear - - * see {@link ContentCaptureSession#newViewStructure(View)} for more info. */ @SystemService(Context.CONTENT_CAPTURE_MANAGER_SERVICE) public final class ContentCaptureManager { @@ -473,17 +424,6 @@ public final class ContentCaptureManager { /** * Checks whether content capture is enabled for this activity. - * - * <p>There are many reasons it could be disabled, such as: - * <ul> - * <li>App itself disabled content capture through {@link #setContentCaptureEnabled(boolean)}. - * <li>Intelligence service did not whitelist content capture for this activity's package. - * <li>Intelligence service did not whitelist content capture for this specific activity. - * <li>Intelligence service disabled content capture globally. - * <li>User disabled content capture globally through the Android Settings app. - * <li>Device manufacturer (OEM) disabled content capture globally. - * <li>Transient errors, such as intelligence service package being updated. - * </ul> */ public boolean isContentCaptureEnabled() { if (mOptions.lite) return false; @@ -503,9 +443,9 @@ public final class ContentCaptureManager { * Gets the list of conditions for when content capture should be allowed. * * <p>This method is typically used by web browsers so they don't generate unnecessary content - * capture events for websites the content capture service is not interested on. + * capture events for some websites. * - * @return list of conditions, or {@code null} if the service didn't set any restriction + * @return list of conditions, or {@code null} if there isn't any restriction * (in which case content capture events should always be generated). If the list is empty, * then it should not generate any event at all. */ diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java index 17a1fb405321..210dea1894bf 100644 --- a/core/java/android/view/contentcapture/ContentCaptureSession.java +++ b/core/java/android/view/contentcapture/ContentCaptureSession.java @@ -41,8 +41,7 @@ import java.util.ArrayList; import java.util.Random; /** - * Session used to notify a system-provided Content Capture service about events associated with - * views. + * Session used to notify the Android system about events associated with views. */ public abstract class ContentCaptureSession implements AutoCloseable { @@ -306,7 +305,7 @@ public abstract class ContentCaptureSession implements AutoCloseable { } /** - * Destroys this session, flushing out all pending notifications to the service. + * Destroys this session, flushing out all pending notifications. * * <p>Once destroyed, any new notification will be dropped. */ @@ -354,7 +353,7 @@ public abstract class ContentCaptureSession implements AutoCloseable { } /** - * Notifies the Content Capture Service that a node has been added to the view structure. + * Notifies the Android system that a node has been added to the view structure. * * @param node node that has been added. */ @@ -372,7 +371,7 @@ public abstract class ContentCaptureSession implements AutoCloseable { abstract void internalNotifyViewAppeared(@NonNull ViewNode.ViewStructureImpl node); /** - * Notifies the Content Capture Service that a node has been removed from the view structure. + * Notifies the Android system that a node has been removed from the view structure. * * @param id id of the node that has been removed. */ @@ -386,7 +385,7 @@ public abstract class ContentCaptureSession implements AutoCloseable { abstract void internalNotifyViewDisappeared(@NonNull AutofillId id); /** - * Notifies the Content Capture Service that many nodes has been removed from a virtual view + * Notifies the Android system that many nodes has been removed from a virtual view * structure. * * <p>Should only be called by views that handle their own virtual view hierarchy. @@ -412,7 +411,7 @@ public abstract class ContentCaptureSession implements AutoCloseable { } /** - * Notifies the Intelligence Service that the value of a text node has been changed. + * Notifies the Android system that the value of a text node has been changed. * * @param id of the node. * @param text new text. diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 744503afc958..83801157d0a9 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -200,7 +200,6 @@ public class ChooserActivity extends ResolverActivity { private ChooserListAdapter mChooserListAdapter; private ChooserRowAdapter mChooserRowAdapter; - private Drawable mChooserRowLayer; private int mChooserRowServiceSpacing; /** {@link ChooserActivity#getBaseScore} */ @@ -468,7 +467,6 @@ public class ChooserActivity extends ResolverActivity { .registerPredictionUpdates(this.getMainExecutor(), mAppPredictorCallback); } - mChooserRowLayer = getResources().getDrawable(R.drawable.chooser_row_layer_list, null); mChooserRowServiceSpacing = getResources() .getDimensionPixelSize(R.dimen.chooser_service_spacing); @@ -1952,6 +1950,7 @@ public class ChooserActivity extends ResolverActivity { int offset = 0; int rowsToShow = mChooserRowAdapter.getContentPreviewRowCount() + + mChooserRowAdapter.getProfileRowCount() + mChooserRowAdapter.getServiceTargetRowCount() + mChooserRowAdapter.getCallerAndRankedTargetRowCount(); @@ -1971,7 +1970,7 @@ public class ChooserActivity extends ResolverActivity { } int lastHeight = 0; - rowsToShow = Math.max(3, rowsToShow); + rowsToShow = Math.min(4, rowsToShow); for (int i = 0; i < Math.min(rowsToShow, mAdapterView.getChildCount()); i++) { lastHeight = mAdapterView.getChildAt(i).getHeight(); offset += lastHeight; @@ -2447,6 +2446,7 @@ public class ChooserActivity extends ResolverActivity { private static final int VIEW_TYPE_DIRECT_SHARE = 0; private static final int VIEW_TYPE_NORMAL = 1; private static final int VIEW_TYPE_CONTENT_PREVIEW = 2; + private static final int VIEW_TYPE_PROFILE = 3; private static final int MAX_TARGETS_PER_ROW_PORTRAIT = 4; private static final int MAX_TARGETS_PER_ROW_LANDSCAPE = 8; @@ -2502,9 +2502,9 @@ public class ChooserActivity extends ResolverActivity { @Override public int getCount() { - return (int) ( getContentPreviewRowCount() + + getProfileRowCount() + getServiceTargetRowCount() + getCallerAndRankedTargetRowCount() + Math.ceil( @@ -2525,6 +2525,10 @@ public class ChooserActivity extends ResolverActivity { return 1; } + public int getProfileRowCount() { + return mChooserListAdapter.getOtherProfile() == null ? 0 : 1; + } + public int getCallerAndRankedTargetRowCount() { return (int) Math.ceil( ((float) mChooserListAdapter.getCallerTargetCount() @@ -2560,6 +2564,10 @@ public class ChooserActivity extends ResolverActivity { return createContentPreviewView(convertView, parent); } + if (viewType == VIEW_TYPE_PROFILE) { + return createProfileView(convertView, parent); + } + if (convertView == null) { holder = createViewHolder(viewType, parent); } else { @@ -2577,6 +2585,10 @@ public class ChooserActivity extends ResolverActivity { return VIEW_TYPE_CONTENT_PREVIEW; } + if (getProfileRowCount() == 1 && position == getContentPreviewRowCount()) { + return VIEW_TYPE_PROFILE; + } + final int start = getFirstRowPosition(position); final int startType = mChooserListAdapter.getPositionTargetType(start); @@ -2589,7 +2601,7 @@ public class ChooserActivity extends ResolverActivity { @Override public int getViewTypeCount() { - return 3; + return 4; } private ViewGroup createContentPreviewView(View convertView, ViewGroup parent) { @@ -2605,6 +2617,17 @@ public class ChooserActivity extends ResolverActivity { (ViewGroup) convertView, parent); } + private View createProfileView(View convertView, ViewGroup parent) { + View profileRow = convertView != null ? convertView : mLayoutInflater.inflate( + R.layout.chooser_profile_row, parent, false); + profileRow.setBackground( + getResources().getDrawable(R.drawable.chooser_row_layer_list, null)); + mProfileView = profileRow.findViewById(R.id.profile_button); + mProfileView.setOnClickListener(ChooserActivity.this::onProfileClick); + bindProfileView(); + return profileRow; + } + private RowViewHolder loadViewsIntoRow(RowViewHolder holder) { final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); final int exactSpec = MeasureSpec.makeMeasureSpec(mChooserTargetWidth, @@ -2723,8 +2746,10 @@ public class ChooserActivity extends ResolverActivity { final ViewGroup row = holder.getViewGroup(); - if (startType != lastStartType || rowPosition == getContentPreviewRowCount()) { - row.setBackground(mChooserRowLayer); + if (startType != lastStartType + || rowPosition == getContentPreviewRowCount() + getProfileRowCount()) { + row.setBackground( + getResources().getDrawable(R.drawable.chooser_row_layer_list, null)); } else { row.setBackground(null); } @@ -2774,7 +2799,7 @@ public class ChooserActivity extends ResolverActivity { } int getFirstRowPosition(int row) { - row -= getContentPreviewRowCount(); + row -= getContentPreviewRowCount() + getProfileRowCount(); final int serviceCount = mChooserListAdapter.getServiceTargetCount(); final int serviceRows = (int) Math.ceil((float) serviceCount diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index ad1e767f011a..2849f57d6fc5 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -108,7 +108,7 @@ public class ResolverActivity extends Activity { private Button mAlwaysButton; private Button mOnceButton; private Button mSettingsButton; - private View mProfileView; + protected View mProfileView; private int mIconDpi; private int mLastSelected = AbsListView.INVALID_POSITION; private boolean mResolvingHome = false; @@ -142,9 +142,7 @@ public class ResolverActivity extends Activity { private final PackageMonitor mPackageMonitor = new PackageMonitor() { @Override public void onSomePackagesChanged() { mAdapter.handlePackagesChanged(); - if (mProfileView != null) { - bindProfileView(); - } + bindProfileView(); } @Override @@ -336,21 +334,7 @@ public class ResolverActivity extends Activity { mProfileView = findViewById(R.id.profile_button); if (mProfileView != null) { - mProfileView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - final DisplayResolveInfo dri = mAdapter.getOtherProfile(); - if (dri == null) { - return; - } - - // Do not show the profile switch message anymore. - mProfileSwitchMessageId = -1; - - onTargetSelected(dri, false); - finish(); - } - }); + mProfileView.setOnClickListener(this::onProfileClick); bindProfileView(); } @@ -367,6 +351,19 @@ public class ResolverActivity extends Activity { + (categories != null ? Arrays.toString(categories.toArray()) : "")); } + protected void onProfileClick(View v) { + final DisplayResolveInfo dri = mAdapter.getOtherProfile(); + if (dri == null) { + return; + } + + // Do not show the profile switch message anymore. + mProfileSwitchMessageId = -1; + + onTargetSelected(dri, false); + finish(); + } + @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); @@ -445,7 +442,11 @@ public class ResolverActivity extends Activity { return R.layout.resolver_list; } - void bindProfileView() { + protected void bindProfileView() { + if (mProfileView == null) { + return; + } + final DisplayResolveInfo dri = mAdapter.getOtherProfile(); if (dri != null) { mProfileView.setVisibility(View.VISIBLE); @@ -709,9 +710,7 @@ public class ResolverActivity extends Activity { mRegistered = true; } mAdapter.handlePackagesChanged(); - if (mProfileView != null) { - bindProfileView(); - } + bindProfileView(); } @Override @@ -1737,9 +1736,7 @@ public class ResolverActivity extends Activity { @Override protected void onPostExecute(List<ResolvedComponentInfo> sortedComponents) { processSortedList(sortedComponents); - if (mProfileView != null) { - bindProfileView(); - } + bindProfileView(); notifyDataSetChanged(); } }; @@ -2148,7 +2145,7 @@ public class ResolverActivity extends Activity { @Override protected void onPostExecute(Drawable d) { - if (mProfileView != null && mAdapter.getOtherProfile() == mDisplayResolveInfo) { + if (mAdapter.getOtherProfile() == mDisplayResolveInfo) { bindProfileView(); } else { mDisplayResolveInfo.setDisplayIcon(d); diff --git a/core/jni/android_ddm_DdmHandleNativeHeap.cpp b/core/jni/android_ddm_DdmHandleNativeHeap.cpp index e22f581e14e2..076e99dd1fba 100644 --- a/core/jni/android_ddm_DdmHandleNativeHeap.cpp +++ b/core/jni/android_ddm_DdmHandleNativeHeap.cpp @@ -22,6 +22,9 @@ #include <jni.h> #include "core_jni_helpers.h" +#include <android-base/logging.h> +#include <bionic_malloc.h> + #include <utils/Log.h> #include <utils/String8.h> @@ -30,11 +33,6 @@ #include <sys/types.h> #include <sys/stat.h> -extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize, - size_t* infoSize, size_t* totalMemory, size_t* backtraceSize); - -extern "C" void free_malloc_leak_info(uint8_t* info); - #define DDMS_HEADER_SIGNATURE 0x812345dd #define DDMS_VERSION 2 @@ -78,9 +76,16 @@ static jbyteArray DdmHandleNativeHeap_getLeakInfo(JNIEnv* env, jobject) { ReadFile("/proc/self/maps", maps); header.mapSize = maps.size(); - uint8_t* allocBytes; - get_malloc_leak_info(&allocBytes, &header.allocSize, &header.allocInfoSize, - &header.totalMemory, &header.backtraceSize); + android_mallopt_leak_info_t leak_info; + if (!android_mallopt(M_GET_MALLOC_LEAK_INFO, &leak_info, sizeof(leak_info))) { + PLOG(ERROR) << "*** Failed to get malloc leak info"; + return nullptr; + } + + header.allocSize = leak_info.overall_size; + header.allocInfoSize = leak_info.info_size; + header.totalMemory = leak_info.total_memory; + header.backtraceSize = leak_info.backtrace_size; ALOGD("*** mapSize: %zu allocSize: %zu allocInfoSize: %zu totalMemory: %zu", header.mapSize, header.allocSize, header.allocInfoSize, header.totalMemory); @@ -98,10 +103,10 @@ static jbyteArray DdmHandleNativeHeap_getLeakInfo(JNIEnv* env, jobject) { env->SetByteArrayRegion(array, sizeof(header), maps.size(), reinterpret_cast<const jbyte*>(maps.string())); env->SetByteArrayRegion(array, sizeof(header) + maps.size(), - header.allocSize, reinterpret_cast<jbyte*>(allocBytes)); + header.allocSize, reinterpret_cast<jbyte*>(leak_info.buffer)); } - free_malloc_leak_info(allocBytes); + android_mallopt(M_FREE_MALLOC_LEAK_INFO, &leak_info, sizeof(leak_info)); return array; } diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index 195fe58f0beb..69a7c4d80532 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -33,6 +33,8 @@ #include <string> #include <vector> +#include <android-base/logging.h> +#include <bionic_malloc.h> #include <debuggerd/client.h> #include <log/log.h> #include <utils/misc.h> @@ -663,9 +665,6 @@ static bool openFile(JNIEnv* env, jobject fileDescriptor, UniqueFile& fp) return true; } -/* pulled out of bionic */ -extern "C" void write_malloc_leak_info(FILE* fp); - /* * Dump the native heap, writing human-readable output to the specified * file descriptor. @@ -681,8 +680,11 @@ static void android_os_Debug_dumpNativeHeap(JNIEnv* env, jobject, ALOGD("Native heap dump starting...\n"); // Formatting of the native heap dump is handled by malloc debug itself. // See https://android.googlesource.com/platform/bionic/+/master/libc/malloc_debug/README.md#backtrace-heap-dump-format - write_malloc_leak_info(fp.get()); - ALOGD("Native heap dump complete.\n"); + if (android_mallopt(M_WRITE_MALLOC_LEAK_INFO_TO_FILE, fp.get(), sizeof(FILE*))) { + ALOGD("Native heap dump complete.\n"); + } else { + PLOG(ERROR) << "Failed to write native heap dump to file"; + } } /* diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml index 68c62a6ebf3e..138e24e36753 100644 --- a/core/res/res/layout/chooser_grid.xml +++ b/core/res/res/layout/chooser_grid.xml @@ -41,21 +41,6 @@ android:layout_centerHorizontal="true" android:layout_alignParentTop="true" /> - <TextView android:id="@+id/profile_button" - android:layout_width="wrap_content" - android:layout_height="48dp" - android:layout_marginEnd="8dp" - android:paddingStart="8dp" - android:paddingEnd="8dp" - android:visibility="gone" - style="?attr/borderlessButtonStyle" - android:textAppearance="?attr/textAppearanceButton" - android:textColor="?attr/colorAccent" - android:gravity="center_vertical" - android:layout_below="@id/drag" - android:layout_alignParentRight="true" - android:singleLine="true"/> - <TextView android:id="@+id/title" android:layout_height="wrap_content" android:layout_width="wrap_content" @@ -67,7 +52,7 @@ android:paddingBottom="@dimen/chooser_view_spacing" android:paddingLeft="24dp" android:paddingRight="24dp" - android:layout_below="@id/profile_button" + android:layout_below="@id/drag" android:layout_centerHorizontal="true"/> </RelativeLayout> diff --git a/core/res/res/layout/chooser_profile_row.xml b/core/res/res/layout/chooser_profile_row.xml new file mode 100644 index 000000000000..1a24a073a122 --- /dev/null +++ b/core/res/res/layout/chooser_profile_row.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2019, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center"> + <TextView + android:id="@+id/profile_button" + android:layout_width="wrap_content" + android:layout_height="48dp" + style="?attr/borderlessButtonStyle" + android:textAppearance="?attr/textAppearanceButton" + android:textColor="?attr/colorAccent" + android:singleLine="true"/> +</LinearLayout> + diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 9c4717b4497e..b3e94e39f30e 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1098,6 +1098,7 @@ 2 - Power off (with confirmation) 3 - Power off (without confirmation) 4 - Go to voice assist + 5 - Go to assistant (Settings.Secure.ASSISTANT) --> <integer name="config_longPressOnPowerBehavior">1</integer> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index a6a0c6e50a85..2f34c943bdfa 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2794,6 +2794,7 @@ <java-symbol type="drawable" name="scroll_indicator_material" /> <java-symbol type="layout" name="chooser_row" /> + <java-symbol type="layout" name="chooser_profile_row" /> <java-symbol type="color" name="chooser_row_divider" /> <java-symbol type="layout" name="chooser_row_direct_share" /> <java-symbol type="bool" name="config_supportDoubleTapWake" /> diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 0e94abc0dcac..a853121bac4e 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -130,8 +130,10 @@ public class SettingsBackupTest { Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE, Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS, Settings.Global.AUTOMATIC_POWER_SAVE_MODE, + Settings.Global.AVERAGE_TIME_TO_DISCHARGE, Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED, Settings.Global.BATTERY_CHARGING_STATE_UPDATE_DELAY, + Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME, Settings.Global.BROADCAST_BG_CONSTANTS, Settings.Global.BROADCAST_FG_CONSTANTS, Settings.Global.BROADCAST_OFFLOAD_CONSTANTS, @@ -462,6 +464,8 @@ public class SettingsBackupTest { Settings.Global.TEXT_CLASSIFIER_ACTION_MODEL_PARAMS, Settings.Global.THEATER_MODE_ON, Settings.Global.TIME_ONLY_MODE_CONSTANTS, + Settings.Global.TIME_REMAINING_ESTIMATE_MILLIS, + Settings.Global.TIME_REMAINING_ESTIMATE_BASED_ON_USAGE, Settings.Global.TRANSITION_ANIMATION_SCALE, Settings.Global.TRUSTED_SOUND, Settings.Global.TZINFO_UPDATE_CONTENT_URL, @@ -573,7 +577,10 @@ public class SettingsBackupTest { Settings.Global.RADIO_BUG_WAKELOCK_TIMEOUT_COUNT_THRESHOLD, Settings.Global.RADIO_BUG_SYSTEM_ERROR_COUNT_THRESHOLD, Settings.Global.ENABLED_SUBSCRIPTION_FOR_SLOT, - Settings.Global.MODEM_STACK_ENABLED_FOR_SLOT); + Settings.Global.MODEM_STACK_ENABLED_FOR_SLOT, + Settings.Global.POWER_BUTTON_LONG_PRESS, + Settings.Global.POWER_BUTTON_VERY_LONG_PRESS); + private static final Set<String> BACKUP_BLACKLISTED_SECURE_SETTINGS = newHashSet( Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java index 29e94e8b4bf6..767ec0e38a86 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java @@ -18,6 +18,7 @@ package com.android.internal.app; import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist; import static androidx.test.espresso.assertion.ViewAssertions.matches; import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; import static androidx.test.espresso.matcher.ViewMatchers.withId; @@ -245,7 +246,7 @@ public class ChooserActivityTest { waitForIdle(); assertThat(activity.getAdapter().getCount(), is(2)); - onView(withId(R.id.profile_button)).check(matches(not(isDisplayed()))); + onView(withId(R.id.profile_button)).check(doesNotExist()); ResolveInfo[] chosen = new ResolveInfo[1]; sOverrides.onSafelyStartCallback = targetInfo -> { diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java index fb5c16b92930..e19ac815b939 100644 --- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java @@ -37,7 +37,8 @@ public class BatterySaverUtils { /** * When set to "true" the notification will be a generic confirm message instead of asking the * user if they want to turn on battery saver. If set to false the dialog will specifically - * talk about turning on battery saver and provide a button for taking the action. + * talk about battery saver without giving the option of turning it on. The only button visible + * will be a generic confirmation button to acknowledge the dialog. */ public static final String EXTRA_CONFIRM_TEXT_ONLY = "extra_confirm_only"; /** diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/Estimate.kt b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/Estimate.kt new file mode 100644 index 000000000000..ae8e1e2a60c0 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/Estimate.kt @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.settingslib.fuelgauge + +import android.content.Context +import android.provider.Settings +import java.time.Duration +import java.time.Instant + +const val AVERAGE_TIME_TO_DISCHARGE_UNKNOWN = -1 +const val ESTIMATE_MILLIS_UNKNOWN = -1 + +class Estimate( + val estimateMillis: Long, + val isBasedOnUsage: Boolean, + val averageDischargeTime: Long +) { + companion object { + /** + * Returns the cached estimate if it is available and fresh. Will return null if estimate is + * unavailable or older than 2 minutes. + * + * @param context A valid context + * @return An [Estimate] object with the latest battery estimates. + */ + @JvmStatic + fun getCachedEstimateIfAvailable(context: Context): Estimate? { + // if time > 2 min return null or the estimate otherwise + val resolver = context.contentResolver + val lastUpdateTime = Instant.ofEpochMilli( + Settings.Global.getLong( + resolver, Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME, -1)) + return if (Duration.between(lastUpdateTime, + Instant.now()).compareTo(Duration.ofMinutes(2)) > 0) { + null + } else Estimate( + Settings.Global.getLong(resolver, + Settings.Global.TIME_REMAINING_ESTIMATE_MILLIS, + ESTIMATE_MILLIS_UNKNOWN.toLong()), + Settings.Global.getInt(resolver, + Settings.Global.TIME_REMAINING_ESTIMATE_BASED_ON_USAGE, 0) == 1, + Settings.Global.getLong(resolver, Settings.Global.AVERAGE_TIME_TO_DISCHARGE, + AVERAGE_TIME_TO_DISCHARGE_UNKNOWN.toLong())) + } + + /** + * Stores an estimate to the cache along with a timestamp. Can be obtained via + * [.getCachedEstimateIfAvailable]. + * + * @param context A valid context + * @param estimate the [Estimate] object to store + */ + @JvmStatic + fun storeCachedEstimate(context: Context, estimate: Estimate) { + // store the estimate and update the timestamp + val resolver = context.contentResolver + Settings.Global.putLong(resolver, Settings.Global.TIME_REMAINING_ESTIMATE_MILLIS, + estimate.estimateMillis) + Settings.Global.putInt(resolver, Settings.Global.TIME_REMAINING_ESTIMATE_BASED_ON_USAGE, + if (estimate.isBasedOnUsage) 1 else 0) + Settings.Global.putLong(resolver, Settings.Global.AVERAGE_TIME_TO_DISCHARGE, + estimate.averageDischargeTime) + Settings.Global.putLong(resolver, Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME, + System.currentTimeMillis()) + } + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java index eca39262dfb5..2e9b03c6b31e 100644 --- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java +++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java @@ -383,7 +383,7 @@ public class CarrierTextController { } if (TextUtils.isEmpty(displayText) && !airplaneMode) { - displayText = TextUtils.join(mSeparator, carrierNames); + displayText = joinNotEmpty(mSeparator, carrierNames); } final CarrierTextCallbackInfo info = new CarrierTextCallbackInfo( displayText, @@ -546,6 +546,25 @@ public class CarrierTextController { } } + /** + * Joins the strings in a sequence using a separator. Empty strings are discarded with no extra + * separator added so there are no extra separators that are not needed. + */ + private static CharSequence joinNotEmpty(CharSequence separator, CharSequence[] sequences) { + int length = sequences.length; + if (length == 0) return ""; + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < length; i++) { + if (!TextUtils.isEmpty(sequences[i])) { + if (!TextUtils.isEmpty(sb)) { + sb.append(separator); + } + sb.append(sequences[i]); + } + } + return sb.toString(); + } + private static List<CharSequence> append(List<CharSequence> list, CharSequence string) { if (!TextUtils.isEmpty(string)) { list.add(string); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java index 9d9c88f2c6ca..744f88d19ba3 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -86,7 +86,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi @Retention(SOURCE) @IntDef({DISMISS_USER_GESTURE, DISMISS_AGED, DISMISS_TASK_FINISHED, DISMISS_BLOCKED, - DISMISS_NOTIF_CANCEL, DISMISS_ACCESSIBILITY_ACTION}) + DISMISS_NOTIF_CANCEL, DISMISS_ACCESSIBILITY_ACTION, DISMISS_NO_LONGER_BUBBLE}) @interface DismissReason {} static final int DISMISS_USER_GESTURE = 1; @@ -95,6 +95,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi static final int DISMISS_BLOCKED = 4; static final int DISMISS_NOTIF_CANCEL = 5; static final int DISMISS_ACCESSIBILITY_ACTION = 6; + static final int DISMISS_NO_LONGER_BUBBLE = 7; static final int MAX_BUBBLES = 5; // TODO: actually enforce this @@ -129,8 +130,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi private final StatusBarWindowController mStatusBarWindowController; private StatusBarStateListener mStatusBarStateListener; - private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider = - Dependency.get(NotificationInterruptionStateProvider.class); + private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider; private INotificationManager mNotificationManagerService; @@ -189,15 +189,19 @@ public class BubbleController implements ConfigurationController.ConfigurationLi @Inject public BubbleController(Context context, StatusBarWindowController statusBarWindowController, - BubbleData data, ConfigurationController configurationController) { + BubbleData data, ConfigurationController configurationController, + NotificationInterruptionStateProvider interruptionStateProvider) { this(context, statusBarWindowController, data, null /* synchronizer */, - configurationController); + configurationController, interruptionStateProvider); } public BubbleController(Context context, StatusBarWindowController statusBarWindowController, BubbleData data, @Nullable BubbleStackView.SurfaceSynchronizer synchronizer, - ConfigurationController configurationController) { + ConfigurationController configurationController, + NotificationInterruptionStateProvider interruptionStateProvider) { mContext = context; + mNotificationInterruptionStateProvider = interruptionStateProvider; + configurationController.addCallback(this /* configurationListener */); mNotificationEntryManager = Dependency.get(NotificationEntryManager.class); @@ -394,7 +398,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi if (!areBubblesEnabled(mContext)) { return; } - if (shouldAutoBubbleForFlags(mContext, entry) || shouldBubble(entry)) { + if (mNotificationInterruptionStateProvider.shouldBubbleUp(entry)) { // TODO: handle group summaries? updateShowInShadeForSuppressNotification(entry); } @@ -405,7 +409,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi if (!areBubblesEnabled(mContext)) { return; } - if (entry.isBubble() && mNotificationInterruptionStateProvider.shouldBubbleUp(entry)) { + if (mNotificationInterruptionStateProvider.shouldBubbleUp(entry)) { updateBubble(entry); } } @@ -415,8 +419,11 @@ public class BubbleController implements ConfigurationController.ConfigurationLi if (!areBubblesEnabled(mContext)) { return; } - if (mNotificationInterruptionStateProvider.shouldBubbleUp(entry) - && alertAgain(entry, entry.notification.getNotification())) { + boolean shouldBubble = mNotificationInterruptionStateProvider.shouldBubbleUp(entry); + if (!shouldBubble && mBubbleData.hasBubbleWithKey(entry.key)) { + // It was previously a bubble but no longer a bubble -- lets remove it + removeBubble(entry.key, DISMISS_NO_LONGER_BUBBLE); + } else if (shouldBubble && alertAgain(entry, entry.notification.getNotification())) { updateShowInShadeForSuppressNotification(entry); entry.setBubbleDismissed(false); // updates come back as bubbles even if dismissed updateBubble(entry); @@ -561,17 +568,6 @@ public class BubbleController implements ConfigurationController.ConfigurationLi } /** - * Whether the notification has been developer configured to bubble and is allowed by the user. - */ - @VisibleForTesting - protected boolean shouldBubble(NotificationEntry entry) { - StatusBarNotification n = entry.notification; - boolean hasOverlayIntent = n.getNotification().getBubbleMetadata() != null - && n.getNotification().getBubbleMetadata().getIntent() != null; - return hasOverlayIntent && entry.canBubble; - } - - /** * Whether the notification should automatically bubble or not. Gated by secure settings flags. */ @VisibleForTesting diff --git a/packages/SystemUI/src/com/android/systemui/power/BatteryStateSnapshot.kt b/packages/SystemUI/src/com/android/systemui/power/BatteryStateSnapshot.kt index 02ad0f1766bd..f73bc93ff313 100644 --- a/packages/SystemUI/src/com/android/systemui/power/BatteryStateSnapshot.kt +++ b/packages/SystemUI/src/com/android/systemui/power/BatteryStateSnapshot.kt @@ -15,6 +15,7 @@ data class BatteryStateSnapshot( val severeLevelThreshold: Int, val lowLevelThreshold: Int, val timeRemainingMillis: Long, + val averageTimeToDischargeMillis: Long, val severeThresholdMillis: Long, val lowThresholdMillis: Long, val isBasedOnUsage: Boolean, @@ -39,18 +40,19 @@ data class BatteryStateSnapshot( severeLevelThreshold: Int, lowLevelThreshold: Int ) : this( - batteryLevel, - isPowerSaver, - plugged, - bucket, - batteryStatus, - severeLevelThreshold, - lowLevelThreshold, - NO_ESTIMATE_AVAILABLE.toLong(), - NO_ESTIMATE_AVAILABLE.toLong(), - NO_ESTIMATE_AVAILABLE.toLong(), - false, - true + batteryLevel, + isPowerSaver, + plugged, + bucket, + batteryStatus, + severeLevelThreshold, + lowLevelThreshold, + NO_ESTIMATE_AVAILABLE.toLong(), + NO_ESTIMATE_AVAILABLE.toLong(), + NO_ESTIMATE_AVAILABLE.toLong(), + NO_ESTIMATE_AVAILABLE.toLong(), + false, + true ) { this.isHybrid = false } diff --git a/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimates.java b/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimates.java index a87922792616..3b464783d009 100644 --- a/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimates.java +++ b/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimates.java @@ -1,5 +1,7 @@ package com.android.systemui.power; +import com.android.settingslib.fuelgauge.Estimate; + public interface EnhancedEstimates { /** diff --git a/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimatesImpl.java b/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimatesImpl.java index bfb809ecbf34..9b1f23aa0d0c 100644 --- a/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimatesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimatesImpl.java @@ -1,5 +1,7 @@ package com.android.systemui.power; +import com.android.settingslib.fuelgauge.Estimate; + public class EnhancedEstimatesImpl implements EnhancedEstimates { @Override diff --git a/packages/SystemUI/src/com/android/systemui/power/Estimate.kt b/packages/SystemUI/src/com/android/systemui/power/Estimate.kt deleted file mode 100644 index dca0d45c1c9f..000000000000 --- a/packages/SystemUI/src/com/android/systemui/power/Estimate.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.android.systemui.power - -data class Estimate(val estimateMillis: Long, val isBasedOnUsage: Boolean)
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java index 25d6d940d92e..b57c053964ca 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java @@ -42,6 +42,7 @@ import android.util.Log; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; +import com.android.settingslib.fuelgauge.Estimate; import com.android.settingslib.utils.ThreadUtils; import com.android.systemui.Dependency; import com.android.systemui.R; @@ -283,6 +284,7 @@ public class PowerUI extends SystemUI { mCurrentBatteryStateSnapshot = new BatteryStateSnapshot(mBatteryLevel, isPowerSaverMode, plugged, bucket, mBatteryStatus, mLowBatteryReminderLevels[1], mLowBatteryReminderLevels[0], estimate.getEstimateMillis(), + estimate.getAverageDischargeTime(), mEnhancedEstimates.getSevereWarningThreshold(), mEnhancedEstimates.getLowWarningThreshold(), estimate.isBasedOnUsage(), mEnhancedEstimates.getLowWarningEnabled()); @@ -316,7 +318,8 @@ public class PowerUI extends SystemUI { return estimate; } return new Estimate(mLastBatteryStateSnapshot.getTimeRemainingMillis(), - mLastBatteryStateSnapshot.isBasedOnUsage()); + mLastBatteryStateSnapshot.isBasedOnUsage(), + mLastBatteryStateSnapshot.getAverageTimeToDischargeMillis()); } @VisibleForTesting diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java index 2da68249d8c4..6adaa0ddbfd2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java @@ -149,6 +149,13 @@ public class KeyguardAffordanceView extends ImageView { updateIconColor(); } + /** + * If current drawable should be tinted. + */ + public boolean shouldTint() { + return mShouldTint; + } + @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); @@ -168,6 +175,9 @@ public class KeyguardAffordanceView extends ImageView { } public void setPreviewView(View v) { + if (mPreviewView == v) { + return; + } View oldPreviewView = mPreviewView; mPreviewView = v; if (mPreviewView != null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java index 059c3f672b69..926d4b6a79b3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java @@ -147,7 +147,14 @@ public class NotificationInterruptionStateProvider { * @return true if the entry should bubble up, false otherwise */ public boolean shouldBubbleUp(NotificationEntry entry) { - StatusBarNotification sbn = entry.notification; + final StatusBarNotification sbn = entry.notification; + if (!entry.canBubble) { + if (DEBUG) { + Log.d(TAG, "No bubble up: not allowed to bubble: " + sbn.getKey()); + } + return false; + } + if (!entry.isBubble()) { if (DEBUG) { Log.d(TAG, "No bubble up: notification " + sbn.getKey() @@ -156,6 +163,15 @@ public class NotificationInterruptionStateProvider { return false; } + final Notification n = sbn.getNotification(); + if (n.getBubbleMetadata() == null || n.getBubbleMetadata().getIntent() == null) { + if (DEBUG) { + Log.d(TAG, "No bubble up: notification: " + sbn.getKey() + + " doesn't have valid metadata"); + } + return false; + } + if (!canHeadsUpCommon(entry)) { return false; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index cb64f10d9e8c..5b464a9ecd97 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -337,7 +337,10 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private void updateRightAffordanceIcon() { IconState state = mRightButton.getIcon(); mRightAffordanceView.setVisibility(!mDozing && state.isVisible ? View.VISIBLE : View.GONE); - mRightAffordanceView.setImageDrawable(state.drawable, state.tint); + if (state.drawable != mRightAffordanceView.getDrawable() + || state.tint != mRightAffordanceView.shouldTint()) { + mRightAffordanceView.setImageDrawable(state.drawable, state.tint); + } mRightAffordanceView.setContentDescription(state.contentDescription); } @@ -389,7 +392,10 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private void updateLeftAffordanceIcon() { IconState state = mLeftButton.getIcon(); mLeftAffordanceView.setVisibility(!mDozing && state.isVisible ? View.VISIBLE : View.GONE); - mLeftAffordanceView.setImageDrawable(state.drawable, state.tint); + if (state.drawable != mLeftAffordanceView.getDrawable() + || state.tint != mLeftAffordanceView.shouldTint()) { + mLeftAffordanceView.setImageDrawable(state.drawable, state.tint); + } mLeftAffordanceView.setContentDescription(state.contentDescription); } @@ -715,11 +721,6 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL updateLeftPreview(); } - public void onKeyguardShowingChanged() { - updateLeftAffordance(); - inflateCameraPreview(); - } - private void setRightButton(IntentButton button) { mRightButton = button; updateRightAffordanceIcon(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 57b2ee9d893c..2207e0412949 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -1304,7 +1304,6 @@ public class NotificationPanelView extends PanelView implements mKeyguardStatusBar.setAlpha(1f); mKeyguardStatusBar.setVisibility(keyguardShowing ? View.VISIBLE : View.INVISIBLE); if (keyguardShowing && oldState != mBarState) { - mKeyguardBottomArea.onKeyguardShowingChanged(); if (mQs != null) { mQs.hideImmediately(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index a381bbc47657..3f33ba633d77 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -3926,6 +3926,10 @@ public class StatusBar extends SystemUI implements DemoMode, mScrimController.setWakeLockScreenSensorActive(true); } + if (reason == DozeLog.PULSE_REASON_DOCKING && mStatusBarWindow != null) { + mStatusBarWindow.suppressWakeUpGesture(true); + } + boolean passiveAuthInterrupt = reason == DozeLog.PULSE_REASON_NOTIFICATION; // Set the state to pulsing, so ScrimController will know what to do once we ask it to // execute the transition. The pulse callback will then be invoked when the scrims @@ -3945,6 +3949,9 @@ public class StatusBar extends SystemUI implements DemoMode, callback.onPulseFinished(); updateNotificationPanelTouchState(); mScrimController.setWakeLockScreenSensorActive(false); + if (mStatusBarWindow != null) { + mStatusBarWindow.suppressWakeUpGesture(false); + } setPulsing(false); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java index 28db28c7a845..44996acafc63 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java @@ -107,12 +107,13 @@ public class StatusBarWindowView extends FrameLayout { private boolean mTouchActive; private boolean mExpandAnimationRunning; private boolean mExpandAnimationPending; + private boolean mSuppressingWakeUpGesture; private final GestureDetector.SimpleOnGestureListener mGestureListener = new GestureDetector.SimpleOnGestureListener() { @Override public boolean onSingleTapConfirmed(MotionEvent e) { - if (mSingleTapEnabled) { + if (mSingleTapEnabled && !mSuppressingWakeUpGesture) { mService.wakeUpIfDozing(SystemClock.uptimeMillis(), StatusBarWindowView.this, "SINGLE_TAP"); return true; @@ -327,6 +328,10 @@ public class StatusBarWindowView extends FrameLayout { mTouchActive = touchActive; } + void suppressWakeUpGesture(boolean suppress) { + mSuppressingWakeUpGesture = suppress; + } + @Override public boolean dispatchTouchEvent(MotionEvent ev) { boolean isDown = ev.getActionMasked() == MotionEvent.ACTION_DOWN; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java index 273fa55ee9d8..fde1455b0af0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java @@ -31,10 +31,10 @@ import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.settingslib.fuelgauge.BatterySaverUtils; +import com.android.settingslib.fuelgauge.Estimate; import com.android.settingslib.utils.PowerUtil; import com.android.systemui.Dependency; import com.android.systemui.power.EnhancedEstimates; -import com.android.systemui.power.Estimate; import java.io.FileDescriptor; import java.io.PrintWriter; diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java index df534d79f730..9f91a17e846d 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java @@ -104,7 +104,8 @@ public class CarrierTextControllerTest extends SysuiTestCase { mCarrierTextCallbackInfo = new CarrierTextController.CarrierTextCallbackInfo("", new CharSequence[]{}, false, new int[]{}); - when(mTelephonyManager.getPhoneCount()).thenReturn(2); + when(mTelephonyManager.getPhoneCount()).thenReturn(3); + mCarrierTextController = new TestCarrierTextController(mContext, SEPARATOR, true, true, mKeyguardUpdateMonitor); // This should not start listening on any of the real dependencies @@ -130,6 +131,12 @@ public class CarrierTextControllerTest extends SysuiTestCase { reset(mCarrierTextCallback); when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn( new ArrayList<>()); + + // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the + // same answer as KeyguardUpdateMonitor. Remove when this is addressed + when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn( + new ArrayList<>()); + when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn( IccCardConstants.State.CARD_IO_ERROR); // This should not produce an out of bounds error, even though there are no subscriptions @@ -173,7 +180,11 @@ public class CarrierTextControllerTest extends SysuiTestCase { list.add(TEST_SUBSCRIPTION); when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY); when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); + + // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the + // same answer as KeyguardUpdateMonitor. Remove when this is addressed when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list); + mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = @@ -197,7 +208,11 @@ public class CarrierTextControllerTest extends SysuiTestCase { list.add(TEST_SUBSCRIPTION_ROAMING); when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY); when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); + + // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the + // same answer as KeyguardUpdateMonitor. Remove when this is addressed when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list); + mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = @@ -219,6 +234,12 @@ public class CarrierTextControllerTest extends SysuiTestCase { reset(mCarrierTextCallback); when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn( new ArrayList<>()); + + // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the + // same answer as KeyguardUpdateMonitor. Remove when this is addressed + when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn( + new ArrayList<>()); + ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = ArgumentCaptor.forClass( CarrierTextController.CarrierTextCallbackInfo.class); @@ -233,6 +254,121 @@ public class CarrierTextControllerTest extends SysuiTestCase { } + @Test + public void testCarrierText_twoValidSubscriptions() { + reset(mCarrierTextCallback); + List<SubscriptionInfo> list = new ArrayList<>(); + list.add(TEST_SUBSCRIPTION); + list.add(TEST_SUBSCRIPTION); + when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY); + when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); + + // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the + // same answer as KeyguardUpdateMonitor. Remove when this is addressed + when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list); + + mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); + + ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = + ArgumentCaptor.forClass( + CarrierTextController.CarrierTextCallbackInfo.class); + + mCarrierTextController.updateCarrierText(); + mTestableLooper.processAllMessages(); + verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); + + assertEquals(TEST_CARRIER + SEPARATOR + TEST_CARRIER, + captor.getValue().carrierText); + } + + @Test + public void testCarrierText_oneDisabledSub() { + reset(mCarrierTextCallback); + List<SubscriptionInfo> list = new ArrayList<>(); + list.add(TEST_SUBSCRIPTION); + list.add(TEST_SUBSCRIPTION); + when(mKeyguardUpdateMonitor.getSimState(anyInt())) + .thenReturn(IccCardConstants.State.READY) + .thenReturn(IccCardConstants.State.NOT_READY); + when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); + + // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the + // same answer as KeyguardUpdateMonitor. Remove when this is addressed + when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list); + + mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); + + ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = + ArgumentCaptor.forClass( + CarrierTextController.CarrierTextCallbackInfo.class); + + mCarrierTextController.updateCarrierText(); + mTestableLooper.processAllMessages(); + verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); + + assertEquals(TEST_CARRIER, + captor.getValue().carrierText); + } + + @Test + public void testCarrierText_firstDisabledSub() { + reset(mCarrierTextCallback); + List<SubscriptionInfo> list = new ArrayList<>(); + list.add(TEST_SUBSCRIPTION); + list.add(TEST_SUBSCRIPTION); + when(mKeyguardUpdateMonitor.getSimState(anyInt())) + .thenReturn(IccCardConstants.State.NOT_READY) + .thenReturn(IccCardConstants.State.READY); + when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); + + // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the + // same answer as KeyguardUpdateMonitor. Remove when this is addressed + when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list); + + mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); + + ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = + ArgumentCaptor.forClass( + CarrierTextController.CarrierTextCallbackInfo.class); + + mCarrierTextController.updateCarrierText(); + mTestableLooper.processAllMessages(); + verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); + + assertEquals(TEST_CARRIER, + captor.getValue().carrierText); + } + + @Test + public void testCarrierText_threeSubsMiddleDisabled() { + reset(mCarrierTextCallback); + List<SubscriptionInfo> list = new ArrayList<>(); + list.add(TEST_SUBSCRIPTION); + list.add(TEST_SUBSCRIPTION); + list.add(TEST_SUBSCRIPTION); + when(mKeyguardUpdateMonitor.getSimState(anyInt())) + .thenReturn(IccCardConstants.State.READY) + .thenReturn(IccCardConstants.State.NOT_READY) + .thenReturn(IccCardConstants.State.READY); + when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); + mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); + + // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the + // same answer as KeyguardUpdateMonitor. Remove when this is addressed + when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list); + + ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = + ArgumentCaptor.forClass( + CarrierTextController.CarrierTextCallbackInfo.class); + + mCarrierTextController.updateCarrierText(); + mTestableLooper.processAllMessages(); + verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); + + assertEquals(TEST_CARRIER + SEPARATOR + TEST_CARRIER, + captor.getValue().carrierText); + } + public static class TestCarrierTextController extends CarrierTextController { private KeyguardUpdateMonitor mKUM; diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java index 40a53571ddf0..8b0ba9448d2b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -16,6 +16,7 @@ package com.android.systemui.bubbles; +import static android.app.Notification.FLAG_BUBBLE; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static com.google.common.truth.Truth.assertThat; @@ -25,6 +26,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -47,15 +49,18 @@ import androidx.test.filters.SmallTest; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationTestHelper; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.collection.NotificationData; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.StatusBarWindowController; import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.HeadsUpManager; import org.junit.Before; import org.junit.Test; @@ -138,7 +143,7 @@ public class BubbleControllerTest extends SysuiTestCase { // Some bubbles want to suppress notifs Notification.BubbleMetadata suppressNotifMetadata = - getBuilder().setSuppressInitialNotification(true).build(); + getBuilder().setSuppressNotification(true).build(); mSuppressNotifRow = mNotificationTestHelper.createBubble(suppressNotifMetadata, FOREGROUND_TEST_PKG_NAME); @@ -146,9 +151,15 @@ public class BubbleControllerTest extends SysuiTestCase { when(mNotificationEntryManager.getNotificationData()).thenReturn(mNotificationData); when(mNotificationData.getChannel(mRow.getEntry().key)).thenReturn(mRow.getEntry().channel); + TestableNotificationInterruptionStateProvider interruptionStateProvider = + new TestableNotificationInterruptionStateProvider(mContext); + interruptionStateProvider.setUpWithPresenter( + mock(NotificationPresenter.class), + mock(HeadsUpManager.class), + mock(NotificationInterruptionStateProvider.HeadsUpSuppressor.class)); mBubbleData = new BubbleData(mContext); mBubbleController = new TestableBubbleController(mContext, mStatusBarWindowController, - mBubbleData, mConfigurationController); + mBubbleData, mConfigurationController, interruptionStateProvider); mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener); mBubbleController.setExpandListener(mBubbleExpandListener); @@ -487,12 +498,27 @@ public class BubbleControllerTest extends SysuiTestCase { verify(mDeleteIntent, times(2)).send(); } + @Test + public void testRemoveBubble_noLongerBubbleAfterUpdate() + throws PendingIntent.CanceledException { + mBubbleController.updateBubble(mRow.getEntry()); + assertTrue(mBubbleController.hasBubbles()); + + mRow.getEntry().notification.getNotification().flags &= ~FLAG_BUBBLE; + mEntryListener.onPreEntryUpdated(mRow.getEntry()); + + assertFalse(mBubbleController.hasBubbles()); + verify(mDeleteIntent, never()).send(); + } + static class TestableBubbleController extends BubbleController { // Let's assume surfaces can be synchronized immediately. TestableBubbleController(Context context, StatusBarWindowController statusBarWindowController, BubbleData data, - ConfigurationController configurationController) { - super(context, statusBarWindowController, data, Runnable::run, configurationController); + ConfigurationController configurationController, + NotificationInterruptionStateProvider interruptionStateProvider) { + super(context, statusBarWindowController, data, Runnable::run, + configurationController, interruptionStateProvider); } @Override @@ -501,6 +527,15 @@ public class BubbleControllerTest extends SysuiTestCase { } } + public static class TestableNotificationInterruptionStateProvider extends + NotificationInterruptionStateProvider { + + public TestableNotificationInterruptionStateProvider(Context context) { + super(context); + mUseHeadsUp = true; + } + } + /** * @return basic {@link android.app.Notification.BubbleMetadata.Builder} */ diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java index 5928a07487d9..161b40979e11 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java @@ -40,6 +40,7 @@ import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import android.testing.TestableResources; +import com.android.settingslib.fuelgauge.Estimate; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.power.PowerUI.WarningsUI; @@ -358,7 +359,7 @@ public class PowerUITest extends SysuiTestCase { @Test public void testRefreshEstimateIfNeeded_onlyQueriesEstimateOnBatteryLevelChangeOrNull() { mPowerUI.start(); - Estimate estimate = new Estimate(BELOW_HYBRID_THRESHOLD, true); + Estimate estimate = new Estimate(BELOW_HYBRID_THRESHOLD, true, 0); when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true); when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS); when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS); @@ -371,21 +372,21 @@ public class PowerUITest extends SysuiTestCase { assertThat(refreshedEstimate.getEstimateMillis()).isEqualTo(BELOW_HYBRID_THRESHOLD); BatteryStateSnapshot snapshot = new BatteryStateSnapshot( BATTERY_LEVEL_10, false, false, 0, BatteryManager.BATTERY_HEALTH_GOOD, - 0, 0, -1, 0, 0, false, true); + 0, 0, -1, 0, 0, 0, false, true); mPowerUI.mLastBatteryStateSnapshot = snapshot; // query again since the estimate was -1 - estimate = new Estimate(BELOW_SEVERE_HYBRID_THRESHOLD, true); + estimate = new Estimate(BELOW_SEVERE_HYBRID_THRESHOLD, true, 0); when(mEnhancedEstimates.getEstimate()).thenReturn(estimate); refreshedEstimate = mPowerUI.refreshEstimateIfNeeded(); assertThat(refreshedEstimate.getEstimateMillis()).isEqualTo(BELOW_SEVERE_HYBRID_THRESHOLD); snapshot = new BatteryStateSnapshot( BATTERY_LEVEL_10, false, false, 0, BatteryManager.BATTERY_HEALTH_GOOD, 0, - 0, BELOW_SEVERE_HYBRID_THRESHOLD, 0, 0, false, true); + 0, BELOW_SEVERE_HYBRID_THRESHOLD, 0, 0, 0, false, true); mPowerUI.mLastBatteryStateSnapshot = snapshot; // Battery level hasn't changed, so we don't query again - estimate = new Estimate(BELOW_HYBRID_THRESHOLD, true); + estimate = new Estimate(BELOW_HYBRID_THRESHOLD, true, 0); when(mEnhancedEstimates.getEstimate()).thenReturn(estimate); refreshedEstimate = mPowerUI.refreshEstimateIfNeeded(); assertThat(refreshedEstimate.getEstimateMillis()).isEqualTo(BELOW_SEVERE_HYBRID_THRESHOLD); @@ -543,13 +544,14 @@ public class PowerUITest extends SysuiTestCase { public boolean mIsBasedOnUsage = true; public boolean mIsHybrid = true; public boolean mIsLowLevelWarningEnabled = true; + private long mAverageTimeToDischargeMillis = Duration.ofHours(24).toMillis(); public BatteryStateSnapshot get() { if (mIsHybrid) { return new BatteryStateSnapshot(mBatteryLevel, mIsPowerSaver, mPlugged, mBucket, mBatteryStatus, mSevereLevelThreshold, mLowLevelThreshold, - mTimeRemainingMillis, mSevereThresholdMillis, mLowThresholdMillis, - mIsBasedOnUsage, mIsLowLevelWarningEnabled); + mTimeRemainingMillis, mAverageTimeToDischargeMillis, mSevereThresholdMillis, + mLowThresholdMillis, mIsBasedOnUsage, mIsLowLevelWarningEnabled); } else { return new BatteryStateSnapshot(mBatteryLevel, mIsPowerSaver, mPlugged, mBucket, mBatteryStatus, mSevereLevelThreshold, mLowLevelThreshold); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java index 8cc1571b925f..e4b90c54d5b3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java @@ -178,7 +178,10 @@ public class NotificationTestHelper { Notification n = createNotification(false /* isGroupSummary */, null /* groupKey */, bubbleMetadata); n.flags |= FLAG_BUBBLE; - return generateRow(n, pkg, UID, USER_HANDLE, 0 /* extraInflationFlags */, IMPORTANCE_HIGH); + ExpandableNotificationRow row = generateRow(n, pkg, UID, USER_HANDLE, + 0 /* extraInflationFlags */, IMPORTANCE_HIGH); + row.getEntry().canBubble = true; + return row; } /** diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index 43bc21b1943f..fb16465d3486 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -681,6 +681,25 @@ public class StatusBarTest extends SysuiTestCase { } @Test + public void testPulseWhileDozingWithDockingReason_suppressWakeUpGesture() { + // Keep track of callback to be able to stop the pulse + final DozeHost.PulseCallback[] pulseCallback = new DozeHost.PulseCallback[1]; + doAnswer(invocation -> { + pulseCallback[0] = invocation.getArgument(0); + return null; + }).when(mDozeScrimController).pulse(any(), anyInt()); + + // Starting a pulse while docking should suppress wakeup gesture + mStatusBar.mDozeServiceHost.pulseWhileDozing(mock(DozeHost.PulseCallback.class), + DozeLog.PULSE_REASON_DOCKING); + verify(mStatusBarWindowView).suppressWakeUpGesture(eq(true)); + + // Ending a pulse should restore wakeup gesture + pulseCallback[0].onPulseFinished(); + verify(mStatusBarWindowView).suppressWakeUpGesture(eq(false)); + } + + @Test public void testSetState_changesIsFullScreenUserSwitcherState() { mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD); assertFalse(mStatusBar.isFullScreenUserSwitcherState()); diff --git a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java index 55a062187bb1..ecea251cc1ac 100644 --- a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java +++ b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java @@ -16,7 +16,9 @@ package com.android.server.contentsuggestions; +import static android.Manifest.permission.BIND_CONTENT_SUGGESTIONS_SERVICE; import static android.Manifest.permission.MANAGE_CONTENT_SUGGESTIONS; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; import android.annotation.NonNull; import android.annotation.Nullable; @@ -92,16 +94,11 @@ public class ContentSuggestionsManagerService extends return MAX_TEMP_SERVICE_DURATION_MS; } - private boolean isCallerRecents(int userId) { - if (mServiceNameResolver.isTemporary(userId)) { - // If a temporary service is set then skip the recents check - return true; - } - return mActivityTaskManagerInternal.isCallerRecents(Binder.getCallingUid()); - } - - private void enforceCallerIsRecents(int userId, String func) { - if (isCallerRecents(userId)) { + private void enforceCaller(int userId, String func) { + Context ctx = getContext(); + if (ctx.checkCallingPermission(BIND_CONTENT_SUGGESTIONS_SERVICE) == PERMISSION_GRANTED + || mServiceNameResolver.isTemporary(userId) + || mActivityTaskManagerInternal.isCallerRecents(Binder.getCallingUid())) { return; } @@ -122,7 +119,7 @@ public class ContentSuggestionsManagerService extends if (imageContextRequestExtras == null) { throw new IllegalArgumentException("Expected non-null imageContextRequestExtras"); } - enforceCallerIsRecents(UserHandle.getCallingUserId(), "provideContextImage"); + enforceCaller(UserHandle.getCallingUserId(), "provideContextImage"); synchronized (mLock) { final ContentSuggestionsPerUserService service = getServiceForUserLocked(userId); @@ -141,7 +138,7 @@ public class ContentSuggestionsManagerService extends int userId, @NonNull SelectionsRequest selectionsRequest, @NonNull ISelectionsCallback selectionsCallback) { - enforceCallerIsRecents(UserHandle.getCallingUserId(), "suggestContentSelections"); + enforceCaller(UserHandle.getCallingUserId(), "suggestContentSelections"); synchronized (mLock) { final ContentSuggestionsPerUserService service = getServiceForUserLocked(userId); @@ -160,7 +157,7 @@ public class ContentSuggestionsManagerService extends int userId, @NonNull ClassificationsRequest classificationsRequest, @NonNull IClassificationsCallback callback) { - enforceCallerIsRecents(UserHandle.getCallingUserId(), "classifyContentSelections"); + enforceCaller(UserHandle.getCallingUserId(), "classifyContentSelections"); synchronized (mLock) { final ContentSuggestionsPerUserService service = getServiceForUserLocked(userId); @@ -177,7 +174,7 @@ public class ContentSuggestionsManagerService extends @Override public void notifyInteraction( int userId, @NonNull String requestId, @NonNull Bundle bundle) { - enforceCallerIsRecents(UserHandle.getCallingUserId(), "notifyInteraction"); + enforceCaller(UserHandle.getCallingUserId(), "notifyInteraction"); synchronized (mLock) { final ContentSuggestionsPerUserService service = getServiceForUserLocked(userId); @@ -194,7 +191,7 @@ public class ContentSuggestionsManagerService extends @Override public void isEnabled(int userId, @NonNull IResultReceiver receiver) throws RemoteException { - enforceCallerIsRecents(UserHandle.getCallingUserId(), "isEnabled"); + enforceCaller(UserHandle.getCallingUserId(), "isEnabled"); boolean isDisabled; synchronized (mLock) { diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index d30a9d2b158e..2d00f298e25e 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -508,13 +508,14 @@ public class AudioService extends IAudioService.Stub // Used to play ringtones outside system_server private volatile IRingtonePlayer mRingtonePlayer; - // Devices for which the volume is fixed and VolumePanel slider should be disabled + // Devices for which the volume is fixed (volume is either max or muted) int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET | AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_HDMI_ARC | AudioSystem.DEVICE_OUT_SPDIF | AudioSystem.DEVICE_OUT_AUX_LINE; + // Devices for which the volume is always max, no volume panel int mFullVolumeDevices = 0; private final boolean mMonitorRotation; @@ -859,6 +860,11 @@ public class AudioService extends IAudioService.Stub mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER; } mHdmiPlaybackClient = mHdmiManager.getPlaybackClient(); + if (mHdmiPlaybackClient != null) { + // not a television: HDMI output will be always at max + mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI; + mFullVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI; + } mHdmiCecSink = false; mHdmiAudioSystemClient = mHdmiManager.getAudioSystemClient(); } @@ -1065,7 +1071,6 @@ public class AudioService extends IAudioService.Stub } if (isPlatformTelevision()) { - mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI; checkAllFixedVolumeDevices(); synchronized (mHdmiClientLock) { if (mHdmiManager != null && mHdmiPlaybackClient != null) { @@ -1656,7 +1661,7 @@ public class AudioService extends IAudioService.Stub flags &= ~AudioManager.FLAG_FIXED_VOLUME; if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) && - ((device & mFixedVolumeDevices) != 0)) { + ((device & mFixedVolumeDevices) != 0)) { flags |= AudioManager.FLAG_FIXED_VOLUME; // Always toggle between max safe volume and 0 for fixed volume devices where safe @@ -1733,8 +1738,9 @@ public class AudioService extends IAudioService.Stub !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) { Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex); mVolumeController.postDisplaySafeVolumeWarning(flags); - } else if (streamState.adjustIndex(direction * step, device, caller) - || streamState.mIsMuted) { + } else if (((device & mFullVolumeDevices) == 0) + && (streamState.adjustIndex(direction * step, device, caller) + || streamState.mIsMuted)) { // Post message to set system volume (it in turn will post a // message to persist). if (streamState.mIsMuted) { @@ -1785,9 +1791,10 @@ public class AudioService extends IAudioService.Stub synchronized (mHdmiClientLock) { if (mHdmiManager != null) { // mHdmiCecSink true => mHdmiPlaybackClient != null - if (mHdmiCecSink && - streamTypeAlias == AudioSystem.STREAM_MUSIC && - oldIndex != newIndex) { + if (mHdmiCecSink + && streamTypeAlias == AudioSystem.STREAM_MUSIC + // vol change on a full volume device + && ((device & mFullVolumeDevices) != 0)) { int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN : KeyEvent.KEYCODE_VOLUME_UP; final long ident = Binder.clearCallingIdentity(); @@ -1814,7 +1821,7 @@ public class AudioService extends IAudioService.Stub } } int index = mStreamStates[streamType].getIndex(device); - sendVolumeUpdate(streamType, oldIndex, index, flags); + sendVolumeUpdate(streamType, oldIndex, index, flags, device); } // Called after a delay when volume down is pressed while muted @@ -1824,7 +1831,7 @@ public class AudioService extends IAudioService.Stub final int device = getDeviceForStream(stream); final int index = mStreamStates[stream].getIndex(device); - sendVolumeUpdate(stream, index, index, flags); + sendVolumeUpdate(stream, index, index, flags, device); } private void setSystemAudioVolume(int oldVolume, int newVolume, int maxVolume, int flags) { @@ -1835,7 +1842,9 @@ public class AudioService extends IAudioService.Stub || mHdmiTvClient == null || oldVolume == newVolume || (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) != 0 - || !mHdmiSystemAudioSupported) return; + || !mHdmiSystemAudioSupported) { + return; + } final long token = Binder.clearCallingIdentity(); try { mHdmiTvClient.setSystemAudioVolume(oldVolume, newVolume, maxVolume); @@ -2149,7 +2158,7 @@ public class AudioService extends IAudioService.Stub Binder.restoreCallingIdentity(identity); } } - sendVolumeUpdate(streamType, oldIndex, index, flags); + sendVolumeUpdate(streamType, oldIndex, index, flags, device); } @@ -2303,18 +2312,22 @@ public class AudioService extends IAudioService.Stub } // UI update and Broadcast Intent - protected void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) { + protected void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags, int device) + { streamType = mStreamVolumeAlias[streamType]; if (streamType == AudioSystem.STREAM_MUSIC) { - flags = updateFlagsForSystemAudio(flags); + flags = updateFlagsForTvPlatform(flags); + if ((device & mFullVolumeDevices) != 0) { + flags &= ~AudioManager.FLAG_SHOW_UI; + } } mVolumeController.postVolumeChanged(streamType, flags); } // If Hdmi-CEC system audio mode is on, we show volume bar only when TV // receives volume notification from Audio Receiver. - private int updateFlagsForSystemAudio(int flags) { + private int updateFlagsForTvPlatform(int flags) { synchronized (mHdmiClientLock) { if (mHdmiTvClient != null) { if (mHdmiSystemAudioSupported && @@ -2328,7 +2341,7 @@ public class AudioService extends IAudioService.Stub // UI update and Broadcast Intent private void sendMasterMuteUpdate(boolean muted, int flags) { - mVolumeController.postMasterMuteChanged(updateFlagsForSystemAudio(flags)); + mVolumeController.postMasterMuteChanged(updateFlagsForTvPlatform(flags)); broadcastMasterMuteStatus(muted); } @@ -2355,6 +2368,9 @@ public class AudioService extends IAudioService.Stub int device, boolean force, String caller) { + if ((device & mFullVolumeDevices) != 0) { + return; + } VolumeStreamState streamState = mStreamStates[streamType]; if (streamState.setIndex(index, device, caller) || force) { @@ -5810,9 +5826,14 @@ public class AudioService extends IAudioService.Stub } //========================================================================================== - // Hdmi Cec system audio mode. - // If Hdmi Cec's system audio mode is on, audio service should send the volume change - // to HdmiControlService so that the audio receiver can handle it. + // Hdmi CEC: + // - System audio mode: + // If Hdmi Cec's system audio mode is on, audio service should send the volume change + // to HdmiControlService so that the audio receiver can handle it. + // - CEC sink: + // OUT_HDMI becomes a "full volume device", i.e. output is always at maximum level + // and volume changes won't be taken into account on this device. Volume adjustments + // are transformed into key events for the HDMI playback client. //========================================================================================== private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback { @@ -5821,8 +5842,18 @@ public class AudioService extends IAudioService.Stub if (mHdmiManager != null) { mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN); // Television devices without CEC service apply software volume on HDMI output - if (isPlatformTelevision() && !mHdmiCecSink) { - mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI; + if (mHdmiCecSink) { + if (DEBUG_VOL) { + Log.d(TAG, "CEC sink: setting HDMI as full vol device"); + } + mFullVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI; + } else { + if (DEBUG_VOL) { + Log.d(TAG, "TV, no CEC: setting HDMI as regular vol device"); + } + // Android TV devices without CEC service apply software volume on + // HDMI output + mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI; } checkAllFixedVolumeDevices(); } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 3e3a4f2fde6c..e5ecd49c67da 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -308,8 +308,7 @@ public class NotificationManagerService extends SystemService { static final String[] DEFAULT_ALLOWED_ADJUSTMENTS = new String[] { Adjustment.KEY_IMPORTANCE, Adjustment.KEY_CONTEXTUAL_ACTIONS, - Adjustment.KEY_TEXT_REPLIES, - Adjustment.KEY_USER_SENTIMENT}; + Adjustment.KEY_TEXT_REPLIES}; static final String[] NON_BLOCKABLE_DEFAULT_ROLES = new String[] { RoleManager.ROLE_DIALER, @@ -7324,7 +7323,7 @@ public class NotificationManagerService extends SystemService { private static final String ATT_USER_SET = "user_set"; // TODO: STOPSHIP (b/127994217) switch to final value when onboarding flow is implemented - private static final String TAG_ALLOWED_ADJUSTMENT_TYPES = "allowed_adjustments_tmp"; + private static final String TAG_ALLOWED_ADJUSTMENT_TYPES = "allowed_adjustments_tmp2"; private static final String ATT_TYPES = "types"; private final Object mLock = new Object(); diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index d0ca861d8d3b..9b4293d484bc 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -256,6 +256,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Whether to allow devices placed in vr headset viewers to have an alternative Home intent. static final boolean ENABLE_VR_HEADSET_HOME_CAPTURE = true; + // must match: config_shortPressOnPowerBehavior in config.xml static final int SHORT_PRESS_POWER_NOTHING = 0; static final int SHORT_PRESS_POWER_GO_TO_SLEEP = 1; static final int SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP = 2; @@ -263,29 +264,34 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final int SHORT_PRESS_POWER_GO_HOME = 4; static final int SHORT_PRESS_POWER_CLOSE_IME_OR_GO_HOME = 5; + // must match: config_LongPressOnPowerBehavior in config.xml static final int LONG_PRESS_POWER_NOTHING = 0; static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1; static final int LONG_PRESS_POWER_SHUT_OFF = 2; static final int LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM = 3; static final int LONG_PRESS_POWER_GO_TO_VOICE_ASSIST = 4; + static final int LONG_PRESS_POWER_ASSISTANT = 5; // Settings.Secure.ASSISTANT + // must match: config_veryLongPresOnPowerBehavior in config.xml static final int VERY_LONG_PRESS_POWER_NOTHING = 0; static final int VERY_LONG_PRESS_POWER_GLOBAL_ACTIONS = 1; + // must match: config_doublePressOnPowerBehavior in config.xml static final int MULTI_PRESS_POWER_NOTHING = 0; static final int MULTI_PRESS_POWER_THEATER_MODE = 1; static final int MULTI_PRESS_POWER_BRIGHTNESS_BOOST = 2; + // must match: config_longPressOnBackBehavior in config.xml static final int LONG_PRESS_BACK_NOTHING = 0; static final int LONG_PRESS_BACK_GO_TO_VOICE_ASSIST = 1; - // These need to match the documentation/constant in - // core/res/res/values/config.xml + // must match: config_longPressOnHomeBehavior in config.xml static final int LONG_PRESS_HOME_NOTHING = 0; static final int LONG_PRESS_HOME_ALL_APPS = 1; static final int LONG_PRESS_HOME_ASSIST = 2; static final int LAST_LONG_PRESS_HOME_BEHAVIOR = LONG_PRESS_HOME_ASSIST; + // must match: config_doubleTapOnHomeBehavior in config.xml static final int DOUBLE_TAP_HOME_NOTHING = 0; static final int DOUBLE_TAP_HOME_RECENT_SYSTEM_UI = 1; @@ -770,6 +776,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { resolver.registerContentObserver(Settings.Secure.getUriFor( Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED), false, this, UserHandle.USER_ALL); + resolver.registerContentObserver(Settings.Global.getUriFor( + Settings.Global.POWER_BUTTON_LONG_PRESS), false, this, + UserHandle.USER_ALL); + resolver.registerContentObserver(Settings.Global.getUriFor( + Settings.Global.POWER_BUTTON_VERY_LONG_PRESS), false, this, + UserHandle.USER_ALL); updateSettings(); } @@ -1195,38 +1207,38 @@ public class PhoneWindowManager implements WindowManagerPolicy { private void powerLongPress() { final int behavior = getResolvedLongPressOnPowerBehavior(); switch (behavior) { - case LONG_PRESS_POWER_NOTHING: - break; - case LONG_PRESS_POWER_GLOBAL_ACTIONS: - mPowerKeyHandled = true; - performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false, - "Power - Long Press - Global Actions"); - showGlobalActionsInternal(); - break; - case LONG_PRESS_POWER_SHUT_OFF: - case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM: - mPowerKeyHandled = true; - performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false, - "Power - Long Press - Shut Off"); - sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); - mWindowManagerFuncs.shutdown(behavior == LONG_PRESS_POWER_SHUT_OFF); - break; - case LONG_PRESS_POWER_GO_TO_VOICE_ASSIST: - mPowerKeyHandled = true; - performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false, - "Power - Long Press - Go To Voice Assist"); - final boolean keyguardActive = mKeyguardDelegate == null - ? false - : mKeyguardDelegate.isShowing(); - if (!keyguardActive) { - Intent intent = new Intent(Intent.ACTION_VOICE_ASSIST); - if (mAllowStartActivityForLongPressOnPowerDuringSetup) { - mContext.startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF); - } else { - startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF); - } - } - break; + case LONG_PRESS_POWER_NOTHING: + break; + case LONG_PRESS_POWER_GLOBAL_ACTIONS: + mPowerKeyHandled = true; + performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false, + "Power - Long Press - Global Actions"); + showGlobalActionsInternal(); + break; + case LONG_PRESS_POWER_SHUT_OFF: + case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM: + mPowerKeyHandled = true; + performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false, + "Power - Long Press - Shut Off"); + sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); + mWindowManagerFuncs.shutdown(behavior == LONG_PRESS_POWER_SHUT_OFF); + break; + case LONG_PRESS_POWER_GO_TO_VOICE_ASSIST: + mPowerKeyHandled = true; + performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false, + "Power - Long Press - Go To Voice Assist"); + // Some devices allow the voice assistant intent during setup (and use that intent + // to launch something else, like Settings). So we explicitly allow that via the + // config_allowStartActivityForLongPressOnPowerInSetup resource in config.xml. + launchVoiceAssist(mAllowStartActivityForLongPressOnPowerDuringSetup); + break; + case LONG_PRESS_POWER_ASSISTANT: + mPowerKeyHandled = true; + performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false, + "Power - Long Press - Go To Assistant"); + final int powerKeyDeviceId = Integer.MIN_VALUE; + launchAssistAction(null, powerKeyDeviceId); + break; } } @@ -1250,13 +1262,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { case LONG_PRESS_BACK_NOTHING: break; case LONG_PRESS_BACK_GO_TO_VOICE_ASSIST: - final boolean keyguardActive = mKeyguardDelegate == null - ? false - : mKeyguardDelegate.isShowing(); - if (!keyguardActive) { - Intent intent = new Intent(Intent.ACTION_VOICE_ASSIST); - startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF); - } + launchVoiceAssist(false /* allowDuringSetup */); break; } } @@ -1999,6 +2005,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { mHasSoftInput = hasSoftInput; updateRotation = true; } + + mLongPressOnPowerBehavior = Settings.Global.getInt(resolver, + Settings.Global.POWER_BUTTON_LONG_PRESS, + mContext.getResources().getInteger( + com.android.internal.R.integer.config_longPressOnPowerBehavior)); + mVeryLongPressOnPowerBehavior = Settings.Global.getInt(resolver, + Settings.Global.POWER_BUTTON_VERY_LONG_PRESS, + mContext.getResources().getInteger( + com.android.internal.R.integer.config_veryLongPressOnPowerBehavior)); } if (updateRotation) { updateRotation(true); @@ -3225,6 +3240,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { return 0; } + // There are several different flavors of "assistant" that can be launched from + // various parts of the UI. + + /** starts ACTION_SEARCH_LONG_PRESS, usually a voice search prompt */ private void launchAssistLongPressAction() { performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false, "Assist - Long Press"); @@ -3246,6 +3265,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + /** Asks the status bar to startAssist(), usually a full "assistant" interface */ private void launchAssistAction(String hint, int deviceId) { sendCloseSystemWindows(SYSTEM_DIALOG_REASON_ASSIST); if (!isUserSetupComplete()) { @@ -3276,12 +3296,30 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + /** Launches ACTION_VOICE_ASSIST. Does nothing on keyguard. */ + private void launchVoiceAssist(boolean allowDuringSetup) { + final boolean keyguardActive = mKeyguardDelegate == null + ? false + : mKeyguardDelegate.isShowing(); + if (!keyguardActive) { + Intent intent = new Intent(Intent.ACTION_VOICE_ASSIST); + startActivityAsUser(intent, null, UserHandle.CURRENT_OR_SELF, + allowDuringSetup); + } + + } + private void startActivityAsUser(Intent intent, UserHandle handle) { startActivityAsUser(intent, null, handle); } private void startActivityAsUser(Intent intent, Bundle bundle, UserHandle handle) { - if (isUserSetupComplete()) { + startActivityAsUser(intent, bundle, handle, false /* allowDuringSetup */); + } + + private void startActivityAsUser(Intent intent, Bundle bundle, UserHandle handle, + boolean allowDuringSetup) { + if (allowDuringSetup || isUserSetupComplete()) { mContext.startActivityAsUser(intent, bundle, handle); } else { Slog.i(TAG, "Not starting activity because user setup is in progress: " + intent); @@ -5541,6 +5579,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { return "LONG_PRESS_POWER_SHUT_OFF"; case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM: return "LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM"; + case LONG_PRESS_POWER_GO_TO_VOICE_ASSIST: + return "LONG_PRESS_POWER_GO_TO_VOICE_ASSIST"; + case LONG_PRESS_POWER_ASSISTANT: + return "LONG_PRESS_POWER_ASSISTANT"; default: return Integer.toString(behavior); } diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index 0caeb10177b7..1edb93a0cdb9 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -2563,9 +2563,8 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private static final class ThermalEventListener extends IThermalEventListener.Stub { @Override public void notifyThrottling(Temperature temp) { - StatsLog.write(StatsLog.THERMAL_THROTTLING, temp.getType(), - StatsLog.THERMAL_THROTTLING_STATE_CHANGED__STATE__UNKNOWN, - temp.getValue(), temp.getStatus(), temp.getName()); + StatsLog.write(StatsLog.THERMAL_THROTTLING_SEVERITY_STATE_CHANGED, temp.getType(), + temp.getName(), (int) (temp.getValue() * 10), temp.getStatus()); } } |