Add update notification

This commit is contained in:
topjohnwu 2017-02-17 08:51:51 +08:00
parent b58c7ba7c5
commit d99252f394
16 changed files with 222 additions and 107 deletions

View File

@ -8,6 +8,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.VIBRATE" />
<application
android:name=".MagiskManager"
@ -60,7 +61,12 @@
</intent-filter>
</receiver>
<service android:name=".receivers.BootReceiver$BootupIntentService" />
<service android:name=".services.BootupIntentService" />
<service
android:name=".services.UpdateCheckService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="true" />
<provider
android:name="android.support.v4.content.FileProvider"

View File

@ -47,7 +47,7 @@ public class AboutActivity extends Activity {
super.onCreate(savedInstanceState);
String theme = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getString("theme", "");
Logger.dev("AboutActivity: Theme is " + theme);
if (getTopApplication().isDarkTheme) {
if (getApplicationContext().isDarkTheme) {
setTheme(R.style.AppTheme_Dark);
}
setContentView(R.layout.activity_about);

View File

@ -47,6 +47,7 @@ public class MagiskManager extends Application {
public boolean isSuClient = false;
public String suVersion = null;
public boolean disabled = false;
public boolean isNotified = false;
// Data
public ValueSortedMap<String, Repo> repoMap;

View File

@ -29,8 +29,11 @@ import butterknife.ButterKnife;
public class MainActivity extends Activity
implements NavigationView.OnNavigationItemSelectedListener, CallbackEvent.Listener<Void> {
public static final String SECTION = "section";
private final Handler mDrawerHandler = new Handler();
private SharedPreferences prefs;
private int mDrawerItem;
@BindView(R.id.toolbar) Toolbar toolbar;
@BindView(R.id.drawer_layout) DrawerLayout drawer;
@ -41,9 +44,9 @@ public class MainActivity extends Activity
@Override
protected void onCreate(final Bundle savedInstanceState) {
prefs = getTopApplication().prefs;
prefs = getApplicationContext().prefs;
if (getTopApplication().isDarkTheme) {
if (getApplicationContext().isDarkTheme) {
setTheme(R.style.AppTheme_Dark);
}
super.onCreate(savedInstanceState);
@ -75,32 +78,31 @@ public class MainActivity extends Activity
drawer.addDrawerListener(toggle);
toggle.syncState();
navigate(R.id.status);
if (savedInstanceState != null)
navigate(savedInstanceState.getInt(SECTION, R.id.status));
else
navigate(getIntent().getStringExtra(SECTION));
navigationView.setNavigationItemSelectedListener(this);
getTopApplication().reloadMainActivity.register(this);
if (getTopApplication().updateCheckDone.isTriggered)
onTrigger(getTopApplication().updateCheckDone);
getApplicationContext().reloadMainActivity.register(this);
}
@Override
protected void onResume() {
super.onResume();
getTopApplication().updateCheckDone.register(this);
checkHideSection();
}
@Override
protected void onPause() {
getTopApplication().updateCheckDone.unRegister(this);
super.onPause();
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(SECTION, mDrawerItem);
}
@Override
protected void onDestroy() {
getTopApplication().reloadMainActivity.unRegister(this);
getApplicationContext().reloadMainActivity.unRegister(this);
super.onDestroy();
}
@ -122,28 +124,61 @@ public class MainActivity extends Activity
@Override
public void onTrigger(CallbackEvent<Void> event) {
if (event == getTopApplication().updateCheckDone) {
Menu menu = navigationView.getMenu();
menu.findItem(R.id.install).setVisible(
getTopApplication().remoteMagiskVersion > 0 && Shell.rootAccess());
} else if (event == getTopApplication().reloadMainActivity) {
recreate();
}
recreate();
}
private void checkHideSection() {
Menu menu = navigationView.getMenu();
if (Shell.rootAccess()) {
menu.findItem(R.id.magiskhide).setVisible(
getTopApplication().magiskVersion >= 8 && prefs.getBoolean("magiskhide", false));
menu.findItem(R.id.modules).setVisible(getTopApplication().magiskVersion >= 4);
menu.findItem(R.id.downloads).setVisible(getTopApplication().magiskVersion >= 4);
getApplicationContext().magiskVersion >= 8 && prefs.getBoolean("magiskhide", false));
menu.findItem(R.id.modules).setVisible(getApplicationContext().magiskVersion >= 4);
menu.findItem(R.id.downloads).setVisible(getApplicationContext().magiskVersion >= 4);
menu.findItem(R.id.log).setVisible(true);
menu.findItem(R.id.superuser).setVisible(getTopApplication().isSuClient);
menu.findItem(R.id.superuser).setVisible(getApplicationContext().isSuClient);
}
menu.findItem(R.id.install).setVisible(getApplicationContext().remoteMagiskVersion > 0);
}
public void navigate(String item) {
int itemId = R.id.status;
if (item != null) {
switch (item) {
case "status":
itemId = R.id.status;
break;
case "install":
itemId = R.id.install;
break;
case "superuser":
itemId = R.id.superuser;
break;
case "modules":
itemId = R.id.modules;
break;
case "downloads":
itemId = R.id.downloads;
break;
case "magiskhide":
itemId = R.id.magiskhide;
break;
case "log":
itemId = R.id.log;
break;
case "settings":
itemId = R.id.settings;
break;
case "about":
itemId = R.id.app_about;
break;
}
}
navigate(itemId);
}
public void navigate(int itemId) {
mDrawerItem = itemId;
navigationView.setCheckedItem(itemId);
switch (itemId) {
case R.id.status:
displayFragment(new StatusFragment(), "status", true);
@ -165,7 +200,6 @@ public class MainActivity extends Activity
break;
case R.id.log:
displayFragment(new LogFragment(), "log", false);
toolbar.setElevation(0);
break;
case R.id.settings:
startActivity(new Intent(this, SettingsActivity.class));
@ -182,5 +216,6 @@ public class MainActivity extends Activity
transaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
transaction.replace(R.id.content_frame, navFragment, tag).commitNow();
if (setElevation) toolbar.setElevation(toolbarElevation);
else toolbar.setElevation(0);
}
}

View File

@ -31,7 +31,7 @@ public class SettingsActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getTopApplication().isDarkTheme) {
if (getApplicationContext().isDarkTheme) {
setTheme(R.style.AppTheme_Dark);
}
@ -146,8 +146,9 @@ public class SettingsActivity extends Activity {
enabled = prefs.getBoolean("dark_theme", false);
if (getApplication().isDarkTheme != enabled) {
getApplication().isDarkTheme = enabled;
getActivity().recreate();
getApplication().reloadMainActivity.trigger();
getActivity().finish();
getActivity().recreate();
}
break;
case "disable":

View File

@ -1,5 +1,9 @@
package com.topjohnwu.magisk;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
@ -10,19 +14,22 @@ import com.topjohnwu.magisk.asyncs.LoadModules;
import com.topjohnwu.magisk.asyncs.LoadRepos;
import com.topjohnwu.magisk.asyncs.MagiskHide;
import com.topjohnwu.magisk.components.Activity;
import com.topjohnwu.magisk.services.UpdateCheckService;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
import java.util.List;
public class SplashActivity extends Activity {
public class SplashActivity extends Activity{
private static final int UPDATE_SERVICE_ID = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MagiskManager magiskManager = getTopApplication();
MagiskManager magiskManager = getApplicationContext();
// Init the info and configs and root shell
magiskManager.init();
@ -31,8 +38,17 @@ public class SplashActivity extends Activity {
List<String> ret = Shell.sh("getprop persist.magisk.hide");
boolean started = Utils.isValidShellResponse(ret) && Integer.parseInt(ret.get(0)) != 0;
// Initialize the update check service, notify every 3 hours
ComponentName service = new ComponentName(magiskManager, UpdateCheckService.class);
JobInfo jobInfo = new JobInfo.Builder(UPDATE_SERVICE_ID, service)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.setPersisted(true)
.setPeriodic(3 * 60 * 60 * 1000)
.build();
JobScheduler scheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
scheduler.schedule(jobInfo);
// Now fire all async tasks
new CheckUpdates(this).exec();
new GetBootBlocks(this).exec();
if (magiskManager.magiskHide && !magiskManager.disabled &&
magiskManager.magiskVersion > 11 && !started) {
@ -46,10 +62,15 @@ public class SplashActivity extends Activity {
}
}.exec();
new LoadApps(this).exec();
// Preparation done, now start main activity
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(intent);
finish();
new CheckUpdates(this, true){
@Override
protected void onPostExecute(Void v) {
super.onPostExecute(v);
Intent intent = getIntent().setClass(magiskManager, MainActivity.class)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
finish();
}
}.exec();
}
}

View File

@ -1,12 +1,9 @@
package com.topjohnwu.magisk;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -58,8 +55,6 @@ public class StatusFragment extends Fragment implements CallbackEvent.Listener<V
@BindColor(android.R.color.transparent) int trans;
int defaultColor;
private AlertDialog updateMagisk;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
@ -96,6 +91,15 @@ public class StatusFragment extends Fragment implements CallbackEvent.Listener<V
Utils.checkSafetyNet(getApplication());
});
magiskStatusContainer.setOnClickListener(view -> {
((MainActivity) getActivity()).navigationView.setCheckedItem(R.id.install);
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
try {
transaction.replace(R.id.content_frame, new InstallFragment(), "install").commit();
} catch (IllegalStateException ignored) {}
});
if (getApplication().magiskVersion < 0 && Shell.rootAccess() && !noDialog) {
noDialog = true;
new AlertDialogBuilder(getActivity())
@ -229,32 +233,6 @@ public class StatusFragment extends Fragment implements CallbackEvent.Listener<V
magiskCheckUpdatesProgress.setVisibility(View.GONE);
mSwipeRefreshLayout.setRefreshing(false);
updateMagisk = new AlertDialogBuilder(getActivity())
.setTitle(R.string.magisk_update_title)
.setMessage(getString(R.string.magisk_update_message, getApplication().remoteMagiskVersion))
.setCancelable(true)
.setPositiveButton(R.string.goto_install, (dialogInterface, i) -> {
((MainActivity) getActivity()).navigationView.setCheckedItem(R.id.install);
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
try {
transaction.replace(R.id.content_frame, new InstallFragment(), "install").commit();
} catch (IllegalStateException ignored) {}
})
.setNeutralButton(R.string.release_notes, (dialog, which) -> {
getActivity().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getApplication().releaseNoteLink)));
})
.setNegativeButton(R.string.no_thanks, null)
.create();
if (getApplication().magiskVersion < getApplication().remoteMagiskVersion && Shell.rootAccess()) {
magiskStatusContainer.setOnClickListener(view -> updateMagisk.show());
if (!noDialog) {
noDialog = true;
updateMagisk.show();
}
}
}
private void updateSafetyNetUI() {

View File

@ -1,7 +1,16 @@
package com.topjohnwu.magisk.asyncs;
import android.app.Activity;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.TaskStackBuilder;
import android.support.v7.app.NotificationCompat;
import com.topjohnwu.magisk.MainActivity;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.SplashActivity;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.utils.WebService;
import org.json.JSONException;
@ -9,10 +18,18 @@ import org.json.JSONObject;
public class CheckUpdates extends ParallelTask<Void, Void, Void> {
public static final String UPDATE_JSON = "https://raw.githubusercontent.com/topjohnwu/MagiskManager/updates/magisk_update.json";
private static final String UPDATE_JSON = "https://raw.githubusercontent.com/topjohnwu/MagiskManager/updates/magisk_update.json";
private static final int NOTIFICATION_ID = 1;
public CheckUpdates(Activity context) {
super(context);
private boolean showNotification = false;
public CheckUpdates(Context context, boolean b) {
this(context);
showNotification = b && !magiskManager.isNotified;
}
public CheckUpdates(Context context) {
magiskManager = Utils.getMagiskManager(context);
}
@Override
@ -31,6 +48,25 @@ public class CheckUpdates extends ParallelTask<Void, Void, Void> {
@Override
protected void onPostExecute(Void v) {
if (magiskManager.magiskVersion < magiskManager.remoteMagiskVersion && showNotification) {
magiskManager.isNotified = true;
NotificationCompat.Builder builder = new NotificationCompat.Builder(magiskManager);
builder.setSmallIcon(R.drawable.ic_magisk)
.setContentTitle(magiskManager.getString(R.string.magisk_update_title))
.setContentText(magiskManager.getString(R.string.magisk_update_available, magiskManager.remoteMagiskVersion))
.setVibrate(new long[]{0, 100, 100, 100})
.setAutoCancel(true);
Intent intent = new Intent(magiskManager, SplashActivity.class);
intent.putExtra(MainActivity.SECTION, "install");
TaskStackBuilder stackBuilder = TaskStackBuilder.create(magiskManager);
stackBuilder.addParentStack(MainActivity.class);
stackBuilder.addNextIntent(intent);
PendingIntent pendingIntent = stackBuilder.getPendingIntent(NOTIFICATION_ID, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) magiskManager.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(NOTIFICATION_ID, builder.build());
}
magiskManager.updateCheckDone.trigger();
}
}

View File

@ -6,7 +6,8 @@ import com.topjohnwu.magisk.MagiskManager;
public class Activity extends AppCompatActivity {
public MagiskManager getTopApplication() {
@Override
public MagiskManager getApplicationContext() {
return (MagiskManager) getApplication();
}
}

View File

@ -1,17 +1,10 @@
package com.topjohnwu.magisk.receivers;
import android.app.IntentService;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
import java.util.List;
import com.topjohnwu.magisk.services.BootupIntentService;
public class BootReceiver extends BroadcastReceiver {
@ -20,25 +13,4 @@ public class BootReceiver extends BroadcastReceiver {
context.startService(new Intent(context, BootupIntentService.class));
}
public static class BootupIntentService extends IntentService {
public BootupIntentService() {
super("BootupIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
MagiskManager magiskManager = Utils.getMagiskManager(this);
magiskManager.initSuAccess();
magiskManager.updateMagiskInfo();
List<String> ret = Shell.sh("getprop persist.magisk.hide");
boolean started = Utils.isValidShellResponse(ret) && Integer.parseInt(ret.get(0)) != 0;
if (magiskManager.prefs.getBoolean("magiskhide", false) &&
!magiskManager.disabled && !started && magiskManager.magiskVersion > 11) {
magiskManager.toast(R.string.start_magiskhide, Toast.LENGTH_LONG);
Shell.su(true, MagiskManager.MAGISK_HIDE_PATH + "enable",
"setprop persist.magisk.hide 1");
}
}
}
}

View File

@ -0,0 +1,34 @@
package com.topjohnwu.magisk.services;
import android.app.IntentService;
import android.content.Intent;
import android.widget.Toast;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
import java.util.List;
public class BootupIntentService extends IntentService {
public BootupIntentService() {
super("BootupIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
MagiskManager magiskManager = Utils.getMagiskManager(this);
magiskManager.initSuAccess();
magiskManager.updateMagiskInfo();
List<String> ret = Shell.sh("getprop persist.magisk.hide");
boolean started = Utils.isValidShellResponse(ret) && Integer.parseInt(ret.get(0)) != 0;
if (magiskManager.prefs.getBoolean("magiskhide", false) &&
!magiskManager.disabled && !started && magiskManager.magiskVersion > 11) {
magiskManager.toast(R.string.start_magiskhide, Toast.LENGTH_LONG);
Shell.su(true, MagiskManager.MAGISK_HIDE_PATH + "enable",
"setprop persist.magisk.hide 1");
}
}
}

View File

@ -0,0 +1,31 @@
package com.topjohnwu.magisk.services;
import android.app.job.JobParameters;
import android.app.job.JobService;
import com.topjohnwu.magisk.asyncs.CheckUpdates;
public class UpdateCheckService extends JobService {
@Override
public boolean onStartJob(JobParameters params) {
new CheckUpdates(this, true){
@Override
protected Void doInBackground(Void... voids) {
magiskManager.updateMagiskInfo();
return super.doInBackground(voids);
}
@Override
protected void onPostExecute(Void v) {
jobFinished(params, false);
super.onPostExecute(v);
}
}.exec();
return true;
}
@Override
public boolean onStopJob(JobParameters params) {
return true;
}
}

View File

@ -17,9 +17,8 @@ public class RequestActivity extends Activity {
return;
}
getTopApplication().initSuConfigs();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setClass(this, SuRequestActivity.class);
getApplicationContext().initSuConfigs();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK).setClass(this, SuRequestActivity.class);
startActivity(intent);
finish();
}

View File

@ -66,7 +66,7 @@ public class SuRequestActivity extends Activity implements CallbackEvent.Listene
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
pm = getPackageManager();
magiskManager = getTopApplication();
magiskManager = getApplicationContext();
Intent intent = getIntent();
socketPath = intent.getStringExtra("socket");

View File

@ -28,7 +28,7 @@ public class Logger {
public static void dev(String msg) {
if (MagiskManager.devLogging) {
Log.d(TAG, "DEBUG: " + msg);
Log.d(TAG, "DEV: " + msg);
}
}

View File

@ -183,7 +183,7 @@
<string name="target_uid">目標 UID:\u0020</string>
<string name="command">"指令: "</string>
<string name="close">關閉</string>
<string name="internal_storage">Zip 已被儲存到:[內部儲存空間]%1$1</string>
<string name="internal_storage">Zip 已被儲存到:[內部儲存空間]%1$s</string>
<string name="ok"></string>
<string name="process_error">處裡失敗</string>
<string name="download">下載</string>