1 package com.android.settings.backup;
2 
3 import android.app.Dialog;
4 import android.app.backup.IBackupManager;
5 import android.app.settings.SettingsEnums;
6 import android.content.Context;
7 import android.content.DialogInterface;
8 import android.os.Bundle;
9 import android.os.RemoteException;
10 import android.os.ServiceManager;
11 import android.provider.Settings;
12 import android.util.Log;
13 import android.view.View;
14 import android.widget.TextView;
15 
16 import androidx.appcompat.app.AlertDialog;
17 import androidx.preference.Preference;
18 import androidx.preference.PreferenceScreen;
19 import androidx.preference.PreferenceViewHolder;
20 
21 import com.android.settings.R;
22 import com.android.settings.SettingsActivity;
23 import com.android.settings.SettingsPreferenceFragment;
24 import com.android.settings.widget.SettingsMainSwitchBar;
25 
26 /**
27  * Fragment to display a bunch of text about backup and restore, and allow the user to enable/
28  * disable it.
29  */
30 public class ToggleBackupSettingFragment extends SettingsPreferenceFragment
31         implements DialogInterface.OnClickListener, DialogInterface.OnDismissListener {
32     private static final String TAG = "ToggleBackupSettingFragment";
33 
34     private static final String BACKUP_TOGGLE = "toggle_backup";
35 
36     // System setting that governs whether the user is eligible for full app-data backup,
37     // based on whether they have been presented with the details of what that backup entails
38     // (usually surfaced somewhere like device setup)
39     private static final String USER_FULL_DATA_BACKUP_AWARE = "user_full_data_backup_aware";
40 
41     private IBackupManager mBackupManager;
42 
43     protected SettingsMainSwitchBar mSwitchBar;
44 
45     private Preference mSummaryPreference;
46 
47     private Dialog mConfirmDialog;
48 
49     private boolean mWaitingForConfirmationDialog = false;
50 
51     @Override
onCreate(Bundle savedInstanceState)52     public void onCreate(Bundle savedInstanceState) {
53         super.onCreate(savedInstanceState);
54 
55         mBackupManager = IBackupManager.Stub.asInterface(
56                 ServiceManager.getService(Context.BACKUP_SERVICE));
57 
58         PreferenceScreen preferenceScreen = getPreferenceManager().createPreferenceScreen(
59                 getActivity());
60         setPreferenceScreen(preferenceScreen);
61         mSummaryPreference = new Preference(getPrefContext()) {
62             @Override
63             public void onBindViewHolder(PreferenceViewHolder view) {
64                 super.onBindViewHolder(view);
65                 final TextView summaryView = (TextView) view.findViewById(android.R.id.summary);
66                 summaryView.setText(getSummary());
67             }
68         };
69         mSummaryPreference.setPersistent(false);
70         mSummaryPreference.setLayoutResource(R.layout.text_description_preference);
71         preferenceScreen.addPreference(mSummaryPreference);
72     }
73 
74     @Override
onViewCreated(View view, Bundle savedInstanceState)75     public void onViewCreated(View view, Bundle savedInstanceState) {
76         super.onViewCreated(view, savedInstanceState);
77 
78         SettingsActivity activity = (SettingsActivity) getActivity();
79         mSwitchBar = activity.getSwitchBar();
80 
81         // Set up UI.
82         // If the user has not seen legal text for full data backup (if they OTA from L to M) then
83         // full data backup will be off and here we want to show the old summary here that does
84         // not mention full data backup
85         if (Settings.Secure.getInt(getContentResolver(), USER_FULL_DATA_BACKUP_AWARE, 0) != 0) {
86             mSummaryPreference.setSummary(R.string.fullbackup_data_summary);
87         } else {
88             mSummaryPreference.setSummary(R.string.backup_data_summary);
89         }
90         try {
91             boolean backupEnabled = mBackupManager == null ?
92                     false : mBackupManager.isBackupEnabled();
93             mSwitchBar.setCheckedInternal(backupEnabled);
94         } catch (RemoteException e) {
95             // The world is aflame, turn it off.
96             mSwitchBar.setEnabled(false);
97         }
98         getActivity().setTitle(R.string.backup_data_title);
99     }
100 
101     @Override
onDestroyView()102     public void onDestroyView() {
103         super.onDestroyView();
104 
105         mSwitchBar.setOnBeforeCheckedChangeListener(null);
106         mSwitchBar.hide();
107     }
108 
109     @Override
onActivityCreated(Bundle savedInstanceState)110     public void onActivityCreated(Bundle savedInstanceState) {
111         super.onActivityCreated(savedInstanceState);
112 
113         // Set up toggle listener. We need this b/c we have to intercept the toggle event in order
114         // to pop up the dialogue.
115         mSwitchBar.setOnBeforeCheckedChangeListener(
116                 new SettingsMainSwitchBar.OnBeforeCheckedChangeListener() {
117                     @Override
118                     public boolean onBeforeCheckedChanged(boolean checked) {
119                         if (!checked) {
120                             // Don't change Switch status until user makes choice in dialog
121                             // so return true here.
122                             showEraseBackupDialog();
123                             return true;
124                         } else {
125                             setBackupEnabled(true);
126                             mSwitchBar.setCheckedInternal(true);
127                             return true;
128                         }
129                     }
130                 });
131         mSwitchBar.show();
132     }
133 
134     /** Get rid of the dialog if it's still showing. */
135     @Override
onStop()136     public void onStop() {
137         if (mConfirmDialog != null && mConfirmDialog.isShowing()) {
138             mConfirmDialog.dismiss();
139         }
140         mConfirmDialog = null;
141         super.onStop();
142     }
143 
144     @Override
onClick(DialogInterface dialog, int which)145     public void onClick(DialogInterface dialog, int which) {
146         // Accept turning off backup
147         if (which == DialogInterface.BUTTON_POSITIVE) {
148             mWaitingForConfirmationDialog = false;
149             setBackupEnabled(false);
150             mSwitchBar.setCheckedInternal(false);
151         } else if (which == DialogInterface.BUTTON_NEGATIVE) {
152             // Reject turning off backup
153             mWaitingForConfirmationDialog = false;
154             setBackupEnabled(true);
155             mSwitchBar.setCheckedInternal(true);
156         }
157     }
158 
159     @Override
onDismiss(DialogInterface dialog)160     public void onDismiss(DialogInterface dialog) {
161         if (mWaitingForConfirmationDialog) {
162             // dismiss turning off backup
163             setBackupEnabled(true);
164             mSwitchBar.setCheckedInternal(true);
165         }
166     }
167 
showEraseBackupDialog()168     private void showEraseBackupDialog() {
169         CharSequence msg;
170 
171         // If the user has not seen legal text for full data backup (if they OTA from L to M) then
172         // full data backup will be off and here we want to show the old erase_dialog_message here
173         // that does not mention full data backup
174         if (Settings.Secure.getInt(getContentResolver(), USER_FULL_DATA_BACKUP_AWARE, 0) != 0) {
175             msg = getResources().getText(R.string.fullbackup_erase_dialog_message);
176         } else {
177             msg = getResources().getText(R.string.backup_erase_dialog_message);
178         }
179 
180         mWaitingForConfirmationDialog = true;
181 
182         // TODO: DialogFragment?
183         mConfirmDialog = new AlertDialog.Builder(getActivity()).setMessage(msg)
184                 .setTitle(R.string.backup_erase_dialog_title)
185                 .setPositiveButton(android.R.string.ok, this)
186                 .setNegativeButton(android.R.string.cancel, this)
187                 .setOnDismissListener(this)
188                 .show();
189     }
190 
191     @Override
getMetricsCategory()192     public int getMetricsCategory() {
193         return SettingsEnums.PRIVACY;
194     }
195 
196     /**
197      * Informs the BackupManager of a change in backup state - if backup is disabled,
198      * the data on the server will be erased.
199      * @param enable whether to enable backup
200      */
setBackupEnabled(boolean enable)201     private void setBackupEnabled(boolean enable) {
202         if (mBackupManager != null) {
203             try {
204                 mBackupManager.setBackupEnabled(enable);
205             } catch (RemoteException e) {
206                 Log.e(TAG, "Error communicating with BackupManager", e);
207                 return;
208             }
209         }
210     }
211 }
212