From acfc9d75e04c76adf164db2d3f2e1573c374419c Mon Sep 17 00:00:00 2001 From: Moxie Marlinspike Date: Mon, 27 Nov 2017 12:18:14 -0800 Subject: [PATCH] Use startForegroundService instead of startService on Android 8 --- res/values/strings.xml | 1 + .../components/reminder/DozeReminder.java | 15 +++++++------ .../securesms/jobs/PushDecryptJob.java | 21 ++++++++++++++----- .../securesms/service/BootReceiver.java | 9 ++++++-- .../securesms/service/KeyCachingService.java | 16 +++++++------- .../service/MessageRetrievalService.java | 14 +++++-------- .../service/PanicResponderListener.java | 5 ++++- .../PersistentConnectionBootListener.java | 13 ++++++++---- .../securesms/service/WebRtcCallService.java | 5 +++++ .../securesms/util/ServiceUtil.java | 5 +++++ .../webrtc/CallNotificationBuilder.java | 13 ++++++++---- 11 files changed, 77 insertions(+), 40 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 6ab783d99..9c0f2934a 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1310,6 +1310,7 @@ Transport icon Loading... + Connecting... diff --git a/src/org/thoughtcrime/securesms/components/reminder/DozeReminder.java b/src/org/thoughtcrime/securesms/components/reminder/DozeReminder.java index 44537a84c..25b25279c 100644 --- a/src/org/thoughtcrime/securesms/components/reminder/DozeReminder.java +++ b/src/org/thoughtcrime/securesms/components/reminder/DozeReminder.java @@ -1,6 +1,7 @@ package org.thoughtcrime.securesms.components.reminder; +import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.net.Uri; @@ -14,6 +15,7 @@ import android.view.View; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.util.TextSecurePreferences; +@SuppressLint("BatteryLife") public class DozeReminder extends Reminder { @RequiresApi(api = Build.VERSION_CODES.M) @@ -21,14 +23,11 @@ public class DozeReminder extends Reminder { super(context.getString(R.string.DozeReminder_optimize_for_missing_play_services), context.getString(R.string.DozeReminder_this_device_does_not_support_play_services_tap_to_disable_system_battery)); - setOkListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - TextSecurePreferences.setPromptedOptimizeDoze(context, true); - Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, - Uri.parse("package:" + context.getPackageName())); - context.startActivity(intent); - } + setOkListener(v -> { + TextSecurePreferences.setPromptedOptimizeDoze(context, true); + Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, + Uri.parse("package:" + context.getPackageName())); + context.startActivity(intent); }); setDismissListener(new View.OnClickListener() { diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java index 16165a191..8d0e7d9fe 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java @@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; import android.content.Intent; +import android.os.Build; import android.support.annotation.NonNull; import android.util.Log; import android.util.Pair; @@ -239,7 +240,9 @@ public class PushDecryptJob extends ContextJob { intent.putExtra(WebRtcCallService.EXTRA_REMOTE_ADDRESS, Address.fromExternal(context, envelope.getSource())); intent.putExtra(WebRtcCallService.EXTRA_REMOTE_DESCRIPTION, message.getDescription()); intent.putExtra(WebRtcCallService.EXTRA_TIMESTAMP, envelope.getTimestamp()); - context.startService(intent); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) context.startForegroundService(intent); + else context.startService(intent); } } @@ -252,7 +255,9 @@ public class PushDecryptJob extends ContextJob { intent.putExtra(WebRtcCallService.EXTRA_CALL_ID, message.getId()); intent.putExtra(WebRtcCallService.EXTRA_REMOTE_ADDRESS, Address.fromExternal(context, envelope.getSource())); intent.putExtra(WebRtcCallService.EXTRA_REMOTE_DESCRIPTION, message.getDescription()); - context.startService(intent); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) context.startForegroundService(intent); + else context.startService(intent); } private void handleCallIceUpdateMessage(@NonNull SignalServiceEnvelope envelope, @@ -267,7 +272,9 @@ public class PushDecryptJob extends ContextJob { intent.putExtra(WebRtcCallService.EXTRA_ICE_SDP, message.getSdp()); intent.putExtra(WebRtcCallService.EXTRA_ICE_SDP_MID, message.getSdpMid()); intent.putExtra(WebRtcCallService.EXTRA_ICE_SDP_LINE_INDEX, message.getSdpMLineIndex()); - context.startService(intent); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) context.startForegroundService(intent); + else context.startService(intent); } } @@ -283,7 +290,9 @@ public class PushDecryptJob extends ContextJob { intent.setAction(WebRtcCallService.ACTION_REMOTE_HANGUP); intent.putExtra(WebRtcCallService.EXTRA_CALL_ID, message.getId()); intent.putExtra(WebRtcCallService.EXTRA_REMOTE_ADDRESS, Address.fromExternal(context, envelope.getSource())); - context.startService(intent); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) context.startForegroundService(intent); + else context.startService(intent); } } @@ -294,7 +303,9 @@ public class PushDecryptJob extends ContextJob { intent.setAction(WebRtcCallService.ACTION_REMOTE_BUSY); intent.putExtra(WebRtcCallService.EXTRA_CALL_ID, message.getId()); intent.putExtra(WebRtcCallService.EXTRA_REMOTE_ADDRESS, Address.fromExternal(context, envelope.getSource())); - context.startService(intent); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) context.startForegroundService(intent); + else context.startService(intent); } private void handleEndSessionMessage(@NonNull MasterSecretUnion masterSecret, diff --git a/src/org/thoughtcrime/securesms/service/BootReceiver.java b/src/org/thoughtcrime/securesms/service/BootReceiver.java index d654b2c62..42f0fec89 100644 --- a/src/org/thoughtcrime/securesms/service/BootReceiver.java +++ b/src/org/thoughtcrime/securesms/service/BootReceiver.java @@ -3,13 +3,18 @@ package org.thoughtcrime.securesms.service; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.os.Build; public class BootReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - Intent messageRetrievalService = new Intent(context, MessageRetrievalService.class); - context.startService(messageRetrievalService); + if (intent != null && Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { + Intent messageRetrievalService = new Intent(context, MessageRetrievalService.class); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) context.startForegroundService(messageRetrievalService); + else context.startService(messageRetrievalService); + } } } diff --git a/src/org/thoughtcrime/securesms/service/KeyCachingService.java b/src/org/thoughtcrime/securesms/service/KeyCachingService.java index 827c791f3..2ddd2dc58 100644 --- a/src/org/thoughtcrime/securesms/service/KeyCachingService.java +++ b/src/org/thoughtcrime/securesms/service/KeyCachingService.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2011 Whisper Systems * * This program is free software: you can redistribute it and/or modify @@ -16,6 +16,7 @@ */ package org.thoughtcrime.securesms.service; +import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.AlarmManager; import android.app.Notification; @@ -44,6 +45,7 @@ import org.thoughtcrime.securesms.crypto.MasterSecretUtil; import org.thoughtcrime.securesms.jobs.MasterSecretDecryptJob; import org.thoughtcrime.securesms.notifications.MessageNotifier; import org.thoughtcrime.securesms.util.DynamicLanguage; +import org.thoughtcrime.securesms.util.ServiceUtil; import org.thoughtcrime.securesms.util.TextSecurePreferences; import java.util.concurrent.TimeUnit; @@ -95,6 +97,7 @@ public class KeyCachingService extends Service { return masterSecret; } + @SuppressLint("StaticFieldLeak") public void setMasterSecret(final MasterSecret masterSecret) { synchronized (KeyCachingService.class) { KeyCachingService.masterSecret = masterSecret; @@ -176,7 +179,7 @@ public class KeyCachingService extends Service { private void handleActivityStarted() { Log.w("KeyCachingService", "Incrementing activity count..."); - AlarmManager alarmManager = (AlarmManager)this.getSystemService(ALARM_SERVICE); + AlarmManager alarmManager = ServiceUtil.getAlarmManager(this); alarmManager.cancel(pending); activitiesRunning++; } @@ -188,6 +191,7 @@ public class KeyCachingService extends Service { startTimeoutIfAppropriate(); } + @SuppressLint("StaticFieldLeak") private void handleClearKey() { Log.w("KeyCachingService", "handleClearKey()"); KeyCachingService.masterSecret = null; @@ -226,7 +230,7 @@ public class KeyCachingService extends Service { Log.w("KeyCachingService", "Starting timeout: " + timeoutMillis); - AlarmManager alarmManager = (AlarmManager)this.getSystemService(ALARM_SERVICE); + AlarmManager alarmManager = ServiceUtil.getAlarmManager(this); alarmManager.cancel(pending); alarmManager.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + timeoutMillis, pending); } @@ -304,15 +308,13 @@ public class KeyCachingService extends Service { private PendingIntent buildLockIntent() { Intent intent = new Intent(this, KeyCachingService.class); intent.setAction(PASSPHRASE_EXPIRED_EVENT); - PendingIntent pendingIntent = PendingIntent.getService(getApplicationContext(), 0, intent, 0); - return pendingIntent; + return PendingIntent.getService(getApplicationContext(), 0, intent, 0); } private PendingIntent buildLaunchIntent() { Intent intent = new Intent(this, ConversationListActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - PendingIntent launchIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, 0); - return launchIntent; + return PendingIntent.getActivity(getApplicationContext(), 0, intent, 0); } @Override diff --git a/src/org/thoughtcrime/securesms/service/MessageRetrievalService.java b/src/org/thoughtcrime/securesms/service/MessageRetrievalService.java index 8d82c0134..c7b0a6c6d 100644 --- a/src/org/thoughtcrime/securesms/service/MessageRetrievalService.java +++ b/src/org/thoughtcrime/securesms/service/MessageRetrievalService.java @@ -20,7 +20,6 @@ import org.whispersystems.jobqueue.requirements.RequirementListener; import org.whispersystems.libsignal.InvalidVersionException; import org.whispersystems.signalservice.api.SignalServiceMessagePipe; import org.whispersystems.signalservice.api.SignalServiceMessageReceiver; -import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope; import java.util.LinkedList; import java.util.List; @@ -209,16 +208,13 @@ public class MessageRetrievalService extends Service implements InjectableType, try { Log.w(TAG, "Reading message..."); localPipe.read(REQUEST_TIMEOUT_MINUTES, TimeUnit.MINUTES, - new SignalServiceMessagePipe.MessagePipeCallback() { - @Override - public void onMessage(SignalServiceEnvelope envelope) { - Log.w(TAG, "Retrieved envelope! " + envelope.getSource()); + envelope -> { + Log.w(TAG, "Retrieved envelope! " + envelope.getSource()); - PushContentReceiveJob receiveJob = new PushContentReceiveJob(MessageRetrievalService.this); - receiveJob.handle(envelope); + PushContentReceiveJob receiveJob = new PushContentReceiveJob(MessageRetrievalService.this); + receiveJob.handle(envelope); - decrementPushReceived(); - } + decrementPushReceived(); }); } catch (TimeoutException e) { Log.w(TAG, "Application level read timeout..."); diff --git a/src/org/thoughtcrime/securesms/service/PanicResponderListener.java b/src/org/thoughtcrime/securesms/service/PanicResponderListener.java index a3b9aee45..ddbc24452 100644 --- a/src/org/thoughtcrime/securesms/service/PanicResponderListener.java +++ b/src/org/thoughtcrime/securesms/service/PanicResponderListener.java @@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.service; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.os.Build; import org.thoughtcrime.securesms.util.TextSecurePreferences; @@ -22,7 +23,9 @@ public class PanicResponderListener extends BroadcastReceiver { { Intent lockIntent = new Intent(context, KeyCachingService.class); lockIntent.setAction(KeyCachingService.CLEAR_KEY_ACTION); - context.startService(lockIntent); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) context.startForegroundService(lockIntent); + else context.startService(lockIntent); } } } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/service/PersistentConnectionBootListener.java b/src/org/thoughtcrime/securesms/service/PersistentConnectionBootListener.java index e19ce59bf..4040696ec 100644 --- a/src/org/thoughtcrime/securesms/service/PersistentConnectionBootListener.java +++ b/src/org/thoughtcrime/securesms/service/PersistentConnectionBootListener.java @@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.service; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.os.Build; import org.thoughtcrime.securesms.util.TextSecurePreferences; @@ -10,10 +11,14 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences; public class PersistentConnectionBootListener extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - if (TextSecurePreferences.isGcmDisabled(context)) { - Intent serviceIntent = new Intent(context, MessageRetrievalService.class); - serviceIntent.setAction(MessageRetrievalService.ACTION_INITIALIZE); - context.startService(serviceIntent); + if (intent != null && Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { + if (TextSecurePreferences.isGcmDisabled(context)) { + Intent serviceIntent = new Intent(context, MessageRetrievalService.class); + serviceIntent.setAction(MessageRetrievalService.ACTION_INITIALIZE); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) context.startForegroundService(serviceIntent); + else context.startService(serviceIntent); + } } } } diff --git a/src/org/thoughtcrime/securesms/service/WebRtcCallService.java b/src/org/thoughtcrime/securesms/service/WebRtcCallService.java index 51d86c59a..b91e3b32b 100644 --- a/src/org/thoughtcrime/securesms/service/WebRtcCallService.java +++ b/src/org/thoughtcrime/securesms/service/WebRtcCallService.java @@ -97,6 +97,7 @@ import java.util.concurrent.TimeUnit; import javax.inject.Inject; import static org.thoughtcrime.securesms.webrtc.CallNotificationBuilder.TYPE_ESTABLISHED; +import static org.thoughtcrime.securesms.webrtc.CallNotificationBuilder.TYPE_INCOMING_CONNECTING; import static org.thoughtcrime.securesms.webrtc.CallNotificationBuilder.TYPE_INCOMING_RINGING; import static org.thoughtcrime.securesms.webrtc.CallNotificationBuilder.TYPE_OUTGOING_RINGING; @@ -334,6 +335,10 @@ public class WebRtcCallService extends Service implements InjectableType, PeerCo return; } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + setCallInProgressNotification(TYPE_INCOMING_CONNECTING, this.recipient); + } + timeoutExecutor.schedule(new TimeoutRunnable(this.callId), 2, TimeUnit.MINUTES); initializeVideo(); diff --git a/src/org/thoughtcrime/securesms/util/ServiceUtil.java b/src/org/thoughtcrime/securesms/util/ServiceUtil.java index ce06b8fd3..402cabe83 100644 --- a/src/org/thoughtcrime/securesms/util/ServiceUtil.java +++ b/src/org/thoughtcrime/securesms/util/ServiceUtil.java @@ -1,6 +1,7 @@ package org.thoughtcrime.securesms.util; import android.app.Activity; +import android.app.AlarmManager; import android.app.NotificationManager; import android.content.Context; import android.media.AudioManager; @@ -38,4 +39,8 @@ public class ServiceUtil { public static PowerManager getPowerManager(Context context) { return (PowerManager)context.getSystemService(Context.POWER_SERVICE); } + + public static AlarmManager getAlarmManager(Context context) { + return (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); + } } diff --git a/src/org/thoughtcrime/securesms/webrtc/CallNotificationBuilder.java b/src/org/thoughtcrime/securesms/webrtc/CallNotificationBuilder.java index d9ac52eae..7f1b9016d 100644 --- a/src/org/thoughtcrime/securesms/webrtc/CallNotificationBuilder.java +++ b/src/org/thoughtcrime/securesms/webrtc/CallNotificationBuilder.java @@ -28,9 +28,11 @@ public class CallNotificationBuilder { public static final int WEBRTC_NOTIFICATION = 313388; - public static final int TYPE_INCOMING_RINGING = 1; - public static final int TYPE_OUTGOING_RINGING = 2; - public static final int TYPE_ESTABLISHED = 3; + public static final int TYPE_INCOMING_RINGING = 1; + public static final int TYPE_OUTGOING_RINGING = 2; + public static final int TYPE_ESTABLISHED = 3; + public static final int TYPE_INCOMING_CONNECTING = 4; + public static Notification getCallInProgressNotification(Context context, int type, Recipient recipient) { Intent contentIntent = new Intent(context, WebRtcCallActivity.class); @@ -44,7 +46,10 @@ public class CallNotificationBuilder { .setOngoing(true) .setContentTitle(recipient.getName()); - if (type == TYPE_INCOMING_RINGING) { + if (type == TYPE_INCOMING_CONNECTING) { + builder.setContentText(context.getString(R.string.CallNotificationBuilder_connecting)); + builder.setPriority(NotificationCompat.PRIORITY_MIN); + } else if (type == TYPE_INCOMING_RINGING) { builder.setContentText(context.getString(R.string.NotificationBarManager__incoming_signal_call)); builder.addAction(getServiceNotificationAction(context, WebRtcCallService.ACTION_DENY_CALL, R.drawable.ic_close_grey600_32dp, R.string.NotificationBarManager__deny_call)); builder.addAction(getActivityNotificationAction(context, WebRtcCallActivity.ANSWER_ACTION, R.drawable.ic_phone_grey600_32dp, R.string.NotificationBarManager__answer_call));