OSDN Git Service

Taskbar 3.9 (release 1)
authorBraden Farmer <farmerbb@gmail.com>
Sat, 10 Mar 2018 18:46:40 +0000 (11:46 -0700)
committerBraden Farmer <farmerbb@gmail.com>
Sat, 10 Mar 2018 18:46:40 +0000 (11:46 -0700)
Play Store beta release

* Greatly improved integration with SecondScreen
* Improved integration with BlissOS
* Lots of bug fixes and code cleanup

46 files changed:
app/build.gradle
app/src/androidx86/AndroidManifest.xml
app/src/compat-26/java/com/farmerbb/taskbar/util/CompatUtils.java
app/src/main/java/com/farmerbb/taskbar/MainActivity.java
app/src/main/java/com/farmerbb/taskbar/activity/ContextMenuActivity.java
app/src/main/java/com/farmerbb/taskbar/activity/DummyActivity.java
app/src/main/java/com/farmerbb/taskbar/activity/HomeActivity.java
app/src/main/java/com/farmerbb/taskbar/activity/InvisibleActivityFreeform.java
app/src/main/java/com/farmerbb/taskbar/activity/NavigationBarButtonsActivity.java
app/src/main/java/com/farmerbb/taskbar/adapter/StartMenuAdapter.java
app/src/main/java/com/farmerbb/taskbar/fragment/AdvancedFragment.java
app/src/main/java/com/farmerbb/taskbar/fragment/FreeformModeFragment.java
app/src/main/java/com/farmerbb/taskbar/fragment/SettingsFragment.java
app/src/main/java/com/farmerbb/taskbar/receiver/BootReceiver.java
app/src/main/java/com/farmerbb/taskbar/receiver/PackageUpgradeReceiver.java
app/src/main/java/com/farmerbb/taskbar/receiver/QuitReceiver.java
app/src/main/java/com/farmerbb/taskbar/receiver/StartReceiver.java
app/src/main/java/com/farmerbb/taskbar/service/DashboardService.java
app/src/main/java/com/farmerbb/taskbar/service/NotificationService.java
app/src/main/java/com/farmerbb/taskbar/service/StartMenuService.java
app/src/main/java/com/farmerbb/taskbar/service/TaskbarService.java
app/src/main/java/com/farmerbb/taskbar/util/U.java
app/src/main/java/com/jrummyapps/android/os/SystemProperties.java [new file with mode: 0644]
app/src/main/res/values-de/strings.xml
app/src/main/res/values-h720dp/dimens.xml
app/src/main/res/values-h900dp/dimens.xml [new file with mode: 0644]
app/src/main/res/values-ja/strings.xml
app/src/main/res/values-ru/strings.xml
app/src/main/res/values-w600dp-v24/dimens.xml
app/src/main/res/values-w600dp/dimens.xml
app/src/main/res/values-w720dp/dimens.xml
app/src/main/res/values-zh-rCN/strings.xml
app/src/main/res/values/colors.xml
app/src/main/res/values/strings.xml
app/src/playstore/AndroidManifest.xml
app/src/playstore/java/com/farmerbb/taskbar/receiver/DisableFreeformReceiver.java [new file with mode: 0644]
app/src/playstore/java/com/farmerbb/taskbar/receiver/DisableHomeReceiver.java [moved from app/src/main/java/com/farmerbb/taskbar/receiver/DisableHomeReceiver.java with 60% similarity]
app/src/playstore/java/com/farmerbb/taskbar/receiver/EnableFreeformReceiver.java [new file with mode: 0644]
app/src/playstore/java/com/farmerbb/taskbar/receiver/EnableHomeReceiver.java [moved from app/src/main/java/com/farmerbb/taskbar/receiver/EnableHomeReceiver.java with 75% similarity]
app/src/playstore/java/com/farmerbb/taskbar/receiver/ReceiveSettingsReceiver.java [moved from app/src/main/java/com/farmerbb/taskbar/receiver/ReceiveSettingsReceiver.java with 100% similarity]
app/src/playstore/java/com/farmerbb/taskbar/receiver/SendSettingsReceiver.java [moved from app/src/main/java/com/farmerbb/taskbar/receiver/SendSettingsReceiver.java with 99% similarity]
app/src/playstore/res/drawable-anydpi-v26/ic_play_arrow_black_24dp.xml [new file with mode: 0644]
app/src/playstore/res/drawable-anydpi-v26/ic_web_asset_black_24dp_alt.xml [new file with mode: 0644]
app/src/playstore/res/drawable-anydpi-v26/shortcut_icon_freeform.xml [new file with mode: 0644]
app/src/playstore/res/drawable-anydpi-v26/shortcut_icon_start.xml [new file with mode: 0644]
gradle/wrapper/gradle-wrapper.properties

index 4703df2..adebf10 100644 (file)
@@ -19,8 +19,8 @@ android {
         minSdkVersion 21
         targetSdkVersion SDK_VERSION
 
-        versionCode 181
-        versionName "3.8.2"
+        versionCode 182
+        versionName "3.9"
 
         resConfigs "en", "ja", "ru", "de", "zh-rCN"
 
index e812ab4..121dd0a 100644 (file)
 <!-- Manifest used for Android-x86 builds of Taskbar, with the following changes:
 
      * HomeActivity is enabled by default
-     * SendSettingsReceiver and ReceiveSettingsReceiver are not exposed
+     * Certain BroadcastReceivers are not exposed
 -->
-<manifest android:versionCode="181"
-          android:versionName="3.8.2"
+<manifest android:versionCode="182"
+          android:versionName="3.9"
           xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.farmerbb.taskbar" >
 
     <permission android:name="com.farmerbb.taskbar.androidx86.START_STOP_TASKBAR"
         android:protectionLevel="signature" />
 
-    <permission android:name="com.farmerbb.taskbar.androidx86.ENABLE_DISABLE_HOME"
-        android:protectionLevel="signature" />
-
     <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
             </intent-filter>
         </receiver>
         <receiver
-            android:name=".receiver.EnableHomeReceiver"
-            android:enabled="true"
-            android:exported="true"
-            android:permission="com.farmerbb.taskbar.androidx86.ENABLE_DISABLE_HOME" >
-            <intent-filter>
-                <action android:name="com.farmerbb.taskbar.ENABLE_HOME"/>
-            </intent-filter>
-        </receiver>
-        <receiver
-            android:name=".receiver.DisableHomeReceiver"
-            android:enabled="true"
-            android:exported="true"
-            android:permission="com.farmerbb.taskbar.androidx86.ENABLE_DISABLE_HOME" >
-            <intent-filter>
-                <action android:name="com.farmerbb.taskbar.DISABLE_HOME"/>
-            </intent-filter>
-        </receiver>
-        <receiver
             android:name=".receiver.ToggleFreeformModeReceiver"
             android:permission="com.farmerbb.taskbar.androidx86.START_STOP_TASKBAR" >
             <intent-filter>
index cccbb1a..2a44315 100644 (file)
@@ -69,9 +69,10 @@ public class CompatUtils {
     }
 
     public static void startForegroundService(Context context, Intent intent) {
-        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
-            context.startForegroundService(intent);
-        else
+        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+            if(Settings.canDrawOverlays(context))
+                context.startForegroundService(intent);
+        } else
             context.startService(intent);
     }
 
index ed93599..679536d 100644 (file)
@@ -16,7 +16,6 @@
 package com.farmerbb.taskbar;
 
 import android.app.AlertDialog;
-import android.app.AppOpsManager;
 import android.app.FragmentTransaction;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
@@ -25,7 +24,6 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.SharedPreferences;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ShortcutInfo;
@@ -34,7 +32,6 @@ import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
-import android.provider.Settings;
 import android.support.v4.content.LocalBroadcastManager;
 import android.support.v7.app.ActionBar;
 import android.support.v7.app.AppCompatActivity;
@@ -93,8 +90,7 @@ public class MainActivity extends AppCompatActivity {
 
         // Ensure that components that should be enabled are enabled properly
         boolean launcherEnabled = (pref.getBoolean("launcher", false) && U.canDrawOverlays(this))
-                || U.hasSupportLibrary(this)
-                || BuildConfig.APPLICATION_ID.equals(BuildConfig.ANDROIDX86_APPLICATION_ID);
+                || U.isLauncherPermanentlyEnabled(this);
 
         editor.putBoolean("launcher", launcherEnabled);
         editor.apply();
@@ -165,10 +161,10 @@ public class MainActivity extends AppCompatActivity {
                         boolean firstRun = pref.getBoolean("first_run", true);
                         startTaskbarService();
 
-                        if(firstRun && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !U.isSystemApp(this))
-                            showRecentAppsDialog();
+                        if(firstRun)
+                            U.showRecentAppsDialog(this);
                     } else {
-                        U.showPermissionDialog(MainActivity.this);
+                        U.showPermissionDialog(this);
                         compoundButton.setChecked(false);
                     }
                 } else
@@ -251,36 +247,6 @@ public class MainActivity extends AppCompatActivity {
         }
     }
 
-    private void showRecentAppsDialog() {
-        ApplicationInfo applicationInfo = null;
-        try {
-            applicationInfo = getPackageManager().getApplicationInfo(BuildConfig.APPLICATION_ID, 0);
-        } catch (PackageManager.NameNotFoundException e) { /* Gracefully fail */ }
-
-        if(applicationInfo != null) {
-            AppOpsManager appOpsManager = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);
-            int mode = appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, applicationInfo.uid, applicationInfo.packageName);
-
-            if(mode != AppOpsManager.MODE_ALLOWED) {
-                AlertDialog.Builder builder = new AlertDialog.Builder(this);
-                builder.setTitle(R.string.pref_header_recent_apps)
-                        .setMessage(R.string.enable_recent_apps)
-                        .setPositiveButton(R.string.action_ok, (dialog, which) -> {
-                            try {
-                                startActivity(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS));
-                                U.showToastLong(this, R.string.usage_stats_message);
-                            } catch (ActivityNotFoundException e) {
-                                U.showErrorDialog(this, "GET_USAGE_STATS");
-                            }
-                        }).setNegativeButton(R.string.action_cancel, null);
-
-                AlertDialog dialog = builder.create();
-                dialog.show();
-                dialog.setCancelable(false);
-            }
-        }
-    }
-
     @Override
     protected void onResume() {
         super.onResume();
index ad807dd..5d776d4 100644 (file)
@@ -411,7 +411,9 @@ public class ContextMenuActivity extends PreferenceActivity implements Preferenc
                     intent2.putExtra("uninstall", packageName);
                     intent2.putExtra("user_id", userId);
 
-                    startActivity(intent2);
+                    try {
+                        startActivity(intent2);
+                    } catch (IllegalArgumentException e) { /* Gracefully fail */ }
                 } else {
                     Intent intent2 = new Intent(Intent.ACTION_DELETE, Uri.parse("package:" + packageName));
                     intent2.putExtra(Intent.EXTRA_USER, userManager.getUserForSerialNumber(userId));
@@ -419,7 +421,7 @@ public class ContextMenuActivity extends PreferenceActivity implements Preferenc
                     new Handler().post(() -> {
                         try {
                             startActivity(intent2);
-                        } catch (ActivityNotFoundException e) { /* Gracefully fail */ }
+                        } catch (ActivityNotFoundException | IllegalArgumentException e) { /* Gracefully fail */ }
                     });
                 }
 
@@ -431,7 +433,10 @@ public class ContextMenuActivity extends PreferenceActivity implements Preferenc
                 U.launchApp(this, () -> {
                     Intent intent2 = new Intent(this, MainActivity.class);
                     intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
-                    startActivity(intent2, U.getActivityOptionsBundle(ApplicationType.APPLICATION));
+
+                    try {
+                        startActivity(intent2, U.getActivityOptionsBundle(ApplicationType.APPLICATION));
+                    } catch (IllegalArgumentException e) { /* Gracefully fail */ }
                 });
 
                 showStartMenu = false;
@@ -485,9 +490,8 @@ public class ContextMenuActivity extends PreferenceActivity implements Preferenc
             case "show_window_sizes":
                 generateWindowSizes();
 
-                if(Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) {
+                if(U.hasBrokenSetLaunchBoundsApi())
                     U.showToastLong(this, R.string.window_sizes_not_available);
-                }
 
                 getListView().setOnItemLongClickListener((parent, view, position, id) -> {
                     String[] windowSizes = { "standard", "large", "fullscreen", "half_left", "half_right", "phone_size" };
@@ -515,7 +519,7 @@ public class ContextMenuActivity extends PreferenceActivity implements Preferenc
 
                 U.launchApp(getApplicationContext(), packageName, componentName, userId, windowSize, false, true);
 
-                if(Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1)
+                if(U.hasBrokenSetLaunchBoundsApi())
                     U.cancelToast();
 
                 showStartMenu = false;
@@ -559,8 +563,11 @@ public class ContextMenuActivity extends PreferenceActivity implements Preferenc
                     intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT);
 
                     U.launchAppMaximized(getApplicationContext(), intent);
-                } else
-                    startActivity(intent);
+                } else {
+                    try {
+                        startActivity(intent);
+                    } catch (IllegalArgumentException e) { /* Gracefully fail */ }
+                }
 
                 showStartMenu = false;
                 shouldHideTaskbar = true;
@@ -595,7 +602,7 @@ public class ContextMenuActivity extends PreferenceActivity implements Preferenc
                         startActivity(fileManagerIntent, U.getActivityOptionsBundle(ApplicationType.APPLICATION));
                     } catch (ActivityNotFoundException e) {
                         U.showToast(this, R.string.lock_device_not_supported);
-                    }
+                    } catch (IllegalArgumentException e) { /* Gracefully fail */ }
                 });
 
                 showStartMenu = false;
@@ -611,7 +618,7 @@ public class ContextMenuActivity extends PreferenceActivity implements Preferenc
                         startActivity(settingsIntent, U.getActivityOptionsBundle(ApplicationType.APPLICATION));
                     } catch (ActivityNotFoundException e) {
                         U.showToast(this, R.string.lock_device_not_supported);
-                    }
+                    } catch (IllegalArgumentException e) { /* Gracefully fail */ }
                 });
 
                 showStartMenu = false;
@@ -722,7 +729,7 @@ public class ContextMenuActivity extends PreferenceActivity implements Preferenc
 
             getListView().setOnItemLongClickListener(null);
 
-            if(Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1)
+            if(U.hasBrokenSetLaunchBoundsApi())
                 U.cancelToast();
         } else {
             if(contextMenuFix && !showStartMenu)
index f2de763..06cd76d 100644 (file)
@@ -29,7 +29,6 @@ import android.os.Bundle;
 import android.os.Handler;
 import android.os.UserManager;
 import android.provider.Settings;
-import android.support.v7.view.ContextThemeWrapper;
 import android.view.View;
 
 import com.farmerbb.taskbar.R;
@@ -67,19 +66,7 @@ public class DummyActivity extends Activity {
                     startActivity(intent);
                 } catch (ActivityNotFoundException e) { /* Gracefully fail */ }
             } else if(getIntent().hasExtra("device_admin")) {
-                SharedPreferences pref = U.getSharedPreferences(this);
-
-                int theme = -1;
-                switch(pref.getString("theme", "light")) {
-                    case "light":
-                        theme = R.style.AppTheme;
-                        break;
-                    case "dark":
-                        theme = R.style.AppTheme_Dark;
-                        break;
-                }
-
-                AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(this, theme));
+                AlertDialog.Builder builder = new AlertDialog.Builder(U.wrapContext(this));
                 builder.setTitle(R.string.permission_dialog_title)
                         .setMessage(R.string.device_admin_disclosure)
                         .setNegativeButton(R.string.action_cancel, (dialog, which) -> new Handler().post(this::finish))
@@ -101,19 +88,7 @@ public class DummyActivity extends Activity {
                 dialog.show();
                 dialog.setCancelable(false);
             } else if(getIntent().hasExtra("accessibility")) {
-                SharedPreferences pref = U.getSharedPreferences(this);
-
-                int theme = -1;
-                switch(pref.getString("theme", "light")) {
-                    case "light":
-                        theme = R.style.AppTheme;
-                        break;
-                    case "dark":
-                        theme = R.style.AppTheme_Dark;
-                        break;
-                }
-
-                AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(this, theme));
+                AlertDialog.Builder builder = new AlertDialog.Builder(U.wrapContext(this));
                 builder.setTitle(R.string.permission_dialog_title)
                         .setMessage(R.string.enable_accessibility)
                         .setNegativeButton(R.string.action_cancel, (dialog, which) -> new Handler().post(this::finish))
@@ -144,7 +119,12 @@ public class DummyActivity extends Activity {
                 }
 
                 finish();
-            } else finish();
+            } else if(getIntent().hasExtra("show_permission_dialog"))
+                U.showPermissionDialog(U.wrapContext(this), null, this::finish);
+            else if(getIntent().hasExtra("show_recent_apps_dialog"))
+                U.showRecentAppsDialog(U.wrapContext(this), null, this::finish);
+            else
+                finish();
         }
     }
 }
\ No newline at end of file
index 2a9b1d5..610834e 100644 (file)
@@ -30,7 +30,6 @@ import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.support.v4.content.LocalBroadcastManager;
-import android.support.v7.view.ContextThemeWrapper;
 import android.util.DisplayMetrics;
 import android.view.GestureDetector;
 import android.view.MotionEvent;
@@ -150,17 +149,7 @@ public class HomeActivity extends Activity {
                     if(pref.getBoolean("double_tap_to_sleep", false)) {
                         U.lockDevice(HomeActivity.this);
                     } else {
-                        int theme = -1;
-                        switch(pref.getString("theme", "light")) {
-                            case "light":
-                                theme = R.style.AppTheme;
-                                break;
-                            case "dark":
-                                theme = R.style.AppTheme_Dark;
-                                break;
-                        }
-
-                        AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(HomeActivity.this, theme));
+                        AlertDialog.Builder builder = new AlertDialog.Builder(U.wrapContext(HomeActivity.this));
                         builder.setTitle(R.string.double_tap_to_sleep)
                                 .setMessage(R.string.enable_double_tap_to_sleep)
                                 .setNegativeButton(pref.getBoolean("double_tap_dialog_shown", false)
@@ -206,6 +195,9 @@ public class HomeActivity extends Activity {
         LocalBroadcastManager.getInstance(this).registerReceiver(killReceiver, new IntentFilter("com.farmerbb.taskbar.KILL_HOME_ACTIVITY"));
         LocalBroadcastManager.getInstance(this).registerReceiver(forceTaskbarStartReceiver, new IntentFilter("com.farmerbb.taskbar.FORCE_TASKBAR_RESTART"));
 
+        SharedPreferences pref = U.getSharedPreferences(this);
+        pref.edit().putBoolean("launcher", true).apply();
+
         U.initPrefs(this);
     }
 
@@ -268,7 +260,9 @@ public class HomeActivity extends Activity {
             } else if(U.launcherIsDefault(this))
                 startFreeformHack();
         } else
-            dialog = U.showPermissionDialog(this);
+            dialog = U.showPermissionDialog(U.wrapContext(this),
+                    () -> dialog = U.showErrorDialog(U.wrapContext(this), "SYSTEM_ALERT_WINDOW"),
+                    null);
     }
 
     private boolean bootToFreeform() {
@@ -279,12 +273,23 @@ public class HomeActivity extends Activity {
     }
 
     private void startTaskbar() {
+        SharedPreferences pref = U.getSharedPreferences(this);
+        if(pref.getBoolean("first_run", true)) {
+            SharedPreferences.Editor editor = pref.edit();
+            editor.putBoolean("first_run", false);
+            editor.putBoolean("collapsed", true);
+            editor.apply();
+
+            dialog = U.showRecentAppsDialog(U.wrapContext(this),
+                    () -> dialog = U.showErrorDialog(U.wrapContext(this), "GET_USAGE_STATS"),
+                    null);
+        }
+
         // We always start the Taskbar and Start Menu services, even if the app isn't normally running
         startService(new Intent(this, TaskbarService.class));
         startService(new Intent(this, StartMenuService.class));
         startService(new Intent(this, DashboardService.class));
 
-        SharedPreferences pref = U.getSharedPreferences(this);
         if(pref.getBoolean("taskbar_active", false) && !U.isServiceRunning(this, NotificationService.class))
             pref.edit().putBoolean("taskbar_active", false).apply();
 
index 36fb6ac..30cd023 100644 (file)
@@ -196,12 +196,27 @@ public class InvisibleActivityFreeform extends Activity {
             LauncherHelper.getInstance().setOnHomeScreen(true);
             bootToFreeform = true;
 
+            SharedPreferences pref = U.getSharedPreferences(this);
+            if(pref.getBoolean("first_run", true)) {
+                SharedPreferences.Editor editor = pref.edit();
+                editor.putBoolean("first_run", false);
+                editor.putBoolean("collapsed", true);
+                editor.apply();
+
+                new Handler().postDelayed(() -> {
+                    Intent intent = new Intent(this, DummyActivity.class);
+                    intent.putExtra("show_recent_apps_dialog", true);
+                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+                    startActivity(intent);
+                }, 250);
+            }
+
             // We always start the Taskbar and Start Menu services, even if the app isn't normally running
             startService(new Intent(this, TaskbarService.class));
             startService(new Intent(this, StartMenuService.class));
             startService(new Intent(this, DashboardService.class));
 
-            SharedPreferences pref = U.getSharedPreferences(this);
             if(pref.getBoolean("taskbar_active", false) && !U.isServiceRunning(this, NotificationService.class))
                 pref.edit().putBoolean("taskbar_active", false).apply();
 
index 0eb1aa4..a611b8c 100644 (file)
@@ -38,7 +38,7 @@ public class NavigationBarButtonsActivity extends PreferenceActivity implements
         findPreference("button_home").setOnPreferenceClickListener(this);
         findPreference("button_recents").setOnPreferenceClickListener(this);
 
-        if(U.hasSupportLibrary(this))
+        if(U.isBlissOs(this))
             findPreference("auto_hide_navbar").setOnPreferenceClickListener(this);
         else
             getPreferenceScreen().removePreference(findPreference("auto_hide_navbar_category"));
index 0eefc3a..ff32d02 100644 (file)
@@ -116,13 +116,13 @@ public class StartMenuAdapter extends ArrayAdapter<AppEntry> {
                 openContextMenu(entry, location);
             }
 
-            if(action == MotionEvent.ACTION_SCROLL && visualFeedbackEnabled())
+            if(action == MotionEvent.ACTION_SCROLL && U.visualFeedbackEnabled(getContext()))
                 view.setBackgroundColor(0);
 
             return false;
         });
 
-        if(visualFeedbackEnabled()) {
+        if(U.visualFeedbackEnabled(getContext())) {
             layout.setOnHoverListener((v, event) -> {
                 if(event.getAction() == MotionEvent.ACTION_HOVER_ENTER) {
                     int backgroundTint = pref.getBoolean("transparent_start_menu", false)
@@ -190,7 +190,7 @@ public class StartMenuAdapter extends ArrayAdapter<AppEntry> {
             if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && FreeformHackHelper.getInstance().isInFreeformWorkspace()) {
                 DisplayMetrics metrics = U.getRealDisplayMetrics(getContext());
 
-                if(intent != null && Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1)
+                if(intent != null && U.hasBrokenSetLaunchBoundsApi())
                     intent.putExtra("context_menu_fix", true);
 
                 getContext().startActivity(intent, U.getActivityOptions(ApplicationType.CONTEXT_MENU).setLaunchBounds(new Rect(0, 0, metrics.widthPixels, metrics.heightPixels)).toBundle());
@@ -205,9 +205,4 @@ public class StartMenuAdapter extends ArrayAdapter<AppEntry> {
                 && pref.getBoolean("freeform_hack", false)
                 && !FreeformHackHelper.getInstance().isFreeformHackActive();
     }
-
-    private boolean visualFeedbackEnabled() {
-        SharedPreferences pref = U.getSharedPreferences(getContext());
-        return Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1 && pref.getBoolean("visual_feedback", true);
-    }
 }
index 5890270..79056a7 100644 (file)
 package com.farmerbb.taskbar.fragment;
 
 import android.annotation.SuppressLint;
+import android.app.Activity;
 import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
@@ -52,6 +55,15 @@ public class AdvancedFragment extends SettingsFragment implements Preference.OnP
 
     boolean secondScreenPrefEnabled = false;
 
+    private BroadcastReceiver homeToggleReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            SharedPreferences pref = U.getSharedPreferences(getActivity());
+            CheckBoxPreference checkBox = (CheckBoxPreference) findPreference("launcher");
+            checkBox.setChecked(pref.getBoolean("launcher", false));
+        }
+    };
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         finishedLoadingPrefs = false;
@@ -80,8 +92,7 @@ public class AdvancedFragment extends SettingsFragment implements Preference.OnP
 
         SharedPreferences pref = U.getSharedPreferences(getActivity());
         boolean lockHomeToggle = pref.getBoolean("launcher", false)
-                && (U.hasSupportLibrary(getActivity())
-                || BuildConfig.APPLICATION_ID.equals(BuildConfig.ANDROIDX86_APPLICATION_ID));
+                && U.isLauncherPermanentlyEnabled(getActivity());
 
         findPreference("launcher").setEnabled(!lockHomeToggle);
 
@@ -105,7 +116,7 @@ public class AdvancedFragment extends SettingsFragment implements Preference.OnP
 
         if(secondScreenPrefEnabled) {
             findPreference("secondscreen").setTitle(
-                    getSecondScreenPackageName() == null
+                    U.getSecondScreenPackageName(getActivity()) == null
                             ? R.string.pref_secondscreen_title_install
                             : R.string.pref_secondscreen_title_open);
         }
@@ -113,6 +124,21 @@ public class AdvancedFragment extends SettingsFragment implements Preference.OnP
         updateDashboardGridSize(false);
     }
 
+    @Override
+    public void onAttach(Activity activity) {
+        super.onAttach(activity);
+
+        LocalBroadcastManager.getInstance(getActivity()).registerReceiver(homeToggleReceiver,
+                new IntentFilter("com.farmerbb.taskbar.LAUNCHER_PREF_CHANGED"));
+    }
+
+    @Override
+    public void onDetach() {
+        LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(homeToggleReceiver);
+
+        super.onDetach();
+    }
+
     @SuppressLint("SetTextI18n")
     @Override
     public boolean onPreferenceClick(final Preference p) {
@@ -236,7 +262,7 @@ public class AdvancedFragment extends SettingsFragment implements Preference.OnP
                 break;
             case "secondscreen":
                 PackageManager packageManager = getActivity().getPackageManager();
-                String packageName = getSecondScreenPackageName();
+                String packageName = U.getSecondScreenPackageName(getActivity());
                 Intent intent2;
 
                 if(packageName == null) {
@@ -284,23 +310,4 @@ public class AdvancedFragment extends SettingsFragment implements Preference.OnP
 
         if(restartTaskbar) U.restartTaskbar(getActivity());
     }
-
-    private String getSecondScreenPackageName() {
-        PackageManager pm = getActivity().getPackageManager();
-        String packageName;
-
-        try {
-            packageName = "com.farmerbb.secondscreen.free";
-            pm.getPackageInfo(packageName, 0);
-        } catch (PackageManager.NameNotFoundException e) {
-            try {
-                packageName = "com.farmerbb.secondscreen";
-                pm.getPackageInfo(packageName, 0);
-            } catch (PackageManager.NameNotFoundException e1) {
-                packageName = null;
-            }
-        }
-
-        return packageName;
-    }
 }
index 487d960..27ee610 100644 (file)
@@ -91,12 +91,11 @@ public class FreeformModeFragment extends SettingsFragment implements Preference
             AlertDialog dialog = builder.create();
             dialog.show();
             dialog.setCancelable(false);
-        } else if(U.isUntestedAndroidVersion(getActivity())
-                && pref.getInt("current_api_version", Build.VERSION.SDK_INT - 1) < Build.VERSION.SDK_INT) {
+        } else if(U.isUntestedAndroidVersion(getActivity())) {
             AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
             builder.setTitle(R.string.samsung_freeform_title)
                     .setMessage(R.string.dialog_upgrade_message)
-                    .setPositiveButton(R.string.action_ok, (dialog, which) -> pref.edit().putInt("current_api_version", Build.VERSION.SDK_INT).apply());
+                    .setPositiveButton(R.string.action_ok, (dialog, which) -> pref.edit().putFloat("current_api_version_new", U.getCurrentApiVersion()).apply());
 
             AlertDialog dialog = builder.create();
             dialog.show();
@@ -156,7 +155,7 @@ public class FreeformModeFragment extends SettingsFragment implements Preference
                             if(Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) {
                                 builder.setTitle(R.string.freeform_dialog_title)
                                         .setMessage(R.string.freeform_dialog_message_alt)
-                                        .setPositiveButton(R.string.action_ok, (dialogInterface, i) -> freeformSetupComplete());
+                                        .setPositiveButton(R.string.action_continue, (dialogInterface, i) -> freeformSetupComplete());
                             } else {
                                 builder.setTitle(R.string.freeform_dialog_title)
                                         .setMessage(R.string.freeform_dialog_message)
@@ -208,10 +207,8 @@ public class FreeformModeFragment extends SettingsFragment implements Preference
                 CompatUtils.pinAppShortcut(getActivity());
                 break;
             case "window_size":
-                if(Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) {
+                if(U.hasBrokenSetLaunchBoundsApi())
                     U.showToastLong(getActivity(), R.string.window_sizes_not_available);
-                }
-
                 break;
         }
 
index eeaeced..5c2c1df 100644 (file)
@@ -33,7 +33,7 @@ import com.farmerbb.taskbar.MainActivity;
 import com.farmerbb.taskbar.util.FreeformHackHelper;
 import com.farmerbb.taskbar.util.U;
 
-public class SettingsFragment extends PreferenceFragment {
+public abstract class SettingsFragment extends PreferenceFragment {
 
     boolean finishedLoadingPrefs;
     boolean showReminderToast = false;
index 05f330d..fcadbda 100644 (file)
@@ -29,8 +29,12 @@ import com.farmerbb.taskbar.util.U;
 public class BootReceiver extends BroadcastReceiver {
     @Override
     public void onReceive(Context context, Intent intent) {
-        if(intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
+        if(Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
+            // Initialize preferences on BlissOS
             SharedPreferences pref = U.getSharedPreferences(context);
+            if(U.isBlissOs(context) && !pref.getBoolean("bliss_os_prefs", false))
+                U.initPrefs(context);
+
             SharedPreferences.Editor editor = pref.edit();
 
             if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
index c3c68a0..eb30825 100644 (file)
@@ -29,7 +29,7 @@ import com.farmerbb.taskbar.util.U;
 public class PackageUpgradeReceiver extends BroadcastReceiver {
     @Override
     public void onReceive(Context context, Intent intent) {
-        if(intent.getAction().equals(Intent.ACTION_MY_PACKAGE_REPLACED)) {
+        if(Intent.ACTION_MY_PACKAGE_REPLACED.equals(intent.getAction())) {
             SharedPreferences pref = U.getSharedPreferences(context);
             boolean startServices = false;
 
index a5301a4..ca8d29f 100644 (file)
@@ -32,24 +32,27 @@ import com.farmerbb.taskbar.util.U;
 public class QuitReceiver extends BroadcastReceiver {
     @Override
     public void onReceive(Context context, Intent intent) {
-        Intent taskbarIntent = new Intent(context, TaskbarService.class);
-        Intent startMenuIntent = new Intent(context, StartMenuService.class);
-        Intent dashboardIntent = new Intent(context, DashboardService.class);
-        Intent notificationIntent = new Intent(context, NotificationService.class);
-
         SharedPreferences pref = U.getSharedPreferences(context);
-        pref.edit().putBoolean("taskbar_active", false).apply();
+        if(!pref.getBoolean("skip_quit_receiver", false)) {
+            Intent taskbarIntent = new Intent(context, TaskbarService.class);
+            Intent startMenuIntent = new Intent(context, StartMenuService.class);
+            Intent dashboardIntent = new Intent(context, DashboardService.class);
+            Intent notificationIntent = new Intent(context, NotificationService.class);
+
+            pref.edit().putBoolean("taskbar_active", false).apply();
 
-        if(!LauncherHelper.getInstance().isOnHomeScreen()) {
-            context.stopService(taskbarIntent);
-            context.stopService(startMenuIntent);
-            context.stopService(dashboardIntent);
+            if(!LauncherHelper.getInstance().isOnHomeScreen()) {
+                context.stopService(taskbarIntent);
+                context.stopService(startMenuIntent);
+                context.stopService(dashboardIntent);
 
-            IconCache.getInstance(context).clearCache();
+                IconCache.getInstance(context).clearCache();
 
-            LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.START_MENU_DISAPPEARING"));
-        }
+                LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.START_MENU_DISAPPEARING"));
+            }
 
-        context.stopService(notificationIntent);
+            context.stopService(notificationIntent);
+        } else
+            pref.edit().remove("skip_quit_receiver").apply();
     }
 }
index 910c641..ed605af 100644 (file)
@@ -20,6 +20,7 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.os.Build;
+import android.os.Handler;
 
 import com.farmerbb.taskbar.activity.DummyActivity;
 import com.farmerbb.taskbar.service.NotificationService;
@@ -31,10 +32,20 @@ public class StartReceiver extends BroadcastReceiver {
     public void onReceive(Context context, Intent intent) {
         SharedPreferences pref = U.getSharedPreferences(context);
 
-        boolean taskbarNotActive = !pref.getBoolean("taskbar_active", false);
-        boolean taskbarActiveButHidden = pref.getBoolean("taskbar_active", false) && pref.getBoolean("is_hidden", false);
+        boolean taskbarNotActive = !U.isServiceRunning(context, NotificationService.class);
+        boolean taskbarActiveButHidden = !taskbarNotActive && pref.getBoolean("is_hidden", false);
+
+        if(!U.canDrawOverlays(context)) {
+            new Handler().postDelayed(() -> {
+                Intent intent2 = new Intent(context, DummyActivity.class);
+                intent2.putExtra("show_permission_dialog", true);
+                intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+                context.startActivity(intent2);
+            }, 250);
+        } else if(taskbarNotActive || taskbarActiveButHidden) {
+            U.initPrefs(context);
 
-        if(taskbarNotActive || taskbarActiveButHidden) {
             SharedPreferences.Editor editor = pref.edit();
             editor.putBoolean("is_hidden", false);
 
@@ -42,6 +53,14 @@ public class StartReceiver extends BroadcastReceiver {
                 if(pref.getBoolean("first_run", true)) {
                     editor.putBoolean("first_run", false);
                     editor.putBoolean("collapsed", true);
+
+                    new Handler().postDelayed(() -> {
+                        Intent intent2 = new Intent(context, DummyActivity.class);
+                        intent2.putExtra("show_recent_apps_dialog", true);
+                        intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+                        context.startActivity(intent2);
+                    }, 250);
                 }
 
                 editor.putBoolean("taskbar_active", true);
@@ -65,6 +84,7 @@ public class StartReceiver extends BroadcastReceiver {
             notificationIntent.putExtra("start_services", true);
 
             CompatUtils.startForegroundService(context, notificationIntent);
-        }
+        } else if(intent.hasExtra("secondscreen"))
+            pref.edit().putBoolean("skip_quit_receiver", true).apply();
     }
 }
index 0db5936..9a74772 100644 (file)
@@ -45,7 +45,6 @@ import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Process;
-import android.provider.Settings;
 import android.support.v4.content.LocalBroadcastManager;
 import android.support.v4.graphics.ColorUtils;
 import android.util.SparseArray;
@@ -177,7 +176,7 @@ public class DashboardService extends Service {
         SharedPreferences pref = U.getSharedPreferences(this);
         if(pref.getBoolean("dashboard", false)) {
             if(pref.getBoolean("taskbar_active", false) || LauncherHelper.getInstance().isOnHomeScreen()) {
-                if(Build.VERSION.SDK_INT < Build.VERSION_CODES.M || Settings.canDrawOverlays(this))
+                if(U.canDrawOverlays(this))
                     drawDashboard();
                 else {
                     pref.edit().putBoolean("taskbar_active", false).apply();
@@ -349,7 +348,7 @@ public class DashboardService extends Service {
             }
 
             if(inFreeformMode) {
-                if(intent != null && Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1)
+                if(intent != null && U.hasBrokenSetLaunchBoundsApi())
                     intent.putExtra("context_menu_fix", true);
 
                 U.launchAppMaximized(this, intent);
@@ -439,7 +438,7 @@ public class DashboardService extends Service {
             } catch (IllegalArgumentException e) { /* Gracefully fail */ }
 
             SharedPreferences pref = U.getSharedPreferences(this);
-            if(Build.VERSION.SDK_INT < Build.VERSION_CODES.M || Settings.canDrawOverlays(this))
+            if(U.canDrawOverlays(this))
                 drawDashboard();
             else {
                 pref.edit().putBoolean("taskbar_active", false).apply();
index 8027085..98781cf 100644 (file)
@@ -27,7 +27,6 @@ import android.content.IntentFilter;
 import android.content.SharedPreferences;
 import android.os.Build;
 import android.os.IBinder;
-import android.provider.Settings;
 import android.service.quicksettings.TileService;
 import android.support.v4.app.NotificationCompat;
 import android.support.v4.content.ContextCompat;
@@ -87,7 +86,7 @@ public class NotificationService extends Service {
 
         SharedPreferences pref = U.getSharedPreferences(this);
         if(pref.getBoolean("taskbar_active", false)) {
-            if(Build.VERSION.SDK_INT < Build.VERSION_CODES.M || Settings.canDrawOverlays(this)) {
+            if(U.canDrawOverlays(this)) {
                 isHidden = U.getSharedPreferences(this).getBoolean("is_hidden", false);
 
                 Intent intent = new Intent(this, MainActivity.class);
index a22d1e7..824265a 100644 (file)
@@ -44,7 +44,6 @@ import android.support.v4.content.LocalBroadcastManager;
 import android.support.v7.widget.SearchView;
 import android.util.DisplayMetrics;
 import android.util.Patterns;
-import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -182,7 +181,7 @@ public class StartMenuService extends Service {
 
         SharedPreferences pref = U.getSharedPreferences(this);
         if(pref.getBoolean("taskbar_active", false) || LauncherHelper.getInstance().isOnHomeScreen()) {
-            if(Build.VERSION.SDK_INT < Build.VERSION_CODES.M || Settings.canDrawOverlays(this))
+            if(U.canDrawOverlays(this))
                 drawStartMenu();
             else {
                 pref.edit().putBoolean("taskbar_active", false).apply();
@@ -259,19 +258,7 @@ public class StartMenuService extends Service {
         }
 
         // Initialize views
-        int theme = 0;
-
-        switch(pref.getString("theme", "light")) {
-            case "light":
-                theme = R.style.AppTheme;
-                break;
-            case "dark":
-                theme = R.style.AppTheme_Dark;
-                break;
-        }
-
-        ContextThemeWrapper wrapper = new ContextThemeWrapper(this, theme);
-        layout = (StartMenuLayout) LayoutInflater.from(wrapper).inflate(layoutId, null);
+        layout = (StartMenuLayout) LayoutInflater.from(U.wrapContext(this)).inflate(layoutId, null);
         startMenu = U.findViewById(layout, R.id.start_menu);
 
         if((shouldShowSearchBox && !hasHardwareKeyboard) || Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1)
@@ -285,6 +272,9 @@ public class StartMenuService extends Service {
         if(pref.getBoolean("transparent_start_menu", false))
             startMenu.setBackgroundColor(0);
 
+        if(U.visualFeedbackEnabled(this))
+            startMenu.setRecyclerListener(view -> view.setBackgroundColor(0));
+
         searchView = U.findViewById(layout, R.id.search);
 
         int backgroundTint = U.getBackgroundTint(this);
@@ -624,7 +614,7 @@ public class StartMenuService extends Service {
             boolean inFreeformMode = FreeformHackHelper.getInstance().isInFreeformWorkspace();
 
             if(!U.isChromeOs(this) && (!onHomeScreen || inFreeformMode)) {
-                Class clazz = inFreeformMode && Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1
+                Class clazz = inFreeformMode && !U.hasBrokenSetLaunchBoundsApi()
                         ? InvisibleActivityAlt.class
                         : InvisibleActivity.class;
 
@@ -711,7 +701,7 @@ public class StartMenuService extends Service {
                 windowManager.removeView(layout);
             } catch (IllegalArgumentException e) { /* Gracefully fail */ }
 
-            if(Build.VERSION.SDK_INT < Build.VERSION_CODES.M || Settings.canDrawOverlays(this))
+            if(U.canDrawOverlays(this))
                 drawStartMenu();
             else {
                 SharedPreferences pref = U.getSharedPreferences(this);
@@ -750,7 +740,7 @@ public class StartMenuService extends Service {
             if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && FreeformHackHelper.getInstance().isInFreeformWorkspace()) {
                 DisplayMetrics metrics = U.getRealDisplayMetrics(this);
 
-                if(intent != null && Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1)
+                if(intent != null && U.hasBrokenSetLaunchBoundsApi())
                     intent.putExtra("context_menu_fix", true);
 
                 startActivity(intent, U.getActivityOptions(ApplicationType.CONTEXT_MENU).setLaunchBounds(new Rect(0, 0, metrics.widthPixels, metrics.heightPixels)).toBundle());
index d69898d..2a26b63 100644 (file)
@@ -47,12 +47,10 @@ import android.os.PowerManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.provider.Settings;
 import android.speech.RecognizerIntent;
 import android.support.v4.content.ContextCompat;
 import android.support.v4.graphics.ColorUtils;
 import android.util.DisplayMetrics;
-import android.view.ContextThemeWrapper;
 import android.view.Display;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -201,7 +199,7 @@ public class TaskbarService extends Service {
 
         SharedPreferences pref = U.getSharedPreferences(this);
         if(pref.getBoolean("taskbar_active", false) || LauncherHelper.getInstance().isOnHomeScreen()) {
-            if(Build.VERSION.SDK_INT < Build.VERSION_CODES.M || Settings.canDrawOverlays(this))
+            if(U.canDrawOverlays(this))
                 drawTaskbar();
             else {
                 pref.edit().putBoolean("taskbar_active", false).apply();
@@ -271,22 +269,10 @@ public class TaskbarService extends Service {
         }
 
         // Initialize views
-        int theme = 0;
-
         SharedPreferences pref = U.getSharedPreferences(this);
-        switch(pref.getString("theme", "light")) {
-            case "light":
-                theme = R.style.AppTheme;
-                break;
-            case "dark":
-                theme = R.style.AppTheme_Dark;
-                break;
-        }
-
         boolean altButtonConfig = pref.getBoolean("alt_button_config", false);
 
-        ContextThemeWrapper wrapper = new ContextThemeWrapper(this, theme);
-        layout = (LinearLayout) LayoutInflater.from(wrapper).inflate(layoutId, null);
+        layout = (LinearLayout) LayoutInflater.from(U.wrapContext(this)).inflate(layoutId, null);
         taskbar = U.findViewById(layout, R.id.taskbar);
         scrollView = U.findViewById(layout, R.id.taskbar_scrollview);
 
@@ -305,9 +291,7 @@ public class TaskbarService extends Service {
 
         if(pref.getBoolean("app_drawer_icon", false)) {
             startButton.setImageDrawable(ContextCompat.getDrawable(this,
-                    U.hasSupportLibrary(this, 5)
-                            ? R.drawable.bliss
-                            : R.mipmap.ic_launcher));
+                    U.isBlissOs(this) ? R.drawable.bliss : R.mipmap.ic_launcher));
 
             padding = getResources().getDimensionPixelSize(R.dimen.app_drawer_icon_padding_alt);
         } else {
@@ -1147,7 +1131,7 @@ public class TaskbarService extends Service {
         if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && FreeformHackHelper.getInstance().isInFreeformWorkspace()) {
             DisplayMetrics metrics = U.getRealDisplayMetrics(this);
 
-            if(intent != null && Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1)
+            if(intent != null && U.hasBrokenSetLaunchBoundsApi())
                 intent.putExtra("context_menu_fix", true);
 
             startActivity(intent, U.getActivityOptions(ApplicationType.CONTEXT_MENU).setLaunchBounds(new Rect(0, 0, metrics.widthPixels, metrics.heightPixels)).toBundle());
@@ -1175,7 +1159,7 @@ public class TaskbarService extends Service {
 
             currentTaskbarPosition = 0;
 
-            if(Build.VERSION.SDK_INT < Build.VERSION_CODES.M || Settings.canDrawOverlays(this))
+            if(U.canDrawOverlays(this))
                 drawTaskbar();
             else {
                 SharedPreferences pref = U.getSharedPreferences(this);
@@ -1293,7 +1277,7 @@ public class TaskbarService extends Service {
         if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && FreeformHackHelper.getInstance().isInFreeformWorkspace()) {
             DisplayMetrics metrics = U.getRealDisplayMetrics(this);
 
-            if(intent != null && Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1)
+            if(intent != null && U.hasBrokenSetLaunchBoundsApi())
                 intent.putExtra("context_menu_fix", true);
 
             startActivity(intent, U.getActivityOptions(ApplicationType.CONTEXT_MENU).setLaunchBounds(new Rect(0, 0, metrics.widthPixels, metrics.heightPixels)).toBundle());
index 513ffc6..b3d5f9d 100644 (file)
@@ -20,6 +20,7 @@ import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.AlertDialog;
+import android.app.AppOpsManager;
 import android.app.Service;
 import android.app.admin.DevicePolicyManager;
 import android.content.ActivityNotFoundException;
@@ -31,7 +32,6 @@ import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.LauncherActivityInfo;
 import android.content.pm.LauncherApps;
-import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ShortcutInfo;
@@ -47,6 +47,7 @@ import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
 import android.support.v4.content.LocalBroadcastManager;
+import android.support.v7.view.ContextThemeWrapper;
 import android.util.DisplayMetrics;
 import android.view.Display;
 import android.view.Surface;
@@ -66,9 +67,11 @@ import com.farmerbb.taskbar.service.NotificationService;
 import com.farmerbb.taskbar.service.PowerMenuService;
 import com.farmerbb.taskbar.service.StartMenuService;
 import com.farmerbb.taskbar.service.TaskbarService;
+import com.jrummyapps.android.os.SystemProperties;
 
 import java.lang.reflect.Method;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 public class U {
@@ -94,8 +97,20 @@ public class U {
         return pref;
     }
 
+    public static void showPermissionDialog(Context context) {
+        showPermissionDialog(context, null, null);
+    }
+    
     @TargetApi(Build.VERSION_CODES.M)
-    public static AlertDialog showPermissionDialog(final Context context) {
+    public static AlertDialog showPermissionDialog(Context context, Runnable onError, Runnable onFinish) {
+        Runnable finalOnFinish = onFinish == null
+                ? () -> {}
+                : onFinish;
+
+        Runnable finalOnError = onError == null
+                ? () -> showErrorDialog(context, "SYSTEM_ALERT_WINDOW", finalOnFinish)
+                : onError;
+
         AlertDialog.Builder builder = new AlertDialog.Builder(context);
         builder.setTitle(R.string.permission_dialog_title)
                 .setMessage(R.string.permission_dialog_message)
@@ -103,8 +118,10 @@ public class U {
                     try {
                         context.startActivity(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                                 Uri.parse("package:" + BuildConfig.APPLICATION_ID)));
+
+                        finalOnFinish.run();
                     } catch (ActivityNotFoundException e) {
-                        showErrorDialog(context, "SYSTEM_ALERT_WINDOW");
+                        finalOnError.run();
                     }
                 });
 
@@ -115,14 +132,25 @@ public class U {
         return dialog;
     }
 
-    public static void showErrorDialog(final Context context, String appopCmd) {
+    public static AlertDialog showErrorDialog(Context context, String appopCmd) {
+        return showErrorDialog(context, appopCmd, null);
+    }
+
+    private static AlertDialog showErrorDialog(Context context, String appopCmd, Runnable onFinish) {
+        Runnable finalOnFinish = onFinish == null
+                ? () -> {}
+                : onFinish;
+
         AlertDialog.Builder builder = new AlertDialog.Builder(context);
         builder.setTitle(R.string.error_dialog_title)
                 .setMessage(context.getString(R.string.error_dialog_message, BuildConfig.APPLICATION_ID, appopCmd))
-                .setPositiveButton(R.string.action_ok, null);
+                .setPositiveButton(R.string.action_ok, (dialog, which) -> finalOnFinish.run());
 
         AlertDialog dialog = builder.create();
         dialog.show();
+        dialog.setCancelable(false);
+        
+        return dialog;
     }
 
     public static void lockDevice(Context context) {
@@ -245,7 +273,7 @@ public class U {
         SharedPreferences pref = getSharedPreferences(context);
         FreeformHackHelper helper = FreeformHackHelper.getInstance();
 
-        boolean specialLaunch = Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1
+        boolean specialLaunch = hasBrokenSetLaunchBoundsApi()
                 && FreeformHackHelper.getInstance().isInFreeformWorkspace()
                 && MenuHelper.getInstance().isContextMenuOpen();
 
@@ -803,9 +831,9 @@ public class U {
     public static boolean hasFreeformSupport(Context context) {
         return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
                 && (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT)
-                || Settings.Global.getInt(context.getContentResolver(), "enable_freeform_support", -1) == 1
+                || Settings.Global.getInt(context.getContentResolver(), "enable_freeform_support", 0) != 0
                 || (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1
-                && Settings.Global.getInt(context.getContentResolver(), "force_resizable_activities", -1) == 1));
+                && Settings.Global.getInt(context.getContentResolver(), "force_resizable_activities", 0) != 0));
     }
 
     public static boolean hasPartialFreeformSupport() {
@@ -887,7 +915,7 @@ public class U {
                 stackId = FREEFORM_WORKSPACE_STACK_ID;
                 break;
             case CONTEXT_MENU:
-                if(Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1)
+                if(hasBrokenSetLaunchBoundsApi())
                     stackId = FULLSCREEN_WORKSPACE_STACK_ID;
                 break;
         }
@@ -925,16 +953,21 @@ public class U {
         return context.getPackageManager().hasSystemFeature("org.chromium.arc");
     }
 
-    public static boolean hasSupportLibrary(Context context) {
-        return hasSupportLibrary(context, 0);
+    public static boolean isBlissOs(Context context) {
+        String blissVersion = SystemProperties.get("ro.bliss.version");
+        return blissVersion != null && !blissVersion.isEmpty()
+                && BuildConfig.APPLICATION_ID.equals(BuildConfig.BASE_APPLICATION_ID)
+                && isSystemApp(context);
     }
 
-    public static boolean hasSupportLibrary(Context context, int minVersion) {
+    public static boolean isLauncherPermanentlyEnabled(Context context) {
+        if(BuildConfig.APPLICATION_ID.equals(BuildConfig.ANDROIDX86_APPLICATION_ID))
+            return true;
+
         PackageManager pm = context.getPackageManager();
         try {
-            PackageInfo pInfo = pm.getPackageInfo(BuildConfig.SUPPORT_APPLICATION_ID, 0);
-            return pInfo.versionCode >= minVersion
-                    && pm.checkSignatures(BuildConfig.SUPPORT_APPLICATION_ID, BuildConfig.APPLICATION_ID) == PackageManager.SIGNATURE_MATCH
+            pm.getPackageInfo(BuildConfig.SUPPORT_APPLICATION_ID, 0);
+            return pm.checkSignatures(BuildConfig.SUPPORT_APPLICATION_ID, BuildConfig.APPLICATION_ID) == PackageManager.SIGNATURE_MATCH
                     && BuildConfig.APPLICATION_ID.equals(BuildConfig.BASE_APPLICATION_ID)
                     && isSystemApp(context);
         } catch (PackageManager.NameNotFoundException e) {
@@ -1048,12 +1081,12 @@ public class U {
             }
         }
 
-        // Customizations for Bliss-x86
-        if(hasSupportLibrary(context, 5)
-                && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+        // Customizations for BlissOS
+        if(isBlissOs(context) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
+                && !pref.getBoolean("bliss_os_prefs", false)) {
             SharedPreferences.Editor editor = pref.edit();
 
-            if(U.hasFreeformSupport(context)) {
+            if(hasFreeformSupport(context)) {
                 editor.putBoolean("freeform_hack", true);
             }
 
@@ -1068,6 +1101,7 @@ public class U {
             editor.putBoolean("button_home", true);
             editor.putBoolean("button_recents", true);
             editor.putBoolean("auto_hide_navbar", true);
+            editor.putBoolean("bliss_os_prefs", true);
 
             try {
                 Settings.Secure.putString(context.getContentResolver(),
@@ -1140,7 +1174,7 @@ public class U {
     }
 
     public static boolean isOverridingFreeformHack(Context context) {
-        SharedPreferences pref = U.getSharedPreferences(context);
+        SharedPreferences pref = getSharedPreferences(context);
         return isChromeOs(context) && pref.getBoolean("chrome_os_context_menu_fix", true);
     }
 
@@ -1164,18 +1198,116 @@ public class U {
     }
 
     public static boolean isUntestedAndroidVersion(Context context) {
-        int androidSdkInt = Build.VERSION.SDK_INT;
-        int targetSdkInt = context.getApplicationInfo().targetSdkVersion;
+        SharedPreferences pref = getSharedPreferences(context);
+        float testedApiVersion = 27.0f;
 
-        if(androidSdkInt > targetSdkInt)
-            return true;
+        return getCurrentApiVersion() > Math.max(testedApiVersion, pref.getFloat("current_api_version_new", testedApiVersion));
+    }
+
+    public static float getCurrentApiVersion() {
+        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
+            return Float.valueOf(Build.VERSION.SDK_INT + "." + Build.VERSION.PREVIEW_SDK_INT);
+        else
+            return (float) Build.VERSION.SDK_INT;
+    }
+
+    public static boolean hasBrokenSetLaunchBoundsApi() {
+        return Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1;
+    }
+
+    public static String getSecondScreenPackageName(Context context) {
+        return getInstalledPackage(context, Arrays.asList(
+                "com.farmerbb.secondscreen.free",
+                "com.farmerbb.secondscreen"));
+    }
+
+    // Returns the name of an installed package from a list of package names, in order of preference
+    private static String getInstalledPackage(Context context, List<String> packageNames) {
+        if(packageNames == null || packageNames.isEmpty())
+            return null;
 
-        if(androidSdkInt >= Build.VERSION_CODES.M) {
-            int previewSdkInt = Build.VERSION.PREVIEW_SDK_INT;
+        List<String> packages = packageNames instanceof ArrayList ? packageNames : new ArrayList<>(packageNames);
+        String packageName = packages.get(0);
 
-            return androidSdkInt == targetSdkInt && previewSdkInt > 0;
+        try {
+            context.getPackageManager().getPackageInfo(packageName, 0);
+            return packageName;
+        } catch (PackageManager.NameNotFoundException e) {
+            packages.remove(0);
+            return getInstalledPackage(context, packages);
         }
+    }
 
-        return false;
+    public static boolean visualFeedbackEnabled(Context context) {
+        SharedPreferences pref = getSharedPreferences(context);
+        return Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1 && pref.getBoolean("visual_feedback", true);
+    }
+
+    public static void showRecentAppsDialog(Context context) {
+        showRecentAppsDialog(context, null, null);
+    }
+
+    public static AlertDialog showRecentAppsDialog(Context context, Runnable onError, Runnable onFinish) {
+        Runnable finalOnFinish = onFinish == null
+                ? () -> {}
+                : onFinish;
+
+        Runnable finalOnError = onError == null
+                ? () -> showErrorDialog(context, "GET_USAGE_STATS", finalOnFinish)
+                : onError;
+
+        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !isSystemApp(context)) {
+            ApplicationInfo applicationInfo = null;
+            try {
+                applicationInfo = context.getPackageManager().getApplicationInfo(BuildConfig.APPLICATION_ID, 0);
+            } catch (PackageManager.NameNotFoundException e) { /* Gracefully fail */ }
+
+            if(applicationInfo != null) {
+                AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+                int mode = appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, applicationInfo.uid, applicationInfo.packageName);
+
+                if(mode != AppOpsManager.MODE_ALLOWED) {
+                    AlertDialog.Builder builder = new AlertDialog.Builder(context);
+                    builder.setTitle(R.string.pref_header_recent_apps)
+                            .setMessage(R.string.enable_recent_apps)
+                            .setPositiveButton(R.string.action_ok, (dialog, which) -> {
+                                try {
+                                    context.startActivity(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS));
+                                    showToastLong(context, R.string.usage_stats_message);
+
+                                    finalOnFinish.run();
+                                } catch (ActivityNotFoundException e) {
+                                    finalOnError.run();
+                                }
+                            })
+                            .setNegativeButton(R.string.action_cancel, (dialog, which) -> finalOnFinish.run());
+
+                    AlertDialog dialog = builder.create();
+                    dialog.show();
+                    dialog.setCancelable(false);
+                    
+                    return dialog;
+                }
+            }
+        }
+
+        finalOnFinish.run();
+        return null;
+    }
+
+    public static Context wrapContext(Context context) {
+        SharedPreferences pref = getSharedPreferences(context);
+
+        int theme = -1;
+        switch(pref.getString("theme", "light")) {
+            case "light":
+                theme = R.style.AppTheme;
+                break;
+            case "dark":
+                theme = R.style.AppTheme_Dark;
+                break;
+        }
+
+        return theme > -1 ? new ContextThemeWrapper(context, theme) : context;
     }
 }
diff --git a/app/src/main/java/com/jrummyapps/android/os/SystemProperties.java b/app/src/main/java/com/jrummyapps/android/os/SystemProperties.java
new file mode 100644 (file)
index 0000000..77f67aa
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2015 Jared Rummler <jared.rummler@gmail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jrummyapps.android.os;
+
+/**
+ * Gives access to the system properties store. The system properties tore contains a list of string
+ * key-value pairs.
+ *
+ * @author Jared Rummler <jared.rummler@gmail.com>
+ * @since Feb 8, 2015
+ */
+public class SystemProperties {
+
+    // ===========================================================
+    // STATIC FIELDS
+    // ===========================================================
+
+    private static Class<?> CLASS;
+
+    // ===========================================================
+    // STATIC INITIALIZERS
+    // ===========================================================
+
+    static {
+        try {
+            CLASS = Class.forName("android.os.SystemProperties");
+        } catch (ClassNotFoundException e) {
+        }
+    }
+
+    // ===========================================================
+    // STATIC METHODS
+    // ===========================================================
+
+    /** Get the value for the given key. */
+    public static String get(String key) {
+        try {
+            return (String) CLASS.getMethod("get", String.class).invoke(null, key);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    /**
+     * Get the value for the given key.
+     * 
+     * @return if the key isn't found, return def if it isn't null, or an empty string otherwise
+     */
+    public static String get(String key, String def) {
+        try {
+            return (String) CLASS.getMethod("get", String.class, String.class).invoke(null, key,
+                def);
+        } catch (Exception e) {
+            return def;
+        }
+    }
+
+    /**
+     * Get the value for the given key, and return as an integer.
+     * 
+     * @param key
+     *            the key to lookup
+     * @param def
+     *            a default value to return
+     * @return the key parsed as an integer, or def if the key isn't found or cannot be parsed
+     */
+    public static int getInt(String key, int def) {
+        try {
+            return (Integer) CLASS.getMethod("getInt", String.class, int.class).invoke(null, key,
+                def);
+        } catch (Exception e) {
+            return def;
+        }
+    }
+
+    /**
+     * Get the value for the given key, and return as a long.
+     * 
+     * @param key
+     *            the key to lookup
+     * @param def
+     *            a default value to return
+     * @return the key parsed as a long, or def if the key isn't found or cannot be parsed
+     */
+    public static long getLong(String key, long def) {
+        try {
+            return (Long) CLASS.getMethod("getLong", String.class, long.class).invoke(null, key,
+                def);
+        } catch (Exception e) {
+            return def;
+        }
+    }
+
+    /**
+     * Get the value for the given key, returned as a boolean. Values 'n', 'no', '0', 'false' or
+     * 'off' are considered false. Values 'y', 'yes', '1', 'true' or 'on' are considered true. (case
+     * sensitive). If the key does not exist, or has any other value, then the default result is
+     * returned.
+     * 
+     * @param key
+     *            the key to lookup
+     * @param def
+     *            a default value to return
+     * @return the key parsed as a boolean, or def if the key isn't found or is not able to be
+     *         parsed as a boolean.
+     */
+    public static boolean getBoolean(String key, boolean def) {
+        try {
+            return (Boolean) CLASS.getMethod("getBoolean", String.class, boolean.class).invoke(
+                null, key, def);
+        } catch (Exception e) {
+            return def;
+        }
+    }
+
+    /** Set the value for the given key. */
+    public static void set(String key, String val) {
+        try {
+            CLASS.getMethod("set", String.class, String.class).invoke(null, key, val);
+        } catch (Exception ignored) {
+        }
+    }
+
+    public static void addChangeCallback(Runnable callback) {
+        try {
+            CLASS.getMethod("addChangeCallback", Runnable.class).invoke(null, callback);
+        } catch (Exception ignored) {
+        }
+    }
+
+    public static void callChangeCallbacks() {
+        try {
+            CLASS.getMethod("callChangeCallbacks").invoke(null, (Object[]) null);
+        } catch (Exception ignored) {
+        }
+    }
+
+    private SystemProperties() {
+
+    }
+}
\ No newline at end of file
index 0c534c9..22ef705 100644 (file)
 
     <string name="press_enter_alt">@string/press_enter</string>
 
-    <string name="freeform_dialog_message_alt">In order for Taskbar to launch apps in freeform window mode, please follow these steps:\n\n&#8226; Go to Developer Options and enable USB debugging\n\n&#8226; Connect your device to a computer with the Android SDK installed, and run the following adb shell command:\n\nsettings put global enable_freeform_support 1\n\n&#8226; Reboot your device</string>
+    <string name="freeform_dialog_message_alt">In order for Taskbar to launch apps in freeform window mode, please follow these steps:\n\n&#8226; Go to Developer Options and enable USB debugging\n\n&#8226; Connect your device to a computer with the Android SDK installed, and run the following command (one-line):\n\nadb shell settings put global enable_freeform_support 1\n\n&#8226; Reboot your device</string>
 
     <string name="color_picker_alpha">Alpha</string>
     <string name="color_picker_red">Red</string>
     <string name="pref_secondscreen_title_install">Install SecondScreen</string>
     <string name="pref_secondscreen_description">Change your device\'s resolution and density when connected to an external display, for a Continuum or DeX-like experience</string>
 
-    <string name="dialog_upgrade_message">Taskbar\'s freeform mode support has not been tested on this version of Android. It may behave in unexpected ways - check for updates if there are any issues.</string>
+    <string name="dialog_upgrade_message">Taskbar\'s freeform mode support has not been tested on this version of Android. It may stop working completely or behave in other unexpected ways.\n\nCheck for app updates if you see any issues.</string>
 
     <string name="use_default">Use default</string>
 
+    <string name="action_continue">Continue</string>
+
 </resources>
index 050cd6f..1a00ddf 100644 (file)
@@ -23,4 +23,6 @@
     <dimen name="start_menu_grid_padding">4dp</dimen>
     <dimen name="start_menu_icon_padding">6dp</dimen>
     <dimen name="start_menu_no_apps_found_text">16sp</dimen>
+    <dimen name="phone_size_width">360dp</dimen>
+    <dimen name="phone_size_height">640dp</dimen>
 </resources>
diff --git a/app/src/main/res/values-h900dp/dimens.xml b/app/src/main/res/values-h900dp/dimens.xml
new file mode 100644 (file)
index 0000000..2dd0d59
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2018 Braden Farmer
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <dimen name="phone_size_width">411dp</dimen>
+    <dimen name="phone_size_height">731dp</dimen>
+</resources>
index 71f0a38..bdd4b2c 100644 (file)
 
     <string name="press_enter_alt">@string/press_enter</string>
 
-    <string name="freeform_dialog_message_alt">In order for Taskbar to launch apps in freeform window mode, please follow these steps:\n\n&#8226; Go to Developer Options and enable USB debugging\n\n&#8226; Connect your device to a computer with the Android SDK installed, and run the following adb shell command:\n\nsettings put global enable_freeform_support 1\n\n&#8226; Reboot your device</string>
+    <string name="freeform_dialog_message_alt">In order for Taskbar to launch apps in freeform window mode, please follow these steps:\n\n&#8226; Go to Developer Options and enable USB debugging\n\n&#8226; Connect your device to a computer with the Android SDK installed, and run the following command (one-line):\n\nadb shell settings put global enable_freeform_support 1\n\n&#8226; Reboot your device</string>
 
     <string name="color_picker_alpha">Alpha</string>
     <string name="color_picker_red">Red</string>
     <string name="pref_secondscreen_title_install">Install SecondScreen</string>
     <string name="pref_secondscreen_description">Change your device\'s resolution and density when connected to an external display, for a Continuum or DeX-like experience</string>
 
-    <string name="dialog_upgrade_message">Taskbar\'s freeform mode support has not been tested on this version of Android. It may behave in unexpected ways - check for updates if there are any issues.</string>
+    <string name="dialog_upgrade_message">Taskbar\'s freeform mode support has not been tested on this version of Android. It may stop working completely or behave in other unexpected ways.\n\nCheck for app updates if you see any issues.</string>
 
     <string name="use_default">Use default</string>
 
+    <string name="action_continue">Continue</string>
+
 </resources>
index 606f2cf..0f52643 100644 (file)
     <string name="pref_secondscreen_title_install">Install SecondScreen</string>
     <string name="pref_secondscreen_description">Change your device\'s resolution and density when connected to an external display, for a Continuum or DeX-like experience</string>
 
-    <string name="dialog_upgrade_message">Taskbar\'s freeform mode support has not been tested on this version of Android. It may behave in unexpected ways - check for updates if there are any issues.</string>
+    <string name="dialog_upgrade_message">Taskbar\'s freeform mode support has not been tested on this version of Android. It may stop working completely or behave in other unexpected ways.\n\nCheck for app updates if you see any issues.</string>
 
     <string name="use_default">Use default</string>
 
+    <string name="action_continue">Continue</string>
+
 </resources>
index 8400c09..1ec8858 100644 (file)
@@ -1,9 +1,12 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- Copyright 2016 Braden Farmer
+
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
      You may obtain a copy of the License at
+
           http://www.apache.org/licenses/LICENSE-2.0
+
      Unless required by applicable law or agreed to in writing, software
      distributed under the License is distributed on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
index 239c161..6782fbf 100644 (file)
@@ -1,9 +1,12 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- Copyright 2016 Braden Farmer
+
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
      You may obtain a copy of the License at
+
           http://www.apache.org/licenses/LICENSE-2.0
+
      Unless required by applicable law or agreed to in writing, software
      distributed under the License is distributed on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -13,6 +16,4 @@
 
 <resources>
     <dimen name="context_menu_width">320dp</dimen>
-    <dimen name="phone_size_width">360dp</dimen>
-    <dimen name="phone_size_height">640dp</dimen>
 </resources>
\ No newline at end of file
index 6044c93..3ebebf3 100644 (file)
@@ -16,6 +16,4 @@
 
 <resources>
     <dimen name="max_width">720dp</dimen>
-    <dimen name="phone_size_width">411dp</dimen>
-    <dimen name="phone_size_height">731dp</dimen>
 </resources>
index 0de75b2..dba3f9f 100644 (file)
     <string name="pref_secondscreen_title_install">Install SecondScreen</string>
     <string name="pref_secondscreen_description">Change your device\'s resolution and density when connected to an external display, for a Continuum or DeX-like experience</string>
 
-    <string name="dialog_upgrade_message">Taskbar\'s freeform mode support has not been tested on this version of Android. It may behave in unexpected ways - check for updates if there are any issues.</string>
+    <string name="dialog_upgrade_message">Taskbar\'s freeform mode support has not been tested on this version of Android. It may stop working completely or behave in other unexpected ways.\n\nCheck for app updates if you see any issues.</string>
 
     <string name="use_default">Use default</string>
 
+    <string name="action_continue">Continue</string>
+
 </resources>
\ No newline at end of file
index b9e4bf7..ad14e95 100644 (file)
@@ -35,4 +35,6 @@
 
     <color name="ic_launcher_adaptive_bg">#4557A6</color>
     <color name="ic_freeform_mode_adaptive_bg">#4790CD</color>
+
+    <color name="app_shortcut_bg">#F5F5F5</color>
 </resources>
index 2cfe710..c45fddb 100644 (file)
     <string name="pref_title_invisible_button">Hide button while Taskbar is collapsed</string>
     <string name="pref_title_freeform_mode_help">Help &amp; instructions for freeform mode</string>
     <string name="freeform_help_dialog_title">Help &amp; instructions</string>
-    <string name="freeform_help_dialog_message"><b>About freeform mode</b>\n\nTaskbar lets you launch apps in freeform floating windows on Android 7.0+ (Nougat).  No root access is required.  Android 8.0+ (Oreo) is also supported via an adb shell command.\n\nSimply follow these steps to configure your device for launching apps in freeform mode:\n\n<b>1.</b> Check the box for \"Freeform window support\" inside the Taskbar app\n\n<b>2.</b> Follow the directions that appear in the pop-up to enable the proper settings on your device (one-time setup)\n\n<b>3.</b> Go to your device\'s recent apps page and clear all recent apps*\n\n<b>4.</b> Select an app using Taskbar to launch it in a freeform window\n\n* For best results, especially on Android 8.0+, restart your device before using freeform mode\n\n<b>Window size presets</b>\n\nTaskbar can launch app windows in various preset sizes.  You can choose a window size by long-pressing or right-clicking an app icon and selecting \"New window.\"\n\nTo save a window size preset for a specific app, simply long-press the preset, and a checkmark will appear indicating that it is set as default.  Taskbar will launch the app using this selected size on subsequent launches.\n\nNote that window sizes don\'t work correctly on Android 8.0+.  However, you can work around this by launching the app, immediately closing it, then launching it again from Android\'s overview menu.\n\n<b>Troubleshooting</b>\n\n<i>&#8226; Apps still launch fullscreen</i>\n\nIf an app is launched that is already loaded into memory, Taskbar will bring it into the foreground. In order to launch the app into freeform mode, it has to be launched from a fresh state.\n\nSwipe the app away from recents, and then re-launch it from the recent apps page using Taskbar. If this doesn\'t work, then long-press the app icon, select \"App info,\" and then force stop the app.  Alternatively, you can restart your device.\n\n<i>&#8226; Apps that are maximized cannot be restored into a window</i>\n\nIf you press the Maximize button on an app\'s title bar, Android will bring the app out of freeform mode and into fullscreen mode. As mentioned above, Taskbar can only launch apps into freeform windows if they are launched from a fresh state.\n\nTo fix this, you can maximize windows by tapping or clicking just outside the app\'s window frame.  This will expand the window to fill all the available space while keeping it in the freeform window workspace.\n\n<b>Enabling full system-level freeform window support</b>\n\nIf you have access to a computer with the Android SDK installed, you can enable support for freeform mode at the system level by running the following adb shell command:\n\nsettings put global enable_freeform_support 1\n\nReboot your device after running the above command, and a new button will appear for app entries in your device\'s recent apps page to enter/exit freeform mode for a given app. (Note that the button does not work on Android 7.1.2)</string>
+    <string name="freeform_help_dialog_message"><b>About freeform mode</b>\n\nTaskbar lets you launch apps in freeform floating windows on Android 7.0+ (Nougat).  No root access is required.  Android 8.0+ (Oreo) is also supported via an adb shell command.\n\nSimply follow these steps to configure your device for launching apps in freeform mode:\n\n<b>1.</b> Check the box for \"Freeform window support\" inside the Taskbar app\n\n<b>2.</b> Follow the directions that appear in the pop-up to enable the proper settings on your device (one-time setup)\n\n<b>3.</b> Go to your device\'s recent apps page and clear all recent apps*\n\n<b>4.</b> Select an app using Taskbar to launch it in a freeform window\n\n* For best results, especially on Android 8.0+, restart your device before using freeform mode\n\n<b>Window size presets</b>\n\nTaskbar can launch app windows in various preset sizes.  You can choose a window size by long-pressing or right-clicking an app icon and selecting \"New window.\"\n\nTo save a window size preset for a specific app, simply long-press the preset, and a checkmark will appear indicating that it is set as default.  Taskbar will launch the app using this selected size on subsequent launches.\n\nNote that window sizes don\'t work correctly on Android 8.0+.  However, you can work around this by launching the app, immediately closing it, then launching it again from Android\'s overview menu.\n\n<b>Troubleshooting</b>\n\n<i>&#8226; Apps still launch fullscreen</i>\n\nIf an app is launched that is already loaded into memory, Taskbar will bring it into the foreground. In order to launch the app into freeform mode, it has to be launched from a fresh state.\n\nSwipe the app away from recents, and then re-launch it from the recent apps page using Taskbar. If this doesn\'t work, then long-press the app icon, select \"App info,\" and then force stop the app.  Alternatively, you can restart your device.\n\n<i>&#8226; Apps that are maximized cannot be restored into a window</i>\n\nIf you press the Maximize button on an app\'s title bar, Android will bring the app out of freeform mode and into fullscreen mode. As mentioned above, Taskbar can only launch apps into freeform windows if they are launched from a fresh state.\n\nTo fix this, you can maximize windows by tapping or clicking just outside the app\'s window frame.  This will expand the window to fill all the available space while keeping it in the freeform window workspace.\n\n<b>Enabling full system-level freeform window support</b>\n\nIf you have access to a computer with the Android SDK installed, you can enable support for freeform mode at the system level by running the following command (one-line):\n\nadb shell settings put global enable_freeform_support 1\n\nReboot your device after running the above command, and a new button will appear for app entries in your device\'s recent apps page to enter/exit freeform mode for a given app. (Note that the button does not work on Android 7.1.2)</string>
 
     <string name="action_developer_options">Open Developer Options</string>
     <string name="action_close">Close</string>
 
     <string name="press_enter_alt">No apps found\n\nPress Enter to open in browser</string>
 
-    <string name="freeform_dialog_message_alt">In order for Taskbar to launch apps in freeform window mode, please follow these steps:\n\n&#8226; Go to Developer Options and enable USB debugging\n\n&#8226; Connect your device to a computer with the Android SDK installed, and run the following adb shell command:\n\nsettings put global enable_freeform_support 1\n\n&#8226; Reboot your device</string>
+    <string name="freeform_dialog_message_alt">In order for Taskbar to launch apps in freeform window mode, please follow these steps:\n\n&#8226; Go to Developer Options and enable USB debugging\n\n&#8226; Connect your device to a computer with the Android SDK installed, and run the following command (one-line):\n\nadb shell settings put global enable_freeform_support 1\n\n&#8226; Reboot your device</string>
 
     <string name="color_picker_alpha">Alpha</string>
     <string name="color_picker_red">Red</string>
     <string name="pref_secondscreen_title_install">Install SecondScreen</string>
     <string name="pref_secondscreen_description">Change your device\'s resolution and density when connected to an external display, for a Continuum or DeX-like experience</string>
 
-    <string name="dialog_upgrade_message">Taskbar\'s freeform mode support has not been tested on this version of Android. It may behave in unexpected ways - check for updates if there are any issues.</string>
+    <string name="dialog_upgrade_message">Taskbar\'s freeform mode support has not been tested on this version of Android. It may stop working completely or behave in other unexpected ways.\n\nCheck for app updates if you see any issues.</string>
 
     <string name="use_default">Use default</string>
 
+    <string name="action_continue">Continue</string>
+
 </resources>
index 0aad14a..59dd02a 100644 (file)
@@ -27,6 +27,9 @@
     <permission android:name="${applicationId}.ENABLE_DISABLE_HOME"
         android:protectionLevel="signature" />
 
+    <permission android:name="${applicationId}.ENABLE_DISABLE_FREEFORM"
+        android:protectionLevel="signature" />
+
     <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" tools:ignore="ProtectedPermissions" />
     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
                 <action android:name="com.farmerbb.taskbar.TOGGLE_FREEFORM_MODE"/>
             </intent-filter>
         </receiver>
+        <receiver
+            android:name=".receiver.EnableFreeformReceiver"
+            android:enabled="true"
+            android:exported="true"
+            android:permission="${applicationId}.ENABLE_DISABLE_FREEFORM" >
+            <intent-filter>
+                <action android:name="com.farmerbb.taskbar.ENABLE_FREEFORM_MODE"/>
+            </intent-filter>
+        </receiver>
+        <receiver
+            android:name=".receiver.DisableFreeformReceiver"
+            android:enabled="true"
+            android:exported="true"
+            android:permission="${applicationId}.ENABLE_DISABLE_FREEFORM" >
+            <intent-filter>
+                <action android:name="com.farmerbb.taskbar.DISABLE_FREEFORM_MODE"/>
+            </intent-filter>
+        </receiver>
 
     </application>
 
diff --git a/app/src/playstore/java/com/farmerbb/taskbar/receiver/DisableFreeformReceiver.java b/app/src/playstore/java/com/farmerbb/taskbar/receiver/DisableFreeformReceiver.java
new file mode 100644 (file)
index 0000000..386c2f5
--- /dev/null
@@ -0,0 +1,42 @@
+/* Copyright 2018 Braden Farmer
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.farmerbb.taskbar.receiver;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.support.v4.content.LocalBroadcastManager;
+
+import com.farmerbb.taskbar.util.U;
+
+public class DisableFreeformReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        SharedPreferences pref = U.getSharedPreferences(context);
+        boolean freeformEnabled = pref.getBoolean("freeform_hack", false);
+
+        if(pref.getBoolean("skip_disable_freeform_receiver", false))
+            pref.edit().remove("skip_disable_freeform_receiver").apply();
+        else if(!U.isChromeOs(context) && freeformEnabled) {
+            U.restartNotificationService(context);
+
+            pref.edit().putBoolean("freeform_hack", false).apply();
+
+            LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.UPDATE_FREEFORM_CHECKBOX"));
+        }
+    }
+}
\ No newline at end of file
@@ -30,13 +30,19 @@ public class DisableHomeReceiver extends BroadcastReceiver {
     @Override
     public void onReceive(Context context, Intent intent) {
         SharedPreferences pref = U.getSharedPreferences(context);
-        pref.edit().putBoolean("launcher", false).apply();
+        if(pref.getBoolean("skip_disable_home_receiver", false))
+            pref.edit().remove("skip_disable_home_receiver").apply();
+        else if(!U.isLauncherPermanentlyEnabled(context)) {
+            pref.edit().putBoolean("launcher", false).apply();
 
-        ComponentName component = new ComponentName(context, HomeActivity.class);
-        context.getPackageManager().setComponentEnabledSetting(component,
-                PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
-                PackageManager.DONT_KILL_APP);
+            ComponentName component = new ComponentName(context, HomeActivity.class);
+            context.getPackageManager().setComponentEnabledSetting(component,
+                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+                    PackageManager.DONT_KILL_APP);
 
-        LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.KILL_HOME_ACTIVITY"));
+            LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
+            lbm.sendBroadcast(new Intent("com.farmerbb.taskbar.KILL_HOME_ACTIVITY"));
+            lbm.sendBroadcast(new Intent("com.farmerbb.taskbar.LAUNCHER_PREF_CHANGED"));
+        }
     }
 }
diff --git a/app/src/playstore/java/com/farmerbb/taskbar/receiver/EnableFreeformReceiver.java b/app/src/playstore/java/com/farmerbb/taskbar/receiver/EnableFreeformReceiver.java
new file mode 100644 (file)
index 0000000..05a7ef2
--- /dev/null
@@ -0,0 +1,42 @@
+/* Copyright 2018 Braden Farmer
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.farmerbb.taskbar.receiver;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.support.v4.content.LocalBroadcastManager;
+
+import com.farmerbb.taskbar.util.U;
+
+public class EnableFreeformReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        SharedPreferences pref = U.getSharedPreferences(context);
+        boolean freeformEnabled = pref.getBoolean("freeform_hack", false);
+
+        if(intent.hasExtra("secondscreen") && freeformEnabled)
+            pref.edit().putBoolean("skip_disable_freeform_receiver", true).apply();
+        else if(U.hasFreeformSupport(context) && !freeformEnabled) {
+            U.restartNotificationService(context);
+
+            pref.edit().putBoolean("freeform_hack", true).apply();
+
+            LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.UPDATE_FREEFORM_CHECKBOX"));
+        }
+    }
+}
\ No newline at end of file
@@ -21,6 +21,7 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
+import android.support.v4.content.LocalBroadcastManager;
 
 import com.farmerbb.taskbar.activity.HomeActivity;
 import com.farmerbb.taskbar.util.U;
@@ -28,8 +29,10 @@ import com.farmerbb.taskbar.util.U;
 public class EnableHomeReceiver extends BroadcastReceiver {
     @Override
     public void onReceive(Context context, Intent intent) {
-        if(U.canDrawOverlays(context)) {
-            SharedPreferences pref = U.getSharedPreferences(context);
+        SharedPreferences pref = U.getSharedPreferences(context);
+        if(intent.hasExtra("secondscreen") && pref.getBoolean("launcher", false))
+            pref.edit().putBoolean("skip_disable_home_receiver", true).apply();
+        else if(U.canDrawOverlays(context)) {
             SharedPreferences.Editor editor = pref.edit();
             editor.putBoolean("launcher", true);
             editor.apply();
@@ -38,6 +41,9 @@ public class EnableHomeReceiver extends BroadcastReceiver {
             context.getPackageManager().setComponentEnabledSetting(component,
                     PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                     PackageManager.DONT_KILL_APP);
+
+            LocalBroadcastManager.getInstance(context)
+                    .sendBroadcast(new Intent("com.farmerbb.taskbar.LAUNCHER_PREF_CHANGED"));
         }
     }
 }
@@ -28,7 +28,6 @@ import com.farmerbb.taskbar.util.PinnedBlockedApps;
 import com.farmerbb.taskbar.util.SavedWindowSizes;
 import com.farmerbb.taskbar.util.SavedWindowSizesEntry;
 import com.farmerbb.taskbar.util.TopApps;
-import com.farmerbb.taskbar.util.U;
 
 import java.io.BufferedReader;
 import java.io.File;
diff --git a/app/src/playstore/res/drawable-anydpi-v26/ic_play_arrow_black_24dp.xml b/app/src/playstore/res/drawable-anydpi-v26/ic_play_arrow_black_24dp.xml
new file mode 100644 (file)
index 0000000..59d7802
--- /dev/null
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="54.0"
+        android:viewportHeight="54.0">
+    <path
+        android:fillColor="@color/colorPrimary"
+        android:pathData="M23,20.5v14l11,-7z"/>
+</vector>
diff --git a/app/src/playstore/res/drawable-anydpi-v26/ic_web_asset_black_24dp_alt.xml b/app/src/playstore/res/drawable-anydpi-v26/ic_web_asset_black_24dp_alt.xml
new file mode 100644 (file)
index 0000000..1b3aaab
--- /dev/null
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="62.0"
+        android:viewportHeight="62.0">
+    <path
+        android:pathData="M26,24L24,24c-1.11,0 -2,0.9 -2,2v12c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L40,26c0,-1.1 -0.89,-2 -2,-2zM19,38L24,38L24,28h14v10z"
+        android:fillColor="@color/colorPrimary"/>
+</vector>
diff --git a/app/src/playstore/res/drawable-anydpi-v26/shortcut_icon_freeform.xml b/app/src/playstore/res/drawable-anydpi-v26/shortcut_icon_freeform.xml
new file mode 100644 (file)
index 0000000..69b07ba
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@color/app_shortcut_bg"/>
+    <foreground android:drawable="@drawable/ic_web_asset_black_24dp_alt"/>
+</adaptive-icon>
\ No newline at end of file
diff --git a/app/src/playstore/res/drawable-anydpi-v26/shortcut_icon_start.xml b/app/src/playstore/res/drawable-anydpi-v26/shortcut_icon_start.xml
new file mode 100644 (file)
index 0000000..76851a1
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@color/app_shortcut_bg"/>
+    <foreground android:drawable="@drawable/ic_play_arrow_black_24dp"/>
+</adaptive-icon>
\ No newline at end of file
index e9e4d04..c3510d6 100644 (file)
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.5.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip