зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1550291 - Android Q: Use the overlay permission or a foreground notification to start the crash handler; r=VladBaicu
Android Q doesn't allow starting Activities from background. https://developer.android.com/preview/privacy/background-activity-starts We can either piggy-back the SYSTEM_ALERT_WINDOW permission given by the user for the Tab Queue functionality or use a foreground notification from where users could start `CrashReporterActivity`. Differential Revision: https://phabricator.services.mozilla.com/D33029 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
c9f1eb41c0
Коммит
70755e0b8c
|
@ -23,4 +23,5 @@
|
|||
<item type="id" name="action_button"/>
|
||||
<item type="id" name="page_progress"/>
|
||||
<item type="id" name="mediaControlNotification"/>
|
||||
<item type="id" name="crashReporterNotification"/>
|
||||
</resources>
|
||||
|
|
|
@ -1,23 +1,92 @@
|
|||
package org.mozilla.gecko;
|
||||
|
||||
import android.app.IntentService;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.os.IBinder;
|
||||
import android.provider.Settings;
|
||||
|
||||
import org.mozilla.gecko.notifications.NotificationHelper;
|
||||
|
||||
public class CrashHandlerService extends IntentService {
|
||||
public class CrashHandlerService extends Service {
|
||||
private static final String ACTION_STOP = "action_stop";
|
||||
// Build.VERSION_CODES.Q placeholder. While Android Q is in Beta it shares API 28 with Android P.
|
||||
private static final int ANDROID_Q = 29;
|
||||
|
||||
public CrashHandlerService() {
|
||||
super("Crash Handler");
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
if (ACTION_STOP.equals(intent.getAction())) {
|
||||
dismissNotification();
|
||||
} else {
|
||||
intent.setClass(this, CrashReporterActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
|
||||
if (AppConstants.Versions.feature29Plus) {
|
||||
startCrashHandling(intent);
|
||||
} else {
|
||||
startActivity(intent);
|
||||
|
||||
// Avoid ANR due to background limitations on Oreo+
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
return Service.START_NOT_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHandleIntent(@Nullable Intent intent) {
|
||||
intent.setClass(this, CrashReporterActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(intent);
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Avoid ANR due to background limitations on Oreo+
|
||||
System.exit(0);
|
||||
/**
|
||||
* Call this for any necessary cleanup like removing the foreground notification shown on Android Q+.
|
||||
*/
|
||||
public static void reportingStarted(final Context context) {
|
||||
if (AppConstants.Versions.feature29Plus) {
|
||||
final Intent intent = new Intent(context, CrashHandlerService.class);
|
||||
intent.setAction(ACTION_STOP);
|
||||
context.startService(intent);
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(ANDROID_Q)
|
||||
private Notification getActivityNotification(final Context context, final Intent activityIntent) {
|
||||
final Intent dismissNotificationIntent = new Intent(ACTION_STOP, null, this, this.getClass());
|
||||
final PendingIntent dismissNotification = PendingIntent.getService(this, 0, dismissNotificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
final PendingIntent startReporterActivity = PendingIntent.getActivity(this, 0, activityIntent, 0);
|
||||
final String notificationChannelId = NotificationHelper.getInstance(context)
|
||||
.getNotificationChannel(NotificationHelper.Channel.CRASH_HANDLER).getId();
|
||||
|
||||
return new Notification.Builder(this, notificationChannelId)
|
||||
.setSmallIcon(R.drawable.ic_status_logo)
|
||||
.setContentTitle(getString(R.string.crash_notification_title))
|
||||
.setContentText(getString(R.string.crash_notification_message))
|
||||
.setDefaults(Notification.DEFAULT_ALL)
|
||||
.setContentIntent(startReporterActivity)
|
||||
.addAction(0, getString(R.string.crash_notification_negative_button_text), dismissNotification)
|
||||
.build();
|
||||
}
|
||||
|
||||
@TargetApi(ANDROID_Q)
|
||||
private void dismissNotification() {
|
||||
stopForeground(Service.STOP_FOREGROUND_REMOVE);
|
||||
}
|
||||
|
||||
@TargetApi(ANDROID_Q)
|
||||
private void startCrashHandling(final Intent activityIntent) {
|
||||
// Piggy-back the SYSTEM_ALERT_WINDOW permission given by the user for the Tab Queue functionality.
|
||||
// Otherwise fallback to display a foreground notification, this being the only way we can
|
||||
// start an activity from background.
|
||||
// https://developer.android.com/preview/privacy/background-activity-starts#conditions-allow-activity-starts
|
||||
if (Settings.canDrawOverlays(this)) {
|
||||
startActivity(activityIntent);
|
||||
} else {
|
||||
final Notification notification = getActivityNotification(this, activityIntent);
|
||||
startForeground(R.id.mediaControlNotification, notification);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -139,6 +139,8 @@ public class CrashReporterActivity extends AppCompatActivity
|
|||
@Override
|
||||
@SuppressLint("WrongThread") // We don't have a worker thread for the TelemetryDispatcher
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
informReporterStarted();
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
// mHandler is created here so runnables can be run on the main thread
|
||||
mHandler = new Handler();
|
||||
|
@ -596,4 +598,11 @@ public class CrashReporterActivity extends AppCompatActivity
|
|||
private String unescape(String string) {
|
||||
return string.replaceAll("\\\\\\\\", "\\").replaceAll("\\\\n", "\n").replaceAll("\\\\t", "\t");
|
||||
}
|
||||
|
||||
/**
|
||||
* Inform other parts of the app that user started the crash reporting process.
|
||||
*/
|
||||
private void informReporterStarted() {
|
||||
CrashHandlerService.reportingStarted(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,6 +68,11 @@
|
|||
<!ENTITY sending_crash_report "Sending crash report\u2026">
|
||||
<!ENTITY crash_close_label "Close">
|
||||
<!ENTITY crash_restart_label "Restart &brandShortName;">
|
||||
<!-- Localization note (crash_notification_title, crash_notification_message, crash_notification_negative_button_text)
|
||||
Text displayed in a system notification to allow starting the Crash Reporter (Android Q and later).-->
|
||||
<!ENTITY crash_notification_title "&brandShortName; crashed">
|
||||
<!ENTITY crash_notification_message "Tap to report to &vendorShortName;">
|
||||
<!ENTITY crash_notification_negative_button_text "Ignore">
|
||||
|
||||
<!ENTITY url_bar_default_text2 "Search or enter address">
|
||||
|
||||
|
|
|
@ -71,6 +71,9 @@
|
|||
<string name="sending_crash_report">&sending_crash_report;</string>
|
||||
<string name="crash_close_label">&crash_close_label;</string>
|
||||
<string name="crash_restart_label">&crash_restart_label;</string>
|
||||
<string name="crash_notification_title">&crash_notification_title;</string>
|
||||
<string name="crash_notification_message">&crash_notification_message;</string>
|
||||
<string name="crash_notification_negative_button_text">&crash_notification_negative_button_text;</string>
|
||||
|
||||
<string name="url_bar_default_text">&url_bar_default_text2;</string>
|
||||
<string name="url_bar_qrcode_text">&url_bar_qrcode_text2;</string>
|
||||
|
|
Загрузка…
Ссылка в новой задаче