diff --git a/app/build.gradle b/app/build.gradle index 66cffe2..00d3449 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,16 +1,20 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 27 + compileSdkVersion 28 buildToolsVersion "28.0.3" defaultConfig { applicationId 'com.samebits.beacon.locator' minSdkVersion 18 - targetSdkVersion 27 - versionCode 121 - versionName '1.2.1' + targetSdkVersion 28 + versionCode 122 + versionName '1.2.2' testApplicationId 'com.samebits.beacon.locator.test' } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } buildTypes { release { minifyEnabled false @@ -49,11 +53,10 @@ android { } dependencies { - final SUPPORT_LIBRARY_VERSION = '27.1.1' + final SUPPORT_LIBRARY_VERSION = '28.0.0' final DAGGER_VERSION = '2.11' - implementation fileTree(include: ['*.jar'], dir: 'libs') - api 'org.altbeacon:android-beacon-library:2.15.2' + api 'org.altbeacon:android-beacon-library:2.15.4' implementation "com.android.support:support-v4:$SUPPORT_LIBRARY_VERSION" implementation "com.android.support:support-v13:$SUPPORT_LIBRARY_VERSION" implementation "com.android.support:appcompat-v7:$SUPPORT_LIBRARY_VERSION" @@ -65,7 +68,7 @@ dependencies { implementation "com.google.dagger:dagger:$DAGGER_VERSION" annotationProcessor "com.google.dagger:dagger-compiler:$DAGGER_VERSION" compileOnly 'org.glassfish:javax.annotation:10.0-b28' - implementation 'com.jakewharton:butterknife:8.8.0' - annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.0' + implementation 'com.jakewharton:butterknife:9.0.0-rc3' + annotationProcessor 'com.jakewharton:butterknife-compiler:9.0.0-rc3' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1a3c118..33467d8 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -9,6 +9,8 @@ + + mRegions = new ArrayList<>(); List mBeacons = new ArrayList<>(); - private BackgroundPowerSaver mBackgroundPowerSaver; + BackgroundSwitchWatcher mBackgroundSwitchWatcher; private BeaconManager mBeaconManager; private DataManager mDataManager; private RegionBootstrap mRegionBootstrap; - private LocalBroadcastManager mBroadcaster; + BeaconRegionReceiver mRegionReceiver; + BeaconAlertReceiver mAlertReceiver; + LocationReceiver mLocationReceiver; public static BeaconLocatorApp from(@NonNull Context context) { return (BeaconLocatorApp) context.getApplicationContext(); @@ -81,6 +88,31 @@ public ApplicationComponent getComponent() { return applicationComponent; } + void registerReceivers() { + + mRegionReceiver = new BeaconRegionReceiver(); + mLocationReceiver = new LocationReceiver(); + mAlertReceiver = new BeaconAlertReceiver(); + + LocalBroadcastManager.getInstance(this).registerReceiver( + mRegionReceiver, new IntentFilter( Constants.NOTIFY_BEACON_ENTERS_REGION)); + LocalBroadcastManager.getInstance(this).registerReceiver( + mRegionReceiver, new IntentFilter( Constants.NOTIFY_BEACON_LEAVES_REGION)); + LocalBroadcastManager.getInstance(this).registerReceiver( + mRegionReceiver, new IntentFilter( Constants.NOTIFY_BEACON_NEAR_YOU_REGION)); + + LocalBroadcastManager.getInstance(this).registerReceiver( + mLocationReceiver, new IntentFilter( Constants.GET_CURRENT_LOCATION)); + LocalBroadcastManager.getInstance(this).registerReceiver( + mAlertReceiver, new IntentFilter( Constants.ALARM_NOTIFICATION_SHOW)); + } + + void unregisterReceivers() { + LocalBroadcastManager.getInstance(this).unregisterReceiver( mRegionReceiver ); + LocalBroadcastManager.getInstance(this).unregisterReceiver( mLocationReceiver ); + LocalBroadcastManager.getInstance(this).unregisterReceiver( mAlertReceiver ); + } + @Override public void onCreate() { @@ -93,33 +125,19 @@ public void onCreate() { mBeaconManager = BeaconLocatorApp.from(this).getComponent().beaconManager(); mDataManager = BeaconLocatorApp.from(this).getComponent().dataManager(); - mBroadcaster = LocalBroadcastManager.getInstance(this); + registerReceivers(); initBeaconManager(); - // the ability to continually scan for long periods of time in the background on Andorid 8+ - // in exchange for showing an icon at the top of the screen and a always-on notification to - // communicate to users that your app is using resources in the background. - - if (PreferencesUtil.isForegroundScan(this)) { - Notification.Builder builder = new Notification.Builder(this); - builder.setSmallIcon(R.mipmap.ic_launcher); - builder.setContentTitle(getText(R.string.text_scanning)); - Intent intent = new Intent(this, MainNavigationActivity.class); - PendingIntent pendingIntent = PendingIntent.getActivity( - this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT - ); - builder.setContentIntent(pendingIntent); - mBeaconManager.enableForegroundServiceScanning(builder.build(), 456); - } else { - mBeaconManager.disableForegroundServiceScanning(); - } - enableBackgroundScan(PreferencesUtil.isBackgroundScan(this)); + } + @Override + public void onTerminate() { + unregisterReceivers(); + super.onTerminate(); } private void initBeaconManager() { - mBeaconManager.setBackgroundMode(PreferencesUtil.isBackgroundScan(this)); if (PreferencesUtil.isEddystoneLayoutUID(this)) { mBeaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout(BeaconParser.EDDYSTONE_UID_LAYOUT)); @@ -132,88 +150,124 @@ private void initBeaconManager() { } mBeaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout(BeaconParser.ALTBEACON_LAYOUT)); + //konkakt? mBeaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25")); mBeaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24")); mBeaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("m:0-3=4c000215,i:4-19,i:20-21,i:22-23,p:24-24")); - mBeaconManager.setBackgroundBetweenScanPeriod(PreferencesUtil.getBackgroundScanInterval(this)); + mBeaconManager.setAndroidLScanningDisabled(true); + mBeaconManager.setBackgroundScanPeriod(15000L); + mBeaconManager.setForegroundBetweenScanPeriod(0L); // default is 0L + mBeaconManager.setForegroundScanPeriod(1100L); // Default is 1100L + mBackgroundSwitchWatcher = new BackgroundSwitchWatcher(this); - if (PreferencesUtil.isForegroundScan(this)) { + if (PreferencesUtil.isForegroundScan(this) && PreferencesUtil.isBackgroundScan(this)) { - mBeaconManager.setEnableScheduledScanJobs(false); - mBeaconManager.setBackgroundBetweenScanPeriod(0L); - mBeaconManager.setBackgroundScanPeriod(1100L); + startScanAsForegroundService(); } else { - mBeaconManager.setEnableScheduledScanJobs(true); - mBeaconManager.setBackgroundScanPeriod(10000L); // default is 10000L - mBeaconManager.setForegroundBetweenScanPeriod(0L); // default is 0L - mBeaconManager.setForegroundScanPeriod(1100L); // Default is 1100L - //mBeaconManager.setMaxTrackingAge(10000); - //mBeaconManager.setRegionExitPeriod(18000L); + stopScanAsForegroundService(); } - /* - RangedBeacon.setMaxTrackingAge() only controls the period of time ranged beacons will continue to be - returned after the scanning service stops detecting them. - It has no affect on when monitored regions trigger exits. It is set to 5 seconds by default. + enableBackgroundScan(true); + + } - Monitored regions are exited whenever a scan period finishes and the BeaconManager.setRegionExitPeriod() - has passed since the last detection. - By default, this is 10 seconds, but you can customize it. + private void setScanSettings() { - Using the defaults, the library will stop sending ranging updates five seconds after a beacon was last seen, - and then send a region exit 10 seconds after it was last seen. - You are welcome to change these two settings to meet your needs, but the BeaconManager.setRegionExitPeriod() - should generally be the same or longer than the RangedBeacon.setMaxTrackingAge(). - */ + if (mBeaconManager == null) return; - mBackgroundPowerSaver = new BackgroundPowerSaver(this); - mBeaconManager.addRangeNotifier(this); + mBeaconManager.setBackgroundBetweenScanPeriod(PreferencesUtil.getBackgroundScanInterval(this)); try { if (mBeaconManager.isAnyConsumerBound()) { mBeaconManager.updateScanPeriods(); } } catch (RemoteException e) { - Log.e(Constants.TAG, "update scan periods error", e); + Log.e(Constants.TAG, "Update scan periods error", e); } } + + /** + * Here we switch between scan types when app in the foreground or background + * @param enable yes or no + */ public void enableBackgroundScan(boolean enable) { - if (enable) { - Log.d(Constants.TAG, "Enable Background Scan"); - enableRegions(); - //loadTrackedBeacons(); + + if (mBeaconManager == null) return; + + setScanSettings(); + + boolean backgroundScanEnabled = PreferencesUtil.isBackgroundScan(this); + if (enable && backgroundScanEnabled) { + Log.d(Constants.TAG, "Enable background scan"); + if (enableRegions()) { + mBeaconManager.setBackgroundMode(true); + } else { + Log.i(Constants.TAG, "Background scan is disabled, no cattailer to watch"); + } } else { - Log.d(Constants.TAG, "Disable Background Scan"); + Log.d(Constants.TAG, "Disable background scan"); disableRegions(); + mBeaconManager.setBackgroundMode(false); } } private void disableRegions() { - if (mRegionBootstrap != null) { - mRegionBootstrap.disable(); + if (mRegionBootstrap != null && mRegions != null) { + try { + mRegionBootstrap.disable(); + } catch (Exception e) { + Log.e(Constants.TAG, "Disable Regisons", e); + } } } - /** - * consider to use as a cache of beacons - */ - private void loadTrackedBeacons() { - mBeacons = mDataManager.getAllBeacons(); - } - - private void enableRegions() { + private boolean enableRegions() { mRegions = getAllEnabledRegions(); if (mRegions.size() > 0) { mRegionBootstrap = new RegionBootstrap(this, mRegions); + return true; } else { Log.d(Constants.TAG, "Ignore Background scan, no regions"); } + return false; + } + + public void startScanAsForegroundService() { + + Log.d(Constants.TAG, "Init: Enable as foreground service scan"); + + if (mBeaconManager == null || mBeaconManager.isAnyConsumerBound()) { + Log.w(Constants.TAG, "Cannot start scan in foreground mode, beacon manager is bound"); + return; + } + + NotificationBuilder notificationBuilder = new NotificationBuilder(this); + + PendingIntent notificationIntent = PendingIntent.getActivity(this, 0, + new Intent(this, MainNavigationActivity.class), PendingIntent.FLAG_UPDATE_CURRENT); + + notificationBuilder.createNotificationService(getString(R.string.text_scan_foreground_service), notificationIntent); + + mBeaconManager.enableForegroundServiceScanning(notificationBuilder.getBuilder().build(), Constants.FOREGROUND_NOTIFICATION_ID); + + } + + public void stopScanAsForegroundService() { + + Log.d(Constants.TAG, "Init: Disable as foreground service scan"); + + if (mBeaconManager == null || mBeaconManager.isAnyConsumerBound()) { + Log.w(Constants.TAG, "Cannot stop scan in foreground mode, beacon manager is bound"); + return; + } + + mBeaconManager.disableForegroundServiceScanning(); } public List getAllEnabledRegions() { @@ -244,7 +298,7 @@ public void didEnterRegion(Region region) { Intent intent = new Intent(); intent.setAction(Constants.NOTIFY_BEACON_ENTERS_REGION); intent.putExtra("REGION", (Parcelable)region); - mBroadcaster.sendBroadcast(intent); + LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent); } } } @@ -270,7 +324,7 @@ public void didExitRegion(Region region) { Intent intent = new Intent(); intent.setAction(Constants.NOTIFY_BEACON_LEAVES_REGION); intent.putExtra("REGION", (Parcelable) region); - mBroadcaster.sendBroadcast(intent); } + LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent); } } } @@ -300,7 +354,8 @@ public void didRangeBeaconsInRegion(Collection beacons, Region region) { Intent intent = new Intent(); intent.setAction(Constants.NOTIFY_BEACON_NEAR_YOU_REGION); intent.putExtra("REGION", (Parcelable)region); - mBroadcaster.sendBroadcast(intent); } + LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent); + } } } } diff --git a/app/src/main/java/com/samebits/beacon/locator/receiver/BeaconAlertReceiver.java b/app/src/main/java/com/samebits/beacon/locator/receiver/BeaconAlertReceiver.java index 1fac1e7..db930ed 100644 --- a/app/src/main/java/com/samebits/beacon/locator/receiver/BeaconAlertReceiver.java +++ b/app/src/main/java/com/samebits/beacon/locator/receiver/BeaconAlertReceiver.java @@ -49,18 +49,11 @@ private void createNotification(Context context, String title, String msgText, S PendingIntent notificationIntent = PendingIntent.getActivity(context, 0, new Intent(context, MainNavigationActivity.class), 0); NotificationBuilder notificationBuilder = new NotificationBuilder(context); - notificationBuilder.createNotification(R.mipmap.ic_launcher, title, isVibrate, notificationIntent); + notificationBuilder.createNotification(title, ringtone, isVibrate, notificationIntent); notificationBuilder.setMessage(msgText); notificationBuilder.setTicker(msgAlert); - if (isVibrate) { - notificationBuilder.setVibration(); - } - - if (ringtone != null && ringtone.length() > 0) { - notificationBuilder.setRingtone(ringtone); - } notificationBuilder.show(1); diff --git a/app/src/main/java/com/samebits/beacon/locator/receiver/LocationReceiver.java b/app/src/main/java/com/samebits/beacon/locator/receiver/LocationReceiver.java index ec89e00..dc578b6 100644 --- a/app/src/main/java/com/samebits/beacon/locator/receiver/LocationReceiver.java +++ b/app/src/main/java/com/samebits/beacon/locator/receiver/LocationReceiver.java @@ -75,7 +75,7 @@ public void onReceive(Context context, Intent intent) { PendingIntent notificationIntent = PendingIntent.getActivity(context, 0, mapIntent, PendingIntent.FLAG_UPDATE_CURRENT); NotificationBuilder notificationBuilder = new NotificationBuilder(context); - notificationBuilder.createNotification(R.mipmap.ic_launcher, context.getString(R.string.action_alarm_text_title), true, notificationIntent); + notificationBuilder.createNotification(context.getString(R.string.action_alarm_text_title), null,true, notificationIntent); notificationBuilder.setMessage(context.getString(R.string.notification_display_last_position)); notificationBuilder.show(1); diff --git a/app/src/main/java/com/samebits/beacon/locator/ui/activity/BaseActivity.java b/app/src/main/java/com/samebits/beacon/locator/ui/activity/BaseActivity.java index a6c8e1e..f526cd3 100644 --- a/app/src/main/java/com/samebits/beacon/locator/ui/activity/BaseActivity.java +++ b/app/src/main/java/com/samebits/beacon/locator/ui/activity/BaseActivity.java @@ -28,10 +28,8 @@ import android.view.Menu; import android.view.MenuItem; -import com.samebits.beacon.locator.BeaconLocatorApp; import com.samebits.beacon.locator.R; import com.samebits.beacon.locator.util.Constants; -import com.samebits.beacon.locator.util.PreferencesUtil; /** @@ -39,7 +37,6 @@ */ @SuppressLint("Registered") public class BaseActivity extends AppCompatActivity { - public static int glCount = 0; @Override public boolean onCreateOptionsMenu(Menu menu) { @@ -107,7 +104,6 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { } - protected Fragment checkFragmentInstance(int id, Object instanceClass) { Fragment fragment = getFragmentInstance(id); @@ -129,21 +125,4 @@ protected Fragment getFragmentInstance(int id) { } - @Override - protected void onStart() { - super.onStart(); - glCount++; - if (glCount == 1) { - BeaconLocatorApp.from(this).enableBackgroundScan(false); - } - } - - @Override - protected void onStop() { - super.onStop(); - glCount--; - if (glCount <= 0) { - BeaconLocatorApp.from(this).enableBackgroundScan(PreferencesUtil.isBackgroundScan(this)); - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/samebits/beacon/locator/ui/activity/MainNavigationActivity.java b/app/src/main/java/com/samebits/beacon/locator/ui/activity/MainNavigationActivity.java index 8a10ab8..244aa14 100644 --- a/app/src/main/java/com/samebits/beacon/locator/ui/activity/MainNavigationActivity.java +++ b/app/src/main/java/com/samebits/beacon/locator/ui/activity/MainNavigationActivity.java @@ -25,7 +25,6 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; -import android.content.IntentFilter; import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; @@ -35,7 +34,6 @@ import android.support.design.widget.NavigationView; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; -import android.support.v4.content.LocalBroadcastManager; import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBar; @@ -51,9 +49,6 @@ import com.samebits.beacon.locator.BeaconLocatorApp; import com.samebits.beacon.locator.R; import com.samebits.beacon.locator.model.TrackedBeacon; -import com.samebits.beacon.locator.receiver.BeaconAlertReceiver; -import com.samebits.beacon.locator.receiver.BeaconRegionReceiver; -import com.samebits.beacon.locator.receiver.LocationReceiver; import com.samebits.beacon.locator.ui.fragment.BeaconFragment; import com.samebits.beacon.locator.ui.fragment.DetectedBeaconsFragment; import com.samebits.beacon.locator.ui.fragment.ScanFragment; @@ -61,6 +56,7 @@ import com.samebits.beacon.locator.ui.fragment.TrackedBeaconsFragment; import com.samebits.beacon.locator.util.Constants; import com.samebits.beacon.locator.util.DialogBuilder; +import com.samebits.beacon.locator.util.WhiteListUtils; import org.altbeacon.beacon.BeaconManager; @@ -88,9 +84,6 @@ public class MainNavigationActivity extends BaseActivity BeaconManager mBeaconManager; - BeaconRegionReceiver mRegionReceiver; - BeaconAlertReceiver mAlertReceiver; - LocationReceiver mLocationReceiver; TrackedBeacon mSelectedBeacon; private Unbinder unbinder; @@ -129,9 +122,9 @@ protected void onCreate(Bundle savedInstanceState) { checkPermissions(); verifyBluetooth(); - readExtras(); + WhiteListUtils.startAutoStartActivity(this); - registerReceivers(); + readExtras(); if (null == savedInstanceState) { if (mSelectedBeacon != null) { @@ -143,35 +136,11 @@ protected void onCreate(Bundle savedInstanceState) { } - void registerReceivers() { - - mRegionReceiver = new BeaconRegionReceiver(); - mLocationReceiver = new LocationReceiver(); - mAlertReceiver = new BeaconAlertReceiver(); - - LocalBroadcastManager.getInstance(this).registerReceiver( - mRegionReceiver, new IntentFilter( Constants.NOTIFY_BEACON_ENTERS_REGION)); - LocalBroadcastManager.getInstance(this).registerReceiver( - mRegionReceiver, new IntentFilter( Constants.NOTIFY_BEACON_LEAVES_REGION)); - LocalBroadcastManager.getInstance(this).registerReceiver( - mRegionReceiver, new IntentFilter( Constants.NOTIFY_BEACON_NEAR_YOU_REGION)); - - LocalBroadcastManager.getInstance(this).registerReceiver( - mLocationReceiver, new IntentFilter( Constants.GET_CURRENT_LOCATION)); - LocalBroadcastManager.getInstance(this).registerReceiver( - mAlertReceiver, new IntentFilter( Constants.ALARM_NOTIFICATION_SHOW)); - } - - void unregisterReceivers() { - LocalBroadcastManager.getInstance(this).unregisterReceiver( mRegionReceiver ); - LocalBroadcastManager.getInstance(this).unregisterReceiver( mLocationReceiver ); - LocalBroadcastManager.getInstance(this).unregisterReceiver( mAlertReceiver ); - } - @Override protected void onDestroy() { - unregisterReceivers(); - unbinder.unbind(); + if (unbinder != null) { + unbinder.unbind(); + } super.onDestroy(); } diff --git a/app/src/main/java/com/samebits/beacon/locator/ui/activity/SettingsActivity.java b/app/src/main/java/com/samebits/beacon/locator/ui/activity/SettingsActivity.java index 8774724..18c3ffa 100644 --- a/app/src/main/java/com/samebits/beacon/locator/ui/activity/SettingsActivity.java +++ b/app/src/main/java/com/samebits/beacon/locator/ui/activity/SettingsActivity.java @@ -199,9 +199,10 @@ public void onCreate(Bundle savedInstanceState) { // guidelines. bindPreferenceSummaryToValue(findPreference("scan_default_region_text")); bindPreferenceSummaryToValue(findPreference("scan_manual_timeout_list")); + bindPreferenceSummaryToValue(findPreference("scan_background_timeout_list")); bindPreferenceSummaryToValue(findPreference("scan_sorting_order_list")); - Preference fgScanPref = findPreference("scan_foreground_switch"); - fgScanPref.setEnabled(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O); + // Preference fgScanPref = findPreference("scan_foreground_switch"); + // fgScanPref.setEnabled(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O); } diff --git a/app/src/main/java/com/samebits/beacon/locator/ui/fragment/DetectedBeaconsFragment.java b/app/src/main/java/com/samebits/beacon/locator/ui/fragment/DetectedBeaconsFragment.java index 45e3d5f..aade36f 100644 --- a/app/src/main/java/com/samebits/beacon/locator/ui/fragment/DetectedBeaconsFragment.java +++ b/app/src/main/java/com/samebits/beacon/locator/ui/fragment/DetectedBeaconsFragment.java @@ -98,9 +98,11 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa @Override public void onDestroyView() { - super.onDestroyView(); + if (unbinder != null) { + unbinder.unbind(); + } mTimer.cancel(); - unbinder.unbind(); + super.onDestroyView(); } private void setupToolbar() { @@ -155,6 +157,7 @@ private void emptyListSetup() { } } + @Override public void startScan() { mProgressBar.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/com/samebits/beacon/locator/ui/fragment/ScanFragment.java b/app/src/main/java/com/samebits/beacon/locator/ui/fragment/ScanFragment.java index 64aab55..80836d7 100644 --- a/app/src/main/java/com/samebits/beacon/locator/ui/fragment/ScanFragment.java +++ b/app/src/main/java/com/samebits/beacon/locator/ui/fragment/ScanFragment.java @@ -69,10 +69,10 @@ public void onCreate(Bundle savedInstanceState) { @Override public void onDestroyView() { - super.onDestroyView(); - if (mBeaconManager != null && mBeaconManager.isBound(this)) { + if (mBeaconManager.isBound(this)) { mBeaconManager.unbind(this); } + super.onDestroyView(); } @@ -98,17 +98,6 @@ public void onStop() { stopScan(); } - @Override - public void onResume() { - super.onResume(); - if (mBeaconManager.isBound(this)) mBeaconManager.setBackgroundMode(false); - } - - @Override - public void onPause() { - //if (mBeaconManager.isBound(this)) mBeaconManager.setBackgroundMode(PreferencesUtil.isBackgroundScan(getActivity())); - super.onPause(); - } public void scanStartStopAction() { if (isScanning) { diff --git a/app/src/main/java/com/samebits/beacon/locator/ui/fragment/TrackedBeaconsFragment.java b/app/src/main/java/com/samebits/beacon/locator/ui/fragment/TrackedBeaconsFragment.java index 2d53f9e..3cce2de 100644 --- a/app/src/main/java/com/samebits/beacon/locator/ui/fragment/TrackedBeaconsFragment.java +++ b/app/src/main/java/com/samebits/beacon/locator/ui/fragment/TrackedBeaconsFragment.java @@ -108,8 +108,8 @@ public void onStart() { @Override public void onDestroyView() { - super.onDestroyView(); unbinder.unbind(); + super.onDestroyView(); } diff --git a/app/src/main/java/com/samebits/beacon/locator/util/BackgroundSwitchWatcher.java b/app/src/main/java/com/samebits/beacon/locator/util/BackgroundSwitchWatcher.java new file mode 100644 index 0000000..e243f85 --- /dev/null +++ b/app/src/main/java/com/samebits/beacon/locator/util/BackgroundSwitchWatcher.java @@ -0,0 +1,78 @@ +package com.samebits.beacon.locator.util; + + +import android.annotation.TargetApi; +import android.app.Activity; +import android.app.Application; +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.NonNull; + + +import com.samebits.beacon.locator.BeaconLocatorApp; + +import org.altbeacon.beacon.logging.LogManager; + +@TargetApi(18) +public class BackgroundSwitchWatcher implements Application.ActivityLifecycleCallbacks { + @NonNull + private static final String TAG = Constants.TAG; + + @NonNull + private final Context mContext; + + private int activeActivityCount = 0; + + /** + * Constructs a new BackgroundSwitchWatcher + * + * @param context + */ + public BackgroundSwitchWatcher(Context context) { + if (android.os.Build.VERSION.SDK_INT < 18) { + LogManager.w(TAG, "BackgroundSwitchWatcher requires API 18 or higher."); + } + mContext = context; + ((Application)context.getApplicationContext()).registerActivityLifecycleCallbacks(this); + } + + @Override + public void onActivityCreated(Activity activity, Bundle bundle) { + } + + @Override + public void onActivityStarted(Activity activity) { + activeActivityCount++; + LogManager.d(TAG, "activity started: %s active activities: %s", activity, activeActivityCount); + + if (activeActivityCount == 1) { + BeaconLocatorApp.from(mContext).enableBackgroundScan(false); + } + } + + @Override + public void onActivityResumed(Activity activity) { + } + + @Override + public void onActivityPaused(Activity activity) { + } + + @Override + public void onActivityStopped(Activity activity) { + activeActivityCount--; + LogManager.d(TAG,"activity stopped: %s active activities: %s", activity, activeActivityCount); + if (activeActivityCount <= 0) { + BeaconLocatorApp.from(mContext).enableBackgroundScan(true); + } + } + + @Override + public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { + + } + + @Override + public void onActivityDestroyed(Activity activity) { + } + } \ No newline at end of file diff --git a/app/src/main/java/com/samebits/beacon/locator/util/Constants.java b/app/src/main/java/com/samebits/beacon/locator/util/Constants.java index 172f8e3..f5d03ac 100644 --- a/app/src/main/java/com/samebits/beacon/locator/util/Constants.java +++ b/app/src/main/java/com/samebits/beacon/locator/util/Constants.java @@ -18,6 +18,8 @@ package com.samebits.beacon.locator.util; +import android.os.Build; + /** * Created by vitas on 25/10/15. */ @@ -50,6 +52,7 @@ public final class Constants { public static final String ALARM_NOTIFICATION_SHOW = "com.samebits.beacon.locator.action.ALARM_NOTIFICATION_SHOW"; public static final String GET_CURRENT_LOCATION = "com.samebits.beacon.locator.action.GET_CURRENT_LOCATION"; + public static final int FOREGROUND_NOTIFICATION_ID = 11125; private Constants() { } diff --git a/app/src/main/java/com/samebits/beacon/locator/util/DialogBuilder.java b/app/src/main/java/com/samebits/beacon/locator/util/DialogBuilder.java index 5db8366..2bd2f14 100644 --- a/app/src/main/java/com/samebits/beacon/locator/util/DialogBuilder.java +++ b/app/src/main/java/com/samebits/beacon/locator/util/DialogBuilder.java @@ -20,10 +20,18 @@ import android.app.Dialog; import android.content.Context; +import android.content.DialogInterface; +import android.content.SharedPreferences; +import android.support.v4.util.Pair; import android.support.v7.app.AlertDialog; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.CheckBox; import com.samebits.beacon.locator.R; +import static com.samebits.beacon.locator.util.PreferencesUtil.getSharedPreferences; + /** * Created by vitas on 18/10/15. @@ -41,4 +49,45 @@ public static Dialog createSimpleOkErrorDialog(Context context, String title, St return alertDialog.create(); } + public static Pair createDoNotAskDialog(final Context context, + final String prefix, + String title, + String message, + int buttonId, + final DialogInterface.OnClickListener clickListener) { + + AlertDialog.Builder alertDialog = new AlertDialog.Builder(context) + .setTitle(title) + .setMessage(message); + + LayoutInflater adbInflater = LayoutInflater.from(context); + + final View dialogView = adbInflater.inflate(R.layout.popup_do_not_ask, null); + alertDialog.setView(dialogView); + + final CheckBox dontShowAgain = dialogView.findViewById(R.id.skip); + + alertDialog.setPositiveButton(buttonId, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + String checkBoxResult = "NOT checked"; + if (dontShowAgain.isChecked()) + checkBoxResult = "checked"; + SharedPreferences settings = getSharedPreferences(context); + SharedPreferences.Editor editor = settings.edit(); + editor.putString(prefix+"_skipMessage", checkBoxResult); + // Commit the edits! + editor.apply(); + + if (clickListener != null) { + clickListener.onClick(dialog, which); + } + } + }); + + SharedPreferences settings = getSharedPreferences(context); + String skipMessage = settings.getString(prefix+"_skipMessage", "NOT checked"); + + return new Pair<>(alertDialog.create(), !skipMessage.equals("checked")); + } + } diff --git a/app/src/main/java/com/samebits/beacon/locator/util/NotificationBuilder.java b/app/src/main/java/com/samebits/beacon/locator/util/NotificationBuilder.java index 1ec6cff..23945f2 100644 --- a/app/src/main/java/com/samebits/beacon/locator/util/NotificationBuilder.java +++ b/app/src/main/java/com/samebits/beacon/locator/util/NotificationBuilder.java @@ -27,10 +27,15 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; +import android.media.AudioAttributes; +import android.media.AudioManager; +import android.media.Ringtone; +import android.media.RingtoneManager; import android.net.Uri; import android.os.Build; import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationCompat.Builder; +import android.support.v4.app.NotificationManagerCompat; import android.support.v4.content.ContextCompat; import com.samebits.beacon.locator.R; @@ -43,7 +48,11 @@ public class NotificationBuilder { private Context mContext; private Builder mBuilder; - private NotificationManager mNotificationManager; + private long[] mVibrate_pattern = new long[]{500, 500}; + private NotificationManagerCompat mNotificationManager; + NotificationChannel mNotificationChannel; + public static String NOTIFICATION_CHANNEL_ID = "beacon_locator_channel_01"; + String NOTIFICATION_CHANNEL_SERVICE_ID = "beacon_locator_channel_service"; public NotificationBuilder(Context mContext) { @@ -53,50 +62,99 @@ public NotificationBuilder(Context mContext) { /** * Creation of notification on operations completed */ - public NotificationBuilder createNotification(int smallIcon, String title, boolean isVibrate, PendingIntent notifyIntent) { + public NotificationBuilder createNotification(String title, String ringtone, boolean vibrate, PendingIntent notifyIntent) { NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); - String NOTIFICATION_CHANNEL_ID = "blocator_channel_01"; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, + + mNotificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, title, NotificationManager.IMPORTANCE_HIGH); // Configure the notification channel. - notificationChannel.setDescription("Channel description"); - notificationChannel.enableLights(true); - notificationChannel.setLightColor(Color.RED); - notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE); - - if (isVibrate) { - notificationChannel.setVibrationPattern(new long[]{0, 1000, 500, 1000}); - notificationChannel.enableVibration(true); + mNotificationChannel.setDescription("beacon location notification channel"); + mNotificationChannel.enableLights(true); + + if (vibrate) { + mNotificationChannel.setVibrationPattern(mVibrate_pattern); + mNotificationChannel.enableVibration(true); + } else { + mNotificationChannel.enableVibration(false); + } + + mNotificationChannel.setLightColor(Color.YELLOW); + mNotificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE); + mNotificationChannel.setSound(null, null); + + /* if (ringtone != null) { + AudioAttributes att = new AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_NOTIFICATION) + .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) + .build(); + mNotificationChannel.setSound(Uri.parse(ringtone), att); + } else { + mNotificationChannel.setSound(null, null); } - notificationManager.createNotificationChannel(notificationChannel); + */ + notificationManager.createNotificationChannel(mNotificationChannel); } mBuilder = new NotificationCompat.Builder(mContext, NOTIFICATION_CHANNEL_ID); mBuilder.setAutoCancel(true) - .setDefaults(Notification.DEFAULT_ALL) - .setSmallIcon(smallIcon) + .setDefaults(vibrate?(Notification.DEFAULT_LIGHTS | Notification.DEFAULT_VIBRATE):Notification.DEFAULT_LIGHTS) + .setSmallIcon(getNotificationSmallIcon()) .setContentTitle(title) .setColor(ContextCompat.getColor(mContext, R.color.hn_orange)); + setRingtone(ringtone); + if (notifyIntent != null) { mBuilder.setContentIntent(notifyIntent); } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - // setLargeIcon(R.drawable.logo_notification_lollipop); - //FIXME - setLargeIcon(R.mipmap.ic_launcher); - } else { - setLargeIcon(R.mipmap.ic_launcher); - } + + setLargeIcon(getNotificationLargeIcon()); return this; + } + public NotificationBuilder createNotificationService(String title, PendingIntent notifyIntent) { + + NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + mNotificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_SERVICE_ID, + mContext.getString(R.string.text_scan_foreground_service), NotificationManager.IMPORTANCE_DEFAULT); + + // Configure the notification channel. + mNotificationChannel.setDescription(mContext.getString(R.string.pref_title_background_scan)); + mNotificationChannel.enableLights(false); + mNotificationChannel.enableVibration(false); + mNotificationChannel.setSound(null, null); + mNotificationChannel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); + + notificationManager.createNotificationChannel(mNotificationChannel); + } + + mBuilder = new NotificationCompat.Builder(mContext, NOTIFICATION_CHANNEL_SERVICE_ID); + + mBuilder.setAutoCancel(true) + .setDefaults(0) + .setSmallIcon(getNotificationSmallIcon()) + .setContentTitle(title) + .setColor(ContextCompat.getColor(mContext, R.color.hn_orange)); + + if (notifyIntent != null) { + mBuilder.setContentIntent(notifyIntent); + } + + setLargeIcon(getNotificationLargeIcon()); + + return this; + + } public Builder getBuilder() { return mBuilder; @@ -108,48 +166,66 @@ public NotificationBuilder setLargeIcon(Bitmap largeIconBitmap) { return this; } - public NotificationBuilder setLargeIcon(int largeIconResource) { Bitmap largeIconBitmap = BitmapFactory.decodeResource(mContext.getResources(), largeIconResource); return setLargeIcon(largeIconBitmap); } - public NotificationBuilder setRingtone(String ringtone) { // Ringtone options - if (ringtone != null) { - mBuilder.setSound(Uri.parse(ringtone)); + if (ringtone != null && ringtone.length() > 0) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + AudioAttributes att = new AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_NOTIFICATION) + .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) + .build(); + //mNotificationChannel.setSound(Uri.parse(ringtone), att); + + // if not a silent sound, play + if (!ringtone.equals(mContext.getString(R.string.pref_bn_none_notification_action_ringtone))) { + Ringtone r = RingtoneManager.getRingtone(mContext.getApplicationContext(), Uri.parse(ringtone)); + try { + r.play(); + } catch (Exception e) { + + } + } + } else { + mBuilder.setSound(Uri.parse(ringtone), AudioManager.STREAM_NOTIFICATION); + } } + return this; } - public NotificationBuilder setVibration() { return setVibration(null); } public NotificationBuilder setVibration(long[] pattern) { - if (pattern == null || pattern.length == 0) { - pattern = new long[]{500, 500}; + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { + if (pattern == null || pattern.length == 0) { + mBuilder.setVibrate(mVibrate_pattern); + } else { + mBuilder.setVibrate(pattern); + } } - mBuilder.setVibrate(pattern); + return this; } - public NotificationBuilder setLedActive() { mBuilder.setLights(Color.BLUE, 1000, 1000); return this; } - public NotificationBuilder setIcon(int icon) { mBuilder.setSmallIcon(icon); return this; } - public NotificationBuilder setMessage(String message) { mBuilder.setContentText(message); return this; @@ -165,33 +241,41 @@ public NotificationBuilder setIndeterminate() { return this; } - public NotificationBuilder setOngoing() { mBuilder.setOngoing(true); return this; } - public NotificationBuilder show() { show(0); return this; } - public NotificationBuilder show(long id) { - if (mNotificationManager == null) { - mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); - } + mNotificationManager = NotificationManagerCompat.from(mContext); + Notification mNotification = mBuilder.build(); if (mNotification.contentIntent == null) { // Creates a dummy PendingIntent mBuilder.setContentIntent(PendingIntent.getActivity(mContext, 0, new Intent(), PendingIntent.FLAG_UPDATE_CURRENT)); } - // Builds an anonymous Notification object from the builder, and passes it to the NotificationManager + mNotificationManager.notify((int) id, mBuilder.build()); return this; } + public static int getNotificationSmallIcon() { + boolean useWhiteIcon = (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP); + return useWhiteIcon ? R.mipmap.ic_launcher : R.mipmap.ic_launcher; + + } + + public static int getNotificationLargeIcon() { + boolean useWhiteIcon = (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP); + //TODO + return useWhiteIcon ? R.mipmap.ic_launcher : R.mipmap.ic_launcher; + + } } diff --git a/app/src/main/java/com/samebits/beacon/locator/util/PreferencesUtil.java b/app/src/main/java/com/samebits/beacon/locator/util/PreferencesUtil.java index 4671c23..18af66b 100644 --- a/app/src/main/java/com/samebits/beacon/locator/util/PreferencesUtil.java +++ b/app/src/main/java/com/samebits/beacon/locator/util/PreferencesUtil.java @@ -34,7 +34,6 @@ private PreferencesUtil() { public static SharedPreferences getSharedPreferences(Context context) { return PreferenceManager.getDefaultSharedPreferences(context); - //return BeaconLocatorApp.from(mContext).getSharedPreferences("beaconloc_pref_name", Context.MODE_PRIVATE); } public static String getDefaultRegionName(Context context) { @@ -63,7 +62,7 @@ public static boolean isBackgroundScan(Context context) { public static boolean isForegroundScan(Context context) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - return getSharedPreferences(context).getBoolean("scan_foreground_switch", false); + return getSharedPreferences(context).getBoolean("scan_foreground_switch", true); } return false; } diff --git a/app/src/main/java/com/samebits/beacon/locator/util/WhiteListUtils.java b/app/src/main/java/com/samebits/beacon/locator/util/WhiteListUtils.java new file mode 100644 index 0000000..810fe8a --- /dev/null +++ b/app/src/main/java/com/samebits/beacon/locator/util/WhiteListUtils.java @@ -0,0 +1,107 @@ +package com.samebits.beacon.locator.util; + +import android.content.ComponentName; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.support.v4.util.Pair; +import android.support.v7.app.AlertDialog; +import android.util.Log; + + +import com.samebits.beacon.locator.BuildConfig; +import com.samebits.beacon.locator.R; + +import java.util.List; + +/** + * + * https://gist.github.com/moopat/e9735fa8b5cff69d003353a4feadcdbc + * + * http://www.davidgyoungtech.com/2017/08/07/beacon-detection-with-android-8 + */ +public class WhiteListUtils { + + + private WhiteListUtils() { + } + + + public static void startAutoStartActivity(Context context) { + + for (Intent intent : POWERMANAGER_INTENTS) { + + if (context.getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) { + try { + if (isCallable(context, intent)) { + showAlertWindow(context, intent); + //context.startActivity(intent); + break; + } else { + if (BuildConfig.BUILD_TYPE.contains("release")) { + // Crashlytics.log("Intent not callable for whitelisting " + intent.toString()); + } + Log.w(Constants.TAG, "Intent not callable for whitelisting " + intent.toString()); + } + } catch (Exception e) { + if (BuildConfig.BUILD_TYPE.contains("release")) { + //Crashlytics.logException(e); + } + Log.e(Constants.TAG, "checkOSCompat Error ", e); + } + } + } + } + + + private static void showAlertWindow(final Context context, final Intent intent) { + + Pair result = DialogBuilder.createDoNotAskDialog( + context, + "user_warn_protected_app", + context.getString(R.string.action_settings), + context.getString(R.string.message_need_autostartt_settings), + R.string.action_settings, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + context.startActivity(intent); + //settings.edit().putBoolean(SKIP_WHITELIST_APP, true).apply(); + } + }); + if (result.second) { + result.first.show(); + } + + } + + private static boolean isCallable(Context context, Intent intent) { + List list = context.getPackageManager().queryIntentActivities(intent, + PackageManager.MATCH_DEFAULT_ONLY); + return list.size() > 0; + } + + + /** + * List of all know third party power management, autostart activities + */ + private static final Intent[] POWERMANAGER_INTENTS = { + new Intent().setComponent(new ComponentName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity")), + new Intent().setComponent(new ComponentName("com.letv.android.letvsafe", "com.letv.android.letvsafe.AutobootManageActivity")), + new Intent().setComponent(new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.optimize.process.ProtectActivity")), + new Intent().setComponent(new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.appcontrol.activity.StartupAppControlActivity")), + new Intent().setComponent(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.permission.startup.StartupAppListActivity")), + new Intent().setComponent(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.startupapp.StartupAppListActivity")), + new Intent().setComponent(new ComponentName("com.oppo.safe", "com.oppo.safe.permission.startup.StartupAppListActivity")), + new Intent().setComponent(new ComponentName("com.iqoo.secure", "com.iqoo.secure.ui.phoneoptimize.AddWhiteListActivity")), + new Intent().setComponent(new ComponentName("com.iqoo.secure", "com.iqoo.secure.ui.phoneoptimize.BgStartUpManager")), + new Intent().setComponent(new ComponentName("com.vivo.permissionmanager", "com.vivo.permissionmanager.activity.BgStartUpManagerActivity")), + new Intent().setComponent(new ComponentName("com.samsung.android.lool", "com.samsung.android.sm.ui.battery.BatteryActivity")), + new Intent().setComponent(new ComponentName("com.htc.pitroad", "com.htc.pitroad.landingpage.activity.LandingPageActivity")), + new Intent().setComponent(new ComponentName("com.asus.mobilemanager", "com.asus.mobilemanager.MainActivity")) + }; + + +} diff --git a/app/src/main/res/layout/fragment_scan_radar.xml b/app/src/main/res/layout/fragment_scan_radar.xml index cee1a00..a070c06 100644 --- a/app/src/main/res/layout/fragment_scan_radar.xml +++ b/app/src/main/res/layout/fragment_scan_radar.xml @@ -11,23 +11,26 @@ + android:padding="16dp" + android:gravity="center|bottom" + android:textAlignment="center" + /> diff --git a/app/src/main/res/layout/layout_empty_list.xml b/app/src/main/res/layout/layout_empty_list.xml index 92ae6a3..0b0e52d 100644 --- a/app/src/main/res/layout/layout_empty_list.xml +++ b/app/src/main/res/layout/layout_empty_list.xml @@ -3,24 +3,32 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/bg_light_grey" + android:padding="6dp" android:orientation="vertical"> - + android:layout_height="match_parent"> - + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/popup_do_not_ask.xml b/app/src/main/res/layout/popup_do_not_ask.xml new file mode 100644 index 0000000..7815aa4 --- /dev/null +++ b/app/src/main/res/layout/popup_do_not_ask.xml @@ -0,0 +1,15 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d5b02b6..54cced9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -37,8 +37,7 @@ Enable foreground scan (Android 8+) Foreground service to be able run scan more often than every 15 min (only Android 8+). - Background scan interval (only Android 4.X) - + Background scan interval Region name Default Manual scan interval @@ -224,5 +223,9 @@ Nearest first Furthest first UUID, Major and Minor + beacon location background service + Please give a permission for unrestricted power management usage and enable autostart to be able scan in the background + Do not ask again + Need Permissions diff --git a/app/src/main/res/xml/pref_scan.xml b/app/src/main/res/xml/pref_scan.xml index 04844ac..13fd574 100644 --- a/app/src/main/res/xml/pref_scan.xml +++ b/app/src/main/res/xml/pref_scan.xml @@ -7,14 +7,9 @@ android:summary="@string/pref_description_background_scan" android:title="@string/pref_title_background_scan" /> -