blob: 8507a9e840eab26a0717c875d7d2b49540b90423 [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;
21import android.os.Build;
22import android.os.Bundle;
23import android.os.UpdateEngine;
24import android.os.UpdateEngineCallback;
25import 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;
36import com.example.android.systemupdatersample.updates.AbNonStreamingUpdate;
37import com.example.android.systemupdatersample.util.UpdateConfigs;
38import com.example.android.systemupdatersample.util.UpdateEngineErrorCodes;
39import com.example.android.systemupdatersample.util.UpdateEngineStatuses;
40
41import java.util.List;
42import java.util.concurrent.atomic.AtomicInteger;
43
44/**
45 * UI for SystemUpdaterSample app.
46 */
47public class MainActivity extends Activity {
48
49 private TextView mTextViewBuild;
50 private Spinner mSpinnerConfigs;
51 private TextView mTextViewConfigsDirHint;
52 private Button mButtonReload;
53 private Button mButtonApplyConfig;
54 private Button mButtonStop;
55 private Button mButtonReset;
56 private ProgressBar mProgressBar;
57 private TextView mTextViewStatus;
58
59 private List<UpdateConfig> mConfigs;
60 private AtomicInteger mUpdateEngineStatus =
61 new AtomicInteger(UpdateEngine.UpdateStatusConstants.IDLE);
62 private UpdateEngine mUpdateEngine = new UpdateEngine();
63
64 /**
65 * Listen to {@code update_engine} events.
66 */
67 private UpdateEngineCallbackImpl mUpdateEngineCallback = new UpdateEngineCallbackImpl();
68
69 @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);
83
84 this.mUpdateEngine.bind(mUpdateEngineCallback);
85
86 this.mTextViewConfigsDirHint.setText(UpdateConfigs.getConfigsRoot(this));
87
88 uiReset();
89
90 loadUpdateConfigs();
91 }
92
93 @Override
94 protected void onDestroy() {
95 this.mUpdateEngine.unbind();
96 super.onDestroy();
97 }
98
99 /**
100 * reload button is clicked
101 */
102 public void onReloadClick(View view) {
103 loadUpdateConfigs();
104 }
105
106 /**
107 * view config button is clicked
108 */
109 public void onViewConfigClick(View view) {
110 UpdateConfig config = mConfigs.get(mSpinnerConfigs.getSelectedItemPosition());
111 new AlertDialog.Builder(this)
112 .setTitle(config.getName())
113 .setMessage(config.getRawJson())
114 .setPositiveButton(R.string.close, (dialog, id) -> dialog.dismiss())
115 .show();
116 }
117
118 /**
119 * apply config button is clicked
120 */
121 public void onApplyConfigClick(View view) {
122 new AlertDialog.Builder(this)
123 .setTitle("Apply Update")
124 .setMessage("Do you really want to apply this update?")
125 .setIcon(android.R.drawable.ic_dialog_alert)
126 .setPositiveButton(android.R.string.ok, (dialog, whichButton) -> {
127 uiSetUpdating();
128 applyUpdate(getSelectedConfig());
129 })
130 .setNegativeButton(android.R.string.cancel, null)
131 .show();
132 }
133
134 /**
135 * stop button clicked
136 */
137 public void onStopClick(View view) {
138 new AlertDialog.Builder(this)
139 .setTitle("Stop Update")
140 .setMessage("Do you really want to cancel running update?")
141 .setIcon(android.R.drawable.ic_dialog_alert)
142 .setPositiveButton(android.R.string.ok, (dialog, whichButton) -> {
143 uiReset();
144 stopRunningUpdate();
145 })
146 .setNegativeButton(android.R.string.cancel, null).show();
147 }
148
149 /**
150 * reset button clicked
151 */
152 public void onResetClick(View view) {
153 new AlertDialog.Builder(this)
154 .setTitle("Reset Update")
155 .setMessage("Do you really want to cancel running update"
156 + " and restore old version?")
157 .setIcon(android.R.drawable.ic_dialog_alert)
158 .setPositiveButton(android.R.string.ok, (dialog, whichButton) -> {
159 uiReset();
160 resetUpdate();
161 })
162 .setNegativeButton(android.R.string.cancel, null).show();
163 }
164
165 /**
166 * Invoked when anything changes. The value of {@code status} will
167 * be one of the values from {@link UpdateEngine.UpdateStatusConstants},
168 * and {@code percent} will be from {@code 0.0} to {@code 1.0}.
169 */
170 private void onStatusUpdate(int status, float percent) {
171 mProgressBar.setProgress((int) (100 * percent));
172 if (mUpdateEngineStatus.get() != status) {
173 mUpdateEngineStatus.set(status);
174 runOnUiThread(() -> {
175 Log.e("UpdateEngine", "StatusUpdate - status="
176 + UpdateEngineStatuses.getStatusText(status)
177 + "/" + status);
178 setUiStatus(status);
179 Toast.makeText(this, "Update Status changed", Toast.LENGTH_LONG)
180 .show();
181 });
182 }
183 }
184
185 /**
186 * Invoked when the payload has been applied, whether successfully or
187 * unsuccessfully. The value of {@code errorCode} will be one of the
188 * values from {@link UpdateEngine.ErrorCodeConstants}.
189 */
190 private void onPayloadApplicationComplete(int errorCode) {
191 runOnUiThread(() -> {
192 final String state = UpdateEngineErrorCodes.isUpdateSucceeded(errorCode)
193 ? "SUCCESS"
194 : "FAILURE";
195 Log.i("UpdateEngine",
196 "Completed - errorCode="
197 + UpdateEngineErrorCodes.getCodeName(errorCode) + "/" + errorCode
198 + " " + state);
199 Toast.makeText(this, "Update completed", Toast.LENGTH_LONG).show();
200 });
201 }
202
203 /** resets ui */
204 private void uiReset() {
205 mTextViewBuild.setText(Build.DISPLAY);
206 mSpinnerConfigs.setEnabled(true);
207 mButtonReload.setEnabled(true);
208 mButtonApplyConfig.setEnabled(true);
209 mButtonStop.setEnabled(false);
210 mButtonReset.setEnabled(false);
211 mProgressBar.setProgress(0);
212 mProgressBar.setEnabled(false);
213 mProgressBar.setVisibility(ProgressBar.INVISIBLE);
214 mTextViewStatus.setText(R.string.unknown);
215 }
216
217 /** sets ui updating mode */
218 private void uiSetUpdating() {
219 mTextViewBuild.setText(Build.DISPLAY);
220 mSpinnerConfigs.setEnabled(false);
221 mButtonReload.setEnabled(false);
222 mButtonApplyConfig.setEnabled(false);
223 mButtonStop.setEnabled(true);
224 mProgressBar.setEnabled(true);
225 mButtonReset.setEnabled(true);
226 mProgressBar.setVisibility(ProgressBar.VISIBLE);
227 }
228
229 /**
230 * loads json configurations from configs dir that is defined in {@link UpdateConfigs}.
231 */
232 private void loadUpdateConfigs() {
233 mConfigs = UpdateConfigs.getUpdateConfigs(this);
234 loadConfigsToSpinner(mConfigs);
235 }
236
237 /**
238 * @param status update engine status code
239 */
240 private void setUiStatus(int status) {
241 String statusText = UpdateEngineStatuses.getStatusText(status);
242 mTextViewStatus.setText(statusText);
243 }
244
245 private void loadConfigsToSpinner(List<UpdateConfig> configs) {
246 String[] spinnerArray = UpdateConfigs.configsToNames(configs);
247 ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(this,
248 android.R.layout.simple_spinner_item,
249 spinnerArray);
250 spinnerArrayAdapter.setDropDownViewResource(android.R.layout
251 .simple_spinner_dropdown_item);
252 mSpinnerConfigs.setAdapter(spinnerArrayAdapter);
253 }
254
255 private UpdateConfig getSelectedConfig() {
256 return mConfigs.get(mSpinnerConfigs.getSelectedItemPosition());
257 }
258
259 /**
260 * Applies the given update
261 */
262 private void applyUpdate(UpdateConfig config) {
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700263 if (config.getInstallType() == UpdateConfig.AB_INSTALL_TYPE_NON_STREAMING) {
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700264 AbNonStreamingUpdate update = new AbNonStreamingUpdate(mUpdateEngine, config);
265 try {
266 update.execute();
267 } catch (Exception e) {
268 Log.e("MainActivity", "Error applying the update", e);
269 Toast.makeText(this, "Error applying the update", Toast.LENGTH_SHORT)
270 .show();
271 }
272 } else {
273 Toast.makeText(this, "Streaming is not implemented", Toast.LENGTH_SHORT)
274 .show();
275 }
276 }
277
278 /**
279 * Requests update engine to stop any ongoing update. If an update has been applied,
280 * leave it as is.
281 */
282 private void stopRunningUpdate() {
283 Toast.makeText(this,
284 "stopRunningUpdate is not implemented",
285 Toast.LENGTH_SHORT).show();
286
287 }
288
289 /**
290 * Resets update engine to IDLE state. Requests to cancel any onging update, or to revert if an
291 * update has been applied.
292 */
293 private void resetUpdate() {
294 Toast.makeText(this,
295 "resetUpdate is not implemented",
296 Toast.LENGTH_SHORT).show();
297 }
298
299 /**
300 * Helper class to delegate UpdateEngine callbacks to MainActivity
301 */
302 class UpdateEngineCallbackImpl extends UpdateEngineCallback {
303 @Override
304 public void onStatusUpdate(int status, float percent) {
305 MainActivity.this.onStatusUpdate(status, percent);
306 }
307
308 @Override
309 public void onPayloadApplicationComplete(int errorCode) {
310 MainActivity.this.onPayloadApplicationComplete(errorCode);
311 }
312 }
313
314}