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.ayst.romupgrade.receiver;
18 |
19 | import android.content.Context;
20 | import android.content.Intent;
21 | import android.content.BroadcastReceiver;
22 | import android.os.Bundle;
23 | import android.text.TextUtils;
24 | import android.util.Log;
25 |
26 | import com.baidu.otasdk.ota.Constants;
27 | import com.ayst.romupgrade.App;
28 | import com.ayst.romupgrade.service.UpdateService;
29 |
30 | /**
31 | * Listen to the broadcast, start the UpdateService
32 | * to perform the upgrade action.
33 | *
34 | * Intent.ACTION_BOOT_COMPLETED
35 | * ConnectivityManager.CONNECTIVITY_ACTION
36 | * Intent.ACTION_MEDIA_MOUNTED
37 | * UsbManager.ACTION_USB_STATE
38 | * VolumeInfo.ACTION_VOLUME_STATE_CHANGED
39 | * Constants.BROADCAST_NEWVERSION
40 | *
41 | * Created by ayst.shen@foxmail.com on 2018/11/6.
42 | */
43 | public class UpdateReceiver extends BroadcastReceiver {
44 | private static final String TAG = "UpdateReceiver";
45 |
46 | private static final String ACTION_START = "com.ayst.romupgrade.action.START";
47 |
48 | private static int sVolumeState = -1;
49 |
50 | @Override
51 | public void onReceive(Context context, Intent intent) {
52 | String action = intent.getAction();
53 | Log.i(TAG, "onReceive, action = " + action);
54 |
55 | if (TextUtils.equals(Intent.ACTION_BOOT_COMPLETED, action)
56 | || TextUtils.equals(ACTION_START, action)) {
57 | /*
58 | Check local and remote upgrade after power-on.
59 | */
60 | Log.i(TAG, "onReceive, Boot completed. To check local and remote update.");
61 | context.startService(buildIntent(context,
62 | UpdateService.COMMAND_INITIAL,
63 | 5000));
64 |
65 | context.startService(buildIntent(context,
66 | UpdateService.COMMAND_CHECK_LOCAL_UPDATE,
67 | 10000));
68 |
69 | // context.startService(buildIntent(context,
70 | // UpdateService.COMMAND_CHECK_REMOTE_UPDATE,
71 | // 25000));
72 |
73 | } else if (TextUtils.equals(Intent.ACTION_MEDIA_MOUNTED, action)) {
74 | /*
75 | U-disk insert check local upgrade.
76 | */
77 | Log.i(TAG, "onReceive, Media is mounted. To check local update.");
78 | context.startService(buildIntent(context,
79 | UpdateService.COMMAND_CHECK_LOCAL_UPDATE,
80 | 5000));
81 |
82 | } else if (TextUtils.equals(UsbManager.ACTION_USB_STATE, action)) {
83 | /*
84 | U-disk insert check local upgrade.
85 | */
86 | Bundle extras = intent.getExtras();
87 | if (null != extras) {
88 | boolean connected = extras.getBoolean(UsbManager.USB_CONNECTED);
89 | boolean configured = extras.getBoolean(UsbManager.USB_CONFIGURED);
90 | boolean mtpEnabled = extras.getBoolean(UsbManager.USB_FUNCTION_MTP);
91 | boolean ptpEnabled = extras.getBoolean(UsbManager.USB_FUNCTION_PTP);
92 |
93 | if (!connected && mtpEnabled && !configured) {
94 | Log.i(TAG, "onReceive, mtp is enabled. To check local update.");
95 | context.startService(buildIntent(context,
96 | UpdateService.COMMAND_CHECK_LOCAL_UPDATE,
97 | 5000));
98 | }
99 | }
100 |
101 | } else if (TextUtils.equals(VolumeInfo.ACTION_VOLUME_STATE_CHANGED, action)) {
102 | /*
103 | U-disk insert check local upgrade.
104 | */
105 | int state = intent.getIntExtra(VolumeInfo.EXTRA_VOLUME_STATE, VolumeInfo.STATE_UNMOUNTED);
106 | if (sVolumeState == VolumeInfo.STATE_UNMOUNTED && state == VolumeInfo.STATE_MOUNTED) {
107 | Log.i(TAG, "onReceive, Volume is mounted. To check local update.");
108 | context.startService(buildIntent(context,
109 | UpdateService.COMMAND_CHECK_LOCAL_UPDATE,
110 | 5000));
111 | }
112 | sVolumeState = state;
113 |
114 | } else if (TextUtils.equals(Constants.BROADCAST_NEWVERSION, action)) {
115 | /*
116 | Baidu otasdk automatically checks for upgrade notifications.
117 | */
118 | String pid = intent.getStringExtra(Constants.BROADCAST_KEY_PID);
119 | if (TextUtils.equals(App.getProductId(), pid)) {
120 | String infos = intent.getStringExtra(Constants.BROADCAST_KEY_INFOS);
121 |
122 | Log.i(TAG, "onReceive, new version infos=" + infos);
123 | if (!TextUtils.isEmpty(infos)) {
124 | Intent serviceIntent = buildIntent(context, UpdateService.COMMAND_NEW_VERSION, 0);
125 | Bundle bundle = new Bundle();
126 | bundle.putString("infos", infos);
127 | serviceIntent.putExtra("bundle", bundle);
128 | context.startService(serviceIntent);
129 | }
130 | }
131 | }
132 | }
133 |
134 | private Intent buildIntent(Context context, int command, int delay) {
135 | Intent intent = new Intent(context, UpdateService.class);
136 | intent.putExtra("command", command);
137 | intent.putExtra("delay", delay);
138 | return intent;
139 | }
140 |
141 | public class VolumeInfo {
142 | /**
143 | * Unmounted
144 | */
145 | public static final int STATE_UNMOUNTED = 0;
146 |
147 | /**
148 | * Checking
149 | */
150 | public static final int STATE_CHECKING = 1;
151 |
152 | /**
153 | * Mounted
154 | */
155 | public static final int STATE_MOUNTED = 2;
156 |
157 | /**
158 | * Read only
159 | */
160 | public static final int STATE_MOUNTED_READ_ONLY = 3;
161 |
162 | /**
163 | * Formatting
164 | */
165 | public static final int STATE_FORMATTING = 4;
166 |
167 | /**
168 | * Ejecting
169 | */
170 | public static final int STATE_EJECTING = 5;
171 | /**
172 | * Not mountable
173 | */
174 | public static final int STATE_UNMOUNTABLE = 6;
175 |
176 | /**
177 | * Removed
178 | */
179 | public static final int STATE_REMOVED = 7;
180 |
181 | /**
182 | * Remove fail
183 | */
184 | public static final int STATE_BAD_REMOVAL = 8;
185 |
186 | /**
187 | * Volume state changed broadcast action.
188 | */
189 | public static final String ACTION_VOLUME_STATE_CHANGED =
190 | "android.os.storage.action.VOLUME_STATE_CHANGED";
191 |
192 | public static final String EXTRA_VOLUME_ID =
193 | "android.os.storage.extra.VOLUME_ID";
194 |
195 | public static final String EXTRA_VOLUME_STATE =
196 | "android.os.storage.extra.VOLUME_STATE";
197 | }
198 |
199 | public class UsbManager {
200 | /**
201 | * Broadcast Action: A sticky broadcast for USB state change events when in device mode.
202 | */
203 | public static final String ACTION_USB_STATE =
204 | "android.hardware.usb.action.USB_STATE";
205 |
206 | /**
207 | * Boolean extra indicating whether USB is connected or disconnected.
208 | * Used in extras for the {@link #ACTION_USB_STATE} broadcast.
209 | *
210 | * {@hide}
211 | */
212 | public static final String USB_CONNECTED = "connected";
213 |
214 | /**
215 | * Boolean extra indicating whether USB is configured.
216 | * Used in extras for the {@link #ACTION_USB_STATE} broadcast.
217 | */
218 | public static final String USB_CONFIGURED = "configured";
219 |
220 | /**
221 | * Name of the MTP USB function.
222 | * Used in extras for the {@link #ACTION_USB_STATE} broadcast
223 | */
224 | public static final String USB_FUNCTION_MTP = "mtp";
225 |
226 | /**
227 | * Name of the PTP USB function.
228 | * Used in extras for the {@link #ACTION_USB_STATE} broadcast
229 | */
230 | public static final String USB_FUNCTION_PTP = "ptp";
231 | }
232 | }
233 |
234 |
235 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ayst/romupgrade/util/AppUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright(c) 2020 Bob Shen
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.ayst.romupgrade.util;
18 |
19 | import android.annotation.SuppressLint;
20 | import android.app.Activity;
21 | import android.content.Context;
22 | import android.content.Intent;
23 | import android.content.pm.PackageInfo;
24 | import android.content.pm.PackageManager;
25 | import android.net.ConnectivityManager;
26 | import android.net.NetworkInfo;
27 | import android.net.wifi.WifiInfo;
28 | import android.net.wifi.WifiManager;
29 | import android.os.Build;
30 | import android.os.Environment;
31 | import android.os.storage.StorageManager;
32 | import android.os.storage.StorageVolume;
33 | import android.text.TextUtils;
34 | import android.util.Log;
35 |
36 | import androidx.annotation.NonNull;
37 | import androidx.annotation.RequiresApi;
38 |
39 | import java.io.BufferedInputStream;
40 | import java.io.BufferedReader;
41 | import java.io.File;
42 | import java.io.FileReader;
43 | import java.io.IOException;
44 | import java.io.InputStreamReader;
45 | import java.io.LineNumberReader;
46 | import java.lang.reflect.Method;
47 | import java.util.ArrayList;
48 | import java.util.List;
49 | import java.util.Locale;
50 |
51 | /**
52 | * Created by ayst.shen@foxmail.com on 2016/4/6.
53 | */
54 | public class AppUtils {
55 | private final static String TAG = "AppUtils";
56 |
57 | private static final String KEY_IS_FIRST = "is_first_run";
58 |
59 | // Application version
60 | private static String mVersionName = "";
61 | private static int mVersionCode = -1;
62 |
63 | // Firmware version
64 | private static String mFwVersion = "";
65 |
66 | // MAC
67 | private static String mEth0Mac = "";
68 | private static String mWifiMac = "";
69 | private static String mMac = "";
70 | private static String mMacNoColon = "";
71 |
72 | // Screen
73 | private static int mScreenWidth = -1;
74 | private static int mScreenHeight = -1;
75 |
76 | // Storage
77 | private static String sRootDir = "";
78 |
79 | // Device id
80 | private static String sDeviceId = "";
81 |
82 | /**
83 | * Is first run
84 | *
85 | * @param context Context
86 | * @return true: First run, false: Not the first time
87 | */
88 | public static boolean isFirstRun(Context context) {
89 | boolean isFirst = SPUtils.getInstance(context).getData(KEY_IS_FIRST, true);
90 | if (isFirst) {
91 | SPUtils.getInstance(context).saveData(KEY_IS_FIRST, false);
92 | }
93 | return isFirst;
94 | }
95 |
96 | /**
97 | * Get application version name
98 | *
99 | * @param context Context
100 | * @return version name
101 | */
102 | public static String getVersionName(Context context) {
103 | if (TextUtils.isEmpty(mVersionName)) {
104 | try {
105 | PackageInfo info = context.getPackageManager().getPackageInfo(
106 | context.getPackageName(), 0);
107 | mVersionName = info.versionName;
108 | mVersionCode = info.versionCode;
109 | } catch (PackageManager.NameNotFoundException e) {
110 | e.printStackTrace();
111 | }
112 | }
113 | return mVersionName;
114 | }
115 |
116 | /**
117 | * Get application version code
118 | *
119 | * @param context Context
120 | * @return version code
121 | */
122 | public static int getVersionCode(Context context) {
123 | if (-1 == mVersionCode) {
124 | try {
125 | PackageInfo info = context.getPackageManager().getPackageInfo(
126 | context.getPackageName(), 0);
127 | mVersionName = info.versionName;
128 | mVersionCode = info.versionCode;
129 | } catch (PackageManager.NameNotFoundException e) {
130 | e.printStackTrace();
131 | }
132 | }
133 | return mVersionCode;
134 | }
135 |
136 | /**
137 | * Get firmware version
138 | *
139 | * @return version
140 | */
141 | public static String getFwVersion() {
142 | if (TextUtils.isEmpty(mFwVersion)) {
143 | mFwVersion = getProperty("ro.fw.version",
144 | getProperty("ro.topband.sw.version", "1.0.0"));
145 | }
146 | return mFwVersion;
147 | }
148 |
149 | /**
150 | * Get serial number
151 | *
152 | * @return serial number
153 | */
154 | @SuppressLint("HardwareIds")
155 | public static String getSerialNo() {
156 | String sn = android.os.Build.SERIAL;
157 | if (TextUtils.isEmpty(sn)) {
158 | sn = getProperty("ro.serialno", "");
159 | if (TextUtils.isEmpty(sn)) {
160 | sn = getProperty("ro.boot.serialno", "");
161 | if (TextUtils.isEmpty(sn)) {
162 | sn = getCPUSerial();
163 | }
164 | }
165 | }
166 |
167 | return sn;
168 | }
169 |
170 | /**
171 | * Get cpu serial
172 | *
173 | * @return success: cpu serial, failed: "0000000000000000"
174 | */
175 | public static String getCPUSerial() {
176 | String cpuAddress = "0000000000000000";
177 |
178 | try {
179 | Process process = Runtime.getRuntime().exec("cat /proc/cpuinfo");
180 | InputStreamReader is = new InputStreamReader(process.getInputStream());
181 | LineNumberReader input = new LineNumberReader(is);
182 |
183 | String str;
184 | while ((str = input.readLine()) != null) {
185 | if (!TextUtils.isEmpty(str)) {
186 | if (str.contains("Serial")) {
187 | String cpuStr = str.substring(str.indexOf(":") + 1);
188 | cpuAddress = cpuStr.trim();
189 | break;
190 | }
191 | }
192 | }
193 | } catch (IOException e) {
194 | Log.e(TAG, "getCPUSerial, " + e.getMessage());
195 | }
196 |
197 | return cpuAddress;
198 | }
199 |
200 | /**
201 | * Get device id
202 | *
203 | * @return device id
204 | */
205 | public static String getDeviceId() {
206 | if (TextUtils.isEmpty(sDeviceId)) {
207 | sDeviceId = getSerialNo();
208 | }
209 |
210 | return sDeviceId;
211 | }
212 |
213 | /**
214 | * Get current country
215 | *
216 | * @return country
217 | */
218 | public static String getCountry() {
219 | return Locale.getDefault().getCountry();
220 | }
221 |
222 | /**
223 | * Get current language
224 | *
225 | * @return language
226 | */
227 | public static String getLanguage() {
228 | return Locale.getDefault().getLanguage();
229 | }
230 |
231 | /**
232 | * Whether the network is connected
233 | *
234 | * @param context Context
235 | * @return true: connected, false: disconnected
236 | */
237 | public static boolean isConnNetWork(Context context) {
238 | ConnectivityManager conManager = (ConnectivityManager) context.
239 | getSystemService(Context.CONNECTIVITY_SERVICE);
240 | NetworkInfo networkInfo = conManager.getActiveNetworkInfo();
241 | return ((networkInfo != null) && networkInfo.isConnected());
242 | }
243 |
244 | /**
245 | * Whether WiFi is connected
246 | *
247 | * @param context Context
248 | * @return true: connected, false: disconnected
249 | */
250 | public static boolean isWifiConnected(Context context) {
251 | ConnectivityManager conManager = (ConnectivityManager) context.
252 | getSystemService(Context.CONNECTIVITY_SERVICE);
253 | NetworkInfo wifiNetworkInfo = conManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
254 | return ((wifiNetworkInfo != null) && wifiNetworkInfo.isConnected());
255 | }
256 |
257 | /**
258 | * Get Ethernet MAC
259 | *
260 | * @param context Context
261 | * @return Mac
262 | */
263 | public static String getEth0Mac(Context context) {
264 | if (TextUtils.isEmpty(mEth0Mac)) {
265 | try {
266 | int numRead = 0;
267 | char[] buf = new char[1024];
268 | StringBuffer strBuf = new StringBuffer(1000);
269 | BufferedReader reader = new BufferedReader(new FileReader(
270 | "/sys/class/net/eth0/address"));
271 | while ((numRead = reader.read(buf)) != -1) {
272 | String readData = String.valueOf(buf, 0, numRead);
273 | strBuf.append(readData);
274 | }
275 | mEth0Mac = strBuf.toString().replaceAll("\r|\n", "");
276 | reader.close();
277 | } catch (IOException ex) {
278 | Log.w(TAG, "eth0 mac not exist");
279 | }
280 | }
281 | return mEth0Mac;
282 | }
283 |
284 | /**
285 | * Get WiFi MAC
286 | *
287 | * @param context Context
288 | * @return Mac
289 | */
290 | @SuppressLint("HardwareIds")
291 | public static String getWifiMac(Context context) {
292 | if (TextUtils.isEmpty(mWifiMac)) {
293 | WifiManager wifiManager = (WifiManager) context.getApplicationContext()
294 | .getSystemService(Context.WIFI_SERVICE);
295 | WifiInfo wifiInfo = wifiManager.getConnectionInfo();
296 | mWifiMac = wifiInfo.getMacAddress();
297 | }
298 | return mWifiMac;
299 | }
300 |
301 | /**
302 | * Get MAC, get the Ethernet MAC first, then get the WiFi MAC if it is empty.
303 | *
304 | * @param context Context
305 | * @return Mac
306 | */
307 | public static String getMac(Context context) {
308 | if (TextUtils.isEmpty(mMac)) {
309 | mMac = getEth0Mac(context);
310 | if (TextUtils.isEmpty(mMac)) {
311 | mMac = getWifiMac(context);
312 | }
313 | }
314 | return mMac;
315 | }
316 |
317 | /**
318 | * Get the MAC with the colon removed
319 | *
320 | * @param context Context
321 | * @return Mac
322 | */
323 | public static String getMacNoColon(Context context) {
324 | if (TextUtils.isEmpty(mMacNoColon)) {
325 | String mac = getMac(context);
326 | if (!TextUtils.isEmpty(mac)) {
327 | mMacNoColon = mac.replace(":", "");
328 | }
329 | }
330 | return mMacNoColon;
331 | }
332 |
333 | /**
334 | * Get screen width
335 | *
336 | * @param context Activity
337 | * @return screen width
338 | */
339 | public static int getScreenWidth(Activity context) {
340 | if (-1 == mScreenWidth) {
341 | mScreenWidth = context.getWindowManager().getDefaultDisplay().getWidth();
342 | }
343 | return mScreenWidth;
344 | }
345 |
346 | /**
347 | * Get screen height
348 | *
349 | * @param context Activity
350 | * @return screen height
351 | */
352 | public static int getScreenHeight(Activity context) {
353 | if (-1 == mScreenHeight) {
354 | mScreenHeight = context.getWindowManager().getDefaultDisplay().getHeight();
355 | }
356 | return mScreenHeight;
357 | }
358 |
359 | /**
360 | * Get property
361 | *
362 | * @param key property key
363 | * @param defaultValue default value
364 | * @return property value
365 | */
366 | @SuppressLint("PrivateApi")
367 | public static String getProperty(String key, String defaultValue) {
368 | String value = defaultValue;
369 | try {
370 | Class> c = Class.forName("android.os.SystemProperties");
371 | Method get = c.getMethod("get", String.class, String.class);
372 | value = (String) (get.invoke(c, key, defaultValue));
373 | } catch (Exception e) {
374 | e.printStackTrace();
375 | }
376 |
377 | return value;
378 | }
379 |
380 | /**
381 | * Set property
382 | *
383 | * @param key property key
384 | * @param value property value
385 | */
386 | @SuppressLint("PrivateApi")
387 | public static void setProperty(String key, String value) {
388 | try {
389 | Class> c = Class.forName("android.os.SystemProperties");
390 | Method set = c.getMethod("set", String.class, String.class);
391 | set.invoke(c, key, value);
392 | } catch (Exception e) {
393 | e.printStackTrace();
394 | }
395 | }
396 |
397 | private static boolean isExternalStorageMounted() {
398 | return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
399 | }
400 |
401 | /**
402 | * /storage/emulated/0/"packagename"
403 | *
404 | * @param context Context
405 | * @return path
406 | */
407 | public static String getExternalRootDir(Context context) {
408 | if (sRootDir.isEmpty()) {
409 | File sdcardDir = null;
410 | try {
411 | if (isExternalStorageMounted()) {
412 | sdcardDir = Environment.getExternalStorageDirectory();
413 | Log.i(TAG, "Environment.MEDIA_MOUNTED :" + sdcardDir.getAbsolutePath()
414 | + " R:" + sdcardDir.canRead() + " W:" + sdcardDir.canWrite());
415 |
416 | if (sdcardDir.canWrite()) {
417 | String dir = sdcardDir.getAbsolutePath() + File.separator + context.getPackageName();
418 | File file = new File(dir);
419 | if (!file.exists()) {
420 | Log.i(TAG, "getExternalRootDir, dir not exist and make dir");
421 | file.mkdirs();
422 | }
423 | sRootDir = dir;
424 | return sRootDir;
425 | }
426 | }
427 | } catch (Exception e) {
428 | e.printStackTrace();
429 | }
430 | }
431 | return sRootDir;
432 | }
433 |
434 | /**
435 | * /storage/emulated/0/"packagename"/"dirName"
436 | *
437 | * @param context Context
438 | * @param dirName relative path
439 | * @return full path
440 | */
441 | public static String getExternalDir(Context context, String dirName) {
442 | String dir = getExternalRootDir(context) + File.separator + dirName;
443 | File file = new File(dir);
444 | if (!file.exists()) {
445 | Log.i(TAG, "getDir, dir not exist and make dir");
446 | file.mkdirs();
447 | }
448 | return dir;
449 | }
450 |
451 | /**
452 | * /storage/emulated/0/Android/data/"packagename"/cache/"dirName"
453 | *
454 | * @param context Context
455 | * @param dirName relative path
456 | * @return full path
457 | */
458 | public static String getExternalCacheDir(Context context, String dirName) {
459 | String dir = "";
460 | if (isExternalStorageMounted()) {
461 | dir = context.getExternalCacheDir().getAbsolutePath() + File.separator + dirName;
462 | File file = new File(dir);
463 | if (!file.exists()) {
464 | Log.i(TAG, "getExternalCacheDir, dir not exist and make dir");
465 | file.mkdirs();
466 | }
467 | }
468 | return dir;
469 | }
470 |
471 | /**
472 | * /data/user/0/"packagename"/cache/"dirName"
473 | *
474 | * @param context Context
475 | * @param dirName relative path
476 | * @return full path
477 | */
478 | public static String getCacheDir(Context context, String dirName) {
479 | String dir = context.getCacheDir().getAbsolutePath() + File.separator + dirName;
480 | File file = new File(dir);
481 | if (!file.exists()) {
482 | Log.i(TAG, "getCacheDir, dir not exist and make dir");
483 | file.mkdirs();
484 | }
485 | return dir;
486 | }
487 |
488 | /**
489 | * Get all external storage paths
490 | *
491 | * @param context context
492 | * @return storage paths
493 | */
494 | public static List getStorageList(Context context) {
495 | List paths;
496 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
497 | paths = getStorageVolumeList(context);
498 | } else {
499 | paths = getMountPathList();
500 | }
501 |
502 | if (paths.isEmpty() && isExternalStorageMounted()) {
503 | paths.add(Environment.getExternalStorageDirectory()
504 | .getAbsolutePath());
505 | }
506 | return paths;
507 | }
508 |
509 | /**
510 | * Get all external storage paths, for lower than Android N
511 | *
512 | * @return storage paths
513 | */
514 | private static List getMountPathList() {
515 | List paths = new ArrayList();
516 |
517 | try {
518 | Process p = Runtime.getRuntime().exec("cat /proc/mounts");
519 | BufferedInputStream inputStream = new BufferedInputStream(p.getInputStream());
520 | BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
521 |
522 | String line;
523 | while ((line = bufferedReader.readLine()) != null) {
524 | Log.i(TAG, "getMountPathList, " + line);
525 |
526 | // /data/media /storage/emulated/0 sdcardfs rw,nosuid,nodev,relatime,uid=1023,gid=1023 0 0
527 | String[] temp = TextUtils.split(line, " ");
528 | String result = temp[1];
529 | File file = new File(result);
530 | if (file.isDirectory() && file.canRead() && file.canWrite()) {
531 | Log.d(TAG, "getMountPathList, add --> " + file.getAbsolutePath());
532 | paths.add(result);
533 | }
534 |
535 | if (p.waitFor() != 0 && p.exitValue() == 1) {
536 | Log.e(TAG, "getMountPathList, cmd execute failed!");
537 | }
538 | }
539 | bufferedReader.close();
540 | inputStream.close();
541 |
542 | } catch (Exception e) {
543 | Log.e(TAG, "getMountPathList, failed, " + e.toString());
544 | }
545 |
546 | return paths;
547 | }
548 |
549 | /**
550 | * Get all external storage paths, for higher than Android N
551 | *
552 | * @param context context
553 | * @return storage paths
554 | */
555 | @RequiresApi(api = Build.VERSION_CODES.N)
556 | private static List getStorageVolumeList(Context context) {
557 | List paths = new ArrayList();
558 | StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
559 | List volumes = storageManager.getStorageVolumes();
560 |
561 | try {
562 | Class> storageVolumeClazz = Class.forName("android.os.storage.StorageVolume");
563 | Method getPath = storageVolumeClazz.getMethod("getPath");
564 | Method isRemovable = storageVolumeClazz.getMethod("isRemovable");
565 |
566 | for (StorageVolume storageVolume : volumes) {
567 | String storagePath = (String) getPath.invoke(storageVolume);
568 | boolean isRemovableResult = (boolean) isRemovable.invoke(storageVolume);
569 | String description = storageVolume.getDescription(context);
570 | paths.add(storagePath);
571 |
572 | Log.d(TAG, "getStorageVolumeList, storagePath=" + storagePath
573 | + ", isRemovableResult=" + isRemovableResult + ", description=" + description);
574 | }
575 | } catch (Exception e) {
576 | Log.e(TAG, "getStorageVolumeList, failed, " + e);
577 | }
578 |
579 | return paths;
580 | }
581 |
582 | /**
583 | * reboot
584 | *
585 | * @param context Context
586 | */
587 | public static void reboot(Context context) {
588 | Intent intent = new Intent(Intent.ACTION_REBOOT);
589 | intent.putExtra("nowait", 1);
590 | intent.putExtra("interval", 1);
591 | intent.putExtra("window", 0);
592 | context.sendBroadcast(intent);
593 | }
594 |
595 | /**
596 | * shutdown
597 | *
598 | * @param context Context
599 | */
600 | public static void shutdown(Context context) {
601 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
602 | Intent intent = new Intent("com.android.internal.intent.action.REQUEST_SHUTDOWN");
603 | intent.putExtra("android.intent.extra.KEY_CONFIRM", false);
604 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
605 | context.startActivity(intent);
606 | } else {
607 | Intent intent = new Intent("android.intent.action.ACTION_REQUEST_SHUTDOWN");
608 | intent.putExtra("android.intent.extra.KEY_CONFIRM", false);
609 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
610 | context.startActivity(intent);
611 | }
612 | }
613 |
614 | /**
615 | * start app
616 | *
617 | * @param context Context
618 | * @param packageName PackageName
619 | */
620 | public static void startApp(@NonNull Context context, @NonNull String packageName) {
621 | Intent intent = context.getPackageManager()
622 | .getLaunchIntentForPackage(packageName);
623 | if (intent != null) {
624 | context.startActivity(intent);
625 | } else {
626 | Log.e(TAG, "startApp, Package does not exist.");
627 | }
628 | }
629 | }
630 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ayst/romupgrade/util/DataEncryptUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright(c) 2020 Bob Shen
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.ayst.romupgrade.util;
18 |
19 | import android.text.TextUtils;
20 | import android.util.Log;
21 |
22 | import com.google.gson.Gson;
23 | import org.json.JSONObject;
24 |
25 | /**
26 | * Created by ayst.shen@foxmail.com on 2017/12/12.
27 | */
28 | public class DataEncryptUtil {
29 | private static final String TAG = "DataEncryptUtil";
30 | private static Gson gson = new Gson();
31 |
32 | public static String encryptData(T value, String key) {
33 | if (value == null) {
34 | Log.e(TAG, "encryptData, value is null");
35 | return "";
36 | }
37 | try {
38 | JSONObject json = new JSONObject(gson.toJson(value));
39 | Log.d(TAG, "encryptData, request data: " + json.toString());
40 | return EncryptUtil.encryptAES(key, json.toString());
41 | } catch (Exception e) {
42 | Log.e(TAG, "encryptData, " + e.getMessage());
43 | }
44 | return "";
45 | }
46 |
47 | public static T decryptData(String value, Class tClass, String key) {
48 | if (!TextUtils.isEmpty(value)) {
49 | try {
50 | String decryptString = EncryptUtil.decryptAES(key, value);
51 | if (!TextUtils.isEmpty(decryptString)) {
52 | return gson.fromJson(decryptString, tClass);
53 | }
54 | } catch (Exception e) {
55 | Log.e(TAG, "decryptData, " + e.getMessage());
56 | }
57 | }
58 | return null;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ayst/romupgrade/util/EncryptUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright(c) 2020 Bob Shen
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.ayst.romupgrade.util;
18 |
19 | import android.annotation.SuppressLint;
20 |
21 | import java.math.BigInteger;
22 | import java.nio.charset.StandardCharsets;
23 | import java.security.MessageDigest;
24 | import java.security.NoSuchAlgorithmException;
25 |
26 | import javax.crypto.Cipher;
27 | import javax.crypto.spec.SecretKeySpec;
28 |
29 | /**
30 | * Created by ayst.shen@foxmail.com on 17/8/15.
31 | */
32 | public class EncryptUtil {
33 | private static final String AES_TRANSFORMATION = "AES/ECB/PKCS5Padding";
34 | private static final String ASE_ALGORITHM = "AES";
35 | private final static String HEX = "0123456789abcdef";
36 |
37 | public static String getMD5HexMsg(String data) throws NoSuchAlgorithmException {
38 | MessageDigest md5Digest = MessageDigest.getInstance("MD5");
39 | md5Digest.update(data.getBytes());
40 | return new BigInteger(1, md5Digest.digest()).toString(16);
41 | }
42 |
43 | public static String encryptAES(String seed, String cleartext) throws Exception {
44 | byte[] rawKey = seed.getBytes(StandardCharsets.UTF_8);
45 | byte[] result = cleartext.getBytes(StandardCharsets.UTF_8);
46 | return toHex(encodeAES(rawKey, result));
47 | }
48 |
49 | public static String decryptAES(String seed, String encrypted) throws Exception {
50 | byte[] rawKey = seed.getBytes(StandardCharsets.UTF_8);
51 | byte[] enc = toByte(encrypted);
52 | byte[] result = decodeAES(rawKey, enc);
53 | return new String(result);
54 | }
55 |
56 | @SuppressLint("GetInstance")
57 | public static byte[] encodeAES(byte[] keyBytes, byte[] data) throws Exception {
58 | Cipher encodeCipher = Cipher.getInstance(AES_TRANSFORMATION);
59 | SecretKeySpec key = new SecretKeySpec(keyBytes, ASE_ALGORITHM);
60 | encodeCipher.init(Cipher.ENCRYPT_MODE, key);
61 | return encodeCipher.doFinal(data);
62 | }
63 |
64 | @SuppressLint("GetInstance")
65 | public static byte[] decodeAES(byte[] keyBytes, byte[] data) throws Exception {
66 | Cipher encodeCipher = Cipher.getInstance(AES_TRANSFORMATION);
67 | SecretKeySpec key = new SecretKeySpec(keyBytes, ASE_ALGORITHM);
68 | encodeCipher.init(Cipher.DECRYPT_MODE, key);
69 | return encodeCipher.doFinal(data);
70 | }
71 |
72 | private static String toHex(byte[] buf) {
73 | if (buf == null)
74 | return "";
75 | StringBuffer result = new StringBuffer(2 * buf.length);
76 | for (int i = 0; i < buf.length; i++) {
77 | appendHex(result, buf[i]);
78 | }
79 | return result.toString();
80 | }
81 |
82 | public static String toHex(String txt) {
83 | return toHex(txt.getBytes());
84 | }
85 |
86 | public static String fromHex(String hex) {
87 | return new String(toByte(hex));
88 | }
89 |
90 | public static byte[] toByte(String hexString) {
91 | int len = hexString.length() / 2;
92 | byte[] result = new byte[len];
93 | for (int i = 0; i < len; i++)
94 | result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2), 16).byteValue();
95 | return result;
96 | }
97 |
98 | private static void appendHex(StringBuffer sb, byte b) {
99 | sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
100 | }
101 |
102 | }
103 |
104 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ayst/romupgrade/util/FileUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright(c) 2020 Bob Shen
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.ayst.romupgrade.util;
18 |
19 | import android.content.ContentResolver;
20 | import android.content.ContentUris;
21 | import android.content.Context;
22 | import android.database.Cursor;
23 | import android.net.Uri;
24 | import android.os.Build;
25 | import android.os.Environment;
26 | import android.provider.DocumentsContract;
27 | import android.provider.MediaStore;
28 | import android.text.TextUtils;
29 |
30 | import java.io.*;
31 |
32 | /**
33 | * Created by ayst.shen@foxmail.com on 17/8/15.
34 | */
35 | public class FileUtils {
36 |
37 | /**
38 | * Write file
39 | *
40 | * @param file Write file
41 | * @param message Written content
42 | * @throws IOException
43 | */
44 | public static void writeFile(File file, String message)
45 | throws IOException {
46 |
47 | FileWriter fWriter = new FileWriter(file);
48 | try {
49 | fWriter.write(message);
50 | } finally {
51 | fWriter.close();
52 | }
53 | }
54 |
55 | /**
56 | * Read file
57 | *
58 | * @param file Read file
59 | * @return Read content
60 | * @throws IOException
61 | */
62 | public static String readFile(File file)
63 | throws IOException {
64 |
65 | FileReader fRead = new FileReader(file);
66 | try {
67 | BufferedReader buffer = new BufferedReader(fRead);
68 | StringBuilder sb = new StringBuilder();
69 | String str;
70 | while ((str = buffer.readLine()) != null) {
71 | sb.append(str);
72 | }
73 | return sb.toString();
74 | } finally {
75 | fRead.close();
76 | }
77 | }
78 |
79 | /**
80 | * Get file suffix
81 | *
82 | * @param fileName file name
83 | * @return suffix
84 | */
85 | public static String getFileSuffix(String fileName) {
86 | if (!TextUtils.isEmpty(fileName) && fileName.length() > 3) {
87 | int dot = fileName.lastIndexOf(".");
88 | if (dot > 0) {
89 | return fileName.substring(dot + 1);
90 | } else {
91 | return "";
92 | }
93 | }
94 | return "";
95 | }
96 |
97 | /**
98 | * Get the file path from uri
99 | *
100 | * @param context Context
101 | * @param uri Uri
102 | * @return File path
103 | */
104 | public static String getFilePathByUri(Context context, Uri uri) {
105 | String path = null;
106 | // Starting with file://
107 | if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {
108 | path = uri.getPath();
109 | return path;
110 | }
111 |
112 | // Starting with content://, example: content://media/extenral/images/media/17766
113 | if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())
114 | && Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
115 | Cursor cursor = context.getContentResolver().query(uri,
116 | new String[]{MediaStore.Images.Media.DATA},
117 | null, null, null);
118 | if (cursor != null) {
119 | if (cursor.moveToFirst()) {
120 | int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
121 | if (columnIndex > -1) {
122 | path = cursor.getString(columnIndex);
123 | }
124 | }
125 | cursor.close();
126 | }
127 | return path;
128 | }
129 |
130 | // Starting with content://, example: content://media/extenral/images/media/17766,
131 | // >= Build.VERSION_CODES.KITKAT
132 | if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())
133 | && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
134 | if (DocumentsContract.isDocumentUri(context, uri)) {
135 | if (isExternalStorageDocument(uri)) {
136 | // ExternalStorageProvider
137 | final String docId = DocumentsContract.getDocumentId(uri);
138 | final String[] split = docId.split(":");
139 | final String type = split[0];
140 | if ("primary".equalsIgnoreCase(type)) {
141 | path = Environment.getExternalStorageDirectory() + "/" + split[1];
142 | return path;
143 | }
144 | } else if (isDownloadsDocument(uri)) {
145 | // DownloadsProvider
146 | final String id = DocumentsContract.getDocumentId(uri);
147 | final Uri contentUri = ContentUris.withAppendedId(
148 | Uri.parse("content://downloads/public_downloads"),
149 | Long.valueOf(id));
150 | path = getDataColumn(context, contentUri, null, null);
151 | return path;
152 | } else if (isMediaDocument(uri)) {
153 | // MediaProvider
154 | final String docId = DocumentsContract.getDocumentId(uri);
155 | final String[] split = docId.split(":");
156 | final String type = split[0];
157 | Uri contentUri = null;
158 | if ("image".equals(type)) {
159 | contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
160 | } else if ("video".equals(type)) {
161 | contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
162 | } else if ("audio".equals(type)) {
163 | contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
164 | }
165 | final String selection = "_id=?";
166 | final String[] selectionArgs = new String[]{split[1]};
167 | path = getDataColumn(context, contentUri, selection, selectionArgs);
168 | return path;
169 | }
170 | }
171 | }
172 | return null;
173 | }
174 |
175 | private static String getDataColumn(Context context, Uri uri, String selection,
176 | String[] selectionArgs) {
177 | Cursor cursor = null;
178 | final String column = "_data";
179 | final String[] projection = {column};
180 | try {
181 | cursor = context.getContentResolver().query(uri, projection, selection,
182 | selectionArgs, null);
183 | if (cursor != null && cursor.moveToFirst()) {
184 | final int column_index = cursor.getColumnIndexOrThrow(column);
185 | return cursor.getString(column_index);
186 | }
187 | } finally {
188 | if (cursor != null)
189 | cursor.close();
190 | }
191 | return null;
192 | }
193 |
194 | private static boolean isExternalStorageDocument(Uri uri) {
195 | return "com.android.externalstorage.documents".equals(uri.getAuthority());
196 | }
197 |
198 | private static boolean isDownloadsDocument(Uri uri) {
199 | return "com.android.providers.downloads.documents".equals(uri.getAuthority());
200 | }
201 |
202 | private static boolean isMediaDocument(Uri uri) {
203 | return "com.android.providers.media.documents".equals(uri.getAuthority());
204 | }
205 | }
206 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ayst/romupgrade/util/InstallUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright(c) 2020 Bob Shen
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.ayst.romupgrade.util;
18 |
19 | import android.app.AlertDialog;
20 | import android.app.Dialog;
21 | import android.content.Context;
22 | import android.content.DialogInterface;
23 | import android.content.Intent;
24 | import android.net.Uri;
25 | import android.os.Build;
26 | import android.provider.Settings;
27 | import android.util.Log;
28 | import android.view.WindowManager;
29 |
30 | import androidx.annotation.RequiresApi;
31 | import androidx.core.content.FileProvider;
32 |
33 | import com.ayst.romupgrade.R;
34 |
35 | import java.io.BufferedReader;
36 | import java.io.DataOutputStream;
37 | import java.io.File;
38 | import java.io.IOException;
39 | import java.io.InputStreamReader;
40 | import java.nio.charset.Charset;
41 |
42 | public class InstallUtil {
43 | private static final String TAG = "InstallUtil";
44 | private static final String AUTHORITY = "com.ayst.romupgrade.fileProvider";
45 |
46 | private static final String EXTRA_SILENT_INSTALL = "silent_install";
47 |
48 | public static void install(Context context, String path) {
49 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
50 | installO(context, path);
51 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
52 | installN(context, path);
53 | } else {
54 | installOther(context, path);
55 | }
56 | }
57 |
58 | /**
59 | * android1.x-6.x
60 | *
61 | * @param context Context
62 | * @param path Package
63 | */
64 | private static void installOther(Context context, String path) {
65 | Intent install = new Intent(Intent.ACTION_VIEW);
66 | install.setDataAndType(Uri.parse("file://" + path),
67 | "application/vnd.android.package-archive");
68 | install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
69 | install.putExtra(EXTRA_SILENT_INSTALL, true); // 静默安装
70 | context.startActivity(install);
71 | }
72 |
73 | /**
74 | * android7.x
75 | *
76 | * @param context Context
77 | * @param path Package
78 | */
79 | private static void installN(Context context, String path) {
80 | Uri apkUri = FileProvider.getUriForFile(context, AUTHORITY, new File(path));
81 | Intent install = new Intent(Intent.ACTION_VIEW);
82 | install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
83 | install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
84 | install.setDataAndType(apkUri, "application/vnd.android.package-archive");
85 | install.putExtra(EXTRA_SILENT_INSTALL, true); // 静默安装
86 | context.startActivity(install);
87 | }
88 |
89 | /**
90 | * android8.x
91 | *
92 | * @param context Context
93 | * @param path Package
94 | */
95 | @RequiresApi(api = Build.VERSION_CODES.O)
96 | private static void installO(Context context, String path) {
97 | boolean isGranted = context.getPackageManager().canRequestPackageInstalls();
98 | if (isGranted) {
99 | installN(context, path);
100 | } else {
101 | Dialog dialog = new AlertDialog.Builder(context.getApplicationContext())
102 | .setTitle(R.string.upgrade_unknown_sources_package)
103 | .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
104 | public void onClick(DialogInterface d, int w) {
105 | Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
106 | context.startActivity(intent);
107 | }
108 | }).create();
109 | dialog.setCancelable(false);
110 | dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
111 | dialog.show();
112 | }
113 | }
114 |
115 | /**
116 | * Silent install
117 | *
118 | * @param path Package
119 | * @return true: success false: failed
120 | */
121 | public static boolean installSilent(String path) {
122 | boolean result = false;
123 | BufferedReader es = null;
124 | DataOutputStream os = null;
125 |
126 | try {
127 | Process process = Runtime.getRuntime().exec("su");
128 | os = new DataOutputStream(process.getOutputStream());
129 |
130 | String command = "pm install -r " + path + "\n";
131 | os.write(command.getBytes(Charset.forName("utf-8")));
132 | os.flush();
133 | os.writeBytes("exit\n");
134 | os.flush();
135 |
136 | process.waitFor();
137 | es = new BufferedReader(new InputStreamReader(process.getErrorStream()));
138 |
139 | String line;
140 | StringBuilder builder = new StringBuilder();
141 | while ((line = es.readLine()) != null) {
142 | builder.append(line);
143 | }
144 | Log.d(TAG, "install msg is " + builder.toString());
145 |
146 | /* Installation is considered a Failure if the result contains
147 | the Failure character, or a success if it is not.
148 | */
149 | if (!builder.toString().contains("Failure")) {
150 | result = true;
151 | }
152 | } catch (Exception e) {
153 | Log.e(TAG, e.getMessage(), e);
154 | } finally {
155 | try {
156 | if (os != null) {
157 | os.close();
158 | }
159 | if (es != null) {
160 | es.close();
161 | }
162 | } catch (IOException e) {
163 | Log.e(TAG, e.getMessage(), e);
164 | }
165 | }
166 |
167 | return result;
168 | }
169 | }
170 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ayst/romupgrade/util/MD5.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright(c) 2020 Bob Shen
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.ayst.romupgrade.util;
18 |
19 | import java.io.FileInputStream;
20 | import java.io.IOException;
21 | import java.io.InputStream;
22 | import java.io.UnsupportedEncodingException;
23 | import java.security.MessageDigest;
24 | import java.security.NoSuchAlgorithmException;
25 |
26 | import android.util.Log;
27 |
28 | /**
29 | * Created by ayst.shen@foxmail.com on 17/8/15.
30 | */
31 | public class MD5 {
32 |
33 | private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
34 | 'A', 'B', 'C', 'D', 'E', 'F'};
35 |
36 | public static String toHexString(byte[] b) {
37 | StringBuilder sb = new StringBuilder(b.length * 2);
38 | for (int i = 0; i < b.length; i++) {
39 | sb.append(HEX_DIGITS[(b[i] & 0xf0) >>> 4]);
40 | sb.append(HEX_DIGITS[b[i] & 0x0f]);
41 | }
42 | return sb.toString();
43 | }
44 |
45 | public static String md5ForFile(String filename) {
46 | InputStream fis = null;
47 | byte[] buffer = new byte[1024];
48 | int numRead = 0;
49 | MessageDigest md5;
50 | try{
51 | fis = new FileInputStream(filename);
52 | md5 = MessageDigest.getInstance("MD5");
53 | long total = 0;
54 | while((numRead=fis.read(buffer)) > 0) {
55 | md5.update(buffer,0,numRead);
56 | total+=numRead;
57 | }
58 | Log.d("MD5", "md5sum.total="+total);
59 | fis.close();
60 | return toHexString(md5.digest());
61 | } catch (Exception e) {
62 | Log.e("MD5", "md5sum.exception="+e.getMessage());
63 | if (fis != null) {
64 | try {
65 | fis.close();
66 | } catch (IOException e1) {
67 | e1.printStackTrace();
68 | }
69 | }
70 | return null;
71 | }
72 | }
73 |
74 | public static String md5ForString(String string) {
75 | byte[] hash;
76 | try {
77 | hash = MessageDigest.getInstance("MD5").digest(
78 | string.getBytes("UTF-8"));
79 | } catch (NoSuchAlgorithmException e) {
80 | throw new RuntimeException("Huh, MD5 should be supported?", e);
81 | } catch (UnsupportedEncodingException e) {
82 | throw new RuntimeException("Huh, UTF-8 should be supported?", e);
83 | }
84 |
85 | StringBuilder hex = new StringBuilder(hash.length * 2);
86 | for (byte b : hash) {
87 | if ((b & 0xFF) < 0x10) {
88 | hex.append("0");
89 | }
90 | hex.append(Integer.toHexString(b & 0xFF));
91 | }
92 | return hex.toString();
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ayst/romupgrade/util/SPUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright(c) 2020 Bob Shen
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.ayst.romupgrade.util;
18 |
19 |
20 | import android.content.Context;
21 | import android.content.SharedPreferences;
22 | import android.content.SharedPreferences.Editor;
23 |
24 | /**
25 | * Created by ayst.shen@foxmail.com on 17/8/15.
26 | */
27 | public class SPUtils {
28 | private static final String SP = "auto_upgrade";
29 |
30 | private static SPUtils instance;
31 | private static SharedPreferences mSp = null;
32 |
33 | private SPUtils(Context context) {
34 | mSp = context.getSharedPreferences(SP, Context.MODE_PRIVATE);
35 | }
36 |
37 | public static SPUtils getInstance(Context context) {
38 | if (instance == null)
39 | instance = new SPUtils(context);
40 | return instance;
41 | }
42 |
43 | /**
44 | * Save data
45 | *
46 | * @param key preference key
47 | * @param value preference value
48 | */
49 | public void saveData(String key, String value) {
50 | Editor editor = mSp.edit();
51 | editor.putString(key, value);
52 | editor.apply();
53 | }
54 |
55 | /**
56 | * Save data
57 | *
58 | * @param key preference key
59 | * @param value preference value
60 | */
61 | public void saveData(String key, boolean value) {
62 | Editor editor = mSp.edit();
63 | editor.putBoolean(key, value);
64 | editor.apply();
65 | }
66 |
67 | /**
68 | * Save data
69 | *
70 | * @param key preference key
71 | * @param value preference value
72 | */
73 | public void saveData(String key, int value) {
74 | Editor editor = mSp.edit();
75 | editor.putInt(key, value);
76 | editor.apply();
77 | }
78 |
79 | /**
80 | * Save data
81 | *
82 | * @param key preference key
83 | * @param value preference value
84 | */
85 | public void saveData(String key, float value) {
86 | Editor editor = mSp.edit();
87 | editor.putFloat(key, value);
88 | editor.apply();
89 | }
90 |
91 | /**
92 | * Get data
93 | *
94 | * @param key preference key
95 | * @param defValue default value
96 | * @return value
97 | */
98 | public String getData(String key, String defValue) {
99 | return mSp.getString(key, defValue);
100 | }
101 |
102 | /**
103 | * Get data
104 | *
105 | * @param key preference key
106 | * @param defValue default value
107 | * @return value
108 | */
109 | public boolean getData(String key, boolean defValue) {
110 | return mSp.getBoolean(key, defValue);
111 | }
112 |
113 | /**
114 | * Get data
115 | *
116 | * @param key preference key
117 | * @param defValue default value
118 | * @return value
119 | */
120 | public int getData(String key, int defValue) {
121 | return mSp.getInt(key, defValue);
122 | }
123 |
124 | /**
125 | * Get data
126 | *
127 | * @param key preference key
128 | * @param defValue default value
129 | * @return value
130 | */
131 | public float getData(String key, float defValue) {
132 | return mSp.getFloat(key, defValue);
133 | }
134 |
135 | }
136 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ayst/romupgrade/util/filecopy/FileCopyTask.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright(c) 2020 Bob Shen
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.ayst.romupgrade.util.filecopy;
18 |
19 | import android.content.Context;
20 | import android.os.AsyncTask;
21 | import android.util.Log;
22 |
23 | import androidx.documentfile.provider.DocumentFile;
24 |
25 | import java.io.IOException;
26 | import java.io.InputStream;
27 | import java.io.OutputStream;
28 | import java.lang.ref.WeakReference;
29 |
30 | /**
31 | * Asynchronous task to copy a file.
32 | *
33 | * @author ayst.shen@foxmail.com
34 | */
35 | public class FileCopyTask extends AsyncTask {
36 | private static final String TAG = "FileCopyTask";
37 |
38 | private WeakReference mWeakContext;
39 | private FileCopyTaskParam mParam;
40 |
41 | public FileCopyTask(Context context) {
42 | mWeakContext = new WeakReference<>(context);
43 | }
44 |
45 | @Override
46 | protected void onPreExecute() {
47 | }
48 |
49 | private void copyFile(DocumentFile from, DocumentFile to) throws Exception {
50 | long size = from.length();
51 |
52 | if (mWeakContext.get() != null) {
53 | InputStream inputStream = mWeakContext.get().getContentResolver().openInputStream(from.getUri());
54 | OutputStream outputStream = mWeakContext.get().getContentResolver().openOutputStream(to.getUri());
55 |
56 | if (null != inputStream && null != outputStream) {
57 | byte[] bytes = new byte[1024];
58 | int count;
59 | long total = 0;
60 |
61 | while ((count = inputStream.read(bytes)) != -1) {
62 | outputStream.write(bytes, 0, count);
63 | if (size > 0) {
64 | total += count;
65 | publishProgress((int) (total * 100 / size));
66 | }
67 | }
68 |
69 | outputStream.close();
70 | inputStream.close();
71 | } else {
72 | throw new IOException("InputStream or OutputStream is null");
73 | }
74 | } else {
75 | throw new Exception("Context is null");
76 | }
77 | }
78 |
79 | @Override
80 | protected Void doInBackground(FileCopyTaskParam... params) {
81 | long time = System.currentTimeMillis();
82 | mParam = params[0];
83 | try {
84 | copyFile(DocumentFile.fromFile(mParam.from), DocumentFile.fromFile(mParam.to));
85 | } catch (Exception e) {
86 | Log.e(TAG, "could not copy file, e: ", e);
87 | if (null != mParam.listener) {
88 | mParam.listener.error(e);
89 | }
90 | }
91 |
92 | Log.i(TAG, "copy time: " + (System.currentTimeMillis() - time));
93 | return null;
94 | }
95 |
96 | @Override
97 | protected void onPostExecute(Void result) {
98 | if (null != mParam.listener) {
99 | mParam.listener.completed(mParam.to);
100 | }
101 | }
102 |
103 | @Override
104 | protected void onProgressUpdate(Integer... values) {
105 | if (null != mParam.listener) {
106 | mParam.listener.progress(values[0]);
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ayst/romupgrade/util/filecopy/FileCopyTaskParam.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright(c) 2020 Bob Shen
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.ayst.romupgrade.util.filecopy;
18 |
19 | import java.io.File;
20 |
21 | /**
22 | * Class to hold the files for a copy task. Holds the source and the
23 | * destination file.
24 | *
25 | * @author ayst.shen@foxmail.com
26 | *
27 | */
28 | public class FileCopyTaskParam {
29 | public File from;
30 | public File to;
31 | public IFileCopyListener listener;
32 | }
33 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ayst/romupgrade/util/filecopy/IFileCopyListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright(c) 2020 Bob Shen
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.ayst.romupgrade.util.filecopy;
18 |
19 | public interface IFileCopyListener {
20 | public void progress(int progress);
21 | public void completed(T file);
22 | public void error(Exception e);
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
23 |
28 |
29 |
35 |
38 |
41 |
42 |
43 |
44 |
50 |
51 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_default_disable.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
20 |
21 |
23 |
24 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_default_normal.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
20 |
21 |
23 |
24 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_default_pressed.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
20 |
21 |
23 |
24 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_default_selected.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
20 |
21 |
23 |
24 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_default_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_default_text_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
23 |
26 |
31 |
36 |
41 |
46 |
51 |
56 |
61 |
66 |
71 |
76 |
81 |
86 |
91 |
96 |
101 |
106 |
111 |
116 |
121 |
126 |
131 |
136 |
141 |
146 |
151 |
156 |
161 |
166 |
171 |
176 |
181 |
186 |
187 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_download.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
23 |
24 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_download_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
22 |
23 |
29 |
30 |
37 |
38 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aystshen/Android-RomUpgrade/01ccdc2301286af214ae9c075f54107c9a90a938/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aystshen/Android-RomUpgrade/01ccdc2301286af214ae9c075f54107c9a90a938/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aystshen/Android-RomUpgrade/01ccdc2301286af214ae9c075f54107c9a90a938/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aystshen/Android-RomUpgrade/01ccdc2301286af214ae9c075f54107c9a90a938/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aystshen/Android-RomUpgrade/01ccdc2301286af214ae9c075f54107c9a90a938/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aystshen/Android-RomUpgrade/01ccdc2301286af214ae9c075f54107c9a90a938/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aystshen/Android-RomUpgrade/01ccdc2301286af214ae9c075f54107c9a90a938/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aystshen/Android-RomUpgrade/01ccdc2301286af214ae9c075f54107c9a90a938/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aystshen/Android-RomUpgrade/01ccdc2301286af214ae9c075f54107c9a90a938/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aystshen/Android-RomUpgrade/01ccdc2301286af214ae9c075f54107c9a90a938/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values-zh/strings.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 | "升级"
19 | "隐藏"
20 | "取消"
21 | "重试"
22 | "确认"
23 | "删除"
24 | "确定"
25 |
26 | "升级"
27 | "下载"
28 | "立即升级"
29 | "暂不升级"
30 | "发现新版本,是否升级?\n"
31 | "升级成功!"
32 | "升级失败!"
33 | "准备安装:"
34 | "安装成功!"
35 | "安装失败!"
36 | "验证失败!"
37 | "安装应用需要打开未知来源权限,请去设置中开启权限!"
38 | "升级包版本小于等于当前系统版本,将不会被升级!"
39 |
40 |
41 | "参数错误!"
42 | "网络错误!"
43 | "无更新!"
44 |
45 |
46 | "参数错误!"
47 | "网络错误!"
48 | "空间不足!"
49 | "安装app,app已安装错误!"
50 | "更新app,app未安装错误!"
51 | "更新app,版本过低错误!"
52 | "sha1校验失败!"
53 |
54 |
55 | "参数错误!"
56 | "sha1校验失败!"
57 | "签名校验失败!"
58 | "文件不存在!"
59 | "卸载app,app未安装!"
60 | "app安装错误!"
61 | "app卸载错误!"
62 | "安装自定义错误!"
63 | "用户取消升级!"
64 |
65 |
66 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | #302f57
20 | #191645
21 | #30c7ff
22 |
23 | #80191645
24 |
25 | #00000000
26 | #ffc6e578
27 |
28 | #49d452
29 | #803d9909
30 | #fffa9d3e
31 | #ffc6c6c6
32 | #80c6c6c6
33 | #ffff0000
34 | #80ff0000
35 | #ffe6615c
36 | #80e6615c
37 |
38 | #ff000000
39 | #10000000
40 | #23000000
41 | #33000000
42 | #4d000000
43 | #66000000
44 | #80000000
45 | #99000000
46 | #b3000000
47 |
48 | #ffffffff
49 | #10ffffff
50 | #23ffffff
51 | #33ffffff
52 | #4dffffff
53 | #66ffffff
54 | #80ffffff
55 | #99ffffff
56 | #b3ffffff
57 |
58 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 | 18sp
21 | 14sp
22 | 12sp
23 | 8sp
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 | Upgrade
19 | Hide
20 | Cancel
21 | Retry
22 | OK
23 | Delete
24 | OK
25 |
26 | Upgrade
27 | Download
28 | Upgrade
29 | Cancel
30 | "Found a new version, is it upgraded?\n"
31 | Upgrade success!
32 | Upgrade failed!
33 | Ready to install:
34 | install success!
35 | install failed!
36 | invalid package!
37 | To install the application, you need to open the permissions of unknown source. Please go to Settings to open the permissions!
38 | Upgrade package versions less than or equal to the current system version will not be upgraded!
39 |
40 |
41 | "param error!"
42 | "network error!"
43 | "no update!"
44 |
45 |
46 | "param error!"
47 | "network error!"
48 | "no space!"
49 | "app installed!"
50 | "app not install!"
51 | "low version!"
52 | "sha1 verify error!"
53 |
54 |
55 | "param error!"
56 | "sha1 verify error!"
57 | "sign verify error!"
58 | "file not exist!"
59 | "not installed!"
60 | "install error!"
61 | "uninstall error!"
62 | "custom error!"
63 | "user not confirm!"
64 |
65 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
26 |
27 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/file_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/system.keystore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aystshen/Android-RomUpgrade/01ccdc2301286af214ae9c075f54107c9a90a938/app/system.keystore
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | repositories {
6 | google()
7 | mavenCentral()
8 | jcenter()
9 | }
10 | dependencies {
11 | classpath 'com.android.tools.build:gradle:3.4.2'
12 |
13 |
14 | // NOTE: Do not place your application dependencies here; they belong
15 | // in the individual module build.gradle files
16 |
17 | // shenhaibo
18 | }
19 | }
20 |
21 | allprojects {
22 | repositories {
23 | google()
24 | mavenCentral()
25 | jcenter()
26 | maven {
27 | url "https://jitpack.io"
28 | }
29 | }
30 | apply from: rootDir.absolutePath + '/utils.gradle'
31 | }
32 |
33 | task clean(type: Delete) {
34 | delete rootProject.buildDir
35 | }
36 |
37 | Properties properties = new Properties()
38 | properties.load(project.rootProject.file('local.properties').newDataInputStream())
39 |
40 | ext {
41 | compileSdkVersion = 28
42 | buildToolsVersion = "28.0.3"
43 | minSdkVersion = 21
44 | targetSdkVersion = 26
45 |
46 | keyStoreAlias = properties.getProperty("keystore.alias")
47 | keyStorePath = properties.getProperty("keystore.path")
48 | keyStorePassword = properties.getProperty("keystore.store_password")
49 | keyStoreKeyPassword = properties.getProperty("keystore.key_password")
50 | }
51 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
19 | android.useAndroidX=true
20 | android.enableJetifier=true
21 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aystshen/Android-RomUpgrade/01ccdc2301286af214ae9c075f54107c9a90a938/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Sep 18 16:15:17 CST 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/screenshots/1585270225.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aystshen/Android-RomUpgrade/01ccdc2301286af214ae9c075f54107c9a90a938/screenshots/1585270225.jpg
--------------------------------------------------------------------------------
/screenshots/1585270231.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aystshen/Android-RomUpgrade/01ccdc2301286af214ae9c075f54107c9a90a938/screenshots/1585270231.jpg
--------------------------------------------------------------------------------
/screenshots/1585270300.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aystshen/Android-RomUpgrade/01ccdc2301286af214ae9c075f54107c9a90a938/screenshots/1585270300.jpg
--------------------------------------------------------------------------------
/screenshots/1585270318.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aystshen/Android-RomUpgrade/01ccdc2301286af214ae9c075f54107c9a90a938/screenshots/1585270318.jpg
--------------------------------------------------------------------------------
/screenshots/device-2020-01-18-150533.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aystshen/Android-RomUpgrade/01ccdc2301286af214ae9c075f54107c9a90a938/screenshots/device-2020-01-18-150533.png
--------------------------------------------------------------------------------
/screenshots/device-2020-01-18-150622.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aystshen/Android-RomUpgrade/01ccdc2301286af214ae9c075f54107c9a90a938/screenshots/device-2020-01-18-150622.png
--------------------------------------------------------------------------------
/screenshots/device-2020-01-18-150651.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aystshen/Android-RomUpgrade/01ccdc2301286af214ae9c075f54107c9a90a938/screenshots/device-2020-01-18-150651.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/utils.gradle:
--------------------------------------------------------------------------------
1 | //此文件申请一些公共参数
2 |
3 | ext {
4 | compileSdkVersion = 25
5 | buildToolsVersion = "25.0.2"
6 | minSdkVersion = 18
7 | targetSdkVersion = 21
8 | }
--------------------------------------------------------------------------------