blob: 9237bc79431023607fa93c8103d513d2830d097a [file] [log] [blame]
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -07001/*
2 * Copyright (C) 2018 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
17package com.example.android.systemupdatersample.ui;
18
19import android.app.Activity;
20import android.app.AlertDialog;
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -070021import android.graphics.Color;
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070022import android.os.Build;
23import android.os.Bundle;
24import android.os.UpdateEngine;
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070025import android.util.Log;
26import android.view.View;
27import android.widget.ArrayAdapter;
28import android.widget.Button;
29import android.widget.ProgressBar;
30import android.widget.Spinner;
31import android.widget.TextView;
32import android.widget.Toast;
33
34import com.example.android.systemupdatersample.R;
35import com.example.android.systemupdatersample.UpdateConfig;
Zhomart Mukhamejanov6f26e712018-05-18 10:15:31 -070036import com.example.android.systemupdatersample.UpdateManager;
Zhomart Mukhamejanovf7a70382018-05-02 20:37:12 -070037import com.example.android.systemupdatersample.util.PayloadSpecs;
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070038import com.example.android.systemupdatersample.util.UpdateConfigs;
39import com.example.android.systemupdatersample.util.UpdateEngineErrorCodes;
40import com.example.android.systemupdatersample.util.UpdateEngineStatuses;
41
42import java.util.List;
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070043
44/**
45 * UI for SystemUpdaterSample app.
46 */
47public class MainActivity extends Activity {
48
Zhomart Mukhamejanovf7a70382018-05-02 20:37:12 -070049 private static final String TAG = "MainActivity";
50
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070051 private TextView mTextViewBuild;
52 private Spinner mSpinnerConfigs;
53 private TextView mTextViewConfigsDirHint;
54 private Button mButtonReload;
55 private Button mButtonApplyConfig;
56 private Button mButtonStop;
57 private Button mButtonReset;
58 private ProgressBar mProgressBar;
59 private TextView mTextViewStatus;
Zhomart Mukhamejanovf7a70382018-05-02 20:37:12 -070060 private TextView mTextViewCompletion;
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -070061 private TextView mTextViewUpdateInfo;
62 private Button mButtonSwitchSlot;
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070063
64 private List<UpdateConfig> mConfigs;
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070065
Zhomart Mukhamejanov6f26e712018-05-18 10:15:31 -070066 private final UpdateManager mUpdateManager =
67 new UpdateManager(new UpdateEngine(), new PayloadSpecs());
Zhomart Mukhamejanovf7a70382018-05-02 20:37:12 -070068
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070069 @Override
70 protected void onCreate(Bundle savedInstanceState) {
71 super.onCreate(savedInstanceState);
72 setContentView(R.layout.activity_main);
73
74 this.mTextViewBuild = findViewById(R.id.textViewBuild);
75 this.mSpinnerConfigs = findViewById(R.id.spinnerConfigs);
76 this.mTextViewConfigsDirHint = findViewById(R.id.textViewConfigsDirHint);
77 this.mButtonReload = findViewById(R.id.buttonReload);
78 this.mButtonApplyConfig = findViewById(R.id.buttonApplyConfig);
79 this.mButtonStop = findViewById(R.id.buttonStop);
80 this.mButtonReset = findViewById(R.id.buttonReset);
81 this.mProgressBar = findViewById(R.id.progressBar);
82 this.mTextViewStatus = findViewById(R.id.textViewStatus);
Zhomart Mukhamejanovf7a70382018-05-02 20:37:12 -070083 this.mTextViewCompletion = findViewById(R.id.textViewCompletion);
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -070084 this.mTextViewUpdateInfo = findViewById(R.id.textViewUpdateInfo);
85 this.mButtonSwitchSlot = findViewById(R.id.buttonSwitchSlot);
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070086
87 this.mTextViewConfigsDirHint.setText(UpdateConfigs.getConfigsRoot(this));
88
89 uiReset();
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070090 loadUpdateConfigs();
Zhomart Mukhamejanovf7a70382018-05-02 20:37:12 -070091
Zhomart Mukhamejanov6f26e712018-05-18 10:15:31 -070092 this.mUpdateManager.setOnEngineStatusUpdateCallback(this::onStatusUpdate);
93 this.mUpdateManager.setOnProgressUpdateCallback(this::onProgressUpdate);
94 this.mUpdateManager.setOnEngineCompleteCallback(this::onPayloadApplicationComplete);
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070095 }
96
97 @Override
98 protected void onDestroy() {
Zhomart Mukhamejanov6f26e712018-05-18 10:15:31 -070099 this.mUpdateManager.setOnEngineStatusUpdateCallback(null);
100 this.mUpdateManager.setOnProgressUpdateCallback(null);
101 this.mUpdateManager.setOnEngineCompleteCallback(null);
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700102 super.onDestroy();
103 }
104
Zhomart Mukhamejanov6f26e712018-05-18 10:15:31 -0700105 @Override
106 protected void onResume() {
107 super.onResume();
108 this.mUpdateManager.bind();
109 }
110
111 @Override
112 protected void onPause() {
113 this.mUpdateManager.unbind();
114 super.onPause();
115 }
116
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700117 /**
118 * reload button is clicked
119 */
120 public void onReloadClick(View view) {
121 loadUpdateConfigs();
122 }
123
124 /**
125 * view config button is clicked
126 */
127 public void onViewConfigClick(View view) {
128 UpdateConfig config = mConfigs.get(mSpinnerConfigs.getSelectedItemPosition());
129 new AlertDialog.Builder(this)
130 .setTitle(config.getName())
131 .setMessage(config.getRawJson())
132 .setPositiveButton(R.string.close, (dialog, id) -> dialog.dismiss())
133 .show();
134 }
135
136 /**
137 * apply config button is clicked
138 */
139 public void onApplyConfigClick(View view) {
140 new AlertDialog.Builder(this)
141 .setTitle("Apply Update")
142 .setMessage("Do you really want to apply this update?")
143 .setIcon(android.R.drawable.ic_dialog_alert)
144 .setPositiveButton(android.R.string.ok, (dialog, whichButton) -> {
145 uiSetUpdating();
Zhomart Mukhamejanov6f26e712018-05-18 10:15:31 -0700146 mUpdateManager.applyUpdate(this, getSelectedConfig());
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700147 })
148 .setNegativeButton(android.R.string.cancel, null)
149 .show();
150 }
151
152 /**
153 * stop button clicked
154 */
155 public void onStopClick(View view) {
156 new AlertDialog.Builder(this)
157 .setTitle("Stop Update")
158 .setMessage("Do you really want to cancel running update?")
159 .setIcon(android.R.drawable.ic_dialog_alert)
160 .setPositiveButton(android.R.string.ok, (dialog, whichButton) -> {
Zhomart Mukhamejanov6f26e712018-05-18 10:15:31 -0700161 mUpdateManager.cancelRunningUpdate();
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700162 })
163 .setNegativeButton(android.R.string.cancel, null).show();
164 }
165
166 /**
167 * reset button clicked
168 */
169 public void onResetClick(View view) {
170 new AlertDialog.Builder(this)
171 .setTitle("Reset Update")
172 .setMessage("Do you really want to cancel running update"
173 + " and restore old version?")
174 .setIcon(android.R.drawable.ic_dialog_alert)
175 .setPositiveButton(android.R.string.ok, (dialog, whichButton) -> {
Zhomart Mukhamejanov6f26e712018-05-18 10:15:31 -0700176 mUpdateManager.resetUpdate();
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700177 })
178 .setNegativeButton(android.R.string.cancel, null).show();
179 }
180
181 /**
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -0700182 * switch slot button clicked
183 */
184 public void onSwitchSlotClick(View view) {
Zhomart Mukhamejanov6f26e712018-05-18 10:15:31 -0700185 mUpdateManager.setSwitchSlotOnReboot();
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -0700186 }
187
188 /**
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700189 * Invoked when anything changes. The value of {@code status} will
190 * be one of the values from {@link UpdateEngine.UpdateStatusConstants},
191 * and {@code percent} will be from {@code 0.0} to {@code 1.0}.
192 */
Zhomart Mukhamejanov6f26e712018-05-18 10:15:31 -0700193 private void onStatusUpdate(int status) {
194 runOnUiThread(() -> {
195 Log.e("UpdateEngine", "StatusUpdate - status="
196 + UpdateEngineStatuses.getStatusText(status)
197 + "/" + status);
198 Toast.makeText(this, "Update Status changed", Toast.LENGTH_LONG)
199 .show();
200 if (status == UpdateEngine.UpdateStatusConstants.IDLE) {
201 Log.d(TAG, "status changed, resetting ui");
202 uiReset();
203 } else {
204 Log.d(TAG, "status changed, setting ui to updating mode");
205 uiSetUpdating();
206 }
207 setUiStatus(status);
208 });
209 }
210
211 private void onProgressUpdate(double progress) {
212 mProgressBar.setProgress((int) (100 * progress));
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700213 }
214
215 /**
216 * Invoked when the payload has been applied, whether successfully or
217 * unsuccessfully. The value of {@code errorCode} will be one of the
218 * values from {@link UpdateEngine.ErrorCodeConstants}.
219 */
220 private void onPayloadApplicationComplete(int errorCode) {
Zhomart Mukhamejanovf7a70382018-05-02 20:37:12 -0700221 final String state = UpdateEngineErrorCodes.isUpdateSucceeded(errorCode)
222 ? "SUCCESS"
223 : "FAILURE";
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700224 runOnUiThread(() -> {
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700225 Log.i("UpdateEngine",
226 "Completed - errorCode="
227 + UpdateEngineErrorCodes.getCodeName(errorCode) + "/" + errorCode
228 + " " + state);
229 Toast.makeText(this, "Update completed", Toast.LENGTH_LONG).show();
Zhomart Mukhamejanovf7a70382018-05-02 20:37:12 -0700230 setUiCompletion(errorCode);
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -0700231 if (errorCode == UpdateEngineErrorCodes.UPDATED_BUT_NOT_ACTIVE) {
232 // if update was successfully applied.
Zhomart Mukhamejanov6f26e712018-05-18 10:15:31 -0700233 if (mUpdateManager.manualSwitchSlotRequired()) {
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -0700234 // Show "Switch Slot" button.
235 uiShowSwitchSlotInfo();
236 }
237 }
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700238 });
239 }
240
241 /** resets ui */
242 private void uiReset() {
243 mTextViewBuild.setText(Build.DISPLAY);
244 mSpinnerConfigs.setEnabled(true);
245 mButtonReload.setEnabled(true);
246 mButtonApplyConfig.setEnabled(true);
247 mButtonStop.setEnabled(false);
248 mButtonReset.setEnabled(false);
249 mProgressBar.setProgress(0);
250 mProgressBar.setEnabled(false);
251 mProgressBar.setVisibility(ProgressBar.INVISIBLE);
252 mTextViewStatus.setText(R.string.unknown);
Zhomart Mukhamejanovf7a70382018-05-02 20:37:12 -0700253 mTextViewCompletion.setText(R.string.unknown);
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -0700254 uiHideSwitchSlotInfo();
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700255 }
256
257 /** sets ui updating mode */
258 private void uiSetUpdating() {
259 mTextViewBuild.setText(Build.DISPLAY);
260 mSpinnerConfigs.setEnabled(false);
261 mButtonReload.setEnabled(false);
262 mButtonApplyConfig.setEnabled(false);
263 mButtonStop.setEnabled(true);
264 mProgressBar.setEnabled(true);
265 mButtonReset.setEnabled(true);
266 mProgressBar.setVisibility(ProgressBar.VISIBLE);
267 }
268
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -0700269 private void uiShowSwitchSlotInfo() {
270 mButtonSwitchSlot.setEnabled(true);
271 mTextViewUpdateInfo.setTextColor(Color.parseColor("#777777"));
272 }
273
274 private void uiHideSwitchSlotInfo() {
275 mTextViewUpdateInfo.setTextColor(Color.parseColor("#AAAAAA"));
276 mButtonSwitchSlot.setEnabled(false);
277 }
278
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700279 /**
280 * loads json configurations from configs dir that is defined in {@link UpdateConfigs}.
281 */
282 private void loadUpdateConfigs() {
283 mConfigs = UpdateConfigs.getUpdateConfigs(this);
284 loadConfigsToSpinner(mConfigs);
285 }
286
287 /**
288 * @param status update engine status code
289 */
290 private void setUiStatus(int status) {
291 String statusText = UpdateEngineStatuses.getStatusText(status);
Zhomart Mukhamejanovf7a70382018-05-02 20:37:12 -0700292 mTextViewStatus.setText(statusText + "/" + status);
293 }
294
295 /**
296 * @param errorCode update engine error code
297 */
298 private void setUiCompletion(int errorCode) {
299 final String state = UpdateEngineErrorCodes.isUpdateSucceeded(errorCode)
300 ? "SUCCESS"
301 : "FAILURE";
302 String errorText = UpdateEngineErrorCodes.getCodeName(errorCode);
303 mTextViewCompletion.setText(state + " " + errorText + "/" + errorCode);
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700304 }
305
306 private void loadConfigsToSpinner(List<UpdateConfig> configs) {
307 String[] spinnerArray = UpdateConfigs.configsToNames(configs);
308 ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(this,
309 android.R.layout.simple_spinner_item,
310 spinnerArray);
311 spinnerArrayAdapter.setDropDownViewResource(android.R.layout
312 .simple_spinner_dropdown_item);
313 mSpinnerConfigs.setAdapter(spinnerArrayAdapter);
314 }
315
316 private UpdateConfig getSelectedConfig() {
317 return mConfigs.get(mSpinnerConfigs.getSelectedItemPosition());
318 }
319
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700320}