Merge "Import translations. DO NOT MERGE" into klp-dev
diff --git a/res/mipmap-hdpi/ic_launcher_settings.png b/res/mipmap-hdpi/ic_launcher_settings.png
index 32da776..a8ccc89 100644
--- a/res/mipmap-hdpi/ic_launcher_settings.png
+++ b/res/mipmap-hdpi/ic_launcher_settings.png
Binary files differ
diff --git a/res/mipmap-mdpi/ic_launcher_settings.png b/res/mipmap-mdpi/ic_launcher_settings.png
index 32a22ac..69709a8 100644
--- a/res/mipmap-mdpi/ic_launcher_settings.png
+++ b/res/mipmap-mdpi/ic_launcher_settings.png
Binary files differ
diff --git a/res/mipmap-xhdpi/ic_launcher_settings.png b/res/mipmap-xhdpi/ic_launcher_settings.png
index 9bfdd78..c3adce6 100644
--- a/res/mipmap-xhdpi/ic_launcher_settings.png
+++ b/res/mipmap-xhdpi/ic_launcher_settings.png
Binary files differ
diff --git a/res/mipmap-xxhdpi/ic_launcher_settings.png b/res/mipmap-xxhdpi/ic_launcher_settings.png
index 489ed6a..52fe978 100644
--- a/res/mipmap-xxhdpi/ic_launcher_settings.png
+++ b/res/mipmap-xxhdpi/ic_launcher_settings.png
Binary files differ
diff --git a/res/mipmap-xxxhdpi/ic_launcher_settings.png b/res/mipmap-xxxhdpi/ic_launcher_settings.png
new file mode 100644
index 0000000..6b92795
--- /dev/null
+++ b/res/mipmap-xxxhdpi/ic_launcher_settings.png
Binary files differ
diff --git a/src/com/android/settings/CredentialStorage.java b/src/com/android/settings/CredentialStorage.java
index 9173e39..fcf208a 100644
--- a/src/com/android/settings/CredentialStorage.java
+++ b/src/com/android/settings/CredentialStorage.java
@@ -25,6 +25,7 @@
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.RemoteException;
+import android.os.Process;
 import android.security.Credentials;
 import android.security.KeyChain.KeyChainConnection;
 import android.security.KeyChain;
@@ -39,6 +40,14 @@
 import android.widget.Toast;
 import com.android.internal.widget.LockPatternUtils;
 
+import com.android.org.bouncycastle.asn1.ASN1InputStream;
+import com.android.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+
+import org.apache.harmony.security.utils.AlgNameMapper;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
 /**
  * CredentialStorage handles KeyStore reset, unlock, and install.
  *
@@ -182,6 +191,20 @@
         return (quality >= MIN_PASSWORD_QUALITY);
     }
 
+    private boolean isHardwareBackedKey(byte[] keyData) {
+        try {
+            ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(keyData));
+            PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject());
+            String algId = pki.getAlgorithmId().getAlgorithm().getId();
+            String algName = AlgNameMapper.map2AlgName(algId);
+
+            return KeyChain.isBoundKeyAlgorithm(algName);
+        } catch (IOException e) {
+            Log.e(TAG, "Failed to parse key data");
+            return false;
+        }
+    }
+
     /**
      * Install credentials if available, otherwise do nothing.
      */
@@ -196,17 +219,27 @@
                 String key = bundle.getString(Credentials.EXTRA_USER_PRIVATE_KEY_NAME);
                 byte[] value = bundle.getByteArray(Credentials.EXTRA_USER_PRIVATE_KEY_DATA);
 
-                if (!mKeyStore.importKey(key, value, uid, KeyStore.FLAG_ENCRYPTED)) {
+                int flags = KeyStore.FLAG_ENCRYPTED;
+                if (uid == Process.WIFI_UID && isHardwareBackedKey(value)) {
+                    // Hardware backed keystore is secure enough to allow for WIFI stack
+                    // to enable access to secure networks without user intervention
+                    Log.d(TAG, "Saving private key with FLAG_NONE for WIFI_UID");
+                    flags = KeyStore.FLAG_NONE;
+                }
+
+                if (!mKeyStore.importKey(key, value, uid, flags)) {
                     Log.e(TAG, "Failed to install " + key + " as user " + uid);
                     return;
                 }
             }
 
+            int flags = (uid == Process.WIFI_UID) ? KeyStore.FLAG_NONE : KeyStore.FLAG_ENCRYPTED;
+
             if (bundle.containsKey(Credentials.EXTRA_USER_CERTIFICATE_NAME)) {
                 String certName = bundle.getString(Credentials.EXTRA_USER_CERTIFICATE_NAME);
                 byte[] certData = bundle.getByteArray(Credentials.EXTRA_USER_CERTIFICATE_DATA);
 
-                if (!mKeyStore.put(certName, certData, uid, KeyStore.FLAG_ENCRYPTED)) {
+                if (!mKeyStore.put(certName, certData, uid, flags)) {
                     Log.e(TAG, "Failed to install " + certName + " as user " + uid);
                     return;
                 }
@@ -216,7 +249,7 @@
                 String caListName = bundle.getString(Credentials.EXTRA_CA_CERTIFICATES_NAME);
                 byte[] caListData = bundle.getByteArray(Credentials.EXTRA_CA_CERTIFICATES_DATA);
 
-                if (!mKeyStore.put(caListName, caListData, uid, KeyStore.FLAG_ENCRYPTED)) {
+                if (!mKeyStore.put(caListName, caListData, uid, flags)) {
                     Log.e(TAG, "Failed to install " + caListName + " as user " + uid);
                     return;
                 }
diff --git a/src/com/android/settings/deviceinfo/Memory.java b/src/com/android/settings/deviceinfo/Memory.java
index d03f6dc..999611d 100644
--- a/src/com/android/settings/deviceinfo/Memory.java
+++ b/src/com/android/settings/deviceinfo/Memory.java
@@ -19,6 +19,7 @@
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.DialogFragment;
+import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -223,7 +224,11 @@
             if (intent != null) {
                 // Don't go across app boundary if monkey is running
                 if (!Utils.isMonkeyRunning()) {
-                    startActivity(intent);
+                    try {
+                        startActivity(intent);
+                    } catch (ActivityNotFoundException anfe) {
+                        Log.w(TAG, "No activity found for intent " + intent);
+                    }
                 }
                 return true;
             }
diff --git a/src/com/android/settings/deviceinfo/StorageVolumePreferenceCategory.java b/src/com/android/settings/deviceinfo/StorageVolumePreferenceCategory.java
index 1992fac..4e5bd63 100644
--- a/src/com/android/settings/deviceinfo/StorageVolumePreferenceCategory.java
+++ b/src/com/android/settings/deviceinfo/StorageVolumePreferenceCategory.java
@@ -34,6 +34,7 @@
 import android.os.storage.StorageVolume;
 import android.preference.Preference;
 import android.preference.PreferenceCategory;
+import android.provider.MediaStore;
 import android.text.format.Formatter;
 
 import com.android.settings.R;
@@ -437,8 +438,8 @@
         } else if (pref == mItemDcim) {
             intent = new Intent(Intent.ACTION_VIEW);
             intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
-            // TODO Create a Videos category, type = vnd.android.cursor.dir/video
-            intent.setType("vnd.android.cursor.dir/image");
+            // TODO Create a Videos category, MediaStore.Video.Media.EXTERNAL_CONTENT_URI
+            intent.setData(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
         } else if (pref == mItemMisc) {
             Context context = getContext().getApplicationContext();
             intent = new Intent(context, MiscFilesHandler.class);
diff --git a/src/com/android/settings/print/PrintServiceSettingsFragment.java b/src/com/android/settings/print/PrintServiceSettingsFragment.java
index c10f4b9..f739b4d 100644
--- a/src/com/android/settings/print/PrintServiceSettingsFragment.java
+++ b/src/com/android/settings/print/PrintServiceSettingsFragment.java
@@ -640,6 +640,11 @@
         }
 
         @Override
+        public boolean isEnabled(int position) {
+            return false;
+        }
+
+        @Override
         public Loader<List<PrinterInfo>> onCreateLoader(int id, Bundle args) {
             if (id == LOADER_ID_PRINTERS_LOADER) {
                 return new PrintersLoader(getActivity());
diff --git a/src/com/android/settings/users/AppRestrictionsFragment.java b/src/com/android/settings/users/AppRestrictionsFragment.java
index 96a7b47..f1022b9 100644
--- a/src/com/android/settings/users/AppRestrictionsFragment.java
+++ b/src/com/android/settings/users/AppRestrictionsFragment.java
@@ -347,6 +347,9 @@
 
     protected Drawable getCircularUserIcon() {
         Bitmap userIcon = mUserManager.getUserIcon(mUser.getIdentifier());
+        if (userIcon == null) {
+            return null;
+        }
         CircleFramedDrawable circularIcon =
                 CircleFramedDrawable.getInstance(this.getActivity(), userIcon);
         return circularIcon;
diff --git a/src/com/android/settings/users/RestrictedProfileSettings.java b/src/com/android/settings/users/RestrictedProfileSettings.java
index 1d712ac..c293536 100644
--- a/src/com/android/settings/users/RestrictedProfileSettings.java
+++ b/src/com/android/settings/users/RestrictedProfileSettings.java
@@ -37,6 +37,7 @@
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Bundle;
+import android.os.UserHandle;
 import android.provider.MediaStore;
 import android.provider.ContactsContract.DisplayPhoto;
 import android.support.v4.content.FileProvider;
@@ -123,10 +124,25 @@
     public void onResume() {
         super.onResume();
 
-        UserInfo info = mUserManager.getUserInfo(mUser.getIdentifier());
-        ((TextView) mHeaderView.findViewById(android.R.id.title)).setText(info.name);
-        ((ImageView) mHeaderView.findViewById(android.R.id.icon)).setImageDrawable(
-                getCircularUserIcon());
+        // Check if user still exists
+        UserInfo info = getExistingUser(mUser);
+        if (info == null) {
+            finishFragment();
+        } else {
+            ((TextView) mHeaderView.findViewById(android.R.id.title)).setText(info.name);
+            ((ImageView) mHeaderView.findViewById(android.R.id.icon)).setImageDrawable(
+                    getCircularUserIcon());
+        }
+    }
+
+    private UserInfo getExistingUser(UserHandle thisUser) {
+        final List<UserInfo> users = mUserManager.getUsers(true); // Only get non-dying
+        for (UserInfo user : users) {
+            if (user.id == thisUser.getIdentifier()) {
+                return user;
+            }
+        }
+        return null;
     }
 
     @Override