Merge branch 'dev/11/fp3/security-aosp-rvc-release' into int/11/fp3

* dev/11/fp3/security-aosp-rvc-release:
  RESTRICT AUTOMERGE: Catch exceptions from setLockCredential()
  Restrict ApnEditor settings
  DO NOT MERGE: Prevent non-system IME from becoming device admin
  Settings: don't try to allow NLSes with too-long component names
  DO NOT MERGE Don't hide approved NLSes in Settings

Change-Id: I4147af6331399be28cc277d0464ed8fd4a2fb964
diff --git a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java
index 113922e..59ec178 100644
--- a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java
+++ b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java
@@ -50,6 +50,8 @@
 import android.util.EventLog;
 import android.util.Log;
 import android.view.Display;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
@@ -138,7 +140,7 @@
         mAppOps = (AppOpsManager)getSystemService(Context.APP_OPS_SERVICE);
         PackageManager packageManager = getPackageManager();
 
-        if ((getIntent().getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
+        if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
             Log.w(TAG, "Cannot start ADD_DEVICE_ADMIN as a new task");
             finish();
             return;
@@ -148,7 +150,7 @@
                 EXTRA_CALLED_FROM_SUPPORT_DIALOG, false);
 
         String action = getIntent().getAction();
-        ComponentName who = (ComponentName)getIntent().getParcelableExtra(
+        ComponentName who = (ComponentName) getIntent().getParcelableExtra(
                 DevicePolicyManager.EXTRA_DEVICE_ADMIN);
         if (who == null) {
             String packageName = getIntent().getStringExtra(EXTRA_DEVICE_ADMIN_PACKAGE_NAME);
@@ -206,7 +208,7 @@
                     PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS);
             int count = avail == null ? 0 : avail.size();
             boolean found = false;
-            for (int i=0; i<count; i++) {
+            for (int i = 0; i < count; i++) {
                 ResolveInfo ri = avail.get(i);
                 if (ai.packageName.equals(ri.activityInfo.packageName)
                         && ai.name.equals(ri.activityInfo.name)) {
@@ -337,12 +339,12 @@
         }
         setContentView(R.layout.device_admin_add);
 
-        mAdminIcon = (ImageView)findViewById(R.id.admin_icon);
-        mAdminName = (TextView)findViewById(R.id.admin_name);
-        mAdminDescription = (TextView)findViewById(R.id.admin_description);
+        mAdminIcon = (ImageView) findViewById(R.id.admin_icon);
+        mAdminName = (TextView) findViewById(R.id.admin_name);
+        mAdminDescription = (TextView) findViewById(R.id.admin_description);
         mProfileOwnerWarning = (TextView) findViewById(R.id.profile_owner_warning);
 
-        mAddMsg = (TextView)findViewById(R.id.add_msg);
+        mAddMsg = (TextView) findViewById(R.id.add_msg);
         mAddMsgExpander = (ImageView) findViewById(R.id.add_msg_expander);
         final View.OnClickListener onClickListener = new View.OnClickListener() {
             @Override
@@ -363,7 +365,7 @@
                         boolean hideMsgExpander = mAddMsg.getLineCount() <= maxLines;
                         mAddMsgExpander.setVisibility(hideMsgExpander ? View.GONE : View.VISIBLE);
                         if (hideMsgExpander) {
-                            ((View)mAddMsgExpander.getParent()).invalidate();
+                            ((View) mAddMsgExpander.getParent()).invalidate();
                         }
                         mAddMsg.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                     }
@@ -381,7 +383,7 @@
         mCancelButton.setOnClickListener(new View.OnClickListener() {
             public void onClick(View v) {
                 EventLog.writeEvent(EventLogTags.EXP_DET_DEVICE_ADMIN_DECLINED_BY_USER,
-                    mDeviceAdmin.getActivityInfo().applicationInfo.uid);
+                        mDeviceAdmin.getActivityInfo().applicationInfo.uid);
                 finish();
             }
         });
@@ -401,58 +403,64 @@
 
         final View restrictedAction = findViewById(R.id.restricted_action);
         restrictedAction.setFilterTouchesWhenObscured(true);
-        restrictedAction.setOnClickListener(new View.OnClickListener() {
-            public void onClick(View v) {
-                if (!mActionButton.isEnabled()) {
-                    showPolicyTransparencyDialogIfRequired();
-                    return;
-                }
-                if (mAdding) {
-                    addAndFinish();
-                } else if (isManagedProfile(mDeviceAdmin)
-                        && mDeviceAdmin.getComponent().equals(mDPM.getProfileOwner())) {
-                    final int userId = UserHandle.myUserId();
-                    UserDialogs.createRemoveDialog(DeviceAdminAdd.this, userId,
-                            new DialogInterface.OnClickListener() {
-                                @Override
-                                public void onClick(DialogInterface dialog, int which) {
-                                    UserManager um = UserManager.get(DeviceAdminAdd.this);
-                                    um.removeUser(userId);
-                                    finish();
-                                }
-                            }
-                    ).show();
-                } else if (mUninstalling) {
-                    mDPM.uninstallPackageWithActiveAdmins(mDeviceAdmin.getPackageName());
-                    finish();
-                } else if (!mWaitingForRemoveMsg) {
-                    try {
-                        // Don't allow the admin to put a dialog up in front
-                        // of us while we interact with the user.
-                        ActivityManager.getService().stopAppSwitches();
-                    } catch (RemoteException e) {
-                    }
-                    mWaitingForRemoveMsg = true;
-                    mDPM.getRemoveWarning(mDeviceAdmin.getComponent(),
-                            new RemoteCallback(new RemoteCallback.OnResultListener() {
-                                @Override
-                                public void onResult(Bundle result) {
-                                    CharSequence msg = result != null
-                                            ? result.getCharSequence(
-                                            DeviceAdminReceiver.EXTRA_DISABLE_WARNING)
-                                            : null;
-                                    continueRemoveAction(msg);
-                                }
-                            }, mHandler));
-                    // Don't want to wait too long.
-                    getWindow().getDecorView().getHandler().postDelayed(new Runnable() {
-                        @Override public void run() {
-                            continueRemoveAction(null);
-                        }
-                    }, 2*1000);
-                }
+
+        final View.OnClickListener restrictedActionClickListener = v -> {
+            if (!mActionButton.isEnabled()) {
+                showPolicyTransparencyDialogIfRequired();
+                return;
             }
+            if (mAdding) {
+                addAndFinish();
+            } else if (isManagedProfile(mDeviceAdmin)
+                    && mDeviceAdmin.getComponent().equals(mDPM.getProfileOwner())) {
+                final int userId = UserHandle.myUserId();
+                UserDialogs.createRemoveDialog(DeviceAdminAdd.this, userId,
+                        new DialogInterface.OnClickListener() {
+                            @Override
+                            public void onClick(DialogInterface dialog, int which) {
+                                UserManager um = UserManager.get(DeviceAdminAdd.this);
+                                um.removeUser(userId);
+                                finish();
+                            }
+                        }
+                ).show();
+            } else if (mUninstalling) {
+                mDPM.uninstallPackageWithActiveAdmins(mDeviceAdmin.getPackageName());
+                finish();
+            } else if (!mWaitingForRemoveMsg) {
+                try {
+                    // Don't allow the admin to put a dialog up in front
+                    // of us while we interact with the user.
+                    ActivityManager.getService().stopAppSwitches();
+                } catch (RemoteException e) {
+                }
+                mWaitingForRemoveMsg = true;
+                mDPM.getRemoveWarning(mDeviceAdmin.getComponent(),
+                        new RemoteCallback(new RemoteCallback.OnResultListener() {
+                            @Override
+                            public void onResult(Bundle result) {
+                                CharSequence msg = result != null
+                                        ? result.getCharSequence(
+                                        DeviceAdminReceiver.EXTRA_DISABLE_WARNING)
+                                        : null;
+                                continueRemoveAction(msg);
+                            }
+                        }, mHandler));
+                // Don't want to wait too long.
+                getWindow().getDecorView().getHandler().postDelayed(
+                        () -> continueRemoveAction(null), 2 * 1000);
+            }
+        };
+        restrictedAction.setOnKeyListener((view, keyCode, keyEvent) -> {
+            if ((keyEvent.getFlags() & KeyEvent.FLAG_FROM_SYSTEM) == 0) {
+                Log.e(TAG, "Can not activate device-admin with KeyEvent from non-system app.");
+                // Consume event to suppress click.
+                return true;
+            }
+            // Fallback to view click handler.
+            return false;
         });
+        restrictedAction.setOnClickListener(restrictedActionClickListener);
     }
 
     /**
diff --git a/src/com/android/settings/applications/specialaccess/notificationaccess/NotificationAccessDetails.java b/src/com/android/settings/applications/specialaccess/notificationaccess/NotificationAccessDetails.java
index 6a4c22e..c77c2b9 100644
--- a/src/com/android/settings/applications/specialaccess/notificationaccess/NotificationAccessDetails.java
+++ b/src/com/android/settings/applications/specialaccess/notificationaccess/NotificationAccessDetails.java
@@ -181,7 +181,10 @@
 
     public void updatePreference(SwitchPreference preference) {
         final CharSequence label = mPackageInfo.applicationInfo.loadLabel(mPm);
+        final boolean isAllowedCn = mComponentName.flattenToShortString().length()
+                <= NotificationManager.MAX_SERVICE_COMPONENT_NAME_LENGTH;
         preference.setChecked(isServiceEnabled(mComponentName));
+        preference.setEnabled(preference.isChecked() || isAllowedCn);
         preference.setOnPreferenceChangeListener((p, newValue) -> {
             final boolean access = (Boolean) newValue;
             if (!access) {
diff --git a/src/com/android/settings/network/ApnEditor.java b/src/com/android/settings/network/ApnEditor.java
index 9ab30cc..0cc8196 100644
--- a/src/com/android/settings/network/ApnEditor.java
+++ b/src/com/android/settings/network/ApnEditor.java
@@ -25,6 +25,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.PersistableBundle;
+import android.os.UserManager;
 import android.provider.Telephony;
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionInfo;
@@ -287,6 +288,11 @@
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
+        if (isUserRestricted()) {
+            Log.e(TAG, "This setting isn't available due to user restriction.");
+            finish();
+            return;
+        }
 
         setLifecycleForAllControllers();
 
@@ -1418,6 +1424,23 @@
         }
     }
 
+    @VisibleForTesting
+    boolean isUserRestricted() {
+        UserManager userManager = getContext().getSystemService(UserManager.class);
+        if (userManager == null) {
+            return false;
+        }
+        if (!userManager.isAdminUser()) {
+            Log.e(TAG, "User is not an admin");
+            return true;
+        }
+        if (userManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) {
+            Log.e(TAG, "User is not allowed to configure mobile network");
+            return true;
+        }
+        return false;
+    }
+
     public static class ErrorDialog extends InstrumentedDialogFragment {
 
         public static void showError(ApnEditor editor) {
diff --git a/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java b/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java
index dfe6df2..a6b565a 100644
--- a/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java
+++ b/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java
@@ -67,7 +67,9 @@
         mUserId = getIntent().getIntExtra(EXTRA_USER_ID, UserHandle.USER_NULL);
         CharSequence mAppLabel;
 
-        if (mComponentName == null || mComponentName.getPackageName() == null) {
+        if (mComponentName == null || mComponentName.getPackageName() == null
+                || mComponentName.flattenToString().length()
+                > NotificationManager.MAX_SERVICE_COMPONENT_NAME_LENGTH) {
             finish();
             return;
         }
diff --git a/src/com/android/settings/notification/NotificationAccessSettings.java b/src/com/android/settings/notification/NotificationAccessSettings.java
index 71e58e4..20e019e 100644
--- a/src/com/android/settings/notification/NotificationAccessSettings.java
+++ b/src/com/android/settings/notification/NotificationAccessSettings.java
@@ -58,8 +58,6 @@
 public class NotificationAccessSettings extends EmptyTextSettings {
     private static final String TAG = "NotifAccessSettings";
 
-    private static final int MAX_CN_LENGTH = 500;
-
     private static final ManagedServiceSettings.Config CONFIG =
             new ManagedServiceSettings.Config.Builder()
                     .setTag(TAG)
@@ -94,12 +92,6 @@
                 .setNoun(CONFIG.noun)
                 .setSetting(CONFIG.setting)
                 .setTag(CONFIG.tag)
-                .setValidator(info -> {
-                    if (info.getComponentName().flattenToString().length() > MAX_CN_LENGTH) {
-                        return false;
-                    }
-                    return true;
-                })
                 .build();
         mServiceListing.addCallback(this::updateList);
         setPreferenceScreen(getPreferenceManager().createPreferenceScreen(mContext));
@@ -140,6 +132,12 @@
         services.sort(new PackageItemInfo.DisplayNameComparator(mPm));
         for (ServiceInfo service : services) {
             final ComponentName cn = new ComponentName(service.packageName, service.name);
+            boolean isAllowed = mNm.isNotificationListenerAccessGranted(cn);
+            if (!isAllowed && cn.flattenToString().length()
+                    > NotificationManager.MAX_SERVICE_COMPONENT_NAME_LENGTH) {
+                continue;
+            }
+
             CharSequence title = null;
             try {
                 title = mPm.getApplicationInfoAsUser(
@@ -154,7 +152,7 @@
             pref.setIcon(mIconDrawableFactory.getBadgedIcon(service, service.applicationInfo,
                     UserHandle.getUserId(service.applicationInfo.uid)));
             pref.setKey(cn.flattenToString());
-            pref.setSummary(mNm.isNotificationListenerAccessGranted(cn)
+            pref.setSummary(isAllowed
                     ? R.string.app_permission_summary_allowed
                     : R.string.app_permission_summary_not_allowed);
             if (managedProfileId != UserHandle.USER_NULL
diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java
index 19cc9c8..9571ff9 100644
--- a/src/com/android/settings/password/ChooseLockPassword.java
+++ b/src/com/android/settings/password/ChooseLockPassword.java
@@ -958,8 +958,13 @@
 
         @Override
         protected Pair<Boolean, Intent> saveAndVerifyInBackground() {
-            final boolean success = mUtils.setLockCredential(
-                    mChosenPassword, mCurrentCredential, mUserId);
+            boolean success;
+            try {
+                success = mUtils.setLockCredential(mChosenPassword, mCurrentCredential, mUserId);
+            } catch (RuntimeException e) {
+                Log.e(TAG, "Failed to set lockscreen credential", e);
+                success = false;
+            }
             if (success) {
                 unifyProfileCredentialIfRequested();
             }
diff --git a/src/com/android/settings/password/ChooseLockPattern.java b/src/com/android/settings/password/ChooseLockPattern.java
index 27fc9f0..61638cb 100644
--- a/src/com/android/settings/password/ChooseLockPattern.java
+++ b/src/com/android/settings/password/ChooseLockPattern.java
@@ -902,8 +902,13 @@
         @Override
         protected Pair<Boolean, Intent> saveAndVerifyInBackground() {
             final int userId = mUserId;
-            final boolean success = mUtils.setLockCredential(mChosenPattern, mCurrentCredential,
-                    userId);
+            boolean success;
+            try {
+                success = mUtils.setLockCredential(mChosenPattern, mCurrentCredential, userId);
+            } catch (RuntimeException e) {
+                Log.e(TAG, "Failed to set lockscreen credential", e);
+                success = false;
+            }
             if (success) {
                 unifyProfileCredentialIfRequested();
             }
diff --git a/tests/robotests/src/com/android/settings/network/ApnEditorTest.java b/tests/robotests/src/com/android/settings/network/ApnEditorTest.java
index 7ec1174..5879c7f 100644
--- a/tests/robotests/src/com/android/settings/network/ApnEditorTest.java
+++ b/tests/robotests/src/com/android/settings/network/ApnEditorTest.java
@@ -34,6 +34,7 @@
 import android.content.res.Resources;
 import android.database.Cursor;
 import android.net.Uri;
+import android.os.UserManager;
 import android.view.KeyEvent;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -101,6 +102,8 @@
     @Mock
     private FragmentActivity mActivity;
     @Mock
+    private UserManager mUserManager;
+    @Mock
     private ProxySubscriptionManager mProxySubscriptionMgr;
 
     @Captor
@@ -126,6 +129,11 @@
         doReturn(mContext.getTheme()).when(mActivity).getTheme();
         doReturn(mContext.getContentResolver()).when(mActivity).getContentResolver();
 
+        doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
+        doReturn(true).when(mUserManager).isAdminUser();
+        doReturn(false).when(mUserManager)
+                .hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
+
         setMockPreference(mContext);
         mApnEditorUT.mApnData = new FakeApnData(APN_DATA);
         mApnEditorUT.sNotSet = "Not Set";
@@ -452,6 +460,27 @@
 
     @Test
     @Config(shadows = ShadowFragment.class)
+    public void onCreate_notAdminUser_shouldFinish() {
+        doReturn(false).when(mUserManager).isAdminUser();
+
+        mApnEditorUT.onCreate(null);
+
+        verify(mApnEditorUT).finish();
+    }
+
+    @Test
+    @Config(shadows = ShadowFragment.class)
+    public void onCreate_hasUserRestriction_shouldFinish() {
+        doReturn(true).when(mUserManager)
+                .hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
+
+        mApnEditorUT.onCreate(null);
+
+        verify(mApnEditorUT).finish();
+    }
+
+    @Test
+    @Config(shadows = ShadowFragment.class)
     public void onCreate_noAction_shouldFinishAndNoCrash() {
         ProxySubscriptionManager proxySubscriptionMgr = mock(ProxySubscriptionManager.class);
         mApnEditorUT.mProxySubscriptionMgr = proxySubscriptionMgr;