您的位置:首页 > 移动开发 > Android开发

Android恢复出厂设置源码分析,基于Android 6.0

2016-08-24 11:55 627 查看
近两天解决一些关于恢复出厂设置的问题,对此略有了解,注释了部分代码,给大家分享

设置>>>备份与重置>>>恢复出厂设置>>>… …

对应得类的路径:

\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>


作者水平有限,有不对之处,敬请谅解,指正!谢谢!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 源码 class 注释