package de.vier_bier.habpanelviewer; import android.app.Activity; import android.app.NotificationChannel; import android.app.NotificationManager; import android.bluetooth.BluetoothManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.graphics.Point; import android.hardware.SensorManager; import android.hardware.camera2.CameraManager; import android.media.AudioManager; import android.media.projection.MediaProjection; import android.media.projection.MediaProjectionManager; import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.os.PowerManager; import android.preference.PreferenceManager; import android.util.DisplayMetrics; import android.util.Log; import android.view.ContextMenu; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MenuInflater; import android.view.MenuItem; import android.view.SurfaceView; import android.view.TextureView; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.core.app.NotificationCompat; import androidx.core.view.GravityCompat; import androidx.drawerlayout.widget.DrawerLayout; import com.google.android.material.navigation.NavigationView; import com.jakewharton.processphoenix.ProcessPhoenix; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; import java.util.ArrayList; import java.util.Date; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import de.vier_bier.habpanelviewer.command.AdminHandler; import de.vier_bier.habpanelviewer.command.BluetoothHandler; import de.vier_bier.habpanelviewer.command.CommandQueue; import de.vier_bier.habpanelviewer.command.FlashHandler; import de.vier_bier.habpanelviewer.command.InternalCommandHandler; import de.vier_bier.habpanelviewer.command.NotificationHandler; import de.vier_bier.habpanelviewer.command.ScreenHandler; import de.vier_bier.habpanelviewer.command.TtsHandler; import de.vier_bier.habpanelviewer.command.VolumeHandler; import de.vier_bier.habpanelviewer.command.WebViewHandler; import de.vier_bier.habpanelviewer.command.log.CommandLogActivity; import de.vier_bier.habpanelviewer.connection.ConnectionStatistics; import de.vier_bier.habpanelviewer.connection.ssl.CertificateManager; import de.vier_bier.habpanelviewer.db.CredentialManager; import de.vier_bier.habpanelviewer.help.HelpActivity; import de.vier_bier.habpanelviewer.openhab.ISseConnectionListener; import de.vier_bier.habpanelviewer.openhab.ServerConnection; import de.vier_bier.habpanelviewer.openhab.SseConnection; import de.vier_bier.habpanelviewer.preferences.PreferenceActivity; import de.vier_bier.habpanelviewer.reporting.AccelerometerMonitor; import de.vier_bier.habpanelviewer.reporting.BatteryMonitor; import de.vier_bier.habpanelviewer.reporting.BrightnessMonitor; import de.vier_bier.habpanelviewer.reporting.ConnectedIndicator; import de.vier_bier.habpanelviewer.reporting.DockingStateMonitor; import de.vier_bier.habpanelviewer.reporting.IDeviceMonitor; import de.vier_bier.habpanelviewer.reporting.PressureMonitor; import de.vier_bier.habpanelviewer.reporting.ProximityMonitor; import de.vier_bier.habpanelviewer.reporting.ScreenMonitor; import de.vier_bier.habpanelviewer.reporting.TemperatureMonitor; import de.vier_bier.habpanelviewer.reporting.VolumeMonitor; import de.vier_bier.habpanelviewer.reporting.motion.Camera; import de.vier_bier.habpanelviewer.reporting.motion.IMotionDetector; import de.vier_bier.habpanelviewer.reporting.motion.MotionDetector; import de.vier_bier.habpanelviewer.reporting.motion.MotionVisualizer; import de.vier_bier.habpanelviewer.status.ApplicationStatus; import de.vier_bier.habpanelviewer.status.StatusInfoActivity; /** * Main activity showing the Webview for openHAB. */ public class MainActivity extends ScreenControllingActivity implements NavigationView.OnNavigationItemSelectedListener { private static final String TAG = "HPV-MainActivity"; private ClientWebView mWebView; private TextView mUrlTextView; private TextView mStatusTextView; private ISseConnectionListener mConnectionListener; private ConnectionStatistics mConnections; private ServerConnection mServerConnection; private AppRestartingExceptionHandler mRestartingExceptionHandler; private NetworkTracker mNetworkTracker; private FlashHandler mFlashService; private IMotionDetector mMotionDetector; private MotionVisualizer mMotionVisualizer; private ConnectedIndicator mConnectedIndicator; private CommandQueue mCommandQueue; private ScreenCapturer mCapturer; private Camera mCam; private TrackShutdownService mService; private final ServiceConnection mSC = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { mService = ((TrackShutdownService.LocalBinder) iBinder).getService(); } @Override public void onServiceDisconnected(ComponentName componentName) { mService = null; } }; private final ArrayList<IDeviceMonitor> mMonitors = new ArrayList<>(); @Override protected void onDestroy() { destroy(); super.onDestroy(); } public void destroy() { Log.v(TAG, "in destroy"); if (mCapturer != null) { mCapturer.terminate(); mCapturer = null; } if (mFlashService != null) { mFlashService.terminate(); mFlashService = null; } if (mMotionDetector != null) { mMotionDetector.terminate(); mMotionDetector = null; } final CountDownLatch l = new CountDownLatch(1); if (mCam != null) { Log.v(TAG, "terminating camera..."); mCam.terminate(l); mCam = null; } else { l.countDown(); } if (mServerConnection != null) { mServerConnection.terminate(this); mServerConnection = null; } if (mConnectedIndicator != null) { mConnectedIndicator.terminate(); mConnectedIndicator = null; } for (IDeviceMonitor m : mMonitors) { m.terminate(); } if (mCommandQueue != null) { mCommandQueue.terminate(); mCommandQueue = null; } if (mNetworkTracker != null) { mNetworkTracker.terminate(this); mNetworkTracker = null; } if (mConnections != null) { mConnections.terminate(); mConnections = null; } if (mWebView != null) { mWebView.unregister(); } EventBus.getDefault().unregister(this); try { l.await(2, TimeUnit.SECONDS); } catch (InterruptedException e) { Log.e(TAG, "failed to terminate camera"); } } public Camera getCamera() { return mCam; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); startService(new Intent(getBaseContext(), TrackShutdownService.class)); EventBus.getDefault().register(this); setContentView(R.layout.activity_main); // inflate navigation header to make sure the textview holding the connection text is created NavigationView navigationView = findViewById(R.id.nav_view); ConstraintLayout navHeader = (ConstraintLayout) LayoutInflater.from(this).inflate(R.layout.navheader_main, null); navigationView.addHeaderView(navHeader); navigationView.setNavigationItemSelectedListener(this); int restartCount = getIntent().getIntExtra(Constants.INTENT_FLAG_RESTART_COUNT, 0); if (!CertificateManager.getInstance().isInitialized()) { UiUtil.showDialog(this, null, getString(R.string.sslFailed)); } if (mRestartingExceptionHandler == null) { mRestartingExceptionHandler = new AppRestartingExceptionHandler(this, Thread.getDefaultUncaughtExceptionHandler(), restartCount); } if (mNetworkTracker == null) { mNetworkTracker = new NetworkTracker(this); } if (mServerConnection == null) { mServerConnection = new ServerConnection(this); mNetworkTracker.addListener(mServerConnection.getSseConnection()); } if (mConnections == null) { mConnections = new ConnectionStatistics(this); } if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && mFlashService == null) { mFlashService = new FlashHandler((CameraManager) getSystemService(Context.CAMERA_SERVICE)); } final SurfaceView motionView = findViewById(R.id.motionView); final TextureView previewView = findViewById(R.id.previewView); boolean cameraFallback = prefs.getBoolean(Constants.PREF_CAMERA_FALLBACK, false); if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT) || (cameraFallback && getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA))) { if (mCam == null) { mCam = new Camera(this, previewView, prefs); } if (mMotionVisualizer == null) { int scaledSize = getResources().getDimensionPixelSize(R.dimen.motionFontSize); mMotionVisualizer = new MotionVisualizer(motionView, navigationView, prefs, mCam.getSensorOrientation(), scaledSize); mMotionDetector = new MotionDetector(this, mCam, mMotionVisualizer, mServerConnection); } } else { Log.d(TAG, "no camera feature_front, hiding preview"); motionView.setVisibility(View.INVISIBLE); previewView.setVisibility(View.INVISIBLE); } if (mConnectedIndicator == null) { mConnectedIndicator = new ConnectedIndicator(this, mServerConnection); } mMonitors.add(new BatteryMonitor(this, mServerConnection)); mMonitors.add(new DockingStateMonitor(this, mServerConnection)); mMonitors.add(new ScreenMonitor(this, mServerConnection)); mMonitors.add(new VolumeMonitor(this, (AudioManager) getSystemService(Context.AUDIO_SERVICE), mServerConnection)); SensorManager m = (SensorManager) getSystemService(Context.SENSOR_SERVICE); mMonitors.add(new AccelerometerMonitor(this, m, mServerConnection)); mMonitors.add(new ProximityMonitor(this, m, mServerConnection)); mMonitors.add(new BrightnessMonitor(this, m, mServerConnection)); mMonitors.add(new PressureMonitor(this, m, mServerConnection)); mMonitors.add(new TemperatureMonitor(this, m, mServerConnection)); if (mCommandQueue == null) { mCommandQueue = new CommandQueue(mServerConnection); mCommandQueue.addHandler(new InternalCommandHandler(this, mMotionDetector, mServerConnection)); mCommandQueue.addHandler(new AdminHandler(this)); mCommandQueue.addHandler(new BluetoothHandler(this, (BluetoothManager) getSystemService(BLUETOOTH_SERVICE))); mCommandQueue.addHandler(new ScreenHandler((PowerManager) getSystemService(POWER_SERVICE), this, () -> { if (prefs.getBoolean(Constants.PREF_PAUSE_WEBVIEW, false)) { mWebView.post(() -> mWebView.pause()); } })); mCommandQueue.addHandler(new VolumeHandler(this, (AudioManager) getSystemService(Context.AUDIO_SERVICE))); mCommandQueue.addHandler(new NotificationHandler(this)); mCommandQueue.addHandler(new TtsHandler(this)); if (mFlashService != null) { mCommandQueue.addHandler(mFlashService); } } mUrlTextView = navHeader.findViewById(R.id.urlTextView); mStatusTextView = navHeader.findViewById(R.id.statusTextView); MenuItem enterCredMenu = navigationView.getMenu().findItem(R.id.action_enter_credentials); mConnectionListener = new ISseConnectionListener() { private SseConnection.Status mLastStatus; @Override public void statusChanged(SseConnection.Status newStatus) { final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); String url = prefs.getString(Constants.PREF_SERVER_URL, ""); runOnUiThread(() -> { mUrlTextView.setText(url); mStatusTextView.setText(newStatus.name()); enterCredMenu.setVisible(newStatus == SseConnection.Status.UNAUTHORIZED); if (newStatus == SseConnection.Status.CONNECTED) { findViewById(R.id.activity_main_layout).setPadding(0,0,0,0); } else { findViewById(R.id.activity_main_layout).setPadding(10, 10,10,10); } }); if (newStatus == SseConnection.Status.CONNECTED) { mConnections.connected(); } else { if (mLastStatus == SseConnection.Status.CONNECTED) { mConnections.disconnected(); } if (newStatus == SseConnection.Status.UNAUTHORIZED) { UiUtil.showPasswordDialog(MainActivity.this, url, "Rest API", new UiUtil.CredentialsListener() { @Override public void credentialsEntered(String host, String realm, String user, String password, boolean store) { CredentialManager.getInstance().setRestCredentials(user, password, store); SharedPreferences.Editor editor1 = prefs.edit(); editor1.putBoolean(Constants.REST_CRED_STORED, true); editor1.apply(); } @Override public void credentialsCancelled() { } }); } } mLastStatus = newStatus; } }; mServerConnection.addConnectionListener(mConnectionListener); if (restartCount > 0) { UiUtil.showSnackBar(mUrlTextView, R.string.appRestarted, R.string.disableRestart, view -> { mRestartingExceptionHandler.disable(); SharedPreferences.Editor editor1 = prefs.edit(); editor1.putBoolean(Constants.PREF_RESTART_ENABLED, false); editor1.apply(); }); } mWebView = findViewById(R.id.activity_main_webview); mWebView.initialize(new ISseConnectionListener() { private SseConnection.Status mLastStatus; @Override public void statusChanged(SseConnection.Status newStatus) { if (newStatus != SseConnection.Status.CONNECTED && mLastStatus == SseConnection.Status.CONNECTED) { mServerConnection.reconnect(); } mLastStatus = newStatus; } }, (url, isHabPanelUrl) -> { if (prefs.getBoolean(Constants.PREF_CURRENT_URL_ENABLED, false)) { mServerConnection.updateState(prefs.getString(Constants.PREF_CURRENT_URL_ITEM, ""), url); } }, mNetworkTracker); mCommandQueue.addHandler(new WebViewHandler(mWebView)); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); int rotation = getWindowManager().getDefaultDisplay().getRotation(); if (mMotionVisualizer != null) { mMotionVisualizer.setDeviceRotation(rotation); } if (mCam != null) { mCam.setDeviceRotation(rotation); } } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.webview_context_menu, menu); menu.findItem(R.id.menu_toggle_kiosk).setVisible(mWebView.isShowingHabPanel()); } @Override public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_reload: mWebView.reload(); break; case R.id.menu_goto_start_url: mWebView.loadStartUrl(); break; case R.id.menu_goto_url: mWebView.enterUrl(this); break; case R.id.menu_set_start_url: final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(MainActivity.this); SharedPreferences.Editor editor1 = prefs.edit(); editor1.putString(Constants.PREF_START_URL, mWebView.getUrl()); editor1.apply(); break; case R.id.menu_clear_credentials: mWebView.clearPasswords(); UiUtil.showSnackBar(mWebView, R.string.credentialsCleared, R.string.action_restart, view -> restartApp()); break; case R.id.menu_clear_cache: mWebView.clearCache(true); UiUtil.showSnackBar(mWebView, R.string.cacheCleared, R.string.menu_reload, view -> mWebView.reload()); break; case R.id.menu_toggle_kiosk: mWebView.toggleKioskMode(); break; default: super.onContextItemSelected(item); return false; } return true; } public ScreenCapturer getCapturer() { return mCapturer; } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == Constants.REQUEST_PICK_APPLICATION && resultCode == RESULT_OK) { startActivity(data); } else if (requestCode == Constants.REQUEST_MEDIA_PROJECTION) { boolean allowCapture = resultCode == RESULT_OK; final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(MainActivity.this); if (prefs.getBoolean(Constants.PREF_CAPTURE_SCREEN_ENABLED, false) != allowCapture) { SharedPreferences.Editor editor1 = prefs.edit(); editor1.putBoolean(Constants.PREF_CAPTURE_SCREEN_ENABLED, allowCapture); editor1.apply(); } if (resultCode == RESULT_OK) { MediaProjectionManager projectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE); MediaProjection projection = projectionManager.getMediaProjection(RESULT_OK, data); DisplayMetrics metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics); Point size = new Point(); getWindowManager().getDefaultDisplay().getSize(size); if (mCapturer == null) { mCapturer = new ScreenCapturer(projection, size.x, size.y, metrics.densityDpi); } } } else if (requestCode == Constants.REQUEST_VALIDATE) { if (resultCode == Activity.RESULT_CANCELED) { UiUtil.showButtonDialog(this, null, getString(R.string.prefsDisabledMissingPermissions), android.R.string.ok, (dialogInterface, i) -> onStart(), -1, null); } else { onStart(); } } } @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(Constants.Restart r) { restartApp(); } @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(Constants.LoadStartUrl r) { final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(MainActivity.this); if (prefs.getBoolean(Constants.PREF_LOAD_START_URL_ON_SCREENON, false)) { mWebView.loadStartUrl(); } } @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(ApplicationStatus status) { status.set(getString(R.string.app_name), "Version: " + getAppVersion()); if (mFlashService == null || !mFlashService.isAvailable()) { status.set(getString(R.string.flashControl), getString(R.string.unavailable)); } if (mMotionDetector == null || mCam == null || !mCam.canBeUsed()) { status.set(getString(R.string.pref_motion), getString(R.string.unavailable)); } String webview = ""; PackageManager pm = getPackageManager(); try { PackageInfo pi = pm.getPackageInfo("com.google.android.webview", 0); webview += "com.google.android.webview " + pi.versionName + "/" + pi.versionCode + "\n"; } catch (PackageManager.NameNotFoundException ignored) { } try { PackageInfo pi = pm.getPackageInfo("com.android.webview", 0); webview += "com.android.webview " + pi.versionName + "/" + pi.versionCode + "\n"; } catch (PackageManager.NameNotFoundException ignored) { } String userAgentString = mWebView.getSettings().getUserAgentString(); userAgentString = userAgentString.replaceAll(".* Chrome/", ""); userAgentString = userAgentString.replaceAll(" .*", ""); webview += "user agent " + userAgentString; status.set("Webview", webview.trim()); } private String getAppVersion() { String version = BuildConfig.VERSION_NAME; if (version.endsWith("pre")) { Date buildDate = new Date(BuildConfig.TIMESTAMP); version += " (" + UiUtil.formatDateTime(buildDate) + ")"; } return version; } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (requestCode == Constants.REQUEST_CAMERA) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(MainActivity.this); if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { if (mCam != null) { mCam.updateFromPreferences(prefs); updateMotionPreferences(); } } else { SharedPreferences.Editor editor1 = prefs.edit(); editor1.putBoolean(Constants.PREF_MOTION_DETECTION_ENABLED, false); editor1.putBoolean(Constants.PREF_MOTION_DETECTION_PREVIEW, false); editor1.apply(); } } } @Override protected void onPause() { unbindService(mSC); if (mService != null) { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel("de.vier_bier.habpanelviewer.status", "Status", NotificationManager.IMPORTANCE_MIN); channel.enableLights(false); channel.setSound(null, null); ((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel); } NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "de.vier_bier.habpanelviewer.status"); builder.setSmallIcon(R.drawable.logo); mService.startForeground(42, builder.build()); } final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(MainActivity.this); boolean pauseWebview = prefs.getBoolean(Constants.PREF_PAUSE_WEBVIEW, false); if (pauseWebview && !((PowerManager) getSystemService(POWER_SERVICE)).isInteractive()) { mWebView.pause(); } super.onPause(); } @Override protected void onResume() { super.onResume(); final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(MainActivity.this); mWebView.resume(prefs.getBoolean(Constants.PREF_LOAD_START_URL_ON_SCREENON, false)); if (mService != null) { mService.stopForeground(true); } bindService(new Intent(getBaseContext(), TrackShutdownService.class), mSC, Context.BIND_AUTO_CREATE); } @Override public void onStart() { super.onStart(); Intent permissionIntent = PermissionUtil.createRequestPermissionsIntent(this); if (permissionIntent != null) { startActivityForResult(permissionIntent, Constants.REQUEST_VALIDATE); return; } final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(MainActivity.this); NavigationView navigationView = findViewById(R.id.nav_view); DrawerLayout.LayoutParams params = (DrawerLayout.LayoutParams) navigationView.getLayoutParams(); final String menuPos = prefs.getString(Constants.PREF_MENU_POSITION, ""); if (getString(R.string.left).equalsIgnoreCase(menuPos)) { params.gravity = Gravity.START; } else { params.gravity = Gravity.END; } if (mRestartingExceptionHandler != null) { mRestartingExceptionHandler.updateFromPreferences(prefs); } if (mCommandQueue != null) { mCommandQueue.updateFromPreferences(prefs); } if (mCapturer == null && prefs.getBoolean(Constants.PREF_CAPTURE_SCREEN_ENABLED, false)) { MediaProjectionManager projectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE); startActivityForResult(projectionManager.createScreenCaptureIntent(), Constants.REQUEST_MEDIA_PROJECTION); } else if (mCapturer != null && !prefs.getBoolean(Constants.PREF_CAPTURE_SCREEN_ENABLED, false)) { mCapturer.terminate(); mCapturer = null; } for (IDeviceMonitor m : mMonitors) { m.updateFromPreferences(prefs); } mConnectedIndicator.updateFromPreferences(prefs); mWebView.updateFromPreferences(prefs); mServerConnection.updateFromPreferences(prefs, this); updateMotionPreferences(); if (prefs.getBoolean(Constants.PREF_SHOW_CONTEXT_MENU, true)) { registerForContextMenu(mWebView); } else { unregisterForContextMenu(mWebView); } } public void updateMotionPreferences() { final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(MainActivity.this); if (mCam != null) { mCam.updateFromPreferences(prefs); } if (mMotionDetector != null) { mMotionDetector.updateFromPreferences(prefs); } SurfaceView motionView = findViewById(R.id.motionView); boolean showPreview = prefs.getBoolean(Constants.PREF_MOTION_DETECTION_PREVIEW, false); if (showPreview && mCam != null && mCam.canBeUsed()) { ViewGroup.LayoutParams params = motionView.getLayoutParams(); params.height = 480; params.width = 640; motionView.setLayoutParams(params); motionView.setVisibility(View.VISIBLE); } else { motionView.setVisibility(View.INVISIBLE); } } @Override public View getScreenOnView() { return mWebView; } @Override public void onBackPressed() { DrawerLayout drawer = findViewById(R.id.drawer_layout); if (drawer.isDrawerOpen(GravityCompat.START)) { drawer.closeDrawer(GravityCompat.START); } else if (mWebView.canGoBack()) { mWebView.goBack(); } else { super.onBackPressed(); } } @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { int id = item.getItemId(); if (id == R.id.action_preferences) { showPreferences(); } else if (id == R.id.action_start_app) { Intent launchIntent = getLaunchIntent(); if (launchIntent != null) { startActivityForResult(launchIntent, Constants.REQUEST_PICK_APPLICATION); } } else if (id == R.id.action_info) { startActivity(StatusInfoActivity.class); } else if (id == R.id.action_cmd_log) { startActivity(CommandLogActivity.class); } else if (id == R.id.action_help) { startActivity(HelpActivity.class); } else if (id == R.id.action_discover) { showIntro(); } else if (id == R.id.action_show_log) { startActivity(LogActivity.class); } else if (id == R.id.action_restart) { restartApp(); } else if (id == R.id.action_enter_credentials) { if (mServerConnection.getSseConnection().getStatus() == SseConnection.Status.UNAUTHORIZED) { mConnectionListener.statusChanged(SseConnection.Status.UNAUTHORIZED); // leave drawer open so connection status is visible return true; } } DrawerLayout drawer = findViewById(R.id.drawer_layout); drawer.closeDrawers(); return true; } private void restartApp() { destroy(); ProcessPhoenix.triggerRebirth(this); } private Intent getLaunchIntent() { Intent main = new Intent(Intent.ACTION_MAIN); main.addCategory(Intent.CATEGORY_LAUNCHER); Intent chooser = new Intent(Intent.ACTION_PICK_ACTIVITY); chooser.putExtra(Intent.EXTRA_TITLE, "Select App to start"); chooser.putExtra(Intent.EXTRA_INTENT, main); return chooser; } private void showPreferences() { Intent intent = new Intent(MainActivity.this, PreferenceActivity.class); intent.putExtra(Constants.INTENT_FLAG_CAMERA_ENABLED, mCam != null); intent.putExtra(Constants.INTENT_FLAG_FLASH_ENABLED, mFlashService != null && mFlashService.isAvailable()); intent.putExtra(Constants.INTENT_FLAG_MOTION_ENABLED, mMotionDetector != null && mCam != null && mCam.canBeUsed()); for (IDeviceMonitor m : mMonitors) { m.disablePreferences(intent); } startActivityForResult(intent, 0); } private void startActivity(Class activityClass) { Intent intent = new Intent(); intent.setClass(MainActivity.this, activityClass); startActivityForResult(intent, 0); } private void showIntro() { Intent intent = new Intent(MainActivity.this, IntroActivity.class); intent.putExtra(Constants.INTENT_FLAG_INTRO_ONLY, true); new Thread(() -> runOnUiThread(() -> startActivity(intent))).start(); } }