diff options
81 files changed, 1372 insertions, 550 deletions
diff --git a/api/current.txt b/api/current.txt index 6d46da9c7321..f9b566087a8b 100644 --- a/api/current.txt +++ b/api/current.txt @@ -52240,7 +52240,6 @@ package android.view.contentcapture { } public final class ContentCaptureManager { - method public android.view.contentcapture.ContentCaptureSession createContentCaptureSession(android.view.contentcapture.ContentCaptureContext); method public android.content.ComponentName getServiceComponentName(); method public boolean isContentCaptureEnabled(); method public void removeUserData(android.view.contentcapture.UserDataRemovalRequest); @@ -52249,6 +52248,7 @@ package android.view.contentcapture { public abstract class ContentCaptureSession implements java.lang.AutoCloseable { method public void close(); + method public final android.view.contentcapture.ContentCaptureSession createContentCaptureSession(android.view.contentcapture.ContentCaptureContext); method public final void destroy(); method public final android.view.contentcapture.ContentCaptureSessionId getContentCaptureSessionId(); method public final void notifyViewAppeared(android.view.ViewStructure); diff --git a/api/system-current.txt b/api/system-current.txt index b32836a075d2..3aa7cc7a1bdb 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5085,6 +5085,16 @@ package android.service.contentcapture { package android.service.euicc { + public final class DownloadSubscriptionResult implements android.os.Parcelable { + ctor public DownloadSubscriptionResult(int, int, int); + method public int describeContents(); + method public int getCardId(); + method public int getResolvableErrors(); + method public int getResult(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.service.euicc.DownloadSubscriptionResult> CREATOR; + } + public final class EuiccProfileInfo implements android.os.Parcelable { method public int describeContents(); method public android.service.carrier.CarrierIdentifier getCarrierIdentifier(); @@ -5138,7 +5148,8 @@ package android.service.euicc { ctor public EuiccService(); method public android.os.IBinder onBind(android.content.Intent); method public abstract int onDeleteSubscription(int, java.lang.String); - method public abstract int onDownloadSubscription(int, android.telephony.euicc.DownloadableSubscription, boolean, boolean); + method public abstract android.service.euicc.DownloadSubscriptionResult onDownloadSubscription(int, android.telephony.euicc.DownloadableSubscription, boolean, boolean, android.os.Bundle); + method public deprecated int onDownloadSubscription(int, android.telephony.euicc.DownloadableSubscription, boolean, boolean); method public abstract int onEraseSubscriptions(int); method public abstract android.service.euicc.GetDefaultDownloadableSubscriptionListResult onGetDefaultDownloadableSubscriptionList(int, boolean); method public abstract android.service.euicc.GetDownloadableSubscriptionMetadataResult onGetDownloadableSubscriptionMetadata(int, android.telephony.euicc.DownloadableSubscription, boolean); @@ -5153,19 +5164,25 @@ package android.service.euicc { field public static final java.lang.String ACTION_BIND_CARRIER_PROVISIONING_SERVICE = "android.service.euicc.action.BIND_CARRIER_PROVISIONING_SERVICE"; field public static final java.lang.String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = "android.service.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS"; field public static final java.lang.String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION = "android.service.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION"; - field public static final java.lang.String ACTION_RESOLVE_CONFIRMATION_CODE = "android.service.euicc.action.RESOLVE_CONFIRMATION_CODE"; + field public static final deprecated java.lang.String ACTION_RESOLVE_CONFIRMATION_CODE = "android.service.euicc.action.RESOLVE_CONFIRMATION_CODE"; field public static final java.lang.String ACTION_RESOLVE_DEACTIVATE_SIM = "android.service.euicc.action.RESOLVE_DEACTIVATE_SIM"; field public static final java.lang.String ACTION_RESOLVE_NO_PRIVILEGES = "android.service.euicc.action.RESOLVE_NO_PRIVILEGES"; + field public static final java.lang.String ACTION_RESOLVE_RESOLVABLE_ERRORS = "android.service.euicc.action.RESOLVE_RESOLVABLE_ERRORS"; field public static final java.lang.String CATEGORY_EUICC_UI = "android.service.euicc.category.EUICC_UI"; field public static final java.lang.String EUICC_SERVICE_INTERFACE = "android.service.euicc.EuiccService"; + field public static final java.lang.String EXTRA_RESOLUTION_ALLOW_POLICY_RULES = "android.service.euicc.extra.RESOLUTION_ALLOW_POLICY_RULES"; field public static final java.lang.String EXTRA_RESOLUTION_CALLING_PACKAGE = "android.service.euicc.extra.RESOLUTION_CALLING_PACKAGE"; field public static final java.lang.String EXTRA_RESOLUTION_CONFIRMATION_CODE = "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE"; field public static final java.lang.String EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED = "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE_RETRIED"; field public static final java.lang.String EXTRA_RESOLUTION_CONSENT = "android.service.euicc.extra.RESOLUTION_CONSENT"; + field public static final java.lang.String EXTRA_RESOLVABLE_ERRORS = "android.service.euicc.extra.RESOLVABLE_ERRORS"; + field public static final int RESOLVABLE_ERROR_CONFIRMATION_CODE = 1; // 0x1 + field public static final int RESOLVABLE_ERROR_POLICY_RULES = 2; // 0x2 field public static final int RESULT_FIRST_USER = 1; // 0x1 field public static final int RESULT_MUST_DEACTIVATE_SIM = -1; // 0xffffffff - field public static final int RESULT_NEED_CONFIRMATION_CODE = -2; // 0xfffffffe + field public static final deprecated int RESULT_NEED_CONFIRMATION_CODE = -2; // 0xfffffffe field public static final int RESULT_OK = 0; // 0x0 + field public static final int RESULT_RESOLVABLE_ERRORS = -2; // 0xfffffffe } public static abstract class EuiccService.OtaStatusChangedCallback { @@ -6464,12 +6481,17 @@ package android.telephony.euicc { method public void getDownloadableSubscriptionMetadata(android.telephony.euicc.DownloadableSubscription, android.app.PendingIntent); method public int getOtaStatus(); field public static final java.lang.String ACTION_OTA_STATUS_CHANGED = "android.telephony.euicc.action.OTA_STATUS_CHANGED"; + field public static final java.lang.String ACTION_PROFILE_SELECTION = "android.telephony.euicc.action.PROFILE_SELECTION"; field public static final java.lang.String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION = "android.telephony.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION"; + field public static final int EUICC_ACTIVATION_TYPE_BACKUP = 2; // 0x2 + field public static final int EUICC_ACTIVATION_TYPE_DEFAULT = 1; // 0x1 + field public static final int EUICC_ACTIVATION_TYPE_TRANSFER = 3; // 0x3 field public static final int EUICC_OTA_FAILED = 2; // 0x2 field public static final int EUICC_OTA_IN_PROGRESS = 1; // 0x1 field public static final int EUICC_OTA_NOT_NEEDED = 4; // 0x4 field public static final int EUICC_OTA_STATUS_UNAVAILABLE = 5; // 0x5 field public static final int EUICC_OTA_SUCCEEDED = 3; // 0x3 + field public static final java.lang.String EXTRA_ACTIVATION_TYPE = "android.telephony.euicc.extra.ACTIVATION_TYPE"; field public static final java.lang.String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS"; field public static final java.lang.String EXTRA_FORCE_PROVISION = "android.telephony.euicc.extra.FORCE_PROVISION"; } @@ -7553,6 +7575,7 @@ package android.view.contentcapture { method public int getDisplayId(); method public android.os.Bundle getExtras(); method public int getFlags(); + method public android.view.contentcapture.ContentCaptureSessionId getParentSessionId(); method public int getTaskId(); method public android.net.Uri getUri(); field public static final int FLAG_DISABLED_BY_APP = 1; // 0x1 diff --git a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java index 02de7f05be7c..0775afeaeda4 100644 --- a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java +++ b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java @@ -16,209 +16,193 @@ package com.android.statsd.shelltools.testdrive; import com.android.internal.os.StatsdConfigProto.AtomMatcher; +import com.android.internal.os.StatsdConfigProto.EventMetric; +import com.android.internal.os.StatsdConfigProto.FieldFilter; +import com.android.internal.os.StatsdConfigProto.GaugeMetric; import com.android.internal.os.StatsdConfigProto.SimpleAtomMatcher; import com.android.internal.os.StatsdConfigProto.StatsdConfig; +import com.android.internal.os.StatsdConfigProto.TimeUnit; import com.android.os.AtomsProto.Atom; import com.android.os.StatsLog.ConfigMetricsReport; import com.android.os.StatsLog.ConfigMetricsReportList; +import com.android.os.StatsLog.StatsLogReport; import com.android.statsd.shelltools.Utils; import com.google.common.io.Files; -import com.google.protobuf.TextFormat; -import com.google.protobuf.TextFormat.ParseException; import java.io.File; import java.io.IOException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; public class TestDrive { - public static final int PULL_ATOM_START = 10000; - public static final long ATOM_MATCHER_ID = 1234567; - - public static final long CONFIG_ID = 54321; - - private static boolean mIsPushedAtom = false; - - private static final Logger logger = Logger.getLogger(TestDrive.class.getName()); + private static final int METRIC_ID_BASE = 1111; + private static final long ATOM_MATCHER_ID_BASE = 1234567; + private static final int PULL_ATOM_START = 10000; + private static final long CONFIG_ID = 54321; + private static final String[] ALLOWED_LOG_SOURCES = { + "AID_GRAPHICS", + "AID_INCIDENTD", + "AID_STATSD", + "AID_RADIO", + "com.android.systemui", + "com.android.vending", + "AID_SYSTEM", + "AID_ROOT", + "AID_BLUETOOTH", + "AID_LMKD" + }; + private static final Logger LOGGER = Logger.getLogger(TestDrive.class.getName()); + + private final Set<Long> mTrackedMetrics = new HashSet<>(); public static void main(String[] args) { TestDrive testDrive = new TestDrive(); - Utils.setUpLogger(logger, false); + Set<Integer> trackedAtoms = new HashSet<>(); + Utils.setUpLogger(LOGGER, false); + String remoteConfigPath = null; - if (args.length != 1) { - logger.log(Level.SEVERE, "Usage: ./test_drive <atomId>"); - return; - } - int atomId; - try { - atomId = Integer.valueOf(args[0]); - } catch (NumberFormatException e) { - logger.log(Level.SEVERE, "Bad atom id provided: " + args[0]); - return; - } - if (Atom.getDescriptor().findFieldByNumber(atomId) == null) { - logger.log(Level.SEVERE, "No such atom found: " + args[0]); + if (args.length < 1) { + LOGGER.log(Level.SEVERE, "Usage: ./test_drive <atomId1> <atomId2> ... <atomIdN>"); return; } - mIsPushedAtom = atomId < PULL_ATOM_START; + for (int i = 0; i < args.length; i++) { + try { + int atomId = Integer.valueOf(args[i]); + if (Atom.getDescriptor().findFieldByNumber(atomId) == null) { + LOGGER.log(Level.SEVERE, "No such atom found: " + args[i]); + continue; + } + trackedAtoms.add(atomId); + } catch (NumberFormatException e) { + LOGGER.log(Level.SEVERE, "Bad atom id provided: " + args[i]); + continue; + } + } try { - StatsdConfig config = testDrive.createConfig(atomId); + StatsdConfig config = testDrive.createConfig(trackedAtoms); if (config == null) { - logger.log(Level.SEVERE, "Failed to create valid config."); + LOGGER.log(Level.SEVERE, "Failed to create valid config."); return; } - testDrive.pushConfig(config); - logger.info("Pushed the following config to statsd:"); - logger.info(config.toString()); - if (mIsPushedAtom) { - logger.info( + remoteConfigPath = testDrive.pushConfig(config); + LOGGER.info("Pushed the following config to statsd:"); + LOGGER.info(config.toString()); + if (!hasPulledAtom(trackedAtoms)) { + LOGGER.info( "Now please play with the device to trigger the event. All events should " + "be dumped after 1 min ..."); Thread.sleep(60_000); } else { // wait for 2 min - logger.info("Now wait for 2 minutes ..."); + LOGGER.info("Now wait for 2 minutes ..."); Thread.sleep(120_000); } testDrive.dumpMetrics(); } catch (Exception e) { - logger.log(Level.SEVERE, "Failed to test drive: " + e.getMessage()); + LOGGER.log(Level.SEVERE, "Failed to test drive: " + e.getMessage(), e); } finally { testDrive.removeConfig(); + if (remoteConfigPath != null) { + try { + Utils.runCommand(null, LOGGER, "adb", "shell", "rm", remoteConfigPath); + } catch (Exception e) { + LOGGER.log(Level.WARNING, + "Unable to remove remote config file: " + remoteConfigPath, e); + } + } } } - private void pushConfig(StatsdConfig config) throws IOException, InterruptedException { - File configFile = File.createTempFile("statsdconfig", ".config"); - configFile.deleteOnExit(); - Files.write(config.toByteArray(), configFile); - String remotePath = "/data/local/tmp/" + configFile.getName(); - Utils.runCommand(null, logger, "adb", "push", configFile.getAbsolutePath(), remotePath); - Utils.runCommand(null, logger, - "adb", "shell", "cat", remotePath, "|", Utils.CMD_UPDATE_CONFIG, - String.valueOf(CONFIG_ID)); - } - - private void removeConfig() { - try { - Utils.runCommand(null, logger, - "adb", "shell", Utils.CMD_REMOVE_CONFIG, String.valueOf(CONFIG_ID)); - } catch (Exception e) { - logger.log(Level.SEVERE, "Failed to remove config: " + e.getMessage()); + private void dumpMetrics() throws Exception { + ConfigMetricsReportList reportList = Utils.getReportList(CONFIG_ID, true, false, LOGGER); + // We may get multiple reports. Take the last one. + ConfigMetricsReport report = reportList.getReports(reportList.getReportsCount() - 1); + for (StatsLogReport statsLog : report.getMetricsList()) { + if (mTrackedMetrics.contains(statsLog.getMetricId())) { + LOGGER.info(statsLog.toString()); + } } } - private StatsdConfig createConfig(int atomId) { - try { - if (mIsPushedAtom) { - return createSimpleEventMetricConfig(atomId); + private StatsdConfig createConfig(Set<Integer> atomIds) { + long metricId = METRIC_ID_BASE; + long atomMatcherId = ATOM_MATCHER_ID_BASE; + + StatsdConfig.Builder builder = StatsdConfig.newBuilder(); + builder + .addAllAllowedLogSource(Arrays.asList(ALLOWED_LOG_SOURCES)) + .setHashStringsInMetricReport(false); + + for (int atomId : atomIds) { + if (isPulledAtom(atomId)) { + builder.addAtomMatcher(createAtomMatcher(atomId, atomMatcherId)); + GaugeMetric.Builder gaugeMetricBuilder = GaugeMetric.newBuilder(); + gaugeMetricBuilder + .setId(metricId) + .setWhat(atomMatcherId) + .setGaugeFieldsFilter(FieldFilter.newBuilder().setIncludeAll(true).build()) + .setBucket(TimeUnit.ONE_MINUTE); + builder.addGaugeMetric(gaugeMetricBuilder.build()); } else { - return createSimpleGaugeMetricConfig(atomId); + EventMetric.Builder eventMetricBuilder = EventMetric.newBuilder(); + eventMetricBuilder + .setId(metricId) + .setWhat(atomMatcherId); + builder.addEventMetric(eventMetricBuilder.build()); + builder.addAtomMatcher(createAtomMatcher(atomId, atomMatcherId)); } - } catch (ParseException e) { - logger.log( - Level.SEVERE, - "Failed to parse the config! line: " - + e.getLine() - + " col: " - + e.getColumn() - + " " - + e.getMessage()); + atomMatcherId++; + mTrackedMetrics.add(metricId++); } - return null; - } - - private StatsdConfig createSimpleEventMetricConfig(int atomId) throws ParseException { - StatsdConfig.Builder baseBuilder = getSimpleEventMetricBaseConfig(); - baseBuilder.addAtomMatcher(createAtomMatcher(atomId)); - return baseBuilder.build(); + return builder.build(); } - private StatsdConfig createSimpleGaugeMetricConfig(int atomId) throws ParseException { - StatsdConfig.Builder baseBuilder = getSimpleGaugeMetricBaseConfig(); - baseBuilder.addAtomMatcher(createAtomMatcher(atomId)); - return baseBuilder.build(); - } - - private AtomMatcher createAtomMatcher(int atomId) { + private static AtomMatcher createAtomMatcher(int atomId, long matcherId) { AtomMatcher.Builder atomMatcherBuilder = AtomMatcher.newBuilder(); atomMatcherBuilder - .setId(ATOM_MATCHER_ID) + .setId(matcherId) .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder().setAtomId(atomId)); return atomMatcherBuilder.build(); } - private StatsdConfig.Builder getSimpleEventMetricBaseConfig() throws ParseException { - StatsdConfig.Builder builder = StatsdConfig.newBuilder(); - TextFormat.merge(EVENT_BASE_CONFIG_SRTR, builder); - return builder; - } - - private StatsdConfig.Builder getSimpleGaugeMetricBaseConfig() throws ParseException { - StatsdConfig.Builder builder = StatsdConfig.newBuilder(); - TextFormat.merge(GAUGE_BASE_CONFIG_STR, builder); - return builder; + private static String pushConfig(StatsdConfig config) throws IOException, InterruptedException { + File configFile = File.createTempFile("statsdconfig", ".config"); + configFile.deleteOnExit(); + Files.write(config.toByteArray(), configFile); + String remotePath = "/data/local/tmp/" + configFile.getName(); + Utils.runCommand(null, LOGGER, "adb", "push", configFile.getAbsolutePath(), remotePath); + Utils.runCommand(null, LOGGER, + "adb", "shell", "cat", remotePath, "|", Utils.CMD_UPDATE_CONFIG, + String.valueOf(CONFIG_ID)); + return remotePath; } - private void dumpMetrics() throws Exception { - ConfigMetricsReportList reportList = Utils.getReportList(CONFIG_ID, true, false, logger); - // We may get multiple reports. Take the last one. - ConfigMetricsReport report = reportList.getReports(reportList.getReportsCount() - 1); - // Really should be only one metric. - if (report.getMetricsCount() != 1) { - logger.log(Level.SEVERE, - "Only one report metric expected, got " + report.getMetricsCount()); - return; + private static void removeConfig() { + try { + Utils.runCommand(null, LOGGER, + "adb", "shell", Utils.CMD_REMOVE_CONFIG, String.valueOf(CONFIG_ID)); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "Failed to remove config: " + e.getMessage()); } - - logger.info("Got following metric data dump:"); - logger.info(report.getMetrics(0).toString()); } - private static final String EVENT_BASE_CONFIG_SRTR = - "id: 12345\n" - + "event_metric {\n" - + " id: 1111\n" - + " what: 1234567\n" - + "}\n" - + "allowed_log_source: \"AID_GRAPHICS\"\n" - + "allowed_log_source: \"AID_INCIDENTD\"\n" - + "allowed_log_source: \"AID_STATSD\"\n" - + "allowed_log_source: \"AID_RADIO\"\n" - + "allowed_log_source: \"com.android.systemui\"\n" - + "allowed_log_source: \"com.android.vending\"\n" - + "allowed_log_source: \"AID_SYSTEM\"\n" - + "allowed_log_source: \"AID_ROOT\"\n" - + "allowed_log_source: \"AID_BLUETOOTH\"\n" - + "allowed_log_source: \"AID_LMKD\"\n" - + "\n" - + "hash_strings_in_metric_report: false"; - - private static final String GAUGE_BASE_CONFIG_STR = - "id: 56789\n" - + "gauge_metric {\n" - + " id: 2222\n" - + " what: 1234567\n" - + " gauge_fields_filter {\n" - + " include_all: true\n" - + " }\n" - + " bucket: ONE_MINUTE\n" - + "}\n" - + "allowed_log_source: \"AID_GRAPHICS\"\n" - + "allowed_log_source: \"AID_INCIDENTD\"\n" - + "allowed_log_source: \"AID_STATSD\"\n" - + "allowed_log_source: \"AID_RADIO\"\n" - + "allowed_log_source: \"com.android.systemui\"\n" - + "allowed_log_source: \"com.android.vending\"\n" - + "allowed_log_source: \"AID_SYSTEM\"\n" - + "allowed_log_source: \"AID_ROOT\"\n" - + "allowed_log_source: \"AID_BLUETOOTH\"\n" - + "allowed_log_source: \"AID_LMKD\"\n" - + "\n" - + "hash_strings_in_metric_report: false"; + private static boolean isPulledAtom(int atomId) { + return atomId >= PULL_ATOM_START; + } + private static boolean hasPulledAtom(Set<Integer> atoms) { + for (Integer i : atoms) { + if (isPulledAtom(i)) { + return true; + } + } + return false; + } } diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt index 5cd3d5d4fa4d..7bbeb16b1b24 100644 --- a/config/hiddenapi-greylist.txt +++ b/config/hiddenapi-greylist.txt @@ -1474,7 +1474,6 @@ Landroid/service/dreams/IDreamManager;->getDreamComponents()[Landroid/content/Co Landroid/service/dreams/IDreamManager;->isDreaming()Z Landroid/service/dreams/IDreamManager;->setDreamComponents([Landroid/content/ComponentName;)V Landroid/service/euicc/IDeleteSubscriptionCallback;->onComplete(I)V -Landroid/service/euicc/IDownloadSubscriptionCallback;->onComplete(I)V Landroid/service/euicc/IEraseSubscriptionsCallback;->onComplete(I)V Landroid/service/euicc/IEuiccService$Stub;-><init>()V Landroid/service/euicc/IGetDefaultDownloadableSubscriptionListCallback;->onComplete(Landroid/service/euicc/GetDefaultDownloadableSubscriptionListResult;)V diff --git a/core/java/android/annotation/Px.java b/core/java/android/annotation/Px.java index a0ef2244d5e4..ad99fdb7657e 100644 --- a/core/java/android/annotation/Px.java +++ b/core/java/android/annotation/Px.java @@ -29,6 +29,8 @@ import static java.lang.annotation.RetentionPolicy.SOURCE; * Denotes that a numeric parameter, field or method return value is expected * to represent a pixel dimension. * + * @paramDoc This units of this value are pixels. + * @returnDoc This units of this value are pixels. * {@hide} */ @Documented diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 791f3da0d5e8..78fe0024b0b0 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -2496,7 +2496,7 @@ public class AppOpsManager { * @param packageName The package performing the operation. * @param result The result of the note. */ - void onOpNoted(String code, int uid, String packageName, int result); + void onOpNoted(int code, int uid, String packageName, int result); } /** @@ -2953,7 +2953,7 @@ public class AppOpsManager { * @hide */ @RequiresPermission(value=Manifest.permission.WATCH_APPOPS, conditional=true) - public void startWatchingNoted(@NonNull String[] ops, @NonNull OnOpNotedListener callback) { + public void startWatchingNoted(@NonNull int[] ops, @NonNull OnOpNotedListener callback) { IAppOpsNotedCallback cb; synchronized (mNotedWatchers) { cb = mNotedWatchers.get(callback); @@ -2963,17 +2963,13 @@ public class AppOpsManager { cb = new IAppOpsNotedCallback.Stub() { @Override public void opNoted(int op, int uid, String packageName, int mode) { - callback.onOpNoted(sOpToString[op], uid, packageName, mode); + callback.onOpNoted(op, uid, packageName, mode); } }; mNotedWatchers.put(callback, cb); } try { - final int[] opCodes = new int[ops.length]; - for (int i = 0; i < opCodes.length; i++) { - opCodes[i] = strOpToOp(ops[i]); - } - mService.startWatchingNoted(opCodes, cb); + mService.startWatchingNoted(ops, cb); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2983,7 +2979,7 @@ public class AppOpsManager { * Stop watching for noted app ops. An app op may be immediate or long running. * Unregistering a non-registered callback has no effect. * - * @see #startWatchingNoted(String[], OnOpNotedListener) + * @see #startWatchingNoted(int[], OnOpNotedListener) * @see #noteOp(String, int, String) * * @hide diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java index 8a0d916187b7..f3810bddf9c7 100644 --- a/core/java/android/os/GraphicsEnvironment.java +++ b/core/java/android/os/GraphicsEnvironment.java @@ -257,8 +257,7 @@ public class GraphicsEnvironment { return sDriverMap.get(OpenGlDriverChoice.DEFAULT); } // Make sure we have good settings to use - if (globalSettingsDriverPkgs.isEmpty() || globalSettingsDriverValues.isEmpty() - || (globalSettingsDriverPkgs.size() != globalSettingsDriverValues.size())) { + if (globalSettingsDriverPkgs.size() != globalSettingsDriverValues.size()) { Log.w(TAG, "Global.Settings values are invalid: " + "globalSettingsDriverPkgs.size = " @@ -299,9 +298,120 @@ public class GraphicsEnvironment { } /** + * Attempt to setup ANGLE with a temporary rules file. + * True: Temporary rules file was loaded. + * False: Temporary rules file was *not* loaded. + */ + private boolean setupAngleWithTempRulesFile(Context context, + String packageName, + String paths, + String devOptIn) { + // Check for temporary rules if debuggable or root + if (!isDebuggable(context) && !(getCanLoadSystemLibraries() == 1)) { + Log.v(TAG, "Skipping loading temporary rules file"); + return false; + } + + String angleTempRules = SystemProperties.get(ANGLE_TEMP_RULES); + + if ((angleTempRules == null) || angleTempRules.isEmpty()) { + Log.v(TAG, "System property '" + ANGLE_TEMP_RULES + "' is not set or is empty"); + return false; + } + + Log.i(TAG, "Detected system property " + ANGLE_TEMP_RULES + ": " + angleTempRules); + + File tempRulesFile = new File(angleTempRules); + if (tempRulesFile.exists()) { + Log.i(TAG, angleTempRules + " exists, loading file."); + try { + FileInputStream stream = new FileInputStream(angleTempRules); + + try { + FileDescriptor rulesFd = stream.getFD(); + long rulesOffset = 0; + long rulesLength = stream.getChannel().size(); + Log.i(TAG, "Loaded temporary ANGLE rules from " + angleTempRules); + + setAngleInfo(paths, packageName, devOptIn, rulesFd, rulesOffset, rulesLength); + + stream.close(); + + // We successfully setup ANGLE, so return with good status + return true; + } catch (IOException e) { + Log.w(TAG, "Hit IOException thrown by FileInputStream: " + e); + } + } catch (FileNotFoundException e) { + Log.w(TAG, "Temp ANGLE rules file not found: " + e); + } catch (SecurityException e) { + Log.w(TAG, "Temp ANGLE rules file not accessible: " + e); + } + } + + return false; + } + + /** + * Attempt to setup ANGLE with a (temporary) default rules file: b/121153494 + * True: Rules file was loaded. + * False: Rules file was *not* loaded. + */ + private boolean setupAngleRulesDebug(String packageName, String paths, String devOptIn) { + // b/121153494 + // Skip APK rules file checking. + if (!DEBUG) { + Log.v(TAG, "Skipping loading the rules file."); + // Fill in some default values for now, so the loader can get an answer when it asks. + // Most importantly, we need to indicate which app we are init'ing and what the + // developer options for it are so we can turn on ANGLE if needed. + setAngleInfo(paths, packageName, devOptIn, null, 0, 0); + return true; + } + + return false; + } + + /** + * Attempt to setup ANGLE with a rules file loaded from the ANGLE APK. + * True: APK rules file was loaded. + * False: APK rules file was *not* loaded. + */ + private boolean setupAngleRulesApk(String anglePkgName, + ApplicationInfo angleInfo, + Context context, + String packageName, + String paths, + String devOptIn) { + // Pass the rules file to loader for ANGLE decisions + try { + AssetManager angleAssets = + context.getPackageManager().getResourcesForApplication(angleInfo).getAssets(); + + try { + AssetFileDescriptor assetsFd = angleAssets.openFd(ANGLE_RULES_FILE); + + setAngleInfo(paths, packageName, devOptIn, assetsFd.getFileDescriptor(), + assetsFd.getStartOffset(), assetsFd.getLength()); + + assetsFd.close(); + + return true; + } catch (IOException e) { + Log.w(TAG, "Failed to get AssetFileDescriptor for " + ANGLE_RULES_FILE + + " from '" + anglePkgName + "': " + e); + } + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, "Failed to get AssetManager for '" + anglePkgName + "': " + e); + } + + return false; + } + + /** * Pass ANGLE details down to trigger enable logic */ - private void setupAngle(Context context, Bundle bundle, String packageName) { + public void setupAngle(Context context, Bundle bundle, String packageName) { String devOptIn = getDriverForPkg(bundle, packageName); if (DEBUG) { @@ -327,86 +437,29 @@ public class GraphicsEnvironment { String abi = chooseAbi(angleInfo); // Build a path that includes installed native libs and APK - StringBuilder sb = new StringBuilder(); - sb.append(angleInfo.nativeLibraryDir) - .append(File.pathSeparator) - .append(angleInfo.sourceDir) - .append("!/lib/") - .append(abi); - String paths = sb.toString(); + String paths = angleInfo.nativeLibraryDir + + File.pathSeparator + + angleInfo.sourceDir + + "!/lib/" + + abi; if (DEBUG) Log.v(TAG, "ANGLE package libs: " + paths); - // Look up rules file to pass to ANGLE - FileDescriptor rulesFd = null; - long rulesOffset = 0; - long rulesLength = 0; - - // Check for temporary rules if debuggable or root - if (isDebuggable(context) || (getCanLoadSystemLibraries() == 1)) { - String angleTempRules = SystemProperties.get(ANGLE_TEMP_RULES); - if (angleTempRules != null && !angleTempRules.isEmpty()) { - Log.i(TAG, "Detected system property " + ANGLE_TEMP_RULES + ": " + angleTempRules); - File tempRulesFile = new File(angleTempRules); - if (tempRulesFile.exists()) { - Log.i(TAG, angleTempRules + " exists, loading file."); - FileInputStream stream = null; - try { - stream = new FileInputStream(angleTempRules); - } catch (FileNotFoundException e) { - Log.w(TAG, "Unable to create stream for temp ANGLE rules"); - } - - if (stream != null) { - try { - rulesFd = stream.getFD(); - rulesOffset = 0; - rulesLength = stream.getChannel().size(); - Log.i(TAG, "Loaded temporary ANGLE rules from " + angleTempRules); - } catch (IOException e) { - Log.w(TAG, "Failed to get input stream for " + angleTempRules); - } - } - } - } + if (setupAngleWithTempRulesFile(context, packageName, paths, devOptIn)) { + // We setup ANGLE with a temp rules file, so we're done here. + return; } - // If no temp rules, load the real ones from the APK - if (DEBUG && (rulesFd == null)) { - - // Pass the rules file to loader for ANGLE decisions - AssetManager angleAssets = null; - try { - angleAssets = - context.getPackageManager().getResourcesForApplication(angleInfo).getAssets(); - } catch (PackageManager.NameNotFoundException e) { - Log.w(TAG, "Failed to get AssetManager for '" + anglePkgName + "'"); - return; - } - - AssetFileDescriptor assetsFd = null; - try { - assetsFd = angleAssets.openFd(ANGLE_RULES_FILE); - } catch (IOException e) { - Log.w(TAG, "Failed to get AssetFileDescriptor for " + ANGLE_RULES_FILE + " from " - + "'" + anglePkgName + "'"); - return; - } - - if (assetsFd != null) { - rulesFd = assetsFd.getFileDescriptor(); - rulesOffset = assetsFd.getStartOffset(); - rulesLength = assetsFd.getLength(); - } else { - Log.w(TAG, "Failed to get file descriptor for " + ANGLE_RULES_FILE); - return; - } + // b/121153494 + if (setupAngleRulesDebug(packageName, paths, devOptIn)) { + // We setup ANGLE with defaults, so we're done here. + return; } - // Further opt-in logic is handled in native, so pass relevant info down - // TODO: Move the ANGLE selection logic earlier so we don't need to keep these - // file descriptors open. - setAngleInfo(paths, packageName, devOptIn, rulesFd, rulesOffset, rulesLength); + if (setupAngleRulesApk(anglePkgName, angleInfo, context, packageName, paths, devOptIn)) { + // We setup ANGLE with rules from the APK, so we're done here. + return; + } } /** diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java index c5e62f1dfe60..64f235546201 100644 --- a/core/java/android/service/contentcapture/ContentCaptureService.java +++ b/core/java/android/service/contentcapture/ContentCaptureService.java @@ -34,13 +34,13 @@ import android.os.RemoteException; import android.util.ArrayMap; import android.util.Log; import android.util.Slog; -import android.view.contentcapture.ActivityContentCaptureSession; import android.view.contentcapture.ContentCaptureContext; import android.view.contentcapture.ContentCaptureEvent; import android.view.contentcapture.ContentCaptureManager; import android.view.contentcapture.ContentCaptureSession; import android.view.contentcapture.ContentCaptureSessionId; import android.view.contentcapture.IContentCaptureDirectManager; +import android.view.contentcapture.MainContentCaptureSession; import com.android.internal.os.IResultReceiver; @@ -293,13 +293,26 @@ public abstract class ContentCaptureService extends Service { final List<ContentCaptureEvent> events = parceledEvents.getList(); for (int i = 0; i < events.size(); i++) { final ContentCaptureEvent event = events.get(i); + if (!handleIsRightCallerFor(event, uid)) continue; String sessionIdString = event.getSessionId(); if (!sessionIdString.equals(lastSessionId)) { - if (!handleIsRightCallerFor(sessionIdString, uid)) continue; sessionId = new ContentCaptureSessionId(sessionIdString); lastSessionId = sessionIdString; } - onContentCaptureEvent(sessionId, event); + switch (event.getType()) { + case ContentCaptureEvent.TYPE_SESSION_STARTED: + final ContentCaptureContext clientContext = event.getClientContext(); + clientContext.setParentSessionId(event.getParentSessionId()); + mSessionsByUid.put(sessionIdString, uid); + onCreateContentCaptureSession(clientContext, sessionId); + break; + case ContentCaptureEvent.TYPE_SESSION_FINISHED: + mSessionsByUid.remove(sessionIdString); + onDestroyContentCaptureSession(sessionId); + break; + default: + onContentCaptureEvent(sessionId, event); + } } } @@ -314,9 +327,18 @@ public abstract class ContentCaptureService extends Service { } /** - * Checks if the given {@code uid} owns the session. + * Checks if the given {@code uid} owns the session associated with the event. */ - private boolean handleIsRightCallerFor(@NonNull String sessionId, int uid) { + private boolean handleIsRightCallerFor(@NonNull ContentCaptureEvent event, int uid) { + final String sessionId; + switch (event.getType()) { + case ContentCaptureEvent.TYPE_SESSION_STARTED: + case ContentCaptureEvent.TYPE_SESSION_FINISHED: + sessionId = event.getParentSessionId(); + break; + default: + sessionId = event.getSessionId(); + } final Integer rightUid = mSessionsByUid.get(sessionId); if (rightUid == null) { if (VERBOSE) Log.v(TAG, "No session for " + sessionId); @@ -347,7 +369,7 @@ public abstract class ContentCaptureService extends Service { final Bundle extras; if (binder != null) { extras = new Bundle(); - extras.putBinder(ActivityContentCaptureSession.EXTRA_BINDER, binder); + extras.putBinder(MainContentCaptureSession.EXTRA_BINDER, binder); } else { extras = null; } diff --git a/core/java/android/service/euicc/DownloadSubscriptionResult.aidl b/core/java/android/service/euicc/DownloadSubscriptionResult.aidl new file mode 100644 index 000000000000..b625fd6d3cb4 --- /dev/null +++ b/core/java/android/service/euicc/DownloadSubscriptionResult.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.euicc; + +parcelable DownloadSubscriptionResult; diff --git a/core/java/android/service/euicc/DownloadSubscriptionResult.java b/core/java/android/service/euicc/DownloadSubscriptionResult.java new file mode 100644 index 000000000000..b410e35f3f83 --- /dev/null +++ b/core/java/android/service/euicc/DownloadSubscriptionResult.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.service.euicc; + +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; +import android.service.euicc.EuiccService.ResolvableError; +import android.service.euicc.EuiccService.Result; + +/** + * Result of a {@link EuiccService#onDownloadSubscription} operation. + * @hide + */ +@SystemApi +public final class DownloadSubscriptionResult implements Parcelable { + + public static final Creator<DownloadSubscriptionResult> CREATOR = + new Creator<DownloadSubscriptionResult>() { + @Override + public DownloadSubscriptionResult createFromParcel(Parcel in) { + return new DownloadSubscriptionResult(in); + } + + @Override + public DownloadSubscriptionResult[] newArray(int size) { + return new DownloadSubscriptionResult[size]; + } + }; + + private final @Result int mResult; + private final @ResolvableError int mResolvableErrors; + private final int mCardId; + + public DownloadSubscriptionResult(@Result int result, @ResolvableError int resolvableErrors, + int cardId) { + this.mResult = result; + this.mResolvableErrors = resolvableErrors; + this.mCardId = cardId; + } + + /** Gets the result of the operation. */ + public @Result int getResult() { + return mResult; + } + + /** + * Gets the bit map of resolvable errors. + * + * <p>The value is passed from EuiccService. The values can be + * + * <ul> + * <li>{@link EuiccService#RESOLVABLE_ERROR_CONFIRMATION_CODE} + * <li>{@link EuiccService#RESOLVABLE_ERROR_POLICY_RULES} + * </ul> + */ + public @ResolvableError int getResolvableErrors() { + return mResolvableErrors; + } + + /** + * Gets the card Id. This is used when resolving resolvable errors. The value is passed from + * EuiccService. + */ + public int getCardId() { + return mCardId; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mResult); + dest.writeInt(mResolvableErrors); + dest.writeInt(mCardId); + } + + @Override + public int describeContents() { + return 0; + } + + private DownloadSubscriptionResult(Parcel in) { + this.mResult = in.readInt(); + this.mResolvableErrors = in.readInt(); + this.mCardId = in.readInt(); + } +} diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java index 49a7320dab6d..4be1f9cd6ae5 100644 --- a/core/java/android/service/euicc/EuiccService.java +++ b/core/java/android/service/euicc/EuiccService.java @@ -16,17 +16,24 @@ package android.service.euicc; import android.annotation.CallSuper; +import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.app.Service; import android.content.Intent; +import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; +import android.telephony.TelephonyManager; import android.telephony.euicc.DownloadableSubscription; import android.telephony.euicc.EuiccInfo; import android.telephony.euicc.EuiccManager.OtaStatus; import android.util.ArraySet; +import android.util.Log; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; @@ -73,6 +80,8 @@ import java.util.concurrent.atomic.AtomicInteger; */ @SystemApi public abstract class EuiccService extends Service { + private static final String TAG = "EuiccService"; + /** Action which must be included in this service's intent filter. */ public static final String EUICC_SERVICE_INTERFACE = "android.service.euicc.EuiccService"; @@ -115,30 +124,91 @@ public abstract class EuiccService extends Service { public static final String ACTION_RESOLVE_NO_PRIVILEGES = "android.service.euicc.action.RESOLVE_NO_PRIVILEGES"; - /** Ask the user to input carrier confirmation code. */ + /** + * Ask the user to input carrier confirmation code. + * + * @deprecated From Q, the resolvable errors happened in the download step are presented as + * bit map in {@link #EXTRA_RESOLVABLE_ERRORS}. The corresponding action would be + * {@link #ACTION_RESOLVE_RESOLVABLE_ERRORS}. + */ + @Deprecated public static final String ACTION_RESOLVE_CONFIRMATION_CODE = "android.service.euicc.action.RESOLVE_CONFIRMATION_CODE"; + /** Ask the user to resolve all the resolvable errors. */ + public static final String ACTION_RESOLVE_RESOLVABLE_ERRORS = + "android.service.euicc.action.RESOLVE_RESOLVABLE_ERRORS"; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, prefix = { "RESOLVABLE_ERROR_" }, value = { + RESOLVABLE_ERROR_CONFIRMATION_CODE, + RESOLVABLE_ERROR_POLICY_RULES, + }) + public @interface ResolvableError {} + + /** + * Possible value for the bit map of resolvable errors indicating the download process needs + * the user to input confirmation code. + */ + public static final int RESOLVABLE_ERROR_CONFIRMATION_CODE = 1 << 0; + /** + * Possible value for the bit map of resolvable errors indicating the download process needs + * the user's consent to allow profile policy rules. + */ + public static final int RESOLVABLE_ERROR_POLICY_RULES = 1 << 1; + /** * Intent extra set for resolution requests containing the package name of the calling app. * This is used by the above actions including ACTION_RESOLVE_DEACTIVATE_SIM, - * ACTION_RESOLVE_NO_PRIVILEGES and ACTION_RESOLVE_CONFIRMATION_CODE. + * ACTION_RESOLVE_NO_PRIVILEGES and ACTION_RESOLVE_RESOLVABLE_ERRORS. */ public static final String EXTRA_RESOLUTION_CALLING_PACKAGE = "android.service.euicc.extra.RESOLUTION_CALLING_PACKAGE"; /** + * Intent extra set for resolution requests containing the list of resolvable errors to be + * resolved. Each resolvable error is an integer. Its possible values include: + * <UL> + * <LI>{@link #RESOLVABLE_ERROR_CONFIRMATION_CODE} + * <LI>{@link #RESOLVABLE_ERROR_POLICY_RULES} + * </UL> + */ + public static final String EXTRA_RESOLVABLE_ERRORS = + "android.service.euicc.extra.RESOLVABLE_ERRORS"; + + /** * Intent extra set for resolution requests containing a boolean indicating whether to ask the * user to retry another confirmation code. */ public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED = "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE_RETRIED"; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "RESULT_" }, value = { + RESULT_OK, + RESULT_MUST_DEACTIVATE_SIM, + RESULT_RESOLVABLE_ERRORS, + RESULT_NEED_CONFIRMATION_CODE, + RESULT_FIRST_USER, + }) + public @interface Result {} + /** Result code for a successful operation. */ public static final int RESULT_OK = 0; /** Result code indicating that an active SIM must be deactivated to perform the operation. */ public static final int RESULT_MUST_DEACTIVATE_SIM = -1; - /** Result code indicating that the user must input a carrier confirmation code. */ + /** Result code indicating that the user must resolve resolvable errors. */ + public static final int RESULT_RESOLVABLE_ERRORS = -2; + /** + * Result code indicating that the user must input a carrier confirmation code. + * + * @deprecated From Q, the resolvable errors happened in the download step are presented as + * bit map in {@link #EXTRA_RESOLVABLE_ERRORS}. The corresponding result would be + * {@link #RESULT_RESOLVABLE_ERRORS}. + */ + @Deprecated public static final int RESULT_NEED_CONFIRMATION_CODE = -2; // New predefined codes should have negative values. @@ -154,7 +224,7 @@ public abstract class EuiccService extends Service { RESOLUTION_ACTIONS = new ArraySet<>(); RESOLUTION_ACTIONS.add(EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM); RESOLUTION_ACTIONS.add(EuiccService.ACTION_RESOLVE_NO_PRIVILEGES); - RESOLUTION_ACTIONS.add(EuiccService.ACTION_RESOLVE_CONFIRMATION_CODE); + RESOLUTION_ACTIONS.add(EuiccService.ACTION_RESOLVE_RESOLVABLE_ERRORS); } /** @@ -169,6 +239,12 @@ public abstract class EuiccService extends Service { */ public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE = "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE"; + /** + * String extra for resolution actions indicating whether the user allows policy rules. + * This is used and set by the implementation and used in {@code EuiccOperation}. + */ + public static final String EXTRA_RESOLUTION_ALLOW_POLICY_RULES = + "android.service.euicc.extra.RESOLUTION_ALLOW_POLICY_RULES"; private final IEuiccService.Stub mStubWrapper; @@ -236,8 +312,7 @@ public abstract class EuiccService extends Service { /** * Return the EID of the eUICC. * - * @param slotId ID of the SIM slot being queried. This is currently not populated but is here - * to future-proof the APIs. + * @param slotId ID of the SIM slot being queried. * @return the EID. * @see android.telephony.euicc.EuiccManager#getEid */ @@ -247,8 +322,7 @@ public abstract class EuiccService extends Service { /** * Return the status of OTA update. * - * @param slotId ID of the SIM slot to use for the operation. This is currently not populated - * but is here to future-proof the APIs. + * @param slotId ID of the SIM slot to use for the operation. * @return The status of Euicc OTA update. * @see android.telephony.euicc.EuiccManager#getOtaStatus */ @@ -257,8 +331,7 @@ public abstract class EuiccService extends Service { /** * Perform OTA if current OS is not the latest one. * - * @param slotId ID of the SIM slot to use for the operation. This is currently not populated - * but is here to future-proof the APIs. + * @param slotId ID of the SIM slot to use for the operation. * @param statusChangedCallback Function called when OTA status changed. */ public abstract void onStartOtaIfNecessary( @@ -281,8 +354,7 @@ public abstract class EuiccService extends Service { /** * Return metadata for subscriptions which are available for download for this device. * - * @param slotId ID of the SIM slot to use for the operation. This is currently not populated - * but is here to future-proof the APIs. + * @param slotId ID of the SIM slot to use for the operation. * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM)} * should be returned to allow the user to consent to this operation first. @@ -302,13 +374,44 @@ public abstract class EuiccService extends Service { * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM} * should be returned to allow the user to consent to this operation first. + * @param resolvedBundle The bundle containing information on resolved errors. It can contain + * a string of confirmation code for the key {@link #EXTRA_RESOLUTION_CONFIRMATION_CODE}, + * and a boolean for key {@link #EXTRA_RESOLUTION_ALLOW_POLICY_RULES} indicating whether + * the user allows profile policy rules or not. + * @return a DownloadSubscriptionResult instance including a result code, a resolvable errors + * bit map, and original the card Id. The result code may be one of the predefined + * {@code RESULT_} constants or any implementation-specific code starting with + * {@link #RESULT_FIRST_USER}. The resolvable error bit map can be either 0 or values + * defined in {@code RESOLVABLE_ERROR_}. + * @see android.telephony.euicc.EuiccManager#downloadSubscription + */ + public abstract DownloadSubscriptionResult onDownloadSubscription(int slotId, + @NonNull DownloadableSubscription subscription, boolean switchAfterDownload, + boolean forceDeactivateSim, @Nullable Bundle resolvedBundle); + + /** + * Download the given subscription. + * + * @param slotId ID of the SIM slot to use for the operation. + * @param subscription The subscription to download. + * @param switchAfterDownload If true, the subscription should be enabled upon successful + * download. + * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the + * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM} + * should be returned to allow the user to consent to this operation first. * @return the result of the download operation. May be one of the predefined {@code RESULT_} * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. * @see android.telephony.euicc.EuiccManager#downloadSubscription + * + * @deprecated From Q, please use the above + * {@link #onDownloadSubscription(int, DownloadableSubscription, boolean, boolean, Bundle)}. */ - public abstract int onDownloadSubscription(int slotId, - DownloadableSubscription subscription, boolean switchAfterDownload, - boolean forceDeactivateSim); + @Deprecated public @Result int onDownloadSubscription(int slotId, + @NonNull DownloadableSubscription subscription, boolean switchAfterDownload, + boolean forceDeactivateSim) { + throw new UnsupportedOperationException("onDownloadSubscription(int, " + + "DownloadableSubscription, boolean, boolean) is deprecated."); + } /** * Return a list of all @link EuiccProfileInfo}s. @@ -318,7 +421,7 @@ public abstract class EuiccService extends Service { * @see android.telephony.SubscriptionManager#getAvailableSubscriptionInfoList * @see android.telephony.SubscriptionManager#getAccessibleSubscriptionInfoList */ - public abstract GetEuiccProfileInfoListResult onGetEuiccProfileInfoList(int slotId); + public abstract @NonNull GetEuiccProfileInfoListResult onGetEuiccProfileInfoList(int slotId); /** * Return info about the eUICC chip/device. @@ -327,7 +430,7 @@ public abstract class EuiccService extends Service { * @return the {@link EuiccInfo} for the eUICC chip/device. * @see android.telephony.euicc.EuiccManager#getEuiccInfo */ - public abstract EuiccInfo onGetEuiccInfo(int slotId); + public abstract @NonNull EuiccInfo onGetEuiccInfo(int slotId); /** * Delete the given subscription. @@ -341,7 +444,7 @@ public abstract class EuiccService extends Service { * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. * @see android.telephony.euicc.EuiccManager#deleteSubscription */ - public abstract int onDeleteSubscription(int slotId, String iccid); + public abstract @Result int onDeleteSubscription(int slotId, String iccid); /** * Switch to the given subscription. @@ -357,7 +460,7 @@ public abstract class EuiccService extends Service { * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. * @see android.telephony.euicc.EuiccManager#switchToSubscription */ - public abstract int onSwitchToSubscription(int slotId, @Nullable String iccid, + public abstract @Result int onSwitchToSubscription(int slotId, @Nullable String iccid, boolean forceDeactivateSim); /** @@ -379,8 +482,7 @@ public abstract class EuiccService extends Service { * <p>This is intended to be used for device resets. As such, the reset should be performed even * if an active SIM must be deactivated in order to access the eUICC. * - * @param slotId ID of the SIM slot to use for the operation. This is currently not populated - * but is here to future-proof the APIs. + * @param slotId ID of the SIM slot to use for the operation. * @return the result of the erase operation. May be one of the predefined {@code RESULT_} * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. * @see android.telephony.euicc.EuiccManager#eraseSubscriptions @@ -395,8 +497,7 @@ public abstract class EuiccService extends Service { * should persist some bit that will remain accessible after the factory reset to bypass this * flow when this method is called. * - * @param slotId ID of the SIM slot to use for the operation. This is currently not populated - * but is here to future-proof the APIs. + * @param slotId ID of the SIM slot to use for the operation. * @return the result of the operation. May be one of the predefined {@code RESULT_} constants * or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. */ @@ -408,13 +509,26 @@ public abstract class EuiccService extends Service { private class IEuiccServiceWrapper extends IEuiccService.Stub { @Override public void downloadSubscription(int slotId, DownloadableSubscription subscription, - boolean switchAfterDownload, boolean forceDeactivateSim, + boolean switchAfterDownload, boolean forceDeactivateSim, Bundle resolvedBundle, IDownloadSubscriptionCallback callback) { mExecutor.execute(new Runnable() { @Override public void run() { - int result = EuiccService.this.onDownloadSubscription( - slotId, subscription, switchAfterDownload, forceDeactivateSim); + DownloadSubscriptionResult result; + try { + result = + EuiccService.this.onDownloadSubscription( + slotId, subscription, switchAfterDownload, forceDeactivateSim, + resolvedBundle); + } catch (AbstractMethodError e) { + Log.w(TAG, "The new onDownloadSubscription(int, " + + "DownloadableSubscription, boolean, boolean, Bundle) is not " + + "implemented. Fall back to the old one.", e); + int resultCode = EuiccService.this.onDownloadSubscription( + slotId, subscription, switchAfterDownload, forceDeactivateSim); + result = new DownloadSubscriptionResult(resultCode, + 0 /* resolvableErrors */, TelephonyManager.INVALID_CARD_ID); + } try { callback.onComplete(result); } catch (RemoteException e) { diff --git a/core/java/android/service/euicc/IDownloadSubscriptionCallback.aidl b/core/java/android/service/euicc/IDownloadSubscriptionCallback.aidl index 6893c8559d9d..50ecbebf5e84 100644 --- a/core/java/android/service/euicc/IDownloadSubscriptionCallback.aidl +++ b/core/java/android/service/euicc/IDownloadSubscriptionCallback.aidl @@ -16,7 +16,9 @@ package android.service.euicc; +import android.service.euicc.DownloadSubscriptionResult; + /** @hide */ oneway interface IDownloadSubscriptionCallback { - void onComplete(int result); + void onComplete(in DownloadSubscriptionResult result); }
\ No newline at end of file diff --git a/core/java/android/service/euicc/IEuiccService.aidl b/core/java/android/service/euicc/IEuiccService.aidl index 45be52740f32..c2cdf093706f 100644 --- a/core/java/android/service/euicc/IEuiccService.aidl +++ b/core/java/android/service/euicc/IEuiccService.aidl @@ -30,11 +30,12 @@ import android.service.euicc.IRetainSubscriptionsForFactoryResetCallback; import android.service.euicc.ISwitchToSubscriptionCallback; import android.service.euicc.IUpdateSubscriptionNicknameCallback; import android.telephony.euicc.DownloadableSubscription; +import android.os.Bundle; /** @hide */ oneway interface IEuiccService { void downloadSubscription(int slotId, in DownloadableSubscription subscription, - boolean switchAfterDownload, boolean forceDeactivateSim, + boolean switchAfterDownload, boolean forceDeactivateSim, in Bundle resolvedBundle, in IDownloadSubscriptionCallback callback); void getDownloadableSubscriptionMetadata(int slotId, in DownloadableSubscription subscription, boolean forceDeactivateSim, in IGetDownloadableSubscriptionMetadataCallback callback); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 468d92290c13..69cd3e6487c9 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -9046,17 +9046,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * {@code onCreate()} and associate it with the root view of the activity: * * <pre> - * ContentCaptureManager mgr = getSystemService(ContentCaptureManager.class); - * if (mgr != null && mgr.isContentCaptureEnabled()) { - * View rootView = findViewById(R.my_root_view); - * ContentCaptureSession session = mgr.createContentCaptureSession(new + * ContentCaptureSession oldSession = rootView.getContentCaptureSession(); + * if (oldSession != null) { + * ContentCaptureSession newSession = oldSession.createContentCaptureSession(new * ContentCaptureContext.Builder().setUri(myUrl).build()); - * rootView.setContentCaptureSession(session); + * rootView.setContentCaptureSession(newSession); * } * </pre> * * @param contentCaptureSession a session created by - * {@link ContentCaptureManager#createContentCaptureSession( + * {@link ContentCaptureSession#createContentCaptureSession( * android.view.contentcapture.ContentCaptureContext)}. */ public void setContentCaptureSession(@NonNull ContentCaptureSession contentCaptureSession) { diff --git a/core/java/android/view/contentcapture/ChildContentCaptureSession.java b/core/java/android/view/contentcapture/ChildContentCaptureSession.java new file mode 100644 index 000000000000..51668319cde2 --- /dev/null +++ b/core/java/android/view/contentcapture/ChildContentCaptureSession.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.view.contentcapture; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.view.autofill.AutofillId; +import android.view.contentcapture.ViewNode.ViewStructureImpl; + +import com.android.internal.util.Preconditions; + +import java.io.PrintWriter; + +/** + * A session that is explicitly created by the app (and hence is a descendant of + * {@link MainContentCaptureSession}). + * + * @hide + */ +final class ChildContentCaptureSession extends ContentCaptureSession { + + @NonNull + private final MainContentCaptureSession mParent; + + /** + * {@link ContentCaptureContext} set by client, or {@code null} when it's the + * {@link ContentCaptureManager#getMainContentCaptureSession() default session} for the + * context. + * + * @hide + */ + @NonNull + private final ContentCaptureContext mClientContext; + + /** @hide */ + protected ChildContentCaptureSession(@NonNull MainContentCaptureSession parent, + @NonNull ContentCaptureContext clientContext) { + mParent = parent; + mClientContext = Preconditions.checkNotNull(clientContext); + } + + @Override + ContentCaptureSession newChild(@NonNull ContentCaptureContext context) { + // TODO(b/121033016): implement it + throw new UnsupportedOperationException("grand-children not implemented yet"); + } + + @Override + void flush() { + mParent.flush(); + } + + @Override + void onDestroy() { + mParent.notifyChildSessionFinished(mParent.mId, mId); + } + + @Override + void internalNotifyViewAppeared(@NonNull ViewStructureImpl node) { + mParent.notifyViewAppeared(mId, node); + } + + @Override + void internalNotifyViewDisappeared(@NonNull AutofillId id) { + mParent.notifyViewDisappeared(mId, id); + } + + @Override + void internalNotifyViewTextChanged(@NonNull AutofillId id, @Nullable CharSequence text, + int flags) { + mParent.notifyViewTextChanged(mId, id, text, flags); + } + @Override + boolean isContentCaptureEnabled() { + return mParent.isContentCaptureEnabled(); + } + + @Override + void dump(String prefix, PrintWriter pw) { + if (mClientContext != null) { + // NOTE: we don't dump clientContent because it could have PII + pw.print(prefix); pw.println("hasClientContext"); + } + super.dump(prefix, pw); + } +} diff --git a/core/java/android/view/contentcapture/ContentCaptureContext.java b/core/java/android/view/contentcapture/ContentCaptureContext.java index 9c11743fdf19..2d2987a035da 100644 --- a/core/java/android/view/contentcapture/ContentCaptureContext.java +++ b/core/java/android/view/contentcapture/ContentCaptureContext.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.annotation.SystemApi; import android.app.TaskInfo; import android.content.ComponentName; +import android.content.Context; import android.net.Uri; import android.os.Bundle; import android.os.Parcel; @@ -76,7 +77,7 @@ public final class ContentCaptureContext implements Parcelable { /** * Flag indicating if this object has the app-provided context (which is set on - * {@link ContentCaptureManager#createContentCaptureSession(ContentCaptureContext)}). + * {@link ContentCaptureSession#createContentCaptureSession(ContentCaptureContext)}). */ private final boolean mHasClientContext; @@ -91,6 +92,9 @@ public final class ContentCaptureContext implements Parcelable { private final int mDisplayId; private final int mFlags; + // Fields below are set by the service upon "delivery" and are not marshalled in the parcel + private @Nullable String mParentSessionId; + /** @hide */ public ContentCaptureContext(@Nullable ContentCaptureContext clientContext, @NonNull ComponentName componentName, int taskId, int displayId, int flags) { @@ -153,16 +157,33 @@ public final class ContentCaptureContext implements Parcelable { } /** - * Gets the activity associated with this context. + * Gets the activity associated with this context, or {@code null} when it is a child session. * * @hide */ @SystemApi - public @NonNull ComponentName getActivityComponent() { + public @Nullable ComponentName getActivityComponent() { return mComponentName; } /** + * Gets the id of the session that originated this session (through + * {@link ContentCaptureSession#createContentCaptureSession(ContentCaptureContext)}), + * or {@code null} if this is the main session associated with the Activity's {@link Context}. + * + * @hide + */ + @SystemApi + public @Nullable ContentCaptureSessionId getParentSessionId() { + return mParentSessionId == null ? null : new ContentCaptureSessionId(mParentSessionId); + } + + /** @hide */ + public void setParentSessionId(@NonNull String parentSessionId) { + mParentSessionId = parentSessionId; + } + + /** * Gets the ID of the display associated with this context, as defined by * {G android.hardware.display.DisplayManager#getDisplay(int) DisplayManager.getDisplay()}. * @@ -242,6 +263,9 @@ public final class ContentCaptureContext implements Parcelable { pw.print("comp="); pw.print(ComponentName.flattenToShortString(mComponentName)); pw.print(", taskId="); pw.print(mTaskId); pw.print(", displayId="); pw.print(mDisplayId); + if (mParentSessionId != null) { + pw.print(", parentId="); pw.print(mParentSessionId); + } if (mFlags > 0) { pw.print(", flags="); pw.print(mFlags); } @@ -262,6 +286,9 @@ public final class ContentCaptureContext implements Parcelable { .append(", taskId=").append(mTaskId) .append(", displayId=").append(mDisplayId) .append(", flags=").append(mFlags); + if (mParentSessionId != null) { + builder.append(", parentId=").append(mParentSessionId); + } if (mExtras != null) { // NOTE: cannot print because it could contain PII builder.append(", hasExtras"); @@ -320,9 +347,9 @@ public final class ContentCaptureContext implements Parcelable { final int taskId = parcel.readInt(); final int displayId = parcel.readInt(); final int flags = parcel.readInt(); - return new ContentCaptureContext(clientContext, componentName, taskId, - displayId, flags); - } + return new ContentCaptureContext(clientContext, componentName, taskId, displayId, + flags); + } } @Override diff --git a/core/java/android/view/contentcapture/ContentCaptureEvent.java b/core/java/android/view/contentcapture/ContentCaptureEvent.java index 43c9699b54b8..9e3da9234b58 100644 --- a/core/java/android/view/contentcapture/ContentCaptureEvent.java +++ b/core/java/android/view/contentcapture/ContentCaptureEvent.java @@ -34,9 +34,9 @@ import java.lang.annotation.RetentionPolicy; public final class ContentCaptureEvent implements Parcelable { /** @hide */ - public static final int TYPE_ACTIVITY_DESTROYED = -2; + public static final int TYPE_SESSION_FINISHED = -2; /** @hide */ - public static final int TYPE_ACTIVITY_CREATED = -1; + public static final int TYPE_SESSION_STARTED = -1; /** * Called when a node has been added to the screen and is visible to the user. @@ -78,6 +78,8 @@ public final class ContentCaptureEvent implements Parcelable { private @Nullable AutofillId mId; private @Nullable ViewNode mNode; private @Nullable CharSequence mText; + private @Nullable String mParentSessionId; + private @Nullable ContentCaptureContext mClientContext; /** @hide */ public ContentCaptureEvent(@NonNull String sessionId, int type, long eventTime, int flags) { @@ -103,12 +105,52 @@ public final class ContentCaptureEvent implements Parcelable { return this; } + /** + * Used by {@link #TYPE_SESSION_STARTED} and {@link #TYPE_SESSION_FINISHED}. + * + * @hide + */ + public ContentCaptureEvent setParentSessionId(@NonNull String parentSessionId) { + mParentSessionId = parentSessionId; + return this; + } + + /** + * Used by {@link #TYPE_SESSION_STARTED} and {@link #TYPE_SESSION_FINISHED}. + * + * @hide + */ + public ContentCaptureEvent setClientContext(@NonNull ContentCaptureContext clientContext) { + mClientContext = clientContext; + return this; + } + /** @hide */ @NonNull public String getSessionId() { return mSessionId; } + /** + * Used by {@link #TYPE_SESSION_STARTED} and {@link #TYPE_SESSION_FINISHED}. + * + * @hide + */ + @Nullable + public String getParentSessionId() { + return mParentSessionId; + } + + /** + * Used by {@link #TYPE_SESSION_STARTED}. + * + * @hide + */ + @Nullable + public ContentCaptureContext getClientContext() { + return mClientContext; + } + /** @hide */ @NonNull public ContentCaptureEvent setViewNode(@NonNull ViewNode node) { @@ -191,7 +233,17 @@ public final class ContentCaptureEvent implements Parcelable { pw.print(", id="); pw.print(mId); } if (mNode != null) { - pw.print(", id="); pw.print(mNode.getAutofillId()); + pw.print(", mNode.id="); pw.print(mNode.getAutofillId()); + } + if (mSessionId != null) { + pw.print(", sessionId="); pw.print(mSessionId); + } + if (mParentSessionId != null) { + pw.print(", parentSessionId="); pw.print(mParentSessionId); + } + if (mText != null) { + // Cannot print content because could have PII + pw.print(", text="); pw.print(mText.length()); pw.print("_chars"); } } @@ -229,6 +281,12 @@ public final class ContentCaptureEvent implements Parcelable { parcel.writeParcelable(mId, flags); ViewNode.writeToParcel(parcel, mNode, flags); parcel.writeCharSequence(mText); + if (mType == TYPE_SESSION_STARTED || mType == TYPE_SESSION_FINISHED) { + parcel.writeString(mParentSessionId); + } + if (mType == TYPE_SESSION_STARTED) { + parcel.writeParcelable(mClientContext, flags); + } } public static final Parcelable.Creator<ContentCaptureEvent> CREATOR = @@ -251,6 +309,12 @@ public final class ContentCaptureEvent implements Parcelable { event.setViewNode(node); } event.setText(parcel.readCharSequence()); + if (type == TYPE_SESSION_STARTED || type == TYPE_SESSION_FINISHED) { + event.setParentSessionId(parcel.readString()); + } + if (type == TYPE_SESSION_STARTED) { + event.setClientContext(parcel.readParcelable(null)); + } return event; } @@ -263,6 +327,10 @@ public final class ContentCaptureEvent implements Parcelable { /** @hide */ public static String getTypeAsString(@EventType int type) { switch (type) { + case TYPE_SESSION_STARTED: + return "SESSION_STARTED"; + case TYPE_SESSION_FINISHED: + return "SESSION_FINISHED"; case TYPE_VIEW_APPEARED: return "VIEW_APPEARED"; case TYPE_VIEW_DISAPPEARED: diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java index fca2857d6e06..983079073d02 100644 --- a/core/java/android/view/contentcapture/ContentCaptureManager.java +++ b/core/java/android/view/contentcapture/ContentCaptureManager.java @@ -18,13 +18,13 @@ package android.view.contentcapture; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemService; +import android.annotation.UiThread; import android.content.ComponentName; import android.content.Context; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.util.Log; -import android.view.View; import com.android.internal.util.Preconditions; @@ -66,7 +66,7 @@ public final class ContentCaptureManager { @NonNull private final Handler mHandler; - private ActivityContentCaptureSession mMainSession; + private MainContentCaptureSession mMainSession; /** @hide */ public ContentCaptureManager(@NonNull Context context, @@ -93,46 +93,20 @@ public final class ContentCaptureManager { } /** - * Creates a new {@link ContentCaptureSession}. - * - * <p>See {@link View#setContentCaptureSession(ContentCaptureSession)} for more info. - */ - @NonNull - public ContentCaptureSession createContentCaptureSession( - @NonNull ContentCaptureContext context) { - if (DEBUG) Log.d(TAG, "createContentCaptureSession(): " + context); - // TODO(b/121033016): for now we're updating the main session, but we need instead: - // 1.Keep a list of sessions - // 2.Making sure the applicationToken and componentName passed by - // the activity is used on all of these sessions - // 3.We might also need to delay the start of all of these sessions until - // onActivityStarted() is called (and the main session is created). - // 4.Close (and delete) these sessions when onActivityStopped() is called. - // 5.Figure out whether each session will have its own mDisabled AtomicBoolean. - if (mMainSession == null) { - mMainSession = new ActivityContentCaptureSession(mContext, mHandler, mService, - mDisabled, Preconditions.checkNotNull(context)); - } else { - throw new IllegalStateException("Manager already has a session: " + mMainSession); - } - return mMainSession; - } - - /** * Gets the main session associated with the context. * * <p>By default there's just one (associated with the activity lifecycle), but apps could - * explicitly add more using {@link #createContentCaptureSession(ContentCaptureContext)}. + * explicitly add more using + * {@link ContentCaptureSession#createContentCaptureSession(ContentCaptureContext)}. * * @hide */ @NonNull - public ActivityContentCaptureSession getMainContentCaptureSession() { - // TODO(b/121033016): figure out how to manage the "default" session when it support - // multiple sessions (can't just be the first one, as it could be closed). + @UiThread + public MainContentCaptureSession getMainContentCaptureSession() { if (mMainSession == null) { - mMainSession = new ActivityContentCaptureSession(mContext, mHandler, mService, - mDisabled, /* clientContext= */ null); + mMainSession = new MainContentCaptureSession(mContext, mHandler, mService, + mDisabled); if (VERBOSE) { Log.v(TAG, "getDefaultContentCaptureSession(): created " + mMainSession); } diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java index aedb7a94ff5d..9f666a40bef3 100644 --- a/core/java/android/view/contentcapture/ContentCaptureSession.java +++ b/core/java/android/view/contentcapture/ContentCaptureSession.java @@ -15,8 +15,10 @@ */ package android.view.contentcapture; +import static android.view.contentcapture.ContentCaptureManager.DEBUG; import static android.view.contentcapture.ContentCaptureManager.VERBOSE; +import android.annotation.CallSuper; import android.annotation.NonNull; import android.annotation.Nullable; import android.util.Log; @@ -30,6 +32,7 @@ import com.android.internal.util.Preconditions; import dalvik.system.CloseGuard; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.UUID; /** @@ -80,6 +83,8 @@ public abstract class ContentCaptureSession implements AutoCloseable { */ public static final int STATE_DISABLED_DUPLICATED_ID = 4; + private static final int INITIAL_CHILDREN_CAPACITY = 5; + /** @hide */ protected final String mTag = getClass().getSimpleName(); @@ -95,19 +100,17 @@ public abstract class ContentCaptureSession implements AutoCloseable { private ContentCaptureSessionId mContentCaptureSessionId; /** - * {@link ContentCaptureContext} set by client, or {@code null} when it's the - * {@link ContentCaptureManager#getMainContentCaptureSession() default session} for the - * context. - * - * @hide + * List of children session. */ + // TODO(b/121033016): need to synchonize access, either by changing on handler or UI thread + // (for now there's no handler on this class, so we need to wait for the next refactoring), + // most likely the former (as we have no guarantee that createContentCaptureSession() + // it will be called in the UiThread; for example, WebView most likely won't call on it) @Nullable - // TODO(b/121042846): move to ChildContentCaptureSession.java - protected final ContentCaptureContext mClientContext; + private ArrayList<ContentCaptureSession> mChildren; /** @hide */ - protected ContentCaptureSession(@Nullable ContentCaptureContext clientContext) { - mClientContext = clientContext; + protected ContentCaptureSession() { mCloseGuard.open("destroy"); } @@ -122,6 +125,28 @@ public abstract class ContentCaptureSession implements AutoCloseable { } /** + * Creates a new {@link ContentCaptureSession}. + * + * <p>See {@link View#setContentCaptureSession(ContentCaptureSession)} for more info. + */ + @NonNull + public final ContentCaptureSession createContentCaptureSession( + @NonNull ContentCaptureContext context) { + final ContentCaptureSession child = newChild(context); + if (DEBUG) { + Log.d(mTag, "createContentCaptureSession(" + context + ": parent=" + mId + ", child= " + + child.mId); + } + if (mChildren == null) { + mChildren = new ArrayList<>(INITIAL_CHILDREN_CAPACITY); + } + mChildren.add(child); + return child; + } + + abstract ContentCaptureSession newChild(@NonNull ContentCaptureContext context); + + /** * Flushes the buffered events to the service. */ abstract void flush(); @@ -134,24 +159,40 @@ public abstract class ContentCaptureSession implements AutoCloseable { public final void destroy() { //TODO(b/111276913): mark it as destroyed so other methods are ignored (and test on CTS) + //TODO(b/111276913): probably shouldn't check for it if (!isContentCaptureEnabled()) return; + mCloseGuard.close(); + //TODO(b/111276913): check state (for example, how to handle if it's waiting for remote // id) and send it to the cache of batched commands if (VERBOSE) { Log.v(mTag, "destroy(): state=" + getStateAsString(mState) + ", mId=" + mId); } - flush(); - - onDestroy(); + // Finish children first + if (mChildren != null) { + final int numberChildren = mChildren.size(); + if (VERBOSE) Log.v(mTag, "Destroying " + numberChildren + " children first"); + for (int i = 0; i < numberChildren; i++) { + final ContentCaptureSession child = mChildren.get(i); + try { + child.destroy(); + } catch (Exception e) { + Log.w(mTag, "exception destroying child session #" + i + ": " + e); + } + } + } - mCloseGuard.close(); + try { + flush(); + } finally { + onDestroy(); + } } abstract void onDestroy(); - /** @hide */ @Override public void close() { @@ -259,7 +300,19 @@ public abstract class ContentCaptureSession implements AutoCloseable { abstract boolean isContentCaptureEnabled(); - abstract void dump(@NonNull String prefix, @NonNull PrintWriter pw); + @CallSuper + void dump(@NonNull String prefix, @NonNull PrintWriter pw) { + if (mChildren != null && !mChildren.isEmpty()) { + final String prefix2 = prefix + " "; + final int numberChildren = mChildren.size(); + pw.print(prefix); pw.print("number children: "); pw.print(numberChildren); + for (int i = 0; i < numberChildren; i++) { + final ContentCaptureSession child = mChildren.get(i); + pw.print(prefix); pw.print(i); pw.println(": "); child.dump(prefix2, pw); + } + } + + } @Override public String toString() { diff --git a/core/java/android/view/contentcapture/IContentCaptureManager.aidl b/core/java/android/view/contentcapture/IContentCaptureManager.aidl index cbd37017038e..01776f846434 100644 --- a/core/java/android/view/contentcapture/IContentCaptureManager.aidl +++ b/core/java/android/view/contentcapture/IContentCaptureManager.aidl @@ -33,7 +33,6 @@ import java.util.List; */ oneway interface IContentCaptureManager { void startSession(int userId, IBinder activityToken, in ComponentName componentName, - String sessionId, in ContentCaptureContext clientContext, int flags, - in IResultReceiver result); + String sessionId, int flags, in IResultReceiver result); void finishSession(int userId, String sessionId); } diff --git a/core/java/android/view/contentcapture/ActivityContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java index a8f3e0bbd45d..ea6f2fe16ef6 100644 --- a/core/java/android/view/contentcapture/ActivityContentCaptureSession.java +++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java @@ -15,6 +15,8 @@ */ package android.view.contentcapture; +import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_FINISHED; +import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_STARTED; import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_APPEARED; import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_DISAPPEARED; import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TEXT_CHANGED; @@ -59,7 +61,7 @@ import java.util.concurrent.atomic.AtomicBoolean; * * @hide */ -public final class ActivityContentCaptureSession extends ContentCaptureSession { +public final class MainContentCaptureSession extends ContentCaptureSession { /** * Handler message used to flush the buffer. @@ -129,18 +131,23 @@ public final class ActivityContentCaptureSession extends ContentCaptureSession { // Lazily created on demand. private ContentCaptureSessionId mContentCaptureSessionId; - /** - * @hide */ - protected ActivityContentCaptureSession(@NonNull Context context, @NonNull Handler handler, - @Nullable IContentCaptureManager systemServerInterface, @NonNull AtomicBoolean disabled, - @Nullable ContentCaptureContext clientContext) { - super(clientContext); + /** @hide */ + protected MainContentCaptureSession(@NonNull Context context, @NonNull Handler handler, + @Nullable IContentCaptureManager systemServerInterface, + @NonNull AtomicBoolean disabled) { mContext = context; mHandler = handler; mSystemServerInterface = systemServerInterface; mDisabled = disabled; } + @Override + ContentCaptureSession newChild(@NonNull ContentCaptureContext clientContext) { + final ContentCaptureSession child = new ChildContentCaptureSession(this, clientContext); + notifyChildSessionStarted(mId, child.mId, clientContext); + return child; + } + /** * Starts this session. * @@ -154,19 +161,19 @@ public final class ActivityContentCaptureSession extends ContentCaptureSession { + ComponentName.flattenToShortString(activityComponent)); } - mHandler.sendMessage(obtainMessage(ActivityContentCaptureSession::handleStartSession, this, + mHandler.sendMessage(obtainMessage(MainContentCaptureSession::handleStartSession, this, applicationToken, activityComponent)); } @Override void flush() { - mHandler.sendMessage(obtainMessage(ActivityContentCaptureSession::handleForceFlush, this)); + mHandler.sendMessage(obtainMessage(MainContentCaptureSession::handleForceFlush, this)); } @Override void onDestroy() { mHandler.sendMessage( - obtainMessage(ActivityContentCaptureSession::handleDestroySession, this)); + obtainMessage(MainContentCaptureSession::handleDestroySession, this)); } private void handleStartSession(@NonNull IBinder token, @NonNull ComponentName componentName) { @@ -188,7 +195,7 @@ public final class ActivityContentCaptureSession extends ContentCaptureSession { try { mSystemServerInterface.startSession(mContext.getUserId(), mApplicationToken, - componentName, mId, mClientContext, flags, new IResultReceiver.Stub() { + componentName, mId, flags, new IResultReceiver.Stub() { @Override public void send(int resultCode, Bundle resultData) { IBinder binder = null; @@ -296,7 +303,7 @@ public final class ActivityContentCaptureSession extends ContentCaptureSession { Log.v(mTag, "Scheduled to flush in " + FLUSHING_FREQUENCY_MS + "ms: " + mNextFlush); } mHandler.sendMessageDelayed( - obtainMessage(ActivityContentCaptureSession::handleFlushIfNeeded, this) + obtainMessage(MainContentCaptureSession::handleFlushIfNeeded, this) .setWhat(MSG_FLUSH), FLUSHING_FREQUENCY_MS); } @@ -312,7 +319,7 @@ public final class ActivityContentCaptureSession extends ContentCaptureSession { if (mEvents == null) return; if (mDirectServiceInterface == null) { - Log.w(mTag, "handleForceFlush(): client not available yet"); + if (DEBUG) Log.d(mTag, "handleForceFlush(): hold your horses, client not ready yet!"); if (!mHandler.hasMessages(MSG_FLUSH)) { handleScheduleFlush(/* checkExisting= */ false); } @@ -367,12 +374,15 @@ public final class ActivityContentCaptureSession extends ContentCaptureSession { handleResetSession(/* resetState= */ true); } - // TODO(b/121042846): once we support multiple sessions, we might need to move some of these + // TODO(b/121033016): once we support multiple sessions, we might need to move some of these // clearings out. private void handleResetSession(boolean resetState) { if (resetState) { mState = STATE_UNKNOWN; } + + // TODO(b/121033016): must reset children (which currently is owned by superclass) + mContentCaptureSessionId = null; mApplicationToken = null; mComponentName = null; @@ -386,24 +396,18 @@ public final class ActivityContentCaptureSession extends ContentCaptureSession { @Override void internalNotifyViewAppeared(@NonNull ViewStructureImpl node) { - mHandler.sendMessage(obtainMessage(ActivityContentCaptureSession::handleSendEvent, this, - new ContentCaptureEvent(mId, TYPE_VIEW_APPEARED) - .setViewNode(node.mNode), /* forceFlush= */ false)); + notifyViewAppeared(mId, node); } @Override void internalNotifyViewDisappeared(@NonNull AutofillId id) { - mHandler.sendMessage(obtainMessage(ActivityContentCaptureSession::handleSendEvent, this, - new ContentCaptureEvent(mId, TYPE_VIEW_DISAPPEARED).setAutofillId(id), - /* forceFlush= */ false)); + notifyViewDisappeared(mId, id); } @Override void internalNotifyViewTextChanged(@NonNull AutofillId id, @Nullable CharSequence text, int flags) { - mHandler.sendMessage(obtainMessage(ActivityContentCaptureSession::handleSendEvent, this, - new ContentCaptureEvent(mId, TYPE_VIEW_TEXT_CHANGED, flags).setAutofillId(id) - .setText(text), /* forceFlush= */ false)); + notifyViewTextChanged(mId, id, text, flags); } @Override @@ -411,6 +415,44 @@ public final class ActivityContentCaptureSession extends ContentCaptureSession { return mSystemServerInterface != null && !mDisabled.get(); } + // TODO(b/121033016): refactor "notifyXXXX" methods below to a common "Buffer" object that is + // shared between ActivityContentCaptureSession and ChildContentCaptureSession objects. Such + // change should also get get rid of the "internalNotifyXXXX" methods above + void notifyChildSessionStarted(@NonNull String parentSessionId, + @NonNull String childSessionId, @NonNull ContentCaptureContext clientContext) { + mHandler.sendMessage(obtainMessage(MainContentCaptureSession::handleSendEvent, this, + new ContentCaptureEvent(childSessionId, TYPE_SESSION_STARTED) + .setParentSessionId(parentSessionId) + .setClientContext(clientContext), + /* forceFlush= */ false)); + } + + void notifyChildSessionFinished(@NonNull String parentSessionId, + @NonNull String childSessionId) { + mHandler.sendMessage(obtainMessage(MainContentCaptureSession::handleSendEvent, this, + new ContentCaptureEvent(childSessionId, TYPE_SESSION_FINISHED) + .setParentSessionId(parentSessionId), /* forceFlush= */ false)); + } + + void notifyViewAppeared(@NonNull String sessionId, @NonNull ViewStructureImpl node) { + mHandler.sendMessage(obtainMessage(MainContentCaptureSession::handleSendEvent, this, + new ContentCaptureEvent(sessionId, TYPE_VIEW_APPEARED) + .setViewNode(node.mNode), /* forceFlush= */ false)); + } + + void notifyViewDisappeared(@NonNull String sessionId, @NonNull AutofillId id) { + mHandler.sendMessage(obtainMessage(MainContentCaptureSession::handleSendEvent, this, + new ContentCaptureEvent(sessionId, TYPE_VIEW_DISAPPEARED).setAutofillId(id), + /* forceFlush= */ false)); + } + + void notifyViewTextChanged(@NonNull String sessionId, @NonNull AutofillId id, + @Nullable CharSequence text, int flags) { + mHandler.sendMessage(obtainMessage(MainContentCaptureSession::handleSendEvent, this, + new ContentCaptureEvent(sessionId, TYPE_VIEW_TEXT_CHANGED, flags).setAutofillId(id) + .setText(text), /* forceFlush= */ false)); + } + @Override void dump(@NonNull String prefix, @NonNull PrintWriter pw) { pw.print(prefix); pw.print("id: "); pw.println(mId); @@ -424,11 +466,6 @@ public final class ActivityContentCaptureSession extends ContentCaptureSession { pw.print(prefix); pw.print("mDirectServiceInterface: "); pw.println(mDirectServiceInterface); } - if (mClientContext != null) { - // NOTE: we don't dump clientContent because it could have PII - pw.print(prefix); pw.println("hasClientContext"); - - } pw.print(prefix); pw.print("mDisabled: "); pw.println(mDisabled.get()); pw.print(prefix); pw.print("isEnabled(): "); pw.println(isContentCaptureEnabled()); if (mContentCaptureSessionId != null) { @@ -459,6 +496,7 @@ public final class ActivityContentCaptureSession extends ContentCaptureSession { pw.print(prefix); pw.print("next flush: "); TimeUtils.formatDuration(mNextFlush - SystemClock.elapsedRealtime(), pw); pw.println(); } + super.dump(prefix, pw); } /** diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index 12ca78a7ce92..eb7338a7ce58 100755 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -45,7 +45,7 @@ namespace android { class BitmapWrapper { public: - BitmapWrapper(Bitmap* bitmap) + explicit BitmapWrapper(Bitmap* bitmap) : mBitmap(bitmap) { } void freePixels() { diff --git a/core/jni/android/graphics/FontUtils.h b/core/jni/android/graphics/FontUtils.h index 9f6462e67050..b36b4e60e33a 100644 --- a/core/jni/android/graphics/FontUtils.h +++ b/core/jni/android/graphics/FontUtils.h @@ -29,7 +29,7 @@ class FontFamily; namespace android { struct FontFamilyWrapper { - FontFamilyWrapper(std::shared_ptr<minikin::FontFamily>&& family) : family(family) {} + explicit FontFamilyWrapper(std::shared_ptr<minikin::FontFamily>&& family) : family(family) {} std::shared_ptr<minikin::FontFamily> family; }; diff --git a/core/jni/android/graphics/GIFMovie.cpp b/core/jni/android/graphics/GIFMovie.cpp index dd99b377988f..f84a4bd09073 100644 --- a/core/jni/android/graphics/GIFMovie.cpp +++ b/core/jni/android/graphics/GIFMovie.cpp @@ -21,7 +21,7 @@ class GIFMovie : public Movie { public: - GIFMovie(SkStream* stream); + explicit GIFMovie(SkStream* stream); virtual ~GIFMovie(); protected: diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp index 33b26899fe81..bd87dcc325a8 100644 --- a/core/jni/fd_utils.cpp +++ b/core/jni/fd_utils.cpp @@ -152,7 +152,7 @@ class FileDescriptorInfo { const bool is_sock; private: - FileDescriptorInfo(int fd); + explicit FileDescriptorInfo(int fd); FileDescriptorInfo(struct stat stat, const std::string& file_path, int fd, int open_flags, int fd_flags, int fs_flags, off_t offset); diff --git a/core/jni/fd_utils.h b/core/jni/fd_utils.h index a3570d7ed1fb..09022a2e2408 100644 --- a/core/jni/fd_utils.h +++ b/core/jni/fd_utils.h @@ -86,7 +86,7 @@ class FileDescriptorTable { bool ReopenOrDetach(std::string* error_msg); private: - FileDescriptorTable(const std::unordered_map<int, FileDescriptorInfo*>& map); + explicit FileDescriptorTable(const std::unordered_map<int, FileDescriptorInfo*>& map); bool RestatInternal(std::set<int>& open_fds, std::string* error_msg); diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 8b6f33fd97e7..299798bde7d3 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -4336,7 +4336,7 @@ <permission android:name="android.permission.SMS_FINANCIAL_TRANSACTIONS" android:protectionLevel="signature|appop" /> - <!-- Required for apps targeting {@link android.os.Build.VERSION_CODES#P} that want to use + <!-- Required for apps targeting {@link android.os.Build.VERSION_CODES#Q} that want to use {@link android.app.Notification.Builder#setFullScreenIntent notification full screen intents}. --> <permission android:name="android.permission.USE_FULL_SCREEN_INTENT" diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index 6e6ed30fef8c..9361c7c29bcb 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -55,6 +55,7 @@ import java.math.BigInteger; import java.io.ByteArrayInputStream; import java.io.IOException; import java.security.InvalidKeyException; +import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; @@ -315,13 +316,14 @@ public class KeyStore { } /** - * List uids of all keys that are auth bound to the current user. + * List uids of all keys that are auth bound to the current user. * Only system is allowed to call this method. */ @UnsupportedAppUsage public int[] listUidsOfAuthBoundKeys() { - final int MAX_RESULT_SIZE = 100; - int[] uidsOut = new int[MAX_RESULT_SIZE]; + // uids are returned as a list of strings because list of integers + // as an output parameter is not supported by aidl-cpp. + List<String> uidsOut = new ArrayList<>(); try { int rc = mBinder.listUidsOfAuthBoundKeys(uidsOut); if (rc != NO_ERROR) { @@ -335,8 +337,8 @@ public class KeyStore { Log.w(TAG, "KeyStore exception", e); return null; } - // Remove any 0 entries - return Arrays.stream(uidsOut).filter(x -> x > 0).toArray(); + // Turn list of strings into an array of uid integers. + return uidsOut.stream().mapToInt(Integer::parseInt).toArray(); } public String[] list(String prefix) { diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java index 9bd59940e37b..b5313256e4dc 100644 --- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java +++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java @@ -17,6 +17,7 @@ package com.android.internal.location; import java.io.UnsupportedEncodingException; +import java.util.concurrent.TimeUnit; import android.app.Notification; import android.app.NotificationManager; @@ -27,19 +28,17 @@ import android.content.Intent; import android.content.IntentFilter; import android.location.LocationManager; import android.location.INetInitiatedListener; +import android.os.SystemClock; import android.telephony.TelephonyManager; import android.telephony.PhoneNumberUtils; import android.telephony.PhoneStateListener; -import android.os.Bundle; import android.os.RemoteException; import android.os.UserHandle; -import android.os.SystemProperties; import android.util.Log; import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.R; import com.android.internal.telephony.GsmAlphabet; -import com.android.internal.telephony.TelephonyProperties; /** * A GPS Network-initiated Handler class used by LocationManager. @@ -50,8 +49,7 @@ public class GpsNetInitiatedHandler { private static final String TAG = "GpsNetInitiatedHandler"; - private static final boolean DEBUG = true; - private static final boolean VERBOSE = false; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); // NI verify activity for bringing up UI (not used yet) public static final String ACTION_NI_VERIFY = "android.intent.action.NETWORK_INITIATED_VERIFY"; @@ -94,6 +92,9 @@ public class GpsNetInitiatedHandler { public static final int GPS_ENC_SUPL_UCS2 = 3; public static final int GPS_ENC_UNKNOWN = -1; + // Limit on SUPL NI emergency mode time extension after emergency sessions ends + private static final int MAX_EMERGENCY_MODE_EXTENSION_SECONDS = 300; // 5 minute maximum + private final Context mContext; private final TelephonyManager mTelephonyManager; private final PhoneStateListener mPhoneStateListener; @@ -109,7 +110,7 @@ public class GpsNetInitiatedHandler { private volatile boolean mIsSuplEsEnabled; // Set to true if the phone is having emergency call. - private volatile boolean mIsInEmergency; + private volatile boolean mIsInEmergencyCall; // If Location function is enabled. private volatile boolean mIsLocationEnabled = false; @@ -119,6 +120,10 @@ public class GpsNetInitiatedHandler { // Set to true if string from HAL is encoded as Hex, e.g., "3F0039" static private boolean mIsHexInput = true; + // End time of emergency call, and extension, if set + private long mCallEndElapsedRealtimeMillis = 0; + private long mEmergencyExtensionMillis = 0; + public static class GpsNiNotification { public int notificationId; @@ -146,16 +151,12 @@ public class GpsNetInitiatedHandler { if (action.equals(Intent.ACTION_NEW_OUTGOING_CALL)) { String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER); /* - Emergency Mode is when during emergency call or in emergency call back mode. - For checking if it is during emergency call: - mIsInEmergency records if the phone is in emergency call or not. It will + Tracks the emergency call: + mIsInEmergencyCall records if the phone is in emergency call or not. It will be set to true when the phone is having emergency call, and then will be set to false by mPhoneStateListener when the emergency call ends. - For checking if it is in emergency call back mode: - Emergency call back mode will be checked by reading system properties - when necessary: SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE) */ - setInEmergency(PhoneNumberUtils.isEmergencyNumber(phoneNumber)); + mIsInEmergencyCall = PhoneNumberUtils.isEmergencyNumber(phoneNumber); if (DEBUG) Log.v(TAG, "ACTION_NEW_OUTGOING_CALL - " + getInEmergency()); } else if (action.equals(LocationManager.MODE_CHANGED_ACTION)) { updateLocationMode(); @@ -195,7 +196,10 @@ public class GpsNetInitiatedHandler { if (DEBUG) Log.d(TAG, "onCallStateChanged(): state is "+ state); // listening for emergency call ends if (state == TelephonyManager.CALL_STATE_IDLE) { - setInEmergency(false); + if (mIsInEmergencyCall) { + mCallEndElapsedRealtimeMillis = SystemClock.elapsedRealtime(); + mIsInEmergencyCall = false; + } } } }; @@ -229,22 +233,35 @@ public class GpsNetInitiatedHandler { return mIsLocationEnabled; } - // Note: Currently, there are two mechanisms involved to determine if a - // phone is in emergency mode: - // 1. If the user is making an emergency call, this is provided by activly - // monitoring the outgoing phone number; - // 2. If the device is in a emergency callback state, this is provided by - // system properties. - // If either one of above exists, the phone is considered in an emergency - // mode. Because of this complexity, we need to be careful about how to set - // and clear the emergency state. - public void setInEmergency(boolean isInEmergency) { - mIsInEmergency = isInEmergency; - } - + /** + * Determines whether device is in user-initiated emergency session based on the following + * 1. If the user is making an emergency call, this is provided by actively + * monitoring the outgoing phone number; + * 2. If the user has recently ended an emergency call, and the device is in a configured time + * window after the end of that call. + * 3. If the device is in a emergency callback state, this is provided by querying + * TelephonyManager. + * @return true if is considered in user initiated emergency mode for NI purposes + */ public boolean getInEmergency() { + boolean isInEmergencyExtension = + (SystemClock.elapsedRealtime() - mCallEndElapsedRealtimeMillis) < + mEmergencyExtensionMillis; boolean isInEmergencyCallback = mTelephonyManager.getEmergencyCallbackMode(); - return mIsInEmergency || isInEmergencyCallback; + return mIsInEmergencyCall || isInEmergencyCallback || isInEmergencyExtension; + } + + public void setEmergencyExtensionSeconds(int emergencyExtensionSeconds) { + if (emergencyExtensionSeconds > MAX_EMERGENCY_MODE_EXTENSION_SECONDS) { + Log.w(TAG, "emergencyExtensionSeconds " + emergencyExtensionSeconds + + " too high, reset to " + MAX_EMERGENCY_MODE_EXTENSION_SECONDS); + emergencyExtensionSeconds = MAX_EMERGENCY_MODE_EXTENSION_SECONDS; + } else if (emergencyExtensionSeconds < 0) { + Log.w(TAG, "emergencyExtensionSeconds " + emergencyExtensionSeconds + + " is negative, reset to zero."); + emergencyExtensionSeconds = 0; + } + mEmergencyExtensionMillis = TimeUnit.SECONDS.toMillis(emergencyExtensionSeconds); } diff --git a/packages/CarSystemUI/res/values/config.xml b/packages/CarSystemUI/res/values/config.xml index c527711f563f..2e05c382a35e 100644 --- a/packages/CarSystemUI/res/values/config.xml +++ b/packages/CarSystemUI/res/values/config.xml @@ -32,7 +32,7 @@ SystemUi b/c it can't be overlayed at this level for now --> <string-array name="config_systemUIServiceComponents" translatable="false"> - <item>com.android.systemui.Dependency</item> + <item>com.android.systemui.Dependency$DependencyCreator</item> <item>com.android.systemui.util.NotificationChannels</item> <item>com.android.systemui.statusbar.CommandQueue$CommandQueueStart</item> <item>com.android.systemui.keyguard.KeyguardViewMediator</item> diff --git a/packages/CompanionDeviceManager/AndroidManifest.xml b/packages/CompanionDeviceManager/AndroidManifest.xml index 0be71e6d17b9..42885e8193a7 100644 --- a/packages/CompanionDeviceManager/AndroidManifest.xml +++ b/packages/CompanionDeviceManager/AndroidManifest.xml @@ -25,7 +25,7 @@ <uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> - <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> + <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/> diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java index 133d8ba8357b..54087d1c67ef 100644 --- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java +++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java @@ -294,7 +294,7 @@ public class Assistant extends NotificationAssistantService { synchronized (mkeyToImpressions) { ChannelImpressions ci = mkeyToImpressions.getOrDefault(key, createChannelImpressionsWithThresholds()); - if (stats.hasSeen()) { + if (stats != null && stats.hasSeen()) { ci.incrementViews(); updatedImpressions = true; } diff --git a/packages/ExternalStorageProvider/tests/Android.bp b/packages/ExternalStorageProvider/tests/Android.bp index 83427d4ebf00..04cf01af073a 100644 --- a/packages/ExternalStorageProvider/tests/Android.bp +++ b/packages/ExternalStorageProvider/tests/Android.bp @@ -14,7 +14,7 @@ android_test { ], static_libs: [ - "android-support-test", + "androidx.test.rules", "mockito-target", "truth-prebuilt", ], diff --git a/packages/ExternalStorageProvider/tests/AndroidManifest.xml b/packages/ExternalStorageProvider/tests/AndroidManifest.xml index 58b6e86dfc77..f1a6af08ec4c 100644 --- a/packages/ExternalStorageProvider/tests/AndroidManifest.xml +++ b/packages/ExternalStorageProvider/tests/AndroidManifest.xml @@ -6,7 +6,7 @@ <uses-library android:name="android.test.runner" /> </application> - <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="com.android.externalstorage" android:label="ExternalStorageProvider Tests" /> </manifest> diff --git a/packages/ExternalStorageProvider/tests/AndroidTest.xml b/packages/ExternalStorageProvider/tests/AndroidTest.xml index e5fa73f59836..f8438b22b603 100644 --- a/packages/ExternalStorageProvider/tests/AndroidTest.xml +++ b/packages/ExternalStorageProvider/tests/AndroidTest.xml @@ -23,7 +23,7 @@ <option name="test-tag" value="ExternalStorageProviderTests" /> <test class="com.android.tradefed.testtype.AndroidJUnitTest" > <option name="package" value="com.android.externalstorage.tests" /> - <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" /> + <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> <option name="hidden-api-checks" value="false"/> </test> </configuration> diff --git a/packages/ExternalStorageProvider/tests/src/com/android/externalstorage/ExternalStorageProviderTest.java b/packages/ExternalStorageProvider/tests/src/com/android/externalstorage/ExternalStorageProviderTest.java index a88b3e146ea1..fbf2e4b8ff19 100644 --- a/packages/ExternalStorageProvider/tests/src/com/android/externalstorage/ExternalStorageProviderTest.java +++ b/packages/ExternalStorageProvider/tests/src/com/android/externalstorage/ExternalStorageProviderTest.java @@ -23,8 +23,9 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import android.content.pm.ProviderInfo; -import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/packages/SettingsLib/tests/integ/Android.mk b/packages/SettingsLib/tests/integ/Android.mk index c893b6dcffbf..4a814df1dfff 100644 --- a/packages/SettingsLib/tests/integ/Android.mk +++ b/packages/SettingsLib/tests/integ/Android.mk @@ -31,8 +31,8 @@ LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_USE_AAPT2 := true LOCAL_STATIC_JAVA_LIBRARIES := \ - android-support-test \ - espresso-core \ + androidx.test.rules \ + androidx.test.espresso.core \ mockito-target-minus-junit4 \ truth-prebuilt diff --git a/packages/SettingsLib/tests/integ/AndroidManifest.xml b/packages/SettingsLib/tests/integ/AndroidManifest.xml index e8e0b41ffd41..da808dd54141 100644 --- a/packages/SettingsLib/tests/integ/AndroidManifest.xml +++ b/packages/SettingsLib/tests/integ/AndroidManifest.xml @@ -31,7 +31,7 @@ <activity android:name=".drawer.SettingsDrawerActivityTest$TestActivity"/> </application> - <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="com.android.settingslib" android:label="Tests for SettingsLib"> </instrumentation> diff --git a/packages/SettingsLib/tests/integ/AndroidTest.xml b/packages/SettingsLib/tests/integ/AndroidTest.xml index d7ee618207a8..b5d09475269e 100644 --- a/packages/SettingsLib/tests/integ/AndroidTest.xml +++ b/packages/SettingsLib/tests/integ/AndroidTest.xml @@ -22,7 +22,7 @@ <option name="test-tag" value="SettingsLibTests" /> <test class="com.android.tradefed.testtype.AndroidJUnitTest" > <option name="package" value="com.android.settingslib" /> - <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" /> + <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> <option name="hidden-api-checks" value="false"/> </test> </configuration> diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/bluetooth/BluetoothEventManagerIntegTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/bluetooth/BluetoothEventManagerIntegTest.java index d0ab46a2f30d..50f5b9d81000 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/bluetooth/BluetoothEventManagerIntegTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/bluetooth/BluetoothEventManagerIntegTest.java @@ -16,15 +16,10 @@ package com.android.settingslib.bluetooth; -import static com.google.common.truth.Truth.assertThat; - -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; -import static java.util.concurrent.TimeUnit.SECONDS; - import android.app.ActivityManager; import android.content.Context; import android.content.Intent; @@ -32,15 +27,18 @@ import android.content.pm.UserInfo; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import static java.util.concurrent.TimeUnit.SECONDS; + import java.util.concurrent.CountDownLatch; /** diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawable/UserIconDrawableTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawable/UserIconDrawableTest.java index 3fa2ce5f8312..a436cb515bb8 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawable/UserIconDrawableTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawable/UserIconDrawableTest.java @@ -27,8 +27,9 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.PorterDuff; import android.graphics.PorterDuff.Mode; -import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; import com.android.settingslib.R; diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java index dddfa7a3a9b4..08484bceb1fb 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java @@ -1,26 +1,29 @@ package com.android.settingslib.graph; +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyFloat; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Rect; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + import com.android.settingslib.R; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import static com.google.common.truth.Truth.assertThat; -import static junit.framework.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyFloat; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; - @SmallTest @RunWith(AndroidJUnit4.class) public class BatteryMeterDrawableBaseTest { diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/inputmethod/InputMethodPreferenceTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/inputmethod/InputMethodPreferenceTest.java index 93b038e07b51..9962e1ca438a 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/inputmethod/InputMethodPreferenceTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/inputmethod/InputMethodPreferenceTest.java @@ -20,12 +20,13 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodSubtype; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + import org.junit.Test; import org.junit.runner.RunWith; diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/inputmethod/InputMethodSubtypePreferenceTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/inputmethod/InputMethodSubtypePreferenceTest.java index e591d8cac9f2..f1c0beae0dc0 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/inputmethod/InputMethodSubtypePreferenceTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/inputmethod/InputMethodSubtypePreferenceTest.java @@ -16,11 +16,12 @@ package com.android.settingslib.inputmethod; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; import android.text.TextUtils; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + import org.junit.Test; import org.junit.runner.RunWith; diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/UserManagerHelperTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/UserManagerHelperTest.java index 54510b27e58d..46557d3106af 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/UserManagerHelperTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/UserManagerHelperTest.java @@ -18,7 +18,6 @@ package com.android.settingslib.users; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -33,8 +32,9 @@ import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.UserHandle; import android.os.UserManager; -import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/NetworkPolicyEditorTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/NetworkPolicyEditorTest.java index ee03d5024351..37f2600e9812 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/NetworkPolicyEditorTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/NetworkPolicyEditorTest.java @@ -16,19 +16,22 @@ package com.android.settingslib.utils; +import static junit.framework.Assert.assertEquals; + import android.net.NetworkPolicy; import android.net.NetworkPolicyManager; import android.net.NetworkTemplate; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + import com.android.settingslib.NetworkPolicyEditor; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import static junit.framework.Assert.assertEquals; - @RunWith(AndroidJUnit4.class) @SmallTest public class NetworkPolicyEditorTest { diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/ZoneGetterTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/ZoneGetterTest.java index 0ec75ecee066..ff8dbda360fc 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/ZoneGetterTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/ZoneGetterTest.java @@ -15,21 +15,23 @@ */ package com.android.settingslib.utils; +import static junit.framework.Assert.assertTrue; + import android.content.Context; -import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; -import android.support.test.filters.SmallTest; import android.text.Spanned; import android.text.style.TtsSpan; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.settingslib.datetime.ZoneGetter; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import java.util.*; -import com.android.settingslib.datetime.ZoneGetter; - -import static junit.framework.Assert.assertTrue; @RunWith(AndroidJUnit4.class) @SmallTest diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java index 032479990cae..fc3034efc08b 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java @@ -22,7 +22,6 @@ import static org.junit.Assert.fail; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -44,12 +43,12 @@ import android.net.wifi.hotspot2.pps.HomeSp; import android.os.Bundle; import android.os.Parcelable; import android.os.SystemClock; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; import android.text.SpannableString; import android.text.format.DateUtils; -import android.text.style.TtsSpan; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; import com.android.settingslib.R; import com.android.settingslib.utils.ThreadUtils; diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java index 1860b31081e1..42eb0b940938 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java @@ -53,9 +53,10 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.SystemClock; import android.provider.Settings; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; import com.android.settingslib.utils.ThreadUtils; @@ -79,7 +80,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; // TODO(sghuman): Change these to robolectric tests b/35766684. - @SmallTest @RunWith(AndroidJUnit4.class) public class WifiTrackerTest { diff --git a/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java b/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java index 8e8d9f741a81..abe82a885a94 100644 --- a/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java +++ b/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java @@ -18,7 +18,7 @@ package com.android.simappdialog; import android.app.Activity; import android.content.Intent; import android.os.Bundle; -import android.os.SystemProperties; +import android.sysprop.SetupWizardProperties; import android.text.TextUtils; import android.view.View; import android.widget.Button; @@ -51,7 +51,7 @@ public class InstallCarrierAppActivity extends Activity implements View.OnClickL // Setup theme for aosp/pixel setTheme( WizardManagerHelper.getThemeRes( - SystemProperties.get("setupwizard.theme"), + SetupWizardProperties.theme().orElse(""), R.style.SuwThemeGlif_Light ) ); diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java index 6135aebb0587..ac6904300f71 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java @@ -36,6 +36,13 @@ public interface ClockPlugin extends Plugin { View getView(); /** + * Get clock view for a large clock that appears behind NSSL. + */ + default View getBigClockView() { + return null; + } + + /** * Set clock paint style. * @param style The new style to set in the paint. */ diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml index ed18dc728402..4e0cbe093c49 100644 --- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml +++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml @@ -24,13 +24,14 @@ android:layout_gravity="@integer/notification_panel_layout_gravity" android:background="@android:color/transparent" android:baselineAligned="false" - android:clickable="false" + android:clickable="true" android:clipChildren="false" android:clipToPadding="false" android:paddingTop="0dp" android:paddingEnd="0dp" android:paddingStart="0dp" - android:elevation="4dp" > + android:elevation="4dp" + android:importantForAccessibility="no" > <include layout="@layout/quick_status_bar_header_system_icons" /> diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index 2674f07c21e4..75c0ec3ced43 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -25,6 +25,12 @@ android:layout_height="match_parent" android:background="@android:color/transparent" > + <FrameLayout + android:id="@+id/big_clock_container" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:visibility="gone" /> + <include layout="@layout/keyguard_status_view" android:visibility="gone" /> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java index 22a23a8f8a21..570d351a8b71 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java @@ -35,7 +35,11 @@ public class KeyguardClockSwitch extends RelativeLayout { /** * Frame for default and custom clock. */ - private FrameLayout mClockFrame; + private FrameLayout mSmallClockFrame; + /** + * Container for big custom clock. + */ + private ViewGroup mBigClockContainer; /** * Status area (date and other stuff) shown below the clock. Plugin can decide whether * or not to show it below the alternate clock. @@ -46,22 +50,27 @@ public class KeyguardClockSwitch extends RelativeLayout { new PluginListener<ClockPlugin>() { @Override public void onPluginConnected(ClockPlugin plugin, Context pluginContext) { - View view = plugin.getView(); - if (view != null) { - disconnectPlugin(); + disconnectPlugin(); + View smallClockView = plugin.getView(); + if (smallClockView != null) { // For now, assume that the most recently connected plugin is the // selected clock face. In the future, the user should be able to // pick a clock face from the available plugins. - mClockPlugin = plugin; - mClockFrame.addView(view, -1, + mSmallClockFrame.addView(smallClockView, -1, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); initPluginParams(); mClockView.setVisibility(View.GONE); - if (!plugin.shouldShowStatusArea()) { - mKeyguardStatusArea.setVisibility(View.GONE); - } } + View bigClockView = plugin.getBigClockView(); + if (bigClockView != null && mBigClockContainer != null) { + mBigClockContainer.addView(bigClockView); + mBigClockContainer.setVisibility(View.VISIBLE); + } + if (!plugin.shouldShowStatusArea()) { + mKeyguardStatusArea.setVisibility(View.GONE); + } + mClockPlugin = plugin; } @Override @@ -86,7 +95,7 @@ public class KeyguardClockSwitch extends RelativeLayout { protected void onFinishInflate() { super.onFinishInflate(); mClockView = findViewById(R.id.default_clock_view); - mClockFrame = findViewById(R.id.clock_view); + mSmallClockFrame = findViewById(R.id.clock_view); mKeyguardStatusArea = findViewById(R.id.keyguard_status_area); } @@ -104,6 +113,20 @@ public class KeyguardClockSwitch extends RelativeLayout { } /** + * Set container for big clock face appearing behind NSSL and KeyguardStatusView. + */ + public void setBigClockContainer(ViewGroup container) { + if (mClockPlugin != null && container != null) { + View bigClockView = mClockPlugin.getBigClockView(); + if (bigClockView != null) { + container.addView(bigClockView); + container.setVisibility(View.VISIBLE); + } + } + mBigClockContainer = container; + } + + /** * It will also update plugin setStyle if plugin is connected. */ public void setStyle(Style style) { @@ -199,9 +222,13 @@ public class KeyguardClockSwitch extends RelativeLayout { private void disconnectPlugin() { if (mClockPlugin != null) { - View view = mClockPlugin.getView(); - if (view != null) { - mClockFrame.removeView(view); + View smallClockView = mClockPlugin.getView(); + if (smallClockView != null) { + mSmallClockFrame.removeView(smallClockView); + } + if (mBigClockContainer != null) { + mBigClockContainer.removeAllViews(); + mBigClockContainer.setVisibility(View.GONE); } mClockPlugin = null; } diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index 6b4d07a44d34..443e389b1d02 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -220,6 +220,7 @@ public class Dependency extends SystemUI { @Inject Lazy<FragmentService> mFragmentService; @Inject Lazy<ExtensionController> mExtensionController; @Inject Lazy<PluginDependencyProvider> mPluginDependencyProvider; + @Nullable @Inject Lazy<LocalBluetoothManager> mLocalBluetoothManager; @Inject Lazy<VolumeDialogController> mVolumeDialogController; @Inject Lazy<MetricsLogger> mMetricsLogger; diff --git a/packages/SystemUI/src/com/android/systemui/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/DependencyProvider.java index b11e189e3a9c..3ca7b971a468 100644 --- a/packages/SystemUI/src/com/android/systemui/DependencyProvider.java +++ b/packages/SystemUI/src/com/android/systemui/DependencyProvider.java @@ -415,6 +415,7 @@ public class DependencyProvider { @Singleton @Provides + @Nullable public LocalBluetoothManager provideLocalBluetoothController(Context context, @Named(BG_HANDLER_NAME) Handler bgHandler) { return LocalBluetoothManager.create(context, bgHandler, diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java index 52d1260b4221..af6ee1f4179a 100644 --- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java @@ -57,21 +57,13 @@ public class AppOpsControllerImpl implements AppOpsController, @GuardedBy("mNotedItems") private final List<AppOpItem> mNotedItems = new ArrayList<>(); - protected static final int[] OPS; - protected static final String[] OPS_STRING = new String[] { - AppOpsManager.OPSTR_CAMERA, - AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW, - AppOpsManager.OPSTR_RECORD_AUDIO, - AppOpsManager.OPSTR_COARSE_LOCATION, - AppOpsManager.OPSTR_FINE_LOCATION}; - - static { - int numOps = OPS_STRING.length; - OPS = new int[numOps]; - for (int i = 0; i < numOps; i++) { - OPS[i] = AppOpsManager.strOpToOp(OPS_STRING[i]); - } - } + protected static final int[] OPS = new int[] { + AppOpsManager.OP_CAMERA, + AppOpsManager.OP_SYSTEM_ALERT_WINDOW, + AppOpsManager.OP_RECORD_AUDIO, + AppOpsManager.OP_COARSE_LOCATION, + AppOpsManager.OP_FINE_LOCATION + }; public AppOpsControllerImpl(Context context, Looper bgLooper) { mContext = context; @@ -92,7 +84,7 @@ public class AppOpsControllerImpl implements AppOpsController, protected void setListening(boolean listening) { if (listening) { mAppOps.startWatchingActive(OPS, this); - mAppOps.startWatchingNoted(OPS_STRING, this); + mAppOps.startWatchingNoted(OPS, this); } else { mAppOps.stopWatchingActive(this); mAppOps.stopWatchingNoted(this); @@ -254,14 +246,13 @@ public class AppOpsControllerImpl implements AppOpsController, } @Override - public void onOpNoted(String code, int uid, String packageName, int result) { + public void onOpNoted(int code, int uid, String packageName, int result) { if (DEBUG) { Log.w(TAG, "Op: " + code + " with result " + AppOpsManager.MODE_NAMES[result]); } if (result != AppOpsManager.MODE_ALLOWED) return; - int op_code = AppOpsManager.strOpToOp(code); - addNoted(op_code, uid, packageName); - notifySuscribers(op_code, uid, packageName, true); + addNoted(code, uid, packageName); + notifySuscribers(code, uid, packageName, true); } private void notifySuscribers(int code, int uid, String packageName, boolean active) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java index 8903a38dc600..aba9bb804619 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java @@ -272,10 +272,17 @@ public class QSFooterImpl extends FrameLayout implements QSFooter, public void updateEverything() { post(() -> { updateVisibilities(); + updateClickabilities(); setClickable(false); }); } + private void updateClickabilities() { + mMultiUserSwitch.setClickable(mMultiUserSwitch.getVisibility() == View.VISIBLE); + mEdit.setClickable(mEdit.getVisibility() == View.VISIBLE); + mSettingsButton.setClickable(mSettingsButton.getVisibility() == View.VISIBLE); + } + private void updateVisibilities() { mSettingsContainer.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE); mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility( diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index f2f83c0e0aa5..bec027f902a0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -426,7 +426,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements if (mExpanded == expanded) return; mExpanded = expanded; mHeaderQsPanel.setExpanded(expanded); - updateEverything(); } /** @@ -698,10 +697,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements .start(); } - public void updateEverything() { - post(() -> setClickable(false)); - } - public void setQSPanel(final QSPanel qsPanel) { mQsPanel = qsPanel; setupHost(qsPanel.getHost()); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java index 7876aa5d89d0..dd07ec4c27dd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.phone; +import static com.android.systemui.statusbar.phone.NavBarTintController.DEFAULT_COLOR_ADAPT_TRANSITION_TIME; import static com.android.systemui.statusbar.phone.NavBarTintController.MIN_COLOR_ADAPT_TRANSITION_TIME; import static com.android.systemui.statusbar.phone.NavBarTintController.NAV_COLOR_TRANSITION_TIME_SETTING; @@ -161,7 +162,7 @@ public class LightBarTransitionsController implements Dumpable, Callbacks, public long getTintAnimationDuration() { if (NavBarTintController.isEnabled(mContext)) { return Math.max(Settings.Global.getInt(mContext.getContentResolver(), - NAV_COLOR_TRANSITION_TIME_SETTING, DEFAULT_TINT_ANIMATION_DURATION), + NAV_COLOR_TRANSITION_TIME_SETTING, DEFAULT_COLOR_ADAPT_TRANSITION_TIME), MIN_COLOR_ADAPT_TRANSITION_TIME); } return DEFAULT_TINT_ANIMATION_DURATION; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java index 9ecee1825f07..b4f850b033e8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java @@ -31,6 +31,7 @@ import android.view.SurfaceControl; public class NavBarTintController { public static final String NAV_COLOR_TRANSITION_TIME_SETTING = "navbar_color_adapt_transition"; public static final int MIN_COLOR_ADAPT_TRANSITION_TIME = 400; + public static final int DEFAULT_COLOR_ADAPT_TRANSITION_TIME = 1500; private final HandlerThread mColorAdaptHandlerThread = new HandlerThread("ColorExtractThread"); private Handler mColorAdaptionHandler; 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 c7e4d340b7d8..c0909e3e5bd2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -53,6 +53,7 @@ import android.widget.FrameLayout; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.keyguard.KeyguardClockSwitch; import com.android.keyguard.KeyguardStatusView; import com.android.systemui.DejankUtils; import com.android.systemui.Dependency; @@ -133,7 +134,7 @@ public class NotificationPanelView extends PanelView implements public static final int FLING_COLLAPSE = 1; /** - * Fing until QS is completely hidden. + * Fling until QS is completely hidden. */ public static final int FLING_HIDE = 2; @@ -359,6 +360,10 @@ public class NotificationPanelView extends PanelView implements mKeyguardStatusBar = findViewById(R.id.keyguard_header); mKeyguardStatusView = findViewById(R.id.keyguard_status_view); + KeyguardClockSwitch keyguardClockSwitch = findViewById(R.id.keyguard_clock_container); + ViewGroup bigClockContainer = findViewById(R.id.big_clock_container); + keyguardClockSwitch.setBigClockContainer(bigClockContainer); + mNotificationContainerParent = findViewById(R.id.notification_container_parent); mNotificationStackScroller = findViewById(R.id.notification_stack_scroller); mNotificationStackScroller.setOnHeightChangedListener(this); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java index fb2ceac4b810..415060244243 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java @@ -107,6 +107,25 @@ public class KeyguardClockSwitchTest extends SysuiTestCase { } @Test + public void onPluginConnected_showPluginBigClock() { + // GIVEN that the container for the big clock has visibility GONE + FrameLayout bigClockContainer = new FrameLayout(getContext()); + bigClockContainer.setVisibility(GONE); + mKeyguardClockSwitch.setBigClockContainer(bigClockContainer); + // AND the plugin returns a view for the big clock + ClockPlugin plugin = mock(ClockPlugin.class); + TextClock pluginView = new TextClock(getContext()); + when(plugin.getBigClockView()).thenReturn(pluginView); + PluginListener listener = mKeyguardClockSwitch.getClockPluginListener(); + // WHEN the plugin is connected + listener.onPluginConnected(plugin, null); + // THEN the big clock container is visible and it is the parent of the + // big clock view. + assertThat(bigClockContainer.getVisibility()).isEqualTo(VISIBLE); + assertThat(pluginView.getParent()).isEqualTo(bigClockContainer); + } + + @Test public void onPluginConnected_nullView() { ClockPlugin plugin = mock(ClockPlugin.class); PluginListener listener = mKeyguardClockSwitch.getClockPluginListener(); @@ -146,6 +165,26 @@ public class KeyguardClockSwitchTest extends SysuiTestCase { } @Test + public void onPluginDisconnected_hidePluginBigClock() { + // GIVEN that the big clock container is visible + FrameLayout bigClockContainer = new FrameLayout(getContext()); + bigClockContainer.setVisibility(VISIBLE); + mKeyguardClockSwitch.setBigClockContainer(bigClockContainer); + // AND the plugin returns a view for the big clock + ClockPlugin plugin = mock(ClockPlugin.class); + TextClock pluginView = new TextClock(getContext()); + when(plugin.getBigClockView()).thenReturn(pluginView); + PluginListener listener = mKeyguardClockSwitch.getClockPluginListener(); + listener.onPluginConnected(plugin, null); + // WHEN the plugin is disconnected + listener.onPluginDisconnected(plugin); + // THEN the big lock container is GONE and the big clock view doesn't have + // a parent. + assertThat(bigClockContainer.getVisibility()).isEqualTo(GONE); + assertThat(pluginView.getParent()).isNull(); + } + + @Test public void onPluginDisconnected_nullView() { ClockPlugin plugin = mock(ClockPlugin.class); PluginListener listener = mKeyguardClockSwitch.getClockPluginListener(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java index bb445483c966..2582946333c0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java @@ -86,7 +86,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mCallback); mController.onOpActiveChanged( AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); - mController.onOpNoted(AppOpsManager.OPSTR_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, + mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, AppOpsManager.MODE_ALLOWED); verify(mCallback).onActiveStateChanged(AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); @@ -136,7 +136,7 @@ public class AppOpsControllerTest extends SysuiTestCase { TEST_UID, TEST_PACKAGE_NAME, true); mController.onOpActiveChanged(AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, true); - mController.onOpNoted(AppOpsManager.OPSTR_FINE_LOCATION, + mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, AppOpsManager.MODE_ALLOWED); assertEquals(3, mController.getActiveAppOps().size()); } @@ -147,7 +147,7 @@ public class AppOpsControllerTest extends SysuiTestCase { TEST_UID, TEST_PACKAGE_NAME, true); mController.onOpActiveChanged(AppOpsManager.OP_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); - mController.onOpNoted(AppOpsManager.OPSTR_FINE_LOCATION, + mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, AppOpsManager.MODE_ALLOWED); assertEquals(2, mController.getActiveAppOpsForUser(UserHandle.getUserId(TEST_UID)).size()); @@ -158,7 +158,7 @@ public class AppOpsControllerTest extends SysuiTestCase { @Test public void opNotedScheduledForRemoval() { mController.setBGHandler(mMockHandler); - mController.onOpNoted(AppOpsManager.OPSTR_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, + mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, AppOpsManager.MODE_ALLOWED); verify(mMockHandler).scheduleRemoval(any(AppOpItem.class), anyLong()); } diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java index e8820ae4e32a..0b3fa0269bd3 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java @@ -20,7 +20,6 @@ import static android.Manifest.permission.MANAGE_CONTENT_CAPTURE; import static android.content.Context.CONTENT_CAPTURE_MANAGER_SERVICE; import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManagerInternal; import android.content.ComponentName; @@ -34,7 +33,6 @@ import android.os.ShellCallback; import android.os.UserHandle; import android.os.UserManager; import android.util.Slog; -import android.view.contentcapture.ContentCaptureContext; import android.view.contentcapture.IContentCaptureManager; import com.android.internal.annotations.GuardedBy; @@ -164,8 +162,7 @@ public final class ContentCaptureManagerService extends @Override public void startSession(@UserIdInt int userId, @NonNull IBinder activityToken, - @NonNull ComponentName componentName, @NonNull String sessionId, - @Nullable ContentCaptureContext clientContext, int flags, + @NonNull ComponentName componentName, @NonNull String sessionId, int flags, @NonNull IResultReceiver result) { Preconditions.checkNotNull(activityToken); Preconditions.checkNotNull(componentName); @@ -175,14 +172,13 @@ public final class ContentCaptureManagerService extends // so we don't pass it on startSession (same for Autofill) final int taskId = getAmInternal().getTaskIdForActivity(activityToken, false); - // TODO(b/111276913): get from AM as well + // TODO(b/121260224): get from AM as well final int displayId = 0; synchronized (mLock) { final ContentCapturePerUserService service = getServiceForUserLocked(userId); service.startSessionLocked(activityToken, componentName, taskId, displayId, - sessionId, Binder.getCallingUid(), clientContext, flags, - mAllowInstantService, result); + sessionId, Binder.getCallingUid(), flags, mAllowInstantService, result); } } diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java index f21b0d810411..03257e3e8514 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java @@ -24,7 +24,6 @@ import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUC import android.Manifest; import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.AppGlobals; import android.app.assist.AssistContent; @@ -39,7 +38,6 @@ import android.os.RemoteException; import android.service.contentcapture.SnapshotData; import android.util.ArrayMap; import android.util.Slog; -import android.view.contentcapture.ContentCaptureContext; import android.view.contentcapture.ContentCaptureSession; import com.android.internal.annotations.GuardedBy; @@ -114,8 +112,8 @@ final class ContentCapturePerUserService @GuardedBy("mLock") public void startSessionLocked(@NonNull IBinder activityToken, @NonNull ComponentName componentName, int taskId, int displayId, - @NonNull String sessionId, int uid, @Nullable ContentCaptureContext clientContext, - int flags, boolean bindInstantServiceAllowed, @NonNull IResultReceiver clientReceiver) { + @NonNull String sessionId, int uid, int flags, boolean bindInstantServiceAllowed, + @NonNull IResultReceiver clientReceiver) { if (!isEnabledLocked()) { setClientState(clientReceiver, ContentCaptureSession.STATE_DISABLED, /* binder=*/ null); return; @@ -142,7 +140,7 @@ final class ContentCapturePerUserService final ContentCaptureServerSession newSession = new ContentCaptureServerSession(getContext(), mUserId, mLock, activityToken, this, serviceComponentName, componentName, taskId, - displayId, sessionId, uid, clientContext, flags, bindInstantServiceAllowed, + displayId, sessionId, uid, flags, bindInstantServiceAllowed, mMaster.verbose); if (mMaster.verbose) { Slog.v(TAG, "startSession(): new session for " diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java index ba98b95082f7..f59636b92278 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java @@ -16,7 +16,6 @@ package com.android.server.contentcapture; import android.annotation.NonNull; -import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; import android.os.IBinder; @@ -56,8 +55,7 @@ final class ContentCaptureServerSession implements ContentCaptureServiceCallback ContentCaptureServerSession(@NonNull Context context, int userId, @NonNull Object lock, @NonNull IBinder activityToken, @NonNull ContentCapturePerUserService service, @NonNull ComponentName serviceComponentName, @NonNull ComponentName appComponentName, - int taskId, int displayId, @NonNull String sessionId, int uid, - @Nullable ContentCaptureContext clientContext, int flags, + int taskId, int displayId, @NonNull String sessionId, int uid, int flags, boolean bindInstantServiceAllowed, boolean verbose) { mLock = lock; mActivityToken = activityToken; @@ -67,8 +65,8 @@ final class ContentCaptureServerSession implements ContentCaptureServiceCallback mRemoteService = new RemoteContentCaptureService(context, ContentCaptureService.SERVICE_INTERFACE, serviceComponentName, userId, this, bindInstantServiceAllowed, verbose); - mContentCaptureContext = new ContentCaptureContext(clientContext, appComponentName, taskId, - displayId, flags); + mContentCaptureContext = new ContentCaptureContext(/* clientContext= */ null, + appComponentName, taskId, displayId, flags); } /** diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 7adcabac26ee..2a806447d605 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -129,6 +129,7 @@ import android.util.TimeUtils; import android.util.Xml; import com.android.internal.annotations.GuardedBy; +import com.android.internal.app.IAppOpsCallback; import com.android.internal.app.IAppOpsService; import com.android.internal.os.AppFuseMount; import com.android.internal.os.BackgroundThread; @@ -1709,6 +1710,10 @@ class StorageManagerService extends IStorageManager.Stub ServiceManager.getService("package")); mIAppOpsService = IAppOpsService.Stub.asInterface( ServiceManager.getService(Context.APP_OPS_SERVICE)); + try { + mIAppOpsService.startWatchingMode(OP_REQUEST_INSTALL_PACKAGES, null, mAppOpsCallback); + } catch (RemoteException e) { + } mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget(); } @@ -3240,6 +3245,15 @@ class StorageManagerService extends IStorageManager.Stub } } + private IAppOpsCallback.Stub mAppOpsCallback = new IAppOpsCallback.Stub() { + @Override + public void opChanged(int op, int uid, String packageName) throws RemoteException { + if (!ENABLE_ISOLATED_STORAGE) return; + + remountUidExternalStorage(uid, getMountMode(uid, packageName)); + } + }; + private static final Pattern PATTERN_TRANSLATE = Pattern.compile( "(?i)^(/storage/[^/]+/(?:[0-9]+/)?)(.*)"); diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index 29e1878b739a..0f060fe09318 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -642,6 +642,17 @@ public class GnssLocationProvider extends AbstractLocationProvider implements Log.e(TAG, "unable to parse SUPL_ES: " + suplESProperty); } } + + String emergencyExtensionSecondsString + = properties.getProperty("ES_EXTENSION_SEC", "0"); + try { + int emergencyExtensionSeconds = + Integer.parseInt(emergencyExtensionSecondsString); + mNIHandler.setEmergencyExtensionSeconds(emergencyExtensionSeconds); + } catch (NumberFormatException e) { + Log.e(TAG, "unable to parse ES_EXTENSION_SEC: " + + emergencyExtensionSecondsString); + } } private void loadPropertiesFromResource(Context context, diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 2359c2a02863..d961bad1cf59 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -4939,7 +4939,7 @@ public class NotificationManagerService extends SystemService { Slog.e(TAG, "Not posting notification without small icon: " + notification); if (old != null && !old.isCanceled) { mListeners.notifyRemovedLocked(r, - NotificationListenerService.REASON_ERROR, null); + NotificationListenerService.REASON_ERROR, r.getStats()); mHandler.post(new Runnable() { @Override public void run() { diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java index 7ae2271adb19..3a7919a0d9ba 100644 --- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java +++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java @@ -120,7 +120,7 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { android.Manifest.permission.INTERACT_ACROSS_PROFILES, callingUid, -1, true); if (permissionFlag != PackageManager.PERMISSION_GRANTED - || !mInjector.getUserManager().isSameProfileGroup(callerUserId, userId)) { + || !isSameProfileGroup(callerUserId, userId)) { throw new SecurityException("Attempt to launch activity without required " + android.Manifest.permission.INTERACT_ACROSS_PROFILES + " permission" + " or target user is not in the same profile group."); @@ -209,6 +209,15 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { } } + private boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId) { + final long ident = mInjector.clearCallingIdentity(); + try { + return mInjector.getUserManager().isSameProfileGroup(callerUserId, userId); + } finally { + mInjector.restoreCallingIdentity(ident); + } + } + /** * Verify that the given calling package is belong to the calling UID. */ diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 6453db5db1b6..90cf94c3ec86 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -20124,10 +20124,10 @@ public class PackageManagerService extends IPackageManager.Stub ContentObserver co = new ContentObserver(mHandler) { @Override public void onChange(boolean selfChange) { - boolean ephemeralFeatureDisabled = + final boolean ephemeralFeatureDisabled = Global.getInt(resolver, Global.ENABLE_EPHEMERAL_FEATURE, 1) == 0; for (int userId : UserManagerService.getInstance().getUserIds()) { - boolean instantAppsDisabledForUser = + final boolean instantAppsDisabledForUser = ephemeralFeatureDisabled || Secure.getIntForUser(resolver, Secure.INSTANT_APPS_ENABLED, 1, userId) == 0; mWebInstantAppsDisabled.put(userId, instantAppsDisabledForUser); diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index c1e9a7353fd5..fc1c65cf5807 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -49,7 +49,6 @@ import android.view.SurfaceControl; import com.android.server.policy.WindowManagerPolicy; import java.io.PrintWriter; -import java.util.Arrays; import java.util.Set; import java.util.function.Consumer; @@ -70,9 +69,9 @@ final class InputMonitor { private final UpdateInputForAllWindowsConsumer mUpdateInputForAllWindowsConsumer = new UpdateInputForAllWindowsConsumer(); - private int mDisplayId; + private final int mDisplayId; - SurfaceControl.Transaction mInputTransaction = new SurfaceControl.Transaction(); + private final SurfaceControl.Transaction mInputTransaction; /** * The set of input consumer added to the window manager by name, which consumes input events @@ -109,6 +108,7 @@ final class InputMonitor { public InputMonitor(WindowManagerService service, int displayId) { mService = service; mDisplayId = displayId; + mInputTransaction = mService.mRoot.getDisplayContent(mDisplayId).getPendingTransaction(); } private void addInputConsumer(String name, InputConsumerImpl consumer) { @@ -397,7 +397,7 @@ final class InputMonitor { wallpaperInputConsumer.show(mInputTransaction, 0); } - mInputTransaction.apply(); + dc.scheduleAnimation(); Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); } diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java index 8ec97c5117f1..d0937e9fba10 100644 --- a/services/core/java/com/android/server/wm/RootActivityContainer.java +++ b/services/core/java/com/android/server/wm/RootActivityContainer.java @@ -1519,6 +1519,13 @@ class RootActivityContainer extends ConfigurationContainer for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { final ActivityDisplay display = mActivityDisplays.get(displayNdx); for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { + // Stacks and activities could be removed while putting activities to sleep if + // the app process was gone. This prevents us getting exception by accessing an + // invalid stack index. + if (stackNdx >= display.getChildCount()) { + continue; + } + final ActivityStack stack = display.getChildAt(stackNdx); if (allowDelay) { allSleep &= stack.goToSleepIfPossible(shuttingDown); diff --git a/services/tests/servicestests/src/com/android/server/appops/AppOpsNotedWatcherTest.java b/services/tests/servicestests/src/com/android/server/appops/AppOpsNotedWatcherTest.java index 52f434db3be3..edd89f9e61d1 100644 --- a/services/tests/servicestests/src/com/android/server/appops/AppOpsNotedWatcherTest.java +++ b/services/tests/servicestests/src/com/android/server/appops/AppOpsNotedWatcherTest.java @@ -52,8 +52,8 @@ public class AppOpsNotedWatcherTest { // Try to start watching noted ops final AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class); try { - appOpsManager.startWatchingNoted(new String[]{AppOpsManager.OPSTR_FINE_LOCATION, - AppOpsManager.OPSTR_RECORD_AUDIO}, listener); + appOpsManager.startWatchingNoted(new int[]{AppOpsManager.OP_FINE_LOCATION, + AppOpsManager.OP_RECORD_AUDIO}, listener); fail("Watching noted ops shoudl require " + Manifest.permission.WATCH_APPOPS); } catch (SecurityException expected) { /*ignored*/ @@ -67,23 +67,23 @@ public class AppOpsNotedWatcherTest { // Start watching noted ops final AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class); - appOpsManager.startWatchingNoted(new String[]{AppOpsManager.OPSTR_FINE_LOCATION, - AppOpsManager.OPSTR_CAMERA}, listener); + appOpsManager.startWatchingNoted(new int[]{AppOpsManager.OP_FINE_LOCATION, + AppOpsManager.OP_CAMERA}, listener); // Note some ops - appOpsManager.noteOp(AppOpsManager.OPSTR_FINE_LOCATION, Process.myUid(), + appOpsManager.noteOp(AppOpsManager.OP_FINE_LOCATION, Process.myUid(), getContext().getPackageName()); - appOpsManager.noteOp(AppOpsManager.OPSTR_CAMERA, Process.myUid(), + appOpsManager.noteOp(AppOpsManager.OP_CAMERA, Process.myUid(), getContext().getPackageName()); // Verify that we got called for the ops being noted final InOrder inOrder = inOrder(listener); inOrder.verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS) - .times(1)).onOpNoted(eq(AppOpsManager.OPSTR_FINE_LOCATION), + .times(1)).onOpNoted(eq(AppOpsManager.OP_FINE_LOCATION), eq(Process.myUid()), eq(getContext().getPackageName()), eq(AppOpsManager.MODE_ALLOWED)); inOrder.verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS) - .times(1)).onOpNoted(eq(AppOpsManager.OPSTR_CAMERA), + .times(1)).onOpNoted(eq(AppOpsManager.OP_CAMERA), eq(Process.myUid()), eq(getContext().getPackageName()), eq(AppOpsManager.MODE_ALLOWED)); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 371e8f4db9de..83c1c7670338 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -3849,4 +3849,26 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.reportSeen(r); verify(mAppUsageStats, times(1)).reportEvent(anyString(), anyInt(), anyInt()); } + + @Test + public void testNotificationStats_notificationError() { + NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); + mService.addNotification(r); + + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, "tag", mUid, 0, + new Notification.Builder(mContext, mTestNotificationChannel.getId()).build(), + new UserHandle(mUid), null, 0); + NotificationRecord update = new NotificationRecord(mContext, sbn, mTestNotificationChannel); + mService.addEnqueuedNotification(update); + assertNull(update.sbn.getNotification().getSmallIcon()); + + NotificationManagerService.PostNotificationRunnable runnable = + mService.new PostNotificationRunnable(update.getKey()); + runnable.run(); + waitForIdle(); + + ArgumentCaptor<NotificationStats> captor = ArgumentCaptor.forClass(NotificationStats.class); + verify(mListeners).notifyRemovedLocked(any(), anyInt(), captor.capture()); + assertNotNull(captor.getValue()); + } } diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index b61e99bc6f0d..2c712a1c36e1 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -2617,8 +2617,7 @@ public class SubscriptionManager { if (availableList == null) { return null; } else { - return getAvailableSubscriptionInfoList().stream() - .filter(subInfo -> !shouldHideSubscription(subInfo)) + return availableList.stream().filter(subInfo -> !shouldHideSubscription(subInfo)) .collect(Collectors.toList()); } } diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java index ebf198702bb9..6326cc688914 100644 --- a/telephony/java/android/telephony/euicc/EuiccManager.java +++ b/telephony/java/android/telephony/euicc/EuiccManager.java @@ -61,7 +61,6 @@ public class EuiccManager { public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = "android.telephony.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS"; - /** * Broadcast Action: The eUICC OTA status is changed. * <p class="note"> @@ -87,6 +86,20 @@ public class EuiccManager { "android.telephony.euicc.action.NOTIFY_CARRIER_SETUP_INCOMPLETE"; /** + * Intent action to select a profile to enable before download a new eSIM profile. + * + * May be called during device provisioning when there are multiple slots having profiles on + * them. This Intent launches a screen for all the current existing profiles and let users to + * choose which one they want to enable. In this case, the slot contains the profile will be + * activated. + * + * @hide + */ + @SystemApi + public static final String ACTION_PROFILE_SELECTION = + "android.telephony.euicc.action.PROFILE_SELECTION"; + + /** * Intent action to provision an embedded subscription. * * <p>May be called during device provisioning to launch a screen to perform embedded SIM @@ -132,6 +145,16 @@ public class EuiccManager { public static final int EMBEDDED_SUBSCRIPTION_RESULT_ERROR = 2; /** + * Key for an extra set on the {@link #ACTION_PROVISION_EMBEDDED_SUBSCRIPTION} intent for which + * kind of activation flow will be evolved. (see {@code EUICC_ACTIVATION_}) + * + * @hide + */ + @SystemApi + public static final String EXTRA_ACTIVATION_TYPE = + "android.telephony.euicc.extra.ACTIVATION_TYPE"; + + /** * Key for an extra set on {@link PendingIntent} result callbacks providing a detailed result * code. * @@ -197,6 +220,52 @@ public class EuiccManager { public static final String META_DATA_CARRIER_ICON = "android.telephony.euicc.carriericon"; /** + * Euicc activation type which will be included in {@link #EXTRA_ACTIVATION_TYPE} and used to + * decide which kind of activation flow should be lauched. + * + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"EUICC_ACTIVATION_"}, value = { + EUICC_ACTIVATION_TYPE_DEFAULT, + EUICC_ACTIVATION_TYPE_BACKUP, + EUICC_ACTIVATION_TYPE_TRANSFER + + }) + public @interface EuiccActivationType{} + + + /** + * The default euicc activation type which includes checking server side and downloading the + * profile based on carrier's download configuration. + * + * @hide + */ + @SystemApi + public static final int EUICC_ACTIVATION_TYPE_DEFAULT = 1; + + /** + * The euicc activation type used when the default download process failed. LPA will start the + * backup flow and try to download the profile for the carrier. + * + * @hide + */ + @SystemApi + public static final int EUICC_ACTIVATION_TYPE_BACKUP = 2; + + /** + * The activation flow of eSIM seamless transfer will be used. LPA will start normal eSIM + * activation flow and if it's failed, the name of the carrier selected will be recorded. After + * the future device pairing, LPA will contact this carrier to transfer it from the other device + * to this device. + * + * @hide + */ + @SystemApi + public static final int EUICC_ACTIVATION_TYPE_TRANSFER = 3; + + + /** * Euicc OTA update status which can be got by {@link #getOtaStatus} * @hide */ @@ -336,7 +405,7 @@ public class EuiccManager { } try { getIEuiccController().downloadSubscription(subscription, switchAfterDownload, - mContext.getOpPackageName(), callbackIntent); + mContext.getOpPackageName(), null /* resolvedBundle */, callbackIntent); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl index 0a0ad90b5954..870a689f85b1 100644 --- a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl +++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl @@ -32,7 +32,7 @@ interface IEuiccController { String getEid(); int getOtaStatus(); oneway void downloadSubscription(in DownloadableSubscription subscription, - boolean switchAfterDownload, String callingPackage, in PendingIntent callbackIntent); + boolean switchAfterDownload, String callingPackage, in Bundle resolvedBundle, in PendingIntent callbackIntent); EuiccInfo getEuiccInfo(); oneway void deleteSubscription(int subscriptionId, String callingPackage, in PendingIntent callbackIntent); diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp index 703a67b791be..5725f0cdae6e 100644 --- a/tools/stats_log_api_gen/Android.bp +++ b/tools/stats_log_api_gen/Android.bp @@ -96,6 +96,7 @@ genrule { cc_library_shared { name: "libstatslog", + host_supported: true, generated_sources: ["statslog.cpp"], generated_headers: ["statslog.h"], cflags: [ @@ -105,8 +106,19 @@ cc_library_shared { export_generated_headers: ["statslog.h"], shared_libs: [ "liblog", - "libutils", "libcutils", ], static_libs: ["libstatssocket"], + target: { + android: { + shared_libs: [ + "libutils", + ], + }, + host: { + static_libs: [ + "libutils", + ], + }, + }, } diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp index 5192a0e7bf19..11b408fb8b9e 100644 --- a/tools/stats_log_api_gen/main.cpp +++ b/tools/stats_log_api_gen/main.cpp @@ -106,7 +106,9 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, fprintf(out, "#include <mutex>\n"); fprintf(out, "#include <chrono>\n"); fprintf(out, "#include <thread>\n"); + fprintf(out, "#ifdef __ANDROID__\n"); fprintf(out, "#include <cutils/properties.h>\n"); + fprintf(out, "#endif\n"); fprintf(out, "#include <stats_event_list.h>\n"); fprintf(out, "#include <log/log.h>\n"); fprintf(out, "#include <statslog.h>\n"); @@ -117,7 +119,11 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, fprintf(out, "namespace util {\n"); fprintf(out, "// the single event tag id for all stats logs\n"); fprintf(out, "const static int kStatsEventTag = 1937006964;\n"); + fprintf(out, "#ifdef __ANDROID__\n"); fprintf(out, "const static bool kStatsdEnabled = property_get_bool(\"ro.statsd.enable\", true);\n"); + fprintf(out, "#else\n"); + fprintf(out, "const static bool kStatsdEnabled = false;\n"); + fprintf(out, "#endif\n"); std::set<string> kTruncatingAtomNames = {"mobile_radio_power_state_changed", "audio_state_changed", |