1. 程式人生 > >Android恢復出廠設定原始碼分析,基於Android 6.0

Android恢復出廠設定原始碼分析,基於Android 6.0

近兩天解決一些關於恢復出廠設定的問題,對此略有了解,註釋了部分程式碼,給大家分享

設定>>>備份與重置>>>恢復出廠設定>>>… …

對應得類的路徑:
\packages\apps\Settings\src\com\android\settings\MasterClear.java
程式碼如下所示:

package com.android.settings;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AuthenticatorDescription;
import
android.app.Activity; import android.app.Fragment; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.os.Bundle; import
android.os.Environment; import android.os.Process; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import
android.widget.CheckBox; import android.widget.LinearLayout; import android.widget.TextView; import com.android.internal.logging.MetricsLogger; import java.util.List; import android.content.IntentFilter; import android.content.BroadcastReceiver; import android.widget.Toast; /** *確認並執行裝置的出廠設定。多重確認是必需的: 首先,點選恢復出廠設定按鈕,如果使用者已經設定鍵盤鎖,則跳轉到解鎖程式 接著是該類的內容,出現提示一些提示語,警告即將刪除出的類容。 並根據不同情況提供選著框(與其它版本不同的是Android 6.0 添加了安全機制 ,以前任何時候都有“是否格式化SD卡的複選框”, 在這個版本中根據不同情況來顯示或隱藏) */ //InstrumentedFragment.java類在同一包內 繼承PreferenceFragment類 public class MasterClear extends InstrumentedFragment { //列印log用 private static final String TAG = "MasterClear"; private static final int KEYGUARD_REQUEST = 55; static final String ERASE_EXTERNAL_EXTRA = "erase_sd"; private View mContentView; private Button mInitiateButton; private View mExternalStorageContainer; private CheckBox mExternalStorage; //自己新增的引數 用來監聽電量 private int mBatteryLevel = 0xffff; / /** * Keyguard validation is run using the standard {@link ConfirmLockPattern} * component as a subactivity * @param request the request code to be returned once confirmation finishes * @return true if confirmation launched */ //鍵盤鎖 private boolean runKeyguardConfirmation(int request) { Resources res = getActivity().getResources(); return new ChooseLockSettingsHelper(getActivity(), this).launchConfirmationActivity( request, res.getText(R.string.master_clear_title)); } //返回解鎖狀態 @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode != KEYGUARD_REQUEST) { return; } // 如果解鎖成功則進入下一個活動,否者恢復原始狀態 if (resultCode == Activity.RESULT_OK) { showFinalConfirmation(); } else { establishInitialState(); } } //將複選框的值帶給下個活動(是否格式化SD卡),啟動下一個活動 private void showFinalConfirmation() { Bundle args = new Bundle(); args.putBoolean(ERASE_EXTERNAL_EXTRA, mExternalStorage.isChecked()); ((SettingsActivity) getActivity()).startPreferencePanel(MasterClearConfirm.class.getName(), args, R.string.master_clear_confirm_title, null, null, 0); } /** * 如果使用者點選開始恢復出廠設定 *如果使用者已經設定鍵盤鎖,則跳轉到解鎖程式 *沒有可用的鍵盤鎖,我們只需進入最後確認提示。 */ private final Button.OnClickListener mInitiateListener = new Button.OnClickListener() { public void onClick(View v) { //自己新增的,監聽電量 start /* if (!runKeyguardConfirmation(KEYGUARD_REQUEST)) { showFinalConfirmation(); } */ if(SystemProperties.getInt("ro.my.phone.reset",0)== 1){ if(mBatteryLevel != 0xffff) { if (mBatteryLevel >= 15) { if (!runKeyguardConfirmation(KEYGUARD_REQUEST)) { showFinalConfirmation(); } }else{ Resources res = getActivity().getResources(); Toast.makeText( getActivity().getApplicationContext(), res.getText(R.string.restore_battery_tip), Toast.LENGTH_SHORT).show(); } } }else{ //原始碼 if (!runKeyguardConfirmation(KEYGUARD_REQUEST)) { showFinalConfirmation(); } } } //自己新增的,監聽電量 end }; /** * In its initial state, the activity presents a button for the user to * click in order to initiate a confirmation sequence. This method is * called from various other points in the code to reset the activity to * this base state. * * <p>Reinflating views from resources is expensive and prevents us from * caching widget pointers, so we use a single-inflate pattern: we lazy- * inflate each view, caching all of the widget pointers we'll need at the * time, then simply reuse the inflated views directly whenever we need * to change contents. */ private void establishInitialState() { mInitiateButton = (Button) mContentView.findViewById(R.id.initiate_master_clear); mInitiateButton.setOnClickListener(mInitiateListener); mExternalStorageContainer = mContentView.findViewById(R.id.erase_external_container); mExternalStorage = (CheckBox) mContentView.findViewById(R.id.erase_external); /* * 如果是外部儲存模擬,這不需要單獨的格式化,會自動格式化其中一部分目錄,而不是全部目錄 * 如果外部儲存為不可拆卸的,並且已經加密,這不要被格式化(新版本機制) */ //是否是外部儲存模擬 boolean isExtStorageEmulated = Environment.isExternalStorageEmulated(); //Environment.isExternalStorageRemovable()可拆卸則返回true, if (isExtStorageEmulated || (!Environment.isExternalStorageRemovable() && isExtStorageEncrypted())) { //隱藏佈局,不顯示覆選框 mExternalStorageContainer.setVisibility(View.GONE); final View externalOption = mContentView.findViewById(R.id.erase_external_option_text); externalOption.setVisibility(View.GONE); //顯示部分警告 final View externalAlsoErased = mContentView.findViewById(R.id.also_erases_external); externalAlsoErased.setVisibility(View.VISIBLE); // 如果不是外部儲存模擬,則是加密分割槽 ,這不要被格式化 mExternalStorage.setChecked(!isExtStorageEmulated); } else { mExternalStorageContainer.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mExternalStorage.toggle(); } }); } //一些初始化設定 final UserManager um = (UserManager) getActivity().getSystemService(Context.USER_SERVICE); loadAccountList(um); StringBuffer contentDescription = new StringBuffer(); View masterClearContainer = mContentView.findViewById(R.id.master_clear_container); getContentDescription(masterClearContainer, contentDescription); masterClearContainer.setContentDescription(contentDescription); } private void getContentDescription(View v, StringBuffer description) { if (v instanceof ViewGroup) { ViewGroup vGroup = (ViewGroup) v; for (int i = 0; i < vGroup.getChildCount(); i++) { View nextChild = vGroup.getChildAt(i); getContentDescription(nextChild, description); } } else if (v instanceof TextView) { TextView vText = (TextView) v; description.append(vText.getText()); description.append(","); // Allow Talkback to pause between sections. } } //是否加密 private boolean isExtStorageEncrypted() { String state = SystemProperties.get("vold.decrypt"); return !"".equals(state); } // private void loadAccountList(final UserManager um) { View accountsLabel = mContentView.findViewById(R.id.accounts_label); LinearLayout contents = (LinearLayout)mContentView.findViewById(R.id.accounts); contents.removeAllViews(); Context context = getActivity(); final List<UserInfo> profiles = um.getProfiles(UserHandle.myUserId()); final int profilesSize = profiles.size(); AccountManager mgr = AccountManager.get(context); LayoutInflater inflater = (LayoutInflater)context.getSystemService( Context.LAYOUT_INFLATER_SERVICE); int accountsCount = 0; for (int profileIndex = 0; profileIndex < profilesSize; profileIndex++) { final UserInfo userInfo = profiles.get(profileIndex); final int profileId = userInfo.id; final UserHandle userHandle = new UserHandle(profileId); Account[] accounts = mgr.getAccountsAsUser(profileId); final int N = accounts.length; if (N == 0) { continue; } accountsCount += N; AuthenticatorDescription[] descs = AccountManager.get(context) .getAuthenticatorTypesAsUser(profileId); final int M = descs.length; View titleView = Utils.inflateCategoryHeader(inflater, contents); final TextView titleText = (TextView) titleView.findViewById(android.R.id.title); titleText.setText(userInfo.isManagedProfile() ? R.string.category_work : R.string.category_personal); contents.addView(titleView); for (int i = 0; i < N; i++) { Account account = accounts[i]; AuthenticatorDescription desc = null; for (int j = 0; j < M; j++) { if (account.type.equals(descs[j].type)) { desc = descs[j]; break; } } if (desc == null) { Log.w(TAG, "No descriptor for account name=" + account.name + " type=" + account.type); continue; } Drawable icon = null; try { if (desc.iconId != 0) { Context authContext = context.createPackageContextAsUser(desc.packageName, 0, userHandle); icon = context.getPackageManager().getUserBadgedIcon( authContext.getDrawable(desc.iconId), userHandle); } } catch (PackageManager.NameNotFoundException e) { Log.w(TAG, "Bad package name for account type " + desc.type); } catch (Resources.NotFoundException e) { Log.w(TAG, "Invalid icon id for account type " + desc.type, e); } if (icon == null) { icon = context.getPackageManager().getDefaultActivityIcon(); } TextView child = (TextView)inflater.inflate(R.layout.master_clear_account, contents, false); child.setText(account.name); child.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null); contents.addView(child); } } if (accountsCount > 0) { accountsLabel.setVisibility(View.VISIBLE); contents.setVisibility(View.VISIBLE); } // Checking for all other users and their profiles if any. View otherUsers = mContentView.findViewById(R.id.other_users_present); final boolean hasOtherUsers = (um.getUserCount() - profilesSize) > 0; otherUsers.setVisibility(hasOtherUsers ? View.VISIBLE : View.GONE); } //載入佈局 @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { if (!Process.myUserHandle().isOwner() || UserManager.get(getActivity()).hasUserRestriction( UserManager.DISALLOW_FACTORY_RESET)) { return inflater.inflate(R.layout.master_clear_disallowed_screen, null); } mContentView = inflater.inflate(R.layout.master_clear, null); establishInitialState(); return mContentView; } @Override protected int getMetricsCategory() { return MetricsLogger.MASTER_CLEAR; } //自己新增的,監聽電量 在低電量下不允許恢復出廠設定 start private IntentFilter mIntentFilter = null; private BroadcastReceiver mIntentReceiver = null; public void onCreate(Bundle icicle){ super.onCreate(icicle); Log.i(TAG,"onCreate"); if(SystemProperties.getInt("ro.wind.phone.reset",0)== 1){ mIntentFilter = new IntentFilter(); mIntentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); mIntentReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if(action.equals(Intent.ACTION_BATTERY_CHANGED)){ mBatteryLevel = intent.getIntExtra("level",0); Log.i(TAG, "mBatteryLevel = " + mBatteryLevel); } } }; } } public void onStart() { super.onStart(); Log.i(TAG,"onStart"); if(SystemProperties.getInt("ro.wind.phone.reset",0)== 1){ getActivity().registerReceiver(mIntentReceiver, mIntentFilter); } } public void onStop() { super.onStop(); Log.i(TAG,"onStop"); if(SystemProperties.getInt("ro.wind.phone.reset",0)== 1){ getActivity().unregisterReceiver(mIntentReceiver); } mBatteryLevel = 0xffff; } //自己新增的,監聽電量 在低電量下不允許恢復出廠設定 end }

該類的佈局:
\packages\apps\Settings\res\layout\master_clear.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >

    <ScrollView
            android:layout_width="match_parent"
            android:layout_height="0dip"
            android:layout_marginStart="12dp"
            android:layout_marginEnd="12dp"
            android:layout_marginTop="12dp"
            android:layout_weight="1">
        <LinearLayout android:id="@+id/master_clear_container"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical">
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:includeFontPadding="false"
                android:textSize="18sp"
                android:text="@string/master_clear_desc" />
            <TextView android:id="@+id/also_erases_external"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:includeFontPadding="false"
                android:visibility="gone"
                android:textSize="18sp"
                android:text="@string/master_clear_desc_also_erases_external" />
            <TextView android:id="@+id/accounts_label"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:visibility="gone"
                android:textSize="18sp"
                android:text="@string/master_clear_accounts" />
            <LinearLayout android:id="@+id/accounts"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:orientation="vertical"
                    android:visibility="gone">
                <!-- Do not add any children here as they will be removed in the MasterClear.java
                    code. A list of accounts will be inserted programmatically. -->
            </LinearLayout>
            <TextView android:id="@+id/other_users_present"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:visibility="gone"
                android:textSize="18sp"
                android:text="@string/master_clear_other_users_present" />
            <TextView android:id="@+id/erase_external_option_text"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textSize="18sp"
                android:text="@string/master_clear_desc_erase_external_storage" />
            <LinearLayout android:id="@+id/erase_external_container"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="horizontal"
                    android:focusable="true"
                    android:clickable="true">
                <CheckBox android:id="@+id/erase_external"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="center_vertical"
                        android:paddingEnd="8dp"
                        android:focusable="false"
                        android:clickable="false"
                        android:duplicateParentState="true" />
                <LinearLayout android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_gravity="center_vertical"
                        android:orientation="vertical">
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:paddingTop="12dp"
                        android:textSize="18sp"
                        android:text="@string/erase_external_storage" />
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:paddingTop="4sp"
                        android:textSize="14sp"
                        android:text="@string/erase_external_storage_description" />
                </LinearLayout>
            </LinearLayout>
        </LinearLayout>
    </ScrollView>
    <Button
            android:id="@+id/initiate_master_clear"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="20dip"
            android:layout_marginBottom="12dip"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/master_clear_button_text"
            android:gravity="center" />

</LinearLayout>

跳轉到下一個類,也就是恢復出廠設定核心類:
\packages\apps\Settings\src\com\android\settings\MasterClearConfirm.java
這裡只貼出主要部分程式碼

 /*恢復出廠設定方法  傳送一個廣播,(!!! 以前舊版本會在此活動介面新增是否格式化外部儲存的複選框 根據複選框的值來發送不同的廣播))*/
    private void doMasterClear() {
        Intent intent = new Intent(Intent.ACTION_MASTER_CLEAR);
        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
        intent.putExtra(Intent.EXTRA_REASON, "MasterClearConfirm");
        intent.putExtra(Intent.EXTRA_WIPE_EXTERNAL_STORAGE, mEraseSdCard);
        getActivity().sendBroadcast(intent);
        // Intent handling is asynchronous -- assume it will happen soon.
    }

該類的佈局檔案:

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >

    <TextView
        android:id="@+id/master_clear_confirm"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="12dp"
        android:layout_marginEnd="12dp"
        android:layout_marginTop="12dp"
        android:textSize="20sp"
        android:text="@string/master_clear_final_desc" />

    <Button android:id="@+id/execute_master_clear"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="40dip"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/master_clear_final_button_text"
        android:gravity="center" />

</LinearLayout>

作者水平有限,有不對之處,敬請諒解,指正!謝謝!