diff options
-rw-r--r-- | Android.mk | 30 | ||||
-rw-r--r-- | AndroidManifest.xml | 52 | ||||
-rw-r--r-- | res/drawable-hdpi/ic_launcher.png | bin | 0 -> 9397 bytes | |||
-rw-r--r-- | res/drawable-mdpi/ic_launcher.png | bin | 0 -> 5237 bytes | |||
-rw-r--r-- | res/drawable-xhdpi/ic_launcher.png | bin | 0 -> 14383 bytes | |||
-rw-r--r-- | res/drawable-xxhdpi/ic_launcher.png | bin | 0 -> 19388 bytes | |||
-rw-r--r-- | res/layout/activity_main.xml | 30 | ||||
-rw-r--r-- | res/layout/folder_entry.xml | 38 | ||||
-rw-r--r-- | res/layout/folder_list.xml | 48 | ||||
-rw-r--r-- | res/values-v21/styles.xml | 20 | ||||
-rw-r--r-- | res/values-w820dp/dimens.xml | 22 | ||||
-rw-r--r-- | res/values/dimens.xml | 21 | ||||
-rw-r--r-- | res/values/strings.xml | 22 | ||||
-rw-r--r-- | res/values/styles.xml | 22 | ||||
-rw-r--r-- | src/com/android/car/systemupdater/DeviceListFragment.java | 102 | ||||
-rw-r--r-- | src/com/android/car/systemupdater/FileAdapter.java | 78 | ||||
-rw-r--r-- | src/com/android/car/systemupdater/SystemUpdaterActivity.java | 305 |
17 files changed, 790 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000..dea6312 --- /dev/null +++ b/Android.mk @@ -0,0 +1,30 @@ +# +# Copyright (C) 2015 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. +# + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_CERTIFICATE := platform + +LOCAL_PACKAGE_NAME := SystemUpdater + +LOCAL_DEX_PREOPT := false + +include $(BUILD_PACKAGE) diff --git a/AndroidManifest.xml b/AndroidManifest.xml new file mode 100644 index 0000000..fcb00fc --- /dev/null +++ b/AndroidManifest.xml @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2015 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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.car.systemupdater" > + <uses-sdk android:minSdkVersion="21" /> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM" /> + <uses-permission android:name="android.permission.DELETE_CACHE_FILES" /> + <uses-permission android:name="android.permission.REBOOT" /> + <uses-permission android:name="android.permission.RECOVERY" /> + <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" /> + <uses-feature android:name="android.hardware.usb.host" /> + <uses-feature + android:glEsVersion="0x00020000" + android:required="true"/> + + <application + android:label="@string/app_name" + android:icon="@drawable/ic_launcher"> + <activity + android:name="com.android.car.systemupdater.SystemUpdaterActivity" + android:label="@string/app_name" + android:icon="@drawable/ic_launcher" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + <intent-filter> + <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> + </intent-filter> + </activity> + </application> + +</manifest> diff --git a/res/drawable-hdpi/ic_launcher.png b/res/drawable-hdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..96a442e --- /dev/null +++ b/res/drawable-hdpi/ic_launcher.png diff --git a/res/drawable-mdpi/ic_launcher.png b/res/drawable-mdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..359047d --- /dev/null +++ b/res/drawable-mdpi/ic_launcher.png diff --git a/res/drawable-xhdpi/ic_launcher.png b/res/drawable-xhdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..71c6d76 --- /dev/null +++ b/res/drawable-xhdpi/ic_launcher.png diff --git a/res/drawable-xxhdpi/ic_launcher.png b/res/drawable-xxhdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..4df1894 --- /dev/null +++ b/res/drawable-xxhdpi/ic_launcher.png diff --git a/res/layout/activity_main.xml b/res/layout/activity_main.xml new file mode 100644 index 0000000..b077f52 --- /dev/null +++ b/res/layout/activity_main.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (c) 2016, 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. +--> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingLeft="@dimen/activity_horizontal_margin" + android:paddingRight="@dimen/activity_horizontal_margin" + android:paddingTop="@dimen/activity_vertical_margin" + android:paddingBottom="@dimen/activity_vertical_margin" + tools:context=".MainActivity"> + <FrameLayout + android:id="@+id/device_container" + android:layout_width="match_parent" + android:layout_height="match_parent" /> +</RelativeLayout> diff --git a/res/layout/folder_entry.xml b/res/layout/folder_entry.xml new file mode 100644 index 0000000..0fec3c0 --- /dev/null +++ b/res/layout/folder_entry.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (c) 2016, 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. +--> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <TextView + android:id="@+id/text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="5dp" + android:layout_marginRight="20dp" + android:gravity="center" + android:textSize="32sp"> + </TextView> + <TextView + android:id="@+id/description" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="5dp" + android:gravity="center" + android:textSize="32sp"> + </TextView> +</LinearLayout> diff --git a/res/layout/folder_list.xml b/res/layout/folder_list.xml new file mode 100644 index 0000000..cb651a3 --- /dev/null +++ b/res/layout/folder_list.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (c) 2016, 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. +--> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <FrameLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" > + <Button + android:id="@+id/back" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/back" + android:layout_gravity="left"/> + + <TextView + android:id="@+id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="48dp" + android:layout_gravity="center" /> + </FrameLayout> + <ListView + android:id="@+id/folder_list" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="10dp" + android:gravity="center" + android:numColumns="auto_fit" + android:verticalSpacing="10dp" + android:drawSelectorOnTop="true" + android:stretchMode="columnWidth" /> +</LinearLayout> diff --git a/res/values-v21/styles.xml b/res/values-v21/styles.xml new file mode 100644 index 0000000..1dd3c66 --- /dev/null +++ b/res/values-v21/styles.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (c) 2016, 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. +--> +<resources> + <style name="AppTheme" parent="android:Theme.Material.Light"> + </style> +</resources> diff --git a/res/values-w820dp/dimens.xml b/res/values-w820dp/dimens.xml new file mode 100644 index 0000000..0ef6ab4 --- /dev/null +++ b/res/values-w820dp/dimens.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (c) 2016, 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. +--> +<resources> + <!-- Example customization of dimensions originally defined in res/values/dimens.xml + (such as screen margins) for screens with more than 820dp of available width. This + would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). --> + <dimen name="activity_horizontal_margin">64dp</dimen> +</resources> diff --git a/res/values/dimens.xml b/res/values/dimens.xml new file mode 100644 index 0000000..2688318 --- /dev/null +++ b/res/values/dimens.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (c) 2016, 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. +--> +<resources> + <!-- Default screen margins, per the Android Design guidelines. --> + <dimen name="activity_horizontal_margin">16dp</dimen> + <dimen name="activity_vertical_margin">16dp</dimen> +</resources> diff --git a/res/values/strings.xml b/res/values/strings.xml new file mode 100644 index 0000000..f820d1c --- /dev/null +++ b/res/values/strings.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (c) 2016, 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. +--> +<resources> + <string name="app_name">SystemUpdater</string> + <string name="action_settings">Settings</string> + <string name="title">Mounted Volumes</string> + <string name="back">Go Back</string> +</resources> diff --git a/res/values/styles.xml b/res/values/styles.xml new file mode 100644 index 0000000..de155d8 --- /dev/null +++ b/res/values/styles.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (c) 2016, 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. +--> +<resources> + <!-- Base application theme. --> + <style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar"> + <!-- Customize your theme here. --> + </style> +</resources> diff --git a/src/com/android/car/systemupdater/DeviceListFragment.java b/src/com/android/car/systemupdater/DeviceListFragment.java new file mode 100644 index 0000000..cb0d43f --- /dev/null +++ b/src/com/android/car/systemupdater/DeviceListFragment.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2015 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.car.systemupdater; + +import android.app.Fragment; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.Button; +import android.widget.ListView; +import android.widget.TextView; +import android.widget.Toast; + +import java.io.File; + +public class DeviceListFragment extends Fragment { + private ListView mFolderListView; + private SystemUpdaterActivity mActivity; + private File[] mFileNames = new File[0]; + private FileAdapter mAdapter; + private Button mBackButton; + private TextView mTitle; + private String mTitleText; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mActivity = (SystemUpdaterActivity) getActivity(); + mAdapter = new FileAdapter(mActivity, R.layout.folder_entry, mFileNames); + } + @Override + public View onCreateView(LayoutInflater inflater, final ViewGroup container, + Bundle savedInstanceState) { + View v = inflater.inflate(R.layout.folder_list, container, false); + mTitle = (TextView) v.findViewById(R.id.title); + if (mTitleText != null) { + mTitle.setText(mTitleText); + } + mFolderListView = (ListView) v.findViewById(R.id.folder_list); + mFolderListView.setAdapter(mAdapter); + mFolderListView.setOnItemClickListener(mItemClickListener); + mBackButton = (Button) v.findViewById(R.id.back); + mBackButton.setOnClickListener(mBackButtonListener); + return v; + } + + public void updateList(File[] locations) { + if (locations != null) { + mFileNames = locations; + if (mAdapter != null) { + mAdapter.setLocations(mFileNames); + } + } + } + + public void updateTitle(String title) { + if (mTitle != null) { + mTitle.setText(title); + } else { + mTitleText = title; + } + } + + private final View.OnClickListener mBackButtonListener = + new View.OnClickListener() { + @Override + public void onClick(View view) { + mActivity.onBackPressed(); + } + }; + + private final AdapterView.OnItemClickListener mItemClickListener = + new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView<?> adapterView, View view, + int position, long id) { + if (mFileNames[position].getName().endsWith(".zip")) { + mActivity.checkPackage(mFileNames[position]); + } else if (mFileNames[position].isDirectory()) { + mActivity.showFolderContent(mFileNames[position]); + } else { + Toast.makeText(mActivity, "This is not a valid file for updating", + Toast.LENGTH_LONG).show(); + } + } + }; +} diff --git a/src/com/android/car/systemupdater/FileAdapter.java b/src/com/android/car/systemupdater/FileAdapter.java new file mode 100644 index 0000000..1b0ecd6 --- /dev/null +++ b/src/com/android/car/systemupdater/FileAdapter.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2015 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.car.systemupdater; + +import android.content.Context; +import android.graphics.Color; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.TextView; + +import java.io.File; + + +public class FileAdapter extends ArrayAdapter<File> { + private final Context mContext; + private File[] mLocations; + private final int mLayoutResourceId; + + public FileAdapter(Context c, int layoutResourceId, File[] locations) { + super(c, layoutResourceId, locations); + mContext = c; + this.mLayoutResourceId = layoutResourceId; + this.mLocations = locations; + } + @Override + public View getView(int position, View convertView, ViewGroup parent) { + ViewHolder vh = new ViewHolder(); + if (convertView == null) { + LayoutInflater inflater = LayoutInflater.from(mContext); + convertView = inflater.inflate(mLayoutResourceId, parent, false); + vh.textView = (TextView) convertView.findViewById(R.id.text); + vh.descriptionView = (TextView) convertView.findViewById(R.id.description); + convertView.setTag(vh); + } else { + vh = (ViewHolder) convertView.getTag(); + } + if (mLocations[position] != null) { + vh.textView.setText(mLocations[position].getAbsolutePath()); + if (mLocations[position].getAbsolutePath().endsWith(".zip") + || mLocations[position].isDirectory()) { + vh.textView.setTextColor(Color.GREEN); + } else { + vh.textView.setTextColor(Color.GRAY); + } + } + return convertView; + } + + @Override + public int getCount() { + return mLocations.length; + } + + public void setLocations(File[] locations) { + mLocations = locations; + notifyDataSetChanged(); + } + + static class ViewHolder { + TextView textView; + TextView descriptionView; + } +} diff --git a/src/com/android/car/systemupdater/SystemUpdaterActivity.java b/src/com/android/car/systemupdater/SystemUpdaterActivity.java new file mode 100644 index 0000000..e442731 --- /dev/null +++ b/src/com/android/car/systemupdater/SystemUpdaterActivity.java @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2015 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.car.systemupdater; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.FragmentManager; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Handler; +import android.os.RecoverySystem; +import android.util.Log; +import android.widget.Toast; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.GeneralSecurityException; +import java.util.List; + +import android.os.storage.StorageEventListener; +import android.os.storage.StorageManager; +import android.os.storage.VolumeInfo; + +/** + * A prototype of performing system update using an ota package on internal or external storage. + * TODO(yaochen): Move the code to a proper location and let it extend CarActivity once available. + */ +public class SystemUpdaterActivity extends Activity { + private static final String TAG = "SystemUpdaterActivity"; + private static final boolean DEBUG = true; + private static final String UPDATE_FILE_NAME = "update.zip"; + + private final Handler mHandler = new Handler(); + private StorageManager mStorageManager = null; + private ProgressDialog mVerifyPackageDialog = null; + + + private final StorageEventListener mListener = new StorageEventListener() { + @Override + public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) { + if (DEBUG) { + Log.d(TAG, "onVolumeMetadataChanged " + oldState + " " + newState + + " " + vol.toString()); + } + showMountedVolumes(); + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + mStorageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE); + if (mStorageManager == null) { + Log.w(TAG, "Failed to get StorageManager"); + Toast.makeText(this, "Cannot get StorageManager!", Toast.LENGTH_LONG).show(); + } + } + + @Override + protected void onResume() { + super.onResume(); + if (mStorageManager != null) { + mStorageManager.registerListener(mListener); + showMountedVolumes(); + } + } + + @Override + protected void onPause() { + super.onPause(); + if (mStorageManager != null) { + mStorageManager.unregisterListener(mListener); + } + } + + @Override + public void onBackPressed() { + if (getFragmentManager().getBackStackEntryCount() > 0) { + getFragmentManager().popBackStackImmediate(); + } else { + super.onBackPressed(); + } + } + + public void showMountedVolumes() { + if (mStorageManager == null) { + return; + } + final List<VolumeInfo> vols = mStorageManager.getVolumes(); + File[] files = new File[vols.size()]; + int i = 0; + for (VolumeInfo vol : vols) { + File path = vol.getPathForUser(getUserId()); + if (vol.getState() != VolumeInfo.STATE_MOUNTED || path == null) { + continue; + } + files[i++] = path; + } + getFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); + DeviceListFragment frag = new DeviceListFragment(); + frag.updateList(files); + frag.updateTitle(getString(R.string.title)); + getFragmentManager().beginTransaction() + .replace(R.id.device_container, frag).commit(); + } + + public void showFolderContent(final File location) { + if (!location.isDirectory()) { + return; + } + AsyncTask<String, Void, File[]> readFilesTask = new AsyncTask<String, Void, File[]>() { + @Override + protected File[] doInBackground(String... strings) { + File f = new File(strings[0]); + /* if we want to filter files, use + File[] files = f.listFiles(new FilenameFilter() { + @Override + public boolean accept(File dir, String filename) { + return true; + } + }); */ + return f.listFiles(); + } + + @Override + protected void onPostExecute(File[] results) { + super.onPostExecute(results); + if (results == null) { + results = new File[0]; + } + DeviceListFragment frag = new DeviceListFragment(); + frag.updateTitle(location.getAbsolutePath()); + frag.updateList(results); + getFragmentManager().beginTransaction() + .replace(R.id.device_container, frag).addToBackStack(null).commit(); + } + }; + readFilesTask.execute(location.getAbsolutePath()); + } + + public void checkPackage(File file) { + mVerifyPackageDialog = new ProgressDialog(this); + mVerifyPackageDialog.setTitle("Verifying... " + file.getAbsolutePath()); + + final PackageVerifier verifyPackage = new PackageVerifier(); + verifyPackage.execute(file); + mVerifyPackageDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialogInterface) { + verifyPackage.cancel(true); + } + }); + mVerifyPackageDialog.setProgressStyle(mVerifyPackageDialog.STYLE_HORIZONTAL); + mVerifyPackageDialog.setMax(100); + mVerifyPackageDialog.setProgress(0); + mVerifyPackageDialog.show(); + } + + private class PackageVerifier extends AsyncTask<File, Void, Exception> { + File mFile; + + @Override + protected Exception doInBackground(File... files) { + File file = files[0]; + mFile = file; + try { + RecoverySystem.verifyPackage(file, mProgressListener, null); + } catch (GeneralSecurityException e) { + Log.e(TAG, "Security Exception in verifying package " + file, e); + return e; + } catch (IOException e) { + Log.e(TAG, "IO Exception in verifying package " + file, e); + return e; + } + return null; + } + + @Override + protected void onPostExecute(Exception result) { + mVerifyPackageDialog.cancel(); + if (result == null) { + mVerifyPackageDialog = new ProgressDialog(SystemUpdaterActivity.this); + mVerifyPackageDialog.setTitle("Copying " + mFile.getName() + + " to " + getCacheDir() + "/" + UPDATE_FILE_NAME); + mVerifyPackageDialog.setProgressStyle(mVerifyPackageDialog.STYLE_HORIZONTAL); + mVerifyPackageDialog.setMax((int) (mFile.length() / 1024)); + mVerifyPackageDialog.show(); + new CopyFile().execute(mFile); + } else { + AlertDialog.Builder doneDialog = + new AlertDialog.Builder(SystemUpdaterActivity.this); + doneDialog.setMessage("Verification failed! " + result.getMessage()).show(); + } + } + } + + + private class CopyFile extends AsyncTask<File, Void, Exception> { + @Override + protected Exception doInBackground(File... files) { + File file = files[0]; + if (getCacheDir().getFreeSpace() < file.length()) { + return new IOException("Not enough cache space!"); + } + File dest = new File(getCacheDir(), UPDATE_FILE_NAME); + try { + copy(file, dest); + } catch (IOException e) { + Log.e(TAG, "Error when coping file to cache", e); + dest.delete(); + return new IOException(e.getMessage()); + } + return null; + } + + @Override + protected void onPostExecute(Exception result) { + mVerifyPackageDialog.cancel(); + AlertDialog.Builder doneDialog = new AlertDialog.Builder(SystemUpdaterActivity.this); + + doneDialog.setMessage("Copy " + (result == null ? "completed!" : "failed!" + + result.getMessage())); + + if (result == null) { + doneDialog.setPositiveButton("Start system update", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + try { + RecoverySystem.installPackage(SystemUpdaterActivity.this, + new File(getCacheDir(), UPDATE_FILE_NAME)); + } catch (IOException e) { + Log.e(TAG, "IOException in installing ota package"); + Toast.makeText(SystemUpdaterActivity.this, + "IOException in installing ota package ", + Toast.LENGTH_LONG).show(); + } + } + }); + } else { + Log.e(TAG, "Copy failed!", result); + } + doneDialog.create().show(); + } + } + + private void copy(File src, File dst) throws IOException { + InputStream in = new FileInputStream(src); + OutputStream out = new FileOutputStream(dst); + try { + // Transfer bytes from in to out + byte[] buf = new byte[0x10000]; // 64k + int len; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + mHandler.post(new Runnable() { + @Override + public void run() { + mVerifyPackageDialog.incrementProgressBy(1); + } + }); + } + } finally { + in.close(); + out.close(); + } + } + + private final RecoverySystem.ProgressListener mProgressListener = + new RecoverySystem.ProgressListener() { + @Override + public void onProgress(final int i) { + mHandler.post(new Runnable() { + @Override + public void run() { + if (mVerifyPackageDialog != null) { + mVerifyPackageDialog.setProgress(i); + } + } + }); + } + }; +} |