diff options
author | Jeff Sharkey <jsharkey@android.com> | 2013-10-28 09:13:51 -0700 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2013-10-28 09:13:51 -0700 |
commit | 650e6f75ebcf38c416fbf1586685b64f1ea6c7d8 (patch) | |
tree | 5271e538563873757f20b1ad5f34701c6b238f80 | |
parent | 475c210649506fa680f7a674468ba7a0fbeb5707 (diff) | |
parent | 88ded90b784beb372c49b1187ee69bdd4595cd10 (diff) | |
download | android_packages_apps_CertInstaller-650e6f75ebcf38c416fbf1586685b64f1ea6c7d8.tar.gz android_packages_apps_CertInstaller-650e6f75ebcf38c416fbf1586685b64f1ea6c7d8.tar.bz2 android_packages_apps_CertInstaller-650e6f75ebcf38c416fbf1586685b64f1ea6c7d8.zip |
am 88ded90b: Pick certificates using OPEN_DOC intent.
* commit '88ded90b784beb372c49b1187ee69bdd4595cd10':
Pick certificates using OPEN_DOC intent.
-rw-r--r-- | AndroidManifest.xml | 10 | ||||
-rw-r--r-- | src/com/android/certinstaller/CertFile.java | 206 | ||||
-rw-r--r-- | src/com/android/certinstaller/CertFileList.java | 198 | ||||
-rw-r--r-- | src/com/android/certinstaller/CertInstallerMain.java | 161 |
4 files changed, 78 insertions, 497 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index b2880d6..0d754b1 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -3,8 +3,6 @@ <original-package android:name="com.android.certinstaller" /> - <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> - <permission android:name="com.android.certinstaller.INSTALL_AS_USER" android:protectionLevel="signature" /> @@ -22,7 +20,10 @@ <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="application/x-x509-ca-cert" /> <data android:mimeType="application/x-x509-user-cert" /> + <data android:mimeType="application/x-x509-server-cert" /> <data android:mimeType="application/x-pkcs12" /> + <data android:mimeType="application/application/x-pem-file" /> + <data android:mimeType="application/pkix-cert" /> </intent-filter> </activity> @@ -40,10 +41,5 @@ android:configChanges="orientation|keyboardHidden" android:exported="false"> </activity> - - <activity android:name=".CertFileList" - android:configChanges="orientation|keyboardHidden" - android:exported="false"> - </activity> </application> </manifest> diff --git a/src/com/android/certinstaller/CertFile.java b/src/com/android/certinstaller/CertFile.java deleted file mode 100644 index 5b4bfbf..0000000 --- a/src/com/android/certinstaller/CertFile.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (C) 2009 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.certinstaller; - -import android.content.Intent; -import android.os.Bundle; -import android.os.Environment; -import android.preference.PreferenceActivity; -import android.security.Credentials; -import android.security.KeyChain; -import android.util.Log; -import android.widget.Toast; - -import java.io.File; -import java.io.FileFilter; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * Base class that deals with certificate files on the SD card. - */ -public class CertFile extends PreferenceActivity implements FileFilter { - static final int CERT_READ_ERROR = R.string.cert_read_error; - static final int CERT_TOO_LARGE_ERROR = R.string.cert_too_large_error; - static final int CERT_FILE_MISSING_ERROR = R.string.cert_missing_error; - - static final String DOWNLOAD_DIR = "download"; - - private static final String TAG = "CertFile"; - - private static final String CERT_FILE_KEY = "cf"; - private static final int MAX_FILE_SIZE = 1000000; - protected static final int REQUEST_INSTALL_CODE = 1; - - private File mCertFile; - - @Override - protected void onSaveInstanceState(Bundle outStates) { - super.onSaveInstanceState(outStates); - if (mCertFile != null) { - outStates.putString(CERT_FILE_KEY, mCertFile.getAbsolutePath()); - } - } - - @Override - protected void onRestoreInstanceState(Bundle savedStates) { - super.onRestoreInstanceState(savedStates); - String path = savedStates.getString(CERT_FILE_KEY); - if (path != null) { - mCertFile = new File(path); - } - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if (requestCode == REQUEST_INSTALL_CODE) { - boolean success = (resultCode == RESULT_OK - && (mCertFile == null || Util.deleteFile(mCertFile))); - onInstallationDone(success); - mCertFile = null; - } else { - Log.w(TAG, "unknown request code: " + requestCode); - } - } - - /** - * Called when installation is done. - * - * @param success true if installation is done successfully - */ - protected void onInstallationDone(boolean success) { - if (success) { - setResult(RESULT_OK); - } - } - - /** - * Called when an error occurs when reading a certificate file. - * - * @param errorId one of {@link #CERT_READ_ERROR}, - * {@link #CERT_TOO_LARGE_ERROR} and {@link #CERT_FILE_MISSING_ERROR} - */ - protected void onError(int errorId) { - } - - /** - * Returns a list of certificate files found on the SD card. - */ - protected List<File> getAllCertFiles() { - List<File> allFiles = new ArrayList<File>(); - File root = Environment.getExternalStorageDirectory(); - - File download = new File(root, DOWNLOAD_DIR); - if (download != null) { - File[] files = download.listFiles(this); - if (files != null) { - Collections.addAll(allFiles, files); - } - } - - File[] files = root.listFiles(this); - if (files != null) { - Collections.addAll(allFiles, files); - } - - return allFiles; - } - - /** - * Invokes {@link CertInstaller} to install the certificate(s) in the file. - * - * @param file the certificate file - */ - protected void installFromFile(File file) { - Log.d(TAG, "install cert from " + file); - - String fileName = file.getName(); - Bundle bundle = getIntent().getExtras(); - - final String name; - final int installAsUid; - if (bundle == null) { - name = fileName; - installAsUid = -1; - } else { - name = bundle.getString(KeyChain.EXTRA_NAME, fileName); - installAsUid = bundle.getInt(Credentials.EXTRA_INSTALL_AS_UID, -1); - } - - if (file.exists()) { - if (file.length() < MAX_FILE_SIZE) { - byte[] data = Util.readFile(file); - if (data == null) { - toastError(CERT_READ_ERROR); - onError(CERT_READ_ERROR); - return; - } - mCertFile = file; - install(fileName, name, installAsUid, data); - } else { - Log.w(TAG, "cert file is too large: " + file.length()); - toastError(CERT_TOO_LARGE_ERROR); - onError(CERT_TOO_LARGE_ERROR); - } - } else { - Log.w(TAG, "cert file does not exist"); - toastError(CERT_FILE_MISSING_ERROR); - onError(CERT_FILE_MISSING_ERROR); - } - } - - @Override public boolean accept(File file) { - if (!file.isDirectory()) { - return isFileAcceptable(file.getPath()); - } else { - return false; - } - } - - protected boolean isFileAcceptable(String path) { - return (path.endsWith(Credentials.EXTENSION_CRT) || - path.endsWith(Credentials.EXTENSION_P12) || - path.endsWith(Credentials.EXTENSION_CER) || - path.endsWith(Credentials.EXTENSION_PFX)); - } - - protected boolean isSdCardPresent() { - return Environment.getExternalStorageState().equals( - Environment.MEDIA_MOUNTED); - } - - private void install(String fileName, String name, int uid, byte[] value) { - Intent intent = new Intent(this, CertInstaller.class); - intent.putExtra(KeyChain.EXTRA_NAME, name); - intent.putExtra(Credentials.EXTRA_INSTALL_AS_UID, uid); - if (fileName.endsWith(Credentials.EXTENSION_PFX) - || fileName.endsWith(Credentials.EXTENSION_P12)) { - intent.putExtra(KeyChain.EXTRA_PKCS12, value); - } else if (fileName.endsWith(Credentials.EXTENSION_CER) - || fileName.endsWith(Credentials.EXTENSION_CRT)) { - intent.putExtra(KeyChain.EXTRA_CERTIFICATE, value); - } else { - throw new AssertionError(fileName); - } - startActivityForResult(intent, REQUEST_INSTALL_CODE); - } - - private void toastError(int msgId) { - Toast.makeText(this, msgId, Toast.LENGTH_LONG).show(); - } -} diff --git a/src/com/android/certinstaller/CertFileList.java b/src/com/android/certinstaller/CertFileList.java deleted file mode 100644 index 1d32c26..0000000 --- a/src/com/android/certinstaller/CertFileList.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (C) 2009 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.certinstaller; - -import android.os.Bundle; -import android.os.Environment; -import android.os.FileObserver; -import android.preference.Preference; -import android.preference.PreferenceScreen; -import android.security.Credentials; -import android.util.Log; -import android.widget.Toast; - -import java.io.File; -import java.io.IOException; -import java.util.List; - -/** - * Lists certificate files in the SD card. User may click one to install it - * to the system keystore. - */ -public class CertFileList extends CertFile - implements Preference.OnPreferenceClickListener { - private static final String TAG = "CertFileList"; - - private static final String DOWNLOAD_DIR = "download"; - - private SdCardMonitor mSdCardMonitor; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.pick_file_pref); - createFileList(); - startSdCardMonitor(); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - stopSdCardMonitor(); - } - - @Override - protected void onInstallationDone(boolean fileDeleted) { - super.onInstallationDone(fileDeleted); - if (!fileDeleted) { - if (isSdCardPresent()) { - setAllFilesEnabled(true); - } else { - Toast.makeText(this, R.string.sdcard_not_present, - Toast.LENGTH_SHORT).show(); - finish(); - } - } - } - - @Override - protected void onError(int errorId) { - if (errorId == CERT_FILE_MISSING_ERROR) { - createFileList(); - } - } - - private void setAllFilesEnabled(boolean enabled) { - PreferenceScreen root = getPreferenceScreen(); - for (int i = 0, n = root.getPreferenceCount(); i < n; i++) { - root.getPreference(i).setEnabled(enabled); - } - } - - public boolean onPreferenceClick(Preference pref) { - File file = new File(Environment.getExternalStorageDirectory(), - pref.getTitle().toString()); - if (file.isDirectory()) { - Log.w(TAG, "impossible to pick a directory! " + file); - } else { - setAllFilesEnabled(false); - installFromFile(file); - } - return true; - } - - private void createFileList() { - if (isFinishing()) { - Log.d(TAG, "finishing, exit createFileList()"); - return; - } - if (!isSdCardPresent()) { - Toast.makeText(this, R.string.sdcard_not_present, - Toast.LENGTH_SHORT).show(); - finish(); - return; - } - - try { - PreferenceScreen root = getPreferenceScreen(); - root.removeAll(); - - List<File> allFiles = getAllCertFiles(); - if (allFiles.isEmpty()) { - Toast.makeText(this, R.string.no_cert_file_found, - Toast.LENGTH_SHORT).show(); - finish(); - return; - } else { - int prefixEnd = Environment.getExternalStorageDirectory() - .getCanonicalPath().length() + 1; - for (File file : allFiles) { - Preference pref = new Preference(this); - pref.setTitle(file.getCanonicalPath().substring(prefixEnd)); - root.addPreference(pref); - pref.setOnPreferenceClickListener(this); - } - } - } catch (IOException e) { - // should not occur - Log.w(TAG, "createFileList(): " + e); - throw new RuntimeException(e); - } - } - - private void startSdCardMonitor() { - if (mSdCardMonitor == null) { - mSdCardMonitor = new SdCardMonitor(); - } - mSdCardMonitor.startWatching(); - } - - private void stopSdCardMonitor() { - if (mSdCardMonitor != null) { - mSdCardMonitor.stopWatching(); - } - } - - private class SdCardMonitor { - FileObserver mRootMonitor; - FileObserver mDownloadMonitor; - - SdCardMonitor() { - File root = Environment.getExternalStorageDirectory(); - mRootMonitor = new FileObserver(root.getPath()) { - @Override - public void onEvent(int evt, String path) { - commonHandler(evt, path); - } - }; - - File download = new File(root, DOWNLOAD_DIR); - mDownloadMonitor = new FileObserver(download.getPath()) { - @Override - public void onEvent(int evt, String path) { - commonHandler(evt, path); - } - }; - } - - private void commonHandler(int evt, String path) { - switch (evt) { - case FileObserver.CREATE: - case FileObserver.DELETE: - if (isFileAcceptable(path)) { - runOnUiThread(new Runnable() { - public void run() { - createFileList(); - } - }); - } - break; - } - }; - - void startWatching() { - mRootMonitor.startWatching(); - mDownloadMonitor.startWatching(); - } - - void stopWatching() { - mRootMonitor.stopWatching(); - mDownloadMonitor.stopWatching(); - } - } -} diff --git a/src/com/android/certinstaller/CertInstallerMain.java b/src/com/android/certinstaller/CertInstallerMain.java index 9b10c07..c83e99f 100644 --- a/src/com/android/certinstaller/CertInstallerMain.java +++ b/src/com/android/certinstaller/CertInstallerMain.java @@ -19,46 +19,46 @@ package com.android.certinstaller; import android.content.Intent; import android.net.Uri; import android.os.Bundle; +import android.preference.PreferenceActivity; +import android.provider.DocumentsContract; import android.security.Credentials; import android.security.KeyChain; import android.util.Log; import android.widget.Toast; -import java.io.ByteArrayOutputStream; -import java.io.File; +import libcore.io.IoUtils; +import libcore.io.Streams; + import java.io.IOException; import java.io.InputStream; -import java.util.List; - -import libcore.io.IoUtils; /** * The main class for installing certificates to the system keystore. It reacts * to the public {@link Credentials#INSTALL_ACTION} intent. */ -public class CertInstallerMain extends CertFile implements Runnable { +public class CertInstallerMain extends PreferenceActivity { + private static final String TAG = "CertInstaller"; + + private static final int REQUEST_INSTALL = 1; + private static final int REQUEST_OPEN_DOCUMENT = 2; + + private static final String[] ACCEPT_MIME_TYPES = { + "application/x-pkcs12", + "application/x-x509-ca-cert", + "application/x-x509-user-cert", + "application/x-x509-server-cert", + "application/x-pem-file", + "application/pkix-cert" + }; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - if (savedInstanceState != null) { - return; - } - new Thread(new Runnable() { - @Override - public void run() { - // don't want to call startActivityForResult() (invoked in - // installFromFile()) here as it makes the new activity (thus - // the whole display) get stuck for about 5 seconds - runOnUiThread(CertInstallerMain.this); - } - }).start(); - } + setResult(RESULT_CANCELED); - @Override - public void run() { - Intent intent = getIntent(); - String action = (intent == null) ? null : intent.getAction(); + final Intent intent = getIntent(); + final String action = intent.getAction(); if (Credentials.INSTALL_ACTION.equals(action) || Credentials.INSTALL_AS_USER_ACTION.equals(action)) { @@ -74,7 +74,7 @@ public class CertInstallerMain extends CertFile implements Runnable { bundle.remove(Credentials.EXTRA_INSTALL_AS_UID); } - // If bundle is empty of any actual credentials, install from external storage. + // If bundle is empty of any actual credentials, ask user to open. // Otherwise, pass extras to CertInstaller to install those credentials. // Either way, we use KeyChain.EXTRA_NAME as the default name if available. if (bundle == null @@ -82,82 +82,71 @@ public class CertInstallerMain extends CertFile implements Runnable { || (bundle.size() == 1 && (bundle.containsKey(KeyChain.EXTRA_NAME) || bundle.containsKey(Credentials.EXTRA_INSTALL_AS_UID)))) { - if (!isSdCardPresent()) { - Toast.makeText(this, R.string.sdcard_not_present, - Toast.LENGTH_SHORT).show(); - } else { - List<File> allFiles = getAllCertFiles(); - if (allFiles.isEmpty()) { - Toast.makeText(this, R.string.no_cert_file_found, - Toast.LENGTH_SHORT).show(); - } else if (allFiles.size() == 1) { - installFromFile(allFiles.get(0)); - return; - } else { - Intent newIntent = new Intent(this, CertFileList.class); - newIntent.putExtras(intent); - startActivityForResult(newIntent, REQUEST_INSTALL_CODE); - return; - } - } + final Intent openIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT); + openIntent.setType("*/*"); + openIntent.putExtra(Intent.EXTRA_MIME_TYPES, ACCEPT_MIME_TYPES); + openIntent.putExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, true); + startActivityForResult(openIntent, REQUEST_OPEN_DOCUMENT); } else { - Intent newIntent = new Intent(this, CertInstaller.class); - newIntent.putExtras(intent); - startActivityForResult(newIntent, REQUEST_INSTALL_CODE); - return; + final Intent installIntent = new Intent(this, CertInstaller.class); + installIntent.putExtras(intent); + startActivityForResult(installIntent, REQUEST_INSTALL); } } else if (Intent.ACTION_VIEW.equals(action)) { - Uri data = intent.getData(); - String type = intent.getType(); - if ((data != null) && (type != null)) { - byte[] payload = null; - InputStream is = null; - try { - is = getContentResolver().openInputStream(data); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - byte[] buffer = new byte[1024]; - int read = 0; - while ((read = is.read(buffer)) > 0) { - out.write(buffer, 0, read); - } - out.flush(); - payload = out.toByteArray(); - } catch (IOException ignored) { - // Not much we can do - it will be logged below as an error. - } finally { - IoUtils.closeQuietly(is); - } - if (payload == null) { - Log.e("CertInstaller", "Unable to read stream for for certificate"); - } else { - installByType(type, payload); - } - } + startInstallActivity(intent.getType(), intent.getData()); } - finish(); } - private void installByType(String type, byte[] value) { + private void startInstallActivity(String mimeType, Uri uri) { + if (mimeType == null) { + mimeType = getContentResolver().getType(uri); + } + + InputStream in = null; + try { + in = getContentResolver().openInputStream(uri); + + final byte[] raw = Streams.readFully(in); + startInstallActivity(mimeType, raw); + + } catch (IOException e) { + Log.e(TAG, "Failed to read certificate: " + e); + Toast.makeText(this, R.string.cert_read_error, Toast.LENGTH_LONG).show(); + } finally { + IoUtils.closeQuietly(in); + } + } + + private void startInstallActivity(String mimeType, byte[] value) { Intent intent = new Intent(this, CertInstaller.class); - if ("application/x-pkcs12".equals(type)) { + if ("application/x-pkcs12".equals(mimeType)) { intent.putExtra(KeyChain.EXTRA_PKCS12, value); - } else if ("application/x-x509-ca-cert".equals(type) - || "application/x-x509-user-cert".equals(type)) { + } else if ("application/x-x509-ca-cert".equals(mimeType) + || "application/x-x509-user-cert".equals(mimeType) + || "application/x-x509-server-cert".equals(mimeType) + || "application/x-pem-file".equals(mimeType) + || "application/pkix-cert".equals(mimeType)) { intent.putExtra(KeyChain.EXTRA_CERTIFICATE, value); } else { - throw new AssertionError("Unknown type: " + type); + throw new IllegalArgumentException("Unknown MIME type: " + mimeType); } - startActivityForResult(intent, REQUEST_INSTALL_CODE); - } - @Override - protected void onInstallationDone(boolean success) { - super.onInstallationDone(success); - finish(); + startActivityForResult(intent, REQUEST_INSTALL); } @Override - protected void onError(int errorId) { - finish(); + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == REQUEST_OPEN_DOCUMENT) { + if (resultCode == RESULT_OK) { + startInstallActivity(null, data.getData()); + } else { + finish(); + } + } else if (requestCode == REQUEST_INSTALL) { + setResult(resultCode); + finish(); + } else { + Log.w(TAG, "unknown request code: " + requestCode); + } } } |