Merge "Revert "Update clearData flow for notification settings"" into qt-dev
diff --git a/api/current.txt b/api/current.txt
index 6253dfd..1623bb8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -8988,8 +8988,8 @@
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 12474ce..68a8816 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -156,7 +156,7 @@
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 @@
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 @@
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 @@
*/
/**
+ * 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 @@
}
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 @@
}
/**
+ * 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 01c7587..0000000
--- 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 444ed92..0000000
--- 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/Activity.java b/core/java/android/app/Activity.java
index 86b10b9..0d22f3a 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -773,6 +773,8 @@
private static final int LOG_AM_ON_RESTART_CALLED = 30058;
private static final int LOG_AM_ON_DESTROY_CALLED = 30060;
private static final int LOG_AM_ON_ACTIVITY_RESULT_CALLED = 30062;
+ private static final int LOG_AM_ON_TOP_RESUMED_GAINED_CALLED = 30064;
+ private static final int LOG_AM_ON_TOP_RESUMED_LOST_CALLED = 30065;
private static class ManagedDialog {
Dialog mDialog;
@@ -1840,6 +1842,13 @@
public void onTopResumedActivityChanged(boolean isTopResumedActivity) {
}
+ final void performTopResumedActivityChanged(boolean isTopResumedActivity, String reason) {
+ onTopResumedActivityChanged(isTopResumedActivity);
+
+ writeEventLog(isTopResumedActivity
+ ? LOG_AM_ON_TOP_RESUMED_GAINED_CALLED : LOG_AM_ON_TOP_RESUMED_LOST_CALLED, reason);
+ }
+
void setVoiceInteractor(IVoiceInteractor voiceInteractor) {
if (mVoiceInteractor != null) {
for (Request activeRequest: mVoiceInteractor.getActiveRequests()) {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 474f25b..13add09 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4026,7 +4026,7 @@
r.persistentState = null;
r.setState(ON_RESUME);
- reportTopResumedActivityChanged(r, r.isTopResumedActivity);
+ reportTopResumedActivityChanged(r, r.isTopResumedActivity, "topWhenResuming");
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException("Unable to resume activity "
@@ -4201,7 +4201,7 @@
r.isTopResumedActivity = onTop;
if (r.getLifecycleState() == ON_RESUME) {
- reportTopResumedActivityChanged(r, onTop);
+ reportTopResumedActivityChanged(r, onTop, "topStateChangedWhenResumed");
} else {
if (DEBUG_ORDER) {
Slog.d(TAG, "Won't deliver top position change in state=" + r.getLifecycleState());
@@ -4213,10 +4213,11 @@
* Call {@link Activity#onTopResumedActivityChanged(boolean)} if its top resumed state changed
* since the last report.
*/
- private void reportTopResumedActivityChanged(ActivityClientRecord r, boolean onTop) {
+ private void reportTopResumedActivityChanged(ActivityClientRecord r, boolean onTop,
+ String reason) {
if (r.lastReportedTopResumedState != onTop) {
r.lastReportedTopResumedState = onTop;
- r.activity.onTopResumedActivityChanged(onTop);
+ r.activity.performTopResumedActivityChanged(onTop, reason);
}
}
@@ -4313,7 +4314,7 @@
// Always reporting top resumed position loss when pausing an activity. If necessary, it
// will be restored in performResumeActivity().
- reportTopResumedActivityChanged(r, false /* onTop */);
+ reportTopResumedActivityChanged(r, false /* onTop */, "pausing");
try {
r.activity.mCalled = false;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 0c6c77f..d0361b7 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3165,8 +3165,8 @@
/**
* 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 @@
* 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 78140cf..07ba2c6 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 @@
/**
* 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 @@
* @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 283cea0..613765f 100644
--- a/core/java/android/content/LocusId.java
+++ b/core/java/android/content/LocusId.java
@@ -29,9 +29,8 @@
* 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 0ea5200..1784d8a 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -8447,6 +8447,20 @@
// 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 1f82fa6..41be38a 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -991,8 +991,8 @@
* 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 @@
/**
* 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 6c498c7..9215de1 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -267,6 +267,13 @@
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 83dc39e..ac59101 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -12666,6 +12666,45 @@
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 @@
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 @@
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 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 94e548f..1692051 100644
--- a/core/java/android/view/contentcapture/ContentCaptureContext.java
+++ b/core/java/android/view/contentcapture/ContentCaptureContext.java
@@ -261,6 +261,7 @@
* 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 26454c0..a977073 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -29,7 +29,6 @@
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.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 @@
* }
* </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 @@
/**
* 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 @@
* 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 17a1fb4..210dea1 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -41,8 +41,7 @@
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 @@
}
/**
- * 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 @@
}
/**
- * 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 @@
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 @@
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 @@
}
/**
- * 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 59e867f..8380115 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -200,7 +200,6 @@
private ChooserListAdapter mChooserListAdapter;
private ChooserRowAdapter mChooserRowAdapter;
- private Drawable mChooserRowLayer;
private int mChooserRowServiceSpacing;
/** {@link ChooserActivity#getBaseScore} */
@@ -219,6 +218,8 @@
private static final int SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED = 4;
private static final int LIST_VIEW_UPDATE_MESSAGE = 5;
+ private static final int MAX_LOG_RANK_POSITION = 12;
+
@VisibleForTesting
public static final int LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS = 250;
@@ -466,7 +467,6 @@
.registerPredictionUpdates(this.getMainExecutor(), mAppPredictorCallback);
}
- mChooserRowLayer = getResources().getDrawable(R.drawable.chooser_row_layer_list, null);
mChooserRowServiceSpacing = getResources()
.getDimensionPixelSize(R.dimen.chooser_service_spacing);
@@ -1015,6 +1015,7 @@
// Lower values mean the ranking was better.
int cat = 0;
int value = which;
+ int directTargetAlsoRanked = -1;
HashedStringCache.HashResult directTargetHashed = null;
switch (mChooserListAdapter.getPositionTargetType(which)) {
case ChooserListAdapter.TARGET_CALLER:
@@ -1034,6 +1035,7 @@
target.getComponentName().getPackageName()
+ target.getTitle().toString(),
mMaxHashSaltDays);
+ directTargetAlsoRanked = getRankedPosition((SelectableTargetInfo) targetInfo);
break;
case ChooserListAdapter.TARGET_STANDARD:
cat = MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_STANDARD_TARGET;
@@ -1056,6 +1058,8 @@
targetLogMaker.addTaggedData(
MetricsEvent.FIELD_HASHED_TARGET_SALT_GEN,
directTargetHashed.saltGeneration);
+ targetLogMaker.addTaggedData(MetricsEvent.FIELD_RANKED_POSITION,
+ directTargetAlsoRanked);
}
getMetricsLogger().write(targetLogMaker);
MetricsLogger.action(this, cat, value);
@@ -1074,6 +1078,21 @@
}
}
+ private int getRankedPosition(SelectableTargetInfo targetInfo) {
+ String targetPackageName =
+ targetInfo.getChooserTarget().getComponentName().getPackageName();
+ int maxRankedResults = Math.min(mChooserListAdapter.mDisplayList.size(),
+ MAX_LOG_RANK_POSITION);
+
+ for (int i = 0; i < maxRankedResults; i++) {
+ if (mChooserListAdapter.mDisplayList.get(i)
+ .getResolveInfo().activityInfo.packageName.equals(targetPackageName)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
void queryTargetServices(ChooserListAdapter adapter) {
final PackageManager pm = getPackageManager();
ShortcutManager sm = (ShortcutManager) getSystemService(ShortcutManager.class);
@@ -1931,6 +1950,7 @@
int offset = 0;
int rowsToShow = mChooserRowAdapter.getContentPreviewRowCount()
+ + mChooserRowAdapter.getProfileRowCount()
+ mChooserRowAdapter.getServiceTargetRowCount()
+ mChooserRowAdapter.getCallerAndRankedTargetRowCount();
@@ -1950,7 +1970,7 @@
}
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;
@@ -2426,6 +2446,7 @@
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;
@@ -2481,9 +2502,9 @@
@Override
public int getCount() {
-
return (int) (
getContentPreviewRowCount()
+ + getProfileRowCount()
+ getServiceTargetRowCount()
+ getCallerAndRankedTargetRowCount()
+ Math.ceil(
@@ -2504,6 +2525,10 @@
return 1;
}
+ public int getProfileRowCount() {
+ return mChooserListAdapter.getOtherProfile() == null ? 0 : 1;
+ }
+
public int getCallerAndRankedTargetRowCount() {
return (int) Math.ceil(
((float) mChooserListAdapter.getCallerTargetCount()
@@ -2539,6 +2564,10 @@
return createContentPreviewView(convertView, parent);
}
+ if (viewType == VIEW_TYPE_PROFILE) {
+ return createProfileView(convertView, parent);
+ }
+
if (convertView == null) {
holder = createViewHolder(viewType, parent);
} else {
@@ -2556,6 +2585,10 @@
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);
@@ -2568,7 +2601,7 @@
@Override
public int getViewTypeCount() {
- return 3;
+ return 4;
}
private ViewGroup createContentPreviewView(View convertView, ViewGroup parent) {
@@ -2584,6 +2617,17 @@
(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,
@@ -2702,8 +2746,10 @@
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);
}
@@ -2753,7 +2799,7 @@
}
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 ad1e767..2849f57 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -108,7 +108,7 @@
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 @@
private final PackageMonitor mPackageMonitor = new PackageMonitor() {
@Override public void onSomePackagesChanged() {
mAdapter.handlePackagesChanged();
- if (mProfileView != null) {
- bindProfileView();
- }
+ bindProfileView();
}
@Override
@@ -336,21 +334,7 @@
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 @@
+ (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 @@
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 @@
mRegistered = true;
}
mAdapter.handlePackagesChanged();
- if (mProfileView != null) {
- bindProfileView();
- }
+ bindProfileView();
}
@Override
@@ -1737,9 +1736,7 @@
@Override
protected void onPostExecute(List<ResolvedComponentInfo> sortedComponents) {
processSortedList(sortedComponents);
- if (mProfileView != null) {
- bindProfileView();
- }
+ bindProfileView();
notifyDataSetChanged();
}
};
@@ -2148,7 +2145,7 @@
@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/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
index a7244a7..76826d3 100644
--- a/core/java/com/android/internal/content/FileSystemProvider.java
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -19,7 +19,6 @@
import android.annotation.CallSuper;
import android.annotation.Nullable;
import android.content.ContentResolver;
-import android.content.ContentValues;
import android.content.Intent;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
@@ -266,17 +265,7 @@
if (visibleFolder != null) {
assert (visibleFolder.isDirectory());
- final long token = Binder.clearCallingIdentity();
-
- try {
- final ContentResolver resolver = getContext().getContentResolver();
- final Uri uri = MediaStore.Files.getDirectoryUri("external");
- ContentValues values = new ContentValues();
- values.put(MediaStore.Files.FileColumns.DATA, visibleFolder.getAbsolutePath());
- resolver.insert(uri, values);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ MediaStore.scanFile(getContext(), visibleFolder);
}
}
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 5fee2c9..8f8e4d8 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -48,8 +48,7 @@
void setIconVisibility(String slot, boolean visible);
@UnsupportedAppUsage
void removeIcon(String slot);
- // TODO(b/117478341): support back button change when IME is showing on a external display.
- void setImeWindowStatus(in IBinder token, int vis, int backDisposition,
+ void setImeWindowStatus(int displayId, in IBinder token, int vis, int backDisposition,
boolean showImeSwitcher);
void expandSettingsPanel(String subPanel);
diff --git a/core/java/com/android/internal/util/ContrastColorUtil.java b/core/java/com/android/internal/util/ContrastColorUtil.java
index d037d4b..bf088e0a 100644
--- a/core/java/com/android/internal/util/ContrastColorUtil.java
+++ b/core/java/com/android/internal/util/ContrastColorUtil.java
@@ -455,7 +455,7 @@
* Resolves {@param color} to an actual color if it is {@link Notification#COLOR_DEFAULT}
*/
public static int resolveColor(Context context, int color, boolean defaultBackgroundIsDark) {
- if (color == Notification.COLOR_DEFAULT || defaultBackgroundIsDark) {
+ if (color == Notification.COLOR_DEFAULT) {
int res = defaultBackgroundIsDark
? com.android.internal.R.color.notification_default_color_dark
: com.android.internal.R.color.notification_default_color_light;
diff --git a/core/jni/android_ddm_DdmHandleNativeHeap.cpp b/core/jni/android_ddm_DdmHandleNativeHeap.cpp
index e22f581..076e99d 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 @@
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 @@
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_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp
index 1c247cb..7052ed6 100644
--- a/core/jni/android_hardware_camera2_DngCreator.cpp
+++ b/core/jni/android_hardware_camera2_DngCreator.cpp
@@ -1008,9 +1008,11 @@
double x, double y,
const std::array<float, 6>& distortion,
const float cx, const float cy, const float f,
- int preCorrW, int preCorrH) {
+ const int preCorrW, const int preCorrH, const int xMin, const int yMin) {
undistort(x, y, distortion, cx, cy, f);
- if (x < 0.0 || y < 0.0 || x > preCorrW - 1 || y > preCorrH - 1) {
+ int xMax = xMin + preCorrW - 1;
+ int yMax = yMin + preCorrH - 1;
+ if (x < xMin || y < yMin || x > xMax || y > yMax) {
return false;
}
return true;
@@ -1019,40 +1021,48 @@
static inline bool boxWithinPrecorrectionArray(
int left, int top, int right, int bottom,
const std::array<float, 6>& distortion,
- const float& cx, const float& cy, const float& f,
- const int& preCorrW, const int& preCorrH){
+ const float cx, const float cy, const float f,
+ const int preCorrW, const int preCorrH, const int xMin, const int yMin){
// Top row
- if (!unDistortWithinPreCorrArray(left, top, distortion, cx, cy, f, preCorrW, preCorrH)) {
+ if (!unDistortWithinPreCorrArray(left, top,
+ distortion, cx, cy, f, preCorrW, preCorrH, xMin, yMin)) {
return false;
}
- if (!unDistortWithinPreCorrArray(cx, top, distortion, cx, cy, f, preCorrW, preCorrH)) {
+ if (!unDistortWithinPreCorrArray(cx, top,
+ distortion, cx, cy, f, preCorrW, preCorrH, xMin, yMin)) {
return false;
}
- if (!unDistortWithinPreCorrArray(right, top, distortion, cx, cy, f, preCorrW, preCorrH)) {
+ if (!unDistortWithinPreCorrArray(right, top,
+ distortion, cx, cy, f, preCorrW, preCorrH, xMin, yMin)) {
return false;
}
// Middle row
- if (!unDistortWithinPreCorrArray(left, cy, distortion, cx, cy, f, preCorrW, preCorrH)) {
+ if (!unDistortWithinPreCorrArray(left, cy,
+ distortion, cx, cy, f, preCorrW, preCorrH, xMin, yMin)) {
return false;
}
- if (!unDistortWithinPreCorrArray(right, cy, distortion, cx, cy, f, preCorrW, preCorrH)) {
+ if (!unDistortWithinPreCorrArray(right, cy,
+ distortion, cx, cy, f, preCorrW, preCorrH, xMin, yMin)) {
return false;
}
// Bottom row
- if (!unDistortWithinPreCorrArray(left, bottom, distortion, cx, cy, f, preCorrW, preCorrH)) {
+ if (!unDistortWithinPreCorrArray(left, bottom,
+ distortion, cx, cy, f, preCorrW, preCorrH, xMin, yMin)) {
return false;
}
- if (!unDistortWithinPreCorrArray(cx, bottom, distortion, cx, cy, f, preCorrW, preCorrH)) {
+ if (!unDistortWithinPreCorrArray(cx, bottom,
+ distortion, cx, cy, f, preCorrW, preCorrH, xMin, yMin)) {
return false;
}
- if (!unDistortWithinPreCorrArray(right, bottom, distortion, cx, cy, f, preCorrW, preCorrH)) {
+ if (!unDistortWithinPreCorrArray(right, bottom,
+ distortion, cx, cy, f, preCorrW, preCorrH, xMin, yMin)) {
return false;
}
return true;
@@ -1062,7 +1072,8 @@
double scale/*must be <= 1.0*/,
const std::array<float, 6>& distortion,
const float cx, const float cy, const float f,
- const int preCorrW, const int preCorrH){
+ const int preCorrW, const int preCorrH,
+ const int xMin, const int yMin){
double left = cx * (1.0 - scale);
double right = (preCorrW - 1) * scale + cx * (1.0 - scale);
@@ -1070,14 +1081,14 @@
double bottom = (preCorrH - 1) * scale + cy * (1.0 - scale);
return boxWithinPrecorrectionArray(left, top, right, bottom,
- distortion, cx, cy, f, preCorrW, preCorrH);
+ distortion, cx, cy, f, preCorrW, preCorrH, xMin, yMin);
}
static status_t findPostCorrectionScale(
double stepSize, double minScale,
const std::array<float, 6>& distortion,
const float cx, const float cy, const float f,
- const int preCorrW, const int preCorrH,
+ const int preCorrW, const int preCorrH, const int xMin, const int yMin,
/*out*/ double* outScale) {
if (outScale == nullptr) {
ALOGE("%s: outScale must not be null", __FUNCTION__);
@@ -1086,7 +1097,7 @@
for (double scale = 1.0; scale > minScale; scale -= stepSize) {
if (scaledBoxWithinPrecorrectionArray(
- scale, distortion, cx, cy, f, preCorrW, preCorrH)) {
+ scale, distortion, cx, cy, f, preCorrW, preCorrH, xMin, yMin)) {
*outScale = scale;
return OK;
}
@@ -1100,16 +1111,18 @@
// are sampled within the precorrection array
static void normalizeLensDistortion(
/*inout*/std::array<float, 6>& distortion,
- float cx, float cy, float f, int preCorrW, int preCorrH) {
- ALOGV("%s: distortion [%f, %f, %f, %f, %f, %f], (cx,cy) (%f, %f), f %f, (W,H) (%d, %d)",
+ float cx, float cy, float f, int preCorrW, int preCorrH, int xMin = 0, int yMin = 0) {
+ ALOGV("%s: distortion [%f, %f, %f, %f, %f, %f], (cx,cy) (%f, %f), f %f, (W,H) (%d, %d)"
+ ", (xmin, ymin, xmax, ymax) (%d, %d, %d, %d)",
__FUNCTION__, distortion[0], distortion[1], distortion[2],
distortion[3], distortion[4], distortion[5],
- cx, cy, f, preCorrW, preCorrH);
+ cx, cy, f, preCorrW, preCorrH,
+ xMin, yMin, xMin + preCorrW - 1, yMin + preCorrH - 1);
// Only update distortion coeffients if we can find a good bounding box
double scale = 1.0;
if (OK == findPostCorrectionScale(0.002, 0.5,
- distortion, cx, cy, f, preCorrW, preCorrH,
+ distortion, cx, cy, f, preCorrW, preCorrH, xMin, yMin,
/*out*/&scale)) {
ALOGV("%s: scaling distortion coefficients by %f", __FUNCTION__, scale);
// The formula:
@@ -1216,6 +1229,8 @@
sp<TiffWriter> writer = new TiffWriter();
+ uint32_t preXMin = 0;
+ uint32_t preYMin = 0;
uint32_t preWidth = 0;
uint32_t preHeight = 0;
uint8_t colorFilter = 0;
@@ -1225,6 +1240,8 @@
camera_metadata_entry entry =
characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_IMAGEWIDTH, writer);
+ preXMin = static_cast<uint32_t>(entry.data.i32[0]);
+ preYMin = static_cast<uint32_t>(entry.data.i32[1]);
preWidth = static_cast<uint32_t>(entry.data.i32[2]);
preHeight = static_cast<uint32_t>(entry.data.i32[3]);
@@ -1966,9 +1983,16 @@
distortion[i+1] = entry3.data.f[i];
}
- // TODO b/118690688: deal with the case where RAW size != preCorrSize
if (preWidth == imageWidth && preHeight == imageHeight) {
normalizeLensDistortion(distortion, cx, cy, f, preWidth, preHeight);
+ } else {
+ // image size == pixel array size (contains optical black pixels)
+ // cx/cy is defined in preCorrArray so adding the offset
+ // Also changes default xmin/ymin so that pixels are only
+ // sampled within preCorrection array
+ normalizeLensDistortion(
+ distortion, cx + preXMin, cy + preYMin, f, preWidth, preHeight,
+ preXMin, preYMin);
}
float m_x = std::fmaxf(preWidth-1 - cx, cx);
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 195fe58..69a7c4d 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 @@
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 @@
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 68c62a6..138e24e3 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 0000000..1a24a07
--- /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 9c4717b..b3e94e3 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 a6a0c6e..2f34c94 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 0e94abc0..a853121 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -130,8 +130,10 @@
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 @@
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 @@
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/android/util/HashedStringCacheTest.java b/core/tests/coretests/src/android/util/HashedStringCacheTest.java
index 333db24..2292473 100644
--- a/core/tests/coretests/src/android/util/HashedStringCacheTest.java
+++ b/core/tests/coretests/src/android/util/HashedStringCacheTest.java
@@ -80,6 +80,17 @@
assertThat(cachedResult2.hashedString, is(cachedResult.hashedString));
}
+
+ @Test
+ public void testThatMultipleInputResultInDifferentHash() {
+ HashedStringCache cache = HashedStringCache.getInstance();
+ HashedStringCache.HashResult cachedResult =
+ cache.hashString(mContext, TAG, TEST_STRING, 7);
+ HashedStringCache.HashResult cachedResult2 =
+ cache.hashString(mContext, TAG, "different_test", 7);
+ assertThat(cachedResult2.hashedString, is(not(cachedResult.hashedString)));
+ }
+
@Test
public void testThatZeroDaysResultsInNewHash() {
HashedStringCache cache = HashedStringCache.getInstance();
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 ac039dd..767ec0e 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 @@
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;
@@ -62,9 +63,6 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.function.Function;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -74,7 +72,10 @@
import org.mockito.Mockito;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.List;
+import java.util.function.Function;
/**
* Chooser activity instrumentation tests
@@ -245,7 +246,7 @@
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 -> {
@@ -770,8 +771,6 @@
}
// This test is too long and too slow and should not be taken as an example for future tests.
- // This is necessary because it tests that multiple calls result in the same result but
- // normally a test this long should be broken into smaller tests testing individual components.
@Test
public void testDirectTargetSelectionLogging() throws InterruptedException {
Intent sendIntent = createSendTextIntent();
@@ -785,7 +784,7 @@
MetricsLogger mockLogger = sOverrides.metricsLogger;
ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
// Create direct share target
- List<ChooserTarget> serviceTargets = createDirectShareTargets(1);
+ List<ChooserTarget> serviceTargets = createDirectShareTargets(1, "");
ResolveInfo ri = ResolverDataProvider.createResolveInfo(3, 0);
// Start activity
@@ -808,7 +807,7 @@
// TODO: restructure the tests b/129870719
Thread.sleep(ChooserActivity.LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS);
- assertThat("Chooser should have 3 targets (2apps, 1 direct)",
+ assertThat("Chooser should have 3 targets (2 apps, 1 direct)",
activity.getAdapter().getCount(), is(3));
assertThat("Chooser should have exactly one selectable direct target",
activity.getAdapter().getSelectableServiceTargetCount(), is(1));
@@ -832,20 +831,36 @@
.getAllValues().get(2).getTaggedData(MetricsEvent.FIELD_HASHED_TARGET_NAME);
assertThat("Hash is not predictable but must be obfuscated",
hashedName, is(not(name)));
+ assertThat("The packages shouldn't match for app target and direct target", logMakerCaptor
+ .getAllValues().get(2).getTaggedData(MetricsEvent.FIELD_RANKED_POSITION), is(-1));
+ }
- // Running the same again to check if the hashed name is the same as before.
+ // This test is too long and too slow and should not be taken as an example for future tests.
+ @Test
+ public void testDirectTargetLoggingWithRankedAppTarget() throws InterruptedException {
+ Intent sendIntent = createSendTextIntent();
+ // We need app targets for direct targets to get displayed
+ List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
+ when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
- Intent sendIntent2 = createSendTextIntent();
+ // Set up resources
+ MetricsLogger mockLogger = sOverrides.metricsLogger;
+ ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
+ // Create direct share target
+ List<ChooserTarget> serviceTargets = createDirectShareTargets(1,
+ resolvedComponentInfos.get(0).getResolveInfoAt(0).activityInfo.packageName);
+ ResolveInfo ri = ResolverDataProvider.createResolveInfo(3, 0);
// Start activity
- final ChooserWrapperActivity activity2 = mActivityRule
- .launchActivity(Intent.createChooser(sendIntent2, null));
- waitForIdle();
+ final ChooserWrapperActivity activity = mActivityRule
+ .launchActivity(Intent.createChooser(sendIntent, null));
// Insert the direct share target
InstrumentationRegistry.getInstrumentation().runOnMainSync(
- () -> activity2.getAdapter().addServiceResults(
- activity2.createTestDisplayResolveInfo(sendIntent,
+ () -> activity.getAdapter().addServiceResults(
+ activity.createTestDisplayResolveInfo(sendIntent,
ri,
"testLabel",
"testInfo",
@@ -858,29 +873,89 @@
// TODO: restructure the tests b/129870719
Thread.sleep(ChooserActivity.LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS);
- assertThat("Chooser should have 3 targets (2apps, 1 direct)",
- activity2.getAdapter().getCount(), is(3));
+ assertThat("Chooser should have 3 targets (2 apps, 1 direct)",
+ activity.getAdapter().getCount(), is(3));
assertThat("Chooser should have exactly one selectable direct target",
- activity2.getAdapter().getSelectableServiceTargetCount(), is(1));
+ activity.getAdapter().getSelectableServiceTargetCount(), is(1));
assertThat("The resolver info must match the resolver info used to create the target",
- activity2.getAdapter().getItem(0).getResolveInfo(), is(ri));
+ activity.getAdapter().getItem(0).getResolveInfo(), is(ri));
// Click on the direct target
+ String name = serviceTargets.get(0).getTitle().toString();
onView(withText(name))
.perform(click());
waitForIdle();
- // Currently we're seeing 6 invocations (3 from above, doubled up)
- // 4. ChooserActivity.onCreate()
- // 5. ChooserActivity$ChooserRowAdapter.createContentPreviewView()
- // 6. ChooserActivity.startSelected -- which is the one we're after
- verify(mockLogger, Mockito.times(6)).write(logMakerCaptor.capture());
- assertThat(logMakerCaptor.getAllValues().get(5).getCategory(),
+ // Currently we're seeing 3 invocations
+ // 1. ChooserActivity.onCreate()
+ // 2. ChooserActivity$ChooserRowAdapter.createContentPreviewView()
+ // 3. ChooserActivity.startSelected -- which is the one we're after
+ verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture());
+ assertThat(logMakerCaptor.getAllValues().get(2).getCategory(),
is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET));
- String hashedName2 = (String) logMakerCaptor
- .getAllValues().get(5).getTaggedData(MetricsEvent.FIELD_HASHED_TARGET_NAME);
- assertThat("Hashing the same name should result in the same hashed value",
- hashedName2, is(hashedName));
+ assertThat("The packages should match for app target and direct target", logMakerCaptor
+ .getAllValues().get(2).getTaggedData(MetricsEvent.FIELD_RANKED_POSITION), is(0));
+ }
+
+ // This test is too long and too slow and should not be taken as an example for future tests.
+ @Test
+ public void testDirectTargetLoggingWithAppTargetNotRanked() throws InterruptedException {
+ Intent sendIntent = createSendTextIntent();
+ // We need app targets for direct targets to get displayed
+ List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(15);
+ when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
+
+ // Set up resources
+ MetricsLogger mockLogger = sOverrides.metricsLogger;
+ ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
+ // Create direct share target
+ List<ChooserTarget> serviceTargets = createDirectShareTargets(1,
+ resolvedComponentInfos.get(14).getResolveInfoAt(0).activityInfo.packageName);
+ ResolveInfo ri = ResolverDataProvider.createResolveInfo(16, 0);
+
+ // Start activity
+ final ChooserWrapperActivity activity = mActivityRule
+ .launchActivity(Intent.createChooser(sendIntent, null));
+ // Insert the direct share target
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(
+ () -> activity.getAdapter().addServiceResults(
+ activity.createTestDisplayResolveInfo(sendIntent,
+ ri,
+ "testLabel",
+ "testInfo",
+ sendIntent),
+ serviceTargets,
+ false)
+ );
+ // Thread.sleep shouldn't be a thing in an integration test but it's
+ // necessary here because of the way the code is structured
+ // TODO: restructure the tests b/129870719
+ Thread.sleep(ChooserActivity.LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS);
+
+ assertThat("Chooser should have 20 targets (4 apps, 1 direct, 15 A-Z)",
+ activity.getAdapter().getCount(), is(20));
+ assertThat("Chooser should have exactly one selectable direct target",
+ activity.getAdapter().getSelectableServiceTargetCount(), is(1));
+ assertThat("The resolver info must match the resolver info used to create the target",
+ activity.getAdapter().getItem(0).getResolveInfo(), is(ri));
+
+ // Click on the direct target
+ String name = serviceTargets.get(0).getTitle().toString();
+ onView(withText(name))
+ .perform(click());
+ waitForIdle();
+
+ // Currently we're seeing 3 invocations
+ // 1. ChooserActivity.onCreate()
+ // 2. ChooserActivity$ChooserRowAdapter.createContentPreviewView()
+ // 3. ChooserActivity.startSelected -- which is the one we're after
+ verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture());
+ assertThat(logMakerCaptor.getAllValues().get(2).getCategory(),
+ is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET));
+ assertThat("The packages shouldn't match for app target and direct target", logMakerCaptor
+ .getAllValues().get(2).getTaggedData(MetricsEvent.FIELD_RANKED_POSITION), is(-1));
}
private Intent createSendTextIntent() {
@@ -946,12 +1021,17 @@
return infoList;
}
- private List<ChooserTarget> createDirectShareTargets(int numberOfResults) {
+ private List<ChooserTarget> createDirectShareTargets(int numberOfResults, String packageName) {
Icon icon = Icon.createWithBitmap(createBitmap());
String testTitle = "testTitle";
List<ChooserTarget> targets = new ArrayList<>();
for (int i = 0; i < numberOfResults; i++) {
- ComponentName componentName = ResolverDataProvider.createComponentName(i);
+ ComponentName componentName;
+ if (packageName.isEmpty()) {
+ componentName = ResolverDataProvider.createComponentName(i);
+ } else {
+ componentName = new ComponentName(packageName, packageName + ".class");
+ }
ChooserTarget tempTarget = new ChooserTarget(
testTitle + i,
icon,
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
index fb5c16b..e19ac81 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 @@
/**
* 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 0000000..ae8e1e2
--- /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/res/layout/ongoing_privacy_chip.xml b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
index 49c16be..dce9ce1 100644
--- a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
+++ b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
@@ -21,8 +21,6 @@
android:id="@+id/privacy_chip"
android:layout_height="match_parent"
android:layout_width="wrap_content"
- android:layout_marginLeft="@dimen/ongoing_appops_chip_margin"
- android:layout_marginRight="@dimen/ongoing_appops_chip_margin"
android:layout_gravity="center_vertical|end"
android:gravity="center_vertical"
android:orientation="horizontal"
diff --git a/packages/SystemUI/res/layout/qs_carrier.xml b/packages/SystemUI/res/layout/qs_carrier.xml
index b94a316..8f74806 100644
--- a/packages/SystemUI/res/layout/qs_carrier.xml
+++ b/packages/SystemUI/res/layout/qs_carrier.xml
@@ -19,6 +19,7 @@
android:id="@+id/linear_carrier"
android:layout_width="wrap_content"
android:layout_height="match_parent"
+ android:minWidth="48dp"
android:orientation="horizontal"
android:gravity="center_vertical|start"
android:background="@android:color/transparent"
diff --git a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
index e44fbcf..8878786 100644
--- a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
+++ b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
@@ -18,7 +18,7 @@
<com.android.systemui.qs.PagedTileLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="0dp"
android:layout_weight="1"
android:clipChildren="true"
android:paddingBottom="@dimen/qs_paged_tile_layout_padding_bottom">
diff --git a/packages/SystemUI/res/layout/quick_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
index 29f53a4..79e2dfb 100644
--- a/packages/SystemUI/res/layout/quick_qs_status_icons.xml
+++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
@@ -21,8 +21,8 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/qs_header_top_margin"
android:layout_marginBottom="14dp"
- android:layout_marginStart="@dimen/status_bar_padding_start"
- android:layout_marginEnd="@dimen/status_bar_padding_end"
+ android:paddingStart="@dimen/status_bar_padding_start"
+ android:paddingEnd="@dimen/status_bar_padding_end"
android:layout_below="@id/quick_status_bar_system_icons"
android:clipChildren="false"
android:clipToPadding="false"
diff --git a/packages/SystemUI/res/layout/quick_settings_header_info.xml b/packages/SystemUI/res/layout/quick_settings_header_info.xml
index da640fd..37c6d9f 100644
--- a/packages/SystemUI/res/layout/quick_settings_header_info.xml
+++ b/packages/SystemUI/res/layout/quick_settings_header_info.xml
@@ -19,7 +19,6 @@
android:layout_width="match_parent"
android:layout_height="@dimen/qs_header_tooltip_height"
android:layout_below="@id/quick_status_bar_system_icons"
- android:layout_marginTop="@dimen/qs_header_top_margin"
android:paddingStart="@dimen/status_bar_padding_start"
android:paddingEnd="@dimen/status_bar_padding_end">
@@ -27,7 +26,7 @@
android:id="@+id/long_press_tooltip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="start|bottom"
+ android:layout_gravity="start|center_vertical"
android:alpha="0"
android:text="@string/quick_settings_header_onboarding_text"
android:textAppearance="@style/TextAppearance.QS.TileLabel"
@@ -36,34 +35,48 @@
<LinearLayout
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="start|bottom"
+ android:layout_height="match_parent"
+ android:layout_gravity="start|center_vertical"
android:gravity="center_vertical">
<LinearLayout
android:id="@+id/status_container"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:layout_gravity="start|center_vertical"
android:layout_weight="1"
android:gravity="center_vertical"
- android:alpha="0">
+ android:alpha="0" >
- <ImageView
- android:id="@+id/next_alarm_icon"
- android:layout_width="@dimen/qs_header_alarm_icon_size"
- android:layout_height="@dimen/qs_header_alarm_icon_size"
- android:src="@drawable/stat_sys_alarm"
- android:tint="?android:attr/textColorPrimary"
- android:visibility="gone"/>
-
- <TextView
- android:id="@+id/next_alarm_text"
+ <LinearLayout
+ android:id = "@+id/alarm_container"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/qs_header_alarm_text_margin_start"
- android:textAppearance="@style/TextAppearance.QS.Status"
- android:visibility="gone"/>
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical"
+ android:gravity="center_vertical"
+ android:focusable="true"
+ android:clickable="true">
+
+ <ImageView
+ android:id="@+id/next_alarm_icon"
+ android:layout_width="@dimen/qs_header_alarm_icon_size"
+ android:layout_height="@dimen/qs_header_alarm_icon_size"
+ android:src="@drawable/ic_alarm"
+ android:tint="?android:attr/textColorPrimary"
+ android:contentDescription="@string/accessibility_quick_settings_alarm_set"
+ android:visibility="gone"/>
+
+ <TextView
+ android:id="@+id/next_alarm_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:marqueeRepeatLimit="marquee_forever"
+ android:layout_marginStart="@dimen/qs_header_alarm_text_margin_start"
+ android:textAppearance="@style/TextAppearance.QS.Status"
+ android:visibility="gone"/>
+ </LinearLayout>
<View
android:id="@+id/status_separator"
@@ -71,20 +84,33 @@
android:layout_height="match_parent"
android:visibility="gone"/>
- <ImageView
- android:id="@+id/ringer_mode_icon"
- android:layout_width="@dimen/qs_header_alarm_icon_size"
- android:layout_height="@dimen/qs_header_alarm_icon_size"
- android:tint="?android:attr/textColorPrimary"
- android:visibility="gone"/>
-
- <TextView
- android:id="@+id/ringer_mode_text"
+ <LinearLayout
+ android:id = "@+id/ringer_container"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/qs_header_alarm_text_margin_start"
- android:textAppearance="@style/TextAppearance.QS.Status"
- android:visibility="gone"/>
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical"
+ android:gravity="center_vertical"
+ android:focusable="true"
+ android:clickable="true">
+
+ <ImageView
+ android:id="@+id/ringer_mode_icon"
+ android:layout_width="@dimen/qs_header_alarm_icon_size"
+ android:layout_height="@dimen/qs_header_alarm_icon_size"
+ android:tint="?android:attr/textColorPrimary"
+ android:visibility="gone"/>
+
+ <TextView
+ android:id="@+id/ringer_mode_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:marqueeRepeatLimit="marquee_forever"
+ android:layout_marginStart="@dimen/qs_header_alarm_text_margin_start"
+ android:textAppearance="@style/TextAppearance.QS.Status"
+ android:visibility="gone"/>
+ </LinearLayout>
</LinearLayout>
<View
@@ -93,11 +119,13 @@
android:layout_height="match_parent"
android:layout_weight="1"/>
+
<include layout="@layout/qs_carrier_group"
android:id="@+id/carrier_group"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android_layout_gravity="center vertical|end"/>
+ android:layout_height="match_parent"
+ android:layout_gravity="end|center_vertical"
+ android:focusable="false"/>
</LinearLayout>
</FrameLayout>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index e768939..90e78e8 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -24,8 +24,8 @@
<dimen name="brightness_mirror_height">40dp</dimen>
- <dimen name="qs_tile_margin_top">2dp</dimen>
- <dimen name="qs_header_tooltip_height">24dp</dimen>
+ <dimen name="qs_tile_margin_top">8dp</dimen>
+ <dimen name="qs_tile_margin_vertical">0dp</dimen>
<dimen name="battery_detail_graph_space_top">9dp</dimen>
<dimen name="battery_detail_graph_space_bottom">9dp</dimen>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 5d8b9e6..7d76160 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -437,7 +437,7 @@
<dimen name="qs_tile_padding_bottom">16dp</dimen>
<dimen name="qs_tile_spacing">4dp</dimen>
<dimen name="qs_panel_padding_bottom">0dp</dimen>
- <dimen name="qs_panel_padding_top">30dp</dimen>
+ <dimen name="qs_panel_padding_top">@dimen/qs_header_tooltip_height</dimen>
<dimen name="qs_detail_header_height">56dp</dimen>
<dimen name="qs_detail_header_padding">0dp</dimen>
<dimen name="qs_detail_image_width">56dp</dimen>
@@ -461,8 +461,8 @@
<dimen name="qs_detail_item_icon_width">32dp</dimen>
<dimen name="qs_detail_item_icon_marginStart">0dp</dimen>
<dimen name="qs_detail_item_icon_marginEnd">20dp</dimen>
- <dimen name="qs_header_tooltip_height">18dp</dimen>
- <dimen name="qs_header_alarm_icon_size">18dp</dimen>
+ <dimen name="qs_header_tooltip_height">48dp</dimen>
+ <dimen name="qs_header_alarm_icon_size">@dimen/status_bar_icon_drawing_size</dimen>
<dimen name="qs_header_mobile_icon_size">@dimen/status_bar_icon_drawing_size</dimen>
<dimen name="qs_header_alarm_text_margin_start">6dp</dimen>
<dimen name="qs_header_separator_width">8dp</dimen>
@@ -473,7 +473,7 @@
<dimen name="qs_footer_padding_end">16dp</dimen>
<dimen name="qs_footer_icon_size">16dp</dimen>
<dimen name="qs_paged_tile_layout_padding_bottom">0dp</dimen>
- <dimen name="qs_header_top_margin">12dp</dimen>
+ <dimen name="qs_header_top_margin">15dp</dimen>
<dimen name="qs_notif_collapsed_space">64dp</dimen>
@@ -1031,8 +1031,6 @@
<dimen name="ongoing_appops_dialog_title_size">20sp</dimen>
<!-- Text size for Ongoing App Ops dialog items -->
<dimen name="ongoing_appops_dialog_item_size">16sp</dimen>
- <!-- Side margins around the Ongoing App Ops chip-->
- <dimen name="ongoing_appops_chip_margin">0dp</dimen>
<!-- Height of the Ongoing App Ops chip -->
<dimen name="ongoing_appops_chip_height">32dp</dimen>
<!-- Padding between background of Ongoing App Ops chip and content -->
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
index eca3926..2e9b03c 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
@@ -383,7 +383,7 @@
}
if (TextUtils.isEmpty(displayText) && !airplaneMode) {
- displayText = TextUtils.join(mSeparator, carrierNames);
+ displayText = joinNotEmpty(mSeparator, carrierNames);
}
final CarrierTextCallbackInfo info = new CarrierTextCallbackInfo(
displayText,
@@ -546,6 +546,25 @@
}
}
+ /**
+ * 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/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 94bb1f3..1bd8e0d 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -204,6 +204,11 @@
return false;
}
+ /** Called when the user is performing an assistant invocation action (e.g. Active Edge) */
+ public void onInvocationProgress(int type, float progress) {
+ // intentional no-op, vendor's AssistManager implementation should override if needed.
+ }
+
public void hideAssist() {
mAssistUtils.hideCurrentSession();
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 9d9c88f..744f88d 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 @@
@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 @@
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 @@
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 @@
@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 @@
if (!areBubblesEnabled(mContext)) {
return;
}
- if (shouldAutoBubbleForFlags(mContext, entry) || shouldBubble(entry)) {
+ if (mNotificationInterruptionStateProvider.shouldBubbleUp(entry)) {
// TODO: handle group summaries?
updateShowInShadeForSuppressNotification(entry);
}
@@ -405,7 +409,7 @@
if (!areBubblesEnabled(mContext)) {
return;
}
- if (entry.isBubble() && mNotificationInterruptionStateProvider.shouldBubbleUp(entry)) {
+ if (mNotificationInterruptionStateProvider.shouldBubbleUp(entry)) {
updateBubble(entry);
}
}
@@ -415,8 +419,11 @@
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 @@
}
/**
- * 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/globalactions/GlobalActionsGridLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
index e7878c6..669348e 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
@@ -117,6 +117,7 @@
} else {
parent.addView(v);
}
+ parent.setVisibility(View.VISIBLE);
}
updateSnapPosition();
updateSeparatedButtonSize();
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java
index 9c71ffc..6bc975a 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java
@@ -41,6 +41,21 @@
private static final String TAG = "ListGridLayout";
private int mExpectedCount;
+ // number of rows and columns to use for different numbers of items
+ private final int[][] mConfigs = {
+ // {rows, columns}
+ {0, 0}, // 0 items
+ {1, 1}, // 1 item
+ {1, 2}, // 2 items
+ {1, 3}, // 3 items
+ {2, 2}, // 4 items
+ {2, 3}, // 5 items
+ {2, 3}, // 6 items
+ {3, 3}, // 7 items
+ {3, 3}, // 8 items
+ {3, 3} // 9 items
+ };
+
public ListGridLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@@ -53,19 +68,28 @@
ViewGroup subList = (ViewGroup) getChildAt(i);
if (subList != null) {
subList.removeAllViews();
+ subList.setVisibility(View.GONE);
}
}
}
/**
* Get the parent view associated with the item which should be placed at the given position.
+ * @param index The index of the item.
+ * @param reverseSublists Reverse the order of sublists. Ordinarily, sublists fill from first to
+ * last, whereas setting this to true will fill them last to first.
+ * @param swapRowsAndColumns Swap the order in which rows and columns are filled. By default,
+ * columns fill first, adding one item to each row. Setting this to
+ * true will cause rows to fill first, adding one item to each column.
+ * @return
*/
public ViewGroup getParentView(int index, boolean reverseSublists, boolean swapRowsAndColumns) {
- if (getRowCount() == 0) {
+ if (getRowCount() == 0 || index < 0) {
return null;
}
- int column = getParentViewIndex(index, reverseSublists, swapRowsAndColumns);
- return (ViewGroup) getChildAt(column);
+ int targetIndex = Math.min(index, getMaxElementCount() - 1);
+ int row = getParentViewIndex(targetIndex, reverseSublists, swapRowsAndColumns);
+ return (ViewGroup) getChildAt(row);
}
private int reverseSublistIndex(int index) {
@@ -74,7 +98,6 @@
private int getParentViewIndex(int index, boolean reverseSublists, boolean swapRowsAndColumns) {
int sublistIndex;
- ViewGroup row;
int rows = getRowCount();
if (swapRowsAndColumns) {
sublistIndex = (int) Math.floor(index / rows);
@@ -92,42 +115,31 @@
*/
public void setExpectedCount(int count) {
mExpectedCount = count;
-
- for (int i = 0; i < getChildCount(); i++) {
- if (i <= getColumnCount()) {
- setSublistVisibility(i, true);
- } else {
- setSublistVisibility(i, false);
- }
- }
}
- private void setSublistVisibility(int index, boolean visible) {
- View subList = getChildAt(index);
- if (subList != null) {
- subList.setVisibility(visible ? View.VISIBLE : View.GONE);
+ private int getMaxElementCount() {
+ return mConfigs.length - 1;
+ }
+
+ private int[] getConfig() {
+ if (mExpectedCount < 0) {
+ return mConfigs[0];
}
+ int targetElements = Math.min(getMaxElementCount(), mExpectedCount);
+ return mConfigs[targetElements];
}
/**
* Get the number of rows which will be used to render children.
*/
public int getRowCount() {
- // special case for 3 to use a single row
- if (mExpectedCount == 3) {
- return 1;
- }
- return (int) Math.round(Math.sqrt(mExpectedCount));
+ return getConfig()[0];
}
/**
* Get the number of columns which will be used to render children.
*/
public int getColumnCount() {
- // special case for 3 to use a single row
- if (mExpectedCount == 3) {
- return 3;
- }
- return (int) Math.ceil(Math.sqrt(mExpectedCount));
+ return getConfig()[1];
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 6af7ac4..d363622 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -66,8 +66,6 @@
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IKeyguardDrawnCallback;
import com.android.internal.policy.IKeyguardExitCallback;
@@ -362,7 +360,6 @@
private boolean mWakeAndUnlocking;
private IKeyguardDrawnCallback mDrawnCallback;
- private boolean mLockWhenSimRemoved;
private CharSequence mCustomMessage;
KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
@@ -465,7 +462,6 @@
if (simState == ABSENT) {
// MVNO SIMs can become transiently NOT_READY when switching networks,
// so we should only lock when they are ABSENT.
- onSimAbsentLocked();
if (simWasLocked) {
if (DEBUG_SIM_STATES) Log.d(TAG, "SIM moved to ABSENT when the "
+ "previous state was locked. Reset the state.");
@@ -498,7 +494,6 @@
+ "show permanently disabled message in lockscreen.");
resetStateLocked();
}
- onSimAbsentLocked();
}
break;
case READY:
@@ -509,7 +504,6 @@
+ "previous state was locked. Reset the state.");
resetStateLocked();
}
- mLockWhenSimRemoved = true;
}
break;
default:
@@ -518,18 +512,6 @@
}
}
- private void onSimAbsentLocked() {
- if (isSecure() && mLockWhenSimRemoved && !mShuttingDown) {
- mLockWhenSimRemoved = false;
- MetricsLogger.action(mContext,
- MetricsProto.MetricsEvent.ACTION_LOCK_BECAUSE_SIM_REMOVED, mShowing);
- if (!mShowing) {
- Log.i(TAG, "SIM removed, showing keyguard");
- doKeyguardLocked(null);
- }
- }
- }
-
@Override
public void onBiometricAuthFailed(BiometricSourceType biometricSourceType) {
final int currentUser = KeyguardUpdateMonitor.getCurrentUser();
diff --git a/packages/SystemUI/src/com/android/systemui/power/BatteryStateSnapshot.kt b/packages/SystemUI/src/com/android/systemui/power/BatteryStateSnapshot.kt
index 02ad0f1..f73bc93 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 @@
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 @@
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 a879227..3b46478 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 bfb809e..9b1f23a 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 dca0d45..0000000
--- 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 25d6d94..b57c053 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.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 @@
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 @@
return estimate;
}
return new Estimate(mLastBatteryStateSnapshot.getTimeRemainingMillis(),
- mLastBatteryStateSnapshot.isBasedOnUsage());
+ mLastBatteryStateSnapshot.isBasedOnUsage(),
+ mLastBatteryStateSnapshot.getAverageTimeToDischargeMillis());
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index ebc3a6a..e22a21a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -63,6 +63,7 @@
private int mLayoutDirection;
private int mHorizontalClipBound;
private final Rect mClippingRect;
+ private int mLastMaxHeight = -1;
public PagedTileLayout(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -303,8 +304,11 @@
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int nTiles = mTiles.size();
- if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
+ // If we have no reason to recalculate the number of rows, skip this step. In particular,
+ // if the height passed by its parent is the same as the last time, we try not to remeasure.
+ if (mDistributeTiles || mLastMaxHeight != MeasureSpec.getSize(heightMeasureSpec)) {
+ mLastMaxHeight = MeasureSpec.getSize(heightMeasureSpec);
// Only change the pages if the number of rows or columns (from updateResources) has
// changed or the tiles have changed
if (mPages.get(0).updateMaxRows(heightMeasureSpec, nTiles) || mDistributeTiles) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java b/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java
index 7de8b74..e352b58 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java
@@ -19,6 +19,8 @@
import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
import android.content.Context;
+import android.content.Intent;
+import android.provider.Settings;
import android.telephony.SubscriptionManager;
import android.util.AttributeSet;
import android.util.Log;
@@ -30,6 +32,7 @@
import com.android.keyguard.CarrierTextController;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.policy.NetworkController;
import javax.inject.Inject;
@@ -40,7 +43,7 @@
*/
public class QSCarrierGroup extends LinearLayout implements
CarrierTextController.CarrierTextCallback,
- NetworkController.SignalCallback {
+ NetworkController.SignalCallback, View.OnClickListener {
private static final String TAG = "QSCarrierGroup";
/**
@@ -53,20 +56,29 @@
private QSCarrier[] mCarrierGroups = new QSCarrier[SIM_SLOTS];
private final CellSignalState[] mInfos = new CellSignalState[SIM_SLOTS];
private CarrierTextController mCarrierTextController;
+ private ActivityStarter mActivityStarter;
private boolean mListening;
@Inject
public QSCarrierGroup(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
- NetworkController networkController) {
+ NetworkController networkController, ActivityStarter activityStarter) {
super(context, attrs);
mNetworkController = networkController;
+ mActivityStarter = activityStarter;
}
@VisibleForTesting
public QSCarrierGroup(Context context, AttributeSet attrs) {
this(context, attrs,
- Dependency.get(NetworkController.class));
+ Dependency.get(NetworkController.class),
+ Dependency.get(ActivityStarter.class));
+ }
+
+ @Override
+ public void onClick(View v) {
+ mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
+ Settings.ACTION_WIRELESS_SETTINGS), 0);
}
@Override
@@ -82,6 +94,7 @@
for (int i = 0; i < SIM_SLOTS; i++) {
mInfos[i] = new CellSignalState();
+ mCarrierGroups[i].setOnClickListener(this);
}
CharSequence separator = mContext.getString(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index dbd3042..f0413cd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -103,7 +103,9 @@
if (navBelow) {
maxQs -= getResources().getDimensionPixelSize(R.dimen.navigation_bar_height);
}
- mQSPanel.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(maxQs, MeasureSpec.AT_MOST));
+ // Measure with EXACTLY. That way, PagedTileLayout will only use excess height and will be
+ // measured last, after other views and padding is accounted for.
+ mQSPanel.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(maxQs, MeasureSpec.EXACTLY));
int width = mQSPanel.getMeasuredWidth();
int height = layoutParams.topMargin + layoutParams.bottomMargin
+ mQSPanel.getMeasuredHeight() + getPaddingBottom();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index d6e0306..fcaf981 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -128,6 +128,24 @@
addView(mDivider);
}
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ // We want all the logic of LinearLayout#onMeasure, and for it to assign the excess space
+ // not used by the other children to PagedTileLayout. However, in this case, LinearLayout
+ // assumes that PagedTileLayout would use all the excess space. This is not the case as
+ // PagedTileLayout height is quantized (because it shows a certain number of rows).
+ // Therefore, after everything is measured, we need to make sure that we add up the correct
+ // total height
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ int height = getPaddingBottom() + getPaddingTop();
+ int numChildren = getChildCount();
+ for (int i = 0; i < numChildren; i++) {
+ View child = getChildAt(i);
+ if (child.getVisibility() != View.GONE) height += child.getMeasuredHeight();
+ }
+ setMeasuredDimension(getMeasuredWidth(), height);
+ }
+
public View getDivider() {
return mDivider;
}
@@ -282,6 +300,7 @@
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mFooter.onConfigurationChanged();
+ updateResources();
updateBrightnessMirror();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index d789821..2e3065a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -35,6 +35,7 @@
import android.os.Handler;
import android.os.Looper;
import android.provider.AlarmClock;
+import android.provider.Settings;
import android.service.notification.ZenModeConfig;
import android.text.format.DateUtils;
import android.util.AttributeSet;
@@ -133,9 +134,11 @@
private ImageView mNextAlarmIcon;
/** {@link TextView} containing the actual text indicating when the next alarm will go off. */
private TextView mNextAlarmTextView;
+ private View mNextAlarmContainer;
private View mStatusSeparator;
private ImageView mRingerModeIcon;
private TextView mRingerModeTextView;
+ private View mRingerContainer;
private Clock mClockView;
private DateView mDateView;
private OngoingPrivacyChip mPrivacyChip;
@@ -203,10 +206,14 @@
mStatusSeparator = findViewById(R.id.status_separator);
mNextAlarmIcon = findViewById(R.id.next_alarm_icon);
mNextAlarmTextView = findViewById(R.id.next_alarm_text);
+ mNextAlarmContainer = findViewById(R.id.alarm_container);
+ mNextAlarmContainer.setOnClickListener(this::onClick);
mRingerModeIcon = findViewById(R.id.ringer_mode_icon);
mRingerModeTextView = findViewById(R.id.ringer_mode_text);
+ mRingerContainer = findViewById(R.id.ringer_container);
+ mRingerContainer.setOnClickListener(this::onClick);
mPrivacyChip = findViewById(R.id.privacy_chip);
- mPrivacyChip.setOnClickListener(this);
+ mPrivacyChip.setOnClickListener(this::onClick);
mCarrierGroup = findViewById(R.id.carrier_group);
@@ -236,6 +243,8 @@
// QS will always show the estimate, and BatteryMeterView handles the case where
// it's unavailable or charging
mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE);
+ mRingerModeTextView.setSelected(true);
+ mNextAlarmTextView.setSelected(true);
}
private List<String> getIgnoredIconSlots() {
@@ -285,11 +294,11 @@
if (!ZenModeConfig.isZenOverridingRinger(mZenController.getZen(),
mZenController.getConsolidatedPolicy())) {
if (mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
- mRingerModeIcon.setImageResource(R.drawable.stat_sys_ringer_vibrate);
+ mRingerModeIcon.setImageResource(R.drawable.ic_volume_ringer_vibrate);
mRingerModeTextView.setText(R.string.qs_status_phone_vibrate);
ringerVisible = true;
} else if (mRingerMode == AudioManager.RINGER_MODE_SILENT) {
- mRingerModeIcon.setImageResource(R.drawable.stat_sys_ringer_silent);
+ mRingerModeIcon.setImageResource(R.drawable.ic_volume_ringer_mute);
mRingerModeTextView.setText(R.string.qs_status_phone_muted);
ringerVisible = true;
}
@@ -546,7 +555,7 @@
@Override
public void onClick(View v) {
- if (v == mClockView) {
+ if (v == mClockView || v == mNextAlarmContainer) {
mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
AlarmClock.ACTION_SHOW_ALARMS),0);
} else if (v == mPrivacyChip) {
@@ -561,6 +570,9 @@
new Intent(Intent.ACTION_REVIEW_ONGOING_PERMISSION_USAGE), 0);
mHost.collapsePanels();
});
+ } else if (v == mRingerContainer) {
+ mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
+ Settings.ACTION_SOUND_SETTINGS), 0);
}
}
@@ -573,7 +585,6 @@
@Override
public void onZenChanged(int zen) {
updateStatusText();
-
}
@Override
@@ -731,8 +742,10 @@
public void setMargins(int sideMargins) {
for (int i = 0; i < getChildCount(); i++) {
View v = getChildAt(i);
+ // Prevents these views from getting set a margin.
+ // The Icon views all have the same padding set in XML to be aligned.
if (v == mSystemIconsView || v == mQuickQsStatusIcons || v == mHeaderQsPanel
- || v == mPrivacyChip) {
+ || v == mHeaderTextContainerView) {
continue;
}
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) v.getLayoutParams();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index 1dd729d..8aacd72 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -137,7 +137,8 @@
* @param tilesCount Upper limit on the number of tiles to show. to prevent empty rows.
*/
public boolean updateMaxRows(int heightMeasureSpec, int tilesCount) {
- final int availableHeight = MeasureSpec.getSize(heightMeasureSpec) - mCellMarginTop;
+ final int availableHeight = MeasureSpec.getSize(heightMeasureSpec) - mCellMarginTop
+ + mCellMarginVertical;
final int previousRows = mRows;
mRows = availableHeight / (mCellHeight + mCellMarginVertical);
if (mRows >= mMaxAllowedRows) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
index 8d2f895..f26a94f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
@@ -81,6 +81,7 @@
state.icon = mIcon;
state.expandedAccessibilityClassName = Switch.class.getName();
state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+ state.showRippleEffect = false;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 2f99cf3..d584959 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -18,7 +18,10 @@
import static android.app.StatusBarManager.DISABLE2_NONE;
import static android.app.StatusBarManager.DISABLE_NONE;
+import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT;
+import static android.inputmethodservice.InputMethodService.IME_INVISIBLE;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
import static com.android.systemui.statusbar.phone.StatusBar.ONLY_CORE_APPS;
@@ -40,6 +43,7 @@
import android.os.Message;
import android.util.Pair;
import android.util.SparseArray;
+import android.view.inputmethod.InputMethodSystemProperty;
import androidx.annotation.VisibleForTesting;
@@ -127,6 +131,11 @@
private Handler mHandler = new H(Looper.getMainLooper());
/** A map of display id - disable flag pair */
private SparseArray<Pair<Integer, Integer>> mDisplayDisabled = new SparseArray<>();
+ /**
+ * The last ID of the display where IME window for which we received setImeWindowStatus
+ * event.
+ */
+ private int mLastUpdatedImeDisplayId = INVALID_DISPLAY;
/**
* These methods are called back on the main thread.
@@ -785,6 +794,32 @@
}
}
+ private void handleShowImeButton(int displayId, IBinder token, int vis, int backDisposition,
+ boolean showImeSwitcher) {
+ if (displayId == INVALID_DISPLAY) return;
+
+ if (!InputMethodSystemProperty.MULTI_CLIENT_IME_ENABLED
+ && mLastUpdatedImeDisplayId != displayId
+ && mLastUpdatedImeDisplayId != INVALID_DISPLAY) {
+ // Set previous NavBar's IME window status as invisible when IME
+ // window switched to another display for single-session IME case.
+ sendImeInvisibleStatusForPrevNavBar();
+ }
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ mCallbacks.get(i).setImeWindowStatus(displayId, token, vis, backDisposition,
+ showImeSwitcher);
+ }
+ mLastUpdatedImeDisplayId = displayId;
+ }
+
+ private void sendImeInvisibleStatusForPrevNavBar() {
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ mCallbacks.get(i).setImeWindowStatus(mLastUpdatedImeDisplayId,
+ null /* token */, IME_INVISIBLE, BACK_DISPOSITION_DEFAULT,
+ false /* showImeSwitcher */);
+ }
+ }
+
private final class H extends Handler {
private H(Looper l) {
super(l);
@@ -852,10 +887,9 @@
break;
case MSG_SHOW_IME_BUTTON:
args = (SomeArgs) msg.obj;
- for (int i = 0; i < mCallbacks.size(); i++) {
- mCallbacks.get(i).setImeWindowStatus(args.argi1, (IBinder) args.arg1,
- args.argi2, args.argi3, args.argi4 != 0 /* showImeSwitcher */);
- }
+ handleShowImeButton(args.argi1 /* displayId */, (IBinder) args.arg1 /* token */,
+ args.argi2 /* vis */, args.argi3 /* backDisposition */,
+ args.argi4 != 0 /* showImeSwitcher */);
break;
case MSG_SHOW_RECENT_APPS:
for (int i = 0; i < mCallbacks.size(); i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
index 2da6824..6adaa0d 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 @@
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 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 059c3f6..926d4b6 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 @@
* @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 @@
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 cb64f10..5b464a9 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 @@
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 @@
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 @@
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/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 4d2b56c..6c1a4fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -1063,4 +1063,9 @@
context.getSystemService(WindowManager.class).addView(navigationBarView, lp);
return navigationBarView;
}
+
+ @VisibleForTesting
+ int getNavigationIconHints() {
+ return mNavigationIconHints;
+ }
}
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 57b2ee9..2207e04 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 @@
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 a381bbc..3f33ba6 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 @@
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 @@
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 28db28c..44996ac 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 @@
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 @@
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 273fa55..fde1455 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 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 df534d7..9f91a17 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
+ @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 40a5357..8b0ba94 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.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 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 @@
// 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 @@
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 @@
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 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/globalactions/ListGridLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/ListGridLayoutTest.java
new file mode 100644
index 0000000..26f1de8
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/ListGridLayoutTest.java
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.globalactions;
+
+import static junit.framework.Assert.assertEquals;
+
+import android.testing.AndroidTestingRunner;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link ListGridLayout}.
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class ListGridLayoutTest extends SysuiTestCase {
+
+ private ListGridLayout mListGridLayout;
+
+ @Before
+ public void setUp() throws Exception {
+ GlobalActionsGridLayout globalActions = (GlobalActionsGridLayout)
+ LayoutInflater.from(mContext).inflate(R.layout.global_actions_grid, null);
+ mListGridLayout = globalActions.getListView();
+ }
+
+ @Test
+ public void testInflation() {
+ assertEquals(3, mListGridLayout.getChildCount());
+ }
+
+ @Test
+ public void testGetRowCount() {
+ // above expected range
+ mListGridLayout.setExpectedCount(99);
+ assertEquals(3, mListGridLayout.getRowCount());
+
+ mListGridLayout.setExpectedCount(9);
+ assertEquals(3, mListGridLayout.getRowCount());
+ mListGridLayout.setExpectedCount(8);
+ assertEquals(3, mListGridLayout.getRowCount());
+ mListGridLayout.setExpectedCount(7);
+ assertEquals(3, mListGridLayout.getRowCount());
+ mListGridLayout.setExpectedCount(6);
+ assertEquals(2, mListGridLayout.getRowCount());
+ mListGridLayout.setExpectedCount(5);
+ assertEquals(2, mListGridLayout.getRowCount());
+ mListGridLayout.setExpectedCount(4);
+ assertEquals(2, mListGridLayout.getRowCount());
+ mListGridLayout.setExpectedCount(3);
+ assertEquals(1, mListGridLayout.getRowCount());
+ mListGridLayout.setExpectedCount(2);
+ assertEquals(1, mListGridLayout.getRowCount());
+ mListGridLayout.setExpectedCount(1);
+ assertEquals(1, mListGridLayout.getRowCount());
+ mListGridLayout.setExpectedCount(0);
+ assertEquals(0, mListGridLayout.getRowCount());
+
+ // below expected range
+ mListGridLayout.setExpectedCount(-1);
+ assertEquals(0, mListGridLayout.getRowCount());
+ }
+
+ @Test
+ public void testGetColumnCount() {
+ // above expected range
+ mListGridLayout.setExpectedCount(99);
+
+ assertEquals(3, mListGridLayout.getColumnCount());
+ mListGridLayout.setExpectedCount(9);
+ assertEquals(3, mListGridLayout.getColumnCount());
+ mListGridLayout.setExpectedCount(8);
+ assertEquals(3, mListGridLayout.getColumnCount());
+ mListGridLayout.setExpectedCount(7);
+ assertEquals(3, mListGridLayout.getColumnCount());
+ mListGridLayout.setExpectedCount(6);
+ assertEquals(3, mListGridLayout.getColumnCount());
+ mListGridLayout.setExpectedCount(5);
+ assertEquals(3, mListGridLayout.getColumnCount());
+ mListGridLayout.setExpectedCount(4);
+ assertEquals(2, mListGridLayout.getColumnCount());
+ mListGridLayout.setExpectedCount(3);
+ assertEquals(3, mListGridLayout.getColumnCount());
+ mListGridLayout.setExpectedCount(2);
+ assertEquals(2, mListGridLayout.getColumnCount());
+ mListGridLayout.setExpectedCount(1);
+ assertEquals(1, mListGridLayout.getColumnCount());
+ mListGridLayout.setExpectedCount(0);
+ assertEquals(0, mListGridLayout.getColumnCount());
+
+ // below expected range
+ mListGridLayout.setExpectedCount(-1);
+ assertEquals(0, mListGridLayout.getColumnCount());
+ }
+
+ @Test
+ public void testGetParentView_default() {
+ mListGridLayout.setExpectedCount(9);
+
+ // below valid range
+ assertEquals(null,
+ mListGridLayout.getParentView(-1, false, false));
+
+ assertEquals(mListGridLayout.getChildAt(0),
+ mListGridLayout.getParentView(0, false, false));
+ assertEquals(mListGridLayout.getChildAt(1),
+ mListGridLayout.getParentView(1, false, false));
+ assertEquals(mListGridLayout.getChildAt(2),
+ mListGridLayout.getParentView(2, false, false));
+ assertEquals(mListGridLayout.getChildAt(0),
+ mListGridLayout.getParentView(3, false, false));
+ assertEquals(mListGridLayout.getChildAt(1),
+ mListGridLayout.getParentView(4, false, false));
+ assertEquals(mListGridLayout.getChildAt(2),
+ mListGridLayout.getParentView(5, false, false));
+ assertEquals(mListGridLayout.getChildAt(0),
+ mListGridLayout.getParentView(6, false, false));
+ assertEquals(mListGridLayout.getChildAt(1),
+ mListGridLayout.getParentView(7, false, false));
+ assertEquals(mListGridLayout.getChildAt(2),
+ mListGridLayout.getParentView(8, false, false));
+
+ // above valid range
+ assertEquals(mListGridLayout.getChildAt(2),
+ mListGridLayout.getParentView(9, false, false));
+ }
+
+ @Test
+ public void testGetParentView_reverseSublists() {
+ mListGridLayout.setExpectedCount(9);
+
+ // below valid range
+ assertEquals(null,
+ mListGridLayout.getParentView(-1, true, false));
+
+ assertEquals(mListGridLayout.getChildAt(2),
+ mListGridLayout.getParentView(0, true, false));
+ assertEquals(mListGridLayout.getChildAt(1),
+ mListGridLayout.getParentView(1, true, false));
+ assertEquals(mListGridLayout.getChildAt(0),
+ mListGridLayout.getParentView(2, true, false));
+ assertEquals(mListGridLayout.getChildAt(2),
+ mListGridLayout.getParentView(3, true, false));
+ assertEquals(mListGridLayout.getChildAt(1),
+ mListGridLayout.getParentView(4, true, false));
+ assertEquals(mListGridLayout.getChildAt(0),
+ mListGridLayout.getParentView(5, true, false));
+ assertEquals(mListGridLayout.getChildAt(2),
+ mListGridLayout.getParentView(6, true, false));
+ assertEquals(mListGridLayout.getChildAt(1),
+ mListGridLayout.getParentView(7, true, false));
+ assertEquals(mListGridLayout.getChildAt(0),
+ mListGridLayout.getParentView(8, true, false));
+
+ // above valid range
+ assertEquals(mListGridLayout.getChildAt(0),
+ mListGridLayout.getParentView(9, true, false));
+ }
+
+ @Test
+ public void testGetParentView_swapRowsAndColumns() {
+ mListGridLayout.setExpectedCount(9);
+
+ // below valid range
+ assertEquals(null,
+ mListGridLayout.getParentView(-1, false, true));
+
+ assertEquals(mListGridLayout.getChildAt(0),
+ mListGridLayout.getParentView(0, false, true));
+ assertEquals(mListGridLayout.getChildAt(0),
+ mListGridLayout.getParentView(1, false, true));
+ assertEquals(mListGridLayout.getChildAt(0),
+ mListGridLayout.getParentView(2, false, true));
+ assertEquals(mListGridLayout.getChildAt(1),
+ mListGridLayout.getParentView(3, false, true));
+ assertEquals(mListGridLayout.getChildAt(1),
+ mListGridLayout.getParentView(4, false, true));
+ assertEquals(mListGridLayout.getChildAt(1),
+ mListGridLayout.getParentView(5, false, true));
+ assertEquals(mListGridLayout.getChildAt(2),
+ mListGridLayout.getParentView(6, false, true));
+ assertEquals(mListGridLayout.getChildAt(2),
+ mListGridLayout.getParentView(7, false, true));
+ assertEquals(mListGridLayout.getChildAt(2),
+ mListGridLayout.getParentView(8, false, true));
+
+ // above valid range
+ assertEquals(mListGridLayout.getChildAt(2),
+ mListGridLayout.getParentView(9, false, true));
+ }
+
+ @Test
+ public void testGetParentView_swapRowsAndColumnsAndReverseSublists() {
+ mListGridLayout.setExpectedCount(9);
+
+ // below valid range
+ assertEquals(null,
+ mListGridLayout.getParentView(-1, true, true));
+
+ assertEquals(mListGridLayout.getChildAt(2),
+ mListGridLayout.getParentView(0, true, true));
+ assertEquals(mListGridLayout.getChildAt(2),
+ mListGridLayout.getParentView(1, true, true));
+ assertEquals(mListGridLayout.getChildAt(2),
+ mListGridLayout.getParentView(2, true, true));
+ assertEquals(mListGridLayout.getChildAt(1),
+ mListGridLayout.getParentView(3, true, true));
+ assertEquals(mListGridLayout.getChildAt(1),
+ mListGridLayout.getParentView(4, true, true));
+ assertEquals(mListGridLayout.getChildAt(1),
+ mListGridLayout.getParentView(5, true, true));
+ assertEquals(mListGridLayout.getChildAt(0),
+ mListGridLayout.getParentView(6, true, true));
+ assertEquals(mListGridLayout.getChildAt(0),
+ mListGridLayout.getParentView(7, true, true));
+ assertEquals(mListGridLayout.getChildAt(0),
+ mListGridLayout.getParentView(8, true, true));
+
+ // above valid range
+ assertEquals(mListGridLayout.getChildAt(0),
+ mListGridLayout.getParentView(9, true, true));
+ }
+
+ @Test
+ public void testRemoveAllItems() {
+ ViewGroup row1 = (ViewGroup) mListGridLayout.getChildAt(0);
+ ViewGroup row2 = (ViewGroup) mListGridLayout.getChildAt(1);
+ ViewGroup row3 = (ViewGroup) mListGridLayout.getChildAt(2);
+ View item1 = new View(mContext, null);
+ View item2 = new View(mContext, null);
+ View item3 = new View(mContext, null);
+
+ row1.addView(item1);
+ row2.addView(item2);
+ row3.addView(item3);
+
+ assertEquals(1, row1.getChildCount());
+ assertEquals(1, row2.getChildCount());
+ assertEquals(1, row3.getChildCount());
+
+ mListGridLayout.removeAllItems();
+
+ assertEquals(0, row1.getChildCount());
+ assertEquals(0, row2.getChildCount());
+ assertEquals(0, row2.getChildCount());
+ }
+}
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 5928a07..161b409 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.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 @@
@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 @@
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 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 8cc1571..e4b90c5 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 @@
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/NavigationBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
index 6a0d61d..3ae57e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
@@ -14,18 +14,38 @@
package com.android.systemui.statusbar.phone;
+import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
+import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
+import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT;
+import static android.inputmethodservice.InputMethodService.IME_VISIBLE;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import android.annotation.LayoutRes;
+import android.annotation.Nullable;
import android.app.Fragment;
+import android.app.FragmentController;
+import android.app.FragmentHostCallback;
import android.content.Context;
+import android.hardware.display.DisplayManagerGlobal;
import android.os.Bundle;
+import android.os.Handler;
import android.os.Looper;
import android.testing.AndroidTestingRunner;
import android.testing.LeakCheck.Tracker;
+import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.view.Display;
+import android.view.DisplayInfo;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
@@ -34,6 +54,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.Dependency;
import com.android.systemui.SysuiBaseFragmentTest;
+import com.android.systemui.SysuiTestableContext;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
@@ -50,9 +71,16 @@
@RunWithLooper()
@SmallTest
public class NavigationBarFragmentTest extends SysuiBaseFragmentTest {
+ private static final int EXTERNAL_DISPLAY_ID = 2;
+ private static final int NAV_BAR_VIEW_ID = 43;
+ private Fragment mFragmentExternalDisplay;
+ private FragmentController mControllerExternalDisplay;
+
+ private SysuiTestableContext mSysuiTestableContextExternal;
private OverviewProxyService mOverviewProxyService =
mDependency.injectMockDependency(OverviewProxyService.class);
+ private CommandQueue mCommandQueue;
private AccessibilityManagerWrapper mAccessibilityWrapper =
new AccessibilityManagerWrapper(mContext) {
Tracker mTracker = mLeakCheck.getTracker("accessibility_manager");
@@ -73,15 +101,51 @@
}
protected void createRootView() {
- mView = new NavigationBarFrame(mContext);
+ mView = new NavigationBarFrame(mSysuiContext);
+ mView.setId(NAV_BAR_VIEW_ID);
}
@Before
- public void setup() {
- mSysuiContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
+ public void setupFragment() throws Exception {
+ setupSysuiDependency();
+ createRootView();
+ TestableLooper.get(this).runWithLooper(() -> {
+ mHandler = new Handler();
+
+ mFragment = instantiate(mSysuiContext, NavigationBarFragment.class.getName(), null);
+ mFragments = FragmentController.createController(
+ new HostCallbacksForExternalDisplay(mSysuiContext));
+ mFragments.attachHost(null);
+ mFragments.getFragmentManager().beginTransaction()
+ .replace(NAV_BAR_VIEW_ID, mFragment)
+ .commit();
+ mControllerExternalDisplay = FragmentController.createController(
+ new HostCallbacksForExternalDisplay(mSysuiTestableContextExternal));
+ mControllerExternalDisplay.attachHost(null);
+ mFragmentExternalDisplay = instantiate(mSysuiTestableContextExternal,
+ NavigationBarFragment.class.getName(), null);
+ mControllerExternalDisplay.getFragmentManager().beginTransaction()
+ .replace(NAV_BAR_VIEW_ID, mFragmentExternalDisplay)
+ .commit();
+ });
+ }
+
+ private void setupSysuiDependency() {
+ mCommandQueue = new CommandQueue(mContext);
+ mSysuiContext.putComponent(CommandQueue.class, mCommandQueue);
mSysuiContext.putComponent(StatusBar.class, mock(StatusBar.class));
mSysuiContext.putComponent(Recents.class, mock(Recents.class));
mSysuiContext.putComponent(Divider.class, mock(Divider.class));
+
+ Display display = new Display(DisplayManagerGlobal.getInstance(), EXTERNAL_DISPLAY_ID,
+ new DisplayInfo(), DEFAULT_DISPLAY_ADJUSTMENTS);
+ mSysuiTestableContextExternal = (SysuiTestableContext) mSysuiContext.createDisplayContext(
+ display);
+ mSysuiTestableContextExternal.putComponent(CommandQueue.class, mCommandQueue);
+ mSysuiTestableContextExternal.putComponent(StatusBar.class, mock(StatusBar.class));
+ mSysuiTestableContextExternal.putComponent(Recents.class, mock(Recents.class));
+ mSysuiTestableContextExternal.putComponent(Divider.class, mock(Divider.class));
+
injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
WindowManager windowManager = mock(WindowManager.class);
Display defaultDisplay = mContext.getSystemService(WindowManager.class).getDefaultDisplay();
@@ -102,15 +166,111 @@
navigationBarFragment.onHomeLongClick(navigationBarFragment.getView());
}
+ @Test
+ public void testSetImeWindowStatusWhenImeSwitchOnDisplay() {
+ // Create default & external NavBar fragment.
+ NavigationBarFragment defaultNavBar = (NavigationBarFragment) mFragment;
+ NavigationBarFragment externalNavBar = (NavigationBarFragment) mFragmentExternalDisplay;
+ mFragments.dispatchCreate();
+ processAllMessages();
+ mFragments.dispatchResume();
+ processAllMessages();
+ mControllerExternalDisplay.dispatchCreate();
+ processAllMessages();
+ mControllerExternalDisplay.dispatchResume();
+ processAllMessages();
+
+ // Set IME window status for default NavBar.
+ mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, null, IME_VISIBLE,
+ BACK_DISPOSITION_DEFAULT, true);
+ Handler.getMain().runWithScissors(() -> { }, 500);
+
+ // Verify IME window state will be updated in default NavBar & external NavBar state reset.
+ assertEquals(NAVIGATION_HINT_BACK_ALT | NAVIGATION_HINT_IME_SHOWN,
+ defaultNavBar.getNavigationIconHints());
+ assertFalse((externalNavBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0);
+ assertFalse((externalNavBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0);
+
+ // Set IME window status for external NavBar.
+ mCommandQueue.setImeWindowStatus(EXTERNAL_DISPLAY_ID, null,
+ IME_VISIBLE, BACK_DISPOSITION_DEFAULT, true);
+ Handler.getMain().runWithScissors(() -> { }, 500);
+
+ // Verify IME window state will be updated in external NavBar & default NavBar state reset.
+ assertEquals(NAVIGATION_HINT_BACK_ALT | NAVIGATION_HINT_IME_SHOWN,
+ externalNavBar.getNavigationIconHints());
+ assertFalse((defaultNavBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0);
+ assertFalse((defaultNavBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0);
+ }
+
@Override
protected Fragment instantiate(Context context, String className, Bundle arguments) {
DeviceProvisionedController deviceProvisionedController =
mock(DeviceProvisionedController.class);
assertNotNull(mAccessibilityWrapper);
- return new NavigationBarFragment(mAccessibilityWrapper,
+ return new NavigationBarFragment(
+ context.getDisplayId() == DEFAULT_DISPLAY ? mAccessibilityWrapper
+ : mock(AccessibilityManagerWrapper.class),
deviceProvisionedController,
new MetricsLogger(),
- new AssistManager(deviceProvisionedController, mContext),
+ mock(AssistManager.class),
mOverviewProxyService);
}
+
+ private class HostCallbacksForExternalDisplay extends
+ FragmentHostCallback<NavigationBarFragmentTest> {
+ private Context mDisplayContext;
+
+ HostCallbacksForExternalDisplay(Context context) {
+ super(context, mHandler, 0);
+ mDisplayContext = context;
+ }
+
+ @Override
+ public NavigationBarFragmentTest onGetHost() {
+ return NavigationBarFragmentTest.this;
+ }
+
+ @Override
+ public Fragment instantiate(Context context, String className, Bundle arguments) {
+ return NavigationBarFragmentTest.this.instantiate(context, className, arguments);
+ }
+
+ @Override
+ public View onFindViewById(int id) {
+ return mView.findViewById(id);
+ }
+
+ @Override
+ public LayoutInflater onGetLayoutInflater() {
+ return new LayoutInflaterWrapper(mDisplayContext);
+ }
+ }
+
+ private static class LayoutInflaterWrapper extends LayoutInflater {
+ protected LayoutInflaterWrapper(Context context) {
+ super(context);
+ }
+
+ @Override
+ public LayoutInflater cloneInContext(Context newContext) {
+ return null;
+ }
+
+ @Override
+ public View inflate(@LayoutRes int resource, @Nullable ViewGroup root,
+ boolean attachToRoot) {
+ NavigationBarView view = mock(NavigationBarView.class);
+ when(view.getDisplay()).thenReturn(mContext.getDisplay());
+ when(view.getBackButton()).thenReturn(mock(ButtonDispatcher.class));
+ when(view.getHomeButton()).thenReturn(mock(ButtonDispatcher.class));
+ when(view.getRecentsButton()).thenReturn(mock(ButtonDispatcher.class));
+ when(view.getAccessibilityButton()).thenReturn(mock(ButtonDispatcher.class));
+ when(view.getRotateSuggestionButton()).thenReturn(mock(RotationContextButton.class));
+ when(view.getBarTransitions()).thenReturn(mock(BarTransitions.class));
+ when(view.getLightTransitionsController()).thenReturn(
+ mock(LightBarTransitionsController.class));
+ return view;
+ }
+ }
}
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 43bc21b..fb16465 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 @@
}
@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 55a0621..ecea251c 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 @@
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 @@
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 @@
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 @@
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 @@
@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 @@
@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/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index e65a4e5..7c2ea3f 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -139,3 +139,8 @@
# The task is being compacted
30063 am_compact (Pid|1|5),(Process Name|3),(Action|3),(BeforeRssTotal|2|2),(BeforeRssFile|2|2),(BeforeRssAnon|2|2),(BeforeRssSwap|2|2),(DeltaRssTotal|2|2),(DeltaRssFile|2|2),(DeltaRssAnon|2|2),(DeltaRssSwap|2|2),(Time|2|3),(LastAction|1|2),(LastActionTimestamp|2|3),(setAdj|1|2),(procState|1|2),(BeforeZRAMFree|2|2),(DeltaZRAMFree|2|2)
+
+# The activity's onTopResumedActivityChanged(true) has been called.
+30064 am_on_top_resumed_gained_called (User|1|5),(Component Name|3),(Reason|3)
+# The activity's onTopResumedActivityChanged(false) has been called.
+30065 am_on_top_resumed_lost_called (User|1|5),(Component Name|3),(Reason|3)
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index d30a9d2..2d00f29 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 @@
// 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 @@
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 @@
}
if (isPlatformTelevision()) {
- mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
checkAllFixedVolumeDevices();
synchronized (mHdmiClientLock) {
if (mHdmiManager != null && mHdmiPlaybackClient != null) {
@@ -1656,7 +1661,7 @@
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 @@
!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 @@
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 @@
}
}
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 @@
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 @@
|| 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 @@
Binder.restoreCallingIdentity(identity);
}
}
- sendVolumeUpdate(streamType, oldIndex, index, flags);
+ sendVolumeUpdate(streamType, oldIndex, index, flags, device);
}
@@ -2303,18 +2312,22 @@
}
// 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 @@
// 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 @@
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 @@
}
//==========================================================================================
- // 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 @@
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/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 3c97c39..c2aade3 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -575,6 +575,12 @@
*/
int mCurTokenDisplayId = INVALID_DISPLAY;
+ /**
+ * The display ID of the input method indicates the fallback display which returned by
+ * {@link #computeImeDisplayIdForTarget}.
+ */
+ private static final int FALLBACK_DISPLAY_ID = DEFAULT_DISPLAY;
+
final ImeDisplayValidator mImeDisplayValidator;
/**
@@ -625,7 +631,8 @@
* currently invisible.
* </dd>
* </dl>
- * <em>Do not update this value outside of setImeWindowStatus.</em>
+ * <em>Do not update this value outside of {@link #setImeWindowStatus(IBinder, int, int)} and
+ * {@link #unbindCurrentMethodLocked()}.</em>
*/
int mImeWindowVis;
@@ -2124,12 +2131,10 @@
*/
static int computeImeDisplayIdForTarget(int displayId, @NonNull ImeDisplayValidator checker) {
if (displayId == DEFAULT_DISPLAY || displayId == INVALID_DISPLAY) {
- // We always assume that the default display id suitable to show the IME window.
- return DEFAULT_DISPLAY;
+ return FALLBACK_DISPLAY_ID;
}
- // Show IME in default display when the display with IME target doesn't support system
- // decorations.
- return checker.displayCanShowIme(displayId) ? displayId : DEFAULT_DISPLAY;
+ // Show IME window on fallback display when the display is not allowed.
+ return checker.displayCanShowIme(displayId) ? displayId : FALLBACK_DISPLAY_ID;
}
@Override
@@ -2198,6 +2203,10 @@
mIWindowManager.removeWindowToken(mCurToken, mCurTokenDisplayId);
} catch (RemoteException e) {
}
+ // Set IME window status as invisible when unbind current method.
+ mImeWindowVis = 0;
+ mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
+ updateSystemUiLocked(mImeWindowVis, mBackDisposition);
mCurToken = null;
mCurTokenDisplayId = INVALID_DISPLAY;
}
@@ -2399,10 +2408,20 @@
@BinderThread
@SuppressWarnings("deprecation")
private void setImeWindowStatus(@NonNull IBinder token, int vis, int backDisposition) {
+ final int topFocusedDisplayId = mWindowManagerInternal.getTopFocusedDisplayId();
+
synchronized (mMethodMap) {
if (!calledWithValidTokenLocked(token)) {
return;
}
+ // Skip update IME status when current token display is not same as focused display.
+ // Note that we still need to update IME status when focusing external display
+ // that does not support system decoration and fallback to show IME on default
+ // display since it is intentional behavior.
+ if (mCurTokenDisplayId != topFocusedDisplayId
+ && mCurTokenDisplayId != FALLBACK_DISPLAY_ID) {
+ return;
+ }
mImeWindowVis = vis;
mBackDisposition = backDisposition;
updateSystemUiLocked(vis, backDisposition);
@@ -2447,7 +2466,8 @@
if (DEBUG) {
Slog.d(TAG, "IME window vis: " + vis
+ " active: " + (vis & InputMethodService.IME_ACTIVE)
- + " inv: " + (vis & InputMethodService.IME_INVISIBLE));
+ + " inv: " + (vis & InputMethodService.IME_INVISIBLE)
+ + " displayId: " + mCurTokenDisplayId);
}
// TODO: Move this clearing calling identity block to setImeWindowStatus after making sure
@@ -2461,7 +2481,7 @@
// mImeWindowVis should be updated before calling shouldShowImeSwitcherLocked().
final boolean needsToShowImeSwitcher = shouldShowImeSwitcherLocked(vis);
if (mStatusBar != null) {
- mStatusBar.setImeWindowStatus(mCurToken, vis, backDisposition,
+ mStatusBar.setImeWindowStatus(mCurTokenDisplayId, mCurToken, vis, backDisposition,
needsToShowImeSwitcher);
}
final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 8578bb7..a349d87 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -248,7 +248,8 @@
scheduleOpTimeOutLocked();
final Intent intent = new Intent().setComponent(job.getServiceComponent());
boolean binding = mContext.bindServiceAsUser(intent, this,
- Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND,
+ Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
+ | Context.BIND_NOT_VISIBLE | Context.BIND_ADJUST_BELOW_PERCEPTIBLE,
new UserHandle(job.getUserId()));
if (!binding) {
if (DEBUG) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 6c11157..2e8e65b 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 @@
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,
@@ -7325,7 +7324,7 @@
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/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 1f5b99c..981e0f5 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -940,13 +940,34 @@
}
}
+ private void applyCustomPolicy(ZenPolicy policy, ZenRule rule) {
+ if (rule.zenMode == NotificationManager.INTERRUPTION_FILTER_NONE) {
+ policy.apply(new ZenPolicy.Builder()
+ .disallowAllSounds()
+ .build());
+ } else if (rule.zenMode
+ == NotificationManager.INTERRUPTION_FILTER_ALARMS) {
+ policy.apply(new ZenPolicy.Builder()
+ .disallowAllSounds()
+ .allowAlarms(true)
+ .allowMedia(true)
+ .build());
+ } else {
+ policy.apply(rule.zenPolicy);
+ }
+ }
+
private void updateConsolidatedPolicy(String reason) {
if (mConfig == null) return;
synchronized (mConfig) {
ZenPolicy policy = new ZenPolicy();
+ if (mConfig.manualRule != null) {
+ applyCustomPolicy(policy, mConfig.manualRule);
+ }
+
for (ZenRule automaticRule : mConfig.automaticRules.values()) {
if (automaticRule.isAutomaticActive()) {
- policy.apply(automaticRule.zenPolicy);
+ applyCustomPolicy(policy, automaticRule);
}
}
Policy newPolicy = mConfig.toNotificationPolicy(policy);
diff --git a/services/core/java/com/android/server/pm/permission/TEST_MAPPING b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
index 2280d3f..05e9b93 100644
--- a/services/core/java/com/android/server/pm/permission/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
@@ -1,14 +1,6 @@
{
"presubmit": [
{
- "name": "GtsPermissionTestCases",
- "options": [
- {
- "include-filter": "com.google.android.permission.gts.DefaultPermissionGrantPolicyTest"
- }
- ]
- },
- {
"name": "CtsPermissionTestCases",
"options": [
{
@@ -31,4 +23,4 @@
]
}
]
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index d0ca861..9b4293d48 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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
}
+ /** 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 @@
}
}
+ /** 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 @@
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 0caeb10..1edb93a 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 @@
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());
}
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index aaf3df3..9cbf00b 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -843,10 +843,9 @@
}
}
- // TODO(b/117478341): support back button change when IME is showing on a external display.
@Override
- public void setImeWindowStatus(final IBinder token, final int vis, final int backDisposition,
- final boolean showImeSwitcher) {
+ public void setImeWindowStatus(int displayId, final IBinder token, final int vis,
+ final int backDisposition, final boolean showImeSwitcher) {
enforceStatusBar();
if (SPEW) {
@@ -857,18 +856,13 @@
// In case of IME change, we need to call up setImeWindowStatus() regardless of
// mImeWindowVis because mImeWindowVis may not have been set to false when the
// previous IME was destroyed.
- // TODO(b/117478341): support back button change when IME is showing on a external
- // display.
- getUiState(DEFAULT_DISPLAY)
- .setImeWindowState(vis, backDisposition, showImeSwitcher, token);
+ getUiState(displayId).setImeWindowState(vis, backDisposition, showImeSwitcher, token);
mHandler.post(() -> {
if (mBar == null) return;
try {
- // TODO(b/117478341): support back button change when IME is showing on a
- // external display.
mBar.setImeWindowStatus(
- DEFAULT_DISPLAY, token, vis, backDisposition, showImeSwitcher);
+ displayId, token, vis, backDisposition, showImeSwitcher);
} catch (RemoteException ex) { }
});
}
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 0ebd092..6ce42ec 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -1132,7 +1132,7 @@
HashSet<Integer> skipRemainingWindowsForTasks = new HashSet<>();
// Iterate until we figure out what is touchable for the entire screen.
- for (int i = visibleWindowCount - 1; i >= 0 && !unaccountedSpace.isEmpty(); i--) {
+ for (int i = visibleWindowCount - 1; i >= 0; i--) {
final WindowState windowState = visibleWindows.valueAt(i);
final Rect boundsInScreen = mTempRect;
@@ -1143,6 +1143,11 @@
addPopulatedWindowInfo(windowState, boundsInScreen, windows, addedWindows);
updateUnaccountedSpace(windowState, boundsInScreen, unaccountedSpace,
skipRemainingWindowsForTasks);
+ focusedWindowAdded |= windowState.isFocused();
+ }
+
+ if (unaccountedSpace.isEmpty() && focusedWindowAdded) {
+ break;
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 76b0351..4ed07c3 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -4089,11 +4089,14 @@
// The activity that we are finishing may be over the lock screen. In this case, we do not
// want to consider activities that cannot be shown on the lock screen as running and should
// proceed with finishing the activity if there is no valid next top running activity.
+ // Note that if this finishing activity is floating task, we don't need to wait the
+ // next activity resume and can destroy it directly.
final ActivityDisplay display = getDisplay();
final ActivityRecord next = display.topRunningActivity(true /* considerKeyguardState */);
+ final boolean isFloating = r.getConfiguration().windowConfiguration.tasksAreFloating();
if (mode == FINISH_AFTER_VISIBLE && (r.visible || r.nowVisible)
- && next != null && !next.nowVisible) {
+ && next != null && !next.nowVisible && !isFloating) {
if (!mStackSupervisor.mStoppingActivities.contains(r)) {
addToStopping(r, false /* scheduleIdle */, false /* idleDelayed */);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 9d80425..78c5dbd 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -476,6 +476,11 @@
public abstract int getDisplayIdForWindow(IBinder windowToken);
/**
+ * @return The top focused display ID.
+ */
+ public abstract int getTopFocusedDisplayId();
+
+ /**
* Checks whether this display should support showing system decorations.
*/
public abstract boolean shouldShowSystemDecorOnDisplay(int displayId);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8ed2a15..d46aa7b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7340,6 +7340,13 @@
}
@Override
+ public int getTopFocusedDisplayId() {
+ synchronized (mGlobalLock) {
+ return mRoot.getTopFocusedDisplayContent().getDisplayId();
+ }
+ }
+
+ @Override
public boolean shouldShowSystemDecorOnDisplay(int displayId) {
synchronized (mGlobalLock) {
return WindowManagerService.this.shouldShowSystemDecors(displayId);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 8e18683..4105487 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2861,6 +2861,13 @@
}
mDestroying = false;
destroyedSomething = true;
+
+ // Since mDestroying will affect AppWindowToken#allDrawn, we need to perform another
+ // traversal in case we are waiting on this window to start the transition.
+ if (getDisplayContent().mAppTransition.isTransitionSet()
+ && getDisplayContent().mOpeningApps.contains(mAppToken)) {
+ mWmService.mWindowPlacerLocked.requestTraversal();
+ }
}
return destroyedSomething;
diff --git a/tests/testables/src/android/testing/BaseFragmentTest.java b/tests/testables/src/android/testing/BaseFragmentTest.java
index 9f60cce..6cd88b5 100644
--- a/tests/testables/src/android/testing/BaseFragmentTest.java
+++ b/tests/testables/src/android/testing/BaseFragmentTest.java
@@ -52,7 +52,7 @@
private static final int VIEW_ID = 42;
private final Class<? extends Fragment> mCls;
- private Handler mHandler;
+ protected Handler mHandler;
protected FrameLayout mView;
protected FragmentController mFragments;
protected Fragment mFragment;