package org.fitchfamily.android.gsmlocation; import android.Manifest; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.location.Location; import android.os.Build; import android.os.Looper; import android.support.v4.app.NotificationCompat; import android.support.v4.content.ContextCompat; import android.telephony.CellLocation; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.TelephonyManager; import android.util.Log; import org.androidannotations.annotations.AfterInject; import org.androidannotations.annotations.EService; import org.androidannotations.annotations.SystemService; import org.fitchfamily.android.gsmlocation.ui.MainActivity; import org.fitchfamily.android.gsmlocation.ui.MainActivity_; import org.fitchfamily.android.gsmlocation.util.LocationUtil; import org.microg.nlp.api.LocationBackendService; import java.util.List; import static org.fitchfamily.android.gsmlocation.LogUtils.makeLogTag; @EService public class GsmService extends LocationBackendService { private static final String TAG = makeLogTag("service"); private static final boolean DEBUG = Config.DEBUG; private TelephonyManager tm; private TelephonyHelper th; protected Thread worker = null; private Thread thread; private Context ctx = null; private static final int NOTIFICATION = 42; private boolean permissionNotificationShown = false; @SystemService protected NotificationManager notificationManager; public synchronized void start() { if (DEBUG) Log.i(TAG, "Starting location backend"); ctx = getApplicationContext(); if (hasLocationAccess()) { setShowPermissionNotification(false); setServiceRunning(true); } else { setShowPermissionNotification(true); setServiceRunning(false); } } @Override protected synchronized Location update() { scanGsm("update"); return null; } @Override protected synchronized void onOpen() { if (DEBUG) Log.i(TAG, "Binder OPEN called"); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { Context ctx = getApplicationContext(); if (ctx.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { Intent intent = new Intent(ctx, ReqLocationPermActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(ctx, 0, intent, 0); Notification notification = new Notification.Builder(ctx) .setContentTitle(getString(R.string.app_name)) .setContentText(getString(R.string.notification_location_permission)) .setSmallIcon(R.drawable.icon) .setContentIntent(pendingIntent) .build(); ((NotificationManager) ctx.getSystemService(NOTIFICATION_SERVICE)) .notify(ReqLocationPermActivity.NOTIFICATION_ID, notification); return; } } start(); } protected synchronized void onClose() { if (DEBUG) Log.i(TAG, "Binder CLOSE called"); super.onClose(); setServiceRunning(false); } private boolean hasLocationAccess() { return ContextCompat.checkSelfPermission(ctx, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED; } private void setServiceRunning(boolean st) { final boolean cur_st = (worker != null); if (cur_st == st) return; if (st) { tm = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE); th = new TelephonyHelper(ctx); try { if (worker != null && worker.isAlive()) worker.interrupt(); worker = new Thread() { public void run() { if (DEBUG) Log.i(TAG, "Starting reporter thread"); Looper.prepare(); final PhoneStateListener listener = new PhoneStateListener() { public void onServiceStateChanged(ServiceState serviceState) { scanGsm("onServiceStateChanged: "); } public void onCellLocationChanged(CellLocation location) { scanGsm("onCellLocationChanged: "); } public void onCellInfoChanged(List<android.telephony.CellInfo> cellInfo) { scanGsm("onCellInfoChanged: "); } }; tm.listen( listener, PhoneStateListener.LISTEN_CELL_INFO | PhoneStateListener.LISTEN_CELL_LOCATION | PhoneStateListener.LISTEN_SERVICE_STATE ); Looper.loop(); } }; worker.start(); } catch (Exception e) { if (DEBUG) Log.e(TAG, "Start failed: " + e.getMessage()); e.printStackTrace(); worker = null; } } else { try { if (worker != null && worker.isAlive()) worker.interrupt(); if (worker != null) worker = null; } finally { worker = null; } } } public synchronized void scanGsm(final String calledFrom) { if (thread != null) { if (DEBUG) Log.i(TAG, "scanGsm() : Thread busy?!"); return; } thread = new Thread(new Runnable() { @Override public void run() { Location rslt = th.getLocationEstimate(); String logString; if (rslt != null) { rslt.setTime(System.currentTimeMillis()); logString = "scanGsm(" + calledFrom + ") " + rslt.toString(); } else logString = "scanGsm(" + calledFrom + ") null position"; if (DEBUG) Log.i(TAG, logString); report(rslt); thread = null; } }); thread.start(); } private void setShowPermissionNotification(boolean visible) { if(visible != permissionNotificationShown) { if(visible) { if(DEBUG) { Log.i(TAG, "setShowPermissionNotification(true)"); } notificationManager.notify( NOTIFICATION, new NotificationCompat.Builder(this) .setWhen(0) .setShowWhen(false) .setAutoCancel(false) .setOngoing(true) .setContentIntent( PendingIntent.getActivity( this, 0, MainActivity_.intent(this).action(MainActivity.Action.request_permission).get(), PendingIntent.FLAG_UPDATE_CURRENT ) ) .setContentTitle(getString(R.string.app_name)) .setContentText(getString(R.string.preference_grant_permission)) .setSmallIcon(R.drawable.ic_stat_no_location) .build() ); } else { if(DEBUG) { Log.i(TAG, "setShowPermissionNotification(false)"); } notificationManager.cancel(NOTIFICATION); } permissionNotificationShown = visible; } } }