Java tutorial
/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package com.linkbubble; import android.app.Notification; import android.app.PendingIntent; import android.app.Service; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.AsyncTask; import android.os.Build; import android.os.IBinder; import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationManagerCompat; import android.util.Log; import android.webkit.WebIconDatabase; import com.linkbubble.ui.NotificationCloseAllActivity; import com.linkbubble.ui.NotificationHideActivity; import com.linkbubble.ui.NotificationShowContentActivity; import com.linkbubble.ui.NotificationUnhideActivity; import com.linkbubble.util.Analytics; import com.linkbubble.util.CrashTracking; import com.squareup.otto.Subscribe; import com.crashlytics.android.Crashlytics; import io.fabric.sdk.android.Fabric; import java.util.Objects; import java.util.Vector; public class MainService extends Service { private static final String BCAST_CONFIGCHANGED = "android.intent.action.CONFIGURATION_CHANGED"; private boolean mRestoreComplete; private boolean mDestroyAllActivities = true; public static class UpdateNotificationEvent { } public static class ShowDefaultNotificationEvent { } public static class ShowUnhideNotificationEvent { } public static class OnDestroyMainServiceEvent { } public static class ReloadMainServiceEvent { public ReloadMainServiceEvent(Context context) { mContext = context; } public Context mContext; } @Override public IBinder onBind(Intent intent) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { String cmd = intent != null ? intent.getStringExtra("cmd") : null; CrashTracking.log("MainService.onStartCommand(), cmd:" + cmd); MainController mainController = MainController.get(); if (mainController == null || intent == null || cmd == null) { stopSelf(); return START_NOT_STICKY; } long urlLoadStartTime = intent.getLongExtra("start_time", System.currentTimeMillis()); if (cmd.compareTo("open") == 0) { String url = intent.getStringExtra("url"); if (url != null) { String openedFromAppName = intent.getStringExtra("openedFromAppName"); mainController.openUrl(url, urlLoadStartTime, true, openedFromAppName); } } else if (cmd.compareTo("restore") == 0) { if (!mRestoreComplete) { String[] urls = intent.getStringArrayExtra("urls"); if (urls != null) { int startOpenTabCount = mainController.getActiveTabCount(); for (int i = 0; i < urls.length; i++) { String urlAsString = urls[i]; if (urlAsString != null && !urlAsString.equals(Constant.WELCOME_MESSAGE_URL)) { boolean setAsCurrentTab = false; if (startOpenTabCount == 0) { setAsCurrentTab = i == urls.length - 1; } mainController.openUrl(urlAsString, urlLoadStartTime, setAsCurrentTab, Analytics.OPENED_URL_FROM_RESTORE); } } } mRestoreComplete = true; } } return START_STICKY; } @Override public void onCreate() { mDestroyAllActivities = true; mRestoreComplete = false; setTheme(Settings.get().getDarkThemeEnabled() ? R.style.MainServiceThemeDark : R.style.MainServiceThemeLight); super.onCreate(); Fabric.with(this, new Crashlytics()); CrashTracking.log("MainService.onCreate()"); showDefaultNotification(); Config.init(this); Settings.get().onOrientationChange(); try { WebIconDatabase.getInstance().open(getDir("icons", MODE_PRIVATE).getPath()); } catch (RuntimeException exc) { CrashTracking.logHandledException(exc); } MainApplication.mDestroyActivitySharedLock = new Object(); MainApplication.mActivityDestroyed = false; MainController.create(this, new MainController.EventHandler() { @Override public void onDestroy() { Settings.get().saveBubbleRestingPoint(); stopSelf(); CrashTracking.log("MainService.onCreate(): onDestroy()"); } }); //Intent i = new Intent(); //i.setData(Uri.parse("https://t.co/uxMl3bWtMP")); //i.setData(Uri.parse("http://t.co/oOyu7GBZMU")); //i.setData(Uri.parse("http://goo.gl/abc57")); //i.setData(Uri.parse("https://bitly.com/QtQET")); //i.setData(Uri.parse("http://www.duckduckgo.com")); //openUrl("https://www.duckduckgo.com"); //openUrl("http://www.duckduckgo.com", true); //openUrl("https://t.co/uxMl3bWtMP", true); IntentFilter filter = new IntentFilter(); filter.addAction(BCAST_CONFIGCHANGED); registerReceiver(mBroadcastReceiver, filter); registerReceiver(mDialogReceiver, new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); filter.addDataScheme("package"); filter = new IntentFilter(Intent.ACTION_SCREEN_ON); filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(Intent.ACTION_USER_PRESENT); registerReceiver(mScreenReceiver, filter); MainApplication.registerForBus(this, this); } @Override public void onDestroy() { if (mDestroyAllActivities) { MainApplication.postEvent(MainService.this, new OnDestroyMainServiceEvent()); } MainApplication.unregisterForBus(this, this); unregisterReceiver(mScreenReceiver); unregisterReceiver(mDialogReceiver); unregisterReceiver(mBroadcastReceiver); MainController.destroy(); CrashTracking.log("MainService.onDestroy()"); super.onDestroy(); } private void cancelCurrentNotification() { stopForeground(true); //Log.d("blerg", "cancelCurrentNotification()"); } private void showDefaultNotification() { Intent closeAllIntent = new Intent(this, NotificationCloseAllActivity.class); closeAllIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | Intent.FLAG_ACTIVITY_NEW_TASK); PendingIntent closeAllPendingIntent = PendingIntent.getActivity(this, (int) System.currentTimeMillis(), closeAllIntent, PendingIntent.FLAG_UPDATE_CURRENT); /*Intent showContentViewIntent = new Intent(this, NotificationShowContentActivity.class); showContentViewIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | Intent.FLAG_ACTIVITY_NEW_TASK); PendingIntent showContentViewPendingIntent = PendingIntent.getActivity(this, (int) System.currentTimeMillis(), showContentViewIntent, PendingIntent.FLAG_UPDATE_CURRENT);*/ Intent hideIntent = new Intent(this, NotificationHideActivity.class); hideIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | Intent.FLAG_ACTIVITY_NEW_TASK); PendingIntent hidePendingIntent = PendingIntent.getActivity(this, (int) System.currentTimeMillis(), hideIntent, PendingIntent.FLAG_UPDATE_CURRENT); NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this) .setSmallIcon(R.drawable.ic_stat).setPriority(Notification.PRIORITY_MIN) .setContentTitle(getString(R.string.app_name)) .setContentText(getString(R.string.notification_default_summary)) //.addAction(R.drawable.ic_action_eye_closed_dark, getString(R.string.notification_action_hide), hidePendingIntent) //.addAction(R.drawable.ic_action_cancel_dark, getString(R.string.notification_action_close_all), closeAllPendingIntent) .addAction( Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT ? R.drawable.ic_action_cancel_white : R.drawable.ic_action_cancel_dark, getString(R.string.notification_action_close_all), closeAllPendingIntent) //.addAction(Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT ? R.drawable.ic_action_cancel_white : R.drawable.ic_action_cancel_dark, getString(R.string.notification_expand), showContentViewPendingIntent) .setGroup(Constant.NOTIFICATION_GROUP_KEY_ARTICLES).setGroupSummary(true).setLocalOnly(true) .setContentIntent(hidePendingIntent); /*MainController controller = MainController.get(); if (null != controller && null != controller.mBubbleFlowDraggable) { if (!controller.mBubbleFlowDraggable.isExpanded()) { notificationBuilder .addAction(R.drawable.ic_stat, getString(R.string.notification_expand), showContentViewPendingIntent) .setContentText(getString(R.string.notification_default_expand_summary)); } }*/ // Nuke all previous notifications and generate unique ids NotificationManagerCompat.from(this).cancelAll(); int notificationId = 77; startForeground(notificationId, notificationBuilder.build()); } private void showUnhideHiddenNotification() { Intent unhideIntent = new Intent(this, NotificationUnhideActivity.class); unhideIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | Intent.FLAG_ACTIVITY_NEW_TASK); PendingIntent unhidePendingIntent = PendingIntent.getActivity(this, (int) System.currentTimeMillis(), unhideIntent, PendingIntent.FLAG_UPDATE_CURRENT); /*Intent showContentViewIntent = new Intent(this, NotificationShowContentActivity.class); showContentViewIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | Intent.FLAG_ACTIVITY_NEW_TASK); PendingIntent showContentViewPendingIntent = PendingIntent.getActivity(this, (int) System.currentTimeMillis(), showContentViewIntent, PendingIntent.FLAG_UPDATE_CURRENT);*/ Intent closeAllIntent = new Intent(this, NotificationCloseAllActivity.class); closeAllIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | Intent.FLAG_ACTIVITY_NEW_TASK); PendingIntent closeAllPendingIntent = PendingIntent.getActivity(this, (int) System.currentTimeMillis(), closeAllIntent, PendingIntent.FLAG_UPDATE_CURRENT); NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this) .setSmallIcon(R.drawable.ic_stat).setPriority(Notification.PRIORITY_MIN) .setContentTitle(getString(R.string.app_name)) .setContentText(getString(R.string.notification_unhide_summary)).setLocalOnly(true) //.addAction(R.drawable.ic_action_eye_open_dark, getString(R.string.notification_action_unhide), unhidePendingIntent) //.addAction(R.drawable.ic_action_cancel_dark, getString(R.string.notification_action_close_all), closeAllPendingIntent) .addAction( Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT ? R.drawable.ic_action_cancel_white : R.drawable.ic_action_cancel_dark, getString(R.string.notification_action_close_all), closeAllPendingIntent) .setContentIntent(unhidePendingIntent); /*MainController controller = MainController.get(); if (null != controller && null != controller.mBubbleFlowDraggable) { if (!controller.mBubbleFlowDraggable.isExpanded()) { notificationBuilder .addAction(R.drawable.ic_stat, getString(R.string.notification_expand), showContentViewPendingIntent) .setContentText(getString(R.string.notification_unhide_expand_summary)); } }*/ NotificationManagerCompat.from(this).cancelAll(); startForeground(1, notificationBuilder.build()); //Log.d("blerg", "showUnhideHiddenNotification()"); } @SuppressWarnings("unused") @Subscribe public void onUpdateNotificationEvent(UpdateNotificationEvent event) { cancelCurrentNotification(); MainController controller = MainController.get(); if (null != controller) { if (controller.getHiddenByUser()) { showUnhideHiddenNotification(); } else { showDefaultNotification(); } } } @SuppressWarnings("unused") @Subscribe public void onShowDefaultNotificationEvent(ShowDefaultNotificationEvent event) { cancelCurrentNotification(); showDefaultNotification(); } @SuppressWarnings("unused") @Subscribe public void onShowUnhideNotificationEvent(ShowUnhideNotificationEvent event) { cancelCurrentNotification(); showUnhideHiddenNotification(); } @SuppressWarnings("unused") @Subscribe public void onReloadMainServiceEvent(ReloadMainServiceEvent event) { Vector<String> urls = Settings.get().loadCurrentTabs(); mDestroyAllActivities = false; stopSelf(); new WaitActivityDestroyedRestoreLinksEvent(event.mContext, urls).execute(); } class WaitActivityDestroyedRestoreLinksEvent extends AsyncTask<Void, Void, Long> { Context mContext; Vector<String> mUrls; WaitActivityDestroyedRestoreLinksEvent(Context context, Vector<String> urls) { super(); mContext = context; mUrls = urls; } protected Long doInBackground(Void... params) { if (null != MainApplication.mDestroyActivitySharedLock) { Log.d("TAG", "!!!!!Creating service"); synchronized (MainApplication.mDestroyActivitySharedLock) { if (!MainApplication.mActivityDestroyed) { try { Log.d("TAG", "!!!!!Waiting in service"); MainApplication.mDestroyActivitySharedLock.wait(); Log.d("TAG", "!!!!!Notified in service"); } catch (InterruptedException e) { } } } } if (null != mUrls && 0 != mUrls.size()) { MainApplication.restoreLinks(mContext, mUrls.toArray(new String[mUrls.size()])); } return null; } } private BroadcastReceiver mDialogReceiver = new BroadcastReceiver() { String SYSTEM_REASON = "reason"; String SYSTEM_HOME_KEY = "homekey"; String SYSTEM_RECENTAPP_KEY = "recentapps"; @Override public void onReceive(Context context, Intent myIntent) { if (myIntent.getAction().equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) { String reason = myIntent.getStringExtra(SYSTEM_REASON); boolean homeKeyClick = false; boolean recentApp = false; if (null != reason) { if (reason.equals(SYSTEM_HOME_KEY)) { homeKeyClick = true; } else if (reason.equals(SYSTEM_RECENTAPP_KEY)) { recentApp = true; } } MainController.get().onCloseSystemDialogs(homeKeyClick, recentApp); } } }; private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent myIntent) { if (myIntent.getAction().equals(BCAST_CONFIGCHANGED)) { MainController.get().onOrientationChanged(); } } }; private BroadcastReceiver mScreenReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { MainController.get().updateScreenState(intent.getAction()); } }; }