Commit 93a78f34 authored by axet's avatar axet 🍄

Merge branch 'smsgate-1.8.20'

parents a39fb2a8 89ec11e2
Pipeline #20864194 passed with stage
in 19 seconds
......@@ -8,8 +8,8 @@ android {
applicationId "com.github.axet.smsgate"
minSdkVersion 9
targetSdkVersion 23
versionCode 203
versionName "1.8.19"
versionCode 204
versionName "1.8.20"
}
packagingOptions {
exclude 'META-INF/LICENSE'
......@@ -39,7 +39,7 @@ android {
dependencies {
testImplementation 'junit:junit:4.12'
implementation 'com.github.axet:android-library:1.22.7' // implementation project(':android-library')
implementation 'com.github.axet:android-library:1.24.10' // implementation project(':android-library')
implementation 'com.android.support:design:25.3.1'
implementation 'com.intellij:annotations:12.0'
implementation 'com.beetstra.jutf7:jutf7:1.0.0'
......
......@@ -207,13 +207,6 @@
<activity
android:name=".activities.SendSMS"
android:exported="true" />
<activity
android:name=".activities.Reboot"
android:exported="true" />
<activity
android:name=".activities.DisableOwner"
android:exported="true"
android:theme="@style/AppThemeDark.NoActionBar" />
<!-- Service that delivers messages from the phone "quick response" -->
<service
......@@ -260,7 +253,8 @@
</intent-filter>
</service>
<service android:name=".services.CommandsService"></service>
<service android:name=".services.CommandsService" />
<service android:name="com.github.axet.androidlibrary.services.WifiKeepService"/>
<service
android:name=".services.NotificationService"
......@@ -288,7 +282,7 @@
android:grantUriPermissions="true"></provider>
<receiver
android:name=".services.DeviceAdmin"
android:name="com.github.axet.androidlibrary.services.DeviceAdmin"
android:description="@string/app_description"
android:label="@string/app_name"
android:permission="android.permission.BIND_DEVICE_ADMIN">
......@@ -297,6 +291,8 @@
android:resource="@xml/device_admin" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
<action android:name="android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED" />
<action android:name="android.intent.action.REBOOT" />
</intent-filter>
</receiver>
</application>
......
package com.github.axet.smsgate.activities;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import com.github.axet.smsgate.app.MainApplication;
/**
* am start -n com.github.axet.smsgate/.activities.DisableOwner
*/
public class DisableOwner extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Dialog d = new AlertDialog.Builder(this)
.setTitle("Disable Device Owner")
.setMessage("Are you sure?")
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
MainApplication.removeDeviceOwner(DisableOwner.this);
finish();
}
})
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
finish();
}
})
.create();
d.show();
}
}
......@@ -7,7 +7,6 @@ import android.content.Intent;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.design.widget.AppBarLayout;
......@@ -26,16 +25,14 @@ import android.widget.LinearLayout;
import android.widget.Toast;
import com.github.axet.androidlibrary.app.Storage;
import com.github.axet.androidlibrary.widgets.OptimizationPreferenceCompat;
import com.github.axet.smsgate.R;
import com.github.axet.smsgate.app.MainApplication;
import com.github.axet.smsgate.dialogs.RebootDialogFragment;
import com.github.axet.smsgate.dialogs.ShareDialogFragment;
import com.github.axet.smsgate.dialogs.ShareIncomingFragment;
import com.github.axet.smsgate.fragments.SchedulersFragment;
import com.github.axet.smsgate.fragments.SettingsFragment;
import com.github.axet.smsgate.services.NotificationListener;
import com.github.axet.smsgate.services.NotificationService;
import com.github.axet.smsgate.services.ScheduleService;
import com.github.axet.smsgate.services.OnBootReceiver;
import com.github.axet.smsgate.widgets.ViewPagerDisabled;
import com.zegoggles.smssync.activity.SMSGateFragment;
......@@ -105,16 +102,12 @@ public class MainActivity extends AppCompatActivity implements DialogInterface.O
setContentView(R.layout.activity_main);
if (OptimizationPreferenceCompat.needKillWarning(this, MainApplication.PREF_NEXT))
OptimizationPreferenceCompat.buildKilledWarning(this, true).show();
intent(getIntent());
SMSGateFragment.checkPermissions(this);
ScheduleService.start(this);
if (Build.VERSION.SDK_INT >= 18) {
NotificationListener.startIfEnabled(this);
}
NotificationService.startIfEnabled(this);
RebootDialogFragment.schedule(this);
MainApplication.wifi(this);
OnBootReceiver.main(this);
// Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
// setSupportActionBar(toolbar);
......@@ -129,10 +122,6 @@ public class MainActivity extends AppCompatActivity implements DialogInterface.O
tabLayout = (TabLayout) findViewById(R.id.tabs);
setupTabs();
// if (OptimizationPreferenceCompat.needWarning(this)) {
// OptimizationPreferenceCompat.showWarning(this);
// }
}
@Override
......
package com.github.axet.smsgate.activities;
import android.app.Activity;
import android.os.Bundle;
import com.github.axet.smsgate.app.MainApplication;
/**
* am start -n com.github.axet.smsgate/.activities.Reboot
*/
public class Reboot extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MainApplication.reboot(this);
finish();
}
}
package com.github.axet.smsgate.app;
import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.app.Notification;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.DhcpInfo;
import android.net.NetworkInfo;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Handler;
import android.support.v7.preference.PreferenceManager;
import android.util.Log;
import android.widget.Toast;
import com.fsck.k9.mail.Address;
import com.fsck.k9.mail.Message;
import com.fsck.k9.mail.internet.MimeMessage;
import com.fsck.k9.mail.internet.TextBody;
import com.github.axet.androidlibrary.app.AlarmManager;
import com.github.axet.androidlibrary.app.SuperUser;
import com.github.axet.androidlibrary.crypto.Bitcoin;
import com.github.axet.androidlibrary.services.FileProvider;
import com.github.axet.smsgate.providers.SIM;
import com.github.axet.smsgate.services.CommandsService;
import com.github.axet.smsgate.services.DeviceAdmin;
import com.github.axet.smsgate.services.FirebaseService;
import com.github.axet.smsgate.services.NotificationService;
import com.github.axet.smsgate.widgets.ApplicationsPreference;
......@@ -47,8 +34,6 @@ import org.json.JSONObject;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
......@@ -68,6 +53,8 @@ public class MainApplication extends App {
public static final String PREF_WIFI = "wifi_only";
public static final String PREF_ADMIN = "admin";
public static final String PREF_OPTIMIZATION = "optimization";
public static final String PREF_OPTIMIZATION_WARNING = "optimization_warning";
public static final String PREF_NEXT = "next";
public static final String PREF_DEFAULTSMS = "defaultsms";
public static final String PREF_FIREBASESETTINGS = "firebase_settings";
public static final String PREF_REBOOT = "reboot";
......@@ -76,8 +63,6 @@ public class MainApplication extends App {
public static final String APPS_INDEX = "APPS_";
public static final String APPS_COUNT = "APPS_COUNT";
public static final String BIN_PING = SuperUser.which("ping");
public static final String APP_FROM = "from";
public static final String APP_SUBJ = "subject";
public static final String APP_BODY = "body";
......@@ -138,7 +123,6 @@ public class MainApplication extends App {
@Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT >= 11) {
keyPair = new Bitcoin(); // min API11+ EC KeyFactory
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
......@@ -206,151 +190,6 @@ public class MainApplication extends App {
edit.commit();
}
@TargetApi(24)
public static void removeDeviceOwner(Context context) {
DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
if (dpm.isProfileOwnerApp(context.getPackageName())) {
ComponentName c = new ComponentName(context, DeviceAdmin.class);
dpm.clearProfileOwner(c);
}
if (dpm.isDeviceOwnerApp(context.getPackageName())) {
dpm.clearDeviceOwnerApp(context.getPackageName());
}
}
// adb shell dpm set-device-owner com.github.axet.smsgate/.services.DeviceAdmin
public static void reboot(Context context) {
if (Build.VERSION.SDK_INT >= 24) {
DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName c = new ComponentName(context, DeviceAdmin.class);
if (dpm.isDeviceOwnerApp(context.getPackageName())) {
dpm.reboot(c);
return;
}
}
SuperUser.Result r = SuperUser.reboot();
if (!r.ok()) {
Log.d(TAG, "Unable reboot: " + r.message(), r.e);
Toast.makeText(context, r.message(), Toast.LENGTH_SHORT).show();
}
}
public static void wipe(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean w = prefs.getBoolean(PREF_ADMIN, false);
DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName c = new ComponentName(context, DeviceAdmin.class);
if (w && dpm.isAdminActive(c)) {
dpm.wipeData(DevicePolicyManager.WIPE_EXTERNAL_STORAGE);
}
}
public static void lock(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean w = prefs.getBoolean(PREF_ADMIN, false);
DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName c = new ComponentName(context, DeviceAdmin.class);
if (w && dpm.isAdminActive(c)) {
dpm.lockNow();
}
}
public static boolean ping(String ip) {
Runtime runtime = Runtime.getRuntime();
try {
Process mIpAddrProcess = runtime.exec(BIN_PING + " -q -c1 -w2 " + ip);
int mExitValue = mIpAddrProcess.waitFor();
if (mExitValue == 0) {
return true;
} else {
return false;
}
} catch (InterruptedException ignore) {
Thread.currentThread().interrupt();
} catch (IOException e) {
Log.d(TAG, "ping failed", e);
}
return false;
}
public static boolean ping(int ip) {
String ipStr = String.format("%d.%d.%d.%d", (ip & 0xff), (ip >> 8 & 0xff), (ip >> 16 & 0xff), (ip >> 24 & 0xff));
return ping(ipStr);
}
public static boolean dns() {
InetAddress a = null;
try {
a = InetAddress.getByName("google.com");
} catch (UnknownHostException e) {
}
return a != null && !a.equals("");
}
// https://forum.fairphone.com/t/help-with-xprivacy-settings-relating-to-google-apps/5741/7
public static void gtalk(Context context) {
ComponentName gtalk = new ComponentName("com.google.android.gsf", "com.google.android.gsf.gtalkservice.service.GTalkService");
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (gtalk.compareTo(service.service) == 0) {
return;
}
}
try {
SuperUser.startService(gtalk);
} catch (RuntimeException e) {
Log.d(TAG, "Unable to start gtalk", e);
}
}
public static void wifi(final Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean wifi = prefs.getBoolean(PREF_WIFIRESTART, false);
Intent intent = (new Intent(context, CommandsService.class));
intent.setAction(CommandsService.WIFI);
if (wifi) {
long inSeconds = 1 * 60;
final long next = System.currentTimeMillis() + (inSeconds * 1000l);
AlarmManager.set(context, next, intent);
Thread t = new Thread(new Runnable() {
@Override
public void run() {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
boolean isConnected = false;
boolean isWiFi = false;
if (activeNetwork != null) {
isConnected = activeNetwork.isConnected();
isWiFi = activeNetwork.getType() == ConnectivityManager.TYPE_WIFI;
}
WifiManager w = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
DhcpInfo d = w.getDhcpInfo();
if (!isWiFi || !isConnected || !ping(d.gateway) || !dns()) {
w.setWifiEnabled(false);
w.setWifiEnabled(true);
}
if (Build.VERSION.SDK_INT <= 18 && SuperUser.isRooted()) {
gtalk(context);
}
if (isWiFi && isConnected) {
Intent gt = new Intent("com.google.android.intent.action.GTALK_HEARTBEAT");
context.sendBroadcast(gt);
Intent mcs = new Intent("com.google.android.intent.action.MCS_HEARTBEAT");
context.sendBroadcast(mcs);
}
}
});
t.start();
} else {
AlarmManager.cancel(context, intent);
}
}
public static Uri shareFile(Context context, String type, String name, byte[] buf) {
try {
File outputDir = context.getCacheDir();
......
......@@ -34,6 +34,7 @@ import com.github.axet.smsgate.R;
import com.github.axet.smsgate.app.MainApplication;
import com.github.axet.smsgate.app.ScheduleTime;
import com.github.axet.smsgate.services.CommandsService;
import com.github.axet.androidlibrary.services.DeviceAdmin;
import java.util.Calendar;
......@@ -135,7 +136,7 @@ public class RebootDialogFragment extends DialogFragment {
builder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
MainApplication.reboot(getContext());
DeviceAdmin.reboot(getContext());
}
});
builder.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
......
......@@ -4,13 +4,12 @@ import android.app.IntentService;
import android.content.Intent;
import android.util.Log;
import com.github.axet.smsgate.app.MainApplication;
import com.github.axet.androidlibrary.services.DeviceAdmin;
public class CommandsService extends IntentService {
public static final String TAG = CommandsService.class.getSimpleName();
public static final String REBOOT = CommandsService.class.getCanonicalName() + ".REBOOT";
public static final String WIFI = CommandsService.class.getCanonicalName() + ".WIFI";
public CommandsService() {
super(CommandsService.class.getSimpleName());
......@@ -28,10 +27,7 @@ public class CommandsService extends IntentService {
Log.d(TAG, "onStartCommand " + action);
if (action != null) {
if (action.equals(REBOOT)) {
MainApplication.reboot(this);
}
if (action.equals(WIFI)) {
MainApplication.wifi(this);
DeviceAdmin.reboot(this);
}
}
} else {
......
package com.github.axet.smsgate.services;
import android.app.admin.DeviceAdminReceiver;
public class DeviceAdmin extends DeviceAdminReceiver {
}
......@@ -20,10 +20,7 @@ import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.net.wifi.SupplicantState;
import android.net.wifi.WifiManager;
import android.os.BatteryManager;
import android.os.Build;
import android.os.Bundle;
......@@ -47,6 +44,8 @@ import android.widget.RemoteViews;
import android.widget.Toast;
import com.github.axet.androidlibrary.crypto.Bitcoin;
import com.github.axet.androidlibrary.services.DeviceAdmin;
import com.github.axet.androidlibrary.services.WifiReceiver;
import com.github.axet.smsgate.R;
import com.github.axet.smsgate.activities.MainActivity;
import com.github.axet.smsgate.app.MainApplication;
......@@ -143,7 +142,7 @@ public class FirebaseService extends Service implements FirebaseAuth.AuthStateLi
HashMap<String, Command> commands = new HashMap<>();
BroadcastReceiver receiver;
BroadcastReceiver wifiReciver;
WifiReceiver wifiReciver;
MyPhoneStateListener phone;
......@@ -151,7 +150,7 @@ public class FirebaseService extends Service implements FirebaseAuth.AuthStateLi
commands.put("reboot", new Command() {
@Override
public void run(JSONObject obj) {
MainApplication.reboot(FirebaseService.this);
DeviceAdmin.reboot(FirebaseService.this);
}
});
commands.put("refresh", new Command() {
......@@ -220,13 +219,13 @@ public class FirebaseService extends Service implements FirebaseAuth.AuthStateLi
commands.put("wipe", new Command() {
@Override
public void run(JSONObject obj) {
MainApplication.wipe(FirebaseService.this);
DeviceAdmin.wipe(FirebaseService.this);
}
});
commands.put("lock", new Command() {
@Override
public void run(JSONObject obj) {
MainApplication.lock(FirebaseService.this);
DeviceAdmin.lock(FirebaseService.this);
}
});
}
......@@ -769,17 +768,6 @@ public class FirebaseService extends Service implements FirebaseAuth.AuthStateLi
return prefs.getBoolean(MainApplication.PREF_FIREBASE, false);
}
public static boolean isConnectedWifi(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
if (activeNetwork != null) { // connected to the internet
if (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI) {
return true;
}
}
return false;
}
public static boolean connected() {
FirebaseAuth mFirebaseAuth = FirebaseAuth.getInstance();
return mFirebaseAuth.getCurrentUser() != null;
......@@ -813,71 +801,23 @@ public class FirebaseService extends Service implements FirebaseAuth.AuthStateLi
ff.addAction(NOTIFICATION);
registerReceiver(receiver, ff);
boolean wifi = prefs.getBoolean(MainApplication.PREF_WIFI, false);
wifiReciver = new WifiReceiver(this) {
@Override
public void resume() {
FirebaseService.this.resume();
}
if (wifi && !isConnectedWifi(this)) {
pause();
}
@Override
public void pause() {
FirebaseService.this.pause();
}
IntentFilter wifiFilter = new IntentFilter();
wifiFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
wifiFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
wifiReciver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
boolean wifi = prefs.getBoolean(MainApplication.PREF_WIFI, false);
final String action = intent.getAction();
Log.d(TAG, intent.toString() + " " + action);
if (action.equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)) {
SupplicantState state = intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE);
if (wifi) { // suplicant only correspond to 'wifi only'
if (intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, false)) {
resume();
return;
}
if (isConnectedWifi(context)) { // maybe 'state' have incorrect state. check system service additionaly.
resume();
return;
}
pause();
return;
}
}
if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
NetworkInfo state = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
if (state.isConnected()) {
if (wifi) { // wifi only?
switch (state.getType()) {
case ConnectivityManager.TYPE_WIFI:
case ConnectivityManager.TYPE_ETHERNET:
resume();
return;
}
} else { // resume for any connection type
resume();
return;
}
}
// if not state.isConnected() maybe it is not correct, check service information
if (wifi) {
if (isConnectedWifi(context)) {
resume();
return;
}
} else {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
if (activeNetwork != null) { // connected to the internet
resume();
return;
}
}
pause();
return;
}
public boolean getWifi() {
return prefs.getBoolean(MainApplication.PREF_WIFI, false);
}
};
registerReceiver(wifiReciver, wifiFilter);
wifiReciver.create();
}
void create() {
......@@ -911,6 +851,8 @@ public class FirebaseService extends Service implements FirebaseAuth.AuthStateLi
};
connected.addValueEventListener(connectedList);
Log.d(TAG, "connect to " + keyPair.getAddress());
user = db.getReference().child("/users/" + keyPair.getAddress());
shares = user.child("shares");
notifications = user.child("notifications");
......@@ -1019,7 +961,7 @@ public class FirebaseService extends Service implements FirebaseAuth.AuthStateLi
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean wifi = prefs.getBoolean(MainApplication.PREF_WIFI, false);
if (wifi) {
return !isConnectedWifi(context);
return !WifiReceiver.isConnectedWifi(context);
} else {
return false;
}
......@@ -1222,8 +1164,13 @@ public class FirebaseService extends Service implements FirebaseAuth.AuthStateLi
public void incoming() {
final Runnable run = new Runnable() {
int count = 0;
@Override
public void run() {
count++;
if (count > 60)
return;
if (messages() == 0) { // we expect message. not yet here? retry
handler.postDelayed(this, 1000);
}
......
......@@ -18,9 +18,12 @@ package com.github.axet.smsgate.services;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.preference.PreferenceManager;
import android.util.Log;
import com.github.axet.androidlibrary.services.WifiKeepService;
import com.github.axet.smsgate.app.MainApplication;
import com.github.axet.smsgate.dialogs.RebootDialogFragment;
import com.zegoggles.smssync.activity.SMSGateFragment;
......@@ -37,20 +40,26 @@ public class OnBootReceiver extends BroadcastReceiver {
}
public static void start(Context context) {
SMSGateFragment.checkPermissions(context);
ScheduleService.start(context);
main(context);
fragment(context);
}
FirebaseService.startIfEnabled(context);
public static void main(Context context) {
SharedPreferences shared = PreferenceManager.getDefaultSharedPreferences(context);
if (Build.VERSION.SDK_INT >= 18) {
SMSGateFragment.checkPermissions(context);
ScheduleService.start(context);
if (Build.VERSION.SDK_INT >= 18)
NotificationListener.startIfEnabled(context);
}
NotificationService.startIfEnabled(context);
RebootDialogFragment.schedule(context);
WifiKeepService.startIfEnabled(context, shared.getBoolean(MainApplication.PREF_WIFIRESTART, false));
}
public static void fragment(Context context) {
SMSGateFragment.checkPermissions(context);
FirebaseService.startIfEnabled(context);
SmsReplyService.startIfEnabled(context);
SmsBackupService.