Commit f68ace0f authored by DrKLO's avatar DrKLO

Start app on system launch, NotificationsService that will keep app running in...

Start app on system launch, NotificationsService that will keep app running in background, special connection to receive update only about new messages, option to disable NotificationsService
parent ee38ecec
......@@ -43,8 +43,6 @@
<uses-library android:name="com.google.android.maps" android:required="false"/>
<service android:name=".AwakeService"/>
</application>
</manifest>
......@@ -43,8 +43,6 @@
<uses-library android:name="com.google.android.maps" android:required="false"/>
<service android:name=".AwakeService"/>
</application>
</manifest>
......@@ -38,6 +38,7 @@
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="false"
......@@ -144,6 +145,15 @@
android:resource="@xml/contacts" />
</service>
<service android:name="org.telegram.messenger.NotificationsService" android:enabled="true"/>
<receiver android:name="org.telegram.messenger.AppStartReceiver" android:enabled="true">
<intent-filter>
<action android:name="org.telegram.start" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
</manifest>
/*
* This is the source code of Telegram for Android v. 1.4.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2014.
*/
package org.telegram.messenger;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import org.telegram.ui.ApplicationLoader;
public class AppStartReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Utilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
ApplicationLoader.startPushService();
}
});
}
}
......@@ -40,6 +40,10 @@ public class ConnectionContext extends PyroClientAdapter {
sessionId = isDebugSession ? (0xabcd000000000000L | (newSessionId & 0x0000ffffffffffffL)) : newSessionId;
}
public void setSessionId(long id) {
sessionId = id;
}
public long getSissionId() {
return sessionId;
}
......
......@@ -37,6 +37,7 @@ public class Datacenter {
public TcpConnection connection;
public TcpConnection downloadConnection;
public TcpConnection uploadConnection;
public TcpConnection pushConnection;
private ArrayList<ServerSalt> authServerSaltSet = new ArrayList<ServerSalt>();
......
......@@ -49,8 +49,6 @@ public class GcmBroadcastReceiver extends BroadcastReceiver {
}
}
AwakeService.startService();
Utilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
......
......@@ -179,7 +179,7 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti
byte[] transportData = messageOs.toByteArray();
datacenter.connection.sendData(transportData, null, false, false);
datacenter.connection.sendData(transportData, null, false);
return transportData;
}
......@@ -576,11 +576,11 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti
return;
}
if (reqPQMsgData != null) {
datacenter.connection.sendData(reqPQMsgData, null, false, false);
datacenter.connection.sendData(reqPQMsgData, null, false);
} else if (reqDHMsgData != null) {
datacenter.connection.sendData(reqDHMsgData, null, false, false);
datacenter.connection.sendData(reqDHMsgData, null, false);
} else if (setClientDHParamsMsgData != null) {
datacenter.connection.sendData(setClientDHParamsMsgData, null, false, false);
datacenter.connection.sendData(setClientDHParamsMsgData, null, false);
}
}
......
......@@ -60,6 +60,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
public SparseArray<MessageObject> dialogMessage = new SparseArray<MessageObject>();
public ConcurrentHashMap<Long, ArrayList<PrintingUser>> printingUsers = new ConcurrentHashMap<Long, ArrayList<PrintingUser>>(100, 1.0f, 2);
public HashMap<Long, CharSequence> printingStrings = new HashMap<Long, CharSequence>();
private int lastPrintingStringCount = 0;
private HashMap<String, ArrayList<DelayedMessage>> delayedMessages = new HashMap<String, ArrayList<DelayedMessage>>();
public SparseArray<MessageObject> sendingMessages = new SparseArray<MessageObject>();
......@@ -291,6 +292,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
printingUsers.clear();
printingStrings.clear();
totalDialogsCount = 0;
lastPrintingStringCount = 0;
hidenAddToContacts.clear();
updatesQueue.clear();
pendingEncMessagesToDelete.clear();
......@@ -821,7 +823,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
} else {
scheduleContactsReload = 0;
}
if (!printingUsers.isEmpty()) {
if (!printingUsers.isEmpty() || lastPrintingStringCount != printingUsers.size()) {
boolean updated = false;
ArrayList<Long> keys = new ArrayList<Long>(printingUsers.keySet());
for (int b = 0; b < keys.size(); b++) {
......@@ -893,6 +895,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter
}
}
lastPrintingStringCount = newPrintingStrings.size();
Utilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
......@@ -3667,7 +3671,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
final ArrayList<Integer> markAsReadMessages = new ArrayList<Integer>();
final HashMap<Integer, Integer> markAsReadEncrypted = new HashMap<Integer, Integer>();
final ArrayList<Integer> deletedMessages = new ArrayList<Integer>();
final ArrayList<Long> printChanges = new ArrayList<Long>();
boolean printChanged = false;
final ArrayList<TLRPC.ChatParticipants> chatInfoToUpdate = new ArrayList<TLRPC.ChatParticipants>();
final ArrayList<TLRPC.Update> updatesOnMainThread = new ArrayList<TLRPC.Update>();
final ArrayList<TLRPC.TL_updateEncryptedMessagesRead> tasks = new ArrayList<TLRPC.TL_updateEncryptedMessagesRead>();
......@@ -3789,9 +3793,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
newUser.userId = update.user_id;
newUser.lastTime = currentTime;
arr.add(newUser);
if (!printChanges.contains(uid)) {
printChanges.add(uid);
}
printChanged = true;
}
}
} else if (update instanceof TLRPC.TL_updateChatParticipants) {
......@@ -3959,9 +3961,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
newUser.userId = update.user_id;
newUser.lastTime = currentTime;
arr.add(newUser);
if (!printChanges.contains(uid)) {
printChanges.add(uid);
}
printChanged = true;
}
} else if (update instanceof TLRPC.TL_updateEncryptedMessagesRead) {
markAsReadEncrypted.put(update.chat_id, Math.max(update.max_date, update.date));
......@@ -4067,19 +4067,19 @@ public class MessagesController implements NotificationCenter.NotificationCenter
for (HashMap.Entry<Long, ArrayList<MessageObject>> pair : messages.entrySet()) {
Long key = pair.getKey();
ArrayList<MessageObject> value = pair.getValue();
boolean printChanged = updatePrintingUsersWithNewMessages(key, value);
if (printChanged && !printChanges.contains(key)) {
printChanges.add(key);
if (updatePrintingUsersWithNewMessages(key, value)) {
printChanged = true;
}
}
}
if (!printChanges.isEmpty()) {
if (printChanged) {
updatePrintingStrings();
}
final MessageObject lastMessageArg = lastMessage;
final int interfaceUpdateMaskFinal = interfaceUpdateMask;
final boolean printChangedArg = printChanged;
processPendingEncMessages();
......@@ -4091,7 +4091,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
MessagesStorage.getInstance().putMessages(messagesArr, true, true);
}
if (!messages.isEmpty() || !markAsReadMessages.isEmpty() || !deletedMessages.isEmpty() || !printChanges.isEmpty() || !chatInfoToUpdate.isEmpty() || !updatesOnMainThread.isEmpty() || !markAsReadEncrypted.isEmpty() || !contactsIds.isEmpty()) {
if (!messages.isEmpty() || !markAsReadMessages.isEmpty() || !deletedMessages.isEmpty() || printChanged || !chatInfoToUpdate.isEmpty() || !updatesOnMainThread.isEmpty() || !markAsReadEncrypted.isEmpty() || !contactsIds.isEmpty()) {
Utilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
......@@ -4179,7 +4179,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
}
}
}
if (!printChanges.isEmpty()) {
if (printChangedArg) {
updateMask |= UPDATE_MASK_USER_PRINT;
}
if (!contactsIds.isEmpty()) {
......@@ -4508,15 +4508,18 @@ public class MessagesController implements NotificationCenter.NotificationCenter
needVibrate = false;
}
String name = Utilities.formatName(user.first_name, user.last_name);
String msgShort = msg.replace(name + ": ", "").replace(name + " ", "");
intent.setAction("com.tmessages.openchat" + Math.random() + Integer.MAX_VALUE);
intent.setFlags(32768);
PendingIntent contentIntent = PendingIntent.getActivity(ApplicationLoader.applicationContext, 0, intent, PendingIntent.FLAG_ONE_SHOT);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(ApplicationLoader.applicationContext)
.setContentTitle(LocaleController.getString("AppName", R.string.AppName))
.setContentTitle(name)
.setSmallIcon(R.drawable.notification)
.setStyle(new NotificationCompat.BigTextStyle().bigText(msg))
.setContentText(msg)
.setStyle(new NotificationCompat.BigTextStyle().bigText(msgShort))
.setContentText(msgShort)
.setAutoCancel(true)
.setTicker(msg);
......
......@@ -10,59 +10,36 @@ package org.telegram.messenger;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.content.SharedPreferences;
import android.os.IBinder;
import android.os.Looper;
import org.telegram.ui.ApplicationLoader;
public class AwakeService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
public static volatile int timeout = 10000;
public static boolean isStarted = false;
private Handler handler = new Handler(Looper.getMainLooper());
public class NotificationsService extends Service {
@Override
public void onCreate() {
super.onCreate();
FileLog.e("tmessages", "service started");
check();
isStarted = true;
ApplicationLoader.postInitApplication();
}
public static void startService() {
try {
if (ApplicationLoader.isScreenOn && ApplicationLoader.lastPauseTime == 0) {
return;
}
timeout = 10000;
if (!isStarted) {
ApplicationLoader.applicationContext.startService(new Intent(ApplicationLoader.applicationContext, AwakeService.class));
}
} catch (Exception e) {
FileLog.e("tmessages", e);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
private void check() {
handler.postDelayed(new Runnable() {
@Override
public void run() {
ApplicationLoader.postInitApplication();
timeout -= 1000;
if (timeout <= 0) {
stopSelf();
isStarted = false;
FileLog.e("tmessages", "service stoped");
} else {
check();
public IBinder onBind(Intent intent) {
return null;
}
public void onDestroy() {
FileLog.e("tmessages", "service destroyed");
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", MODE_PRIVATE);
if (preferences.getBoolean("pushService", true)) {
Intent intent = new Intent("org.telegram.start");
sendBroadcast(intent);
}
}, 1000);
}
}
......@@ -27,6 +27,7 @@ public class RPCRequest {
public static int RPCRequestClassEnableUnauthorized = 8;
public static int RPCRequestClassFailOnServerErrors = 16;
public static int RPCRequestClassCanCompress = 32;
public static int RPCRequestClassPush = 64;
static int RPCRequestClassTransportMask = (RPCRequestClassGeneric | RPCRequestClassDownloadMedia | RPCRequestClassUploadMedia);
......
......@@ -127,11 +127,19 @@ public class TcpConnection extends ConnectionContext {
}
client = selector.connect(new InetSocketAddress(hostAddress, hostPort));
client.addListener(TcpConnection.this);
if ((transportRequestClass & RPCRequest.RPCRequestClassPush) != 0) {
if (isNextPort) {
client.setTimeout(15000);
} else {
client.setTimeout(30000);
}
} else {
if (isNextPort) {
client.setTimeout(8000);
} else {
client.setTimeout(15000);
}
}
selector.wakeup();
} catch (Exception e) {
handleConnectionError(e);
......@@ -270,7 +278,7 @@ public class TcpConnection extends ConnectionContext {
connect();
}
public void sendData(final byte[] data, final ByteBufferDesc buff, final boolean reportAck, final boolean startResponseTimeout) {
public void sendData(final byte[] data, final ByteBufferDesc buff, final boolean reportAck) {
if (data == null && buff == null) {
return;
}
......@@ -408,8 +416,12 @@ public class TcpConnection extends ConnectionContext {
Datacenter datacenter = ConnectionsManager.getInstance().datacenterWithId(datacenterId);
datacenter.storeCurrentAddressAndPortNum();
isNextPort = false;
if ((transportRequestClass & RPCRequest.RPCRequestClassPush) != 0) {
client.setTimeout(40000);
} else {
client.setTimeout(25000);
}
}
hasSomeDataSinceLastConnect = true;
int currentPacketLength;
......
......@@ -21,6 +21,7 @@ public class UserConfig {
public static int clientUserId = 0;
public static boolean clientActivated = false;
public static boolean registeredForPush = false;
public static boolean registeredForInternalPush = false;
public static String pushString = "";
public static int lastSendMessageId = -210000;
public static int lastLocalId = -210000;
......@@ -56,6 +57,7 @@ public class UserConfig {
editor.putString("importHash", importHash);
editor.putBoolean("saveIncomingPhotos", saveIncomingPhotos);
editor.putInt("contactsVersion", contactsVersion);
editor.putBoolean("registeredForInternalPush", registeredForInternalPush);
if (currentUser != null) {
if (withFile) {
SerializedData data = new SerializedData();
......@@ -155,6 +157,7 @@ public class UserConfig {
importHash = preferences.getString("importHash", "");
saveIncomingPhotos = preferences.getBoolean("saveIncomingPhotos", false);
contactsVersion = preferences.getInt("contactsVersion", 0);
registeredForInternalPush = preferences.getBoolean("registeredForInternalPush", false);
String user = preferences.getString("user", null);
if (user != null) {
byte[] userBytes = Base64.decode(user, Base64.DEFAULT);
......@@ -177,6 +180,7 @@ public class UserConfig {
clientUserId = 0;
clientActivated = false;
currentUser = null;
registeredForInternalPush = false;
registeredForPush = false;
contactsHash = "";
importHash = "";
......
......@@ -9,7 +9,9 @@
package org.telegram.ui;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.Application;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
......@@ -28,6 +30,7 @@ import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.gcm.GoogleCloudMessaging;
import org.telegram.messenger.NotificationsService;
import org.telegram.messenger.BuildVars;
import org.telegram.messenger.ConnectionsManager;
import org.telegram.messenger.FileLog;
......@@ -41,6 +44,7 @@ import org.telegram.ui.Views.BaseFragment;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.concurrent.atomic.AtomicInteger;
public class ApplicationLoader extends Application {
......@@ -125,10 +129,12 @@ public class ApplicationLoader extends Application {
MessagesController.getInstance().users.put(UserConfig.clientUserId, UserConfig.currentUser);
ConnectionsManager.getInstance().applyCountryPortNumber(UserConfig.currentUser.phone);
ConnectionsManager.getInstance().initPushConnection();
}
ApplicationLoader app = (ApplicationLoader)ApplicationLoader.applicationContext;
app.initPlayServices();
FileLog.e("tmessages", "app initied");
}
@Override
......@@ -152,6 +158,31 @@ public class ApplicationLoader extends Application {
} catch (Exception e) {
e.printStackTrace();
}
startPushService();
}
public static void startPushService() {
SharedPreferences preferences = applicationContext.getSharedPreferences("Notifications", MODE_PRIVATE);
if (preferences.getBoolean("pushService", true)) {
applicationContext.startService(new Intent(applicationContext, NotificationsService.class));
Calendar cal = Calendar.getInstance();
PendingIntent pintent = PendingIntent.getService(applicationContext, 0, new Intent(applicationContext, NotificationsService.class), 0);
AlarmManager alarm = (AlarmManager) applicationContext.getSystemService(Context.ALARM_SERVICE);
alarm.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 30000, pintent);
} else {
stopPushService();
}
}
public static void stopPushService() {
applicationContext.stopService(new Intent(applicationContext, NotificationsService.class));
PendingIntent pintent = PendingIntent.getService(applicationContext, 0, new Intent(applicationContext, NotificationsService.class), 0);
AlarmManager alarm = (AlarmManager)applicationContext.getSystemService(Context.ALARM_SERVICE);
alarm.cancel(pintent);
}
@Override
......
......@@ -158,6 +158,7 @@ public class LoginActivityRegisterView extends SlideView {
if (delegate != null) {
delegate.needFinishActivity();
}
ConnectionsManager.getInstance().initPushConnection();
}
});
} else {
......
......@@ -241,6 +241,7 @@ public class LoginActivitySmsView extends SlideView implements NotificationCente
if (delegate != null) {
delegate.needFinishActivity();
}
ConnectionsManager.getInstance().initPushConnection();
}
});
} else {
......
......@@ -9,7 +9,9 @@
package org.telegram.ui;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.media.Ringtone;
......@@ -46,6 +48,7 @@ public class SettingsNotificationsActivity extends BaseFragment {
private ListView listView;
private boolean reseting = false;
private int notificationsServiceRow;
private int messageSectionRow;
private int messageAlertRow;
private int messagePreviewRow;
......@@ -70,6 +73,7 @@ public class SettingsNotificationsActivity extends BaseFragment {
@Override
public boolean onFragmentCreate() {
notificationsServiceRow = rowCount++;
messageSectionRow = rowCount++;
messageAlertRow = rowCount++;
messagePreviewRow = rowCount++;
......@@ -260,6 +264,32 @@ public class SettingsNotificationsActivity extends BaseFragment {
editor.putBoolean("EnablePebbleNotifications", !enabled);
editor.commit();
listView.invalidateViews();
} else if (i == notificationsServiceRow) {
final SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE);
boolean enabled = preferences.getBoolean("pushService", true);
if (!enabled) {
final SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("pushService", !enabled);
editor.commit();
listView.invalidateViews();
ApplicationLoader.startPushService();
} else {
AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity);
builder.setMessage(LocaleController.getString("NotificationsServiceDisableInfo", R.string.NotificationsServiceDisableInfo));
builder.setTitle(LocaleController.getString("AppName", R.string.AppName));
builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
ApplicationLoader.stopPushService();
final SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("pushService", false);
editor.commit();
listView.invalidateViews();
}
});
builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null);
builder.show().setCanceledOnTouchOutside(true);
}
}
}
});
......@@ -492,6 +522,10 @@ public class SettingsNotificationsActivity extends BaseFragment {
enabled = preferences.getBoolean("EnablePebbleNotifications", false);
textView.setText(LocaleController.getString("Alert", R.string.Alert));
divider.setVisibility(View.INVISIBLE);
} else if (i == notificationsServiceRow) {
enabled = preferences.getBoolean("pushService", true);
textView.setText(LocaleController.getString("NotificationsService", R.string.NotificationsService));
divider.setVisibility(View.INVISIBLE);
}
if (enabled) {
checkButton.setImageResource(R.drawable.btn_check_on);
......@@ -542,7 +576,7 @@ public class SettingsNotificationsActivity extends BaseFragment {
i == groupAlertRow || i == groupPreviewRow || i == groupVibrateRow ||
i == inappSoundRow || i == inappVibrateRow || i == inappPreviewRow ||
i == contactJoinedRow ||
i == pebbleAlertRow) {
i == pebbleAlertRow || i == notificationsServiceRow) {
return 1;
} else {
return 2;
......
......@@ -265,6 +265,8 @@
<string name="IncorrectLocalization">Incorrect localization file</string>
<string name="Enabled">Enabled</string>
<string name="Disabled">Disabled</string>
<string name="NotificationsService">Notifications Service</string>
<string name="NotificationsServiceDisableInfo">If google play services are enough for you to receive notifications, you can disable Notifications Service. However we recommend you to leave it enabled to keep app running in background and receive instant notifications.</string>
<!--media view-->
<string name="NoMedia">لا توجد وسائط بعد</string>
......
......@@ -265,6 +265,8 @@
<string name="IncorrectLocalization">Falsche Sprachdatei</string>
<string name="Enabled">Enabled</string>
<string name="Disabled">Disabled</string>
<string name="NotificationsService">Notifications Service</string>
<string name="NotificationsServiceDisableInfo">If google play services are enough for you to receive notifications, you can disable Notifications Service. However we recommend you to leave it enabled to keep app running in background and receive instant notifications.</string>
<!--media view-->
<string name="NoMedia">Noch keine geteilten Medien vorhanden</string>
......
......@@ -265,6 +265,8 @@
<string name="IncorrectLocalization">Fichero de localización incorrecto</string>
<string name="Enabled">Enabled</string>
<string name="Disabled">Disabled</string>
<string name="NotificationsService">Notifications Service</string>
<string name="NotificationsServiceDisableInfo">If google play services are enough for you to receive notifications, you can disable Notifications Service. However we recommend you to leave it enabled to keep app running in background and receive instant notifications.</string>
<!--media view-->
<string name="NoMedia">No hay fotos ni vídeos compartidos aún</string>
......
......@@ -265,6 +265,8 @@
<string name="IncorrectLocalization">File della localizzazione non valido</string>
<string name="Enabled">Enabled</string>
<string name="Disabled">Disabled</string>
<string name="NotificationsService">Notifications Service</string>
<string name="NotificationsServiceDisableInfo">If google play services are enough for you to receive notifications, you can disable Notifications Service. However we recommend you to leave it enabled to keep app running in background and receive instant notifications.</string>
<!--media view-->
<string name="NoMedia">Nessun media condiviso</string>
......
......@@ -265,6 +265,8 @@
<string name="IncorrectLocalization">Ongeldig vertalingsbestand</string>
<string name="Enabled">Enabled</string>
<string name="Disabled">Disabled</string>
<string name="NotificationsService">Notifications Service</string>
<string name="NotificationsServiceDisableInfo">If google play services are enough for you to receive notifications, you can disable Notifications Service. However we recommend you to leave it enabled to keep app running in background and receive instant notifications.</string>
<!--media view-->
<string name="NoMedia">Nog geen media gedeeld</string>
......
......@@ -265,6 +265,8 @@
<string name="IncorrectLocalization">Incorrect localization file</string>
<string name="Enabled">Enabled</string>
<string name="Disabled">Disabled</string>
<string name="NotificationsService">Notifications Service</string>
<string name="NotificationsServiceDisableInfo">If google play services are enough for you to receive notifications, you can disable Notifications Service. However we recommend you to leave it enabled to keep app running in background and receive instant notifications.</string>
<!--media view-->
<string name="NoMedia">No shared media yet</string>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment