1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.car.settings.admin;
18 
19 import static android.car.drivingstate.CarDrivingStateEvent.DRIVING_STATE_PARKED;
20 
21 import android.app.Activity;
22 import android.app.AlertDialog;
23 import android.app.NotificationManager;
24 import android.app.PendingIntent;
25 import android.car.Car;
26 import android.car.ICarResultReceiver;
27 import android.car.drivingstate.CarDrivingStateEvent;
28 import android.car.drivingstate.CarDrivingStateManager;
29 import android.content.Intent;
30 import android.os.Bundle;
31 import android.os.IBinder;
32 import android.widget.Toast;
33 
34 import com.android.car.settings.R;
35 import com.android.car.settings.common.Logger;
36 
37 
38 /**
39  * Activity shown when a factory request is imminent, it gives the user the option to reset now or
40  * wait until the device is rebooted / resumed from suspend.
41  */
42 public final class FactoryResetActivity extends Activity {
43     private static final String EXTRA_FACTORY_RESET_CALLBACK = "factory_reset_callback";
44     private static final int FACTORY_RESET_NOTIFICATION_ID = 42;
45     private static final Logger LOG = new Logger(FactoryResetActivity.class);
46     private ICarResultReceiver mCallback;
47     private Car mCar;
48     private CarDrivingStateManager mCarDrivingStateManager;
49 
50     @Override
onCreate(Bundle savedInstanceState)51     protected void onCreate(Bundle savedInstanceState) {
52         super.onCreate(savedInstanceState);
53 
54         Intent intent = getIntent();
55         Object binder = null;
56 
57         try {
58             binder = intent.getExtra(EXTRA_FACTORY_RESET_CALLBACK);
59             mCallback = ICarResultReceiver.Stub.asInterface((IBinder) binder);
60         } catch (Exception e) {
61             LOG.w("error getting IResultReveiver from " + EXTRA_FACTORY_RESET_CALLBACK
62                     + " extra (" + binder + ") on " + intent, e);
63         }
64 
65         if (mCallback == null) {
66             LOG.wtf("no ICarResultReceiver / " + EXTRA_FACTORY_RESET_CALLBACK
67                     + " extra  on " + intent);
68             finish();
69             return;
70         }
71 
72         // Connect to car service
73         mCar = Car.createCar(this);
74         mCarDrivingStateManager = (CarDrivingStateManager) mCar.getCarManager(
75                 Car.CAR_DRIVING_STATE_SERVICE);
76         showMore();
77     }
78 
79     @Override
onStop()80     protected void onStop() {
81         super.onStop();
82         finish();
83     }
84 
showMore()85     private void showMore() {
86         CarDrivingStateEvent state = mCarDrivingStateManager.getCurrentCarDrivingState();
87         switch (state.eventValue) {
88             case DRIVING_STATE_PARKED:
89                 showFactoryResetDialog();
90                 break;
91             default:
92                 showFactoryResetToast();
93         }
94     }
95 
showFactoryResetDialog()96     private void showFactoryResetDialog() {
97         AlertDialog dialog = new AlertDialog.Builder(/* context= */ this,
98                         com.android.internal.R.style.Theme_DeviceDefault_Dialog_Alert)
99                 .setTitle(R.string.factory_reset_parked_title)
100                 .setMessage(R.string.factory_reset_parked_text)
101                 .setPositiveButton(R.string.factory_reset_later_button,
102                         (d, which) -> factoryResetLater())
103                 .setNegativeButton(R.string.factory_reset_now_button,
104                         (d, which) -> factoryResetNow())
105                 .setCancelable(false)
106                 .setOnDismissListener((d) -> finish())
107                 .create();
108 
109         dialog.show();
110     }
111 
showFactoryResetToast()112     private void showFactoryResetToast() {
113         showToast(R.string.factory_reset_driving_text);
114         finish();
115     }
116 
factoryResetNow()117     private void factoryResetNow() {
118         LOG.i("Factory reset acknowledged; finishing it");
119 
120         try {
121             mCallback.send(/* resultCode= */ 0, /* resultData= */ null);
122 
123             // Cancel pending intent and notification
124             getSystemService(NotificationManager.class).cancel(FACTORY_RESET_NOTIFICATION_ID);
125             PendingIntent.getActivity(this, FACTORY_RESET_NOTIFICATION_ID, getIntent(),
126                     PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT).cancel();
127         } catch (Exception e) {
128             LOG.e("error factory resetting or cancelling notification / intent", e);
129             return;
130         } finally {
131             finish();
132         }
133     }
134 
factoryResetLater()135     private void factoryResetLater() {
136         LOG.i("Delaying factory reset.");
137         showToast(R.string.factory_reset_later_text);
138         finish();
139     }
140 
showToast(int resId)141     private void showToast(int resId) {
142         Toast.makeText(this, resId, Toast.LENGTH_LONG).show();
143     }
144 }
145