blob: 0b571cc81f4d144cda8172ff9898529db02c750c [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;
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070032
33import com.example.android.systemupdatersample.R;
34import com.example.android.systemupdatersample.UpdateConfig;
Zhomart Mukhamejanov6f26e712018-05-18 10:15:31 -070035import com.example.android.systemupdatersample.UpdateManager;
Zhomart Mukhamejanov674aa6c2018-05-25 17:00:11 -070036import com.example.android.systemupdatersample.UpdaterState;
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;
Zhomart Mukhamejanov8f4059d2018-05-18 10:15:31 -070059 private TextView mTextViewUpdaterState;
60 private TextView mTextViewEngineStatus;
61 private TextView mTextViewEngineErrorCode;
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -070062 private TextView mTextViewUpdateInfo;
63 private Button mButtonSwitchSlot;
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070064
65 private List<UpdateConfig> mConfigs;
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070066
Zhomart Mukhamejanov6f26e712018-05-18 10:15:31 -070067 private final UpdateManager mUpdateManager =
68 new UpdateManager(new UpdateEngine(), new PayloadSpecs());
Zhomart Mukhamejanovf7a70382018-05-02 20:37:12 -070069
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070070 @Override
71 protected void onCreate(Bundle savedInstanceState) {
72 super.onCreate(savedInstanceState);
73 setContentView(R.layout.activity_main);
74
75 this.mTextViewBuild = findViewById(R.id.textViewBuild);
76 this.mSpinnerConfigs = findViewById(R.id.spinnerConfigs);
77 this.mTextViewConfigsDirHint = findViewById(R.id.textViewConfigsDirHint);
78 this.mButtonReload = findViewById(R.id.buttonReload);
79 this.mButtonApplyConfig = findViewById(R.id.buttonApplyConfig);
80 this.mButtonStop = findViewById(R.id.buttonStop);
81 this.mButtonReset = findViewById(R.id.buttonReset);
82 this.mProgressBar = findViewById(R.id.progressBar);
Zhomart Mukhamejanov8f4059d2018-05-18 10:15:31 -070083 this.mTextViewUpdaterState = findViewById(R.id.textViewUpdaterState);
84 this.mTextViewEngineStatus = findViewById(R.id.textViewEngineStatus);
85 this.mTextViewEngineErrorCode = findViewById(R.id.textViewEngineErrorCode);
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -070086 this.mTextViewUpdateInfo = findViewById(R.id.textViewUpdateInfo);
87 this.mButtonSwitchSlot = findViewById(R.id.buttonSwitchSlot);
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070088
89 this.mTextViewConfigsDirHint.setText(UpdateConfigs.getConfigsRoot(this));
90
91 uiReset();
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070092 loadUpdateConfigs();
Zhomart Mukhamejanovf7a70382018-05-02 20:37:12 -070093
Zhomart Mukhamejanov8f4059d2018-05-18 10:15:31 -070094 this.mUpdateManager.setOnStateChangeCallback(this::onUpdaterStateChange);
95 this.mUpdateManager.setOnEngineStatusUpdateCallback(this::onEngineStatusUpdate);
96 this.mUpdateManager.setOnEngineCompleteCallback(this::onEnginePayloadApplicationComplete);
Zhomart Mukhamejanov6f26e712018-05-18 10:15:31 -070097 this.mUpdateManager.setOnProgressUpdateCallback(this::onProgressUpdate);
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070098 }
99
100 @Override
101 protected void onDestroy() {
Zhomart Mukhamejanov6f26e712018-05-18 10:15:31 -0700102 this.mUpdateManager.setOnEngineStatusUpdateCallback(null);
103 this.mUpdateManager.setOnProgressUpdateCallback(null);
104 this.mUpdateManager.setOnEngineCompleteCallback(null);
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700105 super.onDestroy();
106 }
107
Zhomart Mukhamejanov6f26e712018-05-18 10:15:31 -0700108 @Override
109 protected void onResume() {
110 super.onResume();
111 this.mUpdateManager.bind();
112 }
113
114 @Override
115 protected void onPause() {
116 this.mUpdateManager.unbind();
117 super.onPause();
118 }
119
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700120 /**
121 * reload button is clicked
122 */
123 public void onReloadClick(View view) {
124 loadUpdateConfigs();
125 }
126
127 /**
128 * view config button is clicked
129 */
130 public void onViewConfigClick(View view) {
131 UpdateConfig config = mConfigs.get(mSpinnerConfigs.getSelectedItemPosition());
132 new AlertDialog.Builder(this)
133 .setTitle(config.getName())
134 .setMessage(config.getRawJson())
135 .setPositiveButton(R.string.close, (dialog, id) -> dialog.dismiss())
136 .show();
137 }
138
139 /**
140 * apply config button is clicked
141 */
142 public void onApplyConfigClick(View view) {
143 new AlertDialog.Builder(this)
144 .setTitle("Apply Update")
145 .setMessage("Do you really want to apply this update?")
146 .setIcon(android.R.drawable.ic_dialog_alert)
147 .setPositiveButton(android.R.string.ok, (dialog, whichButton) -> {
148 uiSetUpdating();
Zhomart Mukhamejanov8f4059d2018-05-18 10:15:31 -0700149 uiResetEngineText();
Zhomart Mukhamejanov6f26e712018-05-18 10:15:31 -0700150 mUpdateManager.applyUpdate(this, getSelectedConfig());
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700151 })
152 .setNegativeButton(android.R.string.cancel, null)
153 .show();
154 }
155
156 /**
157 * stop button clicked
158 */
159 public void onStopClick(View view) {
160 new AlertDialog.Builder(this)
161 .setTitle("Stop Update")
162 .setMessage("Do you really want to cancel running update?")
163 .setIcon(android.R.drawable.ic_dialog_alert)
164 .setPositiveButton(android.R.string.ok, (dialog, whichButton) -> {
Zhomart Mukhamejanov6f26e712018-05-18 10:15:31 -0700165 mUpdateManager.cancelRunningUpdate();
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700166 })
167 .setNegativeButton(android.R.string.cancel, null).show();
168 }
169
170 /**
171 * reset button clicked
172 */
173 public void onResetClick(View view) {
174 new AlertDialog.Builder(this)
175 .setTitle("Reset Update")
176 .setMessage("Do you really want to cancel running update"
177 + " and restore old version?")
178 .setIcon(android.R.drawable.ic_dialog_alert)
179 .setPositiveButton(android.R.string.ok, (dialog, whichButton) -> {
Zhomart Mukhamejanov6f26e712018-05-18 10:15:31 -0700180 mUpdateManager.resetUpdate();
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700181 })
182 .setNegativeButton(android.R.string.cancel, null).show();
183 }
184
185 /**
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -0700186 * switch slot button clicked
187 */
188 public void onSwitchSlotClick(View view) {
Zhomart Mukhamejanov6f26e712018-05-18 10:15:31 -0700189 mUpdateManager.setSwitchSlotOnReboot();
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -0700190 }
191
192 /**
Zhomart Mukhamejanov8f4059d2018-05-18 10:15:31 -0700193 * Invoked when SystemUpdaterSample app state changes.
194 * Value of {@code state} will be one of the
Zhomart Mukhamejanov674aa6c2018-05-25 17:00:11 -0700195 * values from {@link UpdaterState}.
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700196 */
Zhomart Mukhamejanov8f4059d2018-05-18 10:15:31 -0700197 private void onUpdaterStateChange(int state) {
198 Log.i(TAG, "onUpdaterStateChange invoked state=" + state);
Zhomart Mukhamejanov6f26e712018-05-18 10:15:31 -0700199 runOnUiThread(() -> {
Zhomart Mukhamejanov8f4059d2018-05-18 10:15:31 -0700200 setUiUpdaterState(state);
201 });
202 }
203
204 /**
205 * Invoked when {@link UpdateEngine} status changes. Value of {@code status} will
206 * be one of the values from {@link UpdateEngine.UpdateStatusConstants}.
207 */
208 private void onEngineStatusUpdate(int status) {
209 runOnUiThread(() -> {
210 Log.e(TAG, "StatusUpdate - status="
Zhomart Mukhamejanov6f26e712018-05-18 10:15:31 -0700211 + UpdateEngineStatuses.getStatusText(status)
212 + "/" + status);
Zhomart Mukhamejanov6f26e712018-05-18 10:15:31 -0700213 if (status == UpdateEngine.UpdateStatusConstants.IDLE) {
214 Log.d(TAG, "status changed, resetting ui");
215 uiReset();
216 } else {
217 Log.d(TAG, "status changed, setting ui to updating mode");
218 uiSetUpdating();
219 }
Zhomart Mukhamejanov8f4059d2018-05-18 10:15:31 -0700220 setUiEngineStatus(status);
Zhomart Mukhamejanov6f26e712018-05-18 10:15:31 -0700221 });
222 }
223
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700224 /**
225 * Invoked when the payload has been applied, whether successfully or
226 * unsuccessfully. The value of {@code errorCode} will be one of the
227 * values from {@link UpdateEngine.ErrorCodeConstants}.
228 */
Zhomart Mukhamejanov8f4059d2018-05-18 10:15:31 -0700229 private void onEnginePayloadApplicationComplete(int errorCode) {
230 final String completionState = UpdateEngineErrorCodes.isUpdateSucceeded(errorCode)
Zhomart Mukhamejanovf7a70382018-05-02 20:37:12 -0700231 ? "SUCCESS"
232 : "FAILURE";
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700233 runOnUiThread(() -> {
Zhomart Mukhamejanov8f4059d2018-05-18 10:15:31 -0700234 Log.i(TAG,
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700235 "Completed - errorCode="
Zhomart Mukhamejanov674aa6c2018-05-25 17:00:11 -0700236 + UpdateEngineErrorCodes.getCodeName(errorCode) + "/" + errorCode
237 + " " + completionState);
Zhomart Mukhamejanov8f4059d2018-05-18 10:15:31 -0700238 setUiEngineErrorCode(errorCode);
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -0700239 if (errorCode == UpdateEngineErrorCodes.UPDATED_BUT_NOT_ACTIVE) {
240 // if update was successfully applied.
Zhomart Mukhamejanov8f4059d2018-05-18 10:15:31 -0700241 if (mUpdateManager.isManualSwitchSlotRequired()) {
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -0700242 // Show "Switch Slot" button.
243 uiShowSwitchSlotInfo();
244 }
245 }
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700246 });
247 }
248
Zhomart Mukhamejanov8f4059d2018-05-18 10:15:31 -0700249 /**
250 * Invoked when update progress changes.
251 */
252 private void onProgressUpdate(double progress) {
253 mProgressBar.setProgress((int) (100 * progress));
254 }
255
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700256 /** resets ui */
257 private void uiReset() {
258 mTextViewBuild.setText(Build.DISPLAY);
259 mSpinnerConfigs.setEnabled(true);
260 mButtonReload.setEnabled(true);
261 mButtonApplyConfig.setEnabled(true);
262 mButtonStop.setEnabled(false);
263 mButtonReset.setEnabled(false);
264 mProgressBar.setProgress(0);
265 mProgressBar.setEnabled(false);
266 mProgressBar.setVisibility(ProgressBar.INVISIBLE);
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -0700267 uiHideSwitchSlotInfo();
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700268 }
269
Zhomart Mukhamejanov8f4059d2018-05-18 10:15:31 -0700270 private void uiResetEngineText() {
271 mTextViewEngineStatus.setText(R.string.unknown);
272 mTextViewEngineErrorCode.setText(R.string.unknown);
273 // Note: Do not reset mTextViewUpdaterState; UpdateManager notifies properly.
274 }
275
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700276 /** sets ui updating mode */
277 private void uiSetUpdating() {
278 mTextViewBuild.setText(Build.DISPLAY);
279 mSpinnerConfigs.setEnabled(false);
280 mButtonReload.setEnabled(false);
281 mButtonApplyConfig.setEnabled(false);
282 mButtonStop.setEnabled(true);
283 mProgressBar.setEnabled(true);
284 mButtonReset.setEnabled(true);
285 mProgressBar.setVisibility(ProgressBar.VISIBLE);
286 }
287
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -0700288 private void uiShowSwitchSlotInfo() {
289 mButtonSwitchSlot.setEnabled(true);
290 mTextViewUpdateInfo.setTextColor(Color.parseColor("#777777"));
291 }
292
293 private void uiHideSwitchSlotInfo() {
294 mTextViewUpdateInfo.setTextColor(Color.parseColor("#AAAAAA"));
295 mButtonSwitchSlot.setEnabled(false);
296 }
297
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700298 /**
299 * loads json configurations from configs dir that is defined in {@link UpdateConfigs}.
300 */
301 private void loadUpdateConfigs() {
302 mConfigs = UpdateConfigs.getUpdateConfigs(this);
303 loadConfigsToSpinner(mConfigs);
304 }
305
306 /**
307 * @param status update engine status code
308 */
Zhomart Mukhamejanov8f4059d2018-05-18 10:15:31 -0700309 private void setUiEngineStatus(int status) {
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700310 String statusText = UpdateEngineStatuses.getStatusText(status);
Zhomart Mukhamejanov8f4059d2018-05-18 10:15:31 -0700311 mTextViewEngineStatus.setText(statusText + "/" + status);
Zhomart Mukhamejanovf7a70382018-05-02 20:37:12 -0700312 }
313
314 /**
315 * @param errorCode update engine error code
316 */
Zhomart Mukhamejanov8f4059d2018-05-18 10:15:31 -0700317 private void setUiEngineErrorCode(int errorCode) {
Zhomart Mukhamejanovf7a70382018-05-02 20:37:12 -0700318 String errorText = UpdateEngineErrorCodes.getCodeName(errorCode);
Zhomart Mukhamejanov8f4059d2018-05-18 10:15:31 -0700319 mTextViewEngineErrorCode.setText(errorText + "/" + errorCode);
320 }
321
322 /**
323 * @param state updater sample state
324 */
325 private void setUiUpdaterState(int state) {
Zhomart Mukhamejanov674aa6c2018-05-25 17:00:11 -0700326 String stateText = UpdaterState.getStateText(state);
Zhomart Mukhamejanov8f4059d2018-05-18 10:15:31 -0700327 mTextViewUpdaterState.setText(stateText + "/" + state);
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700328 }
329
330 private void loadConfigsToSpinner(List<UpdateConfig> configs) {
331 String[] spinnerArray = UpdateConfigs.configsToNames(configs);
332 ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(this,
333 android.R.layout.simple_spinner_item,
334 spinnerArray);
335 spinnerArrayAdapter.setDropDownViewResource(android.R.layout
336 .simple_spinner_dropdown_item);
337 mSpinnerConfigs.setAdapter(spinnerArrayAdapter);
338 }
339
340 private UpdateConfig getSelectedConfig() {
341 return mConfigs.get(mSpinnerConfigs.getSelectedItemPosition());
342 }
343
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700344}