/* * This is the source code of Telegram for Android v. 5.x.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-2018. */ package org.telegram.messenger; import android.annotation.SuppressLint; import android.app.Activity; import android.app.Application; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.res.Configuration; import android.net.ConnectivityManager; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.os.Build; import android.os.Environment; import android.os.Handler; import android.os.PowerManager; import android.os.SystemClock; import android.telephony.TelephonyManager; import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.multidex.MultiDex; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GooglePlayServicesUtil; import org.json.JSONObject; import org.telegram.messenger.fakepasscode.FakePasscodeUtils; import org.telegram.messenger.fakepasscode.RemoveAfterReadingMessages; import org.telegram.messenger.partisan.appmigration.AppMigrator; import org.telegram.messenger.partisan.update.UpdateData; import org.telegram.messenger.voip.VideoCapturerDevice; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.Adapters.DrawerLayoutAdapter; import org.telegram.ui.Components.ForegroundDetector; import org.telegram.ui.Components.Premium.boosts.BoostRepository; import org.telegram.ui.IUpdateButton; import org.telegram.ui.IUpdateLayout; import org.telegram.ui.LauncherIconController; import java.io.BufferedWriter; import java.io.File; import java.util.ArrayList; import java.io.FileWriter; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Locale; public class ApplicationLoader extends Application { public static ApplicationLoader applicationLoaderInstance; @SuppressLint("StaticFieldLeak") public static volatile Context applicationContext; public static volatile NetworkInfo currentNetworkInfo; public static volatile Handler applicationHandler; private static ConnectivityManager connectivityManager; private static volatile boolean applicationInited = false; private static volatile ConnectivityManager.NetworkCallback networkCallback; private static long lastNetworkCheckTypeTime; private static int lastKnownNetworkType = -1; public static long startTime; public static volatile boolean isScreenOn = false; public static volatile boolean mainInterfacePaused = true; public static volatile boolean mainInterfaceStopped = true; public static volatile boolean externalInterfacePaused = true; public static volatile boolean mainInterfacePausedStageQueue = true; public static boolean canDrawOverlays; public static volatile long mainInterfacePausedStageQueueTime; private static PushListenerController.IPushListenerServiceProvider pushProvider; private static IMapsProvider mapsProvider; private static ILocationServiceProvider locationServiceProvider; private static boolean filesCopiedFromUpdater; @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); MultiDex.install(this); } public static ILocationServiceProvider getLocationServiceProvider() { if (locationServiceProvider == null) { locationServiceProvider = applicationLoaderInstance.onCreateLocationServiceProvider(); locationServiceProvider.init(applicationContext); } return locationServiceProvider; } protected ILocationServiceProvider onCreateLocationServiceProvider() { return new GoogleLocationProvider(); } public static IMapsProvider getMapsProvider() { if (mapsProvider == null) { mapsProvider = applicationLoaderInstance.onCreateMapsProvider(); } return mapsProvider; } protected IMapsProvider onCreateMapsProvider() { return new GoogleMapsProvider(); } public static PushListenerController.IPushListenerServiceProvider getPushProvider() { if (pushProvider == null) { pushProvider = applicationLoaderInstance.onCreatePushProvider(); } return pushProvider; } protected PushListenerController.IPushListenerServiceProvider onCreatePushProvider() { return PushListenerController.GooglePushListenerServiceProvider.INSTANCE; } public static String getApplicationId() { return applicationLoaderInstance.onGetApplicationId(); } protected String onGetApplicationId() { return null; } public static boolean isHuaweiStoreBuild() { return applicationLoaderInstance.isHuaweiBuild(); } // This method actually returns whether the application should look like a standalone app public static boolean isStandaloneBuild() { return applicationLoaderInstance.isStandalone(); } protected boolean isHuaweiBuild() { return false; } private Boolean standaloneApp; protected boolean isStandalone() { if (!FakePasscodeUtils.isFakePasscodeActivated()) { return true; } if (standaloneApp == null) { standaloneApp = ApplicationLoader.applicationContext != null && isRealBuildStandaloneBuild(); } return standaloneApp; } public static boolean isRealBuildStandaloneBuild() { List standalonePackageNames = Arrays.asList("org.telegram.messenger.web", "org.telegram.messenger.alpha"); String appPackageName = ApplicationLoader.applicationContext.getPackageName(); return standalonePackageNames.stream().anyMatch(name -> name.equals(appPackageName)); } public static File getFilesDirFixed() { for (int a = 0; a < 10; a++) { File path = ApplicationLoader.applicationContext.getFilesDir(); if (path != null) { return path; } } try { ApplicationInfo info = applicationContext.getApplicationInfo(); File path = new File(info.dataDir, "files"); path.mkdirs(); return path; } catch (Exception e) { FileLog.e(e); } return new File("/data/data/org.telegram.messenger/files"); } public static void postInitApplication() { if (applicationInited || applicationContext == null) { return; } applicationInited = true; NativeLoader.initNativeLibs(ApplicationLoader.applicationContext); try { LocaleController.getInstance(); //TODO improve } catch (Exception e) { e.printStackTrace(); } try { connectivityManager = (ConnectivityManager) ApplicationLoader.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE); BroadcastReceiver networkStateReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { try { currentNetworkInfo = connectivityManager.getActiveNetworkInfo(); } catch (Throwable ignore) { } boolean isSlow = isConnectionSlow(); for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { ConnectionsManager.getInstance(a).checkConnection(); FileLoader.getInstance(a).onNetworkChanged(isSlow); } } }; IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); ApplicationLoader.applicationContext.registerReceiver(networkStateReceiver, filter); } catch (Exception e) { e.printStackTrace(); } try { final IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON); filter.addAction(Intent.ACTION_SCREEN_OFF); final BroadcastReceiver mReceiver = new ScreenReceiver(); applicationContext.registerReceiver(mReceiver, filter); } catch (Exception e) { e.printStackTrace(); } try { PowerManager pm = (PowerManager) ApplicationLoader.applicationContext.getSystemService(Context.POWER_SERVICE); isScreenOn = pm.isScreenOn(); if (BuildVars.LOGS_ENABLED) { FileLog.d("screen state = " + isScreenOn); } } catch (Exception e) { e.printStackTrace(); } SharedConfig.loadConfig(); SharedPrefsHelper.init(applicationContext); checkFiledCopiedFromOldTelegram(); if (SharedConfig.saveLogcatAfterRestart) { saveLogcatFile(); } RemoveAfterReadingMessages.runChecker(); for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { //TODO improve account UserConfig.getInstance(a).loadConfig(); MessagesController.getInstance(a); if (a == 0) { SharedConfig.pushStringStatus = "__FIREBASE_GENERATING_SINCE_" + ConnectionsManager.getInstance(a).getCurrentTime() + "__"; } else { ConnectionsManager.getInstance(a); } TLRPC.User user = UserConfig.getInstance(a).getCurrentUser(); if (user != null) { MessagesController.getInstance(a).putUser(user, true); SendMessagesHelper.getInstance(a).checkUnsentMessages(); } } FakePasscodeUtils.autoAddHidingsToAllFakePasscodes(); ApplicationLoader app = (ApplicationLoader) ApplicationLoader.applicationContext; app.initPushServices(); if (BuildVars.LOGS_ENABLED) { FileLog.d("app initied"); } MediaController.getInstance(); for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { //TODO improve account ContactsController.getInstance(a).checkAppAccount(); DownloadController.getInstance(a); } BillingController.getInstance().startConnection(); } private static void checkFiledCopiedFromOldTelegram() { if (filesCopiedFromUpdater && !SharedConfig.filesCopiedFromOldTelegram) { SharedConfig.filesCopiedFromOldTelegram = true; applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE).edit() .remove("ptgMigrationStep") .remove("ptgMigrationMaxCancelledInstallationDate") .remove("migratedPackageName") .remove("migratedDate") .apply(); SharedConfig.saveConfig(); SharedConfig.reloadConfig(); } } public ApplicationLoader() { super(); } @Override public void onCreate() { File updaterFilesCopied = new File(getFilesDir(), "updater_files_copied"); if (updaterFilesCopied.exists()) { if (copyUpdaterDirectory("shared_prefs") | copyUpdaterDirectory("files")) { filesCopiedFromUpdater = true; } updaterFilesCopied.delete(); } applicationLoaderInstance = this; try { applicationContext = getApplicationContext(); } catch (Throwable ignore) { } super.onCreate(); if (BuildVars.LOGS_ENABLED) { FileLog.d("app start time = " + (startTime = SystemClock.elapsedRealtime())); try { final PackageInfo info = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0); final String abi; switch (info.versionCode % 10) { case 1: case 2: abi = "store bundled " + Build.CPU_ABI + " " + Build.CPU_ABI2; break; default: case 9: if (ApplicationLoader.isStandaloneBuild()) { abi = "direct " + Build.CPU_ABI + " " + Build.CPU_ABI2; } else { abi = "universal " + Build.CPU_ABI + " " + Build.CPU_ABI2; } break; } FileLog.d("buildVersion = " + String.format(Locale.US, "v%s (%d[%d]) %s", info.versionName, info.versionCode / 10, info.versionCode % 10, abi)); } catch (Exception e) { FileLog.e(e); } FileLog.d("device = manufacturer=" + Build.MANUFACTURER + ", device=" + Build.DEVICE + ", model=" + Build.MODEL + ", product=" + Build.PRODUCT); } if (applicationContext == null) { applicationContext = getApplicationContext(); } NativeLoader.initNativeLibs(ApplicationLoader.applicationContext); try { ConnectionsManager.native_setJava(false); } catch (UnsatisfiedLinkError error) { throw new RuntimeException("can't load native libraries " + Build.CPU_ABI + " lookup folder " + NativeLoader.getAbiFolder()); } new ForegroundDetector(this) { @Override public void onActivityStarted(Activity activity) { boolean wasInBackground = isBackground(); super.onActivityStarted(activity); if (wasInBackground) { ensureCurrentNetworkGet(true); } } }; if (BuildVars.LOGS_ENABLED) { FileLog.d("load libs time = " + (SystemClock.elapsedRealtime() - startTime)); } applicationHandler = new Handler(applicationContext.getMainLooper()); AndroidUtilities.runOnUIThread(ApplicationLoader::startPushService); LauncherIconController.tryFixLauncherIconIfNeeded(); ProxyRotationController.init(); } private static void saveLogcatFile() { File downloads = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); File logs = new File(downloads, "logs"); logs.mkdirs(); File logcatFile = new File(logs, "Telegram logcat " + new SimpleDateFormat("yyyy-MM-dd HH.mm.ss.SSS").format(new Date()) + ".txt"); if (logcatFile.exists()) { logcatFile.delete(); } try { FileWriter fileWriter = new FileWriter(logcatFile); BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); String logcat = Utilities.readLogcat(); bufferedWriter.write(logcat); bufferedWriter.close(); fileWriter.close(); } catch (Exception e) { e.printStackTrace(); } } public static void startPushService() { SharedPreferences preferences = MessagesController.getGlobalNotificationsSettings(); boolean enabled; if (preferences.contains("pushService")) { enabled = preferences.getBoolean("pushService", true); } else { enabled = MessagesController.getMainSettings(UserConfig.selectedAccount).getBoolean("keepAliveService", false); } if (enabled) { try { applicationContext.startService(new Intent(applicationContext, NotificationsService.class)); } catch (Throwable ignore) { } } else { applicationContext.stopService(new Intent(applicationContext, NotificationsService.class)); } } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); try { LocaleController.getInstance().onDeviceConfigurationChange(newConfig); AndroidUtilities.checkDisplaySize(applicationContext, newConfig); VideoCapturerDevice.checkScreenCapturerSize(); AndroidUtilities.resetTabletFlag(); } catch (Exception e) { e.printStackTrace(); } } private void initPushServices() { AndroidUtilities.runOnUIThread(() -> { if (getPushProvider().hasServices()) { getPushProvider().onRequestPushToken(); } else { if (BuildVars.LOGS_ENABLED) { FileLog.d("No valid " + getPushProvider().getLogTitle() + " APK found."); } SharedConfig.pushStringStatus = "__NO_GOOGLE_PLAY_SERVICES__"; PushListenerController.sendRegistrationToServer(getPushProvider().getPushType(), null); } }, 1000); } private boolean checkPlayServices() { try { int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this); return resultCode == ConnectionResult.SUCCESS; } catch (Exception e) { FileLog.e(e); } return true; } private static long lastNetworkCheck = -1; private static void ensureCurrentNetworkGet() { final long now = System.currentTimeMillis(); ensureCurrentNetworkGet(now - lastNetworkCheck > 5000); lastNetworkCheck = now; } private static void ensureCurrentNetworkGet(boolean force) { if (force || currentNetworkInfo == null) { try { if (connectivityManager == null) { connectivityManager = (ConnectivityManager) ApplicationLoader.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE); } currentNetworkInfo = connectivityManager.getActiveNetworkInfo(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { if (networkCallback == null) { networkCallback = new ConnectivityManager.NetworkCallback() { @Override public void onAvailable(@NonNull Network network) { lastKnownNetworkType = -1; } @Override public void onCapabilitiesChanged(@NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) { lastKnownNetworkType = -1; } }; connectivityManager.registerDefaultNetworkCallback(networkCallback); } } } catch (Throwable ignore) { } } } public static boolean isRoaming() { try { ensureCurrentNetworkGet(false); return currentNetworkInfo != null && currentNetworkInfo.isRoaming(); } catch (Exception e) { FileLog.e(e); } return false; } public static boolean isConnectedOrConnectingToWiFi() { try { ensureCurrentNetworkGet(false); if (currentNetworkInfo != null && (currentNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI || currentNetworkInfo.getType() == ConnectivityManager.TYPE_ETHERNET)) { NetworkInfo.State state = currentNetworkInfo.getState(); if (state == NetworkInfo.State.CONNECTED || state == NetworkInfo.State.CONNECTING || state == NetworkInfo.State.SUSPENDED) { return true; } } } catch (Exception e) { FileLog.e(e); } return false; } public static boolean isConnectedToWiFi() { try { ensureCurrentNetworkGet(false); if (currentNetworkInfo != null && (currentNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI || currentNetworkInfo.getType() == ConnectivityManager.TYPE_ETHERNET) && currentNetworkInfo.getState() == NetworkInfo.State.CONNECTED) { return true; } } catch (Exception e) { FileLog.e(e); } return false; } public static boolean isConnectionSlow() { try { ensureCurrentNetworkGet(false); if (currentNetworkInfo != null && currentNetworkInfo.getType() == ConnectivityManager.TYPE_MOBILE) { switch (currentNetworkInfo.getSubtype()) { case TelephonyManager.NETWORK_TYPE_1xRTT: case TelephonyManager.NETWORK_TYPE_CDMA: case TelephonyManager.NETWORK_TYPE_EDGE: case TelephonyManager.NETWORK_TYPE_GPRS: case TelephonyManager.NETWORK_TYPE_IDEN: return true; } } } catch (Throwable ignore) { } return false; } public static int getAutodownloadNetworkType() { try { ensureCurrentNetworkGet(false); if (currentNetworkInfo == null) { return StatsController.TYPE_MOBILE; } if (currentNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI || currentNetworkInfo.getType() == ConnectivityManager.TYPE_ETHERNET) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && (lastKnownNetworkType == StatsController.TYPE_MOBILE || lastKnownNetworkType == StatsController.TYPE_WIFI) && System.currentTimeMillis() - lastNetworkCheckTypeTime < 5000) { return lastKnownNetworkType; } if (connectivityManager.isActiveNetworkMetered()) { lastKnownNetworkType = StatsController.TYPE_MOBILE; } else { lastKnownNetworkType = StatsController.TYPE_WIFI; } lastNetworkCheckTypeTime = System.currentTimeMillis(); return lastKnownNetworkType; } if (currentNetworkInfo.isRoaming()) { return StatsController.TYPE_ROAMING; } } catch (Exception e) { FileLog.e(e); } return StatsController.TYPE_MOBILE; } public static int getCurrentNetworkType() { if (isConnectedOrConnectingToWiFi()) { return StatsController.TYPE_WIFI; } else if (isRoaming()) { return StatsController.TYPE_ROAMING; } else { return StatsController.TYPE_MOBILE; } } public static boolean isNetworkOnlineFast() { try { ensureCurrentNetworkGet(false); if (currentNetworkInfo == null) { return true; } if (currentNetworkInfo.isConnectedOrConnecting() || currentNetworkInfo.isAvailable()) { return true; } NetworkInfo netInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE); if (netInfo != null && netInfo.isConnectedOrConnecting()) { return true; } else { netInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); if (netInfo != null && netInfo.isConnectedOrConnecting()) { return true; } } } catch (Exception e) { FileLog.e(e); return true; } return false; } public static boolean isNetworkOnlineRealtime() { try { ConnectivityManager connectivityManager = (ConnectivityManager) ApplicationLoader.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo netInfo = connectivityManager.getActiveNetworkInfo(); if (netInfo != null && (netInfo.isConnectedOrConnecting() || netInfo.isAvailable())) { return true; } netInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE); if (netInfo != null && netInfo.isConnectedOrConnecting()) { return true; } else { netInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); if (netInfo != null && netInfo.isConnectedOrConnecting()) { return true; } } } catch (Exception e) { FileLog.e(e); return true; } return false; } public static boolean isNetworkOnline() { boolean result = isNetworkOnlineRealtime(); if (BuildVars.DEBUG_PRIVATE_VERSION) { boolean result2 = isNetworkOnlineFast(); if (result != result2) { FileLog.d("network online mismatch"); } } return result; } public static void startAppCenter(Activity context) { applicationLoaderInstance.startAppCenterInternal(context); } public static void checkForUpdates() { applicationLoaderInstance.checkForUpdatesInternal(); } public static void appCenterLog(Throwable e) { applicationLoaderInstance.appCenterLogInternal(e); } protected void appCenterLogInternal(Throwable e) { } protected void checkForUpdatesInternal() { } protected void startAppCenterInternal(Activity context) { } private boolean copyUpdaterDirectory(String name) { File updaterDirectory = new File(getFilesDir(), name); File originalDirectory = new File(getFilesDir().getParentFile(), name); return moveFiles(updaterDirectory, originalDirectory); } private boolean moveFiles(File fromDir, File toDir) { File receivedPrefs = fromDir; if (receivedPrefs.exists()) { for (File child : receivedPrefs.listFiles()) { File file = new File(toDir, child.getName()); if (file.exists()) { deleteFileRecursive(file); } child.renameTo(file); } receivedPrefs.delete(); return true; } else { return false; } } private void deleteFileRecursive(File file) { if (file.isDirectory()) { for (File child : file.listFiles()) { deleteFileRecursive(child); } } file.delete(); } public static void logDualCamera(boolean success, boolean vendor) { applicationLoaderInstance.logDualCameraInternal(success, vendor); } protected void logDualCameraInternal(boolean success, boolean vendor) { } public boolean checkApkInstallPermissions(final Context context) { return false; } public boolean openApkInstall(Activity activity, TLRPC.Document document) { return false; } public boolean showUpdateAppPopup(Context context, UpdateData update, int account) { return false; } public IUpdateLayout takeUpdateLayout(Activity activity, ViewGroup sideMenu, ViewGroup sideMenuContainer) { return null; } public IUpdateButton takeUpdateButton(Context context) { return null; } public TLRPC.Update parseTLUpdate(int constructor) { return null; } public void processUpdate(int currentAccount, TLRPC.Update update) { } public boolean onSuggestionFill(String suggestion, CharSequence[] output, boolean[] closeable) { return false; } public boolean onSuggestionClick(String suggestion) { return false; } public boolean extendDrawer(ArrayList items) { return false; } public boolean checkRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) { return false; } public boolean consumePush(int account, JSONObject json) { return false; } public void onResume() { } public boolean onPause() { return false; } public BaseFragment openSettings(int n) { return null; } }