summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/framework/java/android/app/job/JobScheduler.java15
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java18
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/ComponentController.java192
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java9
-rw-r--r--api/current.txt3
-rw-r--r--api/system-current.txt5
-rw-r--r--cmds/statsd/src/atoms.proto66
-rw-r--r--core/java/android/app/TEST_MAPPING4
-rw-r--r--core/java/android/bluetooth/BluetoothPan.java35
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java11
-rw-r--r--core/java/android/preference/SeekBarVolumizer.java51
-rw-r--r--core/java/android/preference/VolumePreference.java5
-rw-r--r--core/java/android/provider/Telephony.java14
-rw-r--r--core/java/android/util/FeatureFlagUtils.java3
-rw-r--r--core/java/android/view/inputmethod/EditorInfo.java47
-rw-r--r--core/proto/android/stats/hdmi/enums.proto122
-rw-r--r--core/res/AndroidManifest.xml2
-rw-r--r--core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java9
-rw-r--r--data/etc/privapp-permissions-platform.xml1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java10
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java7
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java8
-rw-r--r--non-updatable-api/current.txt3
-rw-r--r--non-updatable-api/system-current.txt5
-rw-r--r--packages/SystemUI/res/drawable/ic_move_magnification.xml (renamed from packages/SystemUI/res/drawable/ic_move.xml)2
-rw-r--r--packages/SystemUI/res/layout/window_magnifier_view.xml17
-rw-r--r--packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java30
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java265
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java275
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java15
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java12
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java55
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java196
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java73
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java56
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java40
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java244
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java275
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java350
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java349
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java147
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java113
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java66
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java550
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java379
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java19
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java30
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewController.java58
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java107
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java148
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java324
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java350
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java394
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java413
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LiftToActivateListener.java9
-rw-r--r--packages/SystemUI/src/com/android/keyguard/NumPadKey.java4
-rw-r--r--packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/Dependency.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java71
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/ViewController.java23
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java23
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java122
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java87
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java55
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt84
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewTest.kt59
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java106
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewTest.java79
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java130
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java62
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java102
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java81
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java210
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java29
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java25
-rw-r--r--packages/Tethering/apex/Android.bp1
-rw-r--r--packages/Tethering/bpf_progs/Android.bp33
-rw-r--r--packages/Tethering/bpf_progs/offload.c207
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java3
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java2
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java114
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java11
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java2
-rw-r--r--services/core/java/com/android/server/wm/BarController.java340
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java30
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java618
-rw-r--r--services/core/java/com/android/server/wm/StatusBarController.java109
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java5
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java187
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java160
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java11
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java67
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java2
-rwxr-xr-xtelephony/java/android/telephony/CarrierConfigManager.java46
-rw-r--r--telephony/java/android/telephony/ims/ImsService.java76
-rw-r--r--telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl8
-rw-r--r--telephony/java/android/telephony/ims/compat/ImsService.java87
-rw-r--r--telephony/java/com/android/ims/internal/IImsServiceController.aidl10
117 files changed, 5462 insertions, 4240 deletions
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
index 42725c51fd87..bf5781beb52b 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
@@ -101,10 +101,15 @@ public abstract class JobScheduler {
* version {@link android.os.Build.VERSION_CODES#Q}. As such, the system may throttle calls to
* this API if calls are made too frequently in a short amount of time.
*
+ * <p>Note: The JobService component needs to be enabled in order to successfully schedule a
+ * job.
+ *
* @param job The job you wish scheduled. See
* {@link android.app.job.JobInfo.Builder JobInfo.Builder} for more detail on the sorts of jobs
* you can schedule.
* @return the result of the schedule request.
+ * @throws IllegalArgumentException if the specified {@link JobService} doesn't exist or is
+ * disabled.
*/
public abstract @Result int schedule(@NonNull JobInfo job);
@@ -137,11 +142,21 @@ public abstract class JobScheduler {
* work you are enqueue, since currently this will always be treated as a different JobInfo,
* even if the ClipData contents are exactly the same.</p>
*
+ * <p class="caution"><strong>Note:</strong> Scheduling a job can have a high cost, even if it's
+ * rescheduling the same job and the job didn't execute, especially on platform versions before
+ * version {@link android.os.Build.VERSION_CODES#Q}. As such, the system may throttle calls to
+ * this API if calls are made too frequently in a short amount of time.
+ *
+ * <p>Note: The JobService component needs to be enabled in order to successfully schedule a
+ * job.
+ *
* @param job The job you wish to enqueue work for. See
* {@link android.app.job.JobInfo.Builder JobInfo.Builder} for more detail on the sorts of jobs
* you can schedule.
* @param work New work to enqueue. This will be available later when the job starts running.
* @return the result of the enqueue request.
+ * @throws IllegalArgumentException if the specified {@link JobService} doesn't exist or is
+ * disabled.
*/
public abstract @Result int enqueue(@NonNull JobInfo job, @NonNull JobWorkItem work);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index cf4caea9c487..b638fef36a9e 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -87,11 +87,11 @@ import com.android.server.AppStateTrackerImpl;
import com.android.server.DeviceIdleInternal;
import com.android.server.JobSchedulerBackgroundThread;
import com.android.server.LocalServices;
-import com.android.server.SystemService.TargetUser;
import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob;
import com.android.server.job.JobSchedulerServiceDumpProto.PendingJob;
import com.android.server.job.controllers.BackgroundJobsController;
import com.android.server.job.controllers.BatteryController;
+import com.android.server.job.controllers.ComponentController;
import com.android.server.job.controllers.ConnectivityController;
import com.android.server.job.controllers.ContentObserverController;
import com.android.server.job.controllers.DeviceIdleJobsController;
@@ -1484,6 +1484,7 @@ public class JobSchedulerService extends com.android.server.SystemService
mControllers.add(mDeviceIdleJobsController);
mQuotaController = new QuotaController(this);
mControllers.add(mQuotaController);
+ mControllers.add(new ComponentController(this));
mRestrictiveControllers = new ArrayList<>();
mRestrictiveControllers.add(mBatteryController);
@@ -2300,21 +2301,12 @@ public class JobSchedulerService extends com.android.server.SystemService
return false;
}
- // The expensive check: validate that the defined package+service is
- // still present & viable.
+ // Validate that the defined package+service is still present & viable.
return isComponentUsable(job);
}
private boolean isComponentUsable(@NonNull JobStatus job) {
- final ServiceInfo service;
- try {
- // TODO: cache result until we're notified that something in the package changed.
- service = AppGlobals.getPackageManager().getServiceInfo(
- job.getServiceComponent(), PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
- job.getUserId());
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
+ final ServiceInfo service = job.serviceInfo;
if (service == null) {
if (DEBUG) {
@@ -3104,7 +3096,7 @@ public class JobSchedulerService extends com.android.server.SystemService
try {
componentPresent = (AppGlobals.getPackageManager().getServiceInfo(
js.getServiceComponent(),
- PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
+ PackageManager.MATCH_DIRECT_BOOT_AUTO,
js.getUserId()) != null);
} catch (RemoteException e) {
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ComponentController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ComponentController.java
new file mode 100644
index 000000000000..b47a210cbed8
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ComponentController.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.job.controllers;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AppGlobals;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.net.Uri;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.IndentingPrintWriter;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArrayMap;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.server.job.JobSchedulerService;
+
+import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
+/**
+ * Controller that tracks changes in the service component's enabled state.
+ */
+public class ComponentController extends StateController {
+ private static final String TAG = "JobScheduler.Component";
+ private static final boolean DEBUG = JobSchedulerService.DEBUG
+ || Log.isLoggable(TAG, Log.DEBUG);
+
+ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (action == null) {
+ Slog.wtf(TAG, "Intent action was null");
+ return;
+ }
+ switch (action) {
+ case Intent.ACTION_PACKAGE_CHANGED:
+ final Uri uri = intent.getData();
+ final String pkg = uri != null ? uri.getSchemeSpecificPart() : null;
+ final String[] changedComponents = intent.getStringArrayExtra(
+ Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
+ if (pkg != null && changedComponents != null && changedComponents.length > 0) {
+ updateComponentStateForPackage(pkg);
+ }
+ break;
+ case Intent.ACTION_USER_UNLOCKED:
+ case Intent.ACTION_USER_STOPPED:
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
+ updateComponentStateForUser(userId);
+ break;
+ }
+ }
+ };
+
+ private final ComponentStateUpdateFunctor mComponentStateUpdateFunctor =
+ new ComponentStateUpdateFunctor();
+
+ public ComponentController(JobSchedulerService service) {
+ super(service);
+
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ filter.addDataScheme("package");
+ mContext.registerReceiverAsUser(
+ mBroadcastReceiver, UserHandle.ALL, filter, null, null);
+ final IntentFilter userFilter = new IntentFilter();
+ userFilter.addAction(Intent.ACTION_USER_UNLOCKED);
+ userFilter.addAction(Intent.ACTION_USER_STOPPED);
+ mContext.registerReceiverAsUser(
+ mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
+
+ }
+
+ @Override
+ public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
+ updateComponentEnabledStateLocked(jobStatus, null);
+ }
+
+ @Override
+ public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
+ boolean forUpdate) {
+
+ }
+
+ @Nullable
+ private ServiceInfo getServiceInfo(JobStatus jobStatus,
+ @Nullable SparseArrayMap<ComponentName, ServiceInfo> cache) {
+ final ComponentName cn = jobStatus.getServiceComponent();
+ ServiceInfo si = null;
+ if (cache != null) {
+ si = cache.get(jobStatus.getUserId(), cn);
+ }
+ if (si == null) {
+ try {
+ si = AppGlobals.getPackageManager().getServiceInfo(
+ cn, PackageManager.MATCH_DIRECT_BOOT_AUTO, jobStatus.getUserId());
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ if (cache != null) {
+ cache.add(jobStatus.getUserId(), cn, si);
+ }
+ }
+ return si;
+ }
+
+ private boolean updateComponentEnabledStateLocked(JobStatus jobStatus,
+ @Nullable SparseArrayMap<ComponentName, ServiceInfo> cache) {
+ final ServiceInfo service = getServiceInfo(jobStatus, cache);
+
+ if (DEBUG && service == null) {
+ Slog.v(TAG, jobStatus.toShortString() + " component not present");
+ }
+ final ServiceInfo ogService = jobStatus.serviceInfo;
+ jobStatus.serviceInfo = service;
+ return !Objects.equals(ogService, service);
+ }
+
+ private void updateComponentStateForPackage(final String pkg) {
+ updateComponentStates(
+ jobStatus -> jobStatus.getServiceComponent().getPackageName().equals(pkg));
+ }
+
+ private void updateComponentStateForUser(final int userId) {
+ updateComponentStates(jobStatus -> {
+ // Using user ID instead of source user ID because the service will run under the
+ // user ID, not source user ID.
+ return jobStatus.getUserId() == userId;
+ });
+ }
+
+ private void updateComponentStates(@NonNull Predicate<JobStatus> filter) {
+ synchronized (mLock) {
+ mComponentStateUpdateFunctor.reset();
+ mService.getJobStore().forEachJob(filter, mComponentStateUpdateFunctor);
+ if (mComponentStateUpdateFunctor.mChanged) {
+ mStateChangedListener.onControllerStateChanged();
+ }
+ }
+ }
+
+ final class ComponentStateUpdateFunctor implements Consumer<JobStatus> {
+ boolean mChanged;
+ final SparseArrayMap<ComponentName, ServiceInfo> mTempCache = new SparseArrayMap<>();
+
+ @Override
+ public void accept(JobStatus jobStatus) {
+ mChanged |= updateComponentEnabledStateLocked(jobStatus, mTempCache);
+ }
+
+ private void reset() {
+ mChanged = false;
+ mTempCache.clear();
+ }
+ }
+
+ @Override
+ public void dumpControllerStateLocked(IndentingPrintWriter pw, Predicate<JobStatus> predicate) {
+
+ }
+
+ @Override
+ public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId,
+ Predicate<JobStatus> predicate) {
+
+ }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index d7be2595e88b..c7cc2f03b062 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -27,6 +27,7 @@ import android.app.job.JobInfo;
import android.app.job.JobWorkItem;
import android.content.ClipData;
import android.content.ComponentName;
+import android.content.pm.ServiceInfo;
import android.net.Network;
import android.net.Uri;
import android.os.RemoteException;
@@ -296,6 +297,7 @@ public final class JobStatus {
public ArraySet<Uri> changedUris;
public ArraySet<String> changedAuthorities;
public Network network;
+ public ServiceInfo serviceInfo;
public int lastEvaluatedPriority;
@@ -1284,8 +1286,8 @@ public final class JobStatus {
// run if its constraints are satisfied).
// DeviceNotDozing implicit constraint must be satisfied
// NotRestrictedInBackground implicit constraint must be satisfied
- return mReadyNotDozing && mReadyNotRestrictedInBg && (mReadyDeadlineSatisfied
- || isConstraintsSatisfied(satisfiedConstraints));
+ return mReadyNotDozing && mReadyNotRestrictedInBg && (serviceInfo != null)
+ && (mReadyDeadlineSatisfied || isConstraintsSatisfied(satisfiedConstraints));
}
/** All constraints besides implicit and deadline. */
@@ -1767,6 +1769,9 @@ public final class JobStatus {
pw.print(prefix);
pw.print(" readyDynamicSatisfied: ");
pw.println(mReadyDynamicSatisfied);
+ pw.print(prefix);
+ pw.print(" readyComponentEnabled: ");
+ pw.println(serviceInfo != null);
if (changedAuthorities != null) {
pw.print(prefix); pw.println("Changed authorities:");
diff --git a/api/current.txt b/api/current.txt
index 592a909f7e14..2b662eb0676d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -46766,6 +46766,7 @@ package android.telephony {
field public static final String KEY_APN_EXPAND_BOOL = "apn_expand_bool";
field public static final String KEY_APN_SETTINGS_DEFAULT_APN_TYPES_STRING_ARRAY = "apn_settings_default_apn_types_string_array";
field public static final String KEY_AUTO_RETRY_ENABLED_BOOL = "auto_retry_enabled_bool";
+ field public static final String KEY_CALL_BARRING_DEFAULT_SERVICE_CLASS_INT = "call_barring_default_service_class_int";
field public static final String KEY_CALL_BARRING_SUPPORTS_DEACTIVATE_ALL_BOOL = "call_barring_supports_deactivate_all_bool";
field public static final String KEY_CALL_BARRING_SUPPORTS_PASSWORD_CHANGE_BOOL = "call_barring_supports_password_change_bool";
field public static final String KEY_CALL_BARRING_VISIBILITY_BOOL = "call_barring_visibility_bool";
@@ -46993,6 +46994,8 @@ package android.telephony {
field public static final String KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING = "wfc_emergency_address_carrier_app_string";
field public static final String KEY_WORLD_MODE_ENABLED_BOOL = "world_mode_enabled_bool";
field public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
+ field public static final int SERVICE_CLASS_NONE = 0; // 0x0
+ field public static final int SERVICE_CLASS_VOICE = 1; // 0x1
}
public static final class CarrierConfigManager.Apn {
diff --git a/api/system-current.txt b/api/system-current.txt
index 60145a8242f6..65fe85bdd727 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1592,12 +1592,16 @@ package android.bluetooth {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void setBluetoothTethering(boolean);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED";
+ field public static final String ACTION_TETHERING_STATE_CHANGED = "android.bluetooth.action.TETHERING_STATE_CHANGED";
field public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE";
+ field public static final String EXTRA_TETHERING_STATE = "android.bluetooth.extra.TETHERING_STATE";
field public static final int LOCAL_NAP_ROLE = 1; // 0x1
field public static final int LOCAL_PANU_ROLE = 2; // 0x2
field public static final int PAN_ROLE_NONE = 0; // 0x0
field public static final int REMOTE_NAP_ROLE = 1; // 0x1
field public static final int REMOTE_PANU_ROLE = 2; // 0x2
+ field public static final int TETHERING_STATE_OFF = 1; // 0x1
+ field public static final int TETHERING_STATE_ON = 2; // 0x2
}
public class BluetoothPbap implements android.bluetooth.BluetoothProfile {
@@ -9374,6 +9378,7 @@ package android.provider {
field public static final String APN_SET_ID = "apn_set_id";
field public static final int CARRIER_EDITED = 4; // 0x4
field public static final String EDITED_STATUS = "edited";
+ field public static final int MATCH_ALL_APN_SET_ID = -1; // 0xffffffff
field public static final String MAX_CONNECTIONS = "max_conns";
field public static final String MODEM_PERSIST = "modem_cognitive";
field public static final String MTU = "mtu";
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index fc1455be29b1..0a09801708a5 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -38,6 +38,7 @@ import "frameworks/base/core/proto/android/net/networkcapabilities.proto";
import "frameworks/base/core/proto/android/os/enums.proto";
import "frameworks/base/core/proto/android/server/connectivity/data_stall_event.proto";
import "frameworks/base/core/proto/android/server/enums.proto";
+import "frameworks/base/core/proto/android/stats/hdmi/enums.proto";
import "frameworks/base/core/proto/android/server/job/enums.proto";
import "frameworks/base/core/proto/android/server/location/enums.proto";
import "frameworks/base/core/proto/android/service/procstats_enum.proto";
@@ -490,6 +491,8 @@ message Atom {
UIActionLatencyReported ui_action_latency_reported = 306 [(module) = "framework"];
WifiDisconnectReported wifi_disconnect_reported = 307 [(module) = "wifi"];
WifiConnectionStateChanged wifi_connection_state_changed = 308 [(module) = "wifi"];
+ HdmiCecActiveSourceChanged hdmi_cec_active_source_changed = 309 [(module) = "framework"];
+ HdmiCecMessageReported hdmi_cec_message_reported = 310 [(module) = "framework"];
// StatsdStats tracks platform atoms with ids upto 500.
// Update StatsdStats::kMaxPushedAtomId when atom ids here approach that value.
@@ -11433,4 +11436,65 @@ message BlobInfo {
// List of leasees of this Blob
optional BlobLeaseeListProto leasees = 5 [(log_mode) = MODE_BYTES];
-} \ No newline at end of file
+}
+
+/**
+ * Logs when the HDMI CEC active source changes.
+ *
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/hdmi/HdmiCecAtomWriter.java
+ */
+message HdmiCecActiveSourceChanged {
+ // The logical address of the active source.
+ optional android.stats.hdmi.LogicalAddress active_source_logical_address = 1;
+
+ // The physical address of the active source. Consists of four hexadecimal nibbles.
+ // Examples: 0x1234, 0x0000 (root device). 0xFFFF represents an unknown or invalid address.
+ // See section 8.7 in the HDMI 1.4b spec for details.
+ optional int32 active_source_physical_address = 2;
+
+ // The relationship between this device and the active source.
+ optional android.stats.hdmi.PathRelationship local_relationship = 3;
+}
+
+/**
+ * Logs when an HDMI CEC message is sent or received.
+ *
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/hdmi/HdmiCecAtomWriter.java
+ */
+message HdmiCecMessageReported {
+ // The calling uid of the application that caused this atom to be written.
+ optional int32 uid = 1 [(is_uid) = true];
+
+ // Whether a HDMI CEC message is sent from this device, to this device, or neither.
+ optional android.stats.hdmi.MessageDirection direction = 2;
+
+ // The HDMI CEC logical address of the initiator.
+ optional android.stats.hdmi.LogicalAddress initiator_logical_address = 3;
+
+ // The HDMI CEC logical address of the destination.
+ optional android.stats.hdmi.LogicalAddress destination_logical_address = 4;
+
+ // The opcode of the message. Ranges from 0x00 to 0xFF.
+ // For all values, see section "CEC 15 Message Descriptions" in the HDMI CEC 1.4b spec.
+ optional int32 opcode = 5;
+
+ // The result of attempting to send the message on its final retransmission attempt.
+ // Only applicable to outgoing messages; set to SEND_MESSAGE_RESULT_UNKNOWN otherwise.
+ optional android.stats.hdmi.SendMessageResult send_message_result = 6;
+
+ // Fields specific to <User Control Pressed> messages
+
+ // The user control command that was received.
+ optional android.stats.hdmi.UserControlPressedCommand user_control_pressed_command = 7;
+
+ // Fields specific to <Feature Abort> messages
+
+ // The opcode of the message that was feature aborted.
+ // Set to 0x100 when unknown or not applicable.
+ optional int32 feature_abort_opcode = 8;
+
+ // The reason for the feature abort.
+ optional android.stats.hdmi.FeatureAbortReason feature_abort_reason = 9;
+}
diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING
index 4139b2faeb1b..b0307d1eb939 100644
--- a/core/java/android/app/TEST_MAPPING
+++ b/core/java/android/app/TEST_MAPPING
@@ -70,7 +70,7 @@
"name": "CtsAutoFillServiceTestCases",
"options": [
{
- "include-filter": "android.autofillservice.cts.PreSimpleSaveActivityTest"
+ "include-filter": "android.autofillservice.cts.saveui.PreSimpleSaveActivityTest"
},
{
"exclude-annotation": "androidx.test.filters.FlakyTest"
@@ -82,7 +82,7 @@
"name": "CtsAutoFillServiceTestCases",
"options": [
{
- "include-filter": "android.autofillservice.cts.SimpleSaveActivityTest"
+ "include-filter": "android.autofillservice.cts.saveui.SimpleSaveActivityTest"
},
{
"exclude-annotation": "androidx.test.filters.FlakyTest"
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java
index 73c38cbfbe3f..ce3c7d25a108 100644
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ b/core/java/android/bluetooth/BluetoothPan.java
@@ -89,6 +89,33 @@ public final class BluetoothPan implements BluetoothProfile {
@SuppressLint("ActionValue")
public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE";
+ /**
+ * Intent used to broadcast the change in tethering state of the Pan
+ * Profile
+ *
+ * <p>This intent will have 1 extra:
+ * <ul>
+ * <li> {@link #EXTRA_TETHERING_STATE} - The current state of Bluetooth
+ * tethering. </li>
+ * </ul>
+ *
+ * <p> {@link #EXTRA_TETHERING_STATE} can be any of {@link #TETHERING_STATE_OFF} or
+ * {@link #TETHERING_STATE_ON}
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_TETHERING_STATE_CHANGED =
+ "android.bluetooth.action.TETHERING_STATE_CHANGED";
+
+ /**
+ * Extra for {@link #ACTION_TETHERING_STATE_CHANGED} intent
+ * The tethering state of the PAN profile.
+ * It can be one of {@link #TETHERING_STATE_OFF} or {@link #TETHERING_STATE_ON}.
+ */
+ public static final String EXTRA_TETHERING_STATE =
+ "android.bluetooth.extra.TETHERING_STATE";
+
/** @hide */
@IntDef({PAN_ROLE_NONE, LOCAL_NAP_ROLE, LOCAL_PANU_ROLE})
@Retention(RetentionPolicy.SOURCE)
@@ -114,6 +141,14 @@ public final class BluetoothPan implements BluetoothProfile {
public static final int REMOTE_PANU_ROLE = 2;
+ /** @hide **/
+ @IntDef({TETHERING_STATE_OFF, TETHERING_STATE_ON})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TetheringState{}
+
+ public static final int TETHERING_STATE_OFF = 1;
+
+ public static final int TETHERING_STATE_ON = 2;
/**
* Return codes for the connect and disconnect Bluez / Dbus calls.
*
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 6673cb933eff..d5f2c12e8462 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -146,8 +146,15 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
public int uiOptions = 0;
/**
- * Value for {@link #flags}: if set, this application is installed in the
- * device's system image.
+ * Value for {@link #flags}: if set, this application is installed in the device's system image.
+ * This should not be used to make security decisions. Instead, rely on
+ * {@linkplain android.content.pm.PackageManager#checkSignatures(java.lang.String,java.lang.String)
+ * signature checks} or
+ * <a href="https://developer.android.com/training/articles/security-tips#Permissions">permissions</a>.
+ *
+ * <p><b>Warning:</b> Note that does flag not behave the same as
+ * {@link android.R.attr#protectionLevel android:protectionLevel} {@code system} or
+ * {@code signatureOrSystem}.
*/
public static final int FLAG_SYSTEM = 1<<0;
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index 0cdad9f8de93..400b312bb913 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -46,6 +46,8 @@ import android.widget.SeekBar.OnSeekBarChangeListener;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.SomeArgs;
+import java.util.concurrent.TimeUnit;
+
/**
* Turns a {@link SeekBar} into a volume control.
* @hide
@@ -64,9 +66,15 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
void onSampleStarting(SeekBarVolumizer sbv);
void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch);
void onMuted(boolean muted, boolean zenMuted);
+ /**
+ * Callback reporting that the seek bar is start tracking.
+ * @param sbv - The seek bar that start tracking
+ */
+ void onStartTrackingTouch(SeekBarVolumizer sbv);
}
private static final int MSG_GROUP_VOLUME_CHANGED = 1;
+ private static long sStopVolumeTime = 0L;
private final Handler mVolumeHandler = new VolumeHandler();
private AudioAttributes mAttributes;
private int mVolumeGroupId;
@@ -126,6 +134,9 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
private static final int MSG_STOP_SAMPLE = 2;
private static final int MSG_INIT_SAMPLE = 3;
private static final int CHECK_RINGTONE_PLAYBACK_DELAY_MS = 1000;
+ private static final long SET_STREAM_VOLUME_DELAY_MS = TimeUnit.MILLISECONDS.toMillis(500);
+ private static final long START_SAMPLE_DELAY_MS = TimeUnit.MILLISECONDS.toMillis(500);
+ private static final long DURATION_TO_START_DELAYING = TimeUnit.MILLISECONDS.toMillis(2000);
private NotificationManager.Policy mNotificationPolicy;
private boolean mAllowAlarms;
@@ -314,7 +325,29 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
if (mHandler == null) return;
mHandler.removeMessages(MSG_START_SAMPLE);
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_SAMPLE),
- isSamplePlaying() ? CHECK_RINGTONE_PLAYBACK_DELAY_MS : 0);
+ isSamplePlaying() ? CHECK_RINGTONE_PLAYBACK_DELAY_MS
+ : isDelay() ? START_SAMPLE_DELAY_MS : 0);
+ }
+
+ // After stop volume it needs to add a small delay when playing volume or set stream.
+ // It is because the call volume is from the earpiece and the alarm/ring/media
+ // is from the speaker. If play the alarm volume or set alarm stream right after stop
+ // call volume, the alarm volume on earpiece is returned then cause the volume value incorrect.
+ // It needs a small delay after stop call volume to get alarm volume on speaker.
+ // e.g. : If the ring volume has adjusted right after call volume stopped in 2 second
+ // then delay 0.5 second to set stream or play volume ringtone.
+ private boolean isDelay() {
+ final long durationTime = java.lang.System.currentTimeMillis() - sStopVolumeTime;
+ return durationTime >= 0 && durationTime < DURATION_TO_START_DELAYING;
+ }
+
+ private void setStopVolumeTime() {
+ // set the time of stop volume
+ if ((mStreamType == AudioManager.STREAM_VOICE_CALL
+ || mStreamType == AudioManager.STREAM_RING
+ || mStreamType == AudioManager.STREAM_ALARM)) {
+ sStopVolumeTime = java.lang.System.currentTimeMillis();
+ }
}
private void onStartSample() {
@@ -341,6 +374,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
private void postStopSample() {
if (mHandler == null) return;
+ setStopVolumeTime();
// remove pending delayed start messages
mHandler.removeMessages(MSG_START_SAMPLE);
mHandler.removeMessages(MSG_STOP_SAMPLE);
@@ -404,10 +438,15 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
// Do the volume changing separately to give responsive UI
mLastProgress = progress;
mHandler.removeMessages(MSG_SET_STREAM_VOLUME);
- mHandler.sendMessage(mHandler.obtainMessage(MSG_SET_STREAM_VOLUME));
+ mHandler.removeMessages(MSG_START_SAMPLE);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SET_STREAM_VOLUME),
+ isDelay() ? SET_STREAM_VOLUME_DELAY_MS : 0);
}
public void onStartTrackingTouch(SeekBar seekBar) {
+ if (mCallback != null) {
+ mCallback.onStartTrackingTouch(this);
+ }
}
public void onStopTrackingTouch(SeekBar seekBar) {
@@ -539,7 +578,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
if (AudioManager.VOLUME_CHANGED_ACTION.equals(action)) {
int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
int streamValue = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1);
- if (hasAudioProductStrategies()) {
+ if (hasAudioProductStrategies() && !isDelay()) {
updateVolumeSlider(streamType, streamValue);
}
} else if (AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION.equals(action)) {
@@ -551,7 +590,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
}
} else if (AudioManager.STREAM_DEVICES_CHANGED_ACTION.equals(action)) {
int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
- if (hasAudioProductStrategies()) {
+ if (hasAudioProductStrategies() && !isDelay()) {
int streamVolume = mAudioManager.getStreamVolume(streamType);
updateVolumeSlider(streamType, streamVolume);
} else {
@@ -559,7 +598,9 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
if (volumeGroup != AudioVolumeGroup.DEFAULT_VOLUME_GROUP
&& volumeGroup == mVolumeGroupId) {
int streamVolume = mAudioManager.getStreamVolume(streamType);
- updateVolumeSlider(streamType, streamVolume);
+ if (!isDelay()) {
+ updateVolumeSlider(streamType, streamVolume);
+ }
}
}
} else if (NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED.equals(action)) {
diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java
index 6eb524a3886c..563bc463e5a3 100644
--- a/core/java/android/preference/VolumePreference.java
+++ b/core/java/android/preference/VolumePreference.java
@@ -176,6 +176,11 @@ public class VolumePreference extends SeekBarDialogPreference implements
}
@Override
+ public void onStartTrackingTouch(SeekBarVolumizer sbv) {
+ // noop
+ }
+
+ @Override
protected Parcelable onSaveInstanceState() {
final Parcelable superState = super.onSaveInstanceState();
if (isPersistent()) {
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 9f52142a5109..79d6bb4a062a 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -3956,9 +3956,7 @@ public final class Telephony {
public static final String APN_SET_ID = "apn_set_id";
/**
- * Possible value for the {@link #APN_SET_ID} field. By default APNs will not belong to a
- * set. If the user manually selects an APN without apn set id, there is no need to
- * prioritize any specific APN set ids.
+ * Possible value for the {@link #APN_SET_ID} field. By default APNs are added to set 0.
* <p>Type: INTEGER</p>
* @hide
*/
@@ -3966,6 +3964,16 @@ public final class Telephony {
public static final int NO_APN_SET_ID = 0;
/**
+ * Possible value for the {@link #APN_SET_ID} field.
+ * APNs with MATCH_ALL_APN_SET_ID will be used regardless of any set ids of
+ * the selected APN.
+ * <p>Type: INTEGER</p>
+ * @hide
+ */
+ @SystemApi
+ public static final int MATCH_ALL_APN_SET_ID = -1;
+
+ /**
* A unique carrier id associated with this APN
* {@see TelephonyManager#getSimCarrierId()}
* <p>Type: STRING</p>
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 9cc6b9f83ede..9244647432c7 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -44,6 +44,8 @@ public class FeatureFlagUtils {
/** @hide */
public static final String SETTINGS_DO_NOT_RESTORE_PRESERVED =
"settings_do_not_restore_preserved";
+ /** @hide */
+ public static final String SETTINGS_PROVIDER_MODEL = "settings_provider_model";
private static final Map<String, String> DEFAULT_FLAGS;
@@ -67,6 +69,7 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS.put("settings_tether_all_in_one", "false");
DEFAULT_FLAGS.put("settings_silky_home", "false");
DEFAULT_FLAGS.put("settings_contextual_home", "false");
+ DEFAULT_FLAGS.put(SETTINGS_PROVIDER_MODEL, "false");
}
/**
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index c5f2299e4f83..104bc4347c29 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -22,13 +22,14 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.LocaleList;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
-import android.text.Editable;
import android.text.InputType;
+import android.text.ParcelableSpan;
import android.text.TextUtils;
import android.util.Printer;
import android.view.View;
@@ -543,6 +544,9 @@ public class EditorInfo implements InputType, Parcelable {
* {@code #getInitialSelectedText}, and {@code #getInitialTextBeforeCursor}. System is allowed
* to trim {@code sourceText} for various reasons while keeping the most valuable data to IMEs.
*
+ * Starting from {@link VERSION_CODES#S}, spans that do not implement {@link Parcelable} will
+ * be automatically dropped.
+ *
* <p><strong>Editor authors: </strong>Providing the initial input text helps reducing IPC calls
* for IMEs to provide many modern features right after the connection setup. We recommend
* calling this method in your implementation.
@@ -562,14 +566,16 @@ public class EditorInfo implements InputType, Parcelable {
* try to include the selected text within {@code subText} to give the system best flexibility
* to choose where and how to trim {@code subText} when necessary.
*
+ * Starting from {@link VERSION_CODES#S}, spans that do not implement {@link Parcelable} will
+ * be automatically dropped.
+ *
* @param subText The input text. When it was trimmed, {@code subTextStart} must be provided
* correctly.
* @param subTextStart The position that the input text got trimmed. For example, when the
* editor wants to trim out the first 10 chars, subTextStart should be 10.
*/
public void setInitialSurroundingSubText(@NonNull CharSequence subText, int subTextStart) {
- CharSequence newSubText = Editable.Factory.getInstance().newEditable(subText);
- Objects.requireNonNull(newSubText);
+ Objects.requireNonNull(subText);
// Swap selection start and end if necessary.
final int subTextSelStart = initialSelStart > initialSelEnd
@@ -577,7 +583,7 @@ public class EditorInfo implements InputType, Parcelable {
final int subTextSelEnd = initialSelStart > initialSelEnd
? initialSelStart - subTextStart : initialSelEnd - subTextStart;
- final int subTextLength = newSubText.length();
+ final int subTextLength = subText.length();
// Unknown or invalid selection.
if (subTextStart < 0 || subTextSelStart < 0 || subTextSelEnd > subTextLength) {
mInitialSurroundingText = new InitialSurroundingText();
@@ -591,12 +597,12 @@ public class EditorInfo implements InputType, Parcelable {
}
if (subTextLength <= MEMORY_EFFICIENT_TEXT_LENGTH) {
- mInitialSurroundingText = new InitialSurroundingText(newSubText, subTextSelStart,
+ mInitialSurroundingText = new InitialSurroundingText(subText, subTextSelStart,
subTextSelEnd);
return;
}
- trimLongSurroundingText(newSubText, subTextSelStart, subTextSelEnd);
+ trimLongSurroundingText(subText, subTextSelStart, subTextSelEnd);
}
/**
@@ -901,7 +907,9 @@ public class EditorInfo implements InputType, Parcelable {
InitialSurroundingText(@Nullable CharSequence surroundingText, int selectionHead,
int selectionEnd) {
- mSurroundingText = surroundingText;
+ // Copy the original text (without NoCopySpan) in case the original text is updated
+ // later.
+ mSurroundingText = copyWithParcelableSpans(surroundingText);
mSelectionHead = selectionHead;
mSelectionEnd = selectionEnd;
}
@@ -975,5 +983,30 @@ public class EditorInfo implements InputType, Parcelable {
return new InitialSurroundingText[size];
}
};
+
+ /**
+ * Create a copy of the given {@link CharSequence} object, with completely copy
+ * {@link ParcelableSpan} instances.
+ *
+ * @param source the original {@link CharSequence} to be copied.
+ * @return the copied {@link CharSequence}. {@code null} if {@code source} is {@code null}.
+ */
+ @Nullable
+ private static CharSequence copyWithParcelableSpans(@Nullable CharSequence source) {
+ if (source == null) {
+ return null;
+ }
+ Parcel parcel = null;
+ try {
+ parcel = Parcel.obtain();
+ TextUtils.writeToParcel(source, parcel, /* parcelableFlags= */ 0);
+ parcel.setDataPosition(0);
+ return TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
+ } finally {
+ if (parcel != null) {
+ parcel.recycle();
+ }
+ }
+ }
}
}
diff --git a/core/proto/android/stats/hdmi/enums.proto b/core/proto/android/stats/hdmi/enums.proto
new file mode 100644
index 000000000000..acb8899fbdd9
--- /dev/null
+++ b/core/proto/android/stats/hdmi/enums.proto
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+package android.stats.hdmi;
+option java_multiple_files = true;
+option java_outer_classname = "HdmiStatsEnums";
+
+// HDMI CEC logical addresses.
+// Values correspond to "CEC Table 5 Logical Addresses" in the HDMI CEC 1.4b spec.
+enum LogicalAddress {
+ LOGICAL_ADDRESS_UNKNOWN = -1;
+ TV = 0;
+ RECORDING_DEVICE_1 = 1;
+ RECORDING_DEVICE_2 = 2;
+ TUNER_1 = 3;
+ PLAYBACK_DEVICE_1 = 4;
+ AUDIO_SYSTEM = 5;
+ TUNER_2 = 6;
+ TUNER_3 = 7;
+ PLAYBACK_DEVICE_2 = 8;
+ RECORDING_DEVICE_3 = 9;
+ TUNER_4 = 10;
+ PLAYBACK_DEVICE_3 = 11;
+ RESERVED_1 = 12;
+ RESERVED_2 = 13;
+ SPECIFIC_USE = 14;
+ UNREGISTERED_OR_BROADCAST = 15;
+}
+
+// The relationship between two paths.
+// Values correspond exactly to PathRelationship in com.android.server.hdmi.Constants.
+enum PathRelationship {
+ RELATIONSHIP_TO_ACTIVE_SOURCE_UNKNOWN = 0;
+ DIFFERENT_BRANCH = 1;
+ ANCESTOR = 2;
+ DESCENDANT = 3;
+ SIBLING = 4;
+ SAME = 5;
+}
+
+// The result of attempting to send a HDMI CEC message.
+// Values correspond to the constants in android.hardware.tv.cec.V1_0.SendMessageResult,
+// offset by 10.
+enum SendMessageResult {
+ SEND_MESSAGE_RESULT_UNKNOWN = 0;
+ SUCCESS = 10;
+ NACK = 11;
+ BUSY = 12;
+ FAIL = 13;
+}
+
+// Whether a HDMI CEC message is sent from this device, to this device, or neither.
+enum MessageDirection {
+ MESSAGE_DIRECTION_UNKNOWN = 0;
+ MESSAGE_DIRECTION_OTHER = 1; // None of the other options.
+ OUTGOING = 2; // Sent from this device.
+ INCOMING = 3; // Sent to this device.
+ TO_SELF = 4; // Sent from this device, to this device. Indicates a bug.
+}
+
+// User control commands. Each value can represent an individual command, or a set of commands.
+// Values correspond to "CEC Table 30 UI Command Codes" in the HDMI CEC 1.4b spec, offset by 0x100.
+enum UserControlPressedCommand {
+ USER_CONTROL_PRESSED_COMMAND_UNKNOWN = 0;
+
+ // Represents all codes that are not represented by another value.
+ USER_CONTROL_PRESSED_COMMAND_OTHER = 1;
+
+ // Represents all number codes (codes 0x1E through 0x29).
+ NUMBER = 2;
+
+ // Navigation
+ SELECT = 0x100;
+ UP = 0x101;
+ DOWN = 0x102;
+ LEFT = 0x103;
+ RIGHT = 0x104;
+ RIGHT_UP = 0x105;
+ RIGHT_DOWN = 0x106;
+ LEFT_UP = 0x107;
+ LEFT_DOWN = 0x108;
+ EXIT = 0x10D;
+
+ // Volume
+ VOLUME_UP = 0x141;
+ VOLUME_DOWN = 0x142;
+ VOLUME_MUTE = 0x143;
+
+ // Power
+ POWER = 0x140;
+ POWER_TOGGLE = 0x16B;
+ POWER_OFF = 0x16C;
+ POWER_ON = 0x16D;
+}
+
+// Reason parameter of the <Feature Abort> message.
+// Values correspond to "CEC Table 29 Operand Descriptions" in the HDMI CEC 1.4b spec,
+// offset by 10.
+enum FeatureAbortReason {
+ FEATURE_ABORT_REASON_UNKNOWN = 0;
+ UNRECOGNIZED_OPCODE = 10;
+ NOT_IN_CORRECT_MODE_TO_RESPOND = 11;
+ CANNOT_PROVIDE_SOURCE = 12;
+ INVALID_OPERAND = 13;
+ REFUSED = 14;
+ UNABLE_TO_DETERMINE = 15;
+} \ No newline at end of file
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 68e2891657ac..c9a4ab081a5b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -238,6 +238,8 @@
android:name="com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_DELIVERY" />
<protected-broadcast
android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.action.TETHERING_STATE_CHANGED" />
<protected-broadcast android:name="android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast android:name="android.bluetooth.pbapclient.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast android:name="android.bluetooth.sap.profile.action.CONNECTION_STATE_CHANGED" />
diff --git a/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java
index 93de03adfa84..5c410878c99d 100644
--- a/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java
@@ -274,13 +274,10 @@ public class EditorInfoTest {
editorInfo.inputType = EditorInfo.TYPE_CLASS_TEXT;
editorInfo.setInitialSurroundingText(sb);
- sb.setLength(0);
- editorInfo.writeToParcel(parcel, 0);
+ sb.setLength(/* newLength= */ 0);
+ editorInfo.writeToParcel(parcel, /* flags= */ 0);
- try {
- editorInfo.getInitialTextBeforeCursor(60, 1);
- fail("Test shouldn't have exception");
- } catch (AssertionError e) { }
+ editorInfo.getInitialTextBeforeCursor(/* length= */ 60, /* flags= */ 1);
}
private static void assertExpectedTextLength(EditorInfo editorInfo,
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 602ccfeca2f2..102c933dd84d 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -226,6 +226,7 @@ applications that come with the platform
<permission name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
<permission name="android.permission.UPDATE_APP_OPS_STATS"/>
<permission name="android.permission.UPDATE_DEVICE_STATS"/>
+ <permission name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/>
</privapp-permissions>
<privapp-permissions package="com.android.providers.media.module">
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index f4b4f374bdc5..d060f6444463 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -172,8 +172,10 @@ public class OneHandedController implements OneHanded {
context, displayController);
OneHandedDisplayAreaOrganizer organizer = new OneHandedDisplayAreaOrganizer(
context, displayController, animationController, tutorialHandler);
+ IOverlayManager overlayManager = IOverlayManager.Stub.asInterface(
+ ServiceManager.getService(Context.OVERLAY_SERVICE));
return new OneHandedController(context, displayController, organizer, touchHandler,
- tutorialHandler, gestureHandler);
+ tutorialHandler, gestureHandler, overlayManager);
}
@VisibleForTesting
@@ -182,7 +184,8 @@ public class OneHandedController implements OneHanded {
OneHandedDisplayAreaOrganizer displayAreaOrganizer,
OneHandedTouchHandler touchHandler,
OneHandedTutorialHandler tutorialHandler,
- OneHandedGestureHandler gestureHandler) {
+ OneHandedGestureHandler gestureHandler,
+ IOverlayManager overlayManager) {
mHasOneHandedFeature = SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false);
if (!mHasOneHandedFeature) {
Log.i(TAG, "Device config SUPPORT_ONE_HANDED_MODE off");
@@ -201,9 +204,8 @@ public class OneHandedController implements OneHanded {
mTouchHandler = touchHandler;
mTutorialHandler = tutorialHandler;
mGestureHandler = gestureHandler;
+ mOverlayManager = overlayManager;
- mOverlayManager = IOverlayManager.Stub.asInterface(
- ServiceManager.getService(Context.OVERLAY_SERVICE));
mOffSetFraction = SystemProperties.getInt(ONE_HANDED_MODE_OFFSET_PERCENTAGE, 50)
/ 100.0f;
mIsOneHandedEnabled = OneHandedSettingsUtil.getSettingsOneHandedModeEnabled(
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
index 1ce8b5445b37..3645f1e56f92 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
@@ -18,13 +18,13 @@ package com.android.wm.shell.onehanded;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.om.IOverlayManager;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -62,6 +62,8 @@ public class OneHandedControllerTest extends OneHandedTestCase {
OneHandedGestureHandler mMockGestureHandler;
@Mock
OneHandedTimeoutHandler mMockTimeoutHandler;
+ @Mock
+ IOverlayManager mMockOverlayManager;
@Before
public void setUp() throws Exception {
@@ -73,7 +75,8 @@ public class OneHandedControllerTest extends OneHandedTestCase {
mMockDisplayAreaOrganizer,
mMockTouchHandler,
mMockTutorialHandler,
- mMockGestureHandler);
+ mMockGestureHandler,
+ mMockOverlayManager);
mOneHandedController = Mockito.spy(oneHandedController);
mTimeoutHandler = Mockito.spy(OneHandedTimeoutHandler.get());
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
index 4a133d39291a..3341c9cbacb9 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
@@ -18,6 +18,7 @@ package com.android.wm.shell.onehanded;
import static org.mockito.Mockito.verify;
+import android.content.om.IOverlayManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -44,6 +45,8 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase {
DisplayController mMockDisplayController;
@Mock
OneHandedDisplayAreaOrganizer mMockDisplayAreaOrganizer;
+ @Mock
+ IOverlayManager mMockOverlayManager;
@Before
public void setUp() {
@@ -56,11 +59,12 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase {
mMockDisplayAreaOrganizer,
mTouchHandler,
mTutorialHandler,
- mGestureHandler);
+ mGestureHandler,
+ mMockOverlayManager);
}
@Test
- public void testOneHandedManager_registerForDisplayAreaOrganizer() {
+ public void testRegisterForDisplayAreaOrganizer() {
verify(mMockDisplayAreaOrganizer).registerTransitionCallback(mTutorialHandler);
}
}
diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index 5f147c93f956..480e49415da6 100644
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -44909,6 +44909,7 @@ package android.telephony {
field public static final String KEY_APN_EXPAND_BOOL = "apn_expand_bool";
field public static final String KEY_APN_SETTINGS_DEFAULT_APN_TYPES_STRING_ARRAY = "apn_settings_default_apn_types_string_array";
field public static final String KEY_AUTO_RETRY_ENABLED_BOOL = "auto_retry_enabled_bool";
+ field public static final String KEY_CALL_BARRING_DEFAULT_SERVICE_CLASS_INT = "call_barring_default_service_class_int";
field public static final String KEY_CALL_BARRING_SUPPORTS_DEACTIVATE_ALL_BOOL = "call_barring_supports_deactivate_all_bool";
field public static final String KEY_CALL_BARRING_SUPPORTS_PASSWORD_CHANGE_BOOL = "call_barring_supports_password_change_bool";
field public static final String KEY_CALL_BARRING_VISIBILITY_BOOL = "call_barring_visibility_bool";
@@ -45136,6 +45137,8 @@ package android.telephony {
field public static final String KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING = "wfc_emergency_address_carrier_app_string";
field public static final String KEY_WORLD_MODE_ENABLED_BOOL = "world_mode_enabled_bool";
field public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
+ field public static final int SERVICE_CLASS_NONE = 0; // 0x0
+ field public static final int SERVICE_CLASS_VOICE = 1; // 0x1
}
public static final class CarrierConfigManager.Apn {
diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt
index 1e5d6cd5c1ff..82f2021af425 100644
--- a/non-updatable-api/system-current.txt
+++ b/non-updatable-api/system-current.txt
@@ -1532,12 +1532,16 @@ package android.bluetooth {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void setBluetoothTethering(boolean);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED";
+ field public static final String ACTION_TETHERING_STATE_CHANGED = "android.bluetooth.action.TETHERING_STATE_CHANGED";
field public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE";
+ field public static final String EXTRA_TETHERING_STATE = "android.bluetooth.extra.TETHERING_STATE";
field public static final int LOCAL_NAP_ROLE = 1; // 0x1
field public static final int LOCAL_PANU_ROLE = 2; // 0x2
field public static final int PAN_ROLE_NONE = 0; // 0x0
field public static final int REMOTE_NAP_ROLE = 1; // 0x1
field public static final int REMOTE_PANU_ROLE = 2; // 0x2
+ field public static final int TETHERING_STATE_OFF = 1; // 0x1
+ field public static final int TETHERING_STATE_ON = 2; // 0x2
}
public class BluetoothPbap implements android.bluetooth.BluetoothProfile {
@@ -8237,6 +8241,7 @@ package android.provider {
field public static final String APN_SET_ID = "apn_set_id";
field public static final int CARRIER_EDITED = 4; // 0x4
field public static final String EDITED_STATUS = "edited";
+ field public static final int MATCH_ALL_APN_SET_ID = -1; // 0xffffffff
field public static final String MAX_CONNECTIONS = "max_conns";
field public static final String MODEM_PERSIST = "modem_cognitive";
field public static final String MTU = "mtu";
diff --git a/packages/SystemUI/res/drawable/ic_move.xml b/packages/SystemUI/res/drawable/ic_move_magnification.xml
index e82c9d0f23a9..ed97d0cc0522 100644
--- a/packages/SystemUI/res/drawable/ic_move.xml
+++ b/packages/SystemUI/res/drawable/ic_move_magnification.xml
@@ -16,7 +16,7 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
- <shape android:shape="oval">
+ <shape android:shape="rectangle">
<solid
android:color="@android:color/black" />
<size
diff --git a/packages/SystemUI/res/layout/window_magnifier_view.xml b/packages/SystemUI/res/layout/window_magnifier_view.xml
index 25d63e3175d0..6ced97836358 100644
--- a/packages/SystemUI/res/layout/window_magnifier_view.xml
+++ b/packages/SystemUI/res/layout/window_magnifier_view.xml
@@ -23,13 +23,13 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/magnification_outer_border_margin"
- android:background="@android:color/black" />
+ android:background="@android:color/black"/>
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/magnification_inner_border_margin"
- android:background="@color/magnification_border_color" />
+ android:background="@color/magnification_border_color"/>
<RelativeLayout
android:layout_width="match_parent"
@@ -40,32 +40,32 @@
android:id="@+id/left_handle"
android:layout_width="@dimen/magnification_border_drag_size"
android:layout_height="match_parent"
- android:layout_above="@+id/bottom_handle" />
+ android:layout_above="@+id/bottom_handle"/>
<View
android:id="@+id/top_handle"
android:layout_width="match_parent"
android:layout_height="@dimen/magnification_border_drag_size"
- android:layout_alignParentTop="true" />
+ android:layout_alignParentTop="true"/>
<View
android:id="@+id/right_handle"
android:layout_width="@dimen/magnification_border_drag_size"
android:layout_height="match_parent"
android:layout_above="@+id/bottom_handle"
- android:layout_alignParentEnd="true" />
+ android:layout_alignParentEnd="true"/>
<View
android:id="@+id/bottom_handle"
android:layout_width="match_parent"
android:layout_height="@dimen/magnification_border_drag_size"
- android:layout_alignParentBottom="true" />
+ android:layout_alignParentBottom="true"/>
<SurfaceView
android:id="@+id/surface_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_margin="@dimen/magnification_mirror_surface_margin" />
+ android:layout_margin="@dimen/magnification_mirror_surface_margin"/>
</RelativeLayout>
@@ -73,8 +73,9 @@
android:id="@+id/drag_handle"
android:layout_width="@dimen/magnification_drag_view_size"
android:layout_height="@dimen/magnification_drag_view_size"
+ android:layout_margin="@dimen/magnification_outer_border_margin"
android:layout_gravity="right|bottom"
android:scaleType="center"
- android:src="@drawable/ic_move" />
+ android:src="@drawable/ic_move_magnification"/>
</FrameLayout> \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java b/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java
index e99245fa438f..23195af8bdea 100644
--- a/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java
+++ b/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java
@@ -33,9 +33,13 @@ import android.view.SurfaceView;
import android.view.ViewGroup;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.keyguard.dagger.KeyguardBouncerScope;
+import com.android.systemui.dagger.qualifiers.Main;
import java.util.NoSuchElementException;
+import javax.inject.Inject;
+
/**
* Encapsulates all logic for secondary lockscreen state management.
*/
@@ -142,9 +146,9 @@ public class AdminSecondaryLockScreenController {
}
};
- public AdminSecondaryLockScreenController(Context context, ViewGroup parent,
+ private AdminSecondaryLockScreenController(Context context, KeyguardSecurityContainer parent,
KeyguardUpdateMonitor updateMonitor, KeyguardSecurityCallback callback,
- Handler handler) {
+ @Main Handler handler) {
mContext = context;
mHandler = handler;
mParent = parent;
@@ -234,4 +238,26 @@ public class AdminSecondaryLockScreenController {
getHolder().removeCallback(mSurfaceHolderCallback);
}
}
+
+ @KeyguardBouncerScope
+ public static class Factory {
+ private final Context mContext;
+ private final KeyguardSecurityContainer mParent;
+ private final KeyguardUpdateMonitor mUpdateMonitor;
+ private final Handler mHandler;
+
+ @Inject
+ public Factory(Context context, KeyguardSecurityContainer parent,
+ KeyguardUpdateMonitor updateMonitor, @Main Handler handler) {
+ mContext = context;
+ mParent = parent;
+ mUpdateMonitor = updateMonitor;
+ mHandler = handler;
+ }
+
+ public AdminSecondaryLockScreenController create(KeyguardSecurityCallback callback) {
+ return new AdminSecondaryLockScreenController(mContext, mParent, mUpdateMonitor,
+ callback, mHandler);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index 88f4176f5eac..cc6df45c598f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -16,46 +16,26 @@
package com.android.keyguard;
-import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL;
-import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED;
-
import android.content.Context;
-import android.content.res.ColorStateList;
-import android.os.AsyncTask;
-import android.os.CountDownTimer;
-import android.os.SystemClock;
import android.util.AttributeSet;
import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
import android.view.View;
-import android.widget.LinearLayout;
-import com.android.internal.util.LatencyTracker;
-import com.android.internal.widget.LockPatternChecker;
-import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockscreenCredential;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
/**
* Base class for PIN and password unlock screens.
*/
-public abstract class KeyguardAbsKeyInputView extends LinearLayout
- implements KeyguardSecurityView, EmergencyButton.EmergencyButtonCallback {
- protected KeyguardSecurityCallback mCallback;
- protected LockPatternUtils mLockPatternUtils;
- protected AsyncTask<?, ?, ?> mPendingLockCheck;
- protected SecurityMessageDisplay mSecurityMessageDisplay;
+public abstract class KeyguardAbsKeyInputView extends KeyguardInputView {
protected View mEcaView;
protected boolean mEnableHaptics;
- private boolean mDismissing;
- protected boolean mResumed;
- private CountDownTimer mCountdownTimer = null;
- private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
// To avoid accidental lockout due to events while the device in in the pocket, ignore
// any passwords with length less than or equal to this length.
protected static final int MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT = 3;
+ private KeyDownListener mKeyDownListener;
public KeyguardAbsKeyInputView(Context context) {
this(context, null);
@@ -63,38 +43,10 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
public KeyguardAbsKeyInputView(Context context, AttributeSet attrs) {
super(context, attrs);
- mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
}
- @Override
- public void setKeyguardCallback(KeyguardSecurityCallback callback) {
- mCallback = callback;
- }
-
- @Override
- public void setLockPatternUtils(LockPatternUtils utils) {
- mLockPatternUtils = utils;
- mEnableHaptics = mLockPatternUtils.isTactileFeedbackEnabled();
- }
-
- @Override
- public void reset() {
- // start fresh
- mDismissing = false;
- resetPasswordText(false /* animate */, false /* announce */);
- // if the user is currently locked out, enforce it.
- long deadline = mLockPatternUtils.getLockoutAttemptDeadline(
- KeyguardUpdateMonitor.getCurrentUser());
- if (shouldLockout(deadline)) {
- handleAttemptLockout(deadline);
- } else {
- resetState();
- }
- }
-
- // Allow subclasses to override this behavior
- protected boolean shouldLockout(long deadline) {
- return deadline != 0;
+ void setEnableHaptics(boolean enableHaptics) {
+ mEnableHaptics = enableHaptics;
}
protected abstract int getPasswordTextViewId();
@@ -102,24 +54,7 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
@Override
protected void onFinishInflate() {
- mLockPatternUtils = new LockPatternUtils(mContext);
mEcaView = findViewById(R.id.keyguard_selector_fade_container);
-
- EmergencyButton button = findViewById(R.id.emergency_call_button);
- if (button != null) {
- button.setCallback(this);
- }
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- mSecurityMessageDisplay = KeyguardMessageArea.findSecurityMessageDisplay(this);
- }
-
- @Override
- public void onEmergencyButtonClickedWhenInCall() {
- mCallback.reset();
}
/*
@@ -131,195 +66,14 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
return R.string.kg_wrong_password;
}
- protected void verifyPasswordAndUnlock() {
- if (mDismissing) return; // already verified but haven't been dismissed; don't do it again.
-
- final LockscreenCredential password = getEnteredCredential();
- setPasswordEntryInputEnabled(false);
- if (mPendingLockCheck != null) {
- mPendingLockCheck.cancel(false);
- }
-
- final int userId = KeyguardUpdateMonitor.getCurrentUser();
- if (password.size() <= MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT) {
- // to avoid accidental lockout, only count attempts that are long enough to be a
- // real password. This may require some tweaking.
- setPasswordEntryInputEnabled(true);
- onPasswordChecked(userId, false /* matched */, 0, false /* not valid - too short */);
- password.zeroize();
- return;
- }
-
- if (LatencyTracker.isEnabled(mContext)) {
- LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL);
- LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL_UNLOCKED);
- }
-
- mKeyguardUpdateMonitor.setCredentialAttempted();
- mPendingLockCheck = LockPatternChecker.checkCredential(
- mLockPatternUtils,
- password,
- userId,
- new LockPatternChecker.OnCheckCallback() {
-
- @Override
- public void onEarlyMatched() {
- if (LatencyTracker.isEnabled(mContext)) {
- LatencyTracker.getInstance(mContext).onActionEnd(
- ACTION_CHECK_CREDENTIAL);
- }
- onPasswordChecked(userId, true /* matched */, 0 /* timeoutMs */,
- true /* isValidPassword */);
- password.zeroize();
- }
-
- @Override
- public void onChecked(boolean matched, int timeoutMs) {
- if (LatencyTracker.isEnabled(mContext)) {
- LatencyTracker.getInstance(mContext).onActionEnd(
- ACTION_CHECK_CREDENTIAL_UNLOCKED);
- }
- setPasswordEntryInputEnabled(true);
- mPendingLockCheck = null;
- if (!matched) {
- onPasswordChecked(userId, false /* matched */, timeoutMs,
- true /* isValidPassword */);
- }
- password.zeroize();
- }
-
- @Override
- public void onCancelled() {
- // We already got dismissed with the early matched callback, so we cancelled
- // the check. However, we still need to note down the latency.
- if (LatencyTracker.isEnabled(mContext)) {
- LatencyTracker.getInstance(mContext).onActionEnd(
- ACTION_CHECK_CREDENTIAL_UNLOCKED);
- }
- password.zeroize();
- }
- });
- }
-
- private void onPasswordChecked(int userId, boolean matched, int timeoutMs,
- boolean isValidPassword) {
- boolean dismissKeyguard = KeyguardUpdateMonitor.getCurrentUser() == userId;
- if (matched) {
- mCallback.reportUnlockAttempt(userId, true, 0);
- if (dismissKeyguard) {
- mDismissing = true;
- mCallback.dismiss(true, userId);
- }
- } else {
- if (isValidPassword) {
- mCallback.reportUnlockAttempt(userId, false, timeoutMs);
- if (timeoutMs > 0) {
- long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
- userId, timeoutMs);
- handleAttemptLockout(deadline);
- }
- }
- if (timeoutMs == 0) {
- mSecurityMessageDisplay.setMessage(getWrongPasswordStringId());
- }
- }
- resetPasswordText(true /* animate */, !matched /* announce deletion if no match */);
- }
-
protected abstract void resetPasswordText(boolean animate, boolean announce);
protected abstract LockscreenCredential getEnteredCredential();
protected abstract void setPasswordEntryEnabled(boolean enabled);
protected abstract void setPasswordEntryInputEnabled(boolean enabled);
- // Prevent user from using the PIN/Password entry until scheduled deadline.
- protected void handleAttemptLockout(long elapsedRealtimeDeadline) {
- setPasswordEntryEnabled(false);
- long elapsedRealtime = SystemClock.elapsedRealtime();
- long secondsInFuture = (long) Math.ceil(
- (elapsedRealtimeDeadline - elapsedRealtime) / 1000.0);
- mCountdownTimer = new CountDownTimer(secondsInFuture * 1000, 1000) {
-
- @Override
- public void onTick(long millisUntilFinished) {
- int secondsRemaining = (int) Math.round(millisUntilFinished / 1000.0);
- mSecurityMessageDisplay.setMessage(mContext.getResources().getQuantityString(
- R.plurals.kg_too_many_failed_attempts_countdown,
- secondsRemaining, secondsRemaining));
- }
-
- @Override
- public void onFinish() {
- mSecurityMessageDisplay.setMessage("");
- resetState();
- }
- }.start();
- }
-
- protected void onUserInput() {
- if (mCallback != null) {
- mCallback.userActivity();
- mCallback.onUserInput();
- }
- mSecurityMessageDisplay.setMessage("");
- }
-
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
- // Fingerprint sensor sends a KeyEvent.KEYCODE_UNKNOWN.
- // We don't want to consider it valid user input because the UI
- // will already respond to the event.
- if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
- onUserInput();
- }
- return false;
- }
-
- @Override
- public boolean needsInput() {
- return false;
- }
-
- @Override
- public void onPause() {
- mResumed = false;
-
- if (mCountdownTimer != null) {
- mCountdownTimer.cancel();
- mCountdownTimer = null;
- }
- if (mPendingLockCheck != null) {
- mPendingLockCheck.cancel(false);
- mPendingLockCheck = null;
- }
- reset();
- }
-
- @Override
- public void onResume(int reason) {
- mResumed = true;
- }
-
- @Override
- public KeyguardSecurityCallback getCallback() {
- return mCallback;
- }
-
- @Override
- public void showPromptReason(int reason) {
- if (reason != PROMPT_REASON_NONE) {
- int promtReasonStringRes = getPromptReasonStringRes(reason);
- if (promtReasonStringRes != 0) {
- mSecurityMessageDisplay.setMessage(promtReasonStringRes);
- }
- }
- }
-
- @Override
- public void showMessage(CharSequence message, ColorStateList colorState) {
- if (colorState != null) {
- mSecurityMessageDisplay.setNextMessageColor(colorState);
- }
- mSecurityMessageDisplay.setMessage(message);
+ return mKeyDownListener != null && mKeyDownListener.onKeyDown(keyCode, event);
}
protected abstract int getPromptReasonStringRes(int reason);
@@ -333,9 +87,12 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
}
}
- @Override
- public boolean startDisappearAnimation(Runnable finishRunnable) {
- return false;
+ public void setKeyDownListener(KeyDownListener keyDownListener) {
+ mKeyDownListener = keyDownListener;
+ }
+
+ public interface KeyDownListener {
+ boolean onKeyDown(int keyCode, KeyEvent keyEvent);
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
new file mode 100644
index 000000000000..d957628c52ab
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL;
+import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED;
+import static com.android.keyguard.KeyguardAbsKeyInputView.MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT;
+
+import android.content.res.ColorStateList;
+import android.os.AsyncTask;
+import android.os.CountDownTimer;
+import android.os.SystemClock;
+import android.view.KeyEvent;
+
+import com.android.internal.util.LatencyTracker;
+import com.android.internal.widget.LockPatternChecker;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockscreenCredential;
+import com.android.keyguard.EmergencyButton.EmergencyButtonCallback;
+import com.android.keyguard.KeyguardAbsKeyInputView.KeyDownListener;
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.systemui.R;
+
+public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKeyInputView>
+ extends KeyguardInputViewController<T> {
+ private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private final LockPatternUtils mLockPatternUtils;
+ private final LatencyTracker mLatencyTracker;
+ private CountDownTimer mCountdownTimer;
+ protected KeyguardMessageAreaController mMessageAreaController;
+ private boolean mDismissing;
+ protected AsyncTask<?, ?, ?> mPendingLockCheck;
+ protected boolean mResumed;
+
+ private final KeyDownListener mKeyDownListener = (keyCode, keyEvent) -> {
+ // Fingerprint sensor sends a KeyEvent.KEYCODE_UNKNOWN.
+ // We don't want to consider it valid user input because the UI
+ // will already respond to the event.
+ if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
+ onUserInput();
+ }
+ return false;
+ };
+
+ private final EmergencyButtonCallback mEmergencyButtonCallback = new EmergencyButtonCallback() {
+ @Override
+ public void onEmergencyButtonClickedWhenInCall() {
+ getKeyguardSecurityCallback().reset();
+ }
+ };
+
+ protected KeyguardAbsKeyInputViewController(T view,
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ SecurityMode securityMode,
+ LockPatternUtils lockPatternUtils,
+ KeyguardSecurityCallback keyguardSecurityCallback,
+ KeyguardMessageAreaController.Factory messageAreaControllerFactory,
+ LatencyTracker latencyTracker) {
+ super(view, securityMode, keyguardSecurityCallback);
+ mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+ mLockPatternUtils = lockPatternUtils;
+ mLatencyTracker = latencyTracker;
+ KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView);
+ mMessageAreaController = messageAreaControllerFactory.create(kma);
+ }
+
+ abstract void resetState();
+
+ @Override
+ public void init() {
+ super.init();
+ mMessageAreaController.init();
+ }
+
+ @Override
+ protected void onViewAttached() {
+ mView.setKeyDownListener(mKeyDownListener);
+ mView.setEnableHaptics(mLockPatternUtils.isTactileFeedbackEnabled());
+ EmergencyButton button = mView.findViewById(R.id.emergency_call_button);
+ if (button != null) {
+ button.setCallback(mEmergencyButtonCallback);
+ }
+ }
+
+ @Override
+ public void reset() {
+ // start fresh
+ mDismissing = false;
+ mView.resetPasswordText(false /* animate */, false /* announce */);
+ // if the user is currently locked out, enforce it.
+ long deadline = mLockPatternUtils.getLockoutAttemptDeadline(
+ KeyguardUpdateMonitor.getCurrentUser());
+ if (shouldLockout(deadline)) {
+ handleAttemptLockout(deadline);
+ } else {
+ mView.resetState();
+ }
+ }
+
+ @Override
+ public boolean needsInput() {
+ return false;
+ }
+
+ @Override
+ public void showMessage(CharSequence message, ColorStateList colorState) {
+ if (colorState != null) {
+ mMessageAreaController.setNextMessageColor(colorState);
+ }
+ mMessageAreaController.setMessage(message);
+ }
+
+ // Allow subclasses to override this behavior
+ protected boolean shouldLockout(long deadline) {
+ return deadline != 0;
+ }
+
+ // Prevent user from using the PIN/Password entry until scheduled deadline.
+ protected void handleAttemptLockout(long elapsedRealtimeDeadline) {
+ mView.setPasswordEntryEnabled(false);
+ long elapsedRealtime = SystemClock.elapsedRealtime();
+ long secondsInFuture = (long) Math.ceil(
+ (elapsedRealtimeDeadline - elapsedRealtime) / 1000.0);
+ mCountdownTimer = new CountDownTimer(secondsInFuture * 1000, 1000) {
+
+ @Override
+ public void onTick(long millisUntilFinished) {
+ int secondsRemaining = (int) Math.round(millisUntilFinished / 1000.0);
+ mMessageAreaController.setMessage(mView.getResources().getQuantityString(
+ R.plurals.kg_too_many_failed_attempts_countdown,
+ secondsRemaining, secondsRemaining));
+ }
+
+ @Override
+ public void onFinish() {
+ mMessageAreaController.setMessage("");
+ resetState();
+ }
+ }.start();
+ }
+
+ void onPasswordChecked(int userId, boolean matched, int timeoutMs, boolean isValidPassword) {
+ boolean dismissKeyguard = KeyguardUpdateMonitor.getCurrentUser() == userId;
+ if (matched) {
+ getKeyguardSecurityCallback().reportUnlockAttempt(userId, true, 0);
+ if (dismissKeyguard) {
+ mDismissing = true;
+ getKeyguardSecurityCallback().dismiss(true, userId);
+ }
+ } else {
+ if (isValidPassword) {
+ getKeyguardSecurityCallback().reportUnlockAttempt(userId, false, timeoutMs);
+ if (timeoutMs > 0) {
+ long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
+ userId, timeoutMs);
+ handleAttemptLockout(deadline);
+ }
+ }
+ if (timeoutMs == 0) {
+ mMessageAreaController.setMessage(mView.getWrongPasswordStringId());
+ }
+ }
+ mView.resetPasswordText(true /* animate */, !matched /* announce deletion if no match */);
+ }
+
+ protected void verifyPasswordAndUnlock() {
+ if (mDismissing) return; // already verified but haven't been dismissed; don't do it again.
+
+ final LockscreenCredential password = mView.getEnteredCredential();
+ mView.setPasswordEntryInputEnabled(false);
+ if (mPendingLockCheck != null) {
+ mPendingLockCheck.cancel(false);
+ }
+
+ final int userId = KeyguardUpdateMonitor.getCurrentUser();
+ if (password.size() <= MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT) {
+ // to avoid accidental lockout, only count attempts that are long enough to be a
+ // real password. This may require some tweaking.
+ mView.setPasswordEntryInputEnabled(true);
+ onPasswordChecked(userId, false /* matched */, 0, false /* not valid - too short */);
+ password.zeroize();
+ return;
+ }
+
+ mLatencyTracker.onActionStart(ACTION_CHECK_CREDENTIAL);
+ mLatencyTracker.onActionStart(ACTION_CHECK_CREDENTIAL_UNLOCKED);
+
+ mKeyguardUpdateMonitor.setCredentialAttempted();
+ mPendingLockCheck = LockPatternChecker.checkCredential(
+ mLockPatternUtils,
+ password,
+ userId,
+ new LockPatternChecker.OnCheckCallback() {
+
+ @Override
+ public void onEarlyMatched() {
+ mLatencyTracker.onActionEnd(ACTION_CHECK_CREDENTIAL);
+
+ onPasswordChecked(userId, true /* matched */, 0 /* timeoutMs */,
+ true /* isValidPassword */);
+ password.zeroize();
+ }
+
+ @Override
+ public void onChecked(boolean matched, int timeoutMs) {
+ mLatencyTracker.onActionEnd(ACTION_CHECK_CREDENTIAL_UNLOCKED);
+ mView.setPasswordEntryInputEnabled(true);
+ mPendingLockCheck = null;
+ if (!matched) {
+ onPasswordChecked(userId, false /* matched */, timeoutMs,
+ true /* isValidPassword */);
+ }
+ password.zeroize();
+ }
+
+ @Override
+ public void onCancelled() {
+ // We already got dismissed with the early matched callback, so we cancelled
+ // the check. However, we still need to note down the latency.
+ mLatencyTracker.onActionEnd(ACTION_CHECK_CREDENTIAL_UNLOCKED);
+ password.zeroize();
+ }
+ });
+ }
+
+ @Override
+ public void showPromptReason(int reason) {
+ if (reason != PROMPT_REASON_NONE) {
+ int promtReasonStringRes = mView.getPromptReasonStringRes(reason);
+ if (promtReasonStringRes != 0) {
+ mMessageAreaController.setMessage(promtReasonStringRes);
+ }
+ }
+ }
+
+ protected void onUserInput() {
+ getKeyguardSecurityCallback().userActivity();
+ getKeyguardSecurityCallback().onUserInput();
+ mMessageAreaController.setMessage("");
+ }
+
+ @Override
+ public void onResume(int reason) {
+ mResumed = true;
+ }
+
+ @Override
+ public void onPause() {
+ mResumed = false;
+
+ if (mCountdownTimer != null) {
+ mCountdownTimer.cancel();
+ mCountdownTimer = null;
+ }
+ if (mPendingLockCheck != null) {
+ mPendingLockCheck.cancel(false);
+ mPendingLockCheck = null;
+ }
+ reset();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index be21d203411e..36d5543f1c01 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -39,7 +39,6 @@ import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.navigationbar.NavigationBarView;
-import com.android.systemui.util.InjectionInflationController;
import javax.inject.Inject;
@@ -49,7 +48,6 @@ public class KeyguardDisplayManager {
private final MediaRouter mMediaRouter;
private final DisplayManager mDisplayService;
- private final InjectionInflationController mInjectableInflater;
private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
private final Context mContext;
@@ -92,10 +90,8 @@ public class KeyguardDisplayManager {
@Inject
public KeyguardDisplayManager(Context context,
- InjectionInflationController injectableInflater,
KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory) {
mContext = context;
- mInjectableInflater = injectableInflater;
mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
mMediaRouter = mContext.getSystemService(MediaRouter.class);
mDisplayService = mContext.getSystemService(DisplayManager.class);
@@ -131,8 +127,7 @@ public class KeyguardDisplayManager {
Presentation presentation = mPresentations.get(displayId);
if (presentation == null) {
final Presentation newPresentation = new KeyguardPresentation(mContext, display,
- mKeyguardStatusViewComponentFactory,
- mInjectableInflater.injectable(LayoutInflater.from(mContext)));
+ mKeyguardStatusViewComponentFactory, LayoutInflater.from(mContext));
newPresentation.setOnDismissListener(dialog -> {
if (newPresentation.equals(mPresentations.get(displayId))) {
mPresentations.remove(displayId);
@@ -250,7 +245,7 @@ public class KeyguardDisplayManager {
private static final int VIDEO_SAFE_REGION = 80; // Percentage of display width & height
private static final int MOVE_CLOCK_TIMEOUT = 10000; // 10s
private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
- private final LayoutInflater mInjectableLayoutInflater;
+ private final LayoutInflater mLayoutInflater;
private KeyguardClockSwitchController mKeyguardClockSwitchController;
private View mClock;
private int mUsableWidth;
@@ -270,10 +265,10 @@ public class KeyguardDisplayManager {
KeyguardPresentation(Context context, Display display,
KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory,
- LayoutInflater injectionLayoutInflater) {
+ LayoutInflater layoutInflater) {
super(context, display, R.style.Theme_SystemUI_KeyguardPresentation);
mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
- mInjectableLayoutInflater = injectionLayoutInflater;
+ mLayoutInflater = layoutInflater;
getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
setCancelable(false);
}
@@ -299,7 +294,7 @@ public class KeyguardDisplayManager {
mMarginLeft = (100 - VIDEO_SAFE_REGION) * p.x / 200;
mMarginTop = (100 - VIDEO_SAFE_REGION) * p.y / 200;
- setContentView(mInjectableLayoutInflater.inflate(R.layout.keyguard_presentation, null));
+ setContentView(mLayoutInflater.inflate(R.layout.keyguard_presentation, null));
// Logic to make the lock screen fullscreen
getWindow().getDecorView().setSystemUiVisibility(
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
index 7aabb17de90c..9ffa658da0e8 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
@@ -178,18 +178,18 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView>
/** Initialize the Controller. */
public void init() {
super.init();
- mView.setViewMediatorCallback(mViewMediatorCallback);
- // Update ViewMediator with the current input method requirements
- mViewMediatorCallback.setNeedsInput(mKeyguardSecurityContainerController.needsInput());
mKeyguardSecurityContainerController.init();
- mKeyguardSecurityContainerController.setSecurityCallback(mSecurityCallback);
- mKeyguardSecurityContainerController.showPrimarySecurityScreen(false);
}
@Override
protected void onViewAttached() {
+ mView.setViewMediatorCallback(mViewMediatorCallback);
+ // Update ViewMediator with the current input method requirements
+ mViewMediatorCallback.setNeedsInput(mKeyguardSecurityContainerController.needsInput());
mKeyguardUpdateMonitor.registerCallback(mUpdateCallback);
mView.setOnKeyListener(mOnKeyListener);
+ mKeyguardSecurityContainerController.setSecurityCallback(mSecurityCallback);
+ mKeyguardSecurityContainerController.showPrimarySecurityScreen(false);
}
@Override
@@ -350,7 +350,7 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView>
}
public boolean handleBackKey() {
- if (mKeyguardSecurityContainerController.getCurrentSecuritySelection()
+ if (mKeyguardSecurityContainerController.getCurrentSecurityMode()
!= SecurityMode.None) {
mKeyguardSecurityContainerController.dismiss(
false, KeyguardUpdateMonitor.getCurrentUser());
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java
new file mode 100644
index 000000000000..d42a53cc875e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.widget.LinearLayout;
+
+import androidx.annotation.Nullable;
+
+/**
+ * A Base class for all Keyguard password/pattern/pin related inputs.
+ */
+public abstract class KeyguardInputView extends LinearLayout {
+
+ public KeyguardInputView(Context context) {
+ super(context);
+ }
+
+ public KeyguardInputView(Context context,
+ @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public KeyguardInputView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ abstract CharSequence getTitle();
+
+ boolean disallowInterceptTouch(MotionEvent event) {
+ return false;
+ }
+
+ void startAppearAnimation() {}
+
+ boolean startDisappearAnimation(Runnable finishRunnable) {
+ return false;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
new file mode 100644
index 000000000000..fbda818740e8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.telephony.TelephonyManager;
+import android.view.inputmethod.InputMethodManager;
+
+import com.android.internal.util.LatencyTracker;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.util.ViewController;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+
+import javax.inject.Inject;
+
+
+/** Controller for a {@link KeyguardSecurityView}. */
+public abstract class KeyguardInputViewController<T extends KeyguardInputView>
+ extends ViewController<T> implements KeyguardSecurityView {
+
+ private final SecurityMode mSecurityMode;
+ private final KeyguardSecurityCallback mKeyguardSecurityCallback;
+ private boolean mPaused;
+
+
+ // The following is used to ignore callbacks from SecurityViews that are no longer current
+ // (e.g. face unlock). This avoids unwanted asynchronous events from messing with the
+ // state for the current security method.
+ private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() {
+ @Override
+ public void userActivity() { }
+ @Override
+ public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) { }
+ @Override
+ public boolean isVerifyUnlockOnly() {
+ return false;
+ }
+ @Override
+ public void dismiss(boolean securityVerified, int targetUserId) { }
+ @Override
+ public void dismiss(boolean authenticated, int targetId,
+ boolean bypassSecondaryLockScreen) { }
+ @Override
+ public void onUserInput() { }
+ @Override
+ public void reset() {}
+ };
+
+ protected KeyguardInputViewController(T view, SecurityMode securityMode,
+ KeyguardSecurityCallback keyguardSecurityCallback) {
+ super(view);
+ mSecurityMode = securityMode;
+ mKeyguardSecurityCallback = keyguardSecurityCallback;
+ }
+
+ @Override
+ protected void onViewAttached() {
+ }
+
+ @Override
+ protected void onViewDetached() {
+ }
+
+ SecurityMode getSecurityMode() {
+ return mSecurityMode;
+ }
+
+ protected KeyguardSecurityCallback getKeyguardSecurityCallback() {
+ if (mPaused) {
+ return mNullCallback;
+ }
+
+ return mKeyguardSecurityCallback;
+ }
+
+ @Override
+ public void reset() {
+ }
+
+ @Override
+ public void onPause() {
+ mPaused = true;
+ }
+
+ @Override
+ public void onResume(int reason) {
+ mPaused = false;
+ }
+
+ @Override
+ public void showPromptReason(int reason) {
+ }
+
+ @Override
+ public void showMessage(CharSequence message, ColorStateList colorState) {
+ }
+
+ public void startAppearAnimation() {
+ mView.startAppearAnimation();
+ }
+
+ public boolean startDisappearAnimation(Runnable finishRunnable) {
+ return mView.startDisappearAnimation(finishRunnable);
+ }
+
+ @Override
+ public CharSequence getTitle() {
+ return mView.getTitle();
+ }
+
+ /** Finds the index of this view in the suppplied parent view. */
+ public int getIndexIn(KeyguardSecurityViewFlipper view) {
+ return view.indexOfChild(mView);
+ }
+
+ /** Factory for a {@link KeyguardInputViewController}. */
+ public static class Factory {
+ private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private final LockPatternUtils mLockPatternUtils;
+ private final LatencyTracker mLatencyTracker;
+ private final KeyguardMessageAreaController.Factory mMessageAreaControllerFactory;
+ private final InputMethodManager mInputMethodManager;
+ private final DelayableExecutor mMainExecutor;
+ private final Resources mResources;
+ private LiftToActivateListener mLiftToActivateListener;
+ private TelephonyManager mTelephonyManager;
+
+ @Inject
+ public Factory(KeyguardUpdateMonitor keyguardUpdateMonitor,
+ LockPatternUtils lockPatternUtils,
+ LatencyTracker latencyTracker,
+ KeyguardMessageAreaController.Factory messageAreaControllerFactory,
+ InputMethodManager inputMethodManager, @Main DelayableExecutor mainExecutor,
+ @Main Resources resources, LiftToActivateListener liftToActivateListener,
+ TelephonyManager telephonyManager) {
+ mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+ mLockPatternUtils = lockPatternUtils;
+ mLatencyTracker = latencyTracker;
+ mMessageAreaControllerFactory = messageAreaControllerFactory;
+ mInputMethodManager = inputMethodManager;
+ mMainExecutor = mainExecutor;
+ mResources = resources;
+ mLiftToActivateListener = liftToActivateListener;
+ mTelephonyManager = telephonyManager;
+ }
+
+ /** Create a new {@link KeyguardInputViewController}. */
+ public KeyguardInputViewController create(KeyguardInputView keyguardInputView,
+ SecurityMode securityMode, KeyguardSecurityCallback keyguardSecurityCallback) {
+ if (keyguardInputView instanceof KeyguardPatternView) {
+ return new KeyguardPatternViewController((KeyguardPatternView) keyguardInputView,
+ mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
+ keyguardSecurityCallback, mLatencyTracker, mMessageAreaControllerFactory);
+ } else if (keyguardInputView instanceof KeyguardPasswordView) {
+ return new KeyguardPasswordViewController((KeyguardPasswordView) keyguardInputView,
+ mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
+ keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
+ mInputMethodManager, mMainExecutor, mResources);
+ } else if (keyguardInputView instanceof KeyguardPINView) {
+ return new KeyguardPinViewController((KeyguardPINView) keyguardInputView,
+ mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
+ keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
+ mLiftToActivateListener);
+ } else if (keyguardInputView instanceof KeyguardSimPinView) {
+ return new KeyguardSimPinViewController((KeyguardSimPinView) keyguardInputView,
+ mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
+ keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
+ mLiftToActivateListener, mTelephonyManager);
+ } else if (keyguardInputView instanceof KeyguardSimPukView) {
+ return new KeyguardSimPukViewController((KeyguardSimPukView) keyguardInputView,
+ mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
+ keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
+ mLiftToActivateListener, mTelephonyManager);
+ }
+
+ throw new RuntimeException("Unable to find controller for " + keyguardInputView);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
index a8b1451d92c7..1a0a4370fca4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
@@ -16,8 +16,6 @@
package com.android.keyguard;
-import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
-
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
@@ -31,20 +29,14 @@ import android.util.TypedValue;
import android.view.View;
import android.widget.TextView;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.statusbar.policy.ConfigurationController;
import java.lang.ref.WeakReference;
-import javax.inject.Inject;
-import javax.inject.Named;
-
/***
* Manages a number of views inside of the given layout. See below for a list of widgets.
*/
-public class KeyguardMessageArea extends TextView implements SecurityMessageDisplay,
- ConfigurationController.ConfigurationListener {
+public class KeyguardMessageArea extends TextView implements SecurityMessageDisplay {
/** Handler token posted with accessibility announcement runnables. */
private static final Object ANNOUNCE_TOKEN = new Object();
@@ -56,71 +48,26 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp
private static final int DEFAULT_COLOR = -1;
private final Handler mHandler;
- private final ConfigurationController mConfigurationController;
private ColorStateList mDefaultColorState;
private CharSequence mMessage;
private ColorStateList mNextMessageColorState = ColorStateList.valueOf(DEFAULT_COLOR);
private boolean mBouncerVisible;
- private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
- public void onFinishedGoingToSleep(int why) {
- setSelected(false);
- }
-
- public void onStartedWakingUp() {
- setSelected(true);
- }
-
- @Override
- public void onKeyguardBouncerChanged(boolean bouncer) {
- mBouncerVisible = bouncer;
- update();
- }
- };
-
- public KeyguardMessageArea(Context context) {
- super(context, null);
- throw new IllegalStateException("This constructor should never be invoked");
- }
-
- @Inject
- public KeyguardMessageArea(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
- ConfigurationController configurationController) {
- this(context, attrs, Dependency.get(KeyguardUpdateMonitor.class), configurationController);
- }
-
- public KeyguardMessageArea(Context context, AttributeSet attrs, KeyguardUpdateMonitor monitor,
- ConfigurationController configurationController) {
+ public KeyguardMessageArea(Context context, AttributeSet attrs) {
super(context, attrs);
setLayerType(LAYER_TYPE_HARDWARE, null); // work around nested unclipped SaveLayer bug
- monitor.registerCallback(mInfoCallback);
mHandler = new Handler(Looper.myLooper());
- mConfigurationController = configurationController;
onThemeChanged();
}
@Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- mConfigurationController.addCallback(this);
- onThemeChanged();
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- mConfigurationController.removeCallback(this);
- }
-
- @Override
public void setNextMessageColor(ColorStateList colorState) {
mNextMessageColorState = colorState;
}
- @Override
- public void onThemeChanged() {
+ void onThemeChanged() {
TypedArray array = mContext.obtainStyledAttributes(new int[] {
R.attr.wallpaperTextColor
});
@@ -130,8 +77,7 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp
update();
}
- @Override
- public void onDensityOrFontScaleChanged() {
+ void onDensityOrFontScaleChanged() {
TypedArray array = mContext.obtainStyledAttributes(R.style.Keyguard_TextView, new int[] {
android.R.attr.textSize
});
@@ -177,12 +123,6 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp
return messageArea;
}
- @Override
- protected void onFinishInflate() {
- boolean shouldMarquee = Dependency.get(KeyguardUpdateMonitor.class).isDeviceInteractive();
- setSelected(shouldMarquee); // This is required to ensure marquee works
- }
-
private void securityMessageChanged(CharSequence message) {
mMessage = message;
update();
@@ -196,7 +136,7 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp
update();
}
- private void update() {
+ void update() {
CharSequence status = mMessage;
setVisibility(TextUtils.isEmpty(status) || !mBouncerVisible ? INVISIBLE : VISIBLE);
setText(status);
@@ -208,6 +148,9 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp
setTextColor(colorState);
}
+ public void setBouncerVisible(boolean bouncerVisible) {
+ mBouncerVisible = bouncerVisible;
+ }
/**
* Runnable used to delay accessibility announcements.
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
index f056bdbb9706..1618e8e58055 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
@@ -16,7 +16,10 @@
package com.android.keyguard;
+import android.content.res.ColorStateList;
+
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
import com.android.systemui.util.ViewController;
import javax.inject.Inject;
@@ -26,6 +29,35 @@ public class KeyguardMessageAreaController extends ViewController<KeyguardMessag
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final ConfigurationController mConfigurationController;
+
+ private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
+ public void onFinishedGoingToSleep(int why) {
+ mView.setSelected(false);
+ }
+
+ public void onStartedWakingUp() {
+ mView.setSelected(true);
+ }
+
+ @Override
+ public void onKeyguardBouncerChanged(boolean bouncer) {
+ mView.setBouncerVisible(bouncer);
+ mView.update();
+ }
+ };
+
+ private ConfigurationListener mConfigurationListener = new ConfigurationListener() {
+ @Override
+ public void onThemeChanged() {
+ mView.onThemeChanged();
+ }
+
+ @Override
+ public void onDensityOrFontScaleChanged() {
+ mView.onDensityOrFontScaleChanged();
+ }
+ };
+
private KeyguardMessageAreaController(KeyguardMessageArea view,
KeyguardUpdateMonitor keyguardUpdateMonitor,
ConfigurationController configurationController) {
@@ -37,17 +69,31 @@ public class KeyguardMessageAreaController extends ViewController<KeyguardMessag
@Override
protected void onViewAttached() {
- //mConfigurationController.addCallback();
- //mKeyguardUpdateMonitor.registerCallback();
+ mConfigurationController.addCallback(mConfigurationListener);
+ mKeyguardUpdateMonitor.registerCallback(mInfoCallback);
+ mView.setSelected(mKeyguardUpdateMonitor.isDeviceInteractive());
+ mView.onThemeChanged();
}
@Override
protected void onViewDetached() {
- //mConfigurationController.removeCallback();
- //mKeyguardUpdateMonitor.removeCallback();
+ mConfigurationController.removeCallback(mConfigurationListener);
+ mKeyguardUpdateMonitor.removeCallback(mInfoCallback);
+ }
+
+ public void setMessage(CharSequence s) {
+ mView.setMessage(s);
+ }
+
+ public void setMessage(int resId) {
+ mView.setMessage(resId);
+ }
+
+ public void setNextMessageColor(ColorStateList colorState) {
+ mView.setNextMessageColor(colorState);
}
- /** Factory for createing {@link com.android.keyguard.KeyguardMessageAreaController}. */
+ /** Factory for creating {@link com.android.keyguard.KeyguardMessageAreaController}. */
public static class Factory {
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final ConfigurationController mConfigurationController;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
index 12ea1d586e10..580d7043a220 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
@@ -24,7 +24,6 @@ import android.view.animation.AnimationUtils;
import com.android.settingslib.animation.AppearAnimationUtils;
import com.android.settingslib.animation.DisappearAnimationUtils;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
/**
@@ -40,10 +39,8 @@ public class KeyguardPINView extends KeyguardPinBasedInputView {
private ViewGroup mRow1;
private ViewGroup mRow2;
private ViewGroup mRow3;
- private View mDivider;
private int mDisappearYTranslation;
private View[][] mViews;
- private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
public KeyguardPINView(Context context) {
this(context, null);
@@ -63,15 +60,10 @@ public class KeyguardPINView extends KeyguardPinBasedInputView {
mContext, android.R.interpolator.fast_out_linear_in));
mDisappearYTranslation = getResources().getDimensionPixelSize(
R.dimen.disappear_y_translation);
- mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
}
@Override
protected void resetState() {
- super.resetState();
- if (mSecurityMessageDisplay != null) {
- mSecurityMessageDisplay.setMessage("");
- }
}
@Override
@@ -88,7 +80,6 @@ public class KeyguardPINView extends KeyguardPinBasedInputView {
mRow1 = findViewById(R.id.row1);
mRow2 = findViewById(R.id.row2);
mRow3 = findViewById(R.id.row3);
- mDivider = findViewById(R.id.divider);
mViews = new View[][]{
new View[]{
mRow0, null, null
@@ -112,18 +103,6 @@ public class KeyguardPINView extends KeyguardPinBasedInputView {
new View[]{
null, mEcaView, null
}};
-
- View cancelBtn = findViewById(R.id.cancel_button);
- if (cancelBtn != null) {
- cancelBtn.setOnClickListener(view -> {
- mCallback.reset();
- mCallback.onCancelClicked();
- });
- }
- }
-
- @Override
- public void showUsabilityHint() {
}
@Override
@@ -147,24 +126,21 @@ public class KeyguardPINView extends KeyguardPinBasedInputView {
});
}
- @Override
- public boolean startDisappearAnimation(final Runnable finishRunnable) {
+ public boolean startDisappearAnimation(boolean needsSlowUnlockTransition,
+ final Runnable finishRunnable) {
+
enableClipping(false);
setTranslationY(0);
AppearAnimationUtils.startTranslationYAnimation(this, 0 /* delay */, 280 /* duration */,
mDisappearYTranslation, mDisappearAnimationUtils.getInterpolator());
- DisappearAnimationUtils disappearAnimationUtils = mKeyguardUpdateMonitor
- .needsSlowUnlockTransition()
+ DisappearAnimationUtils disappearAnimationUtils = needsSlowUnlockTransition
? mDisappearAnimationUtilsLocked
: mDisappearAnimationUtils;
disappearAnimationUtils.startAnimation2d(mViews,
- new Runnable() {
- @Override
- public void run() {
- enableClipping(true);
- if (finishRunnable != null) {
- finishRunnable.run();
- }
+ () -> {
+ enableClipping(true);
+ if (finishRunnable != null) {
+ finishRunnable.run();
}
});
return true;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 97317cf5580f..aaa5efec807e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -16,50 +16,37 @@
package com.android.keyguard;
+import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN;
+import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NONE;
+import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE;
+import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART;
+import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT;
+import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST;
+
import android.content.Context;
import android.graphics.Rect;
-import android.os.UserHandle;
-import android.text.Editable;
-import android.text.InputType;
-import android.text.TextUtils;
-import android.text.TextWatcher;
-import android.text.method.TextKeyListener;
import android.util.AttributeSet;
-import android.view.KeyEvent;
-import android.view.View;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.view.inputmethod.InputMethodSubtype;
import android.widget.TextView;
-import android.widget.TextView.OnEditorActionListener;
import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.TextViewInputDisabler;
import com.android.systemui.R;
-
-import java.util.List;
/**
* Displays an alphanumeric (latin-1) key entry for the user to enter
* an unlock password
*/
-public class KeyguardPasswordView extends KeyguardAbsKeyInputView
- implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
+public class KeyguardPasswordView extends KeyguardAbsKeyInputView {
- private final boolean mShowImeAtScreenOn;
private final int mDisappearYTranslation;
// A delay constant to be used in a workaround for the situation where InputMethodManagerService
// is not switched to the new user yet.
// TODO: Remove this by ensuring such a race condition never happens.
- private static final int DELAY_MILLIS_TO_REEVALUATE_IME_SWITCH_ICON = 500; // 500ms
- InputMethodManager mImm;
private TextView mPasswordEntry;
private TextViewInputDisabler mPasswordEntryDisabler;
- private View mSwitchImeButton;
private Interpolator mLinearOutSlowInInterpolator;
private Interpolator mFastOutLinearInInterpolator;
@@ -70,8 +57,6 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView
public KeyguardPasswordView(Context context, AttributeSet attrs) {
super(context, attrs);
- mShowImeAtScreenOn = context.getResources().
- getBoolean(R.bool.kg_show_ime_at_screen_on);
mDisappearYTranslation = getResources().getDimensionPixelSize(
R.dimen.disappear_y_translation);
mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(
@@ -82,20 +67,6 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView
@Override
protected void resetState() {
- mPasswordEntry.setTextOperationUser(UserHandle.of(KeyguardUpdateMonitor.getCurrentUser()));
- if (mSecurityMessageDisplay != null) {
- mSecurityMessageDisplay.setMessage("");
- }
- final boolean wasDisabled = mPasswordEntry.isEnabled();
- setPasswordEntryEnabled(true);
- setPasswordEntryInputEnabled(true);
- // Don't call showSoftInput when PasswordEntry is invisible or in pausing stage.
- if (!mResumed || !mPasswordEntry.isVisibleToUser()) {
- return;
- }
- if (wasDisabled) {
- mImm.showSoftInput(mPasswordEntry, InputMethodManager.SHOW_IMPLICIT);
- }
}
@Override
@@ -104,29 +75,6 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView
}
@Override
- public boolean needsInput() {
- return true;
- }
-
- @Override
- public void onResume(final int reason) {
- super.onResume(reason);
-
- // Wait a bit to focus the field so the focusable flag on the window is already set then.
- post(new Runnable() {
- @Override
- public void run() {
- if (isShown() && mPasswordEntry.isEnabled()) {
- mPasswordEntry.requestFocus();
- if (reason != KeyguardSecurityView.SCREEN_ON || mShowImeAtScreenOn) {
- mImm.showSoftInput(mPasswordEntry, InputMethodManager.SHOW_IMPLICIT);
- }
- }
- }
- });
- }
-
- @Override
protected int getPromptReasonStringRes(int reason) {
switch (reason) {
case PROMPT_REASON_RESTART:
@@ -146,97 +94,13 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView
}
}
- @Override
- public void onPause() {
- super.onPause();
- mImm.hideSoftInputFromWindow(getWindowToken(), 0);
- }
-
- @Override
- public void onStartingToHide() {
- mImm.hideSoftInputFromWindow(getWindowToken(), 0);
- }
-
- private void updateSwitchImeButton() {
- // If there's more than one IME, enable the IME switcher button
- final boolean wasVisible = mSwitchImeButton.getVisibility() == View.VISIBLE;
- final boolean shouldBeVisible = hasMultipleEnabledIMEsOrSubtypes(mImm, false);
- if (wasVisible != shouldBeVisible) {
- mSwitchImeButton.setVisibility(shouldBeVisible ? View.VISIBLE : View.GONE);
- }
-
- // TODO: Check if we still need this hack.
- // If no icon is visible, reset the start margin on the password field so the text is
- // still centered.
- if (mSwitchImeButton.getVisibility() != View.VISIBLE) {
- android.view.ViewGroup.LayoutParams params = mPasswordEntry.getLayoutParams();
- if (params instanceof MarginLayoutParams) {
- final MarginLayoutParams mlp = (MarginLayoutParams) params;
- mlp.setMarginStart(0);
- mPasswordEntry.setLayoutParams(params);
- }
- }
- }
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mImm = (InputMethodManager) getContext().getSystemService(
- Context.INPUT_METHOD_SERVICE);
-
mPasswordEntry = findViewById(getPasswordTextViewId());
- mPasswordEntry.setTextOperationUser(UserHandle.of(KeyguardUpdateMonitor.getCurrentUser()));
mPasswordEntryDisabler = new TextViewInputDisabler(mPasswordEntry);
- mPasswordEntry.setKeyListener(TextKeyListener.getInstance());
- mPasswordEntry.setInputType(InputType.TYPE_CLASS_TEXT
- | InputType.TYPE_TEXT_VARIATION_PASSWORD);
- mPasswordEntry.setOnEditorActionListener(this);
- mPasswordEntry.addTextChangedListener(this);
-
- // Poke the wakelock any time the text is selected or modified
- mPasswordEntry.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- mCallback.userActivity();
- }
- });
-
- // Set selected property on so the view can send accessibility events.
- mPasswordEntry.setSelected(true);
-
- mSwitchImeButton = findViewById(R.id.switch_ime_button);
- mSwitchImeButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- mCallback.userActivity(); // Leave the screen on a bit longer
- // Do not show auxiliary subtypes in password lock screen.
- mImm.showInputMethodPickerFromSystem(false /* showAuxiliarySubtypes */,
- getContext().getDisplayId());
- }
- });
-
- View cancelBtn = findViewById(R.id.cancel_button);
- if (cancelBtn != null) {
- cancelBtn.setOnClickListener(view -> {
- mCallback.reset();
- mCallback.onCancelClicked();
- });
- }
-
- // If there's more than one IME, enable the IME switcher button
- updateSwitchImeButton();
-
- // When we the current user is switching, InputMethodManagerService sometimes has not
- // switched internal state yet here. As a quick workaround, we check the keyboard state
- // again.
- // TODO: Remove this workaround by ensuring such a race condition never happens.
- postDelayed(new Runnable() {
- @Override
- public void run() {
- updateSwitchImeButton();
- }
- }, DELAY_MILLIS_TO_REEVALUATE_IME_SWITCH_ICON);
}
@Override
@@ -265,59 +129,6 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView
mPasswordEntryDisabler.setInputEnabled(enabled);
}
- /**
- * Method adapted from com.android.inputmethod.latin.Utils
- *
- * @param imm The input method manager
- * @param shouldIncludeAuxiliarySubtypes
- * @return true if we have multiple IMEs to choose from
- */
- private boolean hasMultipleEnabledIMEsOrSubtypes(InputMethodManager imm,
- final boolean shouldIncludeAuxiliarySubtypes) {
- final List<InputMethodInfo> enabledImis =
- imm.getEnabledInputMethodListAsUser(KeyguardUpdateMonitor.getCurrentUser());
-
- // Number of the filtered IMEs
- int filteredImisCount = 0;
-
- for (InputMethodInfo imi : enabledImis) {
- // We can return true immediately after we find two or more filtered IMEs.
- if (filteredImisCount > 1) return true;
- final List<InputMethodSubtype> subtypes =
- imm.getEnabledInputMethodSubtypeList(imi, true);
- // IMEs that have no subtypes should be counted.
- if (subtypes.isEmpty()) {
- ++filteredImisCount;
- continue;
- }
-
- int auxCount = 0;
- for (InputMethodSubtype subtype : subtypes) {
- if (subtype.isAuxiliary()) {
- ++auxCount;
- }
- }
- final int nonAuxCount = subtypes.size() - auxCount;
-
- // IMEs that have one or more non-auxiliary subtypes should be counted.
- // If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary
- // subtypes should be counted as well.
- if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) {
- ++filteredImisCount;
- continue;
- }
- }
-
- return filteredImisCount > 1
- // imm.getEnabledInputMethodSubtypeList(null, false) will return the current IME's enabled
- // input method subtype (The current IME should be LatinIME.)
- || imm.getEnabledInputMethodSubtypeList(null, false).size() > 1;
- }
-
- @Override
- public void showUsabilityHint() {
- }
-
@Override
public int getWrongPasswordStringId() {
return R.string.kg_wrong_password;
@@ -346,45 +157,8 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView
}
@Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- if (mCallback != null) {
- mCallback.userActivity();
- }
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- // Poor man's user edit detection, assuming empty text is programmatic and everything else
- // is from the user.
- if (!TextUtils.isEmpty(s)) {
- onUserInput();
- }
- }
-
- @Override
- public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
- // Check if this was the result of hitting the enter key
- final boolean isSoftImeEvent = event == null
- && (actionId == EditorInfo.IME_NULL
- || actionId == EditorInfo.IME_ACTION_DONE
- || actionId == EditorInfo.IME_ACTION_NEXT);
- final boolean isKeyboardEnterKey = event != null
- && KeyEvent.isConfirmKey(event.getKeyCode())
- && event.getAction() == KeyEvent.ACTION_DOWN;
- if (isSoftImeEvent || isKeyboardEnterKey) {
- verifyPasswordAndUnlock();
- return true;
- }
- return false;
- }
-
- @Override
public CharSequence getTitle() {
- return getContext().getString(
+ return getResources().getString(
com.android.internal.R.string.keyguard_accessibility_password_unlock);
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
new file mode 100644
index 000000000000..d34ea8c5e018
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.content.res.Resources;
+import android.os.UserHandle;
+import android.text.Editable;
+import android.text.InputType;
+import android.text.TextUtils;
+import android.text.TextWatcher;
+import android.text.method.TextKeyListener;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup.MarginLayoutParams;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.InputMethodSubtype;
+import android.widget.TextView;
+import android.widget.TextView.OnEditorActionListener;
+
+import com.android.internal.util.LatencyTracker;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+
+import java.util.List;
+
+public class KeyguardPasswordViewController
+ extends KeyguardAbsKeyInputViewController<KeyguardPasswordView> {
+
+ private static final int DELAY_MILLIS_TO_REEVALUATE_IME_SWITCH_ICON = 500; // 500ms
+
+ private final KeyguardSecurityCallback mKeyguardSecurityCallback;
+ private final InputMethodManager mInputMethodManager;
+ private final DelayableExecutor mMainExecutor;
+ private final boolean mShowImeAtScreenOn;
+ private TextView mPasswordEntry;
+ private View mSwitchImeButton;
+
+ private final OnEditorActionListener mOnEditorActionListener = (v, actionId, event) -> {
+ // Check if this was the result of hitting the enter key
+ final boolean isSoftImeEvent = event == null
+ && (actionId == EditorInfo.IME_NULL
+ || actionId == EditorInfo.IME_ACTION_DONE
+ || actionId == EditorInfo.IME_ACTION_NEXT);
+ final boolean isKeyboardEnterKey = event != null
+ && KeyEvent.isConfirmKey(event.getKeyCode())
+ && event.getAction() == KeyEvent.ACTION_DOWN;
+ if (isSoftImeEvent || isKeyboardEnterKey) {
+ verifyPasswordAndUnlock();
+ return true;
+ }
+ return false;
+ };
+
+ private final TextWatcher mTextWatcher = new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ mKeyguardSecurityCallback.userActivity();
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ if (!TextUtils.isEmpty(s)) {
+ onUserInput();
+ }
+ }
+ };
+
+ protected KeyguardPasswordViewController(KeyguardPasswordView view,
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ SecurityMode securityMode,
+ LockPatternUtils lockPatternUtils,
+ KeyguardSecurityCallback keyguardSecurityCallback,
+ KeyguardMessageAreaController.Factory messageAreaControllerFactory,
+ LatencyTracker latencyTracker,
+ InputMethodManager inputMethodManager,
+ @Main DelayableExecutor mainExecutor,
+ @Main Resources resources) {
+ super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
+ messageAreaControllerFactory, latencyTracker);
+ mKeyguardSecurityCallback = keyguardSecurityCallback;
+ mInputMethodManager = inputMethodManager;
+ mMainExecutor = mainExecutor;
+ mShowImeAtScreenOn = resources.getBoolean(R.bool.kg_show_ime_at_screen_on);
+ mPasswordEntry = mView.findViewById(mView.getPasswordTextViewId());
+ mSwitchImeButton = mView.findViewById(R.id.switch_ime_button);
+ }
+
+ @Override
+ protected void onViewAttached() {
+ super.onViewAttached();
+ mPasswordEntry.setTextOperationUser(UserHandle.of(KeyguardUpdateMonitor.getCurrentUser()));
+ mPasswordEntry.setKeyListener(TextKeyListener.getInstance());
+ mPasswordEntry.setInputType(InputType.TYPE_CLASS_TEXT
+ | InputType.TYPE_TEXT_VARIATION_PASSWORD);
+
+ // Set selected property on so the view can send accessibility events.
+ mPasswordEntry.setSelected(true);
+ mPasswordEntry.setOnEditorActionListener(mOnEditorActionListener);
+ mPasswordEntry.addTextChangedListener(mTextWatcher);
+ // Poke the wakelock any time the text is selected or modified
+ mPasswordEntry.setOnClickListener(v -> mKeyguardSecurityCallback.userActivity());
+
+ mSwitchImeButton.setOnClickListener(v -> {
+ mKeyguardSecurityCallback.userActivity(); // Leave the screen on a bit longer
+ // Do not show auxiliary subtypes in password lock screen.
+ mInputMethodManager.showInputMethodPickerFromSystem(false,
+ mView.getContext().getDisplayId());
+ });
+
+ View cancelBtn = mView.findViewById(R.id.cancel_button);
+ if (cancelBtn != null) {
+ cancelBtn.setOnClickListener(view -> {
+ mKeyguardSecurityCallback.reset();
+ mKeyguardSecurityCallback.onCancelClicked();
+ });
+ }
+
+ // If there's more than one IME, enable the IME switcher button
+ updateSwitchImeButton();
+
+ // When we the current user is switching, InputMethodManagerService sometimes has not
+ // switched internal state yet here. As a quick workaround, we check the keyboard state
+ // again.
+ // TODO: Remove this workaround by ensuring such a race condition never happens.
+ mMainExecutor.executeDelayed(
+ this::updateSwitchImeButton, DELAY_MILLIS_TO_REEVALUATE_IME_SWITCH_ICON);
+ }
+
+ @Override
+ protected void onViewDetached() {
+ super.onViewDetached();
+ mPasswordEntry.setOnEditorActionListener(null);
+ }
+
+ @Override
+ public boolean needsInput() {
+ return true;
+ }
+
+ @Override
+ void resetState() {
+ mPasswordEntry.setTextOperationUser(UserHandle.of(KeyguardUpdateMonitor.getCurrentUser()));
+ mMessageAreaController.setMessage("");
+ final boolean wasDisabled = mPasswordEntry.isEnabled();
+ mView.setPasswordEntryEnabled(true);
+ mView.setPasswordEntryInputEnabled(true);
+ // Don't call showSoftInput when PasswordEntry is invisible or in pausing stage.
+ if (!mResumed || !mPasswordEntry.isVisibleToUser()) {
+ return;
+ }
+ if (wasDisabled) {
+ mInputMethodManager.showSoftInput(mPasswordEntry, InputMethodManager.SHOW_IMPLICIT);
+ }
+ }
+
+ @Override
+ public void onResume(int reason) {
+ super.onResume(reason);
+ // Wait a bit to focus the field so the focusable flag on the window is already set then.
+ mMainExecutor.execute(() -> {
+ if (mView.isShown() && mPasswordEntry.isEnabled()) {
+ mPasswordEntry.requestFocus();
+ if (reason != KeyguardSecurityView.SCREEN_ON || mShowImeAtScreenOn) {
+ mInputMethodManager.showSoftInput(
+ mPasswordEntry, InputMethodManager.SHOW_IMPLICIT);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mInputMethodManager.hideSoftInputFromWindow(mView.getWindowToken(), 0);
+ }
+
+ @Override
+ public void onStartingToHide() {
+ mInputMethodManager.hideSoftInputFromWindow(mView.getWindowToken(), 0);
+ }
+
+ private void updateSwitchImeButton() {
+ // If there's more than one IME, enable the IME switcher button
+ final boolean wasVisible = mSwitchImeButton.getVisibility() == View.VISIBLE;
+ final boolean shouldBeVisible = hasMultipleEnabledIMEsOrSubtypes(
+ mInputMethodManager, false);
+ if (wasVisible != shouldBeVisible) {
+ mSwitchImeButton.setVisibility(shouldBeVisible ? View.VISIBLE : View.GONE);
+ }
+
+ // TODO: Check if we still need this hack.
+ // If no icon is visible, reset the start margin on the password field so the text is
+ // still centered.
+ if (mSwitchImeButton.getVisibility() != View.VISIBLE) {
+ android.view.ViewGroup.LayoutParams params = mPasswordEntry.getLayoutParams();
+ if (params instanceof MarginLayoutParams) {
+ final MarginLayoutParams mlp = (MarginLayoutParams) params;
+ mlp.setMarginStart(0);
+ mPasswordEntry.setLayoutParams(params);
+ }
+ }
+ }
+
+ /**
+ * Method adapted from com.android.inputmethod.latin.Utils
+ *
+ * @param imm The input method manager
+ * @param shouldIncludeAuxiliarySubtypes
+ * @return true if we have multiple IMEs to choose from
+ */
+ private boolean hasMultipleEnabledIMEsOrSubtypes(InputMethodManager imm,
+ final boolean shouldIncludeAuxiliarySubtypes) {
+ final List<InputMethodInfo> enabledImis =
+ imm.getEnabledInputMethodListAsUser(KeyguardUpdateMonitor.getCurrentUser());
+
+ // Number of the filtered IMEs
+ int filteredImisCount = 0;
+
+ for (InputMethodInfo imi : enabledImis) {
+ // We can return true immediately after we find two or more filtered IMEs.
+ if (filteredImisCount > 1) return true;
+ final List<InputMethodSubtype> subtypes =
+ imm.getEnabledInputMethodSubtypeList(imi, true);
+ // IMEs that have no subtypes should be counted.
+ if (subtypes.isEmpty()) {
+ ++filteredImisCount;
+ continue;
+ }
+
+ int auxCount = 0;
+ for (InputMethodSubtype subtype : subtypes) {
+ if (subtype.isAuxiliary()) {
+ ++auxCount;
+ }
+ }
+ final int nonAuxCount = subtypes.size() - auxCount;
+
+ // IMEs that have one or more non-auxiliary subtypes should be counted.
+ // If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary
+ // subtypes should be counted as well.
+ if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) {
+ ++filteredImisCount;
+ continue;
+ }
+ }
+
+ return filteredImisCount > 1
+ // imm.getEnabledInputMethodSubtypeList(null, false) will return the current IME's
+ //enabled input method subtype (The current IME should be LatinIME.)
+ || imm.getEnabledInputMethodSubtypeList(null, false).size() > 1;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
index c4a9fcb45284..bdcf467c2456 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
@@ -15,62 +15,39 @@
*/
package com.android.keyguard;
-import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL;
-import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED;
-
import android.content.Context;
-import android.content.res.ColorStateList;
import android.graphics.Rect;
-import android.os.AsyncTask;
-import android.os.CountDownTimer;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
-import android.widget.LinearLayout;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.LatencyTracker;
-import com.android.internal.widget.LockPatternChecker;
-import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternView;
-import com.android.internal.widget.LockscreenCredential;
import com.android.settingslib.animation.AppearAnimationCreator;
import com.android.settingslib.animation.AppearAnimationUtils;
import com.android.settingslib.animation.DisappearAnimationUtils;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
-import java.util.List;
-
-public class KeyguardPatternView extends LinearLayout implements KeyguardSecurityView,
- AppearAnimationCreator<LockPatternView.CellState>,
- EmergencyButton.EmergencyButtonCallback {
+public class KeyguardPatternView extends KeyguardInputView
+ implements AppearAnimationCreator<LockPatternView.CellState> {
private static final String TAG = "SecurityPatternView";
private static final boolean DEBUG = KeyguardConstants.DEBUG;
- // how long before we clear the wrong pattern
- private static final int PATTERN_CLEAR_TIMEOUT_MS = 2000;
// how long we stay awake after each key beyond MIN_PATTERN_BEFORE_POKE_WAKELOCK
private static final int UNLOCK_PATTERN_WAKE_INTERVAL_MS = 7000;
- // how many cells the user has to cross before we poke the wakelock
- private static final int MIN_PATTERN_BEFORE_POKE_WAKELOCK = 2;
-
// How much we scale up the duration of the disappear animation when the current user is locked
public static final float DISAPPEAR_MULTIPLIER_LOCKED = 1.5f;
// Extra padding, in pixels, that should eat touch events.
private static final int PATTERNS_TOUCH_AREA_EXTENSION = 40;
- private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final AppearAnimationUtils mAppearAnimationUtils;
private final DisappearAnimationUtils mDisappearAnimationUtils;
private final DisappearAnimationUtils mDisappearAnimationUtilsLocked;
@@ -78,11 +55,7 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
private final Rect mTempRect = new Rect();
private final Rect mLockPatternScreenBounds = new Rect();
- private CountDownTimer mCountdownTimer = null;
- private LockPatternUtils mLockPatternUtils;
- private AsyncTask<?, ?, ?> mPendingLockCheck;
private LockPatternView mLockPatternView;
- private KeyguardSecurityCallback mCallback;
/**
* Keeps track of the last time we poked the wake lock during dispatching of the touch event.
@@ -92,26 +65,9 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
*/
private long mLastPokeTime = -UNLOCK_PATTERN_WAKE_INTERVAL_MS;
- /**
- * Useful for clearing out the wrong pattern after a delay
- */
- private Runnable mCancelPatternRunnable = new Runnable() {
- @Override
- public void run() {
- mLockPatternView.clearPattern();
- }
- };
- @VisibleForTesting
KeyguardMessageArea mSecurityMessageDisplay;
private View mEcaView;
private ViewGroup mContainer;
- private int mDisappearYTranslation;
-
- enum FooterMode {
- Normal,
- ForgotLockPattern,
- VerifyUnlocked
- }
public KeyguardPatternView(Context context) {
this(context, null);
@@ -119,7 +75,6 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
public KeyguardPatternView(Context context, AttributeSet attrs) {
super(context, attrs);
- mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
mAppearAnimationUtils = new AppearAnimationUtils(context,
AppearAnimationUtils.DEFAULT_APPEAR_DURATION, 1.5f /* translationScale */,
2.0f /* delayScale */, AnimationUtils.loadInterpolator(
@@ -132,50 +87,16 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
(long) (125 * DISAPPEAR_MULTIPLIER_LOCKED), 1.2f /* translationScale */,
0.6f /* delayScale */, AnimationUtils.loadInterpolator(
mContext, android.R.interpolator.fast_out_linear_in));
- mDisappearYTranslation = getResources().getDimensionPixelSize(
- R.dimen.disappear_y_translation);
- }
-
- @Override
- public void setKeyguardCallback(KeyguardSecurityCallback callback) {
- mCallback = callback;
- }
-
- @Override
- public void setLockPatternUtils(LockPatternUtils utils) {
- mLockPatternUtils = utils;
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mLockPatternUtils = mLockPatternUtils == null
- ? new LockPatternUtils(mContext) : mLockPatternUtils;
mLockPatternView = findViewById(R.id.lockPatternView);
- mLockPatternView.setSaveEnabled(false);
- mLockPatternView.setOnPatternListener(new UnlockPatternListener());
- mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled(
- KeyguardUpdateMonitor.getCurrentUser()));
-
- // vibrate mode will be the same for the life of this screen
- mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled());
mEcaView = findViewById(R.id.keyguard_selector_fade_container);
mContainer = findViewById(R.id.container);
-
- EmergencyButton button = findViewById(R.id.emergency_call_button);
- if (button != null) {
- button.setCallback(this);
- }
-
- View cancelBtn = findViewById(R.id.cancel_button);
- if (cancelBtn != null) {
- cancelBtn.setOnClickListener(view -> {
- mCallback.reset();
- mCallback.onCancelClicked();
- });
- }
}
@Override
@@ -185,11 +106,6 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
}
@Override
- public void onEmergencyButtonClickedWhenInCall() {
- mCallback.reset();
- }
-
- @Override
public boolean onTouchEvent(MotionEvent ev) {
boolean result = super.onTouchEvent(ev);
// as long as the user is entering a pattern (i.e sending a touch event that was handled
@@ -217,248 +133,11 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
}
@Override
- public void reset() {
- // reset lock pattern
- mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled(
- KeyguardUpdateMonitor.getCurrentUser()));
- mLockPatternView.enableInput();
- mLockPatternView.setEnabled(true);
- mLockPatternView.clearPattern();
-
- if (mSecurityMessageDisplay == null) {
- return;
- }
-
- // if the user is currently locked out, enforce it.
- long deadline = mLockPatternUtils.getLockoutAttemptDeadline(
- KeyguardUpdateMonitor.getCurrentUser());
- if (deadline != 0) {
- handleAttemptLockout(deadline);
- } else {
- displayDefaultSecurityMessage();
- }
- }
-
- private void displayDefaultSecurityMessage() {
- if (mSecurityMessageDisplay != null) {
- mSecurityMessageDisplay.setMessage("");
- }
- }
-
- @Override
- public void showUsabilityHint() {
- }
-
- @Override
- public boolean disallowInterceptTouch(MotionEvent event) {
+ boolean disallowInterceptTouch(MotionEvent event) {
return !mLockPatternView.isEmpty()
|| mLockPatternScreenBounds.contains((int) event.getRawX(), (int) event.getRawY());
}
- /** TODO: hook this up */
- public void cleanUp() {
- if (DEBUG) Log.v(TAG, "Cleanup() called on " + this);
- mLockPatternUtils = null;
- mLockPatternView.setOnPatternListener(null);
- }
-
- private class UnlockPatternListener implements LockPatternView.OnPatternListener {
-
- @Override
- public void onPatternStart() {
- mLockPatternView.removeCallbacks(mCancelPatternRunnable);
- mSecurityMessageDisplay.setMessage("");
- }
-
- @Override
- public void onPatternCleared() {
- }
-
- @Override
- public void onPatternCellAdded(List<LockPatternView.Cell> pattern) {
- mCallback.userActivity();
- mCallback.onUserInput();
- }
-
- @Override
- public void onPatternDetected(final List<LockPatternView.Cell> pattern) {
- mKeyguardUpdateMonitor.setCredentialAttempted();
- mLockPatternView.disableInput();
- if (mPendingLockCheck != null) {
- mPendingLockCheck.cancel(false);
- }
-
- final int userId = KeyguardUpdateMonitor.getCurrentUser();
- if (pattern.size() < LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) {
- mLockPatternView.enableInput();
- onPatternChecked(userId, false, 0, false /* not valid - too short */);
- return;
- }
-
- if (LatencyTracker.isEnabled(mContext)) {
- LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL);
- LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL_UNLOCKED);
- }
- mPendingLockCheck = LockPatternChecker.checkCredential(
- mLockPatternUtils,
- LockscreenCredential.createPattern(pattern),
- userId,
- new LockPatternChecker.OnCheckCallback() {
-
- @Override
- public void onEarlyMatched() {
- if (LatencyTracker.isEnabled(mContext)) {
- LatencyTracker.getInstance(mContext).onActionEnd(
- ACTION_CHECK_CREDENTIAL);
- }
- onPatternChecked(userId, true /* matched */, 0 /* timeoutMs */,
- true /* isValidPattern */);
- }
-
- @Override
- public void onChecked(boolean matched, int timeoutMs) {
- if (LatencyTracker.isEnabled(mContext)) {
- LatencyTracker.getInstance(mContext).onActionEnd(
- ACTION_CHECK_CREDENTIAL_UNLOCKED);
- }
- mLockPatternView.enableInput();
- mPendingLockCheck = null;
- if (!matched) {
- onPatternChecked(userId, false /* matched */, timeoutMs,
- true /* isValidPattern */);
- }
- }
-
- @Override
- public void onCancelled() {
- // We already got dismissed with the early matched callback, so we
- // cancelled the check. However, we still need to note down the latency.
- if (LatencyTracker.isEnabled(mContext)) {
- LatencyTracker.getInstance(mContext).onActionEnd(
- ACTION_CHECK_CREDENTIAL_UNLOCKED);
- }
- }
- });
- if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) {
- mCallback.userActivity();
- mCallback.onUserInput();
- }
- }
-
- private void onPatternChecked(int userId, boolean matched, int timeoutMs,
- boolean isValidPattern) {
- boolean dismissKeyguard = KeyguardUpdateMonitor.getCurrentUser() == userId;
- if (matched) {
- mCallback.reportUnlockAttempt(userId, true, 0);
- if (dismissKeyguard) {
- mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Correct);
- mCallback.dismiss(true, userId);
- }
- } else {
- mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong);
- if (isValidPattern) {
- mCallback.reportUnlockAttempt(userId, false, timeoutMs);
- if (timeoutMs > 0) {
- long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
- userId, timeoutMs);
- handleAttemptLockout(deadline);
- }
- }
- if (timeoutMs == 0) {
- mSecurityMessageDisplay.setMessage(R.string.kg_wrong_pattern);
- mLockPatternView.postDelayed(mCancelPatternRunnable, PATTERN_CLEAR_TIMEOUT_MS);
- }
- }
- }
- }
-
- private void handleAttemptLockout(long elapsedRealtimeDeadline) {
- mLockPatternView.clearPattern();
- mLockPatternView.setEnabled(false);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long secondsInFuture = (long) Math.ceil(
- (elapsedRealtimeDeadline - elapsedRealtime) / 1000.0);
- mCountdownTimer = new CountDownTimer(secondsInFuture * 1000, 1000) {
-
- @Override
- public void onTick(long millisUntilFinished) {
- final int secondsRemaining = (int) Math.round(millisUntilFinished / 1000.0);
- mSecurityMessageDisplay.setMessage(mContext.getResources().getQuantityString(
- R.plurals.kg_too_many_failed_attempts_countdown,
- secondsRemaining, secondsRemaining));
- }
-
- @Override
- public void onFinish() {
- mLockPatternView.setEnabled(true);
- displayDefaultSecurityMessage();
- }
-
- }.start();
- }
-
- @Override
- public boolean needsInput() {
- return false;
- }
-
- @Override
- public void onPause() {
- if (mCountdownTimer != null) {
- mCountdownTimer.cancel();
- mCountdownTimer = null;
- }
- if (mPendingLockCheck != null) {
- mPendingLockCheck.cancel(false);
- mPendingLockCheck = null;
- }
- displayDefaultSecurityMessage();
- }
-
- @Override
- public void onResume(int reason) {
- }
-
- @Override
- public KeyguardSecurityCallback getCallback() {
- return mCallback;
- }
-
- @Override
- public void showPromptReason(int reason) {
- switch (reason) {
- case PROMPT_REASON_RESTART:
- mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_restart_pattern);
- break;
- case PROMPT_REASON_TIMEOUT:
- mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_timeout_pattern);
- break;
- case PROMPT_REASON_DEVICE_ADMIN:
- mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_device_admin);
- break;
- case PROMPT_REASON_USER_REQUEST:
- mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_user_request);
- break;
- case PROMPT_REASON_PREPARE_FOR_UPDATE:
- mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_timeout_pattern);
- break;
- case PROMPT_REASON_NONE:
- break;
- default:
- mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_timeout_pattern);
- break;
- }
- }
-
- @Override
- public void showMessage(CharSequence message, ColorStateList colorState) {
- if (colorState != null) {
- mSecurityMessageDisplay.setNextMessageColor(colorState);
- }
- mSecurityMessageDisplay.setMessage(message);
- }
-
- @Override
public void startAppearAnimation() {
enableClipping(false);
setAlpha(1f);
@@ -467,12 +146,7 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
0, mAppearAnimationUtils.getInterpolator());
mAppearAnimationUtils.startAnimation2d(
mLockPatternView.getCellStates(),
- new Runnable() {
- @Override
- public void run() {
- enableClipping(true);
- }
- },
+ () -> enableClipping(true),
this);
if (!TextUtils.isEmpty(mSecurityMessageDisplay.getText())) {
mAppearAnimationUtils.createAnimation(mSecurityMessageDisplay, 0,
@@ -484,11 +158,9 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
}
}
- @Override
- public boolean startDisappearAnimation(final Runnable finishRunnable) {
- float durationMultiplier = mKeyguardUpdateMonitor.needsSlowUnlockTransition()
- ? DISAPPEAR_MULTIPLIER_LOCKED
- : 1f;
+ public boolean startDisappearAnimation(boolean needsSlowUnlockTransition,
+ final Runnable finishRunnable) {
+ float durationMultiplier = needsSlowUnlockTransition ? DISAPPEAR_MULTIPLIER_LOCKED : 1f;
mLockPatternView.clearPattern();
enableClipping(false);
setTranslationY(0);
@@ -497,10 +169,8 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
-mDisappearAnimationUtils.getStartTranslation(),
mDisappearAnimationUtils.getInterpolator());
- DisappearAnimationUtils disappearAnimationUtils = mKeyguardUpdateMonitor
- .needsSlowUnlockTransition()
- ? mDisappearAnimationUtilsLocked
- : mDisappearAnimationUtils;
+ DisappearAnimationUtils disappearAnimationUtils = needsSlowUnlockTransition
+ ? mDisappearAnimationUtilsLocked : mDisappearAnimationUtils;
disappearAnimationUtils.startAnimation2d(mLockPatternView.getCellStates(),
() -> {
enableClipping(true);
@@ -549,7 +219,7 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
@Override
public CharSequence getTitle() {
- return getContext().getString(
+ return getResources().getString(
com.android.internal.R.string.keyguard_accessibility_pattern_unlock);
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
new file mode 100644
index 000000000000..3db9db7be00c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL;
+import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED;
+
+import android.content.res.ColorStateList;
+import android.os.AsyncTask;
+import android.os.CountDownTimer;
+import android.os.SystemClock;
+import android.view.View;
+
+import com.android.internal.util.LatencyTracker;
+import com.android.internal.widget.LockPatternChecker;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockPatternView;
+import com.android.internal.widget.LockPatternView.Cell;
+import com.android.internal.widget.LockscreenCredential;
+import com.android.keyguard.EmergencyButton.EmergencyButtonCallback;
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.systemui.R;
+
+import java.util.List;
+
+public class KeyguardPatternViewController
+ extends KeyguardInputViewController<KeyguardPatternView> {
+
+ // how many cells the user has to cross before we poke the wakelock
+ private static final int MIN_PATTERN_BEFORE_POKE_WAKELOCK = 2;
+
+ // how long before we clear the wrong pattern
+ private static final int PATTERN_CLEAR_TIMEOUT_MS = 2000;
+
+ private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private final LockPatternUtils mLockPatternUtils;
+ private final LatencyTracker mLatencyTracker;
+ private final KeyguardMessageAreaController.Factory mMessageAreaControllerFactory;
+
+ private KeyguardMessageAreaController mMessageAreaController;
+ private LockPatternView mLockPatternView;
+ private CountDownTimer mCountdownTimer;
+ private AsyncTask<?, ?, ?> mPendingLockCheck;
+
+ private EmergencyButtonCallback mEmergencyButtonCallback = new EmergencyButtonCallback() {
+ @Override
+ public void onEmergencyButtonClickedWhenInCall() {
+ getKeyguardSecurityCallback().reset();
+ }
+ };
+
+ /**
+ * Useful for clearing out the wrong pattern after a delay
+ */
+ private Runnable mCancelPatternRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mLockPatternView.clearPattern();
+ }
+ };
+
+ private class UnlockPatternListener implements LockPatternView.OnPatternListener {
+
+ @Override
+ public void onPatternStart() {
+ mLockPatternView.removeCallbacks(mCancelPatternRunnable);
+ mMessageAreaController.setMessage("");
+ }
+
+ @Override
+ public void onPatternCleared() {
+ }
+
+ @Override
+ public void onPatternCellAdded(List<Cell> pattern) {
+ getKeyguardSecurityCallback().userActivity();
+ getKeyguardSecurityCallback().onUserInput();
+ }
+
+ @Override
+ public void onPatternDetected(final List<LockPatternView.Cell> pattern) {
+ mKeyguardUpdateMonitor.setCredentialAttempted();
+ mLockPatternView.disableInput();
+ if (mPendingLockCheck != null) {
+ mPendingLockCheck.cancel(false);
+ }
+
+ final int userId = KeyguardUpdateMonitor.getCurrentUser();
+ if (pattern.size() < LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) {
+ mLockPatternView.enableInput();
+ onPatternChecked(userId, false, 0, false /* not valid - too short */);
+ return;
+ }
+
+ mLatencyTracker.onActionStart(ACTION_CHECK_CREDENTIAL);
+ mLatencyTracker.onActionStart(ACTION_CHECK_CREDENTIAL_UNLOCKED);
+ mPendingLockCheck = LockPatternChecker.checkCredential(
+ mLockPatternUtils,
+ LockscreenCredential.createPattern(pattern),
+ userId,
+ new LockPatternChecker.OnCheckCallback() {
+
+ @Override
+ public void onEarlyMatched() {
+ mLatencyTracker.onActionEnd(ACTION_CHECK_CREDENTIAL);
+ onPatternChecked(userId, true /* matched */, 0 /* timeoutMs */,
+ true /* isValidPattern */);
+ }
+
+ @Override
+ public void onChecked(boolean matched, int timeoutMs) {
+ mLatencyTracker.onActionEnd(ACTION_CHECK_CREDENTIAL_UNLOCKED);
+ mLockPatternView.enableInput();
+ mPendingLockCheck = null;
+ if (!matched) {
+ onPatternChecked(userId, false /* matched */, timeoutMs,
+ true /* isValidPattern */);
+ }
+ }
+
+ @Override
+ public void onCancelled() {
+ // We already got dismissed with the early matched callback, so we
+ // cancelled the check. However, we still need to note down the latency.
+ mLatencyTracker.onActionEnd(ACTION_CHECK_CREDENTIAL_UNLOCKED);
+ }
+ });
+ if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) {
+ getKeyguardSecurityCallback().userActivity();
+ getKeyguardSecurityCallback().onUserInput();
+ }
+ }
+
+ private void onPatternChecked(int userId, boolean matched, int timeoutMs,
+ boolean isValidPattern) {
+ boolean dismissKeyguard = KeyguardUpdateMonitor.getCurrentUser() == userId;
+ if (matched) {
+ getKeyguardSecurityCallback().reportUnlockAttempt(userId, true, 0);
+ if (dismissKeyguard) {
+ mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Correct);
+ getKeyguardSecurityCallback().dismiss(true, userId);
+ }
+ } else {
+ mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong);
+ if (isValidPattern) {
+ getKeyguardSecurityCallback().reportUnlockAttempt(userId, false, timeoutMs);
+ if (timeoutMs > 0) {
+ long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
+ userId, timeoutMs);
+ handleAttemptLockout(deadline);
+ }
+ }
+ if (timeoutMs == 0) {
+ mMessageAreaController.setMessage(R.string.kg_wrong_pattern);
+ mLockPatternView.postDelayed(mCancelPatternRunnable, PATTERN_CLEAR_TIMEOUT_MS);
+ }
+ }
+ }
+ }
+
+ protected KeyguardPatternViewController(KeyguardPatternView view,
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ SecurityMode securityMode,
+ LockPatternUtils lockPatternUtils,
+ KeyguardSecurityCallback keyguardSecurityCallback,
+ LatencyTracker latencyTracker,
+ KeyguardMessageAreaController.Factory messageAreaControllerFactory) {
+ super(view, securityMode, keyguardSecurityCallback);
+ mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+ mLockPatternUtils = lockPatternUtils;
+ mLatencyTracker = latencyTracker;
+ mMessageAreaControllerFactory = messageAreaControllerFactory;
+ KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView);
+ mMessageAreaController = mMessageAreaControllerFactory.create(kma);
+ mLockPatternView = mView.findViewById(R.id.lockPatternView);
+ }
+
+ @Override
+ public void init() {
+ super.init();
+ mMessageAreaController.init();
+ }
+
+ @Override
+ protected void onViewAttached() {
+ mLockPatternView.setOnPatternListener(new UnlockPatternListener());
+ mLockPatternView.setSaveEnabled(false);
+ mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled(
+ KeyguardUpdateMonitor.getCurrentUser()));
+ // vibrate mode will be the same for the life of this screen
+ mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled());
+
+ EmergencyButton button = mView.findViewById(R.id.emergency_call_button);
+ if (button != null) {
+ button.setCallback(mEmergencyButtonCallback);
+ }
+
+ View cancelBtn = mView.findViewById(R.id.cancel_button);
+ if (cancelBtn != null) {
+ cancelBtn.setOnClickListener(view -> {
+ getKeyguardSecurityCallback().reset();
+ getKeyguardSecurityCallback().onCancelClicked();
+ });
+ }
+ }
+
+ @Override
+ protected void onViewDetached() {
+ super.onViewDetached();
+ mLockPatternView.setOnPatternListener(null);
+ EmergencyButton button = mView.findViewById(R.id.emergency_call_button);
+ if (button != null) {
+ button.setCallback(null);
+ }
+ View cancelBtn = mView.findViewById(R.id.cancel_button);
+ if (cancelBtn != null) {
+ cancelBtn.setOnClickListener(null);
+ }
+ }
+
+ @Override
+ public void reset() {
+ // reset lock pattern
+ mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled(
+ KeyguardUpdateMonitor.getCurrentUser()));
+ mLockPatternView.enableInput();
+ mLockPatternView.setEnabled(true);
+ mLockPatternView.clearPattern();
+
+ // if the user is currently locked out, enforce it.
+ long deadline = mLockPatternUtils.getLockoutAttemptDeadline(
+ KeyguardUpdateMonitor.getCurrentUser());
+ if (deadline != 0) {
+ handleAttemptLockout(deadline);
+ } else {
+ displayDefaultSecurityMessage();
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+
+ if (mCountdownTimer != null) {
+ mCountdownTimer.cancel();
+ mCountdownTimer = null;
+ }
+
+ if (mPendingLockCheck != null) {
+ mPendingLockCheck.cancel(false);
+ mPendingLockCheck = null;
+ }
+ displayDefaultSecurityMessage();
+ }
+
+ @Override
+ public boolean needsInput() {
+ return false;
+ }
+
+ @Override
+ public void showPromptReason(int reason) {
+ /// TODO: move all this logic into the MessageAreaController?
+ switch (reason) {
+ case PROMPT_REASON_RESTART:
+ mMessageAreaController.setMessage(R.string.kg_prompt_reason_restart_pattern);
+ break;
+ case PROMPT_REASON_TIMEOUT:
+ mMessageAreaController.setMessage(R.string.kg_prompt_reason_timeout_pattern);
+ break;
+ case PROMPT_REASON_DEVICE_ADMIN:
+ mMessageAreaController.setMessage(R.string.kg_prompt_reason_device_admin);
+ break;
+ case PROMPT_REASON_USER_REQUEST:
+ mMessageAreaController.setMessage(R.string.kg_prompt_reason_user_request);
+ break;
+ case PROMPT_REASON_PREPARE_FOR_UPDATE:
+ mMessageAreaController.setMessage(R.string.kg_prompt_reason_timeout_pattern);
+ break;
+ case PROMPT_REASON_NONE:
+ break;
+ default:
+ mMessageAreaController.setMessage(R.string.kg_prompt_reason_timeout_pattern);
+ break;
+ }
+ }
+
+ @Override
+ public void showMessage(CharSequence message, ColorStateList colorState) {
+ if (colorState != null) {
+ mMessageAreaController.setNextMessageColor(colorState);
+ }
+ mMessageAreaController.setMessage(message);
+ }
+
+ @Override
+ public void startAppearAnimation() {
+ super.startAppearAnimation();
+ }
+
+ @Override
+ public boolean startDisappearAnimation(Runnable finishRunnable) {
+ return mView.startDisappearAnimation(
+ mKeyguardUpdateMonitor.needsSlowUnlockTransition(), finishRunnable);
+ }
+
+ private void displayDefaultSecurityMessage() {
+ mMessageAreaController.setMessage("");
+ }
+
+ private void handleAttemptLockout(long elapsedRealtimeDeadline) {
+ mLockPatternView.clearPattern();
+ mLockPatternView.setEnabled(false);
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long secondsInFuture = (long) Math.ceil(
+ (elapsedRealtimeDeadline - elapsedRealtime) / 1000.0);
+ mCountdownTimer = new CountDownTimer(secondsInFuture * 1000, 1000) {
+
+ @Override
+ public void onTick(long millisUntilFinished) {
+ final int secondsRemaining = (int) Math.round(millisUntilFinished / 1000.0);
+ mMessageAreaController.setMessage(mView.getResources().getQuantityString(
+ R.plurals.kg_too_many_failed_attempts_countdown,
+ secondsRemaining, secondsRemaining));
+ }
+
+ @Override
+ public void onFinish() {
+ mLockPatternView.setEnabled(true);
+ displayDefaultSecurityMessage();
+ }
+
+ }.start();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index c7f27cf8a71a..7fa43116a7b1 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -16,11 +16,17 @@
package com.android.keyguard;
+import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN;
+import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NONE;
+import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE;
+import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART;
+import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT;
+import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST;
+
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.KeyEvent;
-import android.view.MotionEvent;
import android.view.View;
import com.android.internal.widget.LockscreenCredential;
@@ -29,22 +35,12 @@ import com.android.systemui.R;
/**
* A Pin based Keyguard input view
*/
-public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
- implements View.OnKeyListener, View.OnTouchListener {
+public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView {
protected PasswordTextView mPasswordEntry;
private View mOkButton;
private View mDeleteButton;
- private View mButton0;
- private View mButton1;
- private View mButton2;
- private View mButton3;
- private View mButton4;
- private View mButton5;
- private View mButton6;
- private View mButton7;
- private View mButton8;
- private View mButton9;
+ private View[] mButtons = new View[10];
public KeyguardPinBasedInputView(Context context) {
this(context, null);
@@ -62,7 +58,6 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
@Override
protected void resetState() {
- setPasswordEntryEnabled(true);
}
@Override
@@ -86,10 +81,10 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (KeyEvent.isConfirmKey(keyCode)) {
- performClick(mOkButton);
+ mOkButton.performClick();
return true;
} else if (keyCode == KeyEvent.KEYCODE_DEL) {
- performClick(mDeleteButton);
+ mDeleteButton.performClick();
return true;
}
if (keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9) {
@@ -125,42 +120,9 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
}
}
- private void performClick(View view) {
- view.performClick();
- }
-
private void performNumberClick(int number) {
- switch (number) {
- case 0:
- performClick(mButton0);
- break;
- case 1:
- performClick(mButton1);
- break;
- case 2:
- performClick(mButton2);
- break;
- case 3:
- performClick(mButton3);
- break;
- case 4:
- performClick(mButton4);
- break;
- case 5:
- performClick(mButton5);
- break;
- case 6:
- performClick(mButton6);
- break;
- case 7:
- performClick(mButton7);
- break;
- case 8:
- performClick(mButton8);
- break;
- case 9:
- performClick(mButton9);
- break;
+ if (number >= 0 && number <= 9) {
+ mButtons[number].performClick();
}
}
@@ -177,94 +139,31 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
@Override
protected void onFinishInflate() {
mPasswordEntry = findViewById(getPasswordTextViewId());
- mPasswordEntry.setOnKeyListener(this);
// Set selected property on so the view can send accessibility events.
mPasswordEntry.setSelected(true);
- mPasswordEntry.setUserActivityListener(new PasswordTextView.UserActivityListener() {
- @Override
- public void onUserActivity() {
- onUserInput();
- }
- });
-
mOkButton = findViewById(R.id.key_enter);
- if (mOkButton != null) {
- mOkButton.setOnTouchListener(this);
- mOkButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (mPasswordEntry.isEnabled()) {
- verifyPasswordAndUnlock();
- }
- }
- });
- mOkButton.setOnHoverListener(new LiftToActivateListener(getContext()));
- }
mDeleteButton = findViewById(R.id.delete_button);
mDeleteButton.setVisibility(View.VISIBLE);
- mDeleteButton.setOnTouchListener(this);
- mDeleteButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- // check for time-based lockouts
- if (mPasswordEntry.isEnabled()) {
- mPasswordEntry.deleteLastChar();
- }
- }
- });
- mDeleteButton.setOnLongClickListener(new View.OnLongClickListener() {
- @Override
- public boolean onLongClick(View v) {
- // check for time-based lockouts
- if (mPasswordEntry.isEnabled()) {
- resetPasswordText(true /* animate */, true /* announce */);
- }
- doHapticKeyClick();
- return true;
- }
- });
- mButton0 = findViewById(R.id.key0);
- mButton1 = findViewById(R.id.key1);
- mButton2 = findViewById(R.id.key2);
- mButton3 = findViewById(R.id.key3);
- mButton4 = findViewById(R.id.key4);
- mButton5 = findViewById(R.id.key5);
- mButton6 = findViewById(R.id.key6);
- mButton7 = findViewById(R.id.key7);
- mButton8 = findViewById(R.id.key8);
- mButton9 = findViewById(R.id.key9);
+ mButtons[0] = findViewById(R.id.key0);
+ mButtons[1] = findViewById(R.id.key1);
+ mButtons[2] = findViewById(R.id.key2);
+ mButtons[3] = findViewById(R.id.key3);
+ mButtons[4] = findViewById(R.id.key4);
+ mButtons[5] = findViewById(R.id.key5);
+ mButtons[6] = findViewById(R.id.key6);
+ mButtons[7] = findViewById(R.id.key7);
+ mButtons[8] = findViewById(R.id.key8);
+ mButtons[9] = findViewById(R.id.key9);
mPasswordEntry.requestFocus();
super.onFinishInflate();
}
@Override
- public void onResume(int reason) {
- super.onResume(reason);
- mPasswordEntry.requestFocus();
- }
-
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
- doHapticKeyClick();
- }
- return false;
- }
-
- @Override
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- if (event.getAction() == KeyEvent.ACTION_DOWN) {
- return onKeyDown(keyCode, event);
- }
- return false;
- }
-
- @Override
public CharSequence getTitle() {
return getContext().getString(
com.android.internal.R.string.keyguard_accessibility_pin_unlock);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
new file mode 100644
index 000000000000..4d0ebfffbe04
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnKeyListener;
+import android.view.View.OnTouchListener;
+
+import com.android.internal.util.LatencyTracker;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.systemui.R;
+
+public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinBasedInputView>
+ extends KeyguardAbsKeyInputViewController<T> {
+
+ private final LiftToActivateListener mLiftToActivateListener;
+ protected PasswordTextView mPasswordEntry;
+
+ private final OnKeyListener mOnKeyListener = (v, keyCode, event) -> {
+ if (event.getAction() == KeyEvent.ACTION_DOWN) {
+ return mView.onKeyDown(keyCode, event);
+ }
+ return false;
+ };
+
+ private final OnTouchListener mOnTouchListener = (v, event) -> {
+ if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ mView.doHapticKeyClick();
+ }
+ return false;
+ };
+
+ protected KeyguardPinBasedInputViewController(T view,
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ SecurityMode securityMode,
+ LockPatternUtils lockPatternUtils,
+ KeyguardSecurityCallback keyguardSecurityCallback,
+ KeyguardMessageAreaController.Factory messageAreaControllerFactory,
+ LatencyTracker latencyTracker,
+ LiftToActivateListener liftToActivateListener) {
+ super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
+ messageAreaControllerFactory, latencyTracker);
+ mLiftToActivateListener = liftToActivateListener;
+ mPasswordEntry = mView.findViewById(mView.getPasswordTextViewId());
+ }
+
+ @Override
+ protected void onViewAttached() {
+ super.onViewAttached();
+
+ mPasswordEntry.setOnKeyListener(mOnKeyListener);
+ mPasswordEntry.setUserActivityListener(this::onUserInput);
+
+ View deleteButton = mView.findViewById(R.id.delete_button);
+ deleteButton.setOnTouchListener(mOnTouchListener);
+ deleteButton.setOnClickListener(v -> {
+ // check for time-based lockouts
+ if (mPasswordEntry.isEnabled()) {
+ mPasswordEntry.deleteLastChar();
+ }
+ });
+ deleteButton.setOnLongClickListener(v -> {
+ // check for time-based lockouts
+ if (mPasswordEntry.isEnabled()) {
+ mView.resetPasswordText(true /* animate */, true /* announce */);
+ }
+ mView.doHapticKeyClick();
+ return true;
+ });
+
+ View okButton = mView.findViewById(R.id.key_enter);
+ if (okButton != null) {
+ okButton.setOnTouchListener(mOnTouchListener);
+ okButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mPasswordEntry.isEnabled()) {
+ verifyPasswordAndUnlock();
+ }
+ }
+ });
+ okButton.setOnHoverListener(mLiftToActivateListener);
+ }
+ }
+
+ @Override
+ public void onResume(int reason) {
+ super.onResume(reason);
+ mPasswordEntry.requestFocus();
+ }
+
+ @Override
+ void resetState() {
+ mView.setPasswordEntryEnabled(true);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
new file mode 100644
index 000000000000..6769436be8ef
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.view.View;
+
+import com.android.internal.util.LatencyTracker;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.systemui.R;
+
+public class KeyguardPinViewController
+ extends KeyguardPinBasedInputViewController<KeyguardPINView> {
+ private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+
+ protected KeyguardPinViewController(KeyguardPINView view,
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ SecurityMode securityMode, LockPatternUtils lockPatternUtils,
+ KeyguardSecurityCallback keyguardSecurityCallback,
+ KeyguardMessageAreaController.Factory messageAreaControllerFactory,
+ LatencyTracker latencyTracker,
+ LiftToActivateListener liftToActivateListener) {
+ super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
+ messageAreaControllerFactory, latencyTracker, liftToActivateListener);
+ mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+ }
+
+ @Override
+ protected void onViewAttached() {
+ super.onViewAttached();
+
+ View cancelBtn = mView.findViewById(R.id.cancel_button);
+ if (cancelBtn != null) {
+ cancelBtn.setOnClickListener(view -> {
+ getKeyguardSecurityCallback().reset();
+ getKeyguardSecurityCallback().onCancelClicked();
+ });
+ }
+ }
+
+ @Override
+ void resetState() {
+ super.resetState();
+ mMessageAreaController.setMessage("");
+ }
+
+ @Override
+ public boolean startDisappearAnimation(Runnable finishRunnable) {
+ return mView.startDisappearAnimation(
+ mKeyguardUpdateMonitor.needsSlowUnlockTransition(), finishRunnable);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 05172279c4ed..41158296fa57 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -21,8 +21,6 @@ import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsets.Type.systemBars;
import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP;
-import static com.android.systemui.DejankUtils.whitelistIpcs;
-
import static java.lang.Integer.max;
import android.animation.Animator;
@@ -30,25 +28,14 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.app.AlertDialog;
-import android.app.admin.DevicePolicyManager;
import android.content.Context;
-import android.content.Intent;
-import android.content.res.ColorStateList;
import android.graphics.Insets;
import android.graphics.Rect;
-import android.metrics.LogMaker;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.UserHandle;
import android.util.AttributeSet;
-import android.util.Log;
import android.util.MathUtils;
-import android.util.Slog;
import android.util.TypedValue;
-import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.VelocityTracker;
-import android.view.View;
import android.view.ViewConfiguration;
import android.view.WindowInsets;
import android.view.WindowInsetsAnimation;
@@ -63,42 +50,30 @@ import androidx.annotation.VisibleForTesting;
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.SpringAnimation;
-import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
-import com.android.internal.logging.UiEventLoggerImpl;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.settingslib.utils.ThreadUtils;
-import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.SystemUIFactory;
-import com.android.systemui.shared.system.SysUiStatsLog;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.util.InjectionInflationController;
import java.util.List;
-public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSecurityView {
- private static final boolean DEBUG = KeyguardConstants.DEBUG;
- private static final String TAG = "KeyguardSecurityView";
-
- private static final int USER_TYPE_PRIMARY = 1;
- private static final int USER_TYPE_WORK_PROFILE = 2;
- private static final int USER_TYPE_SECONDARY_USER = 3;
+public class KeyguardSecurityContainer extends FrameLayout {
+ static final int USER_TYPE_PRIMARY = 1;
+ static final int USER_TYPE_WORK_PROFILE = 2;
+ static final int USER_TYPE_SECONDARY_USER = 3;
// Bouncer is dismissed due to no security.
- private static final int BOUNCER_DISMISS_NONE_SECURITY = 0;
+ static final int BOUNCER_DISMISS_NONE_SECURITY = 0;
// Bouncer is dismissed due to pin, password or pattern entered.
- private static final int BOUNCER_DISMISS_PASSWORD = 1;
+ static final int BOUNCER_DISMISS_PASSWORD = 1;
// Bouncer is dismissed due to biometric (face, fingerprint or iris) authenticated.
- private static final int BOUNCER_DISMISS_BIOMETRIC = 2;
+ static final int BOUNCER_DISMISS_BIOMETRIC = 2;
// Bouncer is dismissed due to extended access granted.
- private static final int BOUNCER_DISMISS_EXTENDED_ACCESS = 3;
+ static final int BOUNCER_DISMISS_EXTENDED_ACCESS = 3;
// Bouncer is dismissed due to sim card unlock code entered.
- private static final int BOUNCER_DISMISS_SIM = 4;
+ static final int BOUNCER_DISMISS_SIM = 4;
// Make the view move slower than the finger, as if the spring were applying force.
private static final float TOUCH_Y_MULTIPLIER = 0.25f;
@@ -107,36 +82,23 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
// How much to scale the default slop by, to avoid accidental drags.
private static final float SLOP_SCALE = 4f;
- private static final UiEventLogger sUiEventLogger = new UiEventLoggerImpl();
-
private static final long IME_DISAPPEAR_DURATION_MS = 125;
- private KeyguardSecurityModel mSecurityModel;
- private LockPatternUtils mLockPatternUtils;
-
@VisibleForTesting
KeyguardSecurityViewFlipper mSecurityViewFlipper;
- private boolean mIsVerifyUnlockOnly;
- private SecurityMode mCurrentSecuritySelection = SecurityMode.Invalid;
- private KeyguardSecurityView mCurrentSecurityView;
- private SecurityCallback mSecurityCallback;
private AlertDialog mAlertDialog;
- private InjectionInflationController mInjectionInflationController;
private boolean mSwipeUpToRetry;
- private AdminSecondaryLockScreenController mSecondaryLockScreenController;
private final ViewConfiguration mViewConfiguration;
private final SpringAnimation mSpringAnimation;
private final VelocityTracker mVelocityTracker = VelocityTracker.obtain();
- private final KeyguardUpdateMonitor mUpdateMonitor;
- private final KeyguardStateController mKeyguardStateController;
- private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
private float mLastTouchY = -1;
private int mActivePointerId = -1;
private boolean mIsDragging;
private float mStartTouchY = -1;
private boolean mDisappearAnimRunning;
+ private SwipeListener mSwipeListener;
private final WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback =
new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) {
@@ -188,19 +150,22 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
// Used to notify the container when something interesting happens.
public interface SecurityCallback {
- public boolean dismiss(boolean authenticated, int targetUserId,
- boolean bypassSecondaryLockScreen);
- public void userActivity();
- public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput);
+ boolean dismiss(boolean authenticated, int targetUserId, boolean bypassSecondaryLockScreen);
+ void userActivity();
+ void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput);
/**
* @param strongAuth wheher the user has authenticated with strong authentication like
* pattern, password or PIN but not by trust agents or fingerprint
* @param targetUserId a user that needs to be the foreground user at the finish completion.
*/
- public void finish(boolean strongAuth, int targetUserId);
- public void reset();
- public void onCancelClicked();
+ void finish(boolean strongAuth, int targetUserId);
+ void reset();
+ void onCancelClicked();
+ }
+
+ public interface SwipeListener {
+ void onSwipeUp();
}
@VisibleForTesting
@@ -251,52 +216,24 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
public KeyguardSecurityContainer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- mSecurityModel = Dependency.get(KeyguardSecurityModel.class);
- mLockPatternUtils = new LockPatternUtils(context);
- mUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
mSpringAnimation = new SpringAnimation(this, DynamicAnimation.Y);
- mInjectionInflationController = new InjectionInflationController(
- SystemUIFactory.getInstance().getSysUIComponent().createViewInstanceCreatorFactory());
mViewConfiguration = ViewConfiguration.get(context);
- mKeyguardStateController = Dependency.get(KeyguardStateController.class);
- mSecondaryLockScreenController = new AdminSecondaryLockScreenController(context, this,
- mUpdateMonitor, mCallback, new Handler(Looper.myLooper()));
- }
-
- public void setSecurityCallback(SecurityCallback callback) {
- mSecurityCallback = callback;
}
- @Override
- public void onResume(int reason) {
- if (mCurrentSecuritySelection != SecurityMode.None) {
- getSecurityView(mCurrentSecuritySelection).onResume(reason);
- }
+ void onResume(SecurityMode securityMode, boolean faceAuthEnabled) {
mSecurityViewFlipper.setWindowInsetsAnimationCallback(mWindowInsetsAnimationCallback);
- updateBiometricRetry();
+ updateBiometricRetry(securityMode, faceAuthEnabled);
}
- @Override
public void onPause() {
if (mAlertDialog != null) {
mAlertDialog.dismiss();
mAlertDialog = null;
}
- mSecondaryLockScreenController.hide();
- if (mCurrentSecuritySelection != SecurityMode.None) {
- getSecurityView(mCurrentSecuritySelection).onPause();
- }
mSecurityViewFlipper.setWindowInsetsAnimationCallback(null);
}
@Override
- public void onStartingToHide() {
- if (mCurrentSecuritySelection != SecurityMode.None) {
- getSecurityView(mCurrentSecuritySelection).onStartingToHide();
- }
- }
-
- @Override
public boolean shouldDelayChildPressedState() {
return true;
}
@@ -318,13 +255,12 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
return false;
}
// Avoid dragging the pattern view
- if (mCurrentSecurityView.disallowInterceptTouch(event)) {
+ if (mSecurityViewFlipper.getSecurityView().disallowInterceptTouch(event)) {
return false;
}
int index = event.findPointerIndex(mActivePointerId);
float touchSlop = mViewConfiguration.getScaledTouchSlop() * SLOP_SCALE;
- if (mCurrentSecurityView != null && index != -1
- && mStartTouchY - event.getY(index) > touchSlop) {
+ if (index != -1 && mStartTouchY - event.getY(index) > touchSlop) {
mIsDragging = true;
return true;
}
@@ -372,31 +308,28 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
}
if (action == MotionEvent.ACTION_UP) {
if (-getTranslationY() > TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
- MIN_DRAG_SIZE, getResources().getDisplayMetrics())
- && !mUpdateMonitor.isFaceDetectionRunning()) {
- mUpdateMonitor.requestFaceAuth();
- mCallback.userActivity();
- showMessage(null, null);
+ MIN_DRAG_SIZE, getResources().getDisplayMetrics())) {
+ if (mSwipeListener != null) {
+ mSwipeListener.onSwipeUp();
+ }
}
}
return true;
}
+ void setSwipeListener(SwipeListener swipeListener) {
+ mSwipeListener = swipeListener;
+ }
+
private void startSpringAnimation(float startVelocity) {
mSpringAnimation
.setStartVelocity(startVelocity)
.animateToFinalPosition(0);
}
- public void startAppearAnimation() {
- if (mCurrentSecuritySelection != SecurityMode.None) {
- getSecurityView(mCurrentSecuritySelection).startAppearAnimation();
- }
- }
-
- public boolean startDisappearAnimation(Runnable onFinishRunnable) {
+ public void startDisappearAnimation(SecurityMode securitySelection) {
mDisappearAnimRunning = true;
- if (mCurrentSecuritySelection == SecurityMode.Password) {
+ if (securitySelection == SecurityMode.Password) {
mSecurityViewFlipper.getWindowInsetsController().controlWindowInsetsAnimation(ime(),
IME_DISAPPEAR_DURATION_MS,
Interpolators.LINEAR, null, new WindowInsetsAnimationControlListener() {
@@ -441,19 +374,13 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
}
});
}
- if (mCurrentSecuritySelection != SecurityMode.None) {
- return getSecurityView(mCurrentSecuritySelection).startDisappearAnimation(
- onFinishRunnable);
- }
- return false;
}
/**
* Enables/disables swipe up to retry on the bouncer.
*/
- private void updateBiometricRetry() {
- SecurityMode securityMode = getSecurityMode();
- mSwipeUpToRetry = mKeyguardStateController.isFaceAuthEnabled()
+ private void updateBiometricRetry(SecurityMode securityMode, boolean faceAuthEnabled) {
+ mSwipeUpToRetry = faceAuthEnabled
&& securityMode != SecurityMode.SimPin
&& securityMode != SecurityMode.SimPuk
&& securityMode != SecurityMode.None;
@@ -463,53 +390,11 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
return mSecurityViewFlipper.getTitle();
}
- @VisibleForTesting
- protected KeyguardSecurityView getSecurityView(SecurityMode securityMode) {
- final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
- KeyguardSecurityView view = null;
- final int children = mSecurityViewFlipper.getChildCount();
- for (int child = 0; child < children; child++) {
- if (mSecurityViewFlipper.getChildAt(child).getId() == securityViewIdForMode) {
- view = ((KeyguardSecurityView)mSecurityViewFlipper.getChildAt(child));
- break;
- }
- }
- int layoutId = getLayoutIdFor(securityMode);
- if (view == null && layoutId != 0) {
- final LayoutInflater inflater = LayoutInflater.from(mContext);
- if (DEBUG) Log.v(TAG, "inflating id = " + layoutId);
- View v = mInjectionInflationController.injectable(inflater)
- .inflate(layoutId, mSecurityViewFlipper, false);
- mSecurityViewFlipper.addView(v);
- updateSecurityView(v);
- view = (KeyguardSecurityView)v;
- view.reset();
- }
-
- return view;
- }
-
- private void updateSecurityView(View view) {
- if (view instanceof KeyguardSecurityView) {
- KeyguardSecurityView ksv = (KeyguardSecurityView) view;
- ksv.setKeyguardCallback(mCallback);
- ksv.setLockPatternUtils(mLockPatternUtils);
- } else {
- Log.w(TAG, "View " + view + " is not a KeyguardSecurityView");
- }
- }
@Override
public void onFinishInflate() {
super.onFinishInflate();
mSecurityViewFlipper = findViewById(R.id.view_flipper);
- mSecurityViewFlipper.setLockPatternUtils(mLockPatternUtils);
- }
-
- public void setLockPatternUtils(LockPatternUtils utils) {
- mLockPatternUtils = utils;
- mSecurityModel.setLockPatternUtils(utils);
- mSecurityViewFlipper.setLockPatternUtils(mLockPatternUtils);
}
@Override
@@ -546,11 +431,12 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
mAlertDialog.show();
}
- private void showTimeoutDialog(int userId, int timeoutMs) {
- int timeoutInSeconds = (int) timeoutMs / 1000;
+ void showTimeoutDialog(int userId, int timeoutMs, LockPatternUtils lockPatternUtils,
+ SecurityMode securityMode) {
+ int timeoutInSeconds = timeoutMs / 1000;
int messageId = 0;
- switch (mSecurityModel.getSecurityMode(userId)) {
+ switch (securityMode) {
case Pattern:
messageId = R.string.kg_too_many_failed_pattern_attempts_dialog_message;
break;
@@ -570,13 +456,13 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
if (messageId != 0) {
final String message = mContext.getString(messageId,
- mLockPatternUtils.getCurrentFailedPasswordAttempts(userId),
+ lockPatternUtils.getCurrentFailedPasswordAttempts(userId),
timeoutInSeconds);
showDialog(null, message);
}
}
- private void showAlmostAtWipeDialog(int attempts, int remaining, int userType) {
+ void showAlmostAtWipeDialog(int attempts, int remaining, int userType) {
String message = null;
switch (userType) {
case USER_TYPE_PRIMARY:
@@ -595,7 +481,7 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
showDialog(null, message);
}
- private void showWipeDialog(int attempts, int userType) {
+ void showWipeDialog(int attempts, int userType) {
String message = null;
switch (userType) {
case USER_TYPE_PRIMARY:
@@ -614,358 +500,8 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
showDialog(null, message);
}
- private void reportFailedUnlockAttempt(int userId, int timeoutMs) {
- // +1 for this time
- final int failedAttempts = mLockPatternUtils.getCurrentFailedPasswordAttempts(userId) + 1;
-
- if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts);
-
- final DevicePolicyManager dpm = mLockPatternUtils.getDevicePolicyManager();
- final int failedAttemptsBeforeWipe =
- dpm.getMaximumFailedPasswordsForWipe(null, userId);
-
- final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0 ?
- (failedAttemptsBeforeWipe - failedAttempts)
- : Integer.MAX_VALUE; // because DPM returns 0 if no restriction
- if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) {
- // The user has installed a DevicePolicyManager that requests a user/profile to be wiped
- // N attempts. Once we get below the grace period, we post this dialog every time as a
- // clear warning until the deletion fires.
- // Check which profile has the strictest policy for failed password attempts
- final int expiringUser = dpm.getProfileWithMinimumFailedPasswordsForWipe(userId);
- int userType = USER_TYPE_PRIMARY;
- if (expiringUser == userId) {
- // TODO: http://b/23522538
- if (expiringUser != UserHandle.USER_SYSTEM) {
- userType = USER_TYPE_SECONDARY_USER;
- }
- } else if (expiringUser != UserHandle.USER_NULL) {
- userType = USER_TYPE_WORK_PROFILE;
- } // If USER_NULL, which shouldn't happen, leave it as USER_TYPE_PRIMARY
- if (remainingBeforeWipe > 0) {
- showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe, userType);
- } else {
- // Too many attempts. The device will be wiped shortly.
- Slog.i(TAG, "Too many unlock attempts; user " + expiringUser + " will be wiped!");
- showWipeDialog(failedAttempts, userType);
- }
- }
- mLockPatternUtils.reportFailedPasswordAttempt(userId);
- if (timeoutMs > 0) {
- mLockPatternUtils.reportPasswordLockout(timeoutMs, userId);
- showTimeoutDialog(userId, timeoutMs);
- }
- }
-
- /**
- * Shows the primary security screen for the user. This will be either the multi-selector
- * or the user's security method.
- * @param turningOff true if the device is being turned off
- */
- void showPrimarySecurityScreen(boolean turningOff) {
- SecurityMode securityMode = whitelistIpcs(() -> mSecurityModel.getSecurityMode(
- KeyguardUpdateMonitor.getCurrentUser()));
- if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")");
- showSecurityScreen(securityMode);
- }
-
- /**
- * Shows the next security screen if there is one.
- * @param authenticated true if the user entered the correct authentication
- * @param targetUserId a user that needs to be the foreground user at the finish (if called)
- * completion.
- * @param bypassSecondaryLockScreen true if the user is allowed to bypass the secondary
- * secondary lock screen requirement, if any.
- * @return true if keyguard is done
- */
- boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId,
- boolean bypassSecondaryLockScreen) {
- if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
- boolean finish = false;
- boolean strongAuth = false;
- int eventSubtype = -1;
- BouncerUiEvent uiEvent = BouncerUiEvent.UNKNOWN;
- if (mUpdateMonitor.getUserHasTrust(targetUserId)) {
- finish = true;
- eventSubtype = BOUNCER_DISMISS_EXTENDED_ACCESS;
- uiEvent = BouncerUiEvent.BOUNCER_DISMISS_EXTENDED_ACCESS;
- } else if (mUpdateMonitor.getUserUnlockedWithBiometric(targetUserId)) {
- finish = true;
- eventSubtype = BOUNCER_DISMISS_BIOMETRIC;
- uiEvent = BouncerUiEvent.BOUNCER_DISMISS_BIOMETRIC;
- } else if (SecurityMode.None == mCurrentSecuritySelection) {
- SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
- if (SecurityMode.None == securityMode) {
- finish = true; // no security required
- eventSubtype = BOUNCER_DISMISS_NONE_SECURITY;
- uiEvent = BouncerUiEvent.BOUNCER_DISMISS_NONE_SECURITY;
- } else {
- showSecurityScreen(securityMode); // switch to the alternate security view
- }
- } else if (authenticated) {
- switch (mCurrentSecuritySelection) {
- case Pattern:
- case Password:
- case PIN:
- strongAuth = true;
- finish = true;
- eventSubtype = BOUNCER_DISMISS_PASSWORD;
- uiEvent = BouncerUiEvent.BOUNCER_DISMISS_PASSWORD;
- break;
-
- case SimPin:
- case SimPuk:
- // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
- SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
- if (securityMode == SecurityMode.None && mLockPatternUtils.isLockScreenDisabled(
- KeyguardUpdateMonitor.getCurrentUser())) {
- finish = true;
- eventSubtype = BOUNCER_DISMISS_SIM;
- uiEvent = BouncerUiEvent.BOUNCER_DISMISS_SIM;
- } else {
- showSecurityScreen(securityMode);
- }
- break;
-
- default:
- Log.v(TAG, "Bad security screen " + mCurrentSecuritySelection + ", fail safe");
- showPrimarySecurityScreen(false);
- break;
- }
- }
- // Check for device admin specified additional security measures.
- if (finish && !bypassSecondaryLockScreen) {
- Intent secondaryLockscreenIntent =
- mUpdateMonitor.getSecondaryLockscreenRequirement(targetUserId);
- if (secondaryLockscreenIntent != null) {
- mSecondaryLockScreenController.show(secondaryLockscreenIntent);
- return false;
- }
- }
- if (eventSubtype != -1) {
- mMetricsLogger.write(new LogMaker(MetricsEvent.BOUNCER)
- .setType(MetricsEvent.TYPE_DISMISS).setSubtype(eventSubtype));
- }
- if (uiEvent != BouncerUiEvent.UNKNOWN) {
- sUiEventLogger.log(uiEvent);
- }
- if (finish) {
- mSecurityCallback.finish(strongAuth, targetUserId);
- }
- return finish;
- }
-
- /**
- * Switches to the given security view unless it's already being shown, in which case
- * this is a no-op.
- *
- * @param securityMode
- */
- private void showSecurityScreen(SecurityMode securityMode) {
- if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")");
-
- if (securityMode == mCurrentSecuritySelection) return;
-
- KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection);
- KeyguardSecurityView newView = getSecurityView(securityMode);
-
- // Emulate Activity life cycle
- if (oldView != null) {
- oldView.onPause();
- oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view
- }
- if (securityMode != SecurityMode.None) {
- newView.onResume(KeyguardSecurityView.VIEW_REVEALED);
- newView.setKeyguardCallback(mCallback);
- }
-
- // Find and show this child.
- final int childCount = mSecurityViewFlipper.getChildCount();
-
- final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
- for (int i = 0; i < childCount; i++) {
- if (mSecurityViewFlipper.getChildAt(i).getId() == securityViewIdForMode) {
- mSecurityViewFlipper.setDisplayedChild(i);
- break;
- }
- }
-
- mCurrentSecuritySelection = securityMode;
- mCurrentSecurityView = newView;
- mSecurityCallback.onSecurityModeChanged(securityMode,
- securityMode != SecurityMode.None && newView.needsInput());
- }
-
- private KeyguardSecurityCallback mCallback = new KeyguardSecurityCallback() {
- public void userActivity() {
- if (mSecurityCallback != null) {
- mSecurityCallback.userActivity();
- }
- }
-
- @Override
- public void onUserInput() {
- mUpdateMonitor.cancelFaceAuth();
- }
-
- @Override
- public void dismiss(boolean authenticated, int targetId) {
- dismiss(authenticated, targetId, /* bypassSecondaryLockScreen */ false);
- }
-
- @Override
- public void dismiss(boolean authenticated, int targetId,
- boolean bypassSecondaryLockScreen) {
- mSecurityCallback.dismiss(authenticated, targetId, bypassSecondaryLockScreen);
- }
-
- public boolean isVerifyUnlockOnly() {
- return mIsVerifyUnlockOnly;
- }
-
- public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) {
- if (success) {
- SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
- SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__SUCCESS);
- mLockPatternUtils.reportSuccessfulPasswordAttempt(userId);
- // Force a garbage collection in an attempt to erase any lockscreen password left in
- // memory. Do it asynchronously with a 5-sec delay to avoid making the keyguard
- // dismiss animation janky.
- ThreadUtils.postOnBackgroundThread(() -> {
- try {
- Thread.sleep(5000);
- } catch (InterruptedException ignored) { }
- Runtime.getRuntime().gc();
- });
- } else {
- SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
- SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__FAILURE);
- KeyguardSecurityContainer.this.reportFailedUnlockAttempt(userId, timeoutMs);
- }
- mMetricsLogger.write(new LogMaker(MetricsEvent.BOUNCER)
- .setType(success ? MetricsEvent.TYPE_SUCCESS : MetricsEvent.TYPE_FAILURE));
- sUiEventLogger.log(success ? BouncerUiEvent.BOUNCER_PASSWORD_SUCCESS
- : BouncerUiEvent.BOUNCER_PASSWORD_FAILURE);
- }
-
- public void reset() {
- mSecurityCallback.reset();
- }
-
- public void onCancelClicked() {
- mSecurityCallback.onCancelClicked();
- }
- };
-
- // The following is used to ignore callbacks from SecurityViews that are no longer current
- // (e.g. face unlock). This avoids unwanted asynchronous events from messing with the
- // state for the current security method.
- private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() {
- @Override
- public void userActivity() { }
- @Override
- public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) { }
- @Override
- public boolean isVerifyUnlockOnly() { return false; }
- @Override
- public void dismiss(boolean securityVerified, int targetUserId) { }
- @Override
- public void dismiss(boolean authenticated, int targetId,
- boolean bypassSecondaryLockScreen) { }
- @Override
- public void onUserInput() { }
- @Override
- public void reset() {}
- };
-
- private int getSecurityViewIdForMode(SecurityMode securityMode) {
- switch (securityMode) {
- case Pattern: return R.id.keyguard_pattern_view;
- case PIN: return R.id.keyguard_pin_view;
- case Password: return R.id.keyguard_password_view;
- case SimPin: return R.id.keyguard_sim_pin_view;
- case SimPuk: return R.id.keyguard_sim_puk_view;
- }
- return 0;
- }
-
- @VisibleForTesting
- public int getLayoutIdFor(SecurityMode securityMode) {
- switch (securityMode) {
- case Pattern: return R.layout.keyguard_pattern_view;
- case PIN: return R.layout.keyguard_pin_view;
- case Password: return R.layout.keyguard_password_view;
- case SimPin: return R.layout.keyguard_sim_pin_view;
- case SimPuk: return R.layout.keyguard_sim_puk_view;
- default:
- return 0;
- }
- }
-
- public SecurityMode getSecurityMode() {
- return mSecurityModel.getSecurityMode(KeyguardUpdateMonitor.getCurrentUser());
- }
-
- public SecurityMode getCurrentSecurityMode() {
- return mCurrentSecuritySelection;
- }
-
- public KeyguardSecurityView getCurrentSecurityView() {
- return mCurrentSecurityView;
- }
-
- public void verifyUnlock() {
- mIsVerifyUnlockOnly = true;
- showSecurityScreen(getSecurityMode());
- }
-
- public SecurityMode getCurrentSecuritySelection() {
- return mCurrentSecuritySelection;
- }
-
- public void dismiss(boolean authenticated, int targetUserId) {
- mCallback.dismiss(authenticated, targetUserId);
- }
-
- public boolean needsInput() {
- return mSecurityViewFlipper.needsInput();
- }
-
- @Override
- public void setKeyguardCallback(KeyguardSecurityCallback callback) {
- mSecurityViewFlipper.setKeyguardCallback(callback);
- }
-
- @Override
public void reset() {
- mSecurityViewFlipper.reset();
mDisappearAnimRunning = false;
}
-
- @Override
- public KeyguardSecurityCallback getCallback() {
- return mSecurityViewFlipper.getCallback();
- }
-
- @Override
- public void showPromptReason(int reason) {
- if (mCurrentSecuritySelection != SecurityMode.None) {
- if (reason != PROMPT_REASON_NONE) {
- Log.i(TAG, "Strong auth required, reason: " + reason);
- }
- getSecurityView(mCurrentSecuritySelection).showPromptReason(reason);
- }
- }
-
- public void showMessage(CharSequence message, ColorStateList colorState) {
- if (mCurrentSecuritySelection != SecurityMode.None) {
- getSecurityView(mCurrentSecuritySelection).showMessage(message, colorState);
- }
- }
-
- @Override
- public void showUsabilityHint() {
- mSecurityViewFlipper.showUsabilityHint();
- }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 17f25bd08ef4..64676e55b038 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -16,33 +16,166 @@
package com.android.keyguard;
+import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_BIOMETRIC;
+import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_EXTENDED_ACCESS;
+import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_NONE_SECURITY;
+import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_PASSWORD;
+import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_SIM;
+import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_PRIMARY;
+import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_SECONDARY_USER;
+import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_WORK_PROFILE;
+import static com.android.systemui.DejankUtils.whitelistIpcs;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Intent;
import android.content.res.ColorStateList;
+import android.metrics.LogMaker;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEventLogger;
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardSecurityContainer.BouncerUiEvent;
import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback;
+import com.android.keyguard.KeyguardSecurityContainer.SwipeListener;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.keyguard.dagger.KeyguardBouncerScope;
+import com.android.settingslib.utils.ThreadUtils;
+import com.android.systemui.shared.system.SysUiStatsLog;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.ViewController;
import javax.inject.Inject;
/** Controller for {@link KeyguardSecurityContainer} */
-public class KeyguardSecurityContainerController extends ViewController<KeyguardSecurityContainer> {
+@KeyguardBouncerScope
+public class KeyguardSecurityContainerController extends ViewController<KeyguardSecurityContainer>
+ implements KeyguardSecurityView {
+
+ private static final boolean DEBUG = KeyguardConstants.DEBUG;
+ private static final String TAG = "KeyguardSecurityView";
+ private final AdminSecondaryLockScreenController mAdminSecondaryLockScreenController;
private final LockPatternUtils mLockPatternUtils;
- private final KeyguardSecurityViewController.Factory mKeyguardSecurityViewControllerFactory;
+ private final KeyguardUpdateMonitor mUpdateMonitor;
+ private final KeyguardSecurityModel mSecurityModel;
+ private final MetricsLogger mMetricsLogger;
+ private final UiEventLogger mUiEventLogger;
+ private final KeyguardStateController mKeyguardStateController;
+ private final KeyguardSecurityViewFlipperController mSecurityViewFlipperController;
+
+ private SecurityCallback mSecurityCallback;
+ private SecurityMode mCurrentSecurityMode = SecurityMode.Invalid;
+
+ private KeyguardSecurityCallback mKeyguardSecurityCallback = new KeyguardSecurityCallback() {
+ public void userActivity() {
+ if (mSecurityCallback != null) {
+ mSecurityCallback.userActivity();
+ }
+ }
+
+ @Override
+ public void onUserInput() {
+ mUpdateMonitor.cancelFaceAuth();
+ }
+
+ @Override
+ public void dismiss(boolean authenticated, int targetId) {
+ dismiss(authenticated, targetId, /* bypassSecondaryLockScreen */ false);
+ }
+
+ @Override
+ public void dismiss(boolean authenticated, int targetId,
+ boolean bypassSecondaryLockScreen) {
+ mSecurityCallback.dismiss(authenticated, targetId, bypassSecondaryLockScreen);
+ }
+
+ public boolean isVerifyUnlockOnly() {
+ return false;
+ }
+
+ public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) {
+ if (success) {
+ SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
+ SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__SUCCESS);
+ mLockPatternUtils.reportSuccessfulPasswordAttempt(userId);
+ // Force a garbage collection in an attempt to erase any lockscreen password left in
+ // memory. Do it asynchronously with a 5-sec delay to avoid making the keyguard
+ // dismiss animation janky.
+ ThreadUtils.postOnBackgroundThread(() -> {
+ try {
+ Thread.sleep(5000);
+ } catch (InterruptedException ignored) { }
+ Runtime.getRuntime().gc();
+ });
+ } else {
+ SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
+ SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__FAILURE);
+ reportFailedUnlockAttempt(userId, timeoutMs);
+ }
+ mMetricsLogger.write(new LogMaker(MetricsEvent.BOUNCER)
+ .setType(success ? MetricsEvent.TYPE_SUCCESS : MetricsEvent.TYPE_FAILURE));
+ mUiEventLogger.log(success ? BouncerUiEvent.BOUNCER_PASSWORD_SUCCESS
+ : BouncerUiEvent.BOUNCER_PASSWORD_FAILURE);
+ }
+
+ public void reset() {
+ mSecurityCallback.reset();
+ }
+
+ public void onCancelClicked() {
+ mSecurityCallback.onCancelClicked();
+ }
+ };
+
+
+ private SwipeListener mSwipeListener = new SwipeListener() {
+ @Override
+ public void onSwipeUp() {
+ if (!mUpdateMonitor.isFaceDetectionRunning()) {
+ mUpdateMonitor.requestFaceAuth();
+ mKeyguardSecurityCallback.userActivity();
+ showMessage(null, null);
+ }
+ }
+ };
@Inject
KeyguardSecurityContainerController(KeyguardSecurityContainer view,
+ AdminSecondaryLockScreenController.Factory adminSecondaryLockScreenControllerFactory,
LockPatternUtils lockPatternUtils,
- KeyguardSecurityViewController.Factory keyguardSecurityViewControllerFactory) {
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ KeyguardSecurityModel keyguardSecurityModel,
+ MetricsLogger metricsLogger,
+ UiEventLogger uiEventLogger,
+ KeyguardStateController keyguardStateController,
+ KeyguardSecurityViewFlipperController securityViewFlipperController) {
super(view);
mLockPatternUtils = lockPatternUtils;
- view.setLockPatternUtils(mLockPatternUtils);
- mKeyguardSecurityViewControllerFactory = keyguardSecurityViewControllerFactory;
+ mUpdateMonitor = keyguardUpdateMonitor;
+ mSecurityModel = keyguardSecurityModel;
+ mMetricsLogger = metricsLogger;
+ mUiEventLogger = uiEventLogger;
+ mKeyguardStateController = keyguardStateController;
+ mSecurityViewFlipperController = securityViewFlipperController;
+ mAdminSecondaryLockScreenController = adminSecondaryLockScreenControllerFactory.create(
+ mKeyguardSecurityCallback);
+ }
+
+ @Override
+ public void init() {
+ super.init();
+ mSecurityViewFlipperController.init();
}
@Override
protected void onViewAttached() {
+ mView.setSwipeListener(mSwipeListener);
}
@Override
@@ -51,68 +184,270 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
/** */
public void onPause() {
+ mAdminSecondaryLockScreenController.hide();
+ if (mCurrentSecurityMode != SecurityMode.None) {
+ getCurrentSecurityController().onPause();
+ }
mView.onPause();
}
+
+ /**
+ * Shows the primary security screen for the user. This will be either the multi-selector
+ * or the user's security method.
+ * @param turningOff true if the device is being turned off
+ */
public void showPrimarySecurityScreen(boolean turningOff) {
- mView.showPrimarySecurityScreen(turningOff);
+ SecurityMode securityMode = whitelistIpcs(() -> mSecurityModel.getSecurityMode(
+ KeyguardUpdateMonitor.getCurrentUser()));
+ if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")");
+ showSecurityScreen(securityMode);
}
+ @Override
public void showPromptReason(int reason) {
- mView.showPromptReason(reason);
+ if (mCurrentSecurityMode != SecurityMode.None) {
+ if (reason != PROMPT_REASON_NONE) {
+ Log.i(TAG, "Strong auth required, reason: " + reason);
+ }
+ getCurrentSecurityController().showPromptReason(reason);
+ }
}
public void showMessage(CharSequence message, ColorStateList colorState) {
- mView.showMessage(message, colorState);
+ if (mCurrentSecurityMode != SecurityMode.None) {
+ getCurrentSecurityController().showMessage(message, colorState);
+ }
}
- public SecurityMode getCurrentSecuritySelection() {
- return mView.getCurrentSecuritySelection();
+ public SecurityMode getCurrentSecurityMode() {
+ return mCurrentSecurityMode;
}
public void dismiss(boolean authenticated, int targetUserId) {
- mView.dismiss(authenticated, targetUserId);
+ mKeyguardSecurityCallback.dismiss(authenticated, targetUserId);
}
public void reset() {
mView.reset();
+ mSecurityViewFlipperController.reset();
}
public CharSequence getTitle() {
return mView.getTitle();
}
- public void onResume(int screenOn) {
- mView.onResume(screenOn);
+ @Override
+ public void onResume(int reason) {
+ if (mCurrentSecurityMode != SecurityMode.None) {
+ getCurrentSecurityController().onResume(reason);
+ }
+ mView.onResume(
+ mSecurityModel.getSecurityMode(KeyguardUpdateMonitor.getCurrentUser()),
+ mKeyguardStateController.isFaceAuthEnabled());
}
public void startAppearAnimation() {
- mView.startAppearAnimation();
+ if (mCurrentSecurityMode != SecurityMode.None) {
+ getCurrentSecurityController().startAppearAnimation();
+ }
}
public boolean startDisappearAnimation(Runnable onFinishRunnable) {
- return mView.startDisappearAnimation(onFinishRunnable);
+ mView.startDisappearAnimation(getCurrentSecurityMode());
+
+ if (mCurrentSecurityMode != SecurityMode.None) {
+ return getCurrentSecurityController().startDisappearAnimation(onFinishRunnable);
+ }
+
+ return false;
}
public void onStartingToHide() {
- mView.onStartingToHide();
+ if (mCurrentSecurityMode != SecurityMode.None) {
+ getCurrentSecurityController().onStartingToHide();
+ }
}
public void setSecurityCallback(SecurityCallback securityCallback) {
- mView.setSecurityCallback(securityCallback);
+ mSecurityCallback = securityCallback;
}
+ /**
+ * Shows the next security screen if there is one.
+ * @param authenticated true if the user entered the correct authentication
+ * @param targetUserId a user that needs to be the foreground user at the finish (if called)
+ * completion.
+ * @param bypassSecondaryLockScreen true if the user is allowed to bypass the secondary
+ * secondary lock screen requirement, if any.
+ * @return true if keyguard is done
+ */
public boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId,
boolean bypassSecondaryLockScreen) {
- return mView.showNextSecurityScreenOrFinish(
- authenticated, targetUserId, bypassSecondaryLockScreen);
+
+ if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
+ boolean finish = false;
+ boolean strongAuth = false;
+ int eventSubtype = -1;
+ BouncerUiEvent uiEvent = BouncerUiEvent.UNKNOWN;
+ if (mUpdateMonitor.getUserHasTrust(targetUserId)) {
+ finish = true;
+ eventSubtype = BOUNCER_DISMISS_EXTENDED_ACCESS;
+ uiEvent = BouncerUiEvent.BOUNCER_DISMISS_EXTENDED_ACCESS;
+ } else if (mUpdateMonitor.getUserUnlockedWithBiometric(targetUserId)) {
+ finish = true;
+ eventSubtype = BOUNCER_DISMISS_BIOMETRIC;
+ uiEvent = BouncerUiEvent.BOUNCER_DISMISS_BIOMETRIC;
+ } else if (SecurityMode.None == getCurrentSecurityMode()) {
+ SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
+ if (SecurityMode.None == securityMode) {
+ finish = true; // no security required
+ eventSubtype = BOUNCER_DISMISS_NONE_SECURITY;
+ uiEvent = BouncerUiEvent.BOUNCER_DISMISS_NONE_SECURITY;
+ } else {
+ showSecurityScreen(securityMode); // switch to the alternate security view
+ }
+ } else if (authenticated) {
+ switch (getCurrentSecurityMode()) {
+ case Pattern:
+ case Password:
+ case PIN:
+ strongAuth = true;
+ finish = true;
+ eventSubtype = BOUNCER_DISMISS_PASSWORD;
+ uiEvent = BouncerUiEvent.BOUNCER_DISMISS_PASSWORD;
+ break;
+
+ case SimPin:
+ case SimPuk:
+ // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
+ SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
+ if (securityMode == SecurityMode.None && mLockPatternUtils.isLockScreenDisabled(
+ KeyguardUpdateMonitor.getCurrentUser())) {
+ finish = true;
+ eventSubtype = BOUNCER_DISMISS_SIM;
+ uiEvent = BouncerUiEvent.BOUNCER_DISMISS_SIM;
+ } else {
+ showSecurityScreen(securityMode);
+ }
+ break;
+
+ default:
+ Log.v(TAG, "Bad security screen " + getCurrentSecurityMode()
+ + ", fail safe");
+ showPrimarySecurityScreen(false);
+ break;
+ }
+ }
+ // Check for device admin specified additional security measures.
+ if (finish && !bypassSecondaryLockScreen) {
+ Intent secondaryLockscreenIntent =
+ mUpdateMonitor.getSecondaryLockscreenRequirement(targetUserId);
+ if (secondaryLockscreenIntent != null) {
+ mAdminSecondaryLockScreenController.show(secondaryLockscreenIntent);
+ return false;
+ }
+ }
+ if (eventSubtype != -1) {
+ mMetricsLogger.write(new LogMaker(MetricsProto.MetricsEvent.BOUNCER)
+ .setType(MetricsProto.MetricsEvent.TYPE_DISMISS).setSubtype(eventSubtype));
+ }
+ if (uiEvent != BouncerUiEvent.UNKNOWN) {
+ mUiEventLogger.log(uiEvent);
+ }
+ if (finish) {
+ mSecurityCallback.finish(strongAuth, targetUserId);
+ }
+ return finish;
}
public boolean needsInput() {
- return mView.needsInput();
+ return getCurrentSecurityController().needsInput();
}
- public SecurityMode getCurrentSecurityMode() {
- return mView.getCurrentSecurityMode();
+ /**
+ * Switches to the given security view unless it's already being shown, in which case
+ * this is a no-op.
+ *
+ * @param securityMode
+ */
+ @VisibleForTesting
+ void showSecurityScreen(SecurityMode securityMode) {
+ if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")");
+
+ if (securityMode == SecurityMode.Invalid || securityMode == mCurrentSecurityMode) {
+ return;
+ }
+
+ KeyguardInputViewController<KeyguardInputView> oldView = getCurrentSecurityController();
+
+ // Emulate Activity life cycle
+ if (oldView != null) {
+ oldView.onPause();
+ }
+
+ KeyguardInputViewController<KeyguardInputView> newView = changeSecurityMode(securityMode);
+ if (newView != null) {
+ newView.onResume(KeyguardSecurityView.VIEW_REVEALED);
+ mSecurityViewFlipperController.show(newView);
+ }
+
+ mSecurityCallback.onSecurityModeChanged(
+ securityMode, newView != null && newView.needsInput());
+ }
+
+ public void reportFailedUnlockAttempt(int userId, int timeoutMs) {
+ // +1 for this time
+ final int failedAttempts = mLockPatternUtils.getCurrentFailedPasswordAttempts(userId) + 1;
+
+ if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts);
+
+ final DevicePolicyManager dpm = mLockPatternUtils.getDevicePolicyManager();
+ final int failedAttemptsBeforeWipe =
+ dpm.getMaximumFailedPasswordsForWipe(null, userId);
+
+ final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0
+ ? (failedAttemptsBeforeWipe - failedAttempts)
+ : Integer.MAX_VALUE; // because DPM returns 0 if no restriction
+ if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) {
+ // The user has installed a DevicePolicyManager that requests a user/profile to be wiped
+ // N attempts. Once we get below the grace period, we post this dialog every time as a
+ // clear warning until the deletion fires.
+ // Check which profile has the strictest policy for failed password attempts
+ final int expiringUser = dpm.getProfileWithMinimumFailedPasswordsForWipe(userId);
+ int userType = USER_TYPE_PRIMARY;
+ if (expiringUser == userId) {
+ // TODO: http://b/23522538
+ if (expiringUser != UserHandle.USER_SYSTEM) {
+ userType = USER_TYPE_SECONDARY_USER;
+ }
+ } else if (expiringUser != UserHandle.USER_NULL) {
+ userType = USER_TYPE_WORK_PROFILE;
+ } // If USER_NULL, which shouldn't happen, leave it as USER_TYPE_PRIMARY
+ if (remainingBeforeWipe > 0) {
+ mView.showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe, userType);
+ } else {
+ // Too many attempts. The device will be wiped shortly.
+ Slog.i(TAG, "Too many unlock attempts; user " + expiringUser + " will be wiped!");
+ mView.showWipeDialog(failedAttempts, userType);
+ }
+ }
+ mLockPatternUtils.reportFailedPasswordAttempt(userId);
+ if (timeoutMs > 0) {
+ mLockPatternUtils.reportPasswordLockout(timeoutMs, userId);
+ mView.showTimeoutDialog(userId, timeoutMs, mLockPatternUtils,
+ mSecurityModel.getSecurityMode(userId));
+ }
+ }
+
+ private KeyguardInputViewController<KeyguardInputView> getCurrentSecurityController() {
+ return mSecurityViewFlipperController
+ .getSecurityView(mCurrentSecurityMode, mKeyguardSecurityCallback);
+ }
+
+ private KeyguardInputViewController<KeyguardInputView> changeSecurityMode(
+ SecurityMode securityMode) {
+ mCurrentSecurityMode = securityMode;
+ return getCurrentSecurityController();
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
index ac2160ecb4ae..c77c86711abf 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
@@ -18,13 +18,14 @@ package com.android.keyguard;
import static com.android.systemui.DejankUtils.whitelistIpcs;
import android.app.admin.DevicePolicyManager;
-import android.content.Context;
+import android.content.res.Resources;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.Dependency;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
import javax.inject.Inject;
@@ -33,7 +34,7 @@ public class KeyguardSecurityModel {
/**
* The different types of security available.
- * @see KeyguardSecurityContainer#showSecurityScreen
+ * @see KeyguardSecurityContainerController#showSecurityScreen
*/
public enum SecurityMode {
Invalid, // NULL state
@@ -45,21 +46,15 @@ public class KeyguardSecurityModel {
SimPuk // Unlock by entering a sim puk
}
- private final Context mContext;
private final boolean mIsPukScreenAvailable;
- private LockPatternUtils mLockPatternUtils;
+ private final LockPatternUtils mLockPatternUtils;
@Inject
- KeyguardSecurityModel(Context context) {
- mContext = context;
- mLockPatternUtils = new LockPatternUtils(context);
- mIsPukScreenAvailable = mContext.getResources().getBoolean(
+ KeyguardSecurityModel(@Main Resources resources, LockPatternUtils lockPatternUtils) {
+ mIsPukScreenAvailable = resources.getBoolean(
com.android.internal.R.bool.config_enable_puk_unlock_screen);
- }
-
- void setLockPatternUtils(LockPatternUtils utils) {
- mLockPatternUtils = utils;
+ mLockPatternUtils = lockPatternUtils;
}
public SecurityMode getSecurityMode(int userId) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
index 43cef3acf147..ac00e9453c97 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
@@ -18,11 +18,9 @@ package com.android.keyguard;
import android.content.res.ColorStateList;
import android.view.MotionEvent;
-import com.android.internal.widget.LockPatternUtils;
-
public interface KeyguardSecurityView {
- static public final int SCREEN_ON = 1;
- static public final int VIEW_REVEALED = 2;
+ int SCREEN_ON = 1;
+ int VIEW_REVEALED = 2;
int PROMPT_REASON_NONE = 0;
@@ -63,18 +61,6 @@ public interface KeyguardSecurityView {
int PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT = 7;
/**
- * Interface back to keyguard to tell it when security
- * @param callback
- */
- void setKeyguardCallback(KeyguardSecurityCallback callback);
-
- /**
- * Set {@link LockPatternUtils} object. Useful for providing a mock interface.
- * @param utils
- */
- void setLockPatternUtils(LockPatternUtils utils);
-
- /**
* Reset the view and prepare to take input. This should do things like clearing the
* password or pattern and clear error messages.
*/
@@ -101,12 +87,6 @@ public interface KeyguardSecurityView {
boolean needsInput();
/**
- * Get {@link KeyguardSecurityCallback} for the given object
- * @return KeyguardSecurityCallback
- */
- KeyguardSecurityCallback getCallback();
-
- /**
* Show a string explaining why the security view needs to be solved.
*
* @param reason a flag indicating which string should be shown, see {@link #PROMPT_REASON_NONE}
@@ -123,12 +103,6 @@ public interface KeyguardSecurityView {
void showMessage(CharSequence message, ColorStateList colorState);
/**
- * Instruct the view to show usability hints, if any.
- *
- */
- void showUsabilityHint();
-
- /**
* Starts the animation which should run when the security view appears.
*/
void startAppearAnimation();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewController.java
deleted file mode 100644
index ef9ba19fbb43..000000000000
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewController.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import android.view.View;
-
-import com.android.systemui.util.ViewController;
-
-import javax.inject.Inject;
-
-
-/** Controller for a {@link KeyguardSecurityView}. */
-public class KeyguardSecurityViewController extends ViewController<View> {
-
- private final KeyguardSecurityView mView;
-
- private KeyguardSecurityViewController(KeyguardSecurityView view) {
- super((View) view);
- // KeyguardSecurityView isn't actually a View, so we need to track it ourselves.
- mView = view;
- }
-
- @Override
- protected void onViewAttached() {
-
- }
-
- @Override
- protected void onViewDetached() {
-
- }
-
- /** Factory for a {@link KeyguardSecurityViewController}. */
- public static class Factory {
- @Inject
- public Factory() {
- }
-
- /** Create a new {@link KeyguardSecurityViewController}. */
- public KeyguardSecurityViewController create(KeyguardSecurityView view) {
- return new KeyguardSecurityViewController(view);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
index 24da3ad46f23..b8439af6daaa 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
@@ -18,7 +18,6 @@ package com.android.keyguard;
import android.annotation.NonNull;
import android.content.Context;
-import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.util.AttributeSet;
@@ -31,7 +30,6 @@ import android.view.ViewHierarchyEncoder;
import android.widget.FrameLayout;
import android.widget.ViewFlipper;
-import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.R;
/**
@@ -39,7 +37,7 @@ import com.android.systemui.R;
* we can emulate {@link android.view.WindowManager.LayoutParams#FLAG_SLIPPERY} within a view
* hierarchy.
*/
-public class KeyguardSecurityViewFlipper extends ViewFlipper implements KeyguardSecurityView {
+public class KeyguardSecurityViewFlipper extends ViewFlipper {
private static final String TAG = "KeyguardSecurityViewFlipper";
private static final boolean DEBUG = KeyguardConstants.DEBUG;
@@ -69,111 +67,16 @@ public class KeyguardSecurityViewFlipper extends ViewFlipper implements Keyguard
return result;
}
- KeyguardSecurityView getSecurityView() {
+ KeyguardInputView getSecurityView() {
View child = getChildAt(getDisplayedChild());
- if (child instanceof KeyguardSecurityView) {
- return (KeyguardSecurityView) child;
+ if (child instanceof KeyguardInputView) {
+ return (KeyguardInputView) child;
}
return null;
}
- @Override
- public void setKeyguardCallback(KeyguardSecurityCallback callback) {
- KeyguardSecurityView ksv = getSecurityView();
- if (ksv != null) {
- ksv.setKeyguardCallback(callback);
- }
- }
-
- @Override
- public void setLockPatternUtils(LockPatternUtils utils) {
- KeyguardSecurityView ksv = getSecurityView();
- if (ksv != null) {
- ksv.setLockPatternUtils(utils);
- }
- }
-
- @Override
- public void reset() {
- KeyguardSecurityView ksv = getSecurityView();
- if (ksv != null) {
- ksv.reset();
- }
- }
-
- @Override
- public void onPause() {
- KeyguardSecurityView ksv = getSecurityView();
- if (ksv != null) {
- ksv.onPause();
- }
- }
-
- @Override
- public void onResume(int reason) {
- KeyguardSecurityView ksv = getSecurityView();
- if (ksv != null) {
- ksv.onResume(reason);
- }
- }
-
- @Override
- public boolean needsInput() {
- KeyguardSecurityView ksv = getSecurityView();
- return (ksv != null) ? ksv.needsInput() : false;
- }
-
- @Override
- public KeyguardSecurityCallback getCallback() {
- KeyguardSecurityView ksv = getSecurityView();
- return (ksv != null) ? ksv.getCallback() : null;
- }
-
- @Override
- public void showPromptReason(int reason) {
- KeyguardSecurityView ksv = getSecurityView();
- if (ksv != null) {
- ksv.showPromptReason(reason);
- }
- }
-
- @Override
- public void showMessage(CharSequence message, ColorStateList colorState) {
- KeyguardSecurityView ksv = getSecurityView();
- if (ksv != null) {
- ksv.showMessage(message, colorState);
- }
- }
-
- @Override
- public void showUsabilityHint() {
- KeyguardSecurityView ksv = getSecurityView();
- if (ksv != null) {
- ksv.showUsabilityHint();
- }
- }
-
- @Override
- public void startAppearAnimation() {
- KeyguardSecurityView ksv = getSecurityView();
- if (ksv != null) {
- ksv.startAppearAnimation();
- }
- }
-
- @Override
- public boolean startDisappearAnimation(Runnable finishRunnable) {
- KeyguardSecurityView ksv = getSecurityView();
- if (ksv != null) {
- return ksv.startDisappearAnimation(finishRunnable);
- } else {
- return false;
- }
- }
-
- @Override
public CharSequence getTitle() {
- KeyguardSecurityView ksv = getSecurityView();
+ KeyguardInputView ksv = getSecurityView();
if (ksv != null) {
return ksv.getTitle();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
new file mode 100644
index 000000000000..49530355a6fb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.util.Log;
+import android.view.LayoutInflater;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.keyguard.KeyguardInputViewController.Factory;
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.keyguard.dagger.KeyguardBouncerScope;
+import com.android.systemui.R;
+import com.android.systemui.util.ViewController;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+/**
+ * Controller for a {@link KeyguardSecurityViewFlipper}.
+ */
+@KeyguardBouncerScope
+public class KeyguardSecurityViewFlipperController
+ extends ViewController<KeyguardSecurityViewFlipper> {
+
+ private static final boolean DEBUG = KeyguardConstants.DEBUG;
+ private static final String TAG = "KeyguardSecurityView";
+
+ private final List<KeyguardInputViewController<KeyguardInputView>> mChildren =
+ new ArrayList<>();
+ private final LayoutInflater mLayoutInflater;
+ private final Factory mKeyguardSecurityViewControllerFactory;
+
+ @Inject
+ protected KeyguardSecurityViewFlipperController(KeyguardSecurityViewFlipper view,
+ LayoutInflater layoutInflater,
+ KeyguardInputViewController.Factory keyguardSecurityViewControllerFactory) {
+ super(view);
+ mKeyguardSecurityViewControllerFactory = keyguardSecurityViewControllerFactory;
+ mLayoutInflater = layoutInflater;
+ }
+
+ @Override
+ protected void onViewAttached() {
+
+ }
+
+ @Override
+ protected void onViewDetached() {
+
+ }
+
+ public void reset() {
+ for (KeyguardInputViewController<KeyguardInputView> child : mChildren) {
+ child.reset();
+ }
+ }
+
+ @VisibleForTesting
+ KeyguardInputViewController<KeyguardInputView> getSecurityView(SecurityMode securityMode,
+ KeyguardSecurityCallback keyguardSecurityCallback) {
+ KeyguardInputViewController<KeyguardInputView> childController = null;
+ for (KeyguardInputViewController<KeyguardInputView> child : mChildren) {
+ if (child.getSecurityMode() == securityMode) {
+ childController = child;
+ break;
+ }
+ }
+
+ if (childController == null
+ && securityMode != SecurityMode.None && securityMode != SecurityMode.Invalid) {
+
+ int layoutId = getLayoutIdFor(securityMode);
+ KeyguardInputView view = null;
+ if (layoutId != 0) {
+ if (DEBUG) Log.v(TAG, "inflating id = " + layoutId);
+ view = (KeyguardInputView) mLayoutInflater.inflate(
+ layoutId, mView, false);
+ mView.addView(view);
+ childController = mKeyguardSecurityViewControllerFactory.create(
+ view, securityMode, keyguardSecurityCallback);
+ childController.init();
+
+ mChildren.add(childController);
+ }
+ }
+
+ if (childController == null) {
+ childController = new NullKeyguardInputViewController(
+ securityMode, keyguardSecurityCallback);
+ }
+
+ return childController;
+ }
+
+ private int getLayoutIdFor(SecurityMode securityMode) {
+ switch (securityMode) {
+ case Pattern: return com.android.systemui.R.layout.keyguard_pattern_view;
+ case PIN: return com.android.systemui.R.layout.keyguard_pin_view;
+ case Password: return com.android.systemui.R.layout.keyguard_password_view;
+ case SimPin: return com.android.systemui.R.layout.keyguard_sim_pin_view;
+ case SimPuk: return R.layout.keyguard_sim_puk_view;
+ default:
+ return 0;
+ }
+ }
+
+ /** Makes the supplied child visible if it is contained win this view, */
+ public void show(KeyguardInputViewController<KeyguardInputView> childController) {
+ int index = childController.getIndexIn(mView);
+ if (index != -1) {
+ mView.setDisplayedChild(index);
+ }
+ }
+
+ private static class NullKeyguardInputViewController
+ extends KeyguardInputViewController<KeyguardInputView> {
+ protected NullKeyguardInputViewController(SecurityMode securityMode,
+ KeyguardSecurityCallback keyguardSecurityCallback) {
+ super(null, securityMode, keyguardSecurityCallback);
+ }
+
+ @Override
+ public boolean needsInput() {
+ return false;
+ }
+
+ @Override
+ public void onStartingToHide() {
+
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
index 1c47aa0151f0..c0f9ce794628 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
@@ -16,66 +16,19 @@
package com.android.keyguard;
-import android.annotation.NonNull;
-import android.app.AlertDialog;
-import android.app.AlertDialog.Builder;
-import android.app.Dialog;
-import android.app.ProgressDialog;
import android.content.Context;
-import android.content.res.ColorStateList;
import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Color;
-import android.telephony.PinResult;
-import android.telephony.SubscriptionInfo;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.View;
-import android.view.WindowManager;
-import android.widget.ImageView;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
/**
* Displays a PIN pad for unlocking.
*/
public class KeyguardSimPinView extends KeyguardPinBasedInputView {
- private static final String LOG_TAG = "KeyguardSimPinView";
- private static final boolean DEBUG = KeyguardConstants.DEBUG_SIM_STATES;
public static final String TAG = "KeyguardSimPinView";
- private ProgressDialog mSimUnlockProgressDialog = null;
- private CheckSimPin mCheckSimPinThread;
-
- // Below flag is set to true during power-up or when a new SIM card inserted on device.
- // When this is true and when SIM card is PIN locked state, on PIN lock screen, message would
- // be displayed to inform user about the number of remaining PIN attempts left.
- private boolean mShowDefaultMessage = true;
- private int mRemainingAttempts = -1;
- private AlertDialog mRemainingAttemptsDialog;
- private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
- private ImageView mSimImageView;
-
- KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() {
- @Override
- public void onSimStateChanged(int subId, int slotId, int simState) {
- if (DEBUG) Log.v(TAG, "onSimStateChanged(subId=" + subId + ",state=" + simState + ")");
- switch(simState) {
- case TelephonyManager.SIM_STATE_READY: {
- mRemainingAttempts = -1;
- resetState();
- break;
- }
- default:
- resetState();
- }
- }
- };
-
public KeyguardSimPinView(Context context) {
this(context, null);
}
@@ -84,81 +37,9 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView {
super(context, attrs);
}
- @Override
- public void resetState() {
- super.resetState();
- if (DEBUG) Log.v(TAG, "Resetting state");
- handleSubInfoChangeIfNeeded();
- if (mShowDefaultMessage) {
- showDefaultMessage();
- }
- boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
-
+ public void setEsimLocked(boolean locked) {
KeyguardEsimArea esimButton = findViewById(R.id.keyguard_esim_area);
- esimButton.setVisibility(isEsimLocked ? View.VISIBLE : View.GONE);
- }
-
- private void setLockedSimMessage() {
- boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
- int count = 1;
- TelephonyManager telephonyManager =
- (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
- if (telephonyManager != null) {
- count = telephonyManager.getActiveModemCount();
- }
- Resources rez = getResources();
- String msg;
- TypedArray array = mContext.obtainStyledAttributes(new int[] { R.attr.wallpaperTextColor });
- int color = array.getColor(0, Color.WHITE);
- array.recycle();
- if (count < 2) {
- msg = rez.getString(R.string.kg_sim_pin_instructions);
- } else {
- SubscriptionInfo info = Dependency.get(KeyguardUpdateMonitor.class)
- .getSubscriptionInfoForSubId(mSubId);
- CharSequence displayName = info != null ? info.getDisplayName() : ""; // don't crash
- msg = rez.getString(R.string.kg_sim_pin_instructions_multi, displayName);
- if (info != null) {
- color = info.getIconTint();
- }
- }
- if (isEsimLocked) {
- msg = rez.getString(R.string.kg_sim_lock_esim_instructions, msg);
- }
-
- if (mSecurityMessageDisplay != null && getVisibility() == VISIBLE) {
- mSecurityMessageDisplay.setMessage(msg);
- }
- mSimImageView.setImageTintList(ColorStateList.valueOf(color));
- }
-
- private void showDefaultMessage() {
- setLockedSimMessage();
- if (mRemainingAttempts >= 0) {
- return;
- }
-
- // Sending empty PIN here to query the number of remaining PIN attempts
- new CheckSimPin("", mSubId) {
- void onSimCheckResponse(final PinResult result) {
- Log.d(LOG_TAG, "onSimCheckResponse " + " empty One result "
- + result.toString());
- if (result.getAttemptsRemaining() >= 0) {
- mRemainingAttempts = result.getAttemptsRemaining();
- setLockedSimMessage();
- }
- }
- }.start();
- }
-
- private void handleSubInfoChangeIfNeeded() {
- KeyguardUpdateMonitor monitor = Dependency.get(KeyguardUpdateMonitor.class);
- int subId = monitor.getNextSubIdForState(TelephonyManager.SIM_STATE_PIN_REQUIRED);
- if (subId != mSubId && SubscriptionManager.isValidSubscriptionId(subId)) {
- mSubId = subId;
- mShowDefaultMessage = true;
- mRemainingAttempts = -1;
- }
+ esimButton.setVisibility(locked ? View.VISIBLE : View.GONE);
}
@Override
@@ -173,35 +54,6 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView {
return 0;
}
- private String getPinPasswordErrorMessage(int attemptsRemaining, boolean isDefault) {
- String displayMessage;
- int msgId;
- if (attemptsRemaining == 0) {
- displayMessage = getContext().getString(R.string.kg_password_wrong_pin_code_pukked);
- } else if (attemptsRemaining > 0) {
- msgId = isDefault ? R.plurals.kg_password_default_pin_message :
- R.plurals.kg_password_wrong_pin_code;
- displayMessage = getContext().getResources()
- .getQuantityString(msgId, attemptsRemaining, attemptsRemaining);
- } else {
- msgId = isDefault ? R.string.kg_sim_pin_instructions : R.string.kg_password_pin_failed;
- displayMessage = getContext().getString(msgId);
- }
- if (KeyguardEsimArea.isEsimLocked(mContext, mSubId)) {
- displayMessage = getResources()
- .getString(R.string.kg_sim_lock_esim_instructions, displayMessage);
- }
- if (DEBUG) Log.d(LOG_TAG, "getPinPasswordErrorMessage:"
- + " attemptsRemaining=" + attemptsRemaining + " displayMessage=" + displayMessage);
- return displayMessage;
- }
-
- @Override
- protected boolean shouldLockout(long deadline) {
- // SIM PIN doesn't have a timed lockout
- return false;
- }
-
@Override
protected int getPasswordTextViewId() {
return R.id.simPinEntry;
@@ -214,173 +66,6 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView {
if (mEcaView instanceof EmergencyCarrierArea) {
((EmergencyCarrierArea) mEcaView).setCarrierTextVisible(true);
}
- mSimImageView = findViewById(R.id.keyguard_sim);
- }
-
- @Override
- public void showUsabilityHint() {
-
- }
-
- @Override
- public void onResume(int reason) {
- super.onResume(reason);
- Dependency.get(KeyguardUpdateMonitor.class).registerCallback(mUpdateMonitorCallback);
- resetState();
- }
-
- @Override
- public void onPause() {
- // dismiss the dialog.
- if (mSimUnlockProgressDialog != null) {
- mSimUnlockProgressDialog.dismiss();
- mSimUnlockProgressDialog = null;
- }
- Dependency.get(KeyguardUpdateMonitor.class).removeCallback(mUpdateMonitorCallback);
- }
-
- /**
- * Since the IPC can block, we want to run the request in a separate thread
- * with a callback.
- */
- private abstract class CheckSimPin extends Thread {
- private final String mPin;
- private int mSubId;
-
- protected CheckSimPin(String pin, int subId) {
- mPin = pin;
- mSubId = subId;
- }
-
- abstract void onSimCheckResponse(@NonNull PinResult result);
-
- @Override
- public void run() {
- if (DEBUG) {
- Log.v(TAG, "call supplyPinReportResultForSubscriber(subid=" + mSubId + ")");
- }
- TelephonyManager telephonyManager =
- ((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE))
- .createForSubscriptionId(mSubId);
- final PinResult result = telephonyManager.supplyPinReportPinResult(mPin);
- if (result == null) {
- Log.e(TAG, "Error result for supplyPinReportResult.");
- post(new Runnable() {
- @Override
- public void run() {
- onSimCheckResponse(PinResult.getDefaultFailedResult());
- }
- });
- } else {
- if (DEBUG) {
- Log.v(TAG, "supplyPinReportResult returned: " + result.toString());
- }
- post(new Runnable() {
- @Override
- public void run() {
- onSimCheckResponse(result);
- }
- });
- }
- }
- }
-
- private Dialog getSimUnlockProgressDialog() {
- if (mSimUnlockProgressDialog == null) {
- mSimUnlockProgressDialog = new ProgressDialog(mContext);
- mSimUnlockProgressDialog.setMessage(
- mContext.getString(R.string.kg_sim_unlock_progress_dialog_message));
- mSimUnlockProgressDialog.setIndeterminate(true);
- mSimUnlockProgressDialog.setCancelable(false);
- mSimUnlockProgressDialog.getWindow().setType(
- WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- }
- return mSimUnlockProgressDialog;
- }
-
- private Dialog getSimRemainingAttemptsDialog(int remaining) {
- String msg = getPinPasswordErrorMessage(remaining, false);
- if (mRemainingAttemptsDialog == null) {
- Builder builder = new AlertDialog.Builder(mContext);
- builder.setMessage(msg);
- builder.setCancelable(false);
- builder.setNeutralButton(R.string.ok, null);
- mRemainingAttemptsDialog = builder.create();
- mRemainingAttemptsDialog.getWindow().setType(
- WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- } else {
- mRemainingAttemptsDialog.setMessage(msg);
- }
- return mRemainingAttemptsDialog;
- }
-
- @Override
- protected void verifyPasswordAndUnlock() {
- String entry = mPasswordEntry.getText();
-
- if (entry.length() < 4) {
- // otherwise, display a message to the user, and don't submit.
- mSecurityMessageDisplay.setMessage(R.string.kg_invalid_sim_pin_hint);
- resetPasswordText(true /* animate */, true /* announce */);
- mCallback.userActivity();
- return;
- }
-
- getSimUnlockProgressDialog().show();
-
- if (mCheckSimPinThread == null) {
- mCheckSimPinThread = new CheckSimPin(mPasswordEntry.getText(), mSubId) {
- @Override
- void onSimCheckResponse(final PinResult result) {
- post(new Runnable() {
- @Override
- public void run() {
- mRemainingAttempts = result.getAttemptsRemaining();
- if (mSimUnlockProgressDialog != null) {
- mSimUnlockProgressDialog.hide();
- }
- resetPasswordText(true /* animate */,
- /* announce */
- result.getType() != PinResult.PIN_RESULT_TYPE_SUCCESS);
- if (result.getType() == PinResult.PIN_RESULT_TYPE_SUCCESS) {
- Dependency.get(KeyguardUpdateMonitor.class)
- .reportSimUnlocked(mSubId);
- mRemainingAttempts = -1;
- mShowDefaultMessage = true;
- if (mCallback != null) {
- mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser());
- }
- } else {
- mShowDefaultMessage = false;
- if (result.getType() == PinResult.PIN_RESULT_TYPE_INCORRECT) {
- if (result.getAttemptsRemaining() <= 2) {
- // this is getting critical - show dialog
- getSimRemainingAttemptsDialog(
- result.getAttemptsRemaining()).show();
- } else {
- // show message
- mSecurityMessageDisplay.setMessage(
- getPinPasswordErrorMessage(
- result.getAttemptsRemaining(), false));
- }
- } else {
- // "PIN operation failed!" - no idea what this was and no way to
- // find out. :/
- mSecurityMessageDisplay.setMessage(getContext().getString(
- R.string.kg_password_pin_failed));
- }
- if (DEBUG) Log.d(LOG_TAG, "verifyPasswordAndUnlock "
- + " CheckSimPin.onSimCheckResponse: " + result
- + " attemptsRemaining=" + result.getAttemptsRemaining());
- }
- mCallback.userActivity();
- mCheckSimPinThread = null;
- }
- });
- }
- };
- mCheckSimPinThread.start();
- }
}
@Override
@@ -389,11 +74,6 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView {
}
@Override
- public boolean startDisappearAnimation(Runnable finishRunnable) {
- return false;
- }
-
- @Override
public CharSequence getTitle() {
return getContext().getString(
com.android.internal.R.string.keyguard_accessibility_sim_pin_unlock);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
new file mode 100644
index 000000000000..cc8bf4f2d028
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.annotation.NonNull;
+import android.app.AlertDialog;
+import android.app.AlertDialog.Builder;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.telephony.PinResult;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.ImageView;
+
+import com.android.internal.util.LatencyTracker;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.systemui.R;
+
+public class KeyguardSimPinViewController
+ extends KeyguardPinBasedInputViewController<KeyguardSimPinView> {
+ public static final String TAG = "KeyguardSimPinView";
+ private static final String LOG_TAG = "KeyguardSimPinView";
+ private static final boolean DEBUG = KeyguardConstants.DEBUG_SIM_STATES;
+ private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private final TelephonyManager mTelephonyManager;
+
+ private ProgressDialog mSimUnlockProgressDialog;
+ private CheckSimPin mCheckSimPinThread;
+ private int mRemainingAttempts;
+ // Below flag is set to true during power-up or when a new SIM card inserted on device.
+ // When this is true and when SIM card is PIN locked state, on PIN lock screen, message would
+ // be displayed to inform user about the number of remaining PIN attempts left.
+ private boolean mShowDefaultMessage;
+ private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ private AlertDialog mRemainingAttemptsDialog;
+ private ImageView mSimImageView;
+
+ KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onSimStateChanged(int subId, int slotId, int simState) {
+ if (DEBUG) Log.v(TAG, "onSimStateChanged(subId=" + subId + ",state=" + simState + ")");
+ if (simState == TelephonyManager.SIM_STATE_READY) {
+ mRemainingAttempts = -1;
+ resetState();
+ } else {
+ resetState();
+ }
+ }
+ };
+
+ protected KeyguardSimPinViewController(KeyguardSimPinView view,
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ SecurityMode securityMode, LockPatternUtils lockPatternUtils,
+ KeyguardSecurityCallback keyguardSecurityCallback,
+ KeyguardMessageAreaController.Factory messageAreaControllerFactory,
+ LatencyTracker latencyTracker,
+ LiftToActivateListener liftToActivateListener,
+ TelephonyManager telephonyManager) {
+ super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
+ messageAreaControllerFactory, latencyTracker, liftToActivateListener);
+ mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+ mTelephonyManager = telephonyManager;
+ mSimImageView = mView.findViewById(R.id.keyguard_sim);
+ }
+
+ @Override
+ protected void onViewAttached() {
+ super.onViewAttached();
+ }
+
+ @Override
+ void resetState() {
+ super.resetState();
+ if (DEBUG) Log.v(TAG, "Resetting state");
+ handleSubInfoChangeIfNeeded();
+ mMessageAreaController.setMessage("");
+ if (mShowDefaultMessage) {
+ showDefaultMessage();
+ }
+
+ mView.setEsimLocked(KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId));
+ }
+
+ @Override
+ public boolean startDisappearAnimation(Runnable finishRunnable) {
+ return false;
+ }
+
+ @Override
+ public void onResume(int reason) {
+ super.onResume(reason);
+ mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback);
+ mView.resetState();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback);
+
+ // dismiss the dialog.
+ if (mSimUnlockProgressDialog != null) {
+ mSimUnlockProgressDialog.dismiss();
+ mSimUnlockProgressDialog = null;
+ }
+ }
+
+ @Override
+ protected void verifyPasswordAndUnlock() {
+ String entry = mPasswordEntry.getText();
+
+ if (entry.length() < 4) {
+ // otherwise, display a message to the user, and don't submit.
+ mMessageAreaController.setMessage(
+ com.android.systemui.R.string.kg_invalid_sim_pin_hint);
+ mView.resetPasswordText(true /* animate */, true /* announce */);
+ getKeyguardSecurityCallback().userActivity();
+ return;
+ }
+
+ getSimUnlockProgressDialog().show();
+
+ if (mCheckSimPinThread == null) {
+ mCheckSimPinThread = new CheckSimPin(mPasswordEntry.getText(), mSubId) {
+ @Override
+ void onSimCheckResponse(final PinResult result) {
+ mView.post(() -> {
+ mRemainingAttempts = result.getAttemptsRemaining();
+ if (mSimUnlockProgressDialog != null) {
+ mSimUnlockProgressDialog.hide();
+ }
+ mView.resetPasswordText(true /* animate */,
+ /* announce */
+ result.getType() != PinResult.PIN_RESULT_TYPE_SUCCESS);
+ if (result.getType() == PinResult.PIN_RESULT_TYPE_SUCCESS) {
+ mKeyguardUpdateMonitor.reportSimUnlocked(mSubId);
+ mRemainingAttempts = -1;
+ mShowDefaultMessage = true;
+ getKeyguardSecurityCallback().dismiss(
+ true, KeyguardUpdateMonitor.getCurrentUser());
+ } else {
+ mShowDefaultMessage = false;
+ if (result.getType() == PinResult.PIN_RESULT_TYPE_INCORRECT) {
+ if (result.getAttemptsRemaining() <= 2) {
+ // this is getting critical - show dialog
+ getSimRemainingAttemptsDialog(
+ result.getAttemptsRemaining()).show();
+ } else {
+ // show message
+ mMessageAreaController.setMessage(
+ getPinPasswordErrorMessage(
+ result.getAttemptsRemaining(), false));
+ }
+ } else {
+ // "PIN operation failed!" - no idea what this was and no way to
+ // find out. :/
+ mMessageAreaController.setMessage(mView.getResources().getString(
+ R.string.kg_password_pin_failed));
+ }
+ if (DEBUG) {
+ Log.d(LOG_TAG, "verifyPasswordAndUnlock "
+ + " CheckSimPin.onSimCheckResponse: " + result
+ + " attemptsRemaining=" + result.getAttemptsRemaining());
+ }
+ }
+ getKeyguardSecurityCallback().userActivity();
+ mCheckSimPinThread = null;
+ });
+ }
+ };
+ mCheckSimPinThread.start();
+ }
+ }
+
+ private Dialog getSimUnlockProgressDialog() {
+ if (mSimUnlockProgressDialog == null) {
+ mSimUnlockProgressDialog = new ProgressDialog(mView.getContext());
+ mSimUnlockProgressDialog.setMessage(
+ mView.getResources().getString(R.string.kg_sim_unlock_progress_dialog_message));
+ mSimUnlockProgressDialog.setIndeterminate(true);
+ mSimUnlockProgressDialog.setCancelable(false);
+ mSimUnlockProgressDialog.getWindow().setType(
+ WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+ }
+ return mSimUnlockProgressDialog;
+ }
+
+
+ private Dialog getSimRemainingAttemptsDialog(int remaining) {
+ String msg = getPinPasswordErrorMessage(remaining, false);
+ if (mRemainingAttemptsDialog == null) {
+ Builder builder = new AlertDialog.Builder(mView.getContext());
+ builder.setMessage(msg);
+ builder.setCancelable(false);
+ builder.setNeutralButton(R.string.ok, null);
+ mRemainingAttemptsDialog = builder.create();
+ mRemainingAttemptsDialog.getWindow().setType(
+ WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+ } else {
+ mRemainingAttemptsDialog.setMessage(msg);
+ }
+ return mRemainingAttemptsDialog;
+ }
+
+
+ private String getPinPasswordErrorMessage(int attemptsRemaining, boolean isDefault) {
+ String displayMessage;
+ int msgId;
+ if (attemptsRemaining == 0) {
+ displayMessage = mView.getResources().getString(
+ R.string.kg_password_wrong_pin_code_pukked);
+ } else if (attemptsRemaining > 0) {
+ msgId = isDefault ? R.plurals.kg_password_default_pin_message :
+ R.plurals.kg_password_wrong_pin_code;
+ displayMessage = mView.getResources()
+ .getQuantityString(msgId, attemptsRemaining, attemptsRemaining);
+ } else {
+ msgId = isDefault ? R.string.kg_sim_pin_instructions : R.string.kg_password_pin_failed;
+ displayMessage = mView.getResources().getString(msgId);
+ }
+ if (KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId)) {
+ displayMessage = mView.getResources()
+ .getString(R.string.kg_sim_lock_esim_instructions, displayMessage);
+ }
+ if (DEBUG) {
+ Log.d(LOG_TAG, "getPinPasswordErrorMessage: attemptsRemaining="
+ + attemptsRemaining + " displayMessage=" + displayMessage);
+ }
+ return displayMessage;
+ }
+
+ private void showDefaultMessage() {
+ setLockedSimMessage();
+ if (mRemainingAttempts >= 0) {
+ return;
+ }
+
+ // Sending empty PIN here to query the number of remaining PIN attempts
+ new CheckSimPin("", mSubId) {
+ void onSimCheckResponse(final PinResult result) {
+ Log.d(LOG_TAG, "onSimCheckResponse " + " empty One result "
+ + result.toString());
+ if (result.getAttemptsRemaining() >= 0) {
+ mRemainingAttempts = result.getAttemptsRemaining();
+ setLockedSimMessage();
+ }
+ }
+ }.start();
+ }
+
+ /**
+ * Since the IPC can block, we want to run the request in a separate thread
+ * with a callback.
+ */
+ private abstract class CheckSimPin extends Thread {
+ private final String mPin;
+ private int mSubId;
+
+ protected CheckSimPin(String pin, int subId) {
+ mPin = pin;
+ mSubId = subId;
+ }
+
+ abstract void onSimCheckResponse(@NonNull PinResult result);
+
+ @Override
+ public void run() {
+ if (DEBUG) {
+ Log.v(TAG, "call supplyPinReportResultForSubscriber(subid=" + mSubId + ")");
+ }
+ TelephonyManager telephonyManager =
+ mTelephonyManager.createForSubscriptionId(mSubId);
+ final PinResult result = telephonyManager.supplyPinReportPinResult(mPin);
+ if (result == null) {
+ Log.e(TAG, "Error result for supplyPinReportResult.");
+ mView.post(() -> onSimCheckResponse(PinResult.getDefaultFailedResult()));
+ } else {
+ if (DEBUG) {
+ Log.v(TAG, "supplyPinReportResult returned: " + result.toString());
+ }
+ mView.post(() -> onSimCheckResponse(result));
+ }
+ }
+ }
+
+ private void setLockedSimMessage() {
+ boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId);
+ int count = 1;
+ if (mTelephonyManager != null) {
+ count = mTelephonyManager.getActiveModemCount();
+ }
+ Resources rez = mView.getResources();
+ String msg;
+ TypedArray array = mView.getContext().obtainStyledAttributes(
+ new int[] { R.attr.wallpaperTextColor });
+ int color = array.getColor(0, Color.WHITE);
+ array.recycle();
+ if (count < 2) {
+ msg = rez.getString(R.string.kg_sim_pin_instructions);
+ } else {
+ SubscriptionInfo info = mKeyguardUpdateMonitor.getSubscriptionInfoForSubId(mSubId);
+ CharSequence displayName = info != null ? info.getDisplayName() : ""; // don't crash
+ msg = rez.getString(R.string.kg_sim_pin_instructions_multi, displayName);
+ if (info != null) {
+ color = info.getIconTint();
+ }
+ }
+ if (isEsimLocked) {
+ msg = rez.getString(R.string.kg_sim_lock_esim_instructions, msg);
+ }
+
+ if (mView.getVisibility() == View.VISIBLE) {
+ mMessageAreaController.setMessage(msg);
+ }
+ mSimImageView.setImageTintList(ColorStateList.valueOf(color));
+ }
+
+ private void handleSubInfoChangeIfNeeded() {
+ int subId = mKeyguardUpdateMonitor
+ .getNextSubIdForState(TelephonyManager.SIM_STATE_PIN_REQUIRED);
+ if (subId != mSubId && SubscriptionManager.isValidSubscriptionId(subId)) {
+ mSubId = subId;
+ mShowDefaultMessage = true;
+ mRemainingAttempts = -1;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
index 5148dd709026..0d72c93e9041 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
@@ -16,27 +16,10 @@
package com.android.keyguard;
-import android.annotation.NonNull;
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.ProgressDialog;
import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Color;
-import android.telephony.PinResult;
-import android.telephony.SubscriptionInfo;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
import android.util.AttributeSet;
import android.util.Log;
-import android.view.View;
-import android.view.WindowManager;
-import android.widget.ImageView;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
@@ -44,48 +27,9 @@ import com.android.systemui.R;
* Displays a PIN pad for entering a PUK (Pin Unlock Kode) provided by a carrier.
*/
public class KeyguardSimPukView extends KeyguardPinBasedInputView {
- private static final String LOG_TAG = "KeyguardSimPukView";
private static final boolean DEBUG = KeyguardConstants.DEBUG;
public static final String TAG = "KeyguardSimPukView";
- private ProgressDialog mSimUnlockProgressDialog = null;
- private CheckSimPuk mCheckSimPukThread;
-
- // Below flag is set to true during power-up or when a new SIM card inserted on device.
- // When this is true and when SIM card is PUK locked state, on PIN lock screen, message would
- // be displayed to inform user about the number of remaining PUK attempts left.
- private boolean mShowDefaultMessage = true;
- private int mRemainingAttempts = -1;
- private String mPukText;
- private String mPinText;
- private StateMachine mStateMachine = new StateMachine();
- private AlertDialog mRemainingAttemptsDialog;
- private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
- private ImageView mSimImageView;
-
- KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() {
- @Override
- public void onSimStateChanged(int subId, int slotId, int simState) {
- if (DEBUG) Log.v(TAG, "onSimStateChanged(subId=" + subId + ",state=" + simState + ")");
- switch(simState) {
- // If the SIM is unlocked via a key sequence through the emergency dialer, it will
- // move into the READY state and the PUK lock keyguard should be removed.
- case TelephonyManager.SIM_STATE_READY: {
- mRemainingAttempts = -1;
- mShowDefaultMessage = true;
- // mCallback can be null if onSimStateChanged callback is called when keyguard
- // isn't active.
- if (mCallback != null) {
- mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser());
- }
- break;
- }
- default:
- resetState();
- }
- }
- };
-
public KeyguardSimPukView(Context context) {
this(context, null);
}
@@ -94,136 +38,14 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView {
super(context, attrs);
}
- private class StateMachine {
- final int ENTER_PUK = 0;
- final int ENTER_PIN = 1;
- final int CONFIRM_PIN = 2;
- final int DONE = 3;
- private int state = ENTER_PUK;
-
- public void next() {
- int msg = 0;
- if (state == ENTER_PUK) {
- if (checkPuk()) {
- state = ENTER_PIN;
- msg = R.string.kg_puk_enter_pin_hint;
- } else {
- msg = R.string.kg_invalid_sim_puk_hint;
- }
- } else if (state == ENTER_PIN) {
- if (checkPin()) {
- state = CONFIRM_PIN;
- msg = R.string.kg_enter_confirm_pin_hint;
- } else {
- msg = R.string.kg_invalid_sim_pin_hint;
- }
- } else if (state == CONFIRM_PIN) {
- if (confirmPin()) {
- state = DONE;
- msg = R.string.keyguard_sim_unlock_progress_dialog_message;
- updateSim();
- } else {
- state = ENTER_PIN; // try again?
- msg = R.string.kg_invalid_confirm_pin_hint;
- }
- }
- resetPasswordText(true /* animate */, true /* announce */);
- if (msg != 0) {
- mSecurityMessageDisplay.setMessage(msg);
- }
- }
-
-
- void reset() {
- mPinText="";
- mPukText="";
- state = ENTER_PUK;
- handleSubInfoChangeIfNeeded();
- if (mShowDefaultMessage) {
- showDefaultMessage();
- }
- boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
-
- KeyguardEsimArea esimButton = findViewById(R.id.keyguard_esim_area);
- esimButton.setVisibility(isEsimLocked ? View.VISIBLE : View.GONE);
- mPasswordEntry.requestFocus();
- }
-
-
- }
-
- private void showDefaultMessage() {
- if (mRemainingAttempts >= 0) {
- mSecurityMessageDisplay.setMessage(getPukPasswordErrorMessage(
- mRemainingAttempts, true));
- return;
- }
-
- boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
- int count = 1;
- TelephonyManager telephonyManager =
- (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
- if (telephonyManager != null) {
- count = telephonyManager.getActiveModemCount();
- }
- Resources rez = getResources();
- String msg;
- TypedArray array = mContext.obtainStyledAttributes(new int[] { R.attr.wallpaperTextColor });
- int color = array.getColor(0, Color.WHITE);
- array.recycle();
- if (count < 2) {
- msg = rez.getString(R.string.kg_puk_enter_puk_hint);
- } else {
- SubscriptionInfo info = Dependency.get(KeyguardUpdateMonitor.class)
- .getSubscriptionInfoForSubId(mSubId);
- CharSequence displayName = info != null ? info.getDisplayName() : "";
- msg = rez.getString(R.string.kg_puk_enter_puk_hint_multi, displayName);
- if (info != null) {
- color = info.getIconTint();
- }
- }
- if (isEsimLocked) {
- msg = rez.getString(R.string.kg_sim_lock_esim_instructions, msg);
- }
- if (mSecurityMessageDisplay != null) {
- mSecurityMessageDisplay.setMessage(msg);
- }
- mSimImageView.setImageTintList(ColorStateList.valueOf(color));
-
- // Sending empty PUK here to query the number of remaining PIN attempts
- new CheckSimPuk("", "", mSubId) {
- void onSimLockChangedResponse(final PinResult result) {
- if (result == null) Log.e(LOG_TAG, "onSimCheckResponse, pin result is NULL");
- else {
- Log.d(LOG_TAG, "onSimCheckResponse " + " empty One result "
- + result.toString());
- if (result.getAttemptsRemaining() >= 0) {
- mRemainingAttempts = result.getAttemptsRemaining();
- mSecurityMessageDisplay.setMessage(
- getPukPasswordErrorMessage(result.getAttemptsRemaining(), true));
- }
- }
- }
- }.start();
- }
-
- private void handleSubInfoChangeIfNeeded() {
- KeyguardUpdateMonitor monitor = Dependency.get(KeyguardUpdateMonitor.class);
- int subId = monitor.getNextSubIdForState(TelephonyManager.SIM_STATE_PUK_REQUIRED);
- if (subId != mSubId && SubscriptionManager.isValidSubscriptionId(subId)) {
- mSubId = subId;
- mShowDefaultMessage = true;
- mRemainingAttempts = -1;
- }
- }
-
@Override
protected int getPromptReasonStringRes(int reason) {
// No message on SIM Puk
return 0;
}
- private String getPukPasswordErrorMessage(int attemptsRemaining, boolean isDefault) {
+ String getPukPasswordErrorMessage(
+ int attemptsRemaining, boolean isDefault, boolean isEsimLocked) {
String displayMessage;
if (attemptsRemaining == 0) {
@@ -238,28 +60,19 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView {
R.string.kg_password_puk_failed;
displayMessage = getContext().getString(msgId);
}
- if (KeyguardEsimArea.isEsimLocked(mContext, mSubId)) {
+ if (isEsimLocked) {
displayMessage = getResources()
.getString(R.string.kg_sim_lock_esim_instructions, displayMessage);
}
- if (DEBUG) Log.d(LOG_TAG, "getPukPasswordErrorMessage:"
- + " attemptsRemaining=" + attemptsRemaining + " displayMessage=" + displayMessage);
+ if (DEBUG) {
+ Log.d(TAG, "getPukPasswordErrorMessage:"
+ + " attemptsRemaining=" + attemptsRemaining
+ + " displayMessage=" + displayMessage);
+ }
return displayMessage;
}
@Override
- public void resetState() {
- super.resetState();
- mStateMachine.reset();
- }
-
- @Override
- protected boolean shouldLockout(long deadline) {
- // SIM PUK doesn't have a timed lockout
- return false;
- }
-
- @Override
protected int getPasswordTextViewId() {
return R.id.pukEntry;
}
@@ -271,197 +84,6 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView {
if (mEcaView instanceof EmergencyCarrierArea) {
((EmergencyCarrierArea) mEcaView).setCarrierTextVisible(true);
}
- mSimImageView = findViewById(R.id.keyguard_sim);
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- Dependency.get(KeyguardUpdateMonitor.class).registerCallback(mUpdateMonitorCallback);
- resetState();
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- Dependency.get(KeyguardUpdateMonitor.class).removeCallback(mUpdateMonitorCallback);
- }
-
- @Override
- public void showUsabilityHint() {
- }
-
- @Override
- public void onPause() {
- // dismiss the dialog.
- if (mSimUnlockProgressDialog != null) {
- mSimUnlockProgressDialog.dismiss();
- mSimUnlockProgressDialog = null;
- }
- }
-
- /**
- * Since the IPC can block, we want to run the request in a separate thread
- * with a callback.
- */
- private abstract class CheckSimPuk extends Thread {
-
- private final String mPin, mPuk;
- private final int mSubId;
-
- protected CheckSimPuk(String puk, String pin, int subId) {
- mPuk = puk;
- mPin = pin;
- mSubId = subId;
- }
-
- abstract void onSimLockChangedResponse(@NonNull PinResult result);
-
- @Override
- public void run() {
- if (DEBUG) Log.v(TAG, "call supplyPukReportResult()");
- TelephonyManager telephonyManager =
- ((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE))
- .createForSubscriptionId(mSubId);
- final PinResult result = telephonyManager.supplyPukReportPinResult(mPuk, mPin);
- if (result == null) {
- Log.e(TAG, "Error result for supplyPukReportResult.");
- post(new Runnable() {
- @Override
- public void run() {
- onSimLockChangedResponse(PinResult.getDefaultFailedResult());
- }
- });
- } else {
- if (DEBUG) {
- Log.v(TAG, "supplyPukReportResult returned: " + result.toString());
- }
- post(new Runnable() {
- @Override
- public void run() {
- onSimLockChangedResponse(result);
- }
- });
- }
- }
- }
-
- private Dialog getSimUnlockProgressDialog() {
- if (mSimUnlockProgressDialog == null) {
- mSimUnlockProgressDialog = new ProgressDialog(mContext);
- mSimUnlockProgressDialog.setMessage(
- mContext.getString(R.string.kg_sim_unlock_progress_dialog_message));
- mSimUnlockProgressDialog.setIndeterminate(true);
- mSimUnlockProgressDialog.setCancelable(false);
- if (!(mContext instanceof Activity)) {
- mSimUnlockProgressDialog.getWindow().setType(
- WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- }
- }
- return mSimUnlockProgressDialog;
- }
-
- private Dialog getPukRemainingAttemptsDialog(int remaining) {
- String msg = getPukPasswordErrorMessage(remaining, false);
- if (mRemainingAttemptsDialog == null) {
- AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
- builder.setMessage(msg);
- builder.setCancelable(false);
- builder.setNeutralButton(R.string.ok, null);
- mRemainingAttemptsDialog = builder.create();
- mRemainingAttemptsDialog.getWindow().setType(
- WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- } else {
- mRemainingAttemptsDialog.setMessage(msg);
- }
- return mRemainingAttemptsDialog;
- }
-
- private boolean checkPuk() {
- // make sure the puk is at least 8 digits long.
- if (mPasswordEntry.getText().length() == 8) {
- mPukText = mPasswordEntry.getText();
- return true;
- }
- return false;
- }
-
- private boolean checkPin() {
- // make sure the PIN is between 4 and 8 digits
- int length = mPasswordEntry.getText().length();
- if (length >= 4 && length <= 8) {
- mPinText = mPasswordEntry.getText();
- return true;
- }
- return false;
- }
-
- public boolean confirmPin() {
- return mPinText.equals(mPasswordEntry.getText());
- }
-
- private void updateSim() {
- getSimUnlockProgressDialog().show();
-
- if (mCheckSimPukThread == null) {
- mCheckSimPukThread = new CheckSimPuk(mPukText, mPinText, mSubId) {
- @Override
- void onSimLockChangedResponse(final PinResult result) {
- post(new Runnable() {
- @Override
- public void run() {
- if (mSimUnlockProgressDialog != null) {
- mSimUnlockProgressDialog.hide();
- }
- resetPasswordText(true /* animate */,
- /* announce */
- result.getType() != PinResult.PIN_RESULT_TYPE_SUCCESS);
- if (result.getType() == PinResult.PIN_RESULT_TYPE_SUCCESS) {
- Dependency.get(KeyguardUpdateMonitor.class)
- .reportSimUnlocked(mSubId);
- mRemainingAttempts = -1;
- mShowDefaultMessage = true;
- if (mCallback != null) {
- mCallback.dismiss(true,
- KeyguardUpdateMonitor.getCurrentUser());
- }
- } else {
- mShowDefaultMessage = false;
- if (result.getType() == PinResult.PIN_RESULT_TYPE_INCORRECT) {
- // show message
- mSecurityMessageDisplay.setMessage(getPukPasswordErrorMessage(
- result.getAttemptsRemaining(), false));
- if (result.getAttemptsRemaining() <= 2) {
- // this is getting critical - show dialog
- getPukRemainingAttemptsDialog(
- result.getAttemptsRemaining()).show();
- } else {
- // show message
- mSecurityMessageDisplay.setMessage(
- getPukPasswordErrorMessage(
- result.getAttemptsRemaining(), false));
- }
- } else {
- mSecurityMessageDisplay.setMessage(getContext().getString(
- R.string.kg_password_puk_failed));
- }
- if (DEBUG) Log.d(LOG_TAG, "verifyPasswordAndUnlock "
- + " UpdateSim.onSimCheckResponse: "
- + " attemptsRemaining=" + result.getAttemptsRemaining());
- }
- mStateMachine.reset();
- mCheckSimPukThread = null;
- }
- });
- }
- };
- mCheckSimPukThread.start();
- }
- }
-
- @Override
- protected void verifyPasswordAndUnlock() {
- mStateMachine.next();
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
new file mode 100644
index 000000000000..a87374939ba6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
@@ -0,0 +1,413 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.annotation.NonNull;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.telephony.PinResult;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.ImageView;
+
+import com.android.internal.util.LatencyTracker;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.systemui.Dependency;
+import com.android.systemui.R;
+
+public class KeyguardSimPukViewController
+ extends KeyguardPinBasedInputViewController<KeyguardSimPukView> {
+ private static final boolean DEBUG = KeyguardConstants.DEBUG;
+ public static final String TAG = "KeyguardSimPukView";
+
+ private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private final TelephonyManager mTelephonyManager;
+
+ private String mPukText;
+ private String mPinText;
+ private int mRemainingAttempts;
+ // Below flag is set to true during power-up or when a new SIM card inserted on device.
+ // When this is true and when SIM card is PUK locked state, on PIN lock screen, message would
+ // be displayed to inform user about the number of remaining PUK attempts left.
+ private boolean mShowDefaultMessage;
+ private StateMachine mStateMachine = new StateMachine();
+ private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ private CheckSimPuk mCheckSimPukThread;
+ private ProgressDialog mSimUnlockProgressDialog;
+
+ KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onSimStateChanged(int subId, int slotId, int simState) {
+ if (DEBUG) Log.v(TAG, "onSimStateChanged(subId=" + subId + ",state=" + simState + ")");
+ // If the SIM is unlocked via a key sequence through the emergency dialer, it will
+ // move into the READY state and the PUK lock keyguard should be removed.
+ if (simState == TelephonyManager.SIM_STATE_READY) {
+ mRemainingAttempts = -1;
+ mShowDefaultMessage = true;
+ getKeyguardSecurityCallback().dismiss(true, KeyguardUpdateMonitor.getCurrentUser());
+ } else {
+ resetState();
+ }
+ }
+ };
+ private ImageView mSimImageView;
+ private AlertDialog mRemainingAttemptsDialog;
+
+ protected KeyguardSimPukViewController(KeyguardSimPukView view,
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ SecurityMode securityMode, LockPatternUtils lockPatternUtils,
+ KeyguardSecurityCallback keyguardSecurityCallback,
+ KeyguardMessageAreaController.Factory messageAreaControllerFactory,
+ LatencyTracker latencyTracker,
+ LiftToActivateListener liftToActivateListener,
+ TelephonyManager telephonyManager) {
+ super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
+ messageAreaControllerFactory, latencyTracker, liftToActivateListener);
+ mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+ mTelephonyManager = telephonyManager;
+ mSimImageView = mView.findViewById(R.id.keyguard_sim);
+ }
+
+ @Override
+ protected void onViewAttached() {
+ super.onViewAttached();
+ mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback);
+ }
+
+ @Override
+ protected void onViewDetached() {
+ super.onViewDetached();
+ mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback);
+ }
+
+ @Override
+ void resetState() {
+ super.resetState();
+ mStateMachine.reset();
+ }
+
+ @Override
+ protected void verifyPasswordAndUnlock() {
+ mStateMachine.next();
+ }
+
+ private class StateMachine {
+ static final int ENTER_PUK = 0;
+ static final int ENTER_PIN = 1;
+ static final int CONFIRM_PIN = 2;
+ static final int DONE = 3;
+
+ private int mState = ENTER_PUK;
+
+ public void next() {
+ int msg = 0;
+ if (mState == ENTER_PUK) {
+ if (checkPuk()) {
+ mState = ENTER_PIN;
+ msg = com.android.systemui.R.string.kg_puk_enter_pin_hint;
+ } else {
+ msg = com.android.systemui.R.string.kg_invalid_sim_puk_hint;
+ }
+ } else if (mState == ENTER_PIN) {
+ if (checkPin()) {
+ mState = CONFIRM_PIN;
+ msg = com.android.systemui.R.string.kg_enter_confirm_pin_hint;
+ } else {
+ msg = com.android.systemui.R.string.kg_invalid_sim_pin_hint;
+ }
+ } else if (mState == CONFIRM_PIN) {
+ if (confirmPin()) {
+ mState = DONE;
+ msg = com.android.systemui.R.string.keyguard_sim_unlock_progress_dialog_message;
+ updateSim();
+ } else {
+ mState = ENTER_PIN; // try again?
+ msg = com.android.systemui.R.string.kg_invalid_confirm_pin_hint;
+ }
+ }
+ mView.resetPasswordText(true /* animate */, true /* announce */);
+ if (msg != 0) {
+ mMessageAreaController.setMessage(msg);
+ }
+ }
+
+
+ void reset() {
+ mPinText = "";
+ mPukText = "";
+ mState = ENTER_PUK;
+ handleSubInfoChangeIfNeeded();
+ if (mShowDefaultMessage) {
+ showDefaultMessage();
+ }
+ boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId);
+
+ KeyguardEsimArea esimButton = mView.findViewById(R.id.keyguard_esim_area);
+ esimButton.setVisibility(isEsimLocked ? View.VISIBLE : View.GONE);
+ mPasswordEntry.requestFocus();
+ }
+ }
+
+ private void showDefaultMessage() {
+ if (mRemainingAttempts >= 0) {
+ mMessageAreaController.setMessage(mView.getPukPasswordErrorMessage(
+ mRemainingAttempts, true,
+ KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId)));
+ return;
+ }
+
+ boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId);
+ int count = 1;
+ if (mTelephonyManager != null) {
+ count = mTelephonyManager.getActiveModemCount();
+ }
+ Resources rez = mView.getResources();
+ String msg;
+ TypedArray array = mView.getContext().obtainStyledAttributes(
+ new int[] { R.attr.wallpaperTextColor });
+ int color = array.getColor(0, Color.WHITE);
+ array.recycle();
+ if (count < 2) {
+ msg = rez.getString(R.string.kg_puk_enter_puk_hint);
+ } else {
+ SubscriptionInfo info = Dependency.get(KeyguardUpdateMonitor.class)
+ .getSubscriptionInfoForSubId(mSubId);
+ CharSequence displayName = info != null ? info.getDisplayName() : "";
+ msg = rez.getString(R.string.kg_puk_enter_puk_hint_multi, displayName);
+ if (info != null) {
+ color = info.getIconTint();
+ }
+ }
+ if (isEsimLocked) {
+ msg = rez.getString(R.string.kg_sim_lock_esim_instructions, msg);
+ }
+ mMessageAreaController.setMessage(msg);
+ mSimImageView.setImageTintList(ColorStateList.valueOf(color));
+
+ // Sending empty PUK here to query the number of remaining PIN attempts
+ new CheckSimPuk("", "", mSubId) {
+ void onSimLockChangedResponse(final PinResult result) {
+ if (result == null) Log.e(TAG, "onSimCheckResponse, pin result is NULL");
+ else {
+ Log.d(TAG, "onSimCheckResponse " + " empty One result "
+ + result.toString());
+ if (result.getAttemptsRemaining() >= 0) {
+ mRemainingAttempts = result.getAttemptsRemaining();
+ mMessageAreaController.setMessage(
+ mView.getPukPasswordErrorMessage(
+ result.getAttemptsRemaining(), true,
+ KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId)));
+ }
+ }
+ }
+ }.start();
+ }
+
+ private boolean checkPuk() {
+ // make sure the puk is at least 8 digits long.
+ if (mPasswordEntry.getText().length() == 8) {
+ mPukText = mPasswordEntry.getText();
+ return true;
+ }
+ return false;
+ }
+
+ private boolean checkPin() {
+ // make sure the PIN is between 4 and 8 digits
+ int length = mPasswordEntry.getText().length();
+ if (length >= 4 && length <= 8) {
+ mPinText = mPasswordEntry.getText();
+ return true;
+ }
+ return false;
+ }
+
+ public boolean confirmPin() {
+ return mPinText.equals(mPasswordEntry.getText());
+ }
+
+
+
+
+ private void updateSim() {
+ getSimUnlockProgressDialog().show();
+
+ if (mCheckSimPukThread == null) {
+ mCheckSimPukThread = new CheckSimPuk(mPukText, mPinText, mSubId) {
+ @Override
+ void onSimLockChangedResponse(final PinResult result) {
+ mView.post(() -> {
+ if (mSimUnlockProgressDialog != null) {
+ mSimUnlockProgressDialog.hide();
+ }
+ mView.resetPasswordText(true /* animate */,
+ /* announce */
+ result.getType() != PinResult.PIN_RESULT_TYPE_SUCCESS);
+ if (result.getType() == PinResult.PIN_RESULT_TYPE_SUCCESS) {
+ mKeyguardUpdateMonitor.reportSimUnlocked(mSubId);
+ mRemainingAttempts = -1;
+ mShowDefaultMessage = true;
+
+ getKeyguardSecurityCallback().dismiss(
+ true, KeyguardUpdateMonitor.getCurrentUser());
+ } else {
+ mShowDefaultMessage = false;
+ if (result.getType() == PinResult.PIN_RESULT_TYPE_INCORRECT) {
+ // show message
+ mMessageAreaController.setMessage(mView.getPukPasswordErrorMessage(
+ result.getAttemptsRemaining(), false,
+ KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId)));
+ if (result.getAttemptsRemaining() <= 2) {
+ // this is getting critical - show dialog
+ getPukRemainingAttemptsDialog(
+ result.getAttemptsRemaining()).show();
+ } else {
+ // show message
+ mMessageAreaController.setMessage(
+ mView.getPukPasswordErrorMessage(
+ result.getAttemptsRemaining(), false,
+ KeyguardEsimArea.isEsimLocked(
+ mView.getContext(), mSubId)));
+ }
+ } else {
+ mMessageAreaController.setMessage(mView.getResources().getString(
+ R.string.kg_password_puk_failed));
+ }
+ if (DEBUG) {
+ Log.d(TAG, "verifyPasswordAndUnlock "
+ + " UpdateSim.onSimCheckResponse: "
+ + " attemptsRemaining=" + result.getAttemptsRemaining());
+ }
+ }
+ mStateMachine.reset();
+ mCheckSimPukThread = null;
+ });
+ }
+ };
+ mCheckSimPukThread.start();
+ }
+ }
+
+ @Override
+ protected boolean shouldLockout(long deadline) {
+ // SIM PUK doesn't have a timed lockout
+ return false;
+ }
+
+ private Dialog getSimUnlockProgressDialog() {
+ if (mSimUnlockProgressDialog == null) {
+ mSimUnlockProgressDialog = new ProgressDialog(mView.getContext());
+ mSimUnlockProgressDialog.setMessage(
+ mView.getResources().getString(R.string.kg_sim_unlock_progress_dialog_message));
+ mSimUnlockProgressDialog.setIndeterminate(true);
+ mSimUnlockProgressDialog.setCancelable(false);
+ if (!(mView.getContext() instanceof Activity)) {
+ mSimUnlockProgressDialog.getWindow().setType(
+ WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+ }
+ }
+ return mSimUnlockProgressDialog;
+ }
+
+ private void handleSubInfoChangeIfNeeded() {
+ int subId = mKeyguardUpdateMonitor.getNextSubIdForState(
+ TelephonyManager.SIM_STATE_PUK_REQUIRED);
+ if (subId != mSubId && SubscriptionManager.isValidSubscriptionId(subId)) {
+ mSubId = subId;
+ mShowDefaultMessage = true;
+ mRemainingAttempts = -1;
+ }
+ }
+
+
+ private Dialog getPukRemainingAttemptsDialog(int remaining) {
+ String msg = mView.getPukPasswordErrorMessage(remaining, false,
+ KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId));
+ if (mRemainingAttemptsDialog == null) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(mView.getContext());
+ builder.setMessage(msg);
+ builder.setCancelable(false);
+ builder.setNeutralButton(R.string.ok, null);
+ mRemainingAttemptsDialog = builder.create();
+ mRemainingAttemptsDialog.getWindow().setType(
+ WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+ } else {
+ mRemainingAttemptsDialog.setMessage(msg);
+ }
+ return mRemainingAttemptsDialog;
+ }
+
+ @Override
+ public void onPause() {
+ // dismiss the dialog.
+ if (mSimUnlockProgressDialog != null) {
+ mSimUnlockProgressDialog.dismiss();
+ mSimUnlockProgressDialog = null;
+ }
+ }
+
+ /**
+ * Since the IPC can block, we want to run the request in a separate thread
+ * with a callback.
+ */
+ private abstract class CheckSimPuk extends Thread {
+
+ private final String mPin, mPuk;
+ private final int mSubId;
+
+ protected CheckSimPuk(String puk, String pin, int subId) {
+ mPuk = puk;
+ mPin = pin;
+ mSubId = subId;
+ }
+
+ abstract void onSimLockChangedResponse(@NonNull PinResult result);
+
+ @Override
+ public void run() {
+ if (DEBUG) Log.v(TAG, "call supplyPukReportResult()");
+ TelephonyManager telephonyManager = mTelephonyManager.createForSubscriptionId(mSubId);
+ final PinResult result = telephonyManager.supplyPukReportPinResult(mPuk, mPin);
+ if (result == null) {
+ Log.e(TAG, "Error result for supplyPukReportResult.");
+ mView.post(() -> onSimLockChangedResponse(PinResult.getDefaultFailedResult()));
+ } else {
+ if (DEBUG) {
+ Log.v(TAG, "supplyPukReportResult returned: " + result.toString());
+ }
+ mView.post(new Runnable() {
+ @Override
+ public void run() {
+ onSimLockChangedResponse(result);
+ }
+ });
+ }
+ }
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/LiftToActivateListener.java b/packages/SystemUI/src/com/android/keyguard/LiftToActivateListener.java
index e59602b1cfff..425e50ed6397 100644
--- a/packages/SystemUI/src/com/android/keyguard/LiftToActivateListener.java
+++ b/packages/SystemUI/src/com/android/keyguard/LiftToActivateListener.java
@@ -16,11 +16,12 @@
package com.android.keyguard;
-import android.content.Context;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityManager;
+import javax.inject.Inject;
+
/**
* Hover listener that implements lift-to-activate interaction for
* accessibility. May be added to multiple views.
@@ -31,9 +32,9 @@ class LiftToActivateListener implements View.OnHoverListener {
private boolean mCachedClickableState;
- public LiftToActivateListener(Context context) {
- mAccessibilityManager = (AccessibilityManager) context.getSystemService(
- Context.ACCESSIBILITY_SERVICE);
+ @Inject
+ LiftToActivateListener(AccessibilityManager accessibilityManager) {
+ mAccessibilityManager = accessibilityManager;
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index b0457fce6a1a..2205fdd4267d 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -26,6 +26,7 @@ import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityManager;
import android.widget.TextView;
import com.android.internal.widget.LockPatternUtils;
@@ -90,7 +91,8 @@ public class NumPadKey extends ViewGroup {
}
setOnClickListener(mListener);
- setOnHoverListener(new LiftToActivateListener(context));
+ setOnHoverListener(new LiftToActivateListener(
+ (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE)));
mLockPatternUtils = new LockPatternUtils(context);
mPM = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java
index b6010c8915e7..881108858b51 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java
@@ -22,6 +22,7 @@ import android.view.ViewGroup;
import com.android.keyguard.KeyguardHostView;
import com.android.keyguard.KeyguardMessageArea;
import com.android.keyguard.KeyguardSecurityContainer;
+import com.android.keyguard.KeyguardSecurityViewFlipper;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
@@ -58,7 +59,15 @@ public interface KeyguardBouncerModule {
/** */
@Provides
@KeyguardBouncerScope
- static KeyguardSecurityContainer preovidesKeyguardSecurityContainer(KeyguardHostView hostView) {
+ static KeyguardSecurityContainer providesKeyguardSecurityContainer(KeyguardHostView hostView) {
return hostView.findViewById(R.id.keyguard_security_container);
}
+
+ /** */
+ @Provides
+ @KeyguardBouncerScope
+ static KeyguardSecurityViewFlipper providesKeyguardSecurityViewFlipper(
+ KeyguardSecurityContainer containerView) {
+ return containerView.findViewById(R.id.view_flipper);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index ed78c94d45f9..832edf719dbb 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -80,7 +80,6 @@ import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
-import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.phone.AutoHideController;
import com.android.systemui.statusbar.phone.DozeParameters;
@@ -280,7 +279,6 @@ public class Dependency {
@Inject Lazy<VisualStabilityManager> mVisualStabilityManager;
@Inject Lazy<NotificationGutsManager> mNotificationGutsManager;
@Inject Lazy<NotificationMediaManager> mNotificationMediaManager;
- @Inject Lazy<NotificationBlockingHelperManager> mNotificationBlockingHelperManager;
@Inject Lazy<NotificationRemoteInputManager> mNotificationRemoteInputManager;
@Inject Lazy<SmartReplyConstants> mSmartReplyConstants;
@Inject Lazy<NotificationListener> mNotificationListener;
@@ -473,8 +471,6 @@ public class Dependency {
mNotificationGroupAlertTransferHelper::get);
mProviders.put(NotificationMediaManager.class, mNotificationMediaManager::get);
mProviders.put(NotificationGutsManager.class, mNotificationGutsManager::get);
- mProviders.put(NotificationBlockingHelperManager.class,
- mNotificationBlockingHelperManager::get);
mProviders.put(NotificationRemoteInputManager.class,
mNotificationRemoteInputManager::get);
mProviders.put(SmartReplyConstants.class, mSmartReplyConstants::get);
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 494a0f64cea4..714095631fdb 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -48,6 +48,7 @@ import android.view.View;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.systemui.R;
import com.android.systemui.shared.system.WindowManagerWrapper;
@@ -65,7 +66,8 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
private final Point mDisplaySize = new Point();
private final int mDisplayId;
@Surface.Rotation
- private int mRotation;
+ @VisibleForTesting
+ int mRotation;
private final Rect mMagnificationFrame = new Rect();
private final SurfaceControl.Transaction mTransaction;
@@ -97,6 +99,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
private SurfaceView mMirrorSurfaceView;
private int mMirrorSurfaceMargin;
private int mBorderDragSize;
+ private int mDragViewSize;
private int mOuterBorderSize;
// The boundary of magnification frame.
private final Rect mMagnificationFrameBoundary = new Rect();
@@ -109,7 +112,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
WindowMagnificationController(Context context, @NonNull Handler handler,
SfVsyncFrameCallbackProvider sfVsyncFrameProvider,
- MirrorWindowControl mirrorWindowControl, SurfaceControl.Transaction transaction,
+ MirrorWindowControl mirrorWindowControl, SurfaceControl.Transaction transaction,
@NonNull WindowMagnifierCallback callback) {
mContext = context;
mHandler = handler;
@@ -168,6 +171,8 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
R.dimen.magnification_mirror_surface_margin);
mBorderDragSize = mResources.getDimensionPixelSize(
R.dimen.magnification_border_drag_size);
+ mDragViewSize = mResources.getDimensionPixelSize(
+ R.dimen.magnification_drag_view_size);
mOuterBorderSize = mResources.getDimensionPixelSize(
R.dimen.magnification_outer_border_margin);
}
@@ -203,13 +208,12 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
* @param configDiff a bit mask of the differences between the configurations
*/
void onConfigurationChanged(int configDiff) {
- if (!isWindowVisible()) {
- return;
- }
if ((configDiff & ActivityInfo.CONFIG_DENSITY) != 0) {
updateDimensions();
- mWm.removeView(mMirrorView);
- createMirrorWindow();
+ if (isWindowVisible()) {
+ mWm.removeView(mMirrorView);
+ createMirrorWindow();
+ }
} else if ((configDiff & ActivityInfo.CONFIG_ORIENTATION) != 0) {
onRotate();
}
@@ -217,16 +221,20 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
/** Handles MirrorWindow position when the device rotation changed. */
private void onRotate() {
- Display display = mContext.getDisplay();
+ final Display display = mContext.getDisplay();
+ final int oldRotation = mRotation;
display.getRealSize(mDisplaySize);
setMagnificationFrameBoundary();
+ mRotation = display.getRotation();
+ if (!isWindowVisible()) {
+ return;
+ }
// Keep MirrorWindow position on the screen unchanged when device rotates 90°
// clockwise or anti-clockwise.
- final int rotationDegree = getDegreeFromRotation(display.getRotation(), mRotation);
+ final int rotationDegree = getDegreeFromRotation(mRotation, oldRotation);
final Matrix matrix = new Matrix();
matrix.setRotate(rotationDegree);
- mRotation = display.getRotation();
if (rotationDegree == 90) {
matrix.postTranslate(mDisplaySize.x, 0);
} else if (rotationDegree == 270) {
@@ -307,6 +315,10 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
Region regionInsideDragBorder = new Region(mBorderDragSize, mBorderDragSize,
mMirrorView.getWidth() - mBorderDragSize,
mMirrorView.getHeight() - mBorderDragSize);
+ Rect dragArea = new Rect(mMirrorView.getWidth() - mDragViewSize - mBorderDragSize,
+ mMirrorView.getHeight() - mDragViewSize - mBorderDragSize,
+ mMirrorView.getWidth(), mMirrorView.getHeight());
+ regionInsideDragBorder.op(dragArea, Region.Op.DIFFERENCE);
return regionInsideDragBorder;
}
@@ -555,6 +567,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
/**
* Gets the scale.
+ *
* @return {@link Float#NaN} if the window is invisible.
*/
float getScale() {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 06c190f1964c..ba78485438ea 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -16,17 +16,16 @@
package com.android.systemui.biometrics;
-import android.annotation.NonNull;
+import static com.android.internal.util.Preconditions.checkNotNull;
+
import android.annotation.SuppressLint;
-import android.content.ContentResolver;
import android.content.Context;
+import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.IUdfpsOverlayController;
-import android.os.Handler;
-import android.os.Looper;
import android.os.PowerManager;
import android.os.UserHandle;
import android.provider.Settings;
@@ -38,10 +37,16 @@ import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.WindowManager;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import com.android.internal.BrightnessSynchronizer;
import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.DozeReceiver;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.android.systemui.util.settings.SystemSettings;
import java.io.FileWriter;
import java.io.IOException;
@@ -60,8 +65,8 @@ class UdfpsController implements DozeReceiver {
private final FingerprintManager mFingerprintManager;
private final WindowManager mWindowManager;
- private final ContentResolver mContentResolver;
- private final Handler mHandler;
+ private final SystemSettings mSystemSettings;
+ private final DelayableExecutor mFgExecutor;
private final WindowManager.LayoutParams mLayoutParams;
private final UdfpsView mView;
// Debugfs path to control the high-brightness mode.
@@ -88,7 +93,7 @@ class UdfpsController implements DozeReceiver {
// interrupt is being tracked and a timeout is used as a last resort to turn off high brightness
// mode.
private boolean mIsAodInterruptActive;
- private final Runnable mAodInterruptTimeoutAction = this::onCancelAodInterrupt;
+ @Nullable private Runnable mCancelAodTimeoutAction;
public class UdfpsOverlayController extends IUdfpsOverlayController.Stub {
@Override
@@ -138,18 +143,27 @@ class UdfpsController implements DozeReceiver {
@Inject
UdfpsController(@NonNull Context context,
- @NonNull StatusBarStateController statusBarStateController) {
- mFingerprintManager = context.getSystemService(FingerprintManager.class);
- mWindowManager = context.getSystemService(WindowManager.class);
- mContentResolver = context.getContentResolver();
- mHandler = new Handler(Looper.getMainLooper());
+ @Main Resources resources,
+ LayoutInflater inflater,
+ @Nullable FingerprintManager fingerprintManager,
+ PowerManager powerManager,
+ WindowManager windowManager,
+ SystemSettings systemSettings,
+ @NonNull StatusBarStateController statusBarStateController,
+ @Main DelayableExecutor fgExecutor) {
+ // The fingerprint manager is queried for UDFPS before this class is constructed, so the
+ // fingerprint manager should never be null.
+ mFingerprintManager = checkNotNull(fingerprintManager);
+ mWindowManager = windowManager;
+ mSystemSettings = systemSettings;
+ mFgExecutor = fgExecutor;
mLayoutParams = createLayoutParams(context);
- mView = (UdfpsView) LayoutInflater.from(context).inflate(R.layout.udfps_view, null, false);
+ mView = (UdfpsView) inflater.inflate(R.layout.udfps_view, null, false);
- mHbmPath = context.getResources().getString(R.string.udfps_hbm_sysfs_path);
- mHbmEnableCommand = context.getResources().getString(R.string.udfps_hbm_enable_command);
- mHbmDisableCommand = context.getResources().getString(R.string.udfps_hbm_disable_command);
+ mHbmPath = resources.getString(R.string.udfps_hbm_sysfs_path);
+ mHbmEnableCommand = resources.getString(R.string.udfps_hbm_enable_command);
+ mHbmDisableCommand = resources.getString(R.string.udfps_hbm_disable_command);
mHbmSupported = !TextUtils.isEmpty(mHbmPath);
mView.setHbmSupported(mHbmSupported);
@@ -157,11 +171,11 @@ class UdfpsController implements DozeReceiver {
// This range only consists of the minimum and maximum values, which only cover
// non-high-brightness mode.
- float[] nitsRange = toFloatArray(context.getResources().obtainTypedArray(
+ float[] nitsRange = toFloatArray(resources.obtainTypedArray(
com.android.internal.R.array.config_screenBrightnessNits));
// The last value of this range corresponds to the high-brightness mode.
- float[] nitsAutoBrightnessValues = toFloatArray(context.getResources().obtainTypedArray(
+ float[] nitsAutoBrightnessValues = toFloatArray(resources.obtainTypedArray(
com.android.internal.R.array.config_autoBrightnessDisplayValuesNits));
mHbmNits = nitsAutoBrightnessValues[nitsAutoBrightnessValues.length - 1];
@@ -170,12 +184,12 @@ class UdfpsController implements DozeReceiver {
// This range only consists of the minimum and maximum backlight values, which only apply
// in non-high-brightness mode.
float[] normalizedBacklightRange = normalizeBacklightRange(
- context.getResources().getIntArray(
+ resources.getIntArray(
com.android.internal.R.array.config_screenBrightnessBacklight));
mBacklightToNitsSpline = Spline.createSpline(normalizedBacklightRange, nitsRange);
mNitsToHbmBacklightSpline = Spline.createSpline(hbmNitsRange, normalizedBacklightRange);
- mDefaultBrightness = obtainDefaultBrightness(context);
+ mDefaultBrightness = obtainDefaultBrightness(powerManager);
// TODO(b/160025856): move to the "dump" method.
Log.v(TAG, String.format("ctor | mNitsRange: [%f, %f]", nitsRange[0], nitsRange[1]));
@@ -194,7 +208,7 @@ class UdfpsController implements DozeReceiver {
}
private void showUdfpsOverlay() {
- mHandler.post(() -> {
+ mFgExecutor.execute(() -> {
if (!mIsOverlayShowing) {
try {
Log.v(TAG, "showUdfpsOverlay | adding window");
@@ -211,7 +225,7 @@ class UdfpsController implements DozeReceiver {
}
private void hideUdfpsOverlay() {
- mHandler.post(() -> {
+ mFgExecutor.execute(() -> {
if (mIsOverlayShowing) {
Log.v(TAG, "hideUdfpsOverlay | removing window");
mView.setOnTouchListener(null);
@@ -228,7 +242,7 @@ class UdfpsController implements DozeReceiver {
// Returns a value in the range of [0, 255].
private int computeScrimOpacity() {
// Backlight setting can be NaN, -1.0f, and [0.0f, 1.0f].
- float backlightSetting = Settings.System.getFloatForUser(mContentResolver,
+ float backlightSetting = mSystemSettings.getFloatForUser(
Settings.System.SCREEN_BRIGHTNESS_FLOAT, mDefaultBrightness,
UserHandle.USER_CURRENT);
@@ -265,7 +279,8 @@ class UdfpsController implements DozeReceiver {
// Since the sensor that triggers the AOD interrupt doesn't provide ACTION_UP/ACTION_CANCEL,
// we need to be careful about not letting the screen accidentally remain in high brightness
// mode. As a mitigation, queue a call to cancel the fingerprint scan.
- mHandler.postDelayed(mAodInterruptTimeoutAction, AOD_INTERRUPT_TIMEOUT_MILLIS);
+ mCancelAodTimeoutAction = mFgExecutor.executeDelayed(this::onCancelAodInterrupt,
+ AOD_INTERRUPT_TIMEOUT_MILLIS);
// using a hard-coded value for major and minor until it is available from the sensor
onFingerDown(screenX, screenY, 13.0f, 13.0f);
}
@@ -280,7 +295,10 @@ class UdfpsController implements DozeReceiver {
if (!mIsAodInterruptActive) {
return;
}
- mHandler.removeCallbacks(mAodInterruptTimeoutAction);
+ if (mCancelAodTimeoutAction != null) {
+ mCancelAodTimeoutAction.run();
+ mCancelAodTimeoutAction = null;
+ }
mIsAodInterruptActive = false;
onFingerUp();
}
@@ -338,8 +356,7 @@ class UdfpsController implements DozeReceiver {
return lp;
}
- private static float obtainDefaultBrightness(Context context) {
- PowerManager powerManager = context.getSystemService(PowerManager.class);
+ private static float obtainDefaultBrightness(PowerManager powerManager) {
if (powerManager == null) {
Log.e(TAG, "PowerManager is unavailable. Can't obtain default brightness.");
return 0f;
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 38e12a6ed5f8..eb431274b8a3 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -288,6 +288,7 @@ public class DependencyProvider {
/** */
@Provides
+ @SysUISingleton
public LockPatternUtils provideLockPatternUtils(Context context) {
return new LockPatternUtils(context);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index b35579d3624b..79925bad3cc7 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -62,6 +62,7 @@ import android.view.ViewConfiguration;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
+import android.view.inputmethod.InputMethodManager;
import com.android.internal.app.IBatteryStats;
import com.android.internal.statusbar.IStatusBarService;
@@ -183,6 +184,12 @@ public class FrameworkServicesModule {
@Provides
@Singleton
+ static InputMethodManager provideInputMethodManager(Context context) {
+ return context.getSystemService(InputMethodManager.class);
+ }
+
+ @Provides
+ @Singleton
static IPackageManager provideIPackageManager() {
return IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index 1ef806c8bd68..d5820f3e05e4 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -432,8 +432,12 @@ public class DozeMachine {
/** Give the Part a chance to clean itself up. */
default void destroy() {}
- /** Alerts that the screenstate is being changed. */
- default void onScreenState(int state) {}
+ /**
+ * Alerts that the screenstate is being changed.
+ * Note: This may be called from within a call to transitionTo, so local DozeState may not
+ * be accurate nor match with the new displayState.
+ */
+ default void onScreenState(int displayState) {}
/** Sets the {@link DozeMachine} when this Part is associated with one. */
default void setDozeMachine(DozeMachine dozeMachine) {}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index b872b1a4219a..5aeb8df2028d 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -73,7 +73,6 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi
* --ei brightness_bucket 1}
*/
private int mDebugBrightnessBucket = -1;
- private DozeMachine.State mState;
@Inject
public DozeScreenBrightness(Context context, @WrappedService DozeMachine.Service service,
@@ -94,7 +93,6 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi
@Override
public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
- mState = newState;
switch (newState) {
case INITIALIZED:
case DOZE:
@@ -112,10 +110,7 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi
@Override
public void onScreenState(int state) {
- if (!mScreenOff
- && (mState == DozeMachine.State.DOZE_AOD
- || mState == DozeMachine.State.DOZE_AOD_DOCKED)
- && (state == Display.STATE_DOZE || state == Display.STATE_DOZE_SUSPEND)) {
+ if (state == Display.STATE_DOZE || state == Display.STATE_DOZE_SUSPEND) {
setLightSensorEnabled(true);
} else {
setLightSensorEnabled(false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index 23270630c7da..01333f0a47d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -23,7 +23,6 @@ import android.content.pm.ShortcutManager;
import android.os.Handler;
import android.view.accessibility.AccessibilityManager;
-import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.R;
@@ -68,7 +67,6 @@ import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.logging.NotificationPanelLogger;
import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerImpl;
import com.android.systemui.statusbar.notification.row.ChannelEditorDialogController;
-import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback;
import com.android.systemui.statusbar.notification.row.PriorityOnboardingDialogController;
@@ -198,20 +196,6 @@ public interface NotificationsModule {
return new NotificationPanelLoggerImpl();
}
- /** Provides an instance of {@link NotificationBlockingHelperManager} */
- @SysUISingleton
- @Provides
- static NotificationBlockingHelperManager provideNotificationBlockingHelperManager(
- Context context,
- NotificationGutsManager notificationGutsManager,
- NotificationEntryManager notificationEntryManager,
- MetricsLogger metricsLogger,
- GroupMembershipManager groupMembershipManager) {
- return new NotificationBlockingHelperManager(
- context, notificationGutsManager, notificationEntryManager, metricsLogger,
- groupMembershipManager);
- }
-
/** Provides an instance of {@link GroupMembershipManager} */
@SysUISingleton
@Provides
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index adda049951ac..811a72de093c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -500,10 +500,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
* or is in a whitelist).
*/
public boolean getIsNonblockable() {
- boolean isNonblockable = Dependency.get(NotificationBlockingHelperManager.class)
- .isNonblockable(mEntry.getSbn().getPackageName(),
- mEntry.getChannel().getId());
-
// If the SystemNotifAsyncTask hasn't finished running or retrieved a value, we'll try once
// again, but in-place on the main thread this time. This should rarely ever get called.
if (mEntry != null && mEntry.mIsSystemNotification == null) {
@@ -514,13 +510,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mEntry.mIsSystemNotification = isSystemNotification(mContext, mEntry.getSbn());
}
- isNonblockable |= mEntry.getChannel().isImportanceLockedByOEM();
- isNonblockable |= mEntry.getChannel().isImportanceLockedByCriticalDeviceFunction();
+ boolean isNonblockable = mEntry.getChannel().isImportanceLockedByOEM()
+ || mEntry.getChannel().isImportanceLockedByCriticalDeviceFunction();
if (!isNonblockable && mEntry != null && mEntry.mIsSystemNotification != null) {
if (mEntry.mIsSystemNotification) {
- if (mEntry.getChannel() != null
- && !mEntry.getChannel().isBlockable()) {
+ if (mEntry.getChannel() != null && !mEntry.getChannel().isBlockable()) {
isNonblockable = true;
}
}
@@ -1398,26 +1393,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
/**
- * Dismisses the notification with the option of showing the blocking helper in-place if we have
- * a negative user sentiment.
+ * Dismisses the notification.
*
* @param fromAccessibility whether this dismiss is coming from an accessibility action
- * @return whether a blocking helper is shown in this row
*/
- public boolean performDismissWithBlockingHelper(boolean fromAccessibility) {
- NotificationBlockingHelperManager manager =
- Dependency.get(NotificationBlockingHelperManager.class);
- boolean isBlockingHelperShown = manager.perhapsShowBlockingHelper(this, mMenuRow);
-
- Dependency.get(MetricsLogger.class).count(NotificationCounters.NOTIFICATION_DISMISSED, 1);
-
- // Continue with dismiss since we don't want the blocking helper to be directly associated
- // with a certain notification.
- performDismiss(fromAccessibility);
- return isBlockingHelperShown;
- }
-
public void performDismiss(boolean fromAccessibility) {
+ Dependency.get(MetricsLogger.class).count(NotificationCounters.NOTIFICATION_DISMISSED, 1);
dismiss(fromAccessibility);
if (mEntry.isClearable()) {
if (mOnUserInteractionCallback != null) {
@@ -2983,7 +2964,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
switch (action) {
case AccessibilityNodeInfo.ACTION_DISMISS:
- performDismissWithBlockingHelper(true /* fromAccessibility */);
+ performDismiss(true /* fromAccessibility */);
return true;
case AccessibilityNodeInfo.ACTION_COLLAPSE:
case AccessibilityNodeInfo.ACTION_EXPAND:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
index eeac46a60ac8..7071b73c2ebf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
@@ -295,10 +295,6 @@ public class NotificationGuts extends FrameLayout {
*/
private void closeControls(int x, int y, boolean save, boolean force) {
// First try to dismiss any blocking helper.
- boolean wasBlockingHelperDismissed =
- Dependency.get(NotificationBlockingHelperManager.class)
- .dismissCurrentBlockingHelper();
-
if (getWindowToken() == null) {
if (mClosedListener != null) {
mClosedListener.onGutsClosed(this);
@@ -307,10 +303,9 @@ public class NotificationGuts extends FrameLayout {
}
if (mGutsContent == null
- || !mGutsContent.handleCloseControls(save, force)
- || wasBlockingHelperDismissed) {
+ || !mGutsContent.handleCloseControls(save, force)) {
// We only want to do a circular reveal if we're not showing the blocking helper.
- animateClose(x, y, !wasBlockingHelperDismissed /* shouldDoCircularReveal */);
+ animateClose(x, y, true /* shouldDoCircularReveal */);
setExposed(false, mNeedsFalsingProtection);
if (mClosedListener != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index ab241e6721ee..703c214ed3ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -96,7 +96,6 @@ import com.android.systemui.statusbar.notification.row.ActivatableNotificationVi
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.row.ForegroundServiceDungeonView;
-import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
import com.android.systemui.statusbar.notification.row.NotificationGuts;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.NotificationSnooze;
@@ -156,7 +155,6 @@ public class NotificationStackScrollLayoutController {
private final LayoutInflater mLayoutInflater;
private final NotificationRemoteInputManager mRemoteInputManager;
private final VisualStabilityManager mVisualStabilityManager;
- private final NotificationBlockingHelperManager mNotificationBlockingHelperManager;
private final ShadeController mShadeController;
private final KeyguardMediaController mKeyguardMediaController;
private final SysuiStatusBarStateController mStatusBarStateController;
@@ -394,8 +392,6 @@ public class NotificationStackScrollLayoutController {
return;
}
- boolean isBlockingHelperShown = false;
-
mView.removeDraggedView(view);
mView.updateContinuousShadowDrawing();
@@ -405,13 +401,10 @@ public class NotificationStackScrollLayoutController {
mHeadsUpManager.addSwipedOutNotification(
row.getEntry().getSbn().getKey());
}
- isBlockingHelperShown =
- row.performDismissWithBlockingHelper(false /* fromAccessibility */);
+ row.performDismiss(false /* fromAccessibility */);
}
- if (!isBlockingHelperShown) {
- mView.addSwipedOutView(view);
- }
+ mView.addSwipedOutView(view);
mFalsingManager.onNotificationDismissed();
if (mFalsingManager.shouldEnforceBouncer()) {
mStatusBar.executeRunnableDismissingKeyguard(
@@ -582,7 +575,6 @@ public class NotificationStackScrollLayoutController {
LayoutInflater layoutInflater,
NotificationRemoteInputManager remoteInputManager,
VisualStabilityManager visualStabilityManager,
- NotificationBlockingHelperManager notificationBlockingHelperManager,
ShadeController shadeController) {
mAllowLongPress = allowLongPress;
mNotificationGutsManager = notificationGutsManager;
@@ -628,7 +620,6 @@ public class NotificationStackScrollLayoutController {
mLayoutInflater = layoutInflater;
mRemoteInputManager = remoteInputManager;
mVisualStabilityManager = visualStabilityManager;
- mNotificationBlockingHelperManager = notificationBlockingHelperManager;
mShadeController = shadeController;
}
@@ -691,10 +682,6 @@ public class NotificationStackScrollLayoutController {
mView.addOnExpandedHeightChangedListener(mNotificationRoundnessManager::setExpanded);
mVisualStabilityManager.setVisibilityLocationProvider(this::isInVisibleLocation);
- // Blocking helper manager wants to know the expanded state, update as well.
- mView.addOnExpandedHeightChangedListener((height, unused) ->
- mNotificationBlockingHelperManager.setNotificationShadeExpanded(height)
- );
mTunerService.addTunable(
(key, newValue) -> {
diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
index eb8f065149c8..a6cd350b33ce 100644
--- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
@@ -23,7 +23,6 @@ import android.view.InflateException;
import android.view.LayoutInflater;
import android.view.View;
-import com.android.keyguard.KeyguardMessageArea;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.qs.QSFooterImpl;
import com.android.systemui.qs.QSPanel;
@@ -108,11 +107,6 @@ public class InjectionInflationController {
NotificationStackScrollLayout createNotificationStackScrollLayout();
/**
- * Creates the KeyguardMessageArea.
- */
- KeyguardMessageArea createKeyguardMessageArea();
-
- /**
* Creates the QSPanel.
*/
QSPanel createQSPanel();
diff --git a/packages/SystemUI/src/com/android/systemui/util/ViewController.java b/packages/SystemUI/src/com/android/systemui/util/ViewController.java
index 64f8dbbb9e34..c7aa780fcacb 100644
--- a/packages/SystemUI/src/com/android/systemui/util/ViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/ViewController.java
@@ -23,7 +23,20 @@ import android.view.View.OnAttachStateChangeListener;
* Utility class that handles view lifecycle events for View Controllers.
*
* Implementations should handle setup and teardown related activities inside of
- * {@link #onViewAttached()} and {@link #onViewDetached()}.
+ * {@link #onViewAttached()} and {@link #onViewDetached()}. Be sure to call {@link #init()} on
+ * any child controllers that this uses. This can be done in {@link init()} if the controllers
+ * are injected, or right after creation time of the child controller.
+ *
+ * Tip: View "attachment" happens top down - parents are notified that they are attached before
+ * any children. That means that if you call a method on a child controller in
+ * {@link #onViewAttached()}, the child controller may not have had its onViewAttach method
+ * called, so it may not be fully set up.
+ *
+ * As such, make sure that methods on your controller are safe to call _before_ its {@link #init()}
+ * and {@link #onViewAttached()} methods are called. Specifically, if your controller must call
+ * {@link View#findViewById(int)} on its root view to setup member variables, do so in its
+ * constructor. Save {@link #onViewAttached()} for things that can happen post-construction - adding
+ * listeners, dynamically changing content, or other runtime decisions.
*
* @param <T> View class that this ViewController is for.
*/
@@ -54,10 +67,12 @@ public abstract class ViewController<T extends View> {
}
mInited = true;
- if (mView.isAttachedToWindow()) {
- mOnAttachStateListener.onViewAttachedToWindow(mView);
+ if (mView != null) {
+ if (mView.isAttachedToWindow()) {
+ mOnAttachStateListener.onViewAttachedToWindow(mView);
+ }
+ mView.addOnAttachStateChangeListener(mOnAttachStateListener);
}
- mView.addOnAttachStateChangeListener(mOnAttachStateListener);
}
/**
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java
index 9be2d124026c..dffad6ccbea5 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java
@@ -41,8 +41,6 @@ import android.testing.TestableLooper.RunWithLooper;
import android.testing.ViewUtils;
import android.view.SurfaceControlViewHost;
import android.view.SurfaceView;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
import androidx.test.filters.SmallTest;
@@ -67,7 +65,7 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
private ComponentName mComponentName;
private Intent mServiceIntent;
private TestableLooper mTestableLooper;
- private ViewGroup mParent;
+ private KeyguardSecurityContainer mKeyguardSecurityContainer;
@Mock
private Handler mHandler;
@@ -84,8 +82,8 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
public void setUp() {
MockitoAnnotations.initMocks(this);
- mParent = spy(new FrameLayout(mContext));
- ViewUtils.attachView(mParent);
+ mKeyguardSecurityContainer = spy(new KeyguardSecurityContainer(mContext));
+ ViewUtils.attachView(mKeyguardSecurityContainer);
mTestableLooper = TestableLooper.get(this);
mComponentName = new ComponentName(mContext, "FakeKeyguardClient.class");
@@ -96,13 +94,14 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
when(mKeyguardClient.queryLocalInterface(anyString())).thenReturn(mKeyguardClient);
when(mKeyguardClient.asBinder()).thenReturn(mKeyguardClient);
- mTestController = new AdminSecondaryLockScreenController(
- mContext, mParent, mUpdateMonitor, mKeyguardCallback, mHandler);
+ mTestController = new AdminSecondaryLockScreenController.Factory(
+ mContext, mKeyguardSecurityContainer, mUpdateMonitor, mHandler)
+ .create(mKeyguardCallback);
}
@After
public void tearDown() {
- ViewUtils.detachView(mParent);
+ ViewUtils.detachView(mKeyguardSecurityContainer);
}
@Test
@@ -146,7 +145,7 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
SurfaceView v = verifySurfaceReady();
mTestController.hide();
- verify(mParent).removeView(v);
+ verify(mKeyguardSecurityContainer).removeView(v);
assertThat(mContext.isBound(mComponentName)).isFalse();
}
@@ -154,7 +153,7 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
public void testHide_notShown() throws Exception {
mTestController.hide();
// Nothing should happen if trying to hide when the view isn't attached yet.
- verify(mParent, never()).removeView(any(SurfaceView.class));
+ verify(mKeyguardSecurityContainer, never()).removeView(any(SurfaceView.class));
}
@Test
@@ -182,7 +181,7 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
private SurfaceView verifySurfaceReady() throws Exception {
mTestableLooper.processAllMessages();
ArgumentCaptor<SurfaceView> captor = ArgumentCaptor.forClass(SurfaceView.class);
- verify(mParent).addView(captor.capture());
+ verify(mKeyguardSecurityContainer).addView(captor.capture());
mTestableLooper.processAllMessages();
verify(mKeyguardClient).onCreateKeyguardSurface(any(), any(IKeyguardCallback.class));
@@ -190,7 +189,7 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
}
private void verifyViewDismissed(SurfaceView v) throws Exception {
- verify(mParent).removeView(v);
+ verify(mKeyguardSecurityContainer).removeView(v);
verify(mKeyguardCallback).dismiss(true, TARGET_USER_ID, true);
assertThat(mContext.isBound(mComponentName)).isFalse();
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
new file mode 100644
index 000000000000..c2ade81a9877
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.KeyEvent;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.util.LatencyTracker;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardAbsKeyInputView.KeyDownListener;
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public class KeyguardAbsKeyInputViewControllerTest extends SysuiTestCase {
+
+ @Mock
+ private KeyguardAbsKeyInputView mAbsKeyInputView;
+ @Mock
+ private PasswordTextView mPasswordEntry;
+ @Mock
+ private KeyguardMessageArea mKeyguardMessageArea;
+ @Mock
+ private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock
+ private SecurityMode mSecurityMode;
+ @Mock
+ private LockPatternUtils mLockPatternUtils;
+ @Mock
+ private KeyguardSecurityCallback mKeyguardSecurityCallback;
+ @Mock
+ private KeyguardMessageAreaController.Factory mKeyguardMessageAreaControllerFactory;
+ @Mock
+ private KeyguardMessageAreaController mKeyguardMessageAreaController;
+ @Mock
+ private LatencyTracker mLatencyTracker;
+
+ private KeyguardAbsKeyInputViewController mKeyguardAbsKeyInputViewController;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ when(mKeyguardMessageAreaControllerFactory.create(any(KeyguardMessageArea.class)))
+ .thenReturn(mKeyguardMessageAreaController);
+ when(mAbsKeyInputView.getPasswordTextViewId()).thenReturn(1);
+ when(mAbsKeyInputView.findViewById(1)).thenReturn(mPasswordEntry);
+ when(mAbsKeyInputView.isAttachedToWindow()).thenReturn(true);
+ when(mAbsKeyInputView.findViewById(R.id.keyguard_message_area))
+ .thenReturn(mKeyguardMessageArea);
+ mKeyguardAbsKeyInputViewController = new KeyguardAbsKeyInputViewController(mAbsKeyInputView,
+ mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback,
+ mKeyguardMessageAreaControllerFactory, mLatencyTracker) {
+ @Override
+ void resetState() {
+ }
+
+ @Override
+ public void onResume(int reason) {
+ super.onResume(reason);
+ }
+ };
+ mKeyguardAbsKeyInputViewController.init();
+ reset(mKeyguardMessageAreaController); // Clear out implicit call to init.
+ }
+
+ @Test
+ public void onKeyDown_clearsSecurityMessage() {
+ ArgumentCaptor<KeyDownListener> onKeyDownListenerArgumentCaptor =
+ ArgumentCaptor.forClass(KeyDownListener.class);
+ verify(mAbsKeyInputView).setKeyDownListener(onKeyDownListenerArgumentCaptor.capture());
+ onKeyDownListenerArgumentCaptor.getValue().onKeyDown(
+ KeyEvent.KEYCODE_0, mock(KeyEvent.class));
+ verify(mKeyguardSecurityCallback).userActivity();
+ verify(mKeyguardMessageAreaController).setMessage(eq(""));
+ }
+
+ @Test
+ public void onKeyDown_noSecurityMessageInteraction() {
+ ArgumentCaptor<KeyDownListener> onKeyDownListenerArgumentCaptor =
+ ArgumentCaptor.forClass(KeyDownListener.class);
+ verify(mAbsKeyInputView).setKeyDownListener(onKeyDownListenerArgumentCaptor.capture());
+ onKeyDownListenerArgumentCaptor.getValue().onKeyDown(
+ KeyEvent.KEYCODE_UNKNOWN, mock(KeyEvent.class));
+ verifyZeroInteractions(mKeyguardSecurityCallback);
+ verifyZeroInteractions(mKeyguardMessageAreaController);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
index 5999e2cdec78..e7930795c7f8 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
@@ -41,11 +41,9 @@ import android.widget.FrameLayout;
import android.widget.TextClock;
import com.android.systemui.R;
-import com.android.systemui.SystemUIFactory;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.ClockPlugin;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.util.InjectionInflationController;
import org.junit.Before;
import org.junit.Test;
@@ -78,12 +76,7 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
when(mMockKeyguardSliceView.findViewById(R.id.keyguard_status_area))
.thenReturn(mMockKeyguardSliceView);
- InjectionInflationController inflationController = new InjectionInflationController(
- SystemUIFactory.getInstance()
- .getSysUIComponent()
- .createViewInstanceCreatorFactory());
- LayoutInflater layoutInflater = inflationController
- .injectable(LayoutInflater.from(getContext()));
+ LayoutInflater layoutInflater = LayoutInflater.from(getContext());
layoutInflater.setPrivateFactory(new LayoutInflater.Factory2() {
@Override
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
new file mode 100644
index 000000000000..a7197cca530c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class KeyguardMessageAreaControllerTest extends SysuiTestCase {
+ @Mock
+ private ConfigurationController mConfigurationController;
+ @Mock
+ private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock
+ private KeyguardMessageArea mKeyguardMessageArea;
+
+ private KeyguardMessageAreaController mMessageAreaController;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mMessageAreaController = new KeyguardMessageAreaController.Factory(
+ mKeyguardUpdateMonitor, mConfigurationController).create(mKeyguardMessageArea);
+ }
+
+ @Test
+ public void onAttachedToWindow_registersConfigurationCallback() {
+ ArgumentCaptor<ConfigurationListener> configurationListenerArgumentCaptor =
+ ArgumentCaptor.forClass(ConfigurationListener.class);
+
+ mMessageAreaController.onViewAttached();
+ verify(mConfigurationController).addCallback(configurationListenerArgumentCaptor.capture());
+
+ mMessageAreaController.onViewDetached();
+ verify(mConfigurationController).removeCallback(
+ eq(configurationListenerArgumentCaptor.getValue()));
+ }
+
+ @Test
+ public void onAttachedToWindow_registersKeyguardUpdateMontiorCallback() {
+ ArgumentCaptor<KeyguardUpdateMonitorCallback> keyguardUpdateMonitorCallbackArgumentCaptor =
+ ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class);
+
+ mMessageAreaController.onViewAttached();
+ verify(mKeyguardUpdateMonitor).registerCallback(
+ keyguardUpdateMonitorCallbackArgumentCaptor.capture());
+
+ mMessageAreaController.onViewDetached();
+ verify(mKeyguardUpdateMonitor).removeCallback(
+ eq(keyguardUpdateMonitorCallbackArgumentCaptor.getValue()));
+ }
+
+ @Test
+ public void testClearsTextField() {
+ mMessageAreaController.setMessage("");
+ verify(mKeyguardMessageArea).setMessage("");
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java
index fc7b9a4b47d1..31fb25a7a89c 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -11,65 +11,60 @@
* 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
+ * limitations under the License.
*/
package com.android.keyguard;
-import static junit.framework.Assert.assertEquals;
-
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.verify;
+import static com.google.common.truth.Truth.assertThat;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
+import android.view.View;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.policy.ConfigurationController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
public class KeyguardMessageAreaTest extends SysuiTestCase {
- @Mock
- private ConfigurationController mConfigurationController;
- @Mock
- private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private KeyguardMessageArea mMessageArea;
+ private KeyguardMessageArea mKeyguardMessageArea;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mMessageArea = new KeyguardMessageArea(mContext, null, mKeyguardUpdateMonitor,
- mConfigurationController);
- waitForIdleSync();
+ mKeyguardMessageArea = new KeyguardMessageArea(mContext, null);
+ mKeyguardMessageArea.setBouncerVisible(true);
}
@Test
- public void onAttachedToWindow_registersConfigurationCallback() {
- mMessageArea.onAttachedToWindow();
- verify(mConfigurationController).addCallback(eq(mMessageArea));
-
- mMessageArea.onDetachedFromWindow();
- verify(mConfigurationController).removeCallback(eq(mMessageArea));
+ public void testShowsTextField() {
+ mKeyguardMessageArea.setVisibility(View.INVISIBLE);
+ mKeyguardMessageArea.setMessage("oobleck");
+ assertThat(mKeyguardMessageArea.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mKeyguardMessageArea.getText()).isEqualTo("oobleck");
}
@Test
- public void clearFollowedByMessage_keepsMessage() {
- mMessageArea.setMessage("");
- mMessageArea.setMessage("test");
-
- CharSequence[] messageText = new CharSequence[1];
- messageText[0] = mMessageArea.getText();
-
- assertEquals("test", messageText[0]);
+ public void testHiddenWhenBouncerHidden() {
+ mKeyguardMessageArea.setBouncerVisible(false);
+ mKeyguardMessageArea.setVisibility(View.INVISIBLE);
+ mKeyguardMessageArea.setMessage("oobleck");
+ assertThat(mKeyguardMessageArea.getVisibility()).isEqualTo(View.INVISIBLE);
+ assertThat(mKeyguardMessageArea.getText()).isEqualTo("oobleck");
}
+ @Test
+ public void testClearsTextField() {
+ mKeyguardMessageArea.setVisibility(View.VISIBLE);
+ mKeyguardMessageArea.setMessage("");
+ assertThat(mKeyguardMessageArea.getVisibility()).isEqualTo(View.INVISIBLE);
+ assertThat(mKeyguardMessageArea.getText()).isEqualTo("");
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
new file mode 100644
index 000000000000..c69ec1a254c3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.internal.util.LatencyTracker
+import com.android.internal.widget.LockPatternUtils
+import com.android.internal.widget.LockPatternView
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class KeyguardPatternViewControllerTest : SysuiTestCase() {
+ @Mock
+ private lateinit var mKeyguardPatternView: KeyguardPatternView
+ @Mock
+ private lateinit var mKeyguardUpdateMonitor: KeyguardUpdateMonitor
+ @Mock
+ private lateinit var mSecurityMode: KeyguardSecurityModel.SecurityMode
+ @Mock
+ private lateinit var mLockPatternUtils: LockPatternUtils
+ @Mock
+ private lateinit var mKeyguardSecurityCallback: KeyguardSecurityCallback
+ @Mock
+ private lateinit var mLatencyTracker: LatencyTracker
+ @Mock
+ private lateinit
+ var mKeyguardMessageAreaControllerFactory: KeyguardMessageAreaController.Factory
+ @Mock
+ private lateinit var mKeyguardMessageArea: KeyguardMessageArea
+ @Mock
+ private lateinit var mKeyguardMessageAreaController: KeyguardMessageAreaController
+ @Mock
+ private lateinit var mLockPatternView: LockPatternView
+
+ private lateinit var mKeyguardPatternViewController: KeyguardPatternViewController
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ `when`(mKeyguardPatternView.isAttachedToWindow).thenReturn(true)
+ `when`(mKeyguardPatternView.findViewById<KeyguardMessageArea>(R.id.keyguard_message_area))
+ .thenReturn(mKeyguardMessageArea)
+ `when`(mKeyguardPatternView.findViewById<LockPatternView>(R.id.lockPatternView))
+ .thenReturn(mLockPatternView)
+ `when`(mKeyguardMessageAreaControllerFactory.create(mKeyguardMessageArea))
+ .thenReturn(mKeyguardMessageAreaController)
+ mKeyguardPatternViewController = KeyguardPatternViewController(mKeyguardPatternView,
+ mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback,
+ mLatencyTracker, mKeyguardMessageAreaControllerFactory)
+ }
+
+ @Test
+ fun onPause_clearsTextField() {
+ mKeyguardPatternViewController.init()
+ mKeyguardPatternViewController.onPause()
+ verify(mKeyguardMessageAreaController).setMessage("")
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewTest.kt
deleted file mode 100644
index b4363cf215f1..000000000000
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewTest.kt
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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 com.android.keyguard
-
-import androidx.test.filters.SmallTest
-import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
-import android.view.LayoutInflater
-
-import com.android.systemui.R
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.statusbar.policy.ConfigurationController
-import com.google.common.truth.Truth.assertThat
-
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mockito.mock
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-@TestableLooper.RunWithLooper
-class KeyguardPatternViewTest : SysuiTestCase() {
-
- private lateinit var mKeyguardPatternView: KeyguardPatternView
- private lateinit var mSecurityMessage: KeyguardMessageArea
-
- @Before
- fun setup() {
- val inflater = LayoutInflater.from(context)
- mDependency.injectMockDependency(KeyguardUpdateMonitor::class.java)
- mKeyguardPatternView = inflater.inflate(R.layout.keyguard_pattern_view, null)
- as KeyguardPatternView
- mSecurityMessage = KeyguardMessageArea(mContext, null,
- mock(KeyguardUpdateMonitor::class.java), mock(ConfigurationController::class.java))
- mKeyguardPatternView.mSecurityMessageDisplay = mSecurityMessage
- }
-
- @Test
- fun onPause_clearsTextField() {
- mSecurityMessage.setMessage("an old message")
- mKeyguardPatternView.onPause()
- assertThat(mSecurityMessage.text).isEqualTo("")
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
new file mode 100644
index 000000000000..4944284698a0
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.View;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.util.LatencyTracker;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public class KeyguardPinBasedInputViewControllerTest extends SysuiTestCase {
+
+ @Mock
+ private KeyguardPinBasedInputView mPinBasedInputView;
+ @Mock
+ private PasswordTextView mPasswordEntry;
+ @Mock
+ private KeyguardMessageArea mKeyguardMessageArea;
+ @Mock
+ private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock
+ private SecurityMode mSecurityMode;
+ @Mock
+ private LockPatternUtils mLockPatternUtils;
+ @Mock
+ private KeyguardSecurityCallback mKeyguardSecurityCallback;
+ @Mock
+ private KeyguardMessageAreaController.Factory mKeyguardMessageAreaControllerFactory;
+ @Mock
+ private KeyguardMessageAreaController mKeyguardMessageAreaController;
+ @Mock
+ private LatencyTracker mLatencyTracker;
+ @Mock
+ private LiftToActivateListener mLiftToactivateListener;
+ @Mock
+ private View mDeleteButton;
+ @Mock
+ private View mOkButton;
+
+ private KeyguardPinBasedInputViewController mKeyguardPinViewController;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ when(mKeyguardMessageAreaControllerFactory.create(any(KeyguardMessageArea.class)))
+ .thenReturn(mKeyguardMessageAreaController);
+ when(mPinBasedInputView.getPasswordTextViewId()).thenReturn(1);
+ when(mPinBasedInputView.findViewById(1)).thenReturn(mPasswordEntry);
+ when(mPinBasedInputView.isAttachedToWindow()).thenReturn(true);
+ when(mPinBasedInputView.findViewById(R.id.keyguard_message_area))
+ .thenReturn(mKeyguardMessageArea);
+ when(mPinBasedInputView.findViewById(R.id.delete_button))
+ .thenReturn(mDeleteButton);
+ when(mPinBasedInputView.findViewById(R.id.key_enter))
+ .thenReturn(mOkButton);
+ mKeyguardPinViewController = new KeyguardPinBasedInputViewController(mPinBasedInputView,
+ mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback,
+ mKeyguardMessageAreaControllerFactory, mLatencyTracker, mLiftToactivateListener) {
+ @Override
+ public void onResume(int reason) {
+ super.onResume(reason);
+ }
+ };
+ mKeyguardPinViewController.init();
+ }
+
+ @Test
+ public void onResume_requestsFocus() {
+ mKeyguardPinViewController.onResume(KeyguardSecurityView.SCREEN_ON);
+ verify(mPasswordEntry).requestFocus();
+ }
+}
+
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewTest.java
deleted file mode 100644
index 6666a926c68b..000000000000
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewTest.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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 com.android.keyguard;
-
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper.RunWithLooper;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
-public class KeyguardPinBasedInputViewTest extends SysuiTestCase {
-
- @Mock
- private PasswordTextView mPasswordEntry;
- @Mock
- private SecurityMessageDisplay mSecurityMessageDisplay;
- @InjectMocks
- private KeyguardPinBasedInputView mKeyguardPinView;
-
- @Before
- public void setup() {
- LayoutInflater inflater = LayoutInflater.from(getContext());
- mDependency.injectMockDependency(KeyguardUpdateMonitor.class);
- mKeyguardPinView =
- (KeyguardPinBasedInputView) inflater.inflate(R.layout.keyguard_pin_view, null);
- MockitoAnnotations.initMocks(this);
- }
-
- @Test
- public void onResume_requestsFocus() {
- mKeyguardPinView.onResume(KeyguardSecurityView.SCREEN_ON);
- verify(mPasswordEntry).requestFocus();
- }
-
- @Test
- public void onKeyDown_clearsSecurityMessage() {
- mKeyguardPinView.onKeyDown(KeyEvent.KEYCODE_0, mock(KeyEvent.class));
- verify(mSecurityMessageDisplay).setMessage(eq(""));
- }
-
- @Test
- public void onKeyDown_noSecurityMessageInteraction() {
- mKeyguardPinView.onKeyDown(KeyEvent.KEYCODE_UNKNOWN, mock(KeyEvent.class));
- verifyZeroInteractions(mSecurityMessageDisplay);
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java
index 559284ac0672..ae159c73b99f 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java
@@ -31,9 +31,7 @@ import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardDisplayManager.KeyguardPresentation;
import com.android.keyguard.dagger.KeyguardStatusViewComponent;
import com.android.systemui.R;
-import com.android.systemui.SystemUIFactory;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.util.InjectionInflationController;
import org.junit.After;
import org.junit.Before;
@@ -65,7 +63,6 @@ public class KeyguardPresentationTest extends SysuiTestCase {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mDependency.injectMockDependency(KeyguardUpdateMonitor.class);
when(mMockKeyguardClockSwitch.getContext()).thenReturn(mContext);
when(mMockKeyguardSliceView.getContext()).thenReturn(mContext);
when(mMockKeyguardStatusView.getContext()).thenReturn(mContext);
@@ -77,11 +74,7 @@ public class KeyguardPresentationTest extends SysuiTestCase {
allowTestableLooperAsMainThread();
- InjectionInflationController inflationController = new InjectionInflationController(
- SystemUIFactory.getInstance()
- .getSysUIComponent()
- .createViewInstanceCreatorFactory());
- mLayoutInflater = inflationController.injectable(LayoutInflater.from(mContext));
+ mLayoutInflater = LayoutInflater.from(mContext);
mLayoutInflater.setPrivateFactory(new LayoutInflater.Factory2() {
@Override
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
new file mode 100644
index 000000000000..cdb91ecfad89
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.WindowInsetsController;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEventLogger;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper()
+public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
+
+ @Rule
+ public MockitoRule mRule = MockitoJUnit.rule();
+
+ @Mock
+ private KeyguardSecurityContainer mView;
+ @Mock
+ private AdminSecondaryLockScreenController.Factory mAdminSecondaryLockScreenControllerFactory;
+ @Mock
+ private AdminSecondaryLockScreenController mAdminSecondaryLockScreenController;
+ @Mock
+ private LockPatternUtils mLockPatternUtils;
+ @Mock
+ private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock
+ private KeyguardSecurityModel mKeyguardSecurityModel;
+ @Mock
+ private MetricsLogger mMetricsLogger;
+ @Mock
+ private UiEventLogger mUiEventLogger;
+ @Mock
+ private KeyguardStateController mKeyguardStateController;
+ @Mock
+ private KeyguardInputViewController mInputViewController;
+ @Mock
+ private KeyguardSecurityContainer.SecurityCallback mSecurityCallback;
+ @Mock
+ private WindowInsetsController mWindowInsetsController;
+ @Mock
+ private KeyguardSecurityViewFlipper mSecurityViewFlipper;
+ @Mock
+ private KeyguardSecurityViewFlipperController mKeyguardSecurityViewFlipperController;
+
+ private KeyguardSecurityContainerController mKeyguardSecurityContainerController;
+
+ @Before
+ public void setup() {
+ when(mAdminSecondaryLockScreenControllerFactory.create(any(KeyguardSecurityCallback.class)))
+ .thenReturn(mAdminSecondaryLockScreenController);
+ when(mSecurityViewFlipper.getWindowInsetsController()).thenReturn(mWindowInsetsController);
+
+ mKeyguardSecurityContainerController = new KeyguardSecurityContainerController(
+ mView, mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils,
+ mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger,
+ mKeyguardStateController, mKeyguardSecurityViewFlipperController);
+
+ mKeyguardSecurityContainerController.setSecurityCallback(mSecurityCallback);
+ }
+
+ @Test
+ public void showSecurityScreen_canInflateAllModes() {
+ SecurityMode[] modes = SecurityMode.values();
+ for (SecurityMode mode : modes) {
+ when(mInputViewController.getSecurityMode()).thenReturn(mode);
+ mKeyguardSecurityContainerController.showSecurityScreen(mode);
+ if (mode == SecurityMode.Invalid) {
+ verify(mKeyguardSecurityViewFlipperController, never()).getSecurityView(
+ any(SecurityMode.class), any(KeyguardSecurityCallback.class));
+ } else {
+ verify(mKeyguardSecurityViewFlipperController).getSecurityView(
+ eq(mode), any(KeyguardSecurityCallback.class));
+ }
+ }
+ }
+
+ @Test
+ public void startDisappearAnimation_animatesKeyboard() {
+ when(mKeyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(
+ SecurityMode.Password);
+ when(mInputViewController.getSecurityMode()).thenReturn(
+ SecurityMode.Password);
+ when(mKeyguardSecurityViewFlipperController.getSecurityView(
+ eq(SecurityMode.Password), any(KeyguardSecurityCallback.class)))
+ .thenReturn(mInputViewController);
+ mKeyguardSecurityContainerController.showPrimarySecurityScreen(false /* turningOff */);
+
+ mKeyguardSecurityContainerController.startDisappearAnimation(null);
+ verify(mInputViewController).startDisappearAnimation(eq(null));
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index a867825e223d..854be1f76722 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -19,23 +19,19 @@ package com.android.keyguard;
import static android.view.WindowInsets.Type.ime;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.content.Context;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
-import android.view.LayoutInflater;
import android.view.WindowInsetsController;
import androidx.test.filters.SmallTest;
-import com.android.systemui.R;
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.Before;
import org.junit.Rule;
@@ -50,68 +46,26 @@ import org.mockito.junit.MockitoRule;
@TestableLooper.RunWithLooper()
public class KeyguardSecurityContainerTest extends SysuiTestCase {
- @Mock
- private KeyguardSecurityModel mKeyguardSecurityModel;
- @Mock
- private KeyguardStateController mKeyguardStateController;
- @Mock
- private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- @Mock
- private KeyguardSecurityContainer.SecurityCallback mSecurityCallback;
- @Mock
- private KeyguardSecurityView mSecurityView;
+ @Rule
+ public MockitoRule mRule = MockitoJUnit.rule();
+
@Mock
private WindowInsetsController mWindowInsetsController;
@Mock
private KeyguardSecurityViewFlipper mSecurityViewFlipper;
- @Rule
- public MockitoRule mRule = MockitoJUnit.rule();
+
private KeyguardSecurityContainer mKeyguardSecurityContainer;
@Before
public void setup() {
- mDependency.injectTestDependency(KeyguardStateController.class, mKeyguardStateController);
- mDependency.injectTestDependency(KeyguardSecurityModel.class, mKeyguardSecurityModel);
- mDependency.injectTestDependency(KeyguardUpdateMonitor.class, mKeyguardUpdateMonitor);
- mKeyguardSecurityContainer = new KeyguardSecurityContainer(getContext()) {
- @Override
- protected KeyguardSecurityView getSecurityView(
- KeyguardSecurityModel.SecurityMode securityMode) {
- return mSecurityView;
- }
- };
- mKeyguardSecurityContainer.mSecurityViewFlipper = mSecurityViewFlipper;
when(mSecurityViewFlipper.getWindowInsetsController()).thenReturn(mWindowInsetsController);
- mKeyguardSecurityContainer.setSecurityCallback(mSecurityCallback);
- }
-
- @Test
- public void showSecurityScreen_canInflateAllModes() {
- Context context = getContext();
-
- for (int theme : new int[] {R.style.Theme_SystemUI, R.style.Theme_SystemUI_Light}) {
- context.setTheme(theme);
- final LayoutInflater inflater = LayoutInflater.from(context);
- KeyguardSecurityModel.SecurityMode[] modes =
- KeyguardSecurityModel.SecurityMode.values();
- for (KeyguardSecurityModel.SecurityMode mode : modes) {
- final int resId = mKeyguardSecurityContainer.getLayoutIdFor(mode);
- if (resId == 0) {
- continue;
- }
- inflater.inflate(resId, null /* root */, false /* attach */);
- }
- }
+ mKeyguardSecurityContainer = new KeyguardSecurityContainer(getContext());
+ mKeyguardSecurityContainer.mSecurityViewFlipper = mSecurityViewFlipper;
}
@Test
public void startDisappearAnimation_animatesKeyboard() {
- when(mKeyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(
- KeyguardSecurityModel.SecurityMode.Password);
- mKeyguardSecurityContainer.showPrimarySecurityScreen(false /* turningOff */);
-
- mKeyguardSecurityContainer.startDisappearAnimation(null);
- verify(mSecurityView).startDisappearAnimation(eq(null));
+ mKeyguardSecurityContainer.startDisappearAnimation(SecurityMode.Password);
verify(mWindowInsetsController).controlWindowInsetsAnimation(eq(ime()), anyLong(), any(),
any(), any());
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java
new file mode 100644
index 000000000000..3b7f4b839853
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+import android.view.WindowInsetsController;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper()
+public class KeyguardSecurityViewFlipperControllerTest extends SysuiTestCase {
+
+ @Rule
+ public MockitoRule mRule = MockitoJUnit.rule();
+
+ @Mock
+ private KeyguardSecurityViewFlipper mView;
+ @Mock
+ private LayoutInflater mLayoutInflater;
+ @Mock
+ private KeyguardInputViewController.Factory mKeyguardSecurityViewControllerFactory;
+ @Mock
+ private KeyguardInputViewController mKeyguardInputViewController;
+ @Mock
+ private KeyguardInputView mInputView;
+ @Mock
+ private WindowInsetsController mWindowInsetsController;
+ @Mock
+ private KeyguardSecurityCallback mKeyguardSecurityCallback;
+
+ private KeyguardSecurityViewFlipperController mKeyguardSecurityViewFlipperController;
+
+ @Before
+ public void setup() {
+ when(mKeyguardSecurityViewControllerFactory.create(
+ any(KeyguardInputView.class), any(SecurityMode.class),
+ any(KeyguardSecurityCallback.class)))
+ .thenReturn(mKeyguardInputViewController);
+ when(mView.getWindowInsetsController()).thenReturn(mWindowInsetsController);
+
+ mKeyguardSecurityViewFlipperController = new KeyguardSecurityViewFlipperController(mView,
+ mLayoutInflater, mKeyguardSecurityViewControllerFactory);
+ }
+
+ @Test
+ public void showSecurityScreen_canInflateAllModes() {
+ SecurityMode[] modes = SecurityMode.values();
+ // Always return an invalid controller so that we're always making a new one.
+ when(mKeyguardInputViewController.getSecurityMode()).thenReturn(SecurityMode.Invalid);
+ for (SecurityMode mode : modes) {
+ reset(mLayoutInflater);
+ when(mLayoutInflater.inflate(anyInt(), eq(mView), eq(false)))
+ .thenReturn(mInputView);
+ mKeyguardSecurityViewFlipperController.getSecurityView(mode, mKeyguardSecurityCallback);
+ if (mode == SecurityMode.Invalid || mode == SecurityMode.None) {
+ verify(mLayoutInflater, never()).inflate(
+ anyInt(), any(ViewGroup.class), anyBoolean());
+ } else {
+ verify(mLayoutInflater).inflate(anyInt(), eq(mView), eq(false));
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java
index 0431704778c3..79ec4f2c553a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java
@@ -24,9 +24,7 @@ import android.testing.TestableLooper.RunWithLooper;
import android.view.LayoutInflater;
import com.android.systemui.R;
-import com.android.systemui.SystemUIFactory;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.util.InjectionInflationController;
import org.junit.Before;
import org.junit.Test;
@@ -50,13 +48,7 @@ public class KeyguardStatusViewTest extends SysuiTestCase {
@Before
public void setUp() {
allowTestableLooperAsMainThread();
- mDependency.injectMockDependency(KeyguardUpdateMonitor.class);
- InjectionInflationController inflationController = new InjectionInflationController(
- SystemUIFactory.getInstance()
- .getSysUIComponent()
- .createViewInstanceCreatorFactory());
- LayoutInflater layoutInflater = inflationController
- .injectable(LayoutInflater.from(getContext()));
+ LayoutInflater layoutInflater = LayoutInflater.from(getContext());
mKeyguardStatusView =
(KeyguardStatusView) layoutInflater.inflate(R.layout.keyguard_status_view, null);
org.mockito.MockitoAnnotations.initMocks(this);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index 0fe381746449..86b1e61d76b1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -41,7 +41,6 @@ import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.SmartReplyController;
-import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
import org.junit.After;
import org.junit.Before;
@@ -110,7 +109,6 @@ public abstract class SysuiTestCase {
// KeyguardUpdateMonitor to be created (injected).
// TODO(b/1531701009) Clean up NotificationContentView creation to prevent this
mDependency.injectMockDependency(SmartReplyController.class);
- mDependency.injectMockDependency(NotificationBlockingHelperManager.class);
}
@After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index f1f394e70689..539b321991ad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -29,11 +29,14 @@ import static org.mockito.Mockito.when;
import android.app.Instrumentation;
import android.content.Context;
import android.content.pm.ActivityInfo;
+import android.content.res.Resources;
import android.os.Handler;
import android.testing.AndroidTestingRunner;
import android.view.Display;
import android.view.Surface;
import android.view.SurfaceControl;
+import android.view.View;
+import android.view.WindowManager;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -63,15 +66,28 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
WindowMagnifierCallback mWindowMagnifierCallback;
@Mock
SurfaceControl.Transaction mTransaction;
- private Context mContext;
+ @Mock
+ private WindowManager mWindowManager;
+ private Resources mResources;
private WindowMagnificationController mWindowMagnificationController;
private Instrumentation mInstrumentation;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mContext = Mockito.spy(getContext());
+ mContext = Mockito.spy(getContext());
mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ WindowManager wm = mContext.getSystemService(WindowManager.class);
+ doAnswer(invocation ->
+ wm.getMaximumWindowMetrics()
+ ).when(mWindowManager).getMaximumWindowMetrics();
+ mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager);
+ doAnswer(invocation -> {
+ View view = invocation.getArgument(0);
+ WindowManager.LayoutParams lp = invocation.getArgument(1);
+ view.setLayoutParams(lp);
+ return null;
+ }).when(mWindowManager).addView(any(View.class), any(WindowManager.LayoutParams.class));
doAnswer(invocation -> {
FrameCallback callback = invocation.getArgument(0);
callback.doFrame(0);
@@ -81,6 +97,8 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
when(mTransaction.remove(any())).thenReturn(mTransaction);
when(mTransaction.setGeometry(any(), any(), any(),
anyInt())).thenReturn(mTransaction);
+ mResources = Mockito.spy(mContext.getResources());
+ when(mContext.getResources()).thenReturn(mResources);
mWindowMagnificationController = new WindowMagnificationController(mContext,
mHandler, mSfVsyncFrameProvider,
mMirrorWindowControl, mTransaction, mWindowMagnifierCallback);
@@ -150,4 +168,63 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_ORIENTATION);
});
}
+
+ @Test
+ public void onOrientationChanged_enabled_updateDisplayRotationAndLayout() {
+ final Display display = Mockito.spy(mContext.getDisplay());
+ when(display.getRotation()).thenReturn(Surface.ROTATION_90);
+ when(mContext.getDisplay()).thenReturn(display);
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+ Float.NaN);
+ Mockito.reset(mWindowManager);
+ });
+
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_ORIENTATION);
+ });
+
+ assertEquals(Surface.ROTATION_90, mWindowMagnificationController.mRotation);
+ verify(mWindowManager).updateViewLayout(any(), any());
+ }
+
+ @Test
+ public void onOrientationChanged_disabled_updateDisplayRotation() {
+ final Display display = Mockito.spy(mContext.getDisplay());
+ when(display.getRotation()).thenReturn(Surface.ROTATION_90);
+ when(mContext.getDisplay()).thenReturn(display);
+
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_ORIENTATION);
+ });
+
+ assertEquals(Surface.ROTATION_90, mWindowMagnificationController.mRotation);
+ }
+
+
+ @Test
+ public void onDensityChanged_enabled_updateDimensionsAndLayout() {
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+ Float.NaN);
+ Mockito.reset(mWindowManager);
+ });
+
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_DENSITY);
+ });
+
+ verify(mResources, atLeastOnce()).getDimensionPixelSize(anyInt());
+ verify(mWindowManager).removeView(any());
+ verify(mWindowManager).addView(any(), any());
+ }
+
+ @Test
+ public void onDensityChanged_disabled_updateDimensions() {
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_DENSITY);
+ });
+
+ verify(mResources, atLeastOnce()).getDimensionPixelSize(anyInt());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
new file mode 100644
index 000000000000..87ec72fe0a01
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.IUdfpsOverlayController;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.WindowManager;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.settings.FakeSettings;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public class UdfpsControllerTest extends SysuiTestCase {
+
+ @Rule
+ public MockitoRule rule = MockitoJUnit.rule();
+
+ // Unit under test
+ private UdfpsController mUdfpsController;
+
+ // Dependencies
+ @Mock
+ private Resources mResources;
+ @Mock
+ private LayoutInflater mLayoutInflater;
+ @Mock
+ private FingerprintManager mFingerprintManager;
+ @Mock
+ private PowerManager mPowerManager;
+ @Mock
+ private WindowManager mWindowManager;
+ @Mock
+ private StatusBarStateController mStatusBarStateController;
+ private FakeSettings mSystemSettings;
+ private FakeExecutor mFgExecutor;
+
+ // Stuff for configuring mocks
+ @Mock
+ private UdfpsView mUdfpsView;
+ @Mock
+ private TypedArray mBrightnessValues;
+ @Mock
+ private TypedArray mBrightnessBacklight;
+
+ // Capture listeners so that they can be used to send events
+ @Captor private ArgumentCaptor<IUdfpsOverlayController> mOverlayCaptor;
+ private IUdfpsOverlayController mOverlayController;
+ @Captor private ArgumentCaptor<UdfpsView.OnTouchListener> mTouchListenerCaptor;
+
+ @Before
+ public void setUp() {
+ setUpResources();
+ when(mLayoutInflater.inflate(R.layout.udfps_view, null, false)).thenReturn(mUdfpsView);
+ mSystemSettings = new FakeSettings();
+ mFgExecutor = new FakeExecutor(new FakeSystemClock());
+ mUdfpsController = new UdfpsController(
+ mContext,
+ mResources,
+ mLayoutInflater,
+ mFingerprintManager,
+ mPowerManager,
+ mWindowManager,
+ mSystemSettings,
+ mStatusBarStateController,
+ mFgExecutor);
+ verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
+ mOverlayController = mOverlayCaptor.getValue();
+ }
+
+ private void setUpResources() {
+ when(mBrightnessValues.length()).thenReturn(2);
+ when(mBrightnessValues.getFloat(0, PowerManager.BRIGHTNESS_OFF_FLOAT)).thenReturn(1f);
+ when(mBrightnessValues.getFloat(1, PowerManager.BRIGHTNESS_OFF_FLOAT)).thenReturn(2f);
+ when(mResources.obtainTypedArray(com.android.internal.R.array.config_screenBrightnessNits))
+ .thenReturn(mBrightnessValues);
+ when(mBrightnessBacklight.length()).thenReturn(2);
+ when(mBrightnessBacklight.getFloat(0, PowerManager.BRIGHTNESS_OFF_FLOAT)).thenReturn(1f);
+ when(mBrightnessBacklight.getFloat(1, PowerManager.BRIGHTNESS_OFF_FLOAT)).thenReturn(2f);
+ when(mResources.obtainTypedArray(
+ com.android.internal.R.array.config_autoBrightnessDisplayValuesNits))
+ .thenReturn(mBrightnessBacklight);
+ when(mResources.getIntArray(com.android.internal.R.array.config_screenBrightnessBacklight))
+ .thenReturn(new int[]{1, 2});
+ }
+
+ @Test
+ public void dozeTimeTick() {
+ mUdfpsController.dozeTimeTick();
+ verify(mUdfpsView).dozeTimeTick();
+ }
+
+ @Test
+ public void showUdfpsOverlay_addsViewToWindow() throws RemoteException {
+ mOverlayController.showUdfpsOverlay();
+ mFgExecutor.runAllReady();
+ verify(mWindowManager).addView(eq(mUdfpsView), any());
+ }
+
+ @Test
+ public void hideUdfpsOverlay_removesViewFromWindow() throws RemoteException {
+ mOverlayController.showUdfpsOverlay();
+ mOverlayController.hideUdfpsOverlay();
+ mFgExecutor.runAllReady();
+ verify(mWindowManager).removeView(eq(mUdfpsView));
+ }
+
+ @Test
+ public void fingerDown() throws RemoteException {
+ // Configure UdfpsView to accept the ACTION_DOWN event
+ when(mUdfpsView.isScrimShowing()).thenReturn(false);
+ when(mUdfpsView.isValidTouch(anyFloat(), anyFloat(), anyFloat())).thenReturn(true);
+
+ // GIVEN that the overlay is showing
+ mOverlayController.showUdfpsOverlay();
+ mFgExecutor.runAllReady();
+ // WHEN ACTION_DOWN is received
+ verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+ MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
+ event.recycle();
+ // THEN the event is passed to the FingerprintManager
+ verify(mFingerprintManager).onFingerDown(eq(0), eq(0), eq(0f), eq(0f));
+ // AND the scrim and dot is shown
+ verify(mUdfpsView).showScrimAndDot();
+ }
+
+ @Test
+ public void aodInterrupt() throws RemoteException {
+ // GIVEN that the overlay is showing
+ mOverlayController.showUdfpsOverlay();
+ mFgExecutor.runAllReady();
+ // WHEN fingerprint is requested because of AOD interrupt
+ mUdfpsController.onAodInterrupt(0, 0);
+ // THEN the event is passed to the FingerprintManager
+ verify(mFingerprintManager).onFingerDown(eq(0), eq(0), anyFloat(), anyFloat());
+ // AND the scrim and dot is shown
+ verify(mUdfpsView).showScrimAndDot();
+ }
+
+ @Test
+ public void cancelAodInterrupt() throws RemoteException {
+ // GIVEN AOD interrupt
+ mOverlayController.showUdfpsOverlay();
+ mFgExecutor.runAllReady();
+ mUdfpsController.onAodInterrupt(0, 0);
+ // WHEN it is cancelled
+ mUdfpsController.onCancelAodInterrupt();
+ // THEN the scrim and dot is hidden
+ verify(mUdfpsView).hideScrimAndDot();
+ }
+
+ @Test
+ public void aodInterruptTimeout() throws RemoteException {
+ // GIVEN AOD interrupt
+ mOverlayController.showUdfpsOverlay();
+ mFgExecutor.runAllReady();
+ mUdfpsController.onAodInterrupt(0, 0);
+ // WHEN it times out
+ mFgExecutor.advanceClockToNext();
+ mFgExecutor.runAllReady();
+ // THEN the scrim and dot is hidden
+ verify(mUdfpsView).hideScrimAndDot();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
index b85b1c237f6b..be0865d1b3e9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
@@ -115,8 +115,6 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
@Test
public void testAod_usesLightSensor() {
- mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
- mScreen.transitionTo(INITIALIZED, DOZE_AOD);
mScreen.onScreenState(Display.STATE_DOZE);
waitForSensorManager();
@@ -127,8 +125,6 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
@Test
public void testAod_usesDebugValue() throws Exception {
- mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
- mScreen.transitionTo(INITIALIZED, DOZE_AOD);
mScreen.onScreenState(Display.STATE_DOZE);
waitForSensorManager();
@@ -181,14 +177,13 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
}
@Test
- public void testDozingAfterPulsing_pausesLightSensor() throws Exception {
+ public void testScreenOffAfterPulsing_pausesLightSensor() throws Exception {
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
mScreen.transitionTo(INITIALIZED, DOZE);
mScreen.transitionTo(DOZE, DOZE_REQUEST_PULSE);
mScreen.transitionTo(DOZE_REQUEST_PULSE, DOZE_PULSING);
mScreen.transitionTo(DOZE_PULSING, DOZE_PULSE_DONE);
mScreen.transitionTo(DOZE_PULSE_DONE, DOZE);
- mScreen.onScreenState(Display.STATE_DOZE);
waitForSensorManager();
mSensor.sendSensorEvent(1);
@@ -197,6 +192,18 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
}
@Test
+ public void testOnScreenStateSetBeforeTransition_stillRegistersSensor() {
+ mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
+ mScreen.onScreenState(Display.STATE_DOZE);
+ mScreen.transitionTo(INITIALIZED, DOZE_AOD);
+ waitForSensorManager();
+
+ mSensor.sendSensorEvent(1);
+
+ assertEquals(1, mServiceFake.screenBrightness);
+ }
+
+ @Test
public void testNullSensor() throws Exception {
mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager,
Optional.empty() /* sensor */, mDozeHost, null /* handler */,
@@ -206,12 +213,15 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
mScreen.transitionTo(INITIALIZED, DOZE_AOD);
mScreen.transitionTo(DOZE_AOD, DOZE_AOD_PAUSING);
mScreen.transitionTo(DOZE_AOD_PAUSING, DOZE_AOD_PAUSED);
+ mScreen.onScreenState(Display.STATE_DOZE);
+ mScreen.onScreenState(Display.STATE_OFF);
}
@Test
public void testNoBrightnessDeliveredAfterFinish() throws Exception {
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
mScreen.transitionTo(INITIALIZED, DOZE_AOD);
+ mScreen.onScreenState(Display.STATE_DOZE);
mScreen.transitionTo(DOZE_AOD, FINISH);
waitForSensorManager();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index f29b46c73e4d..8f1d71c80e2d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -54,7 +54,6 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@@ -71,7 +70,6 @@ public class ExpandableNotificationRowTest extends SysuiTestCase {
boolean mHeadsUpAnimatingAway = false;
@Rule public MockitoRule mockito = MockitoJUnit.rule();
- @Mock private NotificationBlockingHelperManager mBlockingHelperManager;
@Before
public void setUp() throws Exception {
@@ -83,9 +81,6 @@ public class ExpandableNotificationRowTest extends SysuiTestCase {
mGroupRow = mNotificationTestHelper.createGroup();
mGroupRow.setHeadsUpAnimatingAwayListener(
animatingAway -> mHeadsUpAnimatingAway = animatingAway);
- mDependency.injectTestDependency(
- NotificationBlockingHelperManager.class,
- mBlockingHelperManager);
}
@Test
@@ -257,30 +252,6 @@ public class ExpandableNotificationRowTest extends SysuiTestCase {
}
@Test
- public void testPerformDismissWithBlockingHelper_falseWhenBlockingHelperIsntShown() {
- when(mBlockingHelperManager.perhapsShowBlockingHelper(
- eq(mGroupRow), any(NotificationMenuRowPlugin.class))).thenReturn(false);
-
- assertFalse(
- mGroupRow.performDismissWithBlockingHelper(false /* fromAccessibility */));
- }
-
- @Test
- public void testPerformDismissWithBlockingHelper_doesntPerformOnGroupSummary() {
- ExpandableNotificationRow childRow = mGroupRow.getChildrenContainer().getViewAtPosition(0);
- when(mBlockingHelperManager.perhapsShowBlockingHelper(eq(childRow), any(NotificationMenuRowPlugin.class)))
- .thenReturn(true);
-
- assertTrue(
- childRow.performDismissWithBlockingHelper(false /* fromAccessibility */));
-
- verify(mBlockingHelperManager, times(1))
- .perhapsShowBlockingHelper(eq(childRow), any(NotificationMenuRowPlugin.class));
- verify(mBlockingHelperManager, times(0))
- .perhapsShowBlockingHelper(eq(mGroupRow), any(NotificationMenuRowPlugin.class));
- }
-
- @Test
public void testIsBlockingHelperShowing_isCorrectlyUpdated() {
mGroupRow.setBlockingHelperShowing(true);
assertTrue(mGroupRow.isBlockingHelperShowing());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 5bef2573b48a..bb85cec5c099 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -58,10 +58,8 @@ import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
-import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.FooterView;
-import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.KeyguardBypassEnabledProvider;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -91,7 +89,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Rule public MockitoRule mockito = MockitoJUnit.rule();
@Mock private StatusBar mBar;
@Mock private SysuiStatusBarStateController mBarState;
- @Mock private NotificationBlockingHelperManager mBlockingHelperManager;
@Mock private NotificationGroupManagerLegacy mGroupMembershipManger;
@Mock private NotificationGroupManagerLegacy mGroupExpansionManager;
@Mock private ExpandHelper mExpandHelper;
@@ -120,9 +117,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
1, UserHandle.USER_CURRENT);
// Inject dependencies before initializing the layout
- mDependency.injectTestDependency(
- NotificationBlockingHelperManager.class,
- mBlockingHelperManager);
mDependency.injectTestDependency(SysuiStatusBarStateController.class, mBarState);
mDependency.injectMockDependency(ShadeController.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
index 74a57bf7cc55..01d49c269fb2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java
@@ -27,7 +27,6 @@ import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -65,7 +64,6 @@ import com.android.systemui.statusbar.notification.collection.legacy.VisualStabi
import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ForegroundServiceDungeonView;
-import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController.NotificationPanelEvent;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
@@ -87,8 +85,6 @@ import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.function.BiConsumer;
-
/**
* Tests for {@link NotificationStackScrollLayoutController}.
*/
@@ -132,7 +128,6 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase {
@Mock private NotificationRemoteInputManager mRemoteInputManager;
@Mock private RemoteInputController mRemoteInputController;
@Mock private VisualStabilityManager mVisualStabilityManager;
- @Mock private NotificationBlockingHelperManager mNotificationBlockingHelperManager;
@Mock private ShadeController mShadeController;
@Captor
@@ -184,7 +179,6 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase {
mLayoutInflater,
mRemoteInputManager,
mVisualStabilityManager,
- mNotificationBlockingHelperManager,
mShadeController
);
@@ -378,25 +372,6 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase {
any(ForegroundServiceDungeonView.class));
}
- @Test
- public void testSetExpandedHeight_blockingHelperManagerReceivedCallbacks() {
-
- ArgumentCaptor<BiConsumer<Float, Float>>
- onExpandedHeightChangeListenerCaptor = ArgumentCaptor.forClass(
- BiConsumer.class);
-
- mController.attach(mNotificationStackScrollLayout);
-
- verify(mNotificationStackScrollLayout, times(2)).addOnExpandedHeightChangedListener(
- onExpandedHeightChangeListenerCaptor.capture());
-
- for (BiConsumer<Float, Float> listener :
- onExpandedHeightChangeListenerCaptor.getAllValues()) {
- listener.accept(1f, 2f);
- }
- verify(mNotificationBlockingHelperManager).setNotificationShadeExpanded(1f);
- }
-
private LogMaker logMatcher(int category, int type) {
return argThat(new LogMatcher(category, type));
}
diff --git a/packages/Tethering/apex/Android.bp b/packages/Tethering/apex/Android.bp
index 67097a79e5c0..05243749f765 100644
--- a/packages/Tethering/apex/Android.bp
+++ b/packages/Tethering/apex/Android.bp
@@ -19,6 +19,7 @@ apex {
updatable: true,
min_sdk_version: "current",
java_libs: ["framework-tethering"],
+ bpfs: ["offload.o"],
apps: ["Tethering"],
manifest: "manifest.json",
key: "com.android.tethering.key",
diff --git a/packages/Tethering/bpf_progs/Android.bp b/packages/Tethering/bpf_progs/Android.bp
new file mode 100644
index 000000000000..d54f86148665
--- /dev/null
+++ b/packages/Tethering/bpf_progs/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+//
+// bpf kernel programs
+//
+bpf {
+ name: "offload.o",
+ srcs: ["offload.c"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ include_dirs: [
+ // TODO: get rid of system/netd.
+ "system/netd/bpf_progs", // for bpf_net_helpers.h
+ "system/netd/libnetdbpf/include", // for bpf_shared.h
+ "system/netd/libnetdutils/include", // for UidConstants.h
+ ],
+}
diff --git a/packages/Tethering/bpf_progs/offload.c b/packages/Tethering/bpf_progs/offload.c
new file mode 100644
index 000000000000..cc5af3127b02
--- /dev/null
+++ b/packages/Tethering/bpf_progs/offload.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <linux/if.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/pkt_cls.h>
+#include <linux/tcp.h>
+
+#include "bpf_helpers.h"
+#include "bpf_net_helpers.h"
+#include "netdbpf/bpf_shared.h"
+
+DEFINE_BPF_MAP_GRW(tether_ingress_map, HASH, TetherIngressKey, TetherIngressValue, 64,
+ AID_NETWORK_STACK)
+
+// Tethering stats, indexed by upstream interface.
+DEFINE_BPF_MAP_GRW(tether_stats_map, HASH, uint32_t, TetherStatsValue, 16, AID_NETWORK_STACK)
+
+// Tethering data limit, indexed by upstream interface.
+// (tethering allowed when stats[iif].rxBytes + stats[iif].txBytes < limit[iif])
+DEFINE_BPF_MAP_GRW(tether_limit_map, HASH, uint32_t, uint64_t, 16, AID_NETWORK_STACK)
+
+static inline __always_inline int do_forward(struct __sk_buff* skb, bool is_ethernet) {
+ int l2_header_size = is_ethernet ? sizeof(struct ethhdr) : 0;
+ void* data = (void*)(long)skb->data;
+ const void* data_end = (void*)(long)skb->data_end;
+ struct ethhdr* eth = is_ethernet ? data : NULL; // used iff is_ethernet
+ struct ipv6hdr* ip6 = is_ethernet ? (void*)(eth + 1) : data;
+
+ // Must be meta-ethernet IPv6 frame
+ if (skb->protocol != htons(ETH_P_IPV6)) return TC_ACT_OK;
+
+ // Must have (ethernet and) ipv6 header
+ if (data + l2_header_size + sizeof(*ip6) > data_end) return TC_ACT_OK;
+
+ // Ethertype - if present - must be IPv6
+ if (is_ethernet && (eth->h_proto != htons(ETH_P_IPV6))) return TC_ACT_OK;
+
+ // IP version must be 6
+ if (ip6->version != 6) return TC_ACT_OK;
+
+ // Cannot decrement during forward if already zero or would be zero,
+ // Let the kernel's stack handle these cases and generate appropriate ICMP errors.
+ if (ip6->hop_limit <= 1) return TC_ACT_OK;
+
+ // Protect against forwarding packets sourced from ::1 or fe80::/64 or other weirdness.
+ __be32 src32 = ip6->saddr.s6_addr32[0];
+ if (src32 != htonl(0x0064ff9b) && // 64:ff9b:/32 incl. XLAT464 WKP
+ (src32 & htonl(0xe0000000)) != htonl(0x20000000)) // 2000::/3 Global Unicast
+ return TC_ACT_OK;
+
+ TetherIngressKey k = {
+ .iif = skb->ifindex,
+ .neigh6 = ip6->daddr,
+ };
+
+ TetherIngressValue* v = bpf_tether_ingress_map_lookup_elem(&k);
+
+ // If we don't find any offload information then simply let the core stack handle it...
+ if (!v) return TC_ACT_OK;
+
+ uint32_t stat_and_limit_k = skb->ifindex;
+
+ TetherStatsValue* stat_v = bpf_tether_stats_map_lookup_elem(&stat_and_limit_k);
+
+ // If we don't have anywhere to put stats, then abort...
+ if (!stat_v) return TC_ACT_OK;
+
+ uint64_t* limit_v = bpf_tether_limit_map_lookup_elem(&stat_and_limit_k);
+
+ // If we don't have a limit, then abort...
+ if (!limit_v) return TC_ACT_OK;
+
+ // Required IPv6 minimum mtu is 1280, below that not clear what we should do, abort...
+ const int pmtu = v->pmtu;
+ if (pmtu < IPV6_MIN_MTU) return TC_ACT_OK;
+
+ // Approximate handling of TCP/IPv6 overhead for incoming LRO/GRO packets: default
+ // outbound path mtu of 1500 is not necessarily correct, but worst case we simply
+ // undercount, which is still better then not accounting for this overhead at all.
+ // Note: this really shouldn't be device/path mtu at all, but rather should be
+ // derived from this particular connection's mss (ie. from gro segment size).
+ // This would require a much newer kernel with newer ebpf accessors.
+ // (This is also blindly assuming 12 bytes of tcp timestamp option in tcp header)
+ uint64_t packets = 1;
+ uint64_t bytes = skb->len;
+ if (bytes > pmtu) {
+ const int tcp_overhead = sizeof(struct ipv6hdr) + sizeof(struct tcphdr) + 12;
+ const int mss = pmtu - tcp_overhead;
+ const uint64_t payload = bytes - tcp_overhead;
+ packets = (payload + mss - 1) / mss;
+ bytes = tcp_overhead * packets + payload;
+ }
+
+ // Are we past the limit? If so, then abort...
+ // Note: will not overflow since u64 is 936 years even at 5Gbps.
+ // Do not drop here. Offload is just that, whenever we fail to handle
+ // a packet we let the core stack deal with things.
+ // (The core stack needs to handle limits correctly anyway,
+ // since we don't offload all traffic in both directions)
+ if (stat_v->rxBytes + stat_v->txBytes + bytes > *limit_v) return TC_ACT_OK;
+
+ if (!is_ethernet) {
+ is_ethernet = true;
+ l2_header_size = sizeof(struct ethhdr);
+ // Try to inject an ethernet header, and simply return if we fail
+ if (bpf_skb_change_head(skb, l2_header_size, /*flags*/ 0)) {
+ __sync_fetch_and_add(&stat_v->rxErrors, 1);
+ return TC_ACT_OK;
+ }
+
+ // bpf_skb_change_head() invalidates all pointers - reload them
+ data = (void*)(long)skb->data;
+ data_end = (void*)(long)skb->data_end;
+ eth = data;
+ ip6 = (void*)(eth + 1);
+
+ // I do not believe this can ever happen, but keep the verifier happy...
+ if (data + l2_header_size + sizeof(*ip6) > data_end) {
+ __sync_fetch_and_add(&stat_v->rxErrors, 1);
+ return TC_ACT_SHOT;
+ }
+ };
+
+ // CHECKSUM_COMPLETE is a 16-bit one's complement sum,
+ // thus corrections for it need to be done in 16-byte chunks at even offsets.
+ // IPv6 nexthdr is at offset 6, while hop limit is at offset 7
+ uint8_t old_hl = ip6->hop_limit;
+ --ip6->hop_limit;
+ uint8_t new_hl = ip6->hop_limit;
+
+ // bpf_csum_update() always succeeds if the skb is CHECKSUM_COMPLETE and returns an error
+ // (-ENOTSUPP) if it isn't.
+ bpf_csum_update(skb, 0xFFFF - ntohs(old_hl) + ntohs(new_hl));
+
+ __sync_fetch_and_add(&stat_v->rxPackets, packets);
+ __sync_fetch_and_add(&stat_v->rxBytes, bytes);
+
+ // Overwrite any mac header with the new one
+ *eth = v->macHeader;
+
+ // Redirect to forwarded interface.
+ //
+ // Note that bpf_redirect() cannot fail unless you pass invalid flags.
+ // The redirect actually happens after the ebpf program has already terminated,
+ // and can fail for example for mtu reasons at that point in time, but there's nothing
+ // we can do about it here.
+ return bpf_redirect(v->oif, 0 /* this is effectively BPF_F_EGRESS */);
+}
+
+SEC("schedcls/ingress/tether_ether")
+int sched_cls_ingress_tether_ether(struct __sk_buff* skb) {
+ return do_forward(skb, true);
+}
+
+// Note: section names must be unique to prevent programs from appending to each other,
+// so instead the bpf loader will strip everything past the final $ symbol when actually
+// pinning the program into the filesystem.
+//
+// bpf_skb_change_head() is only present on 4.14+ and 2 trivial kernel patches are needed:
+// ANDROID: net: bpf: Allow TC programs to call BPF_FUNC_skb_change_head
+// ANDROID: net: bpf: permit redirect from ingress L3 to egress L2 devices at near max mtu
+// (the first of those has already been upstreamed)
+//
+// 5.4 kernel support was only added to Android Common Kernel in R,
+// and thus a 5.4 kernel always supports this.
+//
+// Hence, this mandatory (must load successfully) implementation for 5.4+ kernels:
+DEFINE_BPF_PROG_KVER("schedcls/ingress/tether_rawip$5_4", AID_ROOT, AID_ROOT,
+ sched_cls_ingress_tether_rawip_5_4, KVER(5, 4, 0))
+(struct __sk_buff* skb) {
+ return do_forward(skb, false);
+}
+
+// and this identical optional (may fail to load) implementation for [4.14..5.4) patched kernels:
+DEFINE_OPTIONAL_BPF_PROG_KVER_RANGE("schedcls/ingress/tether_rawip$4_14", AID_ROOT, AID_ROOT,
+ sched_cls_ingress_tether_rawip_4_14, KVER(4, 14, 0),
+ KVER(5, 4, 0))
+(struct __sk_buff* skb) {
+ return do_forward(skb, false);
+}
+
+// and define a no-op stub for [4.9,4.14) and unpatched [4.14,5.4) kernels.
+// (if the above real 4.14+ program loaded successfully, then bpfloader will have already pinned
+// it at the same location this one would be pinned at and will thus skip loading this stub)
+DEFINE_BPF_PROG_KVER_RANGE("schedcls/ingress/tether_rawip$stub", AID_ROOT, AID_ROOT,
+ sched_cls_ingress_tether_rawip_stub, KVER_NONE, KVER(5, 4, 0))
+(struct __sk_buff* skb) {
+ return TC_ACT_OK;
+}
+
+LICENSE("Apache 2.0");
+CRITICAL("netd");
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 0d79240a4b59..4e405cc7f7ea 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -418,7 +418,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
if (DBG) {
- Slog.d(TAG, "Bluetooth Adapter name changed to " + newName);
+ Slog.d(TAG, "Bluetooth Adapter name changed to " + newName + " by "
+ + mContext.getPackageName());
}
if (newName != null) {
storeNameAndAddress(newName, null);
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 06f44b1bd388..a80111c2f781 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -6247,7 +6247,7 @@ public class AppOpsService extends IAppOpsService.Stub {
int[] users;
if (userId == UserHandle.USER_ALL) {
- // TODO(b/157921703): this call is returning all users, not just live ones - we
+ // TODO(b/162888972): this call is returning all users, not just live ones - we
// need to either fix the method called, or rename the variable
List<UserInfo> liveUsers = UserManager.get(mContext).getUsers();
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 7175489614ea..99dc58e20209 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -256,8 +256,8 @@ public class Vpn {
@GuardedBy("this")
private final Set<UidRange> mBlockedUidsAsToldToNetd = new ArraySet<>();
- // Handle of the user initiating VPN.
- private final int mUserHandle;
+ // The user id of initiating VPN.
+ private final int mUserId;
interface RetryScheduler {
void checkInterruptAndDelay(boolean sleepLonger) throws InterruptedException;
@@ -384,26 +384,26 @@ public class Vpn {
}
public Vpn(Looper looper, Context context, INetworkManagementService netService,
- @UserIdInt int userHandle, @NonNull KeyStore keyStore) {
- this(looper, context, new Dependencies(), netService, userHandle, keyStore,
+ @UserIdInt int userId, @NonNull KeyStore keyStore) {
+ this(looper, context, new Dependencies(), netService, userId, keyStore,
new SystemServices(context), new Ikev2SessionCreator());
}
@VisibleForTesting
protected Vpn(Looper looper, Context context, Dependencies deps,
INetworkManagementService netService,
- int userHandle, @NonNull KeyStore keyStore, SystemServices systemServices,
+ int userId, @NonNull KeyStore keyStore, SystemServices systemServices,
Ikev2SessionCreator ikev2SessionCreator) {
mContext = context;
mDeps = deps;
mNetd = netService;
- mUserHandle = userHandle;
+ mUserId = userId;
mLooper = looper;
mSystemServices = systemServices;
mIkev2SessionCreator = ikev2SessionCreator;
mPackage = VpnConfig.LEGACY_VPN;
- mOwnerUID = getAppUid(mPackage, mUserHandle);
+ mOwnerUID = getAppUid(mPackage, mUserId);
mIsPackageTargetingAtLeastQ = doesPackageTargetAtLeastQ(mPackage);
try {
@@ -613,7 +613,7 @@ public class Vpn {
PackageManager pm = mContext.getPackageManager();
ApplicationInfo appInfo = null;
try {
- appInfo = pm.getApplicationInfoAsUser(packageName, 0 /*flags*/, mUserHandle);
+ appInfo = pm.getApplicationInfoAsUser(packageName, 0 /*flags*/, mUserId);
} catch (NameNotFoundException unused) {
Log.w(TAG, "Can't find \"" + packageName + "\" when checking always-on support");
}
@@ -624,7 +624,7 @@ public class Vpn {
final Intent intent = new Intent(VpnConfig.SERVICE_INTERFACE);
intent.setPackage(packageName);
List<ResolveInfo> services =
- pm.queryIntentServicesAsUser(intent, PackageManager.GET_META_DATA, mUserHandle);
+ pm.queryIntentServicesAsUser(intent, PackageManager.GET_META_DATA, mUserId);
if (services == null || services.size() == 0) {
return false;
}
@@ -769,12 +769,12 @@ public class Vpn {
final long token = Binder.clearCallingIdentity();
try {
mSystemServices.settingsSecurePutStringForUser(Settings.Secure.ALWAYS_ON_VPN_APP,
- getAlwaysOnPackage(), mUserHandle);
+ getAlwaysOnPackage(), mUserId);
mSystemServices.settingsSecurePutIntForUser(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN,
- (mAlwaysOn && mLockdown ? 1 : 0), mUserHandle);
+ (mAlwaysOn && mLockdown ? 1 : 0), mUserId);
mSystemServices.settingsSecurePutStringForUser(
LOCKDOWN_ALLOWLIST_SETTING_NAME,
- String.join(",", mLockdownAllowlist), mUserHandle);
+ String.join(",", mLockdownAllowlist), mUserId);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -786,11 +786,11 @@ public class Vpn {
final long token = Binder.clearCallingIdentity();
try {
final String alwaysOnPackage = mSystemServices.settingsSecureGetStringForUser(
- Settings.Secure.ALWAYS_ON_VPN_APP, mUserHandle);
+ Settings.Secure.ALWAYS_ON_VPN_APP, mUserId);
final boolean alwaysOnLockdown = mSystemServices.settingsSecureGetIntForUser(
- Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, 0 /*default*/, mUserHandle) != 0;
+ Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, 0 /*default*/, mUserId) != 0;
final String allowlistString = mSystemServices.settingsSecureGetStringForUser(
- LOCKDOWN_ALLOWLIST_SETTING_NAME, mUserHandle);
+ LOCKDOWN_ALLOWLIST_SETTING_NAME, mUserId);
final List<String> allowedPackages = TextUtils.isEmpty(allowlistString)
? Collections.emptyList() : Arrays.asList(allowlistString.split(","));
setAlwaysOnPackageInternal(
@@ -850,13 +850,13 @@ public class Vpn {
DeviceIdleInternal idleController =
LocalServices.getService(DeviceIdleInternal.class);
idleController.addPowerSaveTempWhitelistApp(Process.myUid(), alwaysOnPackage,
- VPN_LAUNCH_IDLE_ALLOWLIST_DURATION_MS, mUserHandle, false, "vpn");
+ VPN_LAUNCH_IDLE_ALLOWLIST_DURATION_MS, mUserId, false, "vpn");
// Start the VPN service declared in the app's manifest.
Intent serviceIntent = new Intent(VpnConfig.SERVICE_INTERFACE);
serviceIntent.setPackage(alwaysOnPackage);
try {
- return mContext.startServiceAsUser(serviceIntent, UserHandle.of(mUserHandle)) != null;
+ return mContext.startServiceAsUser(serviceIntent, UserHandle.of(mUserId)) != null;
} catch (RuntimeException e) {
Log.e(TAG, "VpnService " + serviceIntent + " failed to start", e);
return false;
@@ -958,7 +958,7 @@ public class Vpn {
// We can't just check that packageName matches mPackage, because if the app was uninstalled
// and reinstalled it will no longer be prepared. Similarly if there is a shared UID, the
// calling package may not be the same as the prepared package. Check both UID and package.
- return getAppUid(packageName, mUserHandle) == mOwnerUID && mPackage.equals(packageName);
+ return getAppUid(packageName, mUserId) == mOwnerUID && mPackage.equals(packageName);
}
/** Prepare the VPN for the given package. Does not perform permission checks. */
@@ -998,7 +998,7 @@ public class Vpn {
Log.i(TAG, "Switched from " + mPackage + " to " + newPackage);
mPackage = newPackage;
- mOwnerUID = getAppUid(newPackage, mUserHandle);
+ mOwnerUID = getAppUid(newPackage, mUserId);
mIsPackageTargetingAtLeastQ = doesPackageTargetAtLeastQ(newPackage);
try {
mNetd.allowProtect(mOwnerUID);
@@ -1019,7 +1019,7 @@ public class Vpn {
// Check if the caller is authorized.
enforceControlPermissionOrInternalCaller();
- final int uid = getAppUid(packageName, mUserHandle);
+ final int uid = getAppUid(packageName, mUserId);
if (uid == -1 || VpnConfig.LEGACY_VPN.equals(packageName)) {
// Authorization for nonexistent packages (or fake ones) can't be updated.
return false;
@@ -1095,14 +1095,14 @@ public class Vpn {
|| isVpnServicePreConsented(context, packageName);
}
- private int getAppUid(final String app, final int userHandle) {
+ private int getAppUid(final String app, final int userId) {
if (VpnConfig.LEGACY_VPN.equals(app)) {
return Process.myUid();
}
PackageManager pm = mContext.getPackageManager();
return Binder.withCleanCallingIdentity(() -> {
try {
- return pm.getPackageUidAsUser(app, userHandle);
+ return pm.getPackageUidAsUser(app, userId);
} catch (NameNotFoundException e) {
return -1;
}
@@ -1116,7 +1116,7 @@ public class Vpn {
PackageManager pm = mContext.getPackageManager();
try {
ApplicationInfo appInfo =
- pm.getApplicationInfoAsUser(packageName, 0 /*flags*/, mUserHandle);
+ pm.getApplicationInfoAsUser(packageName, 0 /*flags*/, mUserId);
return appInfo.targetSdkVersion >= VERSION_CODES.Q;
} catch (NameNotFoundException unused) {
Log.w(TAG, "Can't find \"" + packageName + "\"");
@@ -1241,7 +1241,7 @@ public class Vpn {
mNetworkCapabilities.setOwnerUid(mOwnerUID);
mNetworkCapabilities.setAdministratorUids(new int[] {mOwnerUID});
- mNetworkCapabilities.setUids(createUserAndRestrictedProfilesRanges(mUserHandle,
+ mNetworkCapabilities.setUids(createUserAndRestrictedProfilesRanges(mUserId,
mConfig.allowedApplications, mConfig.disallowedApplications));
long token = Binder.clearCallingIdentity();
try {
@@ -1315,7 +1315,7 @@ public class Vpn {
enforceNotRestrictedUser();
ResolveInfo info = AppGlobals.getPackageManager().resolveService(intent,
- null, 0, mUserHandle);
+ null, 0, mUserId);
if (info == null) {
throw new SecurityException("Cannot find " + config.user);
}
@@ -1352,7 +1352,7 @@ public class Vpn {
Connection connection = new Connection();
if (!mContext.bindServiceAsUser(intent, connection,
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
- new UserHandle(mUserHandle))) {
+ new UserHandle(mUserId))) {
throw new IllegalStateException("Cannot bind " + config.user);
}
@@ -1427,10 +1427,10 @@ public class Vpn {
}
// Note: Return type guarantees results are deduped and sorted, which callers require.
- private SortedSet<Integer> getAppsUids(List<String> packageNames, int userHandle) {
+ private SortedSet<Integer> getAppsUids(List<String> packageNames, int userId) {
SortedSet<Integer> uids = new TreeSet<>();
for (String app : packageNames) {
- int uid = getAppUid(app, userHandle);
+ int uid = getAppUid(app, userId);
if (uid != -1) uids.add(uid);
}
return uids;
@@ -1444,22 +1444,22 @@ public class Vpn {
* the UID ranges will match the app list specified there. Otherwise, all UIDs
* in each user and profile will be included.
*
- * @param userHandle The userId to create UID ranges for along with any of its restricted
+ * @param userId The userId to create UID ranges for along with any of its restricted
* profiles.
* @param allowedApplications (optional) List of applications to allow.
* @param disallowedApplications (optional) List of applications to deny.
*/
@VisibleForTesting
- Set<UidRange> createUserAndRestrictedProfilesRanges(@UserIdInt int userHandle,
+ Set<UidRange> createUserAndRestrictedProfilesRanges(@UserIdInt int userId,
@Nullable List<String> allowedApplications,
@Nullable List<String> disallowedApplications) {
final Set<UidRange> ranges = new ArraySet<>();
// Assign the top-level user to the set of ranges
- addUserToRanges(ranges, userHandle, allowedApplications, disallowedApplications);
+ addUserToRanges(ranges, userId, allowedApplications, disallowedApplications);
// If the user can have restricted profiles, assign all its restricted profiles too
- if (canHaveRestrictedProfile(userHandle)) {
+ if (canHaveRestrictedProfile(userId)) {
final long token = Binder.clearCallingIdentity();
List<UserInfo> users;
try {
@@ -1468,7 +1468,7 @@ public class Vpn {
Binder.restoreCallingIdentity(token);
}
for (UserInfo user : users) {
- if (user.isRestricted() && (user.restrictedProfileParentId == userHandle)) {
+ if (user.isRestricted() && (user.restrictedProfileParentId == userId)) {
addUserToRanges(ranges, user.id, allowedApplications, disallowedApplications);
}
}
@@ -1485,18 +1485,18 @@ public class Vpn {
* in the user will be included.
*
* @param ranges {@link Set} of {@link UidRange}s to which to add.
- * @param userHandle The userId to add to {@param ranges}.
+ * @param userId The userId to add to {@param ranges}.
* @param allowedApplications (optional) allowlist of applications to include.
* @param disallowedApplications (optional) denylist of applications to exclude.
*/
@VisibleForTesting
- void addUserToRanges(@NonNull Set<UidRange> ranges, @UserIdInt int userHandle,
+ void addUserToRanges(@NonNull Set<UidRange> ranges, @UserIdInt int userId,
@Nullable List<String> allowedApplications,
@Nullable List<String> disallowedApplications) {
if (allowedApplications != null) {
// Add ranges covering all UIDs for allowedApplications.
int start = -1, stop = -1;
- for (int uid : getAppsUids(allowedApplications, userHandle)) {
+ for (int uid : getAppsUids(allowedApplications, userId)) {
if (start == -1) {
start = uid;
} else if (uid != stop + 1) {
@@ -1508,9 +1508,9 @@ public class Vpn {
if (start != -1) ranges.add(new UidRange(start, stop));
} else if (disallowedApplications != null) {
// Add all ranges for user skipping UIDs for disallowedApplications.
- final UidRange userRange = UidRange.createForUser(userHandle);
+ final UidRange userRange = UidRange.createForUser(userId);
int start = userRange.start;
- for (int uid : getAppsUids(disallowedApplications, userHandle)) {
+ for (int uid : getAppsUids(disallowedApplications, userId)) {
if (uid == start) {
start++;
} else {
@@ -1521,16 +1521,16 @@ public class Vpn {
if (start <= userRange.stop) ranges.add(new UidRange(start, userRange.stop));
} else {
// Add all UIDs for the user.
- ranges.add(UidRange.createForUser(userHandle));
+ ranges.add(UidRange.createForUser(userId));
}
}
// Returns the subset of the full list of active UID ranges the VPN applies to (mVpnUsers) that
- // apply to userHandle.
- static private List<UidRange> uidRangesForUser(int userHandle, Set<UidRange> existingRanges) {
+ // apply to userId.
+ private static List<UidRange> uidRangesForUser(int userId, Set<UidRange> existingRanges) {
// UidRange#createForUser returns the entire range of UIDs available to a macro-user.
// This is something like 0-99999 ; {@see UserHandle#PER_USER_RANGE}
- final UidRange userRange = UidRange.createForUser(userHandle);
+ final UidRange userRange = UidRange.createForUser(userId);
final List<UidRange> ranges = new ArrayList<>();
for (UidRange range : existingRanges) {
if (userRange.containsRange(range)) {
@@ -1545,15 +1545,15 @@ public class Vpn {
*
* <p>Should be called on primary ConnectivityService thread.
*/
- public void onUserAdded(int userHandle) {
+ public void onUserAdded(int userId) {
// If the user is restricted tie them to the parent user's VPN
- UserInfo user = UserManager.get(mContext).getUserInfo(userHandle);
- if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) {
+ UserInfo user = UserManager.get(mContext).getUserInfo(userId);
+ if (user.isRestricted() && user.restrictedProfileParentId == mUserId) {
synchronized(Vpn.this) {
final Set<UidRange> existingRanges = mNetworkCapabilities.getUids();
if (existingRanges != null) {
try {
- addUserToRanges(existingRanges, userHandle, mConfig.allowedApplications,
+ addUserToRanges(existingRanges, userId, mConfig.allowedApplications,
mConfig.disallowedApplications);
// ConnectivityService will call {@link #updateCapabilities} and apply
// those for VPN network.
@@ -1572,16 +1572,16 @@ public class Vpn {
*
* <p>Should be called on primary ConnectivityService thread.
*/
- public void onUserRemoved(int userHandle) {
+ public void onUserRemoved(int userId) {
// clean up if restricted
- UserInfo user = UserManager.get(mContext).getUserInfo(userHandle);
- if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) {
+ UserInfo user = UserManager.get(mContext).getUserInfo(userId);
+ if (user.isRestricted() && user.restrictedProfileParentId == mUserId) {
synchronized(Vpn.this) {
final Set<UidRange> existingRanges = mNetworkCapabilities.getUids();
if (existingRanges != null) {
try {
final List<UidRange> removedRanges =
- uidRangesForUser(userHandle, existingRanges);
+ uidRangesForUser(userId, existingRanges);
existingRanges.removeAll(removedRanges);
// ConnectivityService will call {@link #updateCapabilities} and
// apply those for VPN network.
@@ -1639,7 +1639,7 @@ public class Vpn {
final Set<UidRange> rangesToTellNetdToAdd;
if (enforce) {
final Set<UidRange> rangesThatShouldBeBlocked =
- createUserAndRestrictedProfilesRanges(mUserHandle,
+ createUserAndRestrictedProfilesRanges(mUserId,
/* allowedApplications */ null,
/* disallowedApplications */ exemptedPackages);
@@ -1909,7 +1909,7 @@ public class Vpn {
private void updateAlwaysOnNotification(DetailedState networkState) {
final boolean visible = (mAlwaysOn && networkState != DetailedState.CONNECTED);
- final UserHandle user = UserHandle.of(mUserHandle);
+ final UserHandle user = UserHandle.of(mUserId);
final long token = Binder.clearCallingIdentity();
try {
final NotificationManager notificationManager = NotificationManager.from(mContext);
@@ -2019,7 +2019,7 @@ public class Vpn {
private void enforceNotRestrictedUser() {
Binder.withCleanCallingIdentity(() -> {
final UserManager mgr = UserManager.get(mContext);
- final UserInfo user = mgr.getUserInfo(mUserHandle);
+ final UserInfo user = mgr.getUserInfo(mUserId);
if (user.isRestricted()) {
throw new SecurityException("Restricted users cannot configure VPNs");
@@ -2054,9 +2054,9 @@ public class Vpn {
public void startLegacyVpnPrivileged(VpnProfile profile, KeyStore keyStore,
LinkProperties egress) {
UserManager mgr = UserManager.get(mContext);
- UserInfo user = mgr.getUserInfo(mUserHandle);
+ UserInfo user = mgr.getUserInfo(mUserId);
if (user.isRestricted() || mgr.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN,
- new UserHandle(mUserHandle))) {
+ new UserHandle(mUserId))) {
throw new SecurityException("Restricted users cannot establish VPNs");
}
@@ -2984,14 +2984,14 @@ public class Vpn {
}
private void verifyCallingUidAndPackage(String packageName) {
- if (getAppUid(packageName, mUserHandle) != Binder.getCallingUid()) {
+ if (getAppUid(packageName, mUserId) != Binder.getCallingUid()) {
throw new SecurityException("Mismatched package and UID");
}
}
@VisibleForTesting
String getProfileNameForPackage(String packageName) {
- return Credentials.PLATFORM_VPN + mUserHandle + "_" + packageName;
+ return Credentials.PLATFORM_VPN + mUserId + "_" + packageName;
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 62a527b15c39..48efa5c31f2b 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -2357,6 +2357,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
"Invalid filename: " + targetName);
}
+ // Yell loudly if installers drop attribute installLocation when apps explicitly set.
+ if (apk.installLocation != PackageInfo.INSTALL_LOCATION_UNSPECIFIED) {
+ final String installerPackageName = getInstallerPackageName();
+ if (installerPackageName != null
+ && (params.installLocation != apk.installLocation)) {
+ Slog.wtf(TAG, installerPackageName
+ + " drops manifest attribute android:installLocation in " + targetName
+ + " for " + mPackageName);
+ }
+ }
+
final File targetFile = new File(stageDir, targetName);
resolveAndStageFileLocked(addedFile, targetFile, apk.splitName);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index e848bb7092da..0f0057905100 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -765,8 +765,6 @@ public class UserManagerService extends IUserManager.Stub {
return null;
}
- // TODO(b/157921703): replace by getAliveUsers() or remove (so callers
- // explicitly call the 3-booleans version)
public @NonNull List<UserInfo> getUsers(boolean excludeDying) {
return getUsers(/*excludePartial= */ true, excludeDying, /* excludePreCreated= */
true);
diff --git a/services/core/java/com/android/server/wm/BarController.java b/services/core/java/com/android/server/wm/BarController.java
index 8568d5fc1d64..4a90bbcc6623 100644
--- a/services/core/java/com/android/server/wm/BarController.java
+++ b/services/core/java/com/android/server/wm/BarController.java
@@ -16,88 +16,19 @@
package com.android.server.wm;
-import static com.android.server.wm.BarControllerProto.STATE;
-import static com.android.server.wm.BarControllerProto.TRANSIENT_STATE;
-
import android.annotation.NonNull;
-import android.app.StatusBarManager;
import android.graphics.Rect;
-import android.os.Handler;
-import android.os.Message;
-import android.os.SystemClock;
-import android.util.Slog;
-import android.util.proto.ProtoOutputStream;
-import android.view.View;
-import android.view.ViewRootImpl;
-import android.view.WindowManager;
-
-import com.android.server.LocalServices;
-import com.android.server.UiThread;
-import com.android.server.statusbar.StatusBarManagerInternal;
-
-import java.io.PrintWriter;
/**
* Controls state/behavior specific to a system bar window.
*/
public class BarController {
- private static final boolean DEBUG = false;
-
- private static final int TRANSIENT_BAR_NONE = 0;
- private static final int TRANSIENT_BAR_SHOW_REQUESTED = 1;
- private static final int TRANSIENT_BAR_SHOWING = 2;
- private static final int TRANSIENT_BAR_HIDING = 3;
-
- private static final int TRANSLUCENT_ANIMATION_DELAY_MS = 1000;
-
- private static final int MSG_NAV_BAR_VISIBILITY_CHANGED = 1;
-
- protected final String mTag;
- protected final int mDisplayId;
- private final int mTransientFlag;
- private final int mUnhideFlag;
- private final int mTranslucentFlag;
- private final int mTransparentFlag;
- private final int mStatusBarManagerId;
- private final int mTranslucentWmFlag;
private final int mWindowType;
- protected final Handler mHandler;
- private final Object mServiceAquireLock = new Object();
- private StatusBarManagerInternal mStatusBarInternal;
- protected WindowState mWin;
- private @StatusBarManager.WindowVisibleState int mState =
- StatusBarManager.WINDOW_STATE_SHOWING;
- private int mTransientBarState;
- private boolean mPendingShow;
- private long mLastTranslucent;
- private boolean mShowTransparent;
- private boolean mSetUnHideFlagWhenNextTransparent;
- private boolean mNoAnimationOnNextShow;
private final Rect mContentFrame = new Rect();
- private OnBarVisibilityChangedListener mVisibilityChangeListener;
-
- BarController(String tag, int displayId, int transientFlag, int unhideFlag, int translucentFlag,
- int statusBarManagerId, int windowType, int translucentWmFlag, int transparentFlag) {
- mTag = "BarController." + tag;
- mDisplayId = displayId;
- mTransientFlag = transientFlag;
- mUnhideFlag = unhideFlag;
- mTranslucentFlag = translucentFlag;
- mStatusBarManagerId = statusBarManagerId;
+ BarController(int windowType) {
mWindowType = windowType;
- mTranslucentWmFlag = translucentWmFlag;
- mTransparentFlag = transparentFlag;
- mHandler = new BarHandler();
- }
-
- void setWindow(WindowState win) {
- if (ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL) {
- // BarController gets replaced with InsetsPolicy in the full insets mode.
- return;
- }
- mWin = win;
}
/**
@@ -109,67 +40,6 @@ public class BarController {
mContentFrame.set(frame);
}
- void setShowTransparent(boolean transparent) {
- if (transparent != mShowTransparent) {
- mShowTransparent = transparent;
- mSetUnHideFlagWhenNextTransparent = transparent;
- mNoAnimationOnNextShow = true;
- }
- }
-
- void showTransient() {
- if (mWin != null) {
- setTransientBarState(TRANSIENT_BAR_SHOW_REQUESTED);
- }
- }
-
- boolean isTransientShowing() {
- return mTransientBarState == TRANSIENT_BAR_SHOWING;
- }
-
- boolean isTransientShowRequested() {
- return mTransientBarState == TRANSIENT_BAR_SHOW_REQUESTED;
- }
-
- boolean wasRecentlyTranslucent() {
- return (SystemClock.uptimeMillis() - mLastTranslucent) < TRANSLUCENT_ANIMATION_DELAY_MS;
- }
-
- void adjustSystemUiVisibilityLw(int oldVis, int vis) {
- if (mWin != null && mTransientBarState == TRANSIENT_BAR_SHOWING
- && (vis & mTransientFlag) == 0) {
- // sysui requests hide
- setTransientBarState(TRANSIENT_BAR_HIDING);
- setBarShowingLw(false);
- } else if (mWin != null && (oldVis & mUnhideFlag) != 0 && (vis & mUnhideFlag) == 0) {
- // sysui ready to unhide
- setBarShowingLw(true);
- }
- }
-
- int applyTranslucentFlagLw(WindowState win, int vis, int oldVis) {
- if (mWin != null) {
- if (win != null) {
- int fl = PolicyControl.getWindowFlags(win, null);
- if ((fl & mTranslucentWmFlag) != 0) {
- vis |= mTranslucentFlag;
- } else {
- vis &= ~mTranslucentFlag;
- }
- if ((fl & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
- && isTransparentAllowed(win)) {
- vis |= mTransparentFlag;
- } else {
- vis &= ~mTransparentFlag;
- }
- } else {
- vis = (vis & ~mTranslucentFlag) | (oldVis & mTranslucentFlag);
- vis = (vis & ~mTransparentFlag) | (oldVis & mTransparentFlag);
- }
- }
- return vis;
- }
-
private Rect getContentFrame(@NonNull WindowState win) {
final Rect rotatedContentFrame = win.mToken.getFixedRotationBarContentFrame(mWindowType);
return rotatedContentFrame != null ? rotatedContentFrame : mContentFrame;
@@ -188,212 +58,4 @@ public class BarController {
}
return win.letterboxNotIntersectsOrFullyContains(getContentFrame(win));
}
-
- boolean setBarShowingLw(final boolean show) {
- if (mWin == null) return false;
- if (show && mTransientBarState == TRANSIENT_BAR_HIDING) {
- mPendingShow = true;
- return false;
- }
- final boolean wasVis = mWin.isVisibleLw();
- final boolean wasAnim = mWin.isAnimatingLw();
- final boolean skipAnim = skipAnimation();
- final boolean change = show ? mWin.showLw(!mNoAnimationOnNextShow && !skipAnim)
- : mWin.hideLw(!mNoAnimationOnNextShow && !skipAnim);
- mNoAnimationOnNextShow = false;
- final int state = computeStateLw(wasVis, wasAnim, mWin, change);
- final boolean stateChanged = updateStateLw(state);
-
- if (change && (mVisibilityChangeListener != null)) {
- mHandler.obtainMessage(MSG_NAV_BAR_VISIBILITY_CHANGED, show ? 1 : 0, 0).sendToTarget();
- }
-
- return change || stateChanged;
- }
-
- void setOnBarVisibilityChangedListener(OnBarVisibilityChangedListener listener,
- boolean invokeWithState) {
- mVisibilityChangeListener = listener;
- if (invokeWithState) {
- // Optionally report the initial window state for initialization purposes
- mHandler.obtainMessage(MSG_NAV_BAR_VISIBILITY_CHANGED,
- (mState == StatusBarManager.WINDOW_STATE_SHOWING) ? 1 : 0, 0).sendToTarget();
- }
- }
-
- protected boolean skipAnimation() {
- return !mWin.isDrawn();
- }
-
- private @StatusBarManager.WindowVisibleState int computeStateLw(
- boolean wasVis, boolean wasAnim, WindowState win, boolean change) {
- if (win.isDrawn()) {
- final boolean vis = win.isVisibleLw();
- final boolean anim = win.isAnimatingLw();
- if (mState == StatusBarManager.WINDOW_STATE_HIDING && !change && !vis) {
- return StatusBarManager.WINDOW_STATE_HIDDEN;
- } else if (mState == StatusBarManager.WINDOW_STATE_HIDDEN && vis) {
- return StatusBarManager.WINDOW_STATE_SHOWING;
- } else if (change) {
- if (wasVis && vis && !wasAnim && anim) {
- return StatusBarManager.WINDOW_STATE_HIDING;
- } else {
- return StatusBarManager.WINDOW_STATE_SHOWING;
- }
- }
- }
- return mState;
- }
-
- private boolean updateStateLw(@StatusBarManager.WindowVisibleState final int state) {
- if (mWin != null && state != mState) {
- mState = state;
- if (DEBUG) Slog.d(mTag, "mState: " + StatusBarManager.windowStateToString(state));
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- StatusBarManagerInternal statusbar = getStatusBarInternal();
- if (statusbar != null) {
- statusbar.setWindowState(mDisplayId, mStatusBarManagerId, state);
- }
- }
- });
- return true;
- }
- return false;
- }
-
- boolean checkHiddenLw() {
- if (mWin != null && mWin.isDrawn()) {
- if (!mWin.isVisibleLw() && !mWin.isAnimatingLw()) {
- updateStateLw(StatusBarManager.WINDOW_STATE_HIDDEN);
- }
- if (mTransientBarState == TRANSIENT_BAR_HIDING && !mWin.isVisibleLw()) {
- // Finished animating out, clean up and reset style
- setTransientBarState(TRANSIENT_BAR_NONE);
- if (mPendingShow) {
- setBarShowingLw(true);
- mPendingShow = false;
- }
- return true;
- }
- }
- return false;
- }
-
- boolean checkShowTransientBarLw() {
- if (mTransientBarState == TRANSIENT_BAR_SHOWING) {
- if (DEBUG) Slog.d(mTag, "Not showing transient bar, already shown");
- return false;
- } else if (mTransientBarState == TRANSIENT_BAR_SHOW_REQUESTED) {
- if (DEBUG) Slog.d(mTag, "Not showing transient bar, already requested");
- return false;
- } else if (mWin == null) {
- if (DEBUG) Slog.d(mTag, "Not showing transient bar, bar doesn't exist");
- return false;
- } else if (mWin.isDisplayed()) {
- if (DEBUG) Slog.d(mTag, "Not showing transient bar, bar already visible");
- return false;
- } else {
- return true;
- }
- }
-
- int updateVisibilityLw(boolean transientAllowed, int oldVis, int vis) {
- if (mWin == null) return vis;
- if (isTransientShowing() || isTransientShowRequested()) { // transient bar requested
- if (transientAllowed) {
- vis |= mTransientFlag;
- if ((oldVis & mTransientFlag) == 0) {
- vis |= mUnhideFlag; // tell sysui we're ready to unhide
- }
- setTransientBarState(TRANSIENT_BAR_SHOWING); // request accepted
- } else {
- setTransientBarState(TRANSIENT_BAR_NONE); // request denied
- }
- }
- if (mShowTransparent) {
- vis |= mTransparentFlag;
- if (mSetUnHideFlagWhenNextTransparent) {
- vis |= mUnhideFlag;
- mSetUnHideFlagWhenNextTransparent = false;
- }
- }
- if (mTransientBarState != TRANSIENT_BAR_NONE) {
- vis |= mTransientFlag; // ignore clear requests until transition completes
- vis &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE; // never show transient bars in low profile
- }
- if ((vis & mTranslucentFlag) != 0 || (oldVis & mTranslucentFlag) != 0
- || ((vis | oldVis) & mTransparentFlag) != 0) {
- mLastTranslucent = SystemClock.uptimeMillis();
- }
- return vis;
- }
-
- private void setTransientBarState(int state) {
- if (mWin != null && state != mTransientBarState) {
- if (mTransientBarState == TRANSIENT_BAR_SHOWING || state == TRANSIENT_BAR_SHOWING) {
- mLastTranslucent = SystemClock.uptimeMillis();
- }
- mTransientBarState = state;
- if (DEBUG) Slog.d(mTag, "mTransientBarState: " + transientBarStateToString(state));
- }
- }
-
- protected StatusBarManagerInternal getStatusBarInternal() {
- synchronized (mServiceAquireLock) {
- if (mStatusBarInternal == null) {
- mStatusBarInternal = LocalServices.getService(StatusBarManagerInternal.class);
- }
- return mStatusBarInternal;
- }
- }
-
- private static String transientBarStateToString(int state) {
- if (state == TRANSIENT_BAR_HIDING) return "TRANSIENT_BAR_HIDING";
- if (state == TRANSIENT_BAR_SHOWING) return "TRANSIENT_BAR_SHOWING";
- if (state == TRANSIENT_BAR_SHOW_REQUESTED) return "TRANSIENT_BAR_SHOW_REQUESTED";
- if (state == TRANSIENT_BAR_NONE) return "TRANSIENT_BAR_NONE";
- throw new IllegalArgumentException("Unknown state " + state);
- }
-
- void dumpDebug(ProtoOutputStream proto, long fieldId) {
- final long token = proto.start(fieldId);
- proto.write(STATE, mState);
- proto.write(TRANSIENT_STATE, mTransientBarState);
- proto.end(token);
- }
-
- void dump(PrintWriter pw, String prefix) {
- if (mWin != null) {
- pw.print(prefix); pw.println(mTag);
- pw.print(prefix); pw.print(" "); pw.print("mState"); pw.print('=');
- pw.println(StatusBarManager.windowStateToString(mState));
- pw.print(prefix); pw.print(" "); pw.print("mTransientBar"); pw.print('=');
- pw.println(transientBarStateToString(mTransientBarState));
- pw.print(prefix); pw.print(" mContentFrame="); pw.println(mContentFrame);
- }
- }
-
- private class BarHandler extends Handler {
- BarHandler() {
- super(UiThread.getHandler().getLooper());
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_NAV_BAR_VISIBILITY_CHANGED:
- final boolean visible = msg.arg1 != 0;
- if (mVisibilityChangeListener != null) {
- mVisibilityChangeListener.onBarVisibilityChanged(visible);
- }
- break;
- }
- }
- }
-
- interface OnBarVisibilityChangedListener {
- void onBarVisibilityChanged(boolean visible);
- }
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 2ca849de7f22..0044d7498614 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -192,7 +192,6 @@ import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.SurfaceSession;
import android.view.View;
-import android.view.ViewRootImpl;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowManagerPolicyConstants.PointerEventListener;
@@ -3744,7 +3743,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
void statusBarVisibilityChanged(int visibility) {
mLastStatusBarVisibility = visibility;
- visibility = getDisplayPolicy().adjustSystemUiVisibilityLw(visibility);
updateStatusBarVisibilityLocked(visibility);
}
@@ -3769,32 +3767,16 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
void updateSystemUiVisibility(int visibility, int globalDiff) {
forAllWindows(w -> {
- try {
- final int curValue = w.mSystemUiVisibility;
- final int diff = (curValue ^ visibility) & globalDiff;
- final int newValue = (curValue & ~diff) | (visibility & diff);
- if (newValue != curValue) {
- w.mSeq++;
- w.mSystemUiVisibility = newValue;
- }
- if ((newValue != curValue || w.mAttrs.hasSystemUiListeners)
- && ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL) {
- w.mClient.dispatchSystemUiVisibilityChanged(w.mSeq,
- visibility, newValue, diff);
- }
- } catch (RemoteException e) {
- // so sorry
+ final int curValue = w.mSystemUiVisibility;
+ final int diff = (curValue ^ visibility) & globalDiff;
+ final int newValue = (curValue & ~diff) | (visibility & diff);
+ if (newValue != curValue) {
+ w.mSeq++;
+ w.mSystemUiVisibility = newValue;
}
}, true /* traverseTopToBottom */);
}
- void reevaluateStatusBarVisibility() {
- int visibility = getDisplayPolicy().adjustSystemUiVisibilityLw(mLastStatusBarVisibility);
- if (updateStatusBarVisibilityLocked(visibility)) {
- mWmService.mWindowPlacerLocked.requestTraversal();
- }
- }
-
void onWindowFreezeTimeout() {
Slog.w(TAG_WM, "Window freeze timeout expired.");
mWmService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_TIMEOUT;
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 779f6b2d30cc..572c9b306047 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -57,8 +57,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
-import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
@@ -66,13 +64,11 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BA
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
@@ -134,14 +130,13 @@ import android.graphics.Region;
import android.hardware.input.InputManager;
import android.hardware.power.Boost;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.util.ArraySet;
-import android.util.IntArray;
-import android.util.Pair;
import android.util.PrintWriterPrinter;
import android.util.Slog;
import android.util.SparseArray;
@@ -199,7 +194,6 @@ import java.util.function.Consumer;
*/
public class DisplayPolicy {
private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayPolicy" : TAG_WM;
- private static final boolean DEBUG = false;
private static final boolean ALTERNATE_CAR_MODE_NAV_SIZE = false;
@@ -221,18 +215,6 @@ public class DisplayPolicy {
/** Use the transit animation in style resource (see {@link #selectAnimation}). */
static final int ANIMATION_STYLEABLE = 0;
- /**
- * These are the system UI flags that, when changing, can cause the layout
- * of the screen to change.
- */
- private static final int SYSTEM_UI_CHANGING_LAYOUT =
- View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_FULLSCREEN
- | View.STATUS_BAR_TRANSLUCENT
- | View.NAVIGATION_BAR_TRANSLUCENT
- | View.STATUS_BAR_TRANSPARENT
- | View.NAVIGATION_BAR_TRANSPARENT;
-
private static final int[] SHOW_TYPES_FOR_SWIPE = {ITYPE_NAVIGATION_BAR, ITYPE_STATUS_BAR};
private static final int[] SHOW_TYPES_FOR_PANIC = {ITYPE_NAVIGATION_BAR};
@@ -327,21 +309,10 @@ public class DisplayPolicy {
private boolean mLastImmersiveMode;
- private final StatusBarController mStatusBarController;
-
+ private StatusBarManagerInternal mStatusBarInternal;
+ private final BarController mStatusBarController;
private final BarController mNavigationBarController;
- private final BarController.OnBarVisibilityChangedListener mNavBarVisibilityListener =
- new BarController.OnBarVisibilityChangedListener() {
- @Override
- public void onBarVisibilityChanged(boolean visible) {
- if (mAccessibilityManager == null) {
- return;
- }
- mAccessibilityManager.notifyAccessibilityButtonVisibilityChanged(visible);
- }
- };
-
// The windows we were told about in focusChanged.
private WindowState mFocusedWindow;
private WindowState mLastFocusedWindow;
@@ -353,15 +324,8 @@ public class DisplayPolicy {
private boolean mLastNavVisible;
private boolean mLastNavTranslucent;
private boolean mLastNavAllowedHidden;
- private boolean mLastNotificationShadeForcesShowingNavigation;
-
- int mLastSystemUiFlags;
- // Bits that we are in the process of clearing, so we want to prevent
- // them from being set by applications until everything has been updated
- // to have them clear.
- private int mResettingSystemUiFlags = 0;
- // Bits that we are currently always keeping cleared.
- private int mForceClearedSystemUiFlags = 0;
+
+ private int mLastDisableFlags;
private int mLastAppearance;
private int mLastFullscreenAppearance;
private int mLastDockedAppearance;
@@ -430,6 +394,8 @@ public class DisplayPolicy {
private final GestureNavigationSettingsObserver mGestureNavigationSettingsObserver;
+ private final WindowManagerInternal.AppTransitionListener mAppTransitionListener;
+
private class PolicyHandler extends Handler {
PolicyHandler(Looper looper) {
@@ -472,16 +438,9 @@ public class DisplayPolicy {
mLock = service.getWindowManagerLock();
final int displayId = displayContent.getDisplayId();
- mStatusBarController = new StatusBarController(displayId);
- mNavigationBarController = new BarController("NavigationBar",
- displayId,
- View.NAVIGATION_BAR_TRANSIENT,
- View.NAVIGATION_BAR_UNHIDE,
- View.NAVIGATION_BAR_TRANSLUCENT,
- StatusBarManager.WINDOW_NAVIGATION_BAR,
- TYPE_NAVIGATION_BAR,
- FLAG_TRANSLUCENT_NAVIGATION,
- View.NAVIGATION_BAR_TRANSPARENT);
+
+ mStatusBarController = new BarController(TYPE_STATUS_BAR);
+ mNavigationBarController = new BarController(TYPE_NAVIGATION_BAR);
final Resources r = mContext.getResources();
mCarDockEnablesAccelerometer = r.getBoolean(R.bool.config_carDockEnablesAccelerometer);
@@ -612,8 +571,58 @@ public class DisplayPolicy {
}
});
displayContent.registerPointerEventListener(mSystemGestures);
- displayContent.mAppTransition.registerListenerLocked(
- mStatusBarController.getAppTransitionListener());
+ mAppTransitionListener = new WindowManagerInternal.AppTransitionListener() {
+
+ private Runnable mAppTransitionPending = () -> {
+ StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
+ if (statusBar != null) {
+ statusBar.appTransitionPending(displayId);
+ }
+ };
+
+ private Runnable mAppTransitionCancelled = () -> {
+ StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
+ if (statusBar != null) {
+ statusBar.appTransitionCancelled(displayId);
+ }
+ };
+
+ private Runnable mAppTransitionFinished = () -> {
+ StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
+ if (statusBar != null) {
+ statusBar.appTransitionFinished(displayId);
+ }
+ };
+
+ @Override
+ public void onAppTransitionPendingLocked() {
+ mHandler.post(mAppTransitionPending);
+ }
+
+ @Override
+ public int onAppTransitionStartingLocked(int transit, long duration,
+ long statusBarAnimationStartTime, long statusBarAnimationDuration) {
+ mHandler.post(() -> {
+ StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
+ if (statusBar != null) {
+ statusBar.appTransitionStarting(mContext.getDisplayId(),
+ statusBarAnimationStartTime, statusBarAnimationDuration);
+ }
+ });
+ return 0;
+ }
+
+ @Override
+ public void onAppTransitionCancelledLocked(int transit) {
+ mHandler.post(mAppTransitionCancelled);
+ }
+
+ @Override
+ public void onAppTransitionFinishedLocked(IBinder token) {
+ mHandler.post(mAppTransitionFinished);
+ }
+ };
+ displayContent.mAppTransition.registerListenerLocked(mAppTransitionListener);
mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext, looper,
mService.mVrModeEnabled);
@@ -1066,7 +1075,6 @@ public class DisplayPolicy {
break;
case TYPE_STATUS_BAR:
mStatusBar = win;
- mStatusBarController.setWindow(win);
final TriConsumer<DisplayFrames, WindowState, Rect> frameProvider =
(displayFrames, windowState, rect) -> {
rect.bottom = rect.top + getStatusBarHeight(displayFrames);
@@ -1077,9 +1085,6 @@ public class DisplayPolicy {
break;
case TYPE_NAVIGATION_BAR:
mNavigationBar = win;
- mNavigationBarController.setWindow(win);
- mNavigationBarController.setOnBarVisibilityChangedListener(
- mNavBarVisibilityListener, true);
mDisplayContent.setInsetProvider(ITYPE_NAVIGATION_BAR, win,
(displayFrames, windowState, inOutFrame) -> {
@@ -1135,12 +1140,10 @@ public class DisplayPolicy {
switch (insetsType) {
case ITYPE_STATUS_BAR:
mStatusBarAlt = win;
- mStatusBarController.setWindow(mStatusBarAlt);
mStatusBarAltPosition = getAltBarPosition(attrs);
break;
case ITYPE_NAVIGATION_BAR:
mNavigationBarAlt = win;
- mNavigationBarController.setWindow(mNavigationBarAlt);
mNavigationBarAltPosition = getAltBarPosition(attrs);
break;
}
@@ -1210,12 +1213,10 @@ public class DisplayPolicy {
if (mStatusBar == win || mStatusBarAlt == win) {
mStatusBar = null;
mStatusBarAlt = null;
- mStatusBarController.setWindow(null);
mDisplayContent.setInsetProvider(ITYPE_STATUS_BAR, null, null);
} else if (mNavigationBar == win || mNavigationBarAlt == win) {
mNavigationBar = null;
mNavigationBarAlt = null;
- mNavigationBarController.setWindow(null);
mDisplayContent.setInsetProvider(ITYPE_NAVIGATION_BAR, null, null);
} else if (mNotificationShade == win) {
mNotificationShade = null;
@@ -1235,7 +1236,7 @@ public class DisplayPolicy {
}
@VisibleForTesting
- StatusBarController getStatusBarController() {
+ BarController getStatusBarController() {
return mStatusBarController;
}
@@ -1368,25 +1369,6 @@ public class DisplayPolicy {
}
/**
- * Called when a new system UI visibility is being reported, allowing
- * the policy to adjust what is actually reported.
- * @param visibility The raw visibility reported by the status bar.
- * @return The new desired visibility.
- */
- public int adjustSystemUiVisibilityLw(int visibility) {
- mStatusBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
- mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
-
- // Reset any bits in mForceClearingStatusBarVisibility that
- // are now clear.
- mResettingSystemUiFlags &= visibility;
- // Clear any bits in the new visibility that are currently being
- // force cleared, before reporting it.
- return visibility & ~mResettingSystemUiFlags
- & ~mForceClearedSystemUiFlags;
- }
-
- /**
* @return true if the system bars are forced to stay visible
*/
public boolean areSystemBarsForcedShownLw(WindowState windowState) {
@@ -1481,16 +1463,6 @@ public class DisplayPolicy {
return mForceShowSystemBars;
}
- private final Runnable mClearHideNavigationFlag = new Runnable() {
- @Override
- public void run() {
- synchronized (mLock) {
- mForceClearedSystemUiFlags &= ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
- mDisplayContent.reevaluateStatusBarVisibility();
- }
- }
- };
-
/**
* Input handler used while nav bar is hidden. Captures any touch on the screen,
* to determine when the nav bar should be shown and prevent applications from
@@ -1515,32 +1487,6 @@ public class DisplayPolicy {
return;
}
showSystemBars();
- // Any user activity always causes us to show the
- // navigation controls, if they had been hidden.
- // We also clear the low profile and only content
- // flags so that tapping on the screen will atomically
- // restore all currently hidden screen decorations.
- int newVal = mResettingSystemUiFlags
- | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_LOW_PROFILE
- | View.SYSTEM_UI_FLAG_FULLSCREEN;
- if (mResettingSystemUiFlags != newVal) {
- mResettingSystemUiFlags = newVal;
- changed = true;
- }
- // We don't allow the system's nav bar to be hidden
- // again for 1 second, to prevent applications from
- // spamming us and keeping it from being shown.
- newVal = mForceClearedSystemUiFlags
- | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
- if (mForceClearedSystemUiFlags != newVal) {
- mForceClearedSystemUiFlags = newVal;
- changed = true;
- mHandler.postDelayed(mClearHideNavigationFlag, 1000);
- }
- if (changed) {
- mDisplayContent.reevaluateStatusBarVisibility();
- }
}
}
}
@@ -1594,12 +1540,12 @@ public class DisplayPolicy {
contentFrame -> layoutNavigationBar(displayFrames,
mDisplayContent.getConfiguration().uiMode, mLastNavVisible,
mLastNavTranslucent, mLastNavAllowedHidden,
- mLastNotificationShadeForcesShowingNavigation, contentFrame));
+ contentFrame));
}
if (mStatusBar != null) {
simulateLayoutDecorWindow(mStatusBar, displayFrames, insetsState,
simulatedWindowFrames, barContentFrames,
- contentFrame -> layoutStatusBar(displayFrames, mLastSystemUiFlags,
+ contentFrame -> layoutStatusBar(displayFrames, mLastAppearance,
contentFrame));
}
layoutScreenDecorWindows(displayFrames, simulatedWindowFrames);
@@ -1621,25 +1567,17 @@ public class DisplayPolicy {
// For purposes of putting out fake window up to steal focus, we will
// drive nav being hidden only by whether it is requested.
- final int sysui = mLastSystemUiFlags;
+ final int appearance = mLastAppearance;
final int behavior = mLastBehavior;
final InsetsSourceProvider provider =
mDisplayContent.getInsetsStateController().peekSourceProvider(ITYPE_NAVIGATION_BAR);
boolean navVisible = provider != null ? provider.isClientVisible()
: InsetsState.getDefaultVisibility(ITYPE_NAVIGATION_BAR);
- boolean navTranslucent = (sysui
- & (View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT)) != 0;
- boolean immersive = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0
- || (behavior & BEHAVIOR_SHOW_BARS_BY_SWIPE) != 0;
- boolean immersiveSticky = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0
- || (behavior & BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE) != 0;
+ boolean navTranslucent = (appearance & APPEARANCE_OPAQUE_NAVIGATION_BARS) == 0;
+ boolean immersive = (behavior & BEHAVIOR_SHOW_BARS_BY_SWIPE) != 0;
+ boolean immersiveSticky = (behavior & BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE) != 0;
boolean navAllowedHidden = immersive || immersiveSticky;
navTranslucent &= !immersiveSticky; // transient trumps translucent
- boolean isKeyguardShowing = isKeyguardShowing() && !isKeyguardOccluded();
- boolean notificationShadeForcesShowingNavigation =
- !isKeyguardShowing && mNotificationShade != null
- && (mNotificationShade.getAttrs().privateFlags
- & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
updateHideNavInputEventReceiver();
@@ -1647,21 +1585,15 @@ public class DisplayPolicy {
// be hidden (because of the screen aspect ratio), then take that into account.
navVisible |= !canHideNavigationBar();
- boolean updateSysUiVisibility = layoutNavigationBar(displayFrames, uiMode, navVisible,
- navTranslucent, navAllowedHidden, notificationShadeForcesShowingNavigation,
- null /* simulatedContentFrame */);
+ layoutNavigationBar(displayFrames, uiMode, navVisible,
+ navTranslucent, navAllowedHidden, null /* simulatedContentFrame */);
if (DEBUG_LAYOUT) Slog.i(TAG, "mDock rect:" + displayFrames.mDock);
- updateSysUiVisibility |= layoutStatusBar(displayFrames, sysui,
- null /* simulatedContentFrame */);
- if (updateSysUiVisibility) {
- updateSystemUiVisibilityLw();
- }
+ layoutStatusBar(displayFrames, appearance, null /* simulatedContentFrame */);
layoutScreenDecorWindows(displayFrames, null /* simulatedFrames */);
postAdjustDisplayFrames(displayFrames);
mLastNavVisible = navVisible;
mLastNavTranslucent = navTranslucent;
mLastNavAllowedHidden = navAllowedHidden;
- mLastNotificationShadeForcesShowingNavigation = notificationShadeForcesShowingNavigation;
}
void updateHideNavInputEventReceiver() {
@@ -1825,11 +1757,11 @@ public class DisplayPolicy {
displayFrames.mContent.set(dockFrame);
}
- private boolean layoutStatusBar(DisplayFrames displayFrames, int sysui,
+ private void layoutStatusBar(DisplayFrames displayFrames, int appearance,
Rect simulatedContentFrame) {
// decide where the status bar goes ahead of time
if (mStatusBar == null) {
- return false;
+ return;
}
// apply any status bar insets
getRotatedWindowBounds(displayFrames, mStatusBar, sTmpStatusFrame);
@@ -1860,10 +1792,9 @@ public class DisplayPolicy {
mStatusBarController.setContentFrame(sTmpRect);
}
- boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0
- || mDisplayContent.getInsetsPolicy().isTransient(ITYPE_STATUS_BAR);
- boolean statusBarTranslucent = (sysui
- & (View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT)) != 0;
+ boolean statusBarTransient =
+ mDisplayContent.getInsetsPolicy().isTransient(ITYPE_STATUS_BAR);
+ boolean statusBarTranslucent = (appearance & APPEARANCE_OPAQUE_STATUS_BARS) == 0;
// If the status bar is hidden, we don't want to cause windows behind it to scroll.
if (mStatusBar.isVisibleLw() && !statusBarTransient) {
@@ -1879,8 +1810,7 @@ public class DisplayPolicy {
"dock=%s content=%s cur=%s", dockFrame.toString(),
displayFrames.mContent.toString(), displayFrames.mCurrent.toString()));
- if (!statusBarTranslucent && !mStatusBarController.wasRecentlyTranslucent()
- && !mStatusBar.isAnimatingLw()) {
+ if (!statusBarTranslucent && !mStatusBar.isAnimatingLw()) {
// If the opaque status bar is currently requested to be visible, and not in the
// process of animating on or off, then we can tell the app that it is covered by
@@ -1888,18 +1818,17 @@ public class DisplayPolicy {
displayFrames.mSystem.top = displayFrames.mStable.top;
}
}
- return mStatusBarController.checkHiddenLw();
}
- private boolean layoutNavigationBar(DisplayFrames displayFrames, int uiMode, boolean navVisible,
- boolean navTranslucent, boolean navAllowedHidden,
- boolean statusBarForcesShowingNavigation, Rect simulatedContentFrame) {
+ private void layoutNavigationBar(DisplayFrames displayFrames, int uiMode, boolean navVisible,
+ boolean navTranslucent, boolean navAllowedHidden, Rect simulatedContentFrame) {
if (mNavigationBar == null) {
- return false;
+ return;
}
final Rect navigationFrame = sTmpNavFrame;
- boolean transientNavBarShowing = mNavigationBarController.isTransientShowing();
+ boolean navBarTransient =
+ mDisplayContent.getInsetsPolicy().isTransient(ITYPE_NAVIGATION_BAR);
// Force the navigation bar to its appropriate place and size. We need to do this directly,
// instead of relying on it to bubble up from the nav bar, because this needs to change
// atomically with screen rotations.
@@ -1924,18 +1853,11 @@ public class DisplayPolicy {
- getNavigationBarHeight(rotation, uiMode);
navigationFrame.top = topNavBar;
displayFrames.mStable.bottom = displayFrames.mStableFullscreen.bottom = top;
- if (transientNavBarShowing) {
- mNavigationBarController.setBarShowingLw(true);
- } else if (navVisible) {
- mNavigationBarController.setBarShowingLw(true);
+ if (navVisible && !navBarTransient) {
dockFrame.bottom = displayFrames.mRestricted.bottom = top;
- } else {
- // We currently want to hide the navigation UI - unless we expanded the status bar.
- mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
}
if (navVisible && !navTranslucent && !navAllowedHidden
- && !mNavigationBar.isAnimatingLw()
- && !mNavigationBarController.wasRecentlyTranslucent()) {
+ && !mNavigationBar.isAnimatingLw()) {
// If the opaque nav bar is currently requested to be visible and not in the process
// of animating on or off, then we can tell the app that it is covered by it.
displayFrames.mSystem.bottom = top;
@@ -1946,18 +1868,11 @@ public class DisplayPolicy {
- getNavigationBarWidth(rotation, uiMode);
navigationFrame.left = left;
displayFrames.mStable.right = displayFrames.mStableFullscreen.right = left;
- if (transientNavBarShowing) {
- mNavigationBarController.setBarShowingLw(true);
- } else if (navVisible) {
- mNavigationBarController.setBarShowingLw(true);
+ if (navVisible && !navBarTransient) {
dockFrame.right = displayFrames.mRestricted.right = left;
- } else {
- // We currently want to hide the navigation UI - unless we expanded the status bar.
- mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
}
if (navVisible && !navTranslucent && !navAllowedHidden
- && !mNavigationBar.isAnimatingLw()
- && !mNavigationBarController.wasRecentlyTranslucent()) {
+ && !mNavigationBar.isAnimatingLw()) {
// If the nav bar is currently requested to be visible, and not in the process of
// animating on or off, then we can tell the app that it is covered by it.
displayFrames.mSystem.right = left;
@@ -1968,18 +1883,11 @@ public class DisplayPolicy {
+ getNavigationBarWidth(rotation, uiMode);
navigationFrame.right = right;
displayFrames.mStable.left = displayFrames.mStableFullscreen.left = right;
- if (transientNavBarShowing) {
- mNavigationBarController.setBarShowingLw(true);
- } else if (navVisible) {
- mNavigationBarController.setBarShowingLw(true);
+ if (navVisible && !navBarTransient) {
dockFrame.left = displayFrames.mRestricted.left = right;
- } else {
- // We currently want to hide the navigation UI - unless we expanded the status bar.
- mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
}
if (navVisible && !navTranslucent && !navAllowedHidden
- && !mNavigationBar.isAnimatingLw()
- && !mNavigationBarController.wasRecentlyTranslucent()) {
+ && !mNavigationBar.isAnimatingLw()) {
// If the nav bar is currently requested to be visible, and not in the process of
// animating on or off, then we can tell the app that it is covered by it.
displayFrames.mSystem.left = right;
@@ -2008,7 +1916,6 @@ public class DisplayPolicy {
}
if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + navigationFrame);
- return mNavigationBarController.checkHiddenLw();
}
private boolean canReceiveInput(WindowState win) {
@@ -2059,9 +1966,6 @@ public class DisplayPolicy {
dcf.setEmpty();
windowFrames.setParentFrameWasClippedByDisplayCutout(false);
- final boolean hasNavBar = hasNavigationBar() && mNavigationBar != null
- && mNavigationBar.isVisibleLw();
-
final int adjust = sim & SOFT_INPUT_MASK_ADJUST;
final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) == FLAG_LAYOUT_IN_SCREEN;
@@ -2407,53 +2311,27 @@ public class DisplayPolicy {
+ " top=" + mTopFullscreenOpaqueWindowState);
final boolean forceShowStatusBar = (getStatusBar().getAttrs().privateFlags
& PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR) != 0;
- final boolean notificationShadeForcesShowingNavigation =
- mNotificationShade != null
- && (mNotificationShade.getAttrs().privateFlags
- & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
boolean topAppHidesStatusBar = topAppHidesStatusBar();
if (mForceStatusBar || forceShowStatusBar) {
if (DEBUG_LAYOUT) Slog.v(TAG, "Showing status bar: forced");
- if (mStatusBarController.setBarShowingLw(true)) {
- changes |= FINISH_LAYOUT_REDO_LAYOUT;
- }
// Maintain fullscreen layout until incoming animation is complete.
topIsFullscreen = mTopIsFullscreen && mStatusBar.isAnimatingLw();
- // Transient status bar is not allowed if notification shade is expecting the
- // navigation keys from the user.
- if (notificationShadeForcesShowingNavigation
- && mStatusBarController.isTransientShowing()) {
- mStatusBarController.updateVisibilityLw(false /*transientAllowed*/,
- mLastSystemUiFlags, mLastSystemUiFlags);
- }
} else if (mTopFullscreenOpaqueWindowState != null) {
topIsFullscreen = topAppHidesStatusBar;
// The subtle difference between the window for mTopFullscreenOpaqueWindowState
// and mTopIsFullscreen is that mTopIsFullscreen is set only if the window
// has the FLAG_FULLSCREEN set. Not sure if there is another way that to be the
// case though.
- if (mStatusBarController.isTransientShowing()) {
- if (mStatusBarController.setBarShowingLw(true)) {
- changes |= FINISH_LAYOUT_REDO_LAYOUT;
- }
- } else if (topIsFullscreen && !mDisplayContent.getDefaultTaskDisplayArea()
+ if (!topIsFullscreen || mDisplayContent.getDefaultTaskDisplayArea()
.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
- if (DEBUG_LAYOUT) Slog.v(TAG, "** HIDING status bar");
- if (mStatusBarController.setBarShowingLw(false)) {
- changes |= FINISH_LAYOUT_REDO_LAYOUT;
- } else {
- if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar already hiding");
- }
- } else {
- if (DEBUG_LAYOUT) Slog.v(TAG, "** SHOWING status bar: top is not fullscreen");
- if (mStatusBarController.setBarShowingLw(true)) {
- changes |= FINISH_LAYOUT_REDO_LAYOUT;
- }
topAppHidesStatusBar = false;
}
}
- mStatusBarController.setTopAppHidesStatusBar(topAppHidesStatusBar);
+ StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
+ if (statusBar != null) {
+ statusBar.setTopAppHidesStatusBar(topAppHidesStatusBar);
+ }
}
if (mTopIsFullscreen != topIsFullscreen) {
@@ -2464,7 +2342,7 @@ public class DisplayPolicy {
mTopIsFullscreen = topIsFullscreen;
}
- if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) {
+ if (updateSystemUiVisibilityLw()) {
// If the navigation bar has been hidden or shown, we need to do another
// layout pass to update that window.
changes |= FINISH_LAYOUT_REDO_LAYOUT;
@@ -2497,7 +2375,6 @@ public class DisplayPolicy {
Slog.d(TAG, "attr: " + attrs + " request: " + request);
}
return (fl & LayoutParams.FLAG_FULLSCREEN) != 0
- || (sysui & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0
|| (request != null && !request.isVisible());
}
@@ -2910,7 +2787,7 @@ public class DisplayPolicy {
if (mDisplayContent.isDefaultDisplay) {
mService.mPolicy.onDefaultDisplayFocusChangedLw(newFocus);
}
- if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) {
+ if (updateSystemUiVisibilityLw()) {
// If the navigation bar has been hidden or shown, we need to do another
// layout pass to update that window.
return FINISH_LAYOUT_REDO_LAYOUT;
@@ -2977,17 +2854,20 @@ public class DisplayPolicy {
}
void resetSystemUiVisibilityLw() {
- mLastSystemUiFlags = 0;
+ mLastDisableFlags = 0;
updateSystemUiVisibilityLw();
}
- int updateSystemUiVisibilityLw() {
+ /**
+ * @return {@code true} if the update may affect the layout.
+ */
+ boolean updateSystemUiVisibilityLw() {
// If there is no window focused, there will be nobody to handle the events
// anyway, so just hang on in whatever state we're in until things settle down.
WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow
: mTopFullscreenOpaqueWindowState;
if (winCandidate == null) {
- return 0;
+ return false;
}
// The immersive mode confirmation should never affect the system bar visibility, otherwise
@@ -3003,7 +2883,7 @@ public class DisplayPolicy {
: lastFocusCanReceiveKeys ? mLastFocusedWindow
: mTopFullscreenOpaqueWindowState;
if (winCandidate == null) {
- return 0;
+ return false;
}
}
final WindowState win = winCandidate;
@@ -3011,17 +2891,9 @@ public class DisplayPolicy {
mDisplayContent.getInsetsPolicy().updateBarControlTarget(win);
- int tmpVisibility = PolicyControl.getSystemUiVisibility(win, null)
- & ~mResettingSystemUiFlags
- & ~mForceClearedSystemUiFlags;
- if (mForcingShowNavBar && win.getSurfaceLayer() < mForcingShowNavBarLayer) {
- tmpVisibility
- &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS);
- }
-
- final int fullscreenAppearance = updateLightStatusBarAppearanceLw(0 /* vis */,
+ final int fullscreenAppearance = updateLightStatusBarLw(0 /* vis */,
mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState);
- final int dockedAppearance = updateLightStatusBarAppearanceLw(0 /* vis */,
+ final int dockedAppearance = updateLightStatusBarLw(0 /* vis */,
mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState);
final boolean inSplitScreen =
mService.mRoot.getDefaultTaskDisplayArea().isSplitScreenModeActivated();
@@ -3034,32 +2906,24 @@ public class DisplayPolicy {
mService.getStackBounds(inSplitScreen ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
: WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_UNDEFINED, mNonDockedStackBounds);
- final Pair<Integer, WindowState> result =
- updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
- final int visibility = result.first;
- final WindowState navColorWin = result.second;
+ final int disableFlags = win.getSystemUiVisibility() & StatusBarManager.DISABLE_MASK;
+ final int opaqueAppearance = updateSystemBarsLw(win, disableFlags);
+ final WindowState navColorWin = chooseNavigationColorWindowLw(
+ mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState,
+ mDisplayContent.mInputMethodWindow, mNavigationBarPosition);
final boolean isNavbarColorManagedByIme =
navColorWin != null && navColorWin == mDisplayContent.mInputMethodWindow;
- final int opaqueAppearance = InsetsFlags.getAppearance(visibility)
- & (APPEARANCE_OPAQUE_STATUS_BARS | APPEARANCE_OPAQUE_NAVIGATION_BARS);
- final int appearance = updateLightNavigationBarAppearanceLw(
+ final int appearance = updateLightNavigationBarLw(
win.mAttrs.insetsFlags.appearance, mTopFullscreenOpaqueWindowState,
mTopFullscreenOpaqueOrDimmingWindowState,
mDisplayContent.mInputMethodWindow, navColorWin) | opaqueAppearance;
- final int diff = visibility ^ mLastSystemUiFlags;
- final InsetsPolicy insetsPolicy = getInsetsPolicy();
- final boolean isFullscreen = (visibility & (View.SYSTEM_UI_FLAG_FULLSCREEN
- | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)) != 0
- || (PolicyControl.getWindowFlags(win, win.mAttrs) & FLAG_FULLSCREEN) != 0
- || (getStatusBar() != null && insetsPolicy.isHidden(ITYPE_STATUS_BAR))
- || (getNavigationBar() != null && insetsPolicy.isHidden(
- ITYPE_NAVIGATION_BAR));
+ final InsetsState requestedInsets = win.getRequestedInsetsState();
final int behavior = win.mAttrs.insetsFlags.behavior;
- final boolean isImmersive = (visibility & (View.SYSTEM_UI_FLAG_IMMERSIVE
- | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)) != 0
- || behavior == BEHAVIOR_SHOW_BARS_BY_SWIPE
+ final boolean isImmersive = behavior == BEHAVIOR_SHOW_BARS_BY_SWIPE
|| behavior == BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
- if (diff == 0
+ final boolean isFullscreen = !requestedInsets.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR)
+ || !requestedInsets.getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR);
+ if (mLastDisableFlags == disableFlags
&& mLastAppearance == appearance
&& mLastFullscreenAppearance == fullscreenAppearance
&& mLastDockedAppearance == dockedAppearance
@@ -3068,14 +2932,10 @@ public class DisplayPolicy {
&& mLastFocusIsImmersive == isImmersive
&& mLastNonDockedStackBounds.equals(mNonDockedStackBounds)
&& mLastDockedStackBounds.equals(mDockedStackBounds)) {
- return 0;
+ return false;
}
- // Obtains which types should show transient and which types should abort transient.
- // If there is no transient state change, this pair will contain two empty arrays.
- final Pair<int[], int[]> transientState = getTransientState(visibility, mLastSystemUiFlags);
-
- mLastSystemUiFlags = visibility;
+ mLastDisableFlags = disableFlags;
mLastAppearance = appearance;
mLastFullscreenAppearance = fullscreenAppearance;
mLastDockedAppearance = dockedAppearance;
@@ -3097,50 +2957,17 @@ public class DisplayPolicy {
StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
if (statusBar != null) {
final int displayId = getDisplayId();
- statusBar.setDisableFlags(displayId, visibility & StatusBarManager.DISABLE_MASK,
- cause);
- if (transientState.first.length > 0) {
- statusBar.showTransient(displayId, transientState.first);
- }
- if (transientState.second.length > 0) {
- statusBar.abortTransient(displayId, transientState.second);
- }
+ statusBar.setDisableFlags(displayId, disableFlags, cause);
statusBar.onSystemBarAppearanceChanged(displayId, appearance,
appearanceRegions, isNavbarColorManagedByIme);
statusBar.topAppWindowChanged(displayId, isFullscreen, isImmersive);
- // TODO(b/118118435): Remove this after removing system UI visibilities.
- synchronized (mLock) {
- mDisplayContent.statusBarVisibilityChanged(
- visibility & ~(View.STATUS_BAR_UNHIDE | View.NAVIGATION_BAR_UNHIDE));
- }
}
});
- return diff;
- }
-
- private static Pair<int[], int[]> getTransientState(int vis, int oldVis) {
- final IntArray typesToShow = new IntArray(0);
- final IntArray typesToAbort = new IntArray(0);
- updateTransientState(vis, oldVis, View.STATUS_BAR_TRANSIENT, ITYPE_STATUS_BAR, typesToShow,
- typesToAbort);
- updateTransientState(vis, oldVis, View.NAVIGATION_BAR_TRANSIENT,
- ITYPE_NAVIGATION_BAR, typesToShow, typesToAbort);
- return Pair.create(typesToShow.toArray(), typesToAbort.toArray());
- }
-
- private static void updateTransientState(int vis, int oldVis, int transientFlag,
- @InternalInsetsType int type, IntArray typesToShow, IntArray typesToAbort) {
- final boolean wasTransient = (oldVis & transientFlag) != 0;
- final boolean isTransient = (vis & transientFlag) != 0;
- if (!wasTransient && isTransient) {
- typesToShow.add(type);
- } else if (wasTransient && !isTransient) {
- typesToAbort.add(type);
- }
+ return true;
}
- private int updateLightStatusBarAppearanceLw(@Appearance int appearance, WindowState opaque,
+ private int updateLightStatusBarLw(@Appearance int appearance, WindowState opaque,
WindowState opaqueOrDimming) {
final boolean onKeyguard = isKeyguardShowing() && !isKeyguardOccluded();
final WindowState statusColorWin = onKeyguard ? mNotificationShade : opaqueOrDimming;
@@ -3207,24 +3034,7 @@ public class DisplayPolicy {
}
@VisibleForTesting
- static int updateLightNavigationBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming,
- WindowState imeWindow, WindowState navColorWin) {
-
- if (navColorWin != null) {
- if (navColorWin == imeWindow || navColorWin == opaque) {
- // Respect the light flag.
- vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
- vis |= PolicyControl.getSystemUiVisibility(navColorWin, null)
- & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
- } else if (navColorWin == opaqueOrDimming && navColorWin.isDimming()) {
- // Clear the light flag for dimming window.
- vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
- }
- }
- return vis;
- }
-
- private int updateLightNavigationBarAppearanceLw(int appearance, WindowState opaque,
+ int updateLightNavigationBarLw(int appearance, WindowState opaque,
WindowState opaqueOrDimming, WindowState imeWindow, WindowState navColorWin) {
if (navColorWin != null) {
@@ -3244,7 +3054,7 @@ public class DisplayPolicy {
return appearance;
}
- private Pair<Integer, WindowState> updateSystemBarsLw(WindowState win, int oldVis, int vis) {
+ private int updateSystemBarsLw(WindowState win, int disableFlags) {
final boolean dockedStackVisible = mDisplayContent.getDefaultTaskDisplayArea()
.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
final boolean freeformStackVisible = mDisplayContent.getDefaultTaskDisplayArea()
@@ -3257,115 +3067,46 @@ public class DisplayPolicy {
mForceShowSystemBars = dockedStackVisible || win.inFreeformWindowingMode() || resizing;
final boolean forceOpaqueStatusBar = mForceShowSystemBars && !isKeyguardShowing();
- // apply translucent bar vis flags
- WindowState fullscreenTransWin = isKeyguardShowing() && !isKeyguardOccluded()
- ? mNotificationShade
- : mTopFullscreenOpaqueWindowState;
- vis = mStatusBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
- vis = mNavigationBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
- int dockedVis = mStatusBarController.applyTranslucentFlagLw(
- mTopDockedOpaqueWindowState, 0, 0);
- dockedVis = mNavigationBarController.applyTranslucentFlagLw(
- mTopDockedOpaqueWindowState, dockedVis, 0);
-
final boolean fullscreenDrawsStatusBarBackground =
- drawsStatusBarBackground(vis, mTopFullscreenOpaqueWindowState);
+ drawsStatusBarBackground(mTopFullscreenOpaqueWindowState);
final boolean dockedDrawsStatusBarBackground =
- drawsStatusBarBackground(dockedVis, mTopDockedOpaqueWindowState);
+ drawsStatusBarBackground(mTopDockedOpaqueWindowState);
final boolean fullscreenDrawsNavBarBackground =
- drawsNavigationBarBackground(vis, mTopFullscreenOpaqueWindowState);
+ drawsNavigationBarBackground(mTopFullscreenOpaqueWindowState);
final boolean dockedDrawsNavigationBarBackground =
- drawsNavigationBarBackground(dockedVis, mTopDockedOpaqueWindowState);
+ drawsNavigationBarBackground(mTopDockedOpaqueWindowState);
- // prevent status bar interaction from clearing certain flags
- int type = win.getAttrs().type;
- boolean notificationShadeHasFocus = type == TYPE_NOTIFICATION_SHADE;
- if (notificationShadeHasFocus && !isKeyguardShowing()) {
- int flags = View.SYSTEM_UI_FLAG_FULLSCREEN
- | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_IMMERSIVE
- | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
- | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
- if (isKeyguardOccluded()) {
- flags |= View.STATUS_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSLUCENT;
- }
- vis = (vis & ~flags) | (oldVis & flags);
- }
+ int appearance = APPEARANCE_OPAQUE_NAVIGATION_BARS | APPEARANCE_OPAQUE_STATUS_BARS;
if (fullscreenDrawsStatusBarBackground && dockedDrawsStatusBarBackground) {
- vis |= View.STATUS_BAR_TRANSPARENT;
- vis &= ~View.STATUS_BAR_TRANSLUCENT;
- } else if (forceOpaqueStatusBar) {
- vis &= ~(View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT);
- }
-
- vis = configureNavBarOpacity(vis, dockedStackVisible, freeformStackVisible, resizing,
- fullscreenDrawsNavBarBackground, dockedDrawsNavigationBarBackground);
-
- // update status bar
- boolean immersiveSticky =
- (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
- final boolean hideStatusBarWM =
- mTopFullscreenOpaqueWindowState != null
- && (PolicyControl.getWindowFlags(mTopFullscreenOpaqueWindowState, null)
- & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
- final boolean hideStatusBarSysui =
- (vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
- final boolean hideNavBarSysui = (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
- // We shouldn't rely on the system UI visibilities anymore because the window can
- // use the new API (e.g., WindowInsetsController.hide) to hide navigation bar.
- // TODO(b/149813814): clean up the system UI flag usages in this function.
- || !win.getRequestedInsetsState().getSourceOrDefaultVisibility(
- ITYPE_NAVIGATION_BAR);
+ appearance &= ~APPEARANCE_OPAQUE_STATUS_BARS;
+ }
- final boolean transientStatusBarAllowed = getStatusBar() != null
- && (notificationShadeHasFocus || (!mForceShowSystemBars
- && (hideStatusBarWM || (hideStatusBarSysui && immersiveSticky))));
+ appearance = configureNavBarOpacity(appearance, dockedStackVisible,
+ freeformStackVisible, resizing, fullscreenDrawsNavBarBackground,
+ dockedDrawsNavigationBarBackground);
- final boolean transientNavBarAllowed = mNavigationBar != null
- && !mForceShowSystemBars && hideNavBarSysui && immersiveSticky;
+ final InsetsState requestedInsetsState = win.getRequestedInsetsState();
+ final boolean requestHideNavBar = !requestedInsetsState.getSourceOrDefaultVisibility(
+ ITYPE_NAVIGATION_BAR);
final long now = SystemClock.uptimeMillis();
final boolean pendingPanic = mPendingPanicGestureUptime != 0
&& now - mPendingPanicGestureUptime <= PANIC_GESTURE_EXPIRATION;
final DisplayPolicy defaultDisplayPolicy =
mService.getDefaultDisplayContentLocked().getDisplayPolicy();
- if (pendingPanic && hideNavBarSysui && win != mNotificationShade
+ if (pendingPanic && requestHideNavBar && win != mNotificationShade
&& getInsetsPolicy().isHidden(ITYPE_NAVIGATION_BAR)
// TODO (b/111955725): Show keyguard presentation on all external displays
&& defaultDisplayPolicy.isKeyguardDrawComplete()) {
// The user performed the panic gesture recently, we're about to hide the bars,
// we're no longer on the Keyguard and the screen is ready. We can now request the bars.
mPendingPanicGestureUptime = 0;
- if (!isNavBarEmpty(vis)) {
+ if (!isNavBarEmpty(disableFlags)) {
mDisplayContent.getInsetsPolicy().showTransient(SHOW_TYPES_FOR_PANIC);
}
}
- final boolean denyTransientStatus = mStatusBarController.isTransientShowRequested()
- && !transientStatusBarAllowed && hideStatusBarSysui;
- final boolean denyTransientNav = mNavigationBarController.isTransientShowRequested()
- && !transientNavBarAllowed;
- if (denyTransientStatus || denyTransientNav || mForceShowSystemBars) {
- // clear the clearable flags instead
- clearClearableFlagsLw();
- vis &= ~View.SYSTEM_UI_CLEARABLE_FLAGS;
- }
-
- final boolean immersive = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
- immersiveSticky = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
- final boolean navAllowedHidden = immersive || immersiveSticky;
-
- if (hideNavBarSysui && !navAllowedHidden
- && mService.mPolicy.getWindowLayerLw(win)
- > mService.mPolicy.getWindowLayerFromTypeLw(TYPE_INPUT_CONSUMER)) {
- // We can't hide the navbar from this window otherwise the input consumer would not get
- // the input events.
- vis = (vis & ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
- }
-
- vis = mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis);
-
// update navigation bar
boolean oldImmersiveMode = mLastImmersiveMode;
boolean newImmersiveMode = isImmersiveMode(win);
@@ -3374,23 +3115,13 @@ public class DisplayPolicy {
final String pkg = win.getOwningPackage();
mImmersiveModeConfirmation.immersiveModeChangedLw(pkg, newImmersiveMode,
mService.mPolicy.isUserSetupComplete(),
- isNavBarEmpty(win.getSystemUiVisibility()));
+ isNavBarEmpty(disableFlags));
}
- vis = mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis);
-
- final WindowState navColorWin = chooseNavigationColorWindowLw(
- mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState,
- mDisplayContent.mInputMethodWindow, mNavigationBarPosition);
- vis = updateLightNavigationBarLw(vis, mTopFullscreenOpaqueWindowState,
- mTopFullscreenOpaqueOrDimmingWindowState,
- mDisplayContent.mInputMethodWindow, navColorWin);
-
- return Pair.create(vis, navColorWin);
+ return appearance;
}
- private boolean drawsBarBackground(int vis, WindowState win, BarController controller,
- int translucentFlag) {
+ private boolean drawsBarBackground(WindowState win, BarController controller) {
if (!controller.isTransparentAllowed(win)) {
return false;
}
@@ -3403,73 +3134,59 @@ public class DisplayPolicy {
final boolean forceDrawsSystemBars =
(win.getAttrs().privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
- return forceDrawsSystemBars || drawsSystemBars && (vis & translucentFlag) == 0;
+ return forceDrawsSystemBars || drawsSystemBars;
}
- private boolean drawsStatusBarBackground(int vis, WindowState win) {
- return drawsBarBackground(vis, win, mStatusBarController, FLAG_TRANSLUCENT_STATUS);
+ private boolean drawsStatusBarBackground(WindowState win) {
+ return drawsBarBackground(win, mStatusBarController);
}
- private boolean drawsNavigationBarBackground(int vis, WindowState win) {
- return drawsBarBackground(vis, win, mNavigationBarController, FLAG_TRANSLUCENT_NAVIGATION);
+ private boolean drawsNavigationBarBackground(WindowState win) {
+ return drawsBarBackground(win, mNavigationBarController);
}
/**
* @return the current visibility flags with the nav-bar opacity related flags toggled based
* on the nav bar opacity rules chosen by {@link #mNavBarOpacityMode}.
*/
- private int configureNavBarOpacity(int visibility, boolean dockedStackVisible,
+ private int configureNavBarOpacity(int appearance, boolean dockedStackVisible,
boolean freeformStackVisible, boolean isDockedDividerResizing,
boolean fullscreenDrawsBackground, boolean dockedDrawsNavigationBarBackground) {
if (mNavBarOpacityMode == NAV_BAR_FORCE_TRANSPARENT) {
if (fullscreenDrawsBackground && dockedDrawsNavigationBarBackground) {
- visibility = setNavBarTransparentFlag(visibility);
+ appearance = clearNavBarOpaqueFlag(appearance);
} else if (dockedStackVisible) {
- visibility = setNavBarOpaqueFlag(visibility);
+ appearance = setNavBarOpaqueFlag(appearance);
}
} else if (mNavBarOpacityMode == NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED) {
if (dockedStackVisible || freeformStackVisible || isDockedDividerResizing) {
if (mIsFreeformWindowOverlappingWithNavBar) {
- visibility = setNavBarTranslucentFlag(visibility);
+ appearance = clearNavBarOpaqueFlag(appearance);
} else {
- visibility = setNavBarOpaqueFlag(visibility);
+ appearance = setNavBarOpaqueFlag(appearance);
}
} else if (fullscreenDrawsBackground) {
- visibility = setNavBarTransparentFlag(visibility);
+ appearance = clearNavBarOpaqueFlag(appearance);
}
} else if (mNavBarOpacityMode == NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE) {
if (isDockedDividerResizing) {
- visibility = setNavBarOpaqueFlag(visibility);
+ appearance = setNavBarOpaqueFlag(appearance);
} else if (freeformStackVisible) {
- visibility = setNavBarTranslucentFlag(visibility);
+ appearance = clearNavBarOpaqueFlag(appearance);
} else {
- visibility = setNavBarOpaqueFlag(visibility);
+ appearance = setNavBarOpaqueFlag(appearance);
}
}
- return visibility;
- }
-
- private int setNavBarOpaqueFlag(int visibility) {
- return visibility & ~(View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT);
- }
-
- private int setNavBarTranslucentFlag(int visibility) {
- visibility &= ~View.NAVIGATION_BAR_TRANSPARENT;
- return visibility | View.NAVIGATION_BAR_TRANSLUCENT;
+ return appearance;
}
- private int setNavBarTransparentFlag(int visibility) {
- visibility &= ~View.NAVIGATION_BAR_TRANSLUCENT;
- return visibility | View.NAVIGATION_BAR_TRANSPARENT;
+ private int setNavBarOpaqueFlag(int appearance) {
+ return appearance | APPEARANCE_OPAQUE_NAVIGATION_BARS;
}
- private void clearClearableFlagsLw() {
- int newVal = mResettingSystemUiFlags | View.SYSTEM_UI_CLEARABLE_FLAGS;
- if (newVal != mResettingSystemUiFlags) {
- mResettingSystemUiFlags = newVal;
- mDisplayContent.reevaluateStatusBarVisibility();
- }
+ private int clearNavBarOpaqueFlag(int appearance) {
+ return appearance & ~APPEARANCE_OPAQUE_NAVIGATION_BARS;
}
private boolean isImmersiveMode(WindowState win) {
@@ -3520,7 +3237,7 @@ public class DisplayPolicy {
// taken over the whole screen.
boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(isScreenOn,
SystemClock.elapsedRealtime(), isImmersiveMode(mSystemUiControllingWindow),
- isNavBarEmpty(mLastSystemUiFlags));
+ isNavBarEmpty(mLastDisableFlags));
if (panic) {
mHandler.post(mHiddenNavPanic);
}
@@ -3579,14 +3296,9 @@ public class DisplayPolicy {
pw.print(prefix); pw.print("mKeyguardDrawComplete="); pw.print(mKeyguardDrawComplete);
pw.print(" mWindowManagerDrawComplete="); pw.println(mWindowManagerDrawComplete);
pw.print(prefix); pw.print("mHdmiPlugged="); pw.println(mHdmiPlugged);
- if (mLastSystemUiFlags != 0 || mResettingSystemUiFlags != 0
- || mForceClearedSystemUiFlags != 0) {
- pw.print(prefix); pw.print("mLastSystemUiFlags=0x");
- pw.print(Integer.toHexString(mLastSystemUiFlags));
- pw.print(" mResettingSystemUiFlags=0x");
- pw.print(Integer.toHexString(mResettingSystemUiFlags));
- pw.print(" mForceClearedSystemUiFlags=0x");
- pw.println(Integer.toHexString(mForceClearedSystemUiFlags));
+ if (mLastDisableFlags != 0) {
+ pw.print(prefix); pw.print("mLastDisableFlags=0x");
+ pw.print(Integer.toHexString(mLastDisableFlags));
}
pw.print(prefix); pw.print("mShowingDream="); pw.print(mShowingDream);
pw.print(" mDreamingLockscreen="); pw.print(mDreamingLockscreen);
@@ -3635,8 +3347,6 @@ public class DisplayPolicy {
pw.print(prefix); pw.print("mRemoteInsetsControllerControlsSystemBars");
pw.print(mDisplayContent.getInsetsPolicy().getRemoteInsetsControllerControlsSystemBars());
pw.print(" mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn);
- mStatusBarController.dump(pw, prefix);
- mNavigationBarController.dump(pw, prefix);
pw.print(prefix); pw.println("Looper state:");
mHandler.getLooper().dump(new PrintWriterPrinter(pw), prefix + " ");
diff --git a/services/core/java/com/android/server/wm/StatusBarController.java b/services/core/java/com/android/server/wm/StatusBarController.java
deleted file mode 100644
index 3564e0bce5f5..000000000000
--- a/services/core/java/com/android/server/wm/StatusBarController.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * 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 com.android.server.wm;
-
-import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
-
-import static com.android.server.wm.WindowManagerInternal.AppTransitionListener;
-
-import android.app.StatusBarManager;
-import android.os.IBinder;
-import android.view.View;
-
-import com.android.server.statusbar.StatusBarManagerInternal;
-
-/**
- * Implements status bar specific behavior.
- */
-public class StatusBarController extends BarController {
-
- private final AppTransitionListener mAppTransitionListener = new AppTransitionListener() {
-
- private Runnable mAppTransitionPending = () -> {
- StatusBarManagerInternal statusBar = getStatusBarInternal();
- if (statusBar != null) {
- statusBar.appTransitionPending(mDisplayId);
- }
- };
-
- private Runnable mAppTransitionCancelled = () -> {
- StatusBarManagerInternal statusBar = getStatusBarInternal();
- if (statusBar != null) {
- statusBar.appTransitionCancelled(mDisplayId);
- }
- };
-
- private Runnable mAppTransitionFinished = () -> {
- StatusBarManagerInternal statusBar = getStatusBarInternal();
- if (statusBar != null) {
- statusBar.appTransitionFinished(mDisplayId);
- }
- };
-
- @Override
- public void onAppTransitionPendingLocked() {
- mHandler.post(mAppTransitionPending);
- }
-
- @Override
- public int onAppTransitionStartingLocked(int transit, long duration,
- long statusBarAnimationStartTime, long statusBarAnimationDuration) {
- mHandler.post(() -> {
- StatusBarManagerInternal statusBar = getStatusBarInternal();
- if (statusBar != null) {
- statusBar.appTransitionStarting(mDisplayId,
- statusBarAnimationStartTime, statusBarAnimationDuration);
- }
- });
- return 0;
- }
-
- @Override
- public void onAppTransitionCancelledLocked(int transit) {
- mHandler.post(mAppTransitionCancelled);
- }
-
- @Override
- public void onAppTransitionFinishedLocked(IBinder token) {
- mHandler.post(mAppTransitionFinished);
- }
- };
-
- StatusBarController(int displayId) {
- super("StatusBar",
- displayId,
- View.STATUS_BAR_TRANSIENT,
- View.STATUS_BAR_UNHIDE,
- View.STATUS_BAR_TRANSLUCENT,
- StatusBarManager.WINDOW_STATUS_BAR,
- TYPE_STATUS_BAR,
- FLAG_TRANSLUCENT_STATUS,
- View.STATUS_BAR_TRANSPARENT);
- }
-
- void setTopAppHidesStatusBar(boolean hidesStatusBar) {
- StatusBarManagerInternal statusBar = getStatusBarInternal();
- if (statusBar != null) {
- statusBar.setTopAppHidesStatusBar(hidesStatusBar);
- }
- }
-
- AppTransitionListener getAppTransitionListener() {
- return mAppTransitionListener;
- }
-}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
index 1bf9c2a0822e..6d40034c6000 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
@@ -46,6 +46,7 @@ import android.app.job.JobInfo;
import android.app.usage.UsageStatsManagerInternal;
import android.content.ComponentName;
import android.content.pm.PackageManagerInternal;
+import android.content.pm.ServiceInfo;
import android.net.Uri;
import android.os.SystemClock;
import android.provider.MediaStore;
@@ -685,6 +686,8 @@ public class JobStatusTest {
}
private static JobStatus createJobStatus(JobInfo job) {
- return JobStatus.createFromJobInfo(job, 0, null, -1, "JobStatusTest");
+ JobStatus jobStatus = JobStatus.createFromJobInfo(job, 0, null, -1, "JobStatusTest");
+ jobStatus.serviceInfo = mock(ServiceInfo.class);
+ return jobStatus;
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index 1cf133a2bbf2..18bd6b17f340 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -61,6 +61,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManagerInternal;
+import android.content.pm.ServiceInfo;
import android.os.BatteryManager;
import android.os.BatteryManagerInternal;
import android.os.Handler;
@@ -299,6 +300,7 @@ public class QuotaControllerTest {
JobInfo jobInfo) {
JobStatus js = JobStatus.createFromJobInfo(
jobInfo, callingUid, packageName, SOURCE_USER_ID, testTag);
+ js.serviceInfo = mock(ServiceInfo.class);
// Make sure tests aren't passing just because the default bucket is likely ACTIVE.
js.setStandbyBucket(FREQUENT_INDEX);
// Make sure Doze and background-not-restricted don't affect tests.
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
index 83df40629085..c0d5f7b5aa9e 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
@@ -19,11 +19,18 @@ import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC
import static com.google.common.truth.Truth.assertThat;
-import android.annotation.Nullable;
-import android.app.Instrumentation;
-import android.hardware.hdmi.HdmiDeviceInfo;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.ContextWrapper;
import android.hardware.tv.cec.V1_0.SendMessageResult;
+import android.media.AudioManager;
+import android.os.Handler;
+import android.os.IPowerManager;
+import android.os.IThermalService;
import android.os.Looper;
+import android.os.PowerManager;
import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
@@ -31,10 +38,11 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
@@ -44,7 +52,7 @@ import java.util.ArrayList;
@RunWith(JUnit4.class)
public class ArcInitiationActionFromAvrTest {
- private HdmiDeviceInfo mDeviceInfoForTests;
+ private Context mContextSpy;
private HdmiCecLocalDeviceAudioSystem mHdmiCecLocalDeviceAudioSystem;
private HdmiCecController mHdmiCecController;
private HdmiControlService mHdmiControlService;
@@ -52,87 +60,62 @@ public class ArcInitiationActionFromAvrTest {
private ArcInitiationActionFromAvr mAction;
private TestLooper mTestLooper = new TestLooper();
- private boolean mSendCecCommandSuccess;
- private boolean mShouldDispatchARCInitiated;
- private boolean mArcInitSent;
- private boolean mRequestActiveSourceSent;
- private Instrumentation mInstrumentation;
private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
+ @Mock private IPowerManager mIPowerManagerMock;
+ @Mock private IThermalService mIThermalServiceMock;
+ @Mock private AudioManager mAudioManager;
+
@Before
- public void setUp() {
- mDeviceInfoForTests = new HdmiDeviceInfo(1000, 1);
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
- mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
- mHdmiControlService =
- new HdmiControlService(mInstrumentation.getTargetContext()) {
- @Override
- void sendCecCommand(
- HdmiCecMessage command, @Nullable SendMessageCallback callback) {
- switch (command.getOpcode()) {
- case Constants.MESSAGE_REQUEST_ACTIVE_SOURCE:
- if (callback != null) {
- callback.onSendCompleted(
- mSendCecCommandSuccess
- ? SendMessageResult.SUCCESS
- : SendMessageResult.NACK);
- }
- mRequestActiveSourceSent = true;
- break;
- case Constants.MESSAGE_INITIATE_ARC:
- if (callback != null) {
- callback.onSendCompleted(
- mSendCecCommandSuccess
- ? SendMessageResult.SUCCESS
- : SendMessageResult.NACK);
- }
- mArcInitSent = true;
- if (mShouldDispatchARCInitiated) {
- mHdmiCecLocalDeviceAudioSystem.dispatchMessage(
- HdmiCecMessageBuilder.buildReportArcInitiated(
- Constants.ADDR_TV,
- Constants.ADDR_AUDIO_SYSTEM));
- }
- break;
- default:
- }
- }
+ PowerManager powerManager = new PowerManager(mContextSpy, mIPowerManagerMock,
+ mIThermalServiceMock, new Handler(mTestLooper.getLooper()));
+ when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager);
+ when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
+ when(mIPowerManagerMock.isInteractive()).thenReturn(true);
+ mHdmiControlService =
+ new HdmiControlService(mContextSpy) {
@Override
boolean isPowerStandby() {
return false;
}
@Override
- boolean isAddressAllocated() {
- return true;
+ void wakeUp() {
}
@Override
- Looper getServiceLooper() {
- return mTestLooper.getLooper();
+ PowerManager getPowerManager() {
+ return powerManager;
}
- };
- mHdmiCecLocalDeviceAudioSystem =
- new HdmiCecLocalDeviceAudioSystem(mHdmiControlService) {
@Override
- HdmiDeviceInfo getDeviceInfo() {
- return mDeviceInfoForTests;
+ AudioManager getAudioManager() {
+ return mAudioManager;
}
@Override
- void setArcStatus(boolean enabled) {
- // do nothing
+ boolean isAddressAllocated() {
+ return true;
}
@Override
- protected boolean isSystemAudioActivated() {
- return true;
+ Looper getServiceLooper() {
+ return mTestLooper.getLooper();
}
};
+ mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(mHdmiControlService) {
+ @Override
+ protected void setPreferredAddress(int addr) {
+ }
+ };
+
mHdmiCecLocalDeviceAudioSystem.init();
Looper looper = mTestLooper.getLooper();
mHdmiControlService.setIoLooper(looper);
@@ -150,18 +133,88 @@ public class ArcInitiationActionFromAvrTest {
mTestLooper.dispatchAll();
}
- @Ignore("b/120845532")
@Test
- public void arcInitiation_requestActiveSource() {
- mSendCecCommandSuccess = true;
- mShouldDispatchARCInitiated = true;
- mRequestActiveSourceSent = false;
- mArcInitSent = false;
+ public void arcInitiation_initiated() {
+ mHdmiCecLocalDeviceAudioSystem.addAndStartAction(mAction);
+ mTestLooper.dispatchAll();
+ HdmiCecMessage initiateArc = HdmiCecMessageBuilder.buildInitiateArc(
+ Constants.ADDR_AUDIO_SYSTEM, Constants.ADDR_TV);
+
+ assertThat(mNativeWrapper.getResultMessages()).contains(initiateArc);
+
+ mHdmiControlService.sendCecCommand(
+ HdmiCecMessageBuilder.buildReportArcInitiated(
+ Constants.ADDR_TV,
+ Constants.ADDR_AUDIO_SYSTEM));
+ mTestLooper.dispatchAll();
+
+ assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isTrue();
+ }
+ @Test
+ public void arcInitiation_sendFailed() {
+ mNativeWrapper.setMessageSendResult(Constants.MESSAGE_INITIATE_ARC, SendMessageResult.NACK);
mHdmiCecLocalDeviceAudioSystem.addAndStartAction(mAction);
mTestLooper.dispatchAll();
+ HdmiCecMessage initiateArc = HdmiCecMessageBuilder.buildInitiateArc(
+ Constants.ADDR_AUDIO_SYSTEM, Constants.ADDR_TV);
+
+ assertThat(mNativeWrapper.getResultMessages()).contains(initiateArc);
+
+ assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isFalse();
+ }
- assertThat(mArcInitSent).isTrue();
- assertThat(mRequestActiveSourceSent).isTrue();
+ @Test
+ public void arcInitiation_terminated() {
+ mHdmiCecLocalDeviceAudioSystem.addAndStartAction(mAction);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage initiateArc = HdmiCecMessageBuilder.buildInitiateArc(
+ Constants.ADDR_AUDIO_SYSTEM, Constants.ADDR_TV);
+
+ assertThat(mNativeWrapper.getResultMessages()).contains(initiateArc);
+
+ mHdmiControlService.handleCecCommand(HdmiCecMessageBuilder.buildReportArcTerminated(
+ Constants.ADDR_TV,
+ Constants.ADDR_AUDIO_SYSTEM));
+ mTestLooper.dispatchAll();
+
+ assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isFalse();
+ }
+
+ @Test
+ public void arcInitiation_abort() {
+ mHdmiCecLocalDeviceAudioSystem.addAndStartAction(mAction);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage initiateArc = HdmiCecMessageBuilder.buildInitiateArc(
+ Constants.ADDR_AUDIO_SYSTEM, Constants.ADDR_TV);
+
+ assertThat(mNativeWrapper.getResultMessages()).contains(initiateArc);
+
+ mHdmiControlService.handleCecCommand(
+ HdmiCecMessageBuilder.buildFeatureAbortCommand(
+ Constants.ADDR_TV,
+ Constants.ADDR_AUDIO_SYSTEM, Constants.MESSAGE_INITIATE_ARC,
+ Constants.ABORT_REFUSED));
+ mTestLooper.dispatchAll();
+
+ assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isFalse();
+ }
+
+ //Fail
+ @Test
+ public void arcInitiation_timeout() {
+ mHdmiCecLocalDeviceAudioSystem.addAndStartAction(mAction);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage initiateArc = HdmiCecMessageBuilder.buildInitiateArc(
+ Constants.ADDR_AUDIO_SYSTEM, Constants.ADDR_TV);
+
+ assertThat(mNativeWrapper.getResultMessages()).contains(initiateArc);
+
+ mTestLooper.moveTimeForward(1001);
+ mTestLooper.dispatchAll();
+ assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isTrue();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
index dc326eefbc9b..f986a70804f6 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
@@ -15,13 +15,22 @@
*/
package com.android.server.hdmi;
+import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
+
import static com.google.common.truth.Truth.assertThat;
-import android.annotation.Nullable;
-import android.app.Instrumentation;
-import android.hardware.hdmi.HdmiDeviceInfo;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.ContextWrapper;
import android.hardware.tv.cec.V1_0.SendMessageResult;
+import android.media.AudioManager;
+import android.os.Handler;
+import android.os.IPowerManager;
+import android.os.IThermalService;
import android.os.Looper;
+import android.os.PowerManager;
import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
@@ -29,10 +38,13 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
/** Tests for {@link ArcTerminationActionFromAvr} */
@SmallTest
@@ -40,45 +52,47 @@ import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public class ArcTerminationActionFromAvrTest {
- private HdmiDeviceInfo mDeviceInfoForTests;
+ private Context mContextSpy;
private HdmiCecLocalDeviceAudioSystem mHdmiCecLocalDeviceAudioSystem;
private ArcTerminationActionFromAvr mAction;
+ private HdmiCecController mHdmiCecController;
+ private HdmiControlService mHdmiControlService;
+ private FakeNativeWrapper mNativeWrapper;
+
private TestLooper mTestLooper = new TestLooper();
- private boolean mSendCecCommandSuccess;
- private boolean mShouldDispatchReportArcTerminated;
- private Instrumentation mInstrumentation;
- @Nullable private Boolean mArcEnabled = null;
+ private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
+
+ @Mock private IPowerManager mIPowerManagerMock;
+ @Mock private IThermalService mIThermalServiceMock;
+ @Mock private AudioManager mAudioManager;
@Before
- public void setUp() {
- mDeviceInfoForTests = new HdmiDeviceInfo(1000, 1);
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
- mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
+
+ PowerManager powerManager = new PowerManager(mContextSpy, mIPowerManagerMock,
+ mIThermalServiceMock, new Handler(mTestLooper.getLooper()));
+ when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager);
+ when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
+ when(mIPowerManagerMock.isInteractive()).thenReturn(true);
+
+ mHdmiControlService =
+ new HdmiControlService(mContextSpy) {
+ @Override
+ void wakeUp() {
+ }
- HdmiControlService hdmiControlService =
- new HdmiControlService(mInstrumentation.getTargetContext()) {
@Override
- void sendCecCommand(
- HdmiCecMessage command, @Nullable SendMessageCallback callback) {
- switch (command.getOpcode()) {
- case Constants.MESSAGE_TERMINATE_ARC:
- if (callback != null) {
- callback.onSendCompleted(
- mSendCecCommandSuccess
- ? SendMessageResult.SUCCESS
- : SendMessageResult.NACK);
- }
- if (mShouldDispatchReportArcTerminated) {
- mHdmiCecLocalDeviceAudioSystem.dispatchMessage(
- HdmiCecMessageBuilder.buildReportArcTerminated(
- Constants.ADDR_TV,
- mHdmiCecLocalDeviceAudioSystem.mAddress));
- }
- break;
- default:
- throw new IllegalArgumentException("Unexpected message");
- }
+ PowerManager getPowerManager() {
+ return powerManager;
+ }
+
+ @Override
+ AudioManager getAudioManager() {
+ return mAudioManager;
}
@Override
@@ -97,55 +111,71 @@ public class ArcTerminationActionFromAvrTest {
}
};
- mHdmiCecLocalDeviceAudioSystem =
- new HdmiCecLocalDeviceAudioSystem(hdmiControlService) {
- @Override
- HdmiDeviceInfo getDeviceInfo() {
- return mDeviceInfoForTests;
- }
-
- @Override
- void setArcStatus(boolean enabled) {
- mArcEnabled = enabled;
- }
- };
- mHdmiCecLocalDeviceAudioSystem.init();
Looper looper = mTestLooper.getLooper();
- hdmiControlService.setIoLooper(looper);
-
+ mHdmiControlService.setIoLooper(looper);
+ mNativeWrapper = new FakeNativeWrapper();
+ mHdmiCecController =
+ HdmiCecController.createWithNativeWrapper(this.mHdmiControlService, mNativeWrapper);
+ mHdmiControlService.setCecController(mHdmiCecController);
+ mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
+ mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
+ mHdmiControlService.initPortInfo();
+
+ mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(mHdmiControlService) {
+ @Override
+ protected void setPreferredAddress(int addr) {
+ }
+ };
+ mHdmiCecLocalDeviceAudioSystem.init();
mAction = new ArcTerminationActionFromAvr(mHdmiCecLocalDeviceAudioSystem);
+
+ mLocalDevices.add(mHdmiCecLocalDeviceAudioSystem);
+ mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ mHdmiCecLocalDeviceAudioSystem.setArcStatus(true);
+ mTestLooper.dispatchAll();
}
@Test
- @Ignore("b/120845532")
- public void testSendMessage_notSuccess() {
- mSendCecCommandSuccess = false;
- mShouldDispatchReportArcTerminated = false;
+ public void testSendMessage_sendFailed() {
+ mNativeWrapper.setMessageSendResult(Constants.MESSAGE_TERMINATE_ARC,
+ SendMessageResult.NACK);
mHdmiCecLocalDeviceAudioSystem.addAndStartAction(mAction);
-
mTestLooper.dispatchAll();
- assertThat(mArcEnabled).isNull();
+ HdmiCecMessage terminateArc = HdmiCecMessageBuilder.buildTerminateArc(
+ Constants.ADDR_AUDIO_SYSTEM, Constants.ADDR_TV);
+
+ assertThat(mNativeWrapper.getResultMessages()).contains(terminateArc);
+
+ assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isFalse();
}
@Test
- public void testReportArcTerminated_notReceived() {
- mSendCecCommandSuccess = true;
- mShouldDispatchReportArcTerminated = false;
+ public void testReportArcTerminated_timeout() {
mHdmiCecLocalDeviceAudioSystem.addAndStartAction(mAction);
-
- mTestLooper.moveTimeForward(1000);
mTestLooper.dispatchAll();
- assertThat(mArcEnabled).isNull();
+ HdmiCecMessage terminateArc = HdmiCecMessageBuilder.buildTerminateArc(
+ Constants.ADDR_AUDIO_SYSTEM, Constants.ADDR_TV);
+
+ assertThat(mNativeWrapper.getResultMessages()).contains(terminateArc);
+
+ assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isTrue();
}
@Test
public void testReportArcTerminated_received() {
- mSendCecCommandSuccess = true;
- mShouldDispatchReportArcTerminated = true;
mHdmiCecLocalDeviceAudioSystem.addAndStartAction(mAction);
+ mTestLooper.dispatchAll();
+ HdmiCecMessage terminateArc = HdmiCecMessageBuilder.buildTerminateArc(
+ Constants.ADDR_AUDIO_SYSTEM, Constants.ADDR_TV);
+
+ assertThat(mNativeWrapper.getResultMessages()).contains(terminateArc);
- mTestLooper.moveTimeForward(1000);
+ HdmiCecMessage arcTerminatedResponse = HdmiCecMessageBuilder.buildReportArcTerminated(
+ Constants.ADDR_TV, Constants.ADDR_AUDIO_SYSTEM);
+
+ mHdmiControlService.handleCecCommand(arcTerminatedResponse);
mTestLooper.dispatchAll();
- assertThat(mArcEnabled).isFalse();
+
+ assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isFalse();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java
index 7538468fbe31..01f0a3d398df 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java
@@ -24,6 +24,7 @@ import com.android.server.hdmi.HdmiCecController.NativeWrapper;
import com.google.common.collect.Iterables;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
/** Fake {@link NativeWrapper} useful for testing. */
@@ -48,6 +49,7 @@ final class FakeNativeWrapper implements NativeWrapper {
};
private final List<HdmiCecMessage> mResultMessages = new ArrayList<>();
+ private final HashMap<Integer, Integer> mMessageSendResult = new HashMap<>();
private int mMyPhysicalAddress = 0;
private HdmiPortInfo[] mHdmiPortInfo = null;
@@ -65,9 +67,10 @@ final class FakeNativeWrapper implements NativeWrapper {
if (body.length == 0) {
return mPollAddressResponse[dstAddress];
} else {
- mResultMessages.add(HdmiCecMessageBuilder.of(srcAddress, dstAddress, body));
+ HdmiCecMessage message = HdmiCecMessageBuilder.of(srcAddress, dstAddress, body);
+ mResultMessages.add(message);
+ return mMessageSendResult.getOrDefault(message.getOpcode(), SendMessageResult.SUCCESS);
}
- return SendMessageResult.SUCCESS;
}
@Override
@@ -132,6 +135,10 @@ final class FakeNativeWrapper implements NativeWrapper {
mPollAddressResponse[logicalAddress] = response;
}
+ public void setMessageSendResult(int opcode, int result) {
+ mMessageSendResult.put(opcode, result);
+ }
+
@VisibleForTesting
protected void setPhysicalAddress(int physicalAddress) {
mMyPhysicalAddress = physicalAddress;
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 94e40413f9f8..951118125f6e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -124,7 +124,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
spyOn(mNavBarWindow);
// Disabling this call for most tests since it can override the systemUiFlags when called.
- doReturn(0).when(mDisplayPolicy).updateSystemUiVisibilityLw();
+ doReturn(false).when(mDisplayPolicy).updateSystemUiVisibilityLw();
updateDisplayFrames();
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index b77d21c0f711..a55423a7baf6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -19,9 +19,9 @@ package com.android.server.wm;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.Surface.ROTATION_0;
-import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_TOUCH;
import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
@@ -78,8 +78,7 @@ public class DisplayPolicyTests extends WindowTestsBase {
attrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
attrs.format = PixelFormat.OPAQUE;
- attrs.systemUiVisibility = attrs.subtreeSystemUiVisibility = win.mSystemUiVisibility =
- hasLightNavBar ? SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR : 0;
+ attrs.insetsFlags.appearance = hasLightNavBar ? APPEARANCE_LIGHT_NAVIGATION_BARS : 0;
return win;
}
@@ -103,8 +102,7 @@ public class DisplayPolicyTests extends WindowTestsBase {
attrs.flags = FLAG_NOT_FOCUSABLE | FLAG_LAYOUT_IN_SCREEN
| (drawNavBar ? FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS : 0);
attrs.format = PixelFormat.TRANSPARENT;
- attrs.systemUiVisibility = attrs.subtreeSystemUiVisibility = win.mSystemUiVisibility =
- hasLightNavBar ? SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR : 0;
+ attrs.insetsFlags.appearance = hasLightNavBar ? APPEARANCE_LIGHT_NAVIGATION_BARS : 0;
win.mHasSurface = visible;
return win;
}
@@ -163,6 +161,7 @@ public class DisplayPolicyTests extends WindowTestsBase {
@Test
public void testUpdateLightNavigationBarLw() {
+ DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
final WindowState opaqueDarkNavBar = createOpaqueFullscreen(false);
final WindowState opaqueLightNavBar = createOpaqueFullscreen(true);
@@ -171,50 +170,50 @@ public class DisplayPolicyTests extends WindowTestsBase {
final WindowState imeDrawDarkNavBar = createInputMethodWindow(true, true, false);
final WindowState imeDrawLightNavBar = createInputMethodWindow(true, true, true);
- assertEquals(SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
- DisplayPolicy.updateLightNavigationBarLw(
- SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, null, null,
+ assertEquals(APPEARANCE_LIGHT_NAVIGATION_BARS,
+ displayPolicy.updateLightNavigationBarLw(
+ APPEARANCE_LIGHT_NAVIGATION_BARS, null, null,
null, null));
- // Opaque top fullscreen window overrides SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR flag.
- assertEquals(0, DisplayPolicy.updateLightNavigationBarLw(
+ // Opaque top fullscreen window overrides APPEARANCE_LIGHT_NAVIGATION_BARS flag.
+ assertEquals(0, displayPolicy.updateLightNavigationBarLw(
0, opaqueDarkNavBar, opaqueDarkNavBar, null, opaqueDarkNavBar));
- assertEquals(0, DisplayPolicy.updateLightNavigationBarLw(
- SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueDarkNavBar, opaqueDarkNavBar, null,
+ assertEquals(0, displayPolicy.updateLightNavigationBarLw(
+ APPEARANCE_LIGHT_NAVIGATION_BARS, opaqueDarkNavBar, opaqueDarkNavBar, null,
opaqueDarkNavBar));
- assertEquals(SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
- DisplayPolicy.updateLightNavigationBarLw(0, opaqueLightNavBar,
+ assertEquals(APPEARANCE_LIGHT_NAVIGATION_BARS,
+ displayPolicy.updateLightNavigationBarLw(0, opaqueLightNavBar,
opaqueLightNavBar, null, opaqueLightNavBar));
- assertEquals(SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
- DisplayPolicy.updateLightNavigationBarLw(SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
+ assertEquals(APPEARANCE_LIGHT_NAVIGATION_BARS,
+ displayPolicy.updateLightNavigationBarLw(APPEARANCE_LIGHT_NAVIGATION_BARS,
opaqueLightNavBar, opaqueLightNavBar, null, opaqueLightNavBar));
- // Dimming window clears SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR.
- assertEquals(0, DisplayPolicy.updateLightNavigationBarLw(
+ // Dimming window clears APPEARANCE_LIGHT_NAVIGATION_BARS.
+ assertEquals(0, displayPolicy.updateLightNavigationBarLw(
0, opaqueDarkNavBar, dimming, null, dimming));
- assertEquals(0, DisplayPolicy.updateLightNavigationBarLw(
+ assertEquals(0, displayPolicy.updateLightNavigationBarLw(
0, opaqueLightNavBar, dimming, null, dimming));
- assertEquals(0, DisplayPolicy.updateLightNavigationBarLw(
- SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueDarkNavBar, dimming, null, dimming));
- assertEquals(0, DisplayPolicy.updateLightNavigationBarLw(
- SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueLightNavBar, dimming, null, dimming));
- assertEquals(0, DisplayPolicy.updateLightNavigationBarLw(
- SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueLightNavBar, dimming, imeDrawLightNavBar,
+ assertEquals(0, displayPolicy.updateLightNavigationBarLw(
+ APPEARANCE_LIGHT_NAVIGATION_BARS, opaqueDarkNavBar, dimming, null, dimming));
+ assertEquals(0, displayPolicy.updateLightNavigationBarLw(
+ APPEARANCE_LIGHT_NAVIGATION_BARS, opaqueLightNavBar, dimming, null, dimming));
+ assertEquals(0, displayPolicy.updateLightNavigationBarLw(
+ APPEARANCE_LIGHT_NAVIGATION_BARS, opaqueLightNavBar, dimming, imeDrawLightNavBar,
dimming));
- // IME window clears SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
- assertEquals(0, DisplayPolicy.updateLightNavigationBarLw(
- SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, null, null, imeDrawDarkNavBar,
+ // IME window clears APPEARANCE_LIGHT_NAVIGATION_BARS
+ assertEquals(0, displayPolicy.updateLightNavigationBarLw(
+ APPEARANCE_LIGHT_NAVIGATION_BARS, null, null, imeDrawDarkNavBar,
imeDrawDarkNavBar));
- // Even if the top fullscreen has SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, IME window wins.
- assertEquals(0, DisplayPolicy.updateLightNavigationBarLw(
- SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueLightNavBar, opaqueLightNavBar,
+ // Even if the top fullscreen has APPEARANCE_LIGHT_NAVIGATION_BARS, IME window wins.
+ assertEquals(0, displayPolicy.updateLightNavigationBarLw(
+ APPEARANCE_LIGHT_NAVIGATION_BARS, opaqueLightNavBar, opaqueLightNavBar,
imeDrawDarkNavBar, imeDrawDarkNavBar));
- // IME window should be able to use SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR.
- assertEquals(SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
- DisplayPolicy.updateLightNavigationBarLw(0, opaqueDarkNavBar,
+ // IME window should be able to use APPEARANCE_LIGHT_NAVIGATION_BARS.
+ assertEquals(APPEARANCE_LIGHT_NAVIGATION_BARS,
+ displayPolicy.updateLightNavigationBarLw(0, opaqueDarkNavBar,
opaqueDarkNavBar, imeDrawLightNavBar, imeDrawLightNavBar));
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
index af8cb02a86fe..94ffcdab4fa7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
@@ -45,7 +45,6 @@ import android.util.Pair;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
-import android.view.View;
import android.view.WindowManagerGlobal;
import com.android.internal.R;
@@ -99,11 +98,9 @@ public class DisplayPolicyTestsBase extends WindowTestsBase {
mStatusBarWindow.mAttrs.gravity = Gravity.TOP;
addWindow(mStatusBarWindow);
- mDisplayPolicy.mLastSystemUiFlags |= View.STATUS_BAR_TRANSPARENT;
mNavBarWindow.mAttrs.gravity = Gravity.BOTTOM;
addWindow(mNavBarWindow);
- mDisplayPolicy.mLastSystemUiFlags |= View.NAVIGATION_BAR_TRANSPARENT;
// Update source frame and visibility of insets providers.
mDisplayContent.getInsetsStateController().onPostLayout();
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index edcf0d4f5501..f1540731da8b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -566,7 +566,7 @@ public class SizeCompatTests extends WindowTestsBase {
assertEquals(new Rect(mActivity.getBounds().left, 0, dh - mActivity.getBounds().right, 0),
mActivity.getLetterboxInsets());
- final StatusBarController statusBarController =
+ final BarController statusBarController =
mActivity.mDisplayContent.getDisplayPolicy().getStatusBarController();
// The activity doesn't fill the display, so the letterbox of the rotated activity is
// overlapped with the rotated content frame of status bar. Hence the status bar shouldn't
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 4de1abfee7fc..829c746c1b5f 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -32,6 +32,7 @@ import android.os.RemoteException;
import android.service.carrier.CarrierService;
import android.telecom.TelecomManager;
import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.ImsSsData;
import com.android.internal.telephony.ICarrierConfigLoader;
import com.android.telephony.Rlog;
@@ -66,6 +67,18 @@ public class CarrierConfigManager {
public static final String EXTRA_SUBSCRIPTION_INDEX =
SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX;
+ /**
+ * Service class flag if not specify a service class.
+ * Reference: 3GPP TS 27.007 Section 7.4 Facility lock +CLCK
+ */
+ public static final int SERVICE_CLASS_NONE = ImsSsData.SERVICE_CLASS_NONE;
+
+ /**
+ * Service class flag for voice telephony.
+ * Reference: 3GPP TS 27.007 Section 7.4 Facility lock +CLCK
+ */
+ public static final int SERVICE_CLASS_VOICE = ImsSsData.SERVICE_CLASS_VOICE;
+
private final Context mContext;
/**
@@ -212,6 +225,18 @@ public class CarrierConfigManager {
"call_barring_supports_deactivate_all_bool";
/**
+ * Specifies the service class for call barring service. Default value is
+ * {@link #SERVICE_CLASS_VOICE}.
+ * The value set as below:
+ * <ul>
+ * <li>0: {@link #SERVICE_CLASS_NONE}</li>
+ * <li>1: {@link #SERVICE_CLASS_VOICE}</li>
+ * </ul>
+ */
+ public static final String KEY_CALL_BARRING_DEFAULT_SERVICE_CLASS_INT =
+ "call_barring_default_service_class_int";
+
+ /**
* Flag indicating whether the Phone app should ignore EVENT_SIM_NETWORK_LOCKED
* events from the Sim.
* If true, this will prevent the IccNetworkDepersonalizationPanel from being shown, and
@@ -3889,10 +3914,23 @@ public class CarrierConfigManager {
* Indicating whether DUN APN should be disabled when the device is roaming. In that case,
* the default APN (i.e. internet) will be used for tethering.
*
+ * This config is only available when using Preset APN(not user edited) as Preferred APN.
+ *
+ * @hide
+ */
+ public static final String KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL =
+ "disable_dun_apn_while_roaming_with_preset_apn_bool";
+
+ /**
+ * Where there is no preferred APN, specifies the carrier's default preferred APN.
+ * Specifies the {@link android.provider.Telephony.Carriers.APN} of the default preferred apn.
+ *
+ * This config is only available with Preset APN(not user edited).
+ *
* @hide
*/
- public static final String KEY_DISABLE_DUN_APN_WHILE_ROAMING =
- "disable_dun_apn_while_roaming";
+ public static final String KEY_DEFAULT_PREFERRED_APN_NAME_STRING =
+ "default_preferred_apn_name_string";
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -3968,6 +4006,7 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_CALL_BARRING_VISIBILITY_BOOL, false);
sDefaults.putBoolean(KEY_CALL_BARRING_SUPPORTS_PASSWORD_CHANGE_BOOL, true);
sDefaults.putBoolean(KEY_CALL_BARRING_SUPPORTS_DEACTIVATE_ALL_BOOL, true);
+ sDefaults.putInt(KEY_CALL_BARRING_DEFAULT_SERVICE_CLASS_INT, SERVICE_CLASS_VOICE);
sDefaults.putBoolean(KEY_CALL_FORWARDING_VISIBILITY_BOOL, true);
sDefaults.putBoolean(KEY_CALL_FORWARDING_WHEN_UNREACHABLE_SUPPORTED_BOOL, true);
sDefaults.putBoolean(KEY_CALL_FORWARDING_WHEN_UNANSWERED_SUPPORTED_BOOL, true);
@@ -4432,7 +4471,8 @@ public class CarrierConfigManager {
"ims:2", "cbs:2", "ia:2", "emergency:2", "mcx:3", "xcap:3"
});
sDefaults.putStringArray(KEY_MISSED_INCOMING_CALL_SMS_PATTERN_STRING_ARRAY, new String[0]);
- sDefaults.putBoolean(KEY_DISABLE_DUN_APN_WHILE_ROAMING, false);
+ sDefaults.putBoolean(KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL, false);
+ sDefaults.putString(KEY_DEFAULT_PREFERRED_APN_NAME_STRING, "");
}
/**
diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java
index 2b3072eefe2e..da7311c08307 100644
--- a/telephony/java/android/telephony/ims/ImsService.java
+++ b/telephony/java/android/telephony/ims/ImsService.java
@@ -137,18 +137,30 @@ public class ImsService extends Service {
}
@Override
- public IImsMmTelFeature createMmTelFeature(int slotId, IImsFeatureStatusCallback c) {
- return createMmTelFeatureInternal(slotId, c);
+ public IImsMmTelFeature createMmTelFeature(int slotId) {
+ return createMmTelFeatureInternal(slotId);
}
@Override
- public IImsRcsFeature createRcsFeature(int slotId, IImsFeatureStatusCallback c) {
- return createRcsFeatureInternal(slotId, c);
+ public IImsRcsFeature createRcsFeature(int slotId) {
+ return createRcsFeatureInternal(slotId);
}
@Override
- public void removeImsFeature(int slotId, int featureType, IImsFeatureStatusCallback c) {
- ImsService.this.removeImsFeature(slotId, featureType, c);
+ public void addFeatureStatusCallback(int slotId, int featureType,
+ IImsFeatureStatusCallback c) {
+ ImsService.this.addImsFeatureStatusCallback(slotId, featureType, c);
+ }
+
+ @Override
+ public void removeFeatureStatusCallback(int slotId, int featureType,
+ IImsFeatureStatusCallback c) {
+ ImsService.this.removeImsFeatureStatusCallback(slotId, featureType, c);
+ }
+
+ @Override
+ public void removeImsFeature(int slotId, int featureType) {
+ ImsService.this.removeImsFeature(slotId, featureType);
}
@Override
@@ -204,11 +216,10 @@ public class ImsService extends Service {
return mFeaturesBySlot.get(slotId);
}
- private IImsMmTelFeature createMmTelFeatureInternal(int slotId,
- IImsFeatureStatusCallback c) {
+ private IImsMmTelFeature createMmTelFeatureInternal(int slotId) {
MmTelFeature f = createMmTelFeature(slotId);
if (f != null) {
- setupFeature(f, slotId, ImsFeature.FEATURE_MMTEL, c);
+ setupFeature(f, slotId, ImsFeature.FEATURE_MMTEL);
return f.getBinder();
} else {
Log.e(LOG_TAG, "createMmTelFeatureInternal: null feature returned.");
@@ -216,11 +227,10 @@ public class ImsService extends Service {
}
}
- private IImsRcsFeature createRcsFeatureInternal(int slotId,
- IImsFeatureStatusCallback c) {
+ private IImsRcsFeature createRcsFeatureInternal(int slotId) {
RcsFeature f = createRcsFeature(slotId);
if (f != null) {
- setupFeature(f, slotId, ImsFeature.FEATURE_RCS, c);
+ setupFeature(f, slotId, ImsFeature.FEATURE_RCS);
return f.getBinder();
} else {
Log.e(LOG_TAG, "createRcsFeatureInternal: null feature returned.");
@@ -228,13 +238,45 @@ public class ImsService extends Service {
}
}
- private void setupFeature(ImsFeature f, int slotId, int featureType,
- IImsFeatureStatusCallback c) {
+ private void setupFeature(ImsFeature f, int slotId, int featureType) {
f.initialize(this, slotId);
- f.addImsFeatureStatusCallback(c);
addImsFeature(slotId, featureType, f);
}
+ private void addImsFeatureStatusCallback(int slotId, int featureType,
+ IImsFeatureStatusCallback c) {
+ synchronized (mFeaturesBySlot) {
+ // get ImsFeature associated with the slot/feature
+ SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId);
+ if (features == null) {
+ Log.w(LOG_TAG, "Can not add ImsFeatureStatusCallback - no features on slot "
+ + slotId);
+ return;
+ }
+ ImsFeature f = features.get(featureType);
+ if (f != null) {
+ f.addImsFeatureStatusCallback(c);
+ }
+ }
+ }
+
+ private void removeImsFeatureStatusCallback(int slotId, int featureType,
+ IImsFeatureStatusCallback c) {
+ synchronized (mFeaturesBySlot) {
+ // get ImsFeature associated with the slot/feature
+ SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId);
+ if (features == null) {
+ Log.w(LOG_TAG, "Can not remove ImsFeatureStatusCallback - no features on slot "
+ + slotId);
+ return;
+ }
+ ImsFeature f = features.get(featureType);
+ if (f != null) {
+ f.removeImsFeatureStatusCallback(c);
+ }
+ }
+ }
+
private void addImsFeature(int slotId, int featureType, ImsFeature f) {
synchronized (mFeaturesBySlot) {
// Get SparseArray for Features, by querying slot Id
@@ -248,8 +290,7 @@ public class ImsService extends Service {
}
}
- private void removeImsFeature(int slotId, int featureType,
- IImsFeatureStatusCallback c) {
+ private void removeImsFeature(int slotId, int featureType) {
synchronized (mFeaturesBySlot) {
// get ImsFeature associated with the slot/feature
SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId);
@@ -264,7 +305,6 @@ public class ImsService extends Service {
+ featureType + " exists on slot " + slotId);
return;
}
- f.removeImsFeatureStatusCallback(c);
f.onFeatureRemoved();
features.remove(featureType);
}
diff --git a/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl b/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl
index c7da681b86a3..c956cbcc816c 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl
@@ -31,12 +31,14 @@ import com.android.ims.internal.IImsFeatureStatusCallback;
*/
interface IImsServiceController {
void setListener(IImsServiceControllerListener l);
- IImsMmTelFeature createMmTelFeature(int slotId, in IImsFeatureStatusCallback c);
- IImsRcsFeature createRcsFeature(int slotId, in IImsFeatureStatusCallback c);
+ IImsMmTelFeature createMmTelFeature(int slotId);
+ IImsRcsFeature createRcsFeature(int slotId);
ImsFeatureConfiguration querySupportedImsFeatures();
+ void addFeatureStatusCallback(int slotId, int featureType, in IImsFeatureStatusCallback c);
+ void removeFeatureStatusCallback(int slotId, int featureType, in IImsFeatureStatusCallback c);
// Synchronous call to ensure the ImsService is ready before continuing with feature creation.
void notifyImsServiceReadyForFeatureCreation();
- void removeImsFeature(int slotId, int featureType, in IImsFeatureStatusCallback c);
+ void removeImsFeature(int slotId, int featureType);
IImsConfig getConfig(int slotId);
IImsRegistration getRegistration(int slotId);
oneway void enableIms(int slotId);
diff --git a/telephony/java/android/telephony/ims/compat/ImsService.java b/telephony/java/android/telephony/ims/compat/ImsService.java
index eafbb14539f5..41d1d726b3f4 100644
--- a/telephony/java/android/telephony/ims/compat/ImsService.java
+++ b/telephony/java/android/telephony/ims/compat/ImsService.java
@@ -21,7 +21,6 @@ import android.app.Service;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Intent;
import android.os.IBinder;
-import android.os.RemoteException;
import android.telephony.CarrierConfigManager;
import android.telephony.ims.compat.feature.ImsFeature;
import android.telephony.ims.compat.feature.MMTelFeature;
@@ -91,25 +90,35 @@ public class ImsService extends Service {
protected final IBinder mImsServiceController = new IImsServiceController.Stub() {
@Override
- public IImsMMTelFeature createEmergencyMMTelFeature(int slotId,
- IImsFeatureStatusCallback c) {
- return createEmergencyMMTelFeatureInternal(slotId, c);
+ public IImsMMTelFeature createEmergencyMMTelFeature(int slotId) {
+ return createEmergencyMMTelFeatureInternal(slotId);
}
@Override
- public IImsMMTelFeature createMMTelFeature(int slotId, IImsFeatureStatusCallback c) {
- return createMMTelFeatureInternal(slotId, c);
+ public IImsMMTelFeature createMMTelFeature(int slotId) {
+ return createMMTelFeatureInternal(slotId);
}
@Override
- public IImsRcsFeature createRcsFeature(int slotId, IImsFeatureStatusCallback c) {
- return createRcsFeatureInternal(slotId, c);
+ public IImsRcsFeature createRcsFeature(int slotId) {
+ return createRcsFeatureInternal(slotId);
}
@Override
- public void removeImsFeature(int slotId, int featureType, IImsFeatureStatusCallback c)
- throws RemoteException {
- ImsService.this.removeImsFeature(slotId, featureType, c);
+ public void removeImsFeature(int slotId, int featureType) {
+ ImsService.this.removeImsFeature(slotId, featureType);
+ }
+
+ @Override
+ public void addFeatureStatusCallback(int slotId, int featureType,
+ IImsFeatureStatusCallback c) {
+ addImsFeatureStatusCallback(slotId, featureType, c);
+ }
+
+ @Override
+ public void removeFeatureStatusCallback(int slotId, int featureType,
+ IImsFeatureStatusCallback c) {
+ removeImsFeatureStatusCallback(slotId, featureType, c);
}
};
@@ -137,46 +146,40 @@ public class ImsService extends Service {
return mFeaturesBySlot.get(slotId);
}
- private IImsMMTelFeature createEmergencyMMTelFeatureInternal(int slotId,
- IImsFeatureStatusCallback c) {
+ private IImsMMTelFeature createEmergencyMMTelFeatureInternal(int slotId) {
MMTelFeature f = onCreateEmergencyMMTelImsFeature(slotId);
if (f != null) {
- setupFeature(f, slotId, ImsFeature.EMERGENCY_MMTEL, c);
+ setupFeature(f, slotId, ImsFeature.EMERGENCY_MMTEL);
return f.getBinder();
} else {
return null;
}
}
- private IImsMMTelFeature createMMTelFeatureInternal(int slotId,
- IImsFeatureStatusCallback c) {
+ private IImsMMTelFeature createMMTelFeatureInternal(int slotId) {
MMTelFeature f = onCreateMMTelImsFeature(slotId);
if (f != null) {
- setupFeature(f, slotId, ImsFeature.MMTEL, c);
+ setupFeature(f, slotId, ImsFeature.MMTEL);
return f.getBinder();
} else {
return null;
}
}
- private IImsRcsFeature createRcsFeatureInternal(int slotId,
- IImsFeatureStatusCallback c) {
+ private IImsRcsFeature createRcsFeatureInternal(int slotId) {
RcsFeature f = onCreateRcsFeature(slotId);
if (f != null) {
- setupFeature(f, slotId, ImsFeature.RCS, c);
+ setupFeature(f, slotId, ImsFeature.RCS);
return f.getBinder();
} else {
return null;
}
}
- private void setupFeature(ImsFeature f, int slotId, int featureType,
- IImsFeatureStatusCallback c) {
+ private void setupFeature(ImsFeature f, int slotId, int featureType) {
f.setContext(this);
f.setSlotId(slotId);
- f.addImsFeatureStatusCallback(c);
addImsFeature(slotId, featureType, f);
- // TODO: Remove once new onFeatureReady AIDL is merged in.
f.onFeatureReady();
}
@@ -193,12 +196,45 @@ public class ImsService extends Service {
}
}
- private void removeImsFeature(int slotId, int featureType,
+ private void addImsFeatureStatusCallback(int slotId, int featureType,
+ IImsFeatureStatusCallback c) {
+ synchronized (mFeaturesBySlot) {
+ // get ImsFeature associated with the slot/feature
+ SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId);
+ if (features == null) {
+ Log.w(LOG_TAG, "Can not add ImsFeatureStatusCallback. No ImsFeatures exist on"
+ + " slot " + slotId);
+ return;
+ }
+ ImsFeature f = features.get(featureType);
+ if (f != null) {
+ f.addImsFeatureStatusCallback(c);
+ }
+ }
+ }
+
+ private void removeImsFeatureStatusCallback(int slotId, int featureType,
IImsFeatureStatusCallback c) {
synchronized (mFeaturesBySlot) {
// get ImsFeature associated with the slot/feature
SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId);
if (features == null) {
+ Log.w(LOG_TAG, "Can not remove ImsFeatureStatusCallback. No ImsFeatures exist on"
+ + " slot " + slotId);
+ return;
+ }
+ ImsFeature f = features.get(featureType);
+ if (f != null) {
+ f.removeImsFeatureStatusCallback(c);
+ }
+ }
+ }
+
+ private void removeImsFeature(int slotId, int featureType) {
+ synchronized (mFeaturesBySlot) {
+ // get ImsFeature associated with the slot/feature
+ SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId);
+ if (features == null) {
Log.w(LOG_TAG, "Can not remove ImsFeature. No ImsFeatures exist on slot "
+ slotId);
return;
@@ -209,7 +245,6 @@ public class ImsService extends Service {
+ featureType + " exists on slot " + slotId);
return;
}
- f.removeImsFeatureStatusCallback(c);
f.onFeatureRemoved();
features.remove(featureType);
}
diff --git a/telephony/java/com/android/ims/internal/IImsServiceController.aidl b/telephony/java/com/android/ims/internal/IImsServiceController.aidl
index 857089fac33a..e9528f474082 100644
--- a/telephony/java/com/android/ims/internal/IImsServiceController.aidl
+++ b/telephony/java/com/android/ims/internal/IImsServiceController.aidl
@@ -25,8 +25,10 @@ import com.android.ims.internal.IImsRcsFeature;
* {@hide}
*/
interface IImsServiceController {
- IImsMMTelFeature createEmergencyMMTelFeature(int slotId, in IImsFeatureStatusCallback c);
- IImsMMTelFeature createMMTelFeature(int slotId, in IImsFeatureStatusCallback c);
- IImsRcsFeature createRcsFeature(int slotId, in IImsFeatureStatusCallback c);
- void removeImsFeature(int slotId, int featureType, in IImsFeatureStatusCallback c);
+ IImsMMTelFeature createEmergencyMMTelFeature(int slotId);
+ IImsMMTelFeature createMMTelFeature(int slotId);
+ IImsRcsFeature createRcsFeature(int slotId);
+ void removeImsFeature(int slotId, int featureType);
+ void addFeatureStatusCallback(int slotId, int featureType, in IImsFeatureStatusCallback c);
+ void removeFeatureStatusCallback(int slotId, int featureType, in IImsFeatureStatusCallback c);
}