✨ feat(ui): add AppSettingsPopup for individual app settings
This commit is contained in:
10 files changed
+650
-185
No files matched your search
@@ -79,12 +79,14 @@ import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
|
||||
import io.github.sankalp.lunox.dialogs.AppSettingsPopup;
|
||||
import io.github.sankalp.lunox.dialogs.ColorSizeDialog;
|
||||
import io.github.sankalp.lunox.dialogs.FrozenAppsDialogs;
|
||||
import io.github.sankalp.lunox.dialogs.GlobalColorSizeDialog;
|
||||
import io.github.sankalp.lunox.dialogs.GlobalSettingsDialog;
|
||||
import io.github.sankalp.lunox.dialogs.HiddenAppsDialogs;
|
||||
import io.github.sankalp.lunox.dialogs.PaddingDialog;
|
||||
import io.github.sankalp.lunox.dialogs.PermissionDialog;
|
||||
import io.github.sankalp.lunox.dialogs.RenameInputDialogs;
|
||||
import io.github.sankalp.lunox.model.Apps;
|
||||
import io.github.sankalp.lunox.model.Shortcut;
|
||||
@@ -564,13 +566,13 @@ public class LauncherActivity extends Activity implements View.OnClickListener,
|
||||
// If we have very few apps, try reloading in case permissions were granted
|
||||
loadApps();
|
||||
}
|
||||
|
||||
|
||||
// Check if search box is visible and hide it if needed
|
||||
if (mSearchBox.getVisibility() == View.VISIBLE) {
|
||||
mSearchBox.setVisibility(View.GONE);
|
||||
mHomeLayout.setPadding(DbUtils.getPaddingLeft(), DbUtils.getPaddingTop(), DbUtils.getPaddingRight(), DbUtils.getPaddingBottom());
|
||||
}
|
||||
|
||||
|
||||
// Reset search state
|
||||
searching = false;
|
||||
}
|
||||
@@ -605,88 +607,13 @@ public class LauncherActivity extends Activity implements View.OnClickListener,
|
||||
}
|
||||
|
||||
private void showPopup(String activityName, AppTextView view) {
|
||||
|
||||
Context context;
|
||||
// set theme
|
||||
// if theme wallpaper ie transparent then we have to show other theme
|
||||
if (DbUtils.getTheme() == R.style.Wallpaper)
|
||||
context = new ContextThemeWrapper(this, R.style.AppTheme);
|
||||
else
|
||||
context = new ContextThemeWrapper(this, DbUtils.getTheme());
|
||||
|
||||
PopupMenu popupMenu = new PopupMenu(context, view);
|
||||
popupMenu.getMenuInflater().inflate(R.menu.menu, popupMenu.getMenu());
|
||||
|
||||
|
||||
int color = Color.parseColor("#E53935");
|
||||
|
||||
SpannableString s = new SpannableString(getString(R.string.hide));
|
||||
|
||||
s.setSpan(new ForegroundColorSpan(color), 0, s.length(), 0);
|
||||
popupMenu.getMenu().findItem(R.id.menu_hide).setTitle(s);
|
||||
|
||||
s = new SpannableString(getString(R.string.uninstall));
|
||||
s.setSpan(new ForegroundColorSpan(color), 0, s.length(), 0);
|
||||
popupMenu.getMenu().findItem(R.id.menu_uninstall).setTitle(s);
|
||||
|
||||
s = new SpannableString(getString(R.string.reset_to_default));
|
||||
s.setSpan(new ForegroundColorSpan(color), 0, s.length(), 0);
|
||||
popupMenu.getMenu().findItem(R.id.menu_reset_to_default).setTitle(s);
|
||||
|
||||
|
||||
// set proper item based on Db value
|
||||
if (DbUtils.isAppFrozen(activityName)) {
|
||||
popupMenu.getMenu().findItem(R.id.menu_freeze_size).setTitle(R.string.unfreeze_size);
|
||||
}
|
||||
|
||||
//disable some item for shortcut
|
||||
// and change the uninstall to remove
|
||||
if (view.isShortcut()) {
|
||||
|
||||
SpannableString s1 = new SpannableString(getString(R.string.remove));
|
||||
s1.setSpan(new ForegroundColorSpan(Color.parseColor("#E53935")), 0, s1.length(), 0);
|
||||
popupMenu.getMenu().findItem(R.id.menu_uninstall).setTitle(s1);
|
||||
|
||||
popupMenu.getMenu().findItem(R.id.menu_hide).setVisible(false);
|
||||
//renaming is also disabled;
|
||||
// consider it later
|
||||
popupMenu.getMenu().findItem(R.id.menu_rename).setVisible(false);
|
||||
popupMenu.getMenu().findItem(R.id.menu_app_info).setVisible(false);
|
||||
}
|
||||
|
||||
popupMenu.setOnMenuItemClickListener(menuItem -> {
|
||||
int id = menuItem.getItemId();
|
||||
if (id == R.id.menu_color) {
|
||||
changeColorSize(activityName, view);
|
||||
} else if (id == R.id.menu_rename) {
|
||||
renameApp(activityName, view.getText().toString());
|
||||
} else if (id == R.id.menu_freeze_size) {
|
||||
freezeAppSize(activityName);
|
||||
} else if (id == R.id.menu_hide) {
|
||||
hideApp(activityName);
|
||||
} else if (id == R.id.menu_uninstall) {
|
||||
if (view.isShortcut()) {
|
||||
removeShortcut(view);
|
||||
} else {
|
||||
uninstallApp(activityName);
|
||||
}
|
||||
} else if (id == R.id.menu_app_info) {
|
||||
showAppInfo(activityName);
|
||||
} else if (id == R.id.menu_reset_to_default) {
|
||||
resetApp(activityName);
|
||||
} else if (id == R.id.menu_reset_color) {
|
||||
resetAppColor(activityName);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
// not forget to show popup
|
||||
popupMenu.show();
|
||||
// show app settings popup instead of popup menu
|
||||
AppSettingsPopup popup = new AppSettingsPopup(this, activityName, view, this);
|
||||
popup.showAsDropDown(view);
|
||||
}
|
||||
|
||||
//reset the app color to default color;
|
||||
private void resetAppColor(String activityName) {
|
||||
public void resetAppColor(String activityName) {
|
||||
DbUtils.removeColor(activityName);
|
||||
boolean sortNeeded = (DbUtils.getSortsTypes() == SORT_BY_COLOR);
|
||||
addAppAfterReset(activityName, sortNeeded);
|
||||
@@ -723,7 +650,7 @@ public class LauncherActivity extends Activity implements View.OnClickListener,
|
||||
}
|
||||
|
||||
// as method name suggest
|
||||
private void freezeAppSize(String activityName) {
|
||||
public void freezeAppSize(String activityName) {
|
||||
boolean b = DbUtils.isAppFrozen(activityName);
|
||||
for (Apps apps : mAppsList) {
|
||||
if (activityName.equalsIgnoreCase(apps.getActivityName())) {
|
||||
@@ -734,7 +661,7 @@ public class LauncherActivity extends Activity implements View.OnClickListener,
|
||||
}
|
||||
|
||||
// as method name suggest
|
||||
private void hideApp(String activityName) {
|
||||
public void hideApp(String activityName) {
|
||||
for (Apps apps : mAppsList) {
|
||||
if (activityName.equalsIgnoreCase(apps.getActivityName())) {
|
||||
apps.setAppHidden(true);
|
||||
@@ -744,7 +671,7 @@ public class LauncherActivity extends Activity implements View.OnClickListener,
|
||||
}
|
||||
|
||||
// show the app rename Dialog
|
||||
private void renameApp(String activityName, String appName) {
|
||||
public void renameApp(String activityName, String appName) {
|
||||
dialogs = new RenameInputDialogs(this, activityName, appName, this);
|
||||
Window window = dialogs.getWindow();
|
||||
if (window != null) {
|
||||
@@ -771,20 +698,20 @@ public class LauncherActivity extends Activity implements View.OnClickListener,
|
||||
}
|
||||
|
||||
// reset the app
|
||||
private void resetApp(String activityName) {
|
||||
public void resetApp(String activityName) {
|
||||
DbUtils.removeAppName(activityName);
|
||||
DbUtils.removeColor(activityName);
|
||||
DbUtils.removeSize(activityName);
|
||||
addAppAfterReset(activityName, true);
|
||||
}
|
||||
|
||||
private void showAppInfo(String activityName) {
|
||||
public void showAppInfo(String activityName) {
|
||||
Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
||||
intent.setData(Uri.parse("package:" + activityName.split("/")[0]));
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
private void uninstallApp(String activityName) {
|
||||
public void uninstallApp(String activityName) {
|
||||
Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
|
||||
intent.setData(Uri.parse("package:" + activityName.split("/")[0]));
|
||||
intent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
|
||||
@@ -792,7 +719,7 @@ public class LauncherActivity extends Activity implements View.OnClickListener,
|
||||
}
|
||||
|
||||
//show dialog(i.e a color seek bar) for change color
|
||||
private void changeColorSize(String activityName, TextView view) {
|
||||
public void changeColorSize(String activityName, TextView view) {
|
||||
int color = DbUtils.getAppColor(activityName);
|
||||
if (color == DbUtils.NULL_TEXT_COLOR) {
|
||||
color = view.getCurrentTextColor();
|
||||
@@ -1214,7 +1141,7 @@ public class LauncherActivity extends Activity implements View.OnClickListener,
|
||||
*
|
||||
* @param view shortcut view to be removed...
|
||||
*/
|
||||
private void removeShortcut(AppTextView view) {
|
||||
public void removeShortcut(AppTextView view) {
|
||||
// view.setVisibility(View.GONE);
|
||||
shortcutUtils.removeShortcut(new Shortcut(view.getText().toString(), view.getUri()));
|
||||
|
||||
@@ -1224,13 +1151,13 @@ public class LauncherActivity extends Activity implements View.OnClickListener,
|
||||
|
||||
@Override
|
||||
public void onSwipe(Gestures.Direction direction) {
|
||||
if (direction == Gestures.Direction.SWIPE_RIGHT) {
|
||||
if (direction == Gestures.Direction.SWIPE_UP) {
|
||||
searching = true;
|
||||
mSearchBox.setText("");
|
||||
mSearchBox.setVisibility(View.VISIBLE);
|
||||
mSearchBox.requestFocus();
|
||||
imm.showSoftInput(mSearchBox, InputMethodManager.SHOW_IMPLICIT);
|
||||
} else if (direction == Gestures.Direction.SWIPE_LEFT) {
|
||||
} else if (direction == Gestures.Direction.SWIPE_DOWN) {
|
||||
if (searching) {
|
||||
mSearchBox.setVisibility(View.GONE);
|
||||
imm.hideSoftInputFromWindow(mSearchBox.getWindowToken(), 0);
|
||||
@@ -1245,6 +1172,13 @@ public class LauncherActivity extends Activity implements View.OnClickListener,
|
||||
DeviceAdminManager.lockDevice(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLongPress() {
|
||||
// Show launcher settings on long press in free space
|
||||
dialogs = new GlobalSettingsDialog(this, this);
|
||||
dialogs.show();
|
||||
}
|
||||
|
||||
static class SearchTask extends AsyncTask<CharSequence, Void, ArrayList<Apps>> {
|
||||
@Override
|
||||
protected void onPostExecute(ArrayList<Apps> filteredApps) {
|
||||
@@ -1341,100 +1275,16 @@ public class LauncherActivity extends Activity implements View.OnClickListener,
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a comprehensive permission request dialog
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle("Welcome to Lunox! 🚀");
|
||||
builder.setMessage("To provide the best experience, Lunox needs a few permissions:\n\n" +
|
||||
"📱 **Usage Access**: To show all your installed apps\n" +
|
||||
"🔒 **Device Admin**: To manage app freezing and advanced features\n\n" +
|
||||
"These permissions help Lunox work properly and show all your apps.");
|
||||
|
||||
builder.setIcon(android.R.drawable.ic_dialog_info);
|
||||
builder.setCancelable(false);
|
||||
|
||||
builder.setPositiveButton("Grant Permissions", (dialog, which) -> {
|
||||
requestPermissions();
|
||||
});
|
||||
|
||||
builder.setNegativeButton("Skip for Now", (dialog, which) -> {
|
||||
DbUtils.setPermissionDialogShown(true);
|
||||
});
|
||||
|
||||
AlertDialog dialog = builder.create();
|
||||
dialog.show();
|
||||
// Create the new permission dialog with proper theming
|
||||
Context ctx;
|
||||
if (DbUtils.getTheme() == R.style.Wallpaper)
|
||||
ctx = new ContextThemeWrapper(this, R.style.AppTheme);
|
||||
else
|
||||
ctx = new ContextThemeWrapper(this, DbUtils.getTheme());
|
||||
|
||||
PermissionDialog permissionDialog = new PermissionDialog(ctx, this);
|
||||
permissionDialog.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Request all necessary permissions
|
||||
*/
|
||||
private void requestPermissions() {
|
||||
// Check and request Usage Access permission
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
|
||||
AppOpsManager appOps = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);
|
||||
int mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,
|
||||
android.os.Process.myUid(), getPackageName());
|
||||
if (mode != AppOpsManager.MODE_ALLOWED) {
|
||||
showUsageAccessDialog();
|
||||
}
|
||||
}
|
||||
|
||||
// Check and request Device Admin permission
|
||||
if (!DeviceAdminManager.isDeviceAdminActive(this)) {
|
||||
showDeviceAdminDialog();
|
||||
}
|
||||
|
||||
DbUtils.setPermissionDialogShown(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show dialog to guide user to enable usage access
|
||||
*/
|
||||
private void showUsageAccessDialog() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle("📱 Usage Access Required");
|
||||
builder.setMessage("To show all your installed apps, please enable 'Usage Access' for Lunox:\n\n" +
|
||||
"1. Tap 'Open Settings'\n" +
|
||||
"2. Find 'Lunox Dev' in the list\n" +
|
||||
"3. Toggle 'Allow usage access' ON\n" +
|
||||
"4. Return to Lunox\n\n" +
|
||||
"This helps Lunox detect all your apps properly.");
|
||||
|
||||
builder.setIcon(android.R.drawable.ic_menu_manage);
|
||||
builder.setCancelable(false);
|
||||
|
||||
builder.setPositiveButton("Open Settings", (dialog, which) -> {
|
||||
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
|
||||
startActivity(intent);
|
||||
});
|
||||
|
||||
builder.setNegativeButton("Later", null);
|
||||
|
||||
AlertDialog dialog = builder.create();
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show dialog to guide user to enable device admin
|
||||
*/
|
||||
private void showDeviceAdminDialog() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle("🔒 Device Admin Required");
|
||||
builder.setMessage("Device Admin permission enables advanced features like:\n\n" +
|
||||
"• App freezing functionality\n" +
|
||||
"• Enhanced app management\n" +
|
||||
"• Better system integration\n\n" +
|
||||
"This permission is safe and only used for launcher features.");
|
||||
|
||||
builder.setIcon(android.R.drawable.ic_lock_lock);
|
||||
builder.setCancelable(false);
|
||||
|
||||
builder.setPositiveButton("Enable Device Admin", (dialog, which) -> {
|
||||
DeviceAdminManager.requestDeviceAdminPermission(this);
|
||||
});
|
||||
|
||||
builder.setNegativeButton("Skip", null);
|
||||
|
||||
AlertDialog dialog = builder.create();
|
||||
dialog.show();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Last Launcher
|
||||
* Copyright (C) 2019 Shubham Tyagi
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.github.sankalp.lunox.dialogs;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.PopupWindow;
|
||||
import android.widget.TextView;
|
||||
|
||||
import io.github.sankalp.lunox.LauncherActivity;
|
||||
import io.github.sankalp.lunox.R;
|
||||
import io.github.sankalp.lunox.utils.DbUtils;
|
||||
import io.github.sankalp.lunox.views.textview.AppTextView;
|
||||
|
||||
/**
|
||||
* App settings popup that shows options for individual apps
|
||||
*/
|
||||
public class AppSettingsPopup extends PopupWindow implements View.OnClickListener {
|
||||
|
||||
private final LauncherActivity launcherActivity;
|
||||
private final Context context;
|
||||
private final String activityName;
|
||||
private final AppTextView appTextView;
|
||||
private TextView freezeSize;
|
||||
private TextView hideApp;
|
||||
private TextView resetToDefault;
|
||||
private TextView uninstallApp;
|
||||
|
||||
public AppSettingsPopup(Context context, String activityName, AppTextView appTextView, LauncherActivity launcherActivity) {
|
||||
super(context);
|
||||
this.context = context;
|
||||
this.activityName = activityName;
|
||||
this.appTextView = appTextView;
|
||||
this.launcherActivity = launcherActivity;
|
||||
|
||||
initPopup();
|
||||
}
|
||||
|
||||
private void initPopup() {
|
||||
LayoutInflater inflater = LayoutInflater.from(context);
|
||||
View contentView = inflater.inflate(R.layout.dialog_app_settings, null);
|
||||
setContentView(contentView);
|
||||
|
||||
// Set popup properties
|
||||
setWidth(android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
setHeight(android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
setFocusable(true);
|
||||
setOutsideTouchable(true);
|
||||
|
||||
// Set background to match the dialog style with border
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
|
||||
setBackgroundDrawable(context.getResources().getDrawable(R.drawable.popup_background, null));
|
||||
} else {
|
||||
setBackgroundDrawable(context.getResources().getDrawable(R.drawable.popup_background));
|
||||
}
|
||||
|
||||
// Set up click listeners
|
||||
contentView.findViewById(R.id.app_settings_color).setOnClickListener(this);
|
||||
contentView.findViewById(R.id.app_settings_rename).setOnClickListener(this);
|
||||
|
||||
freezeSize = contentView.findViewById(R.id.app_settings_freeze_size);
|
||||
freezeSize.setOnClickListener(this);
|
||||
|
||||
contentView.findViewById(R.id.app_settings_app_info).setOnClickListener(this);
|
||||
contentView.findViewById(R.id.app_settings_reset_color).setOnClickListener(this);
|
||||
|
||||
hideApp = contentView.findViewById(R.id.app_settings_hide);
|
||||
hideApp.setOnClickListener(this);
|
||||
|
||||
resetToDefault = contentView.findViewById(R.id.app_settings_reset_to_default);
|
||||
resetToDefault.setOnClickListener(this);
|
||||
resetToDefault.setTextColor(Color.parseColor("#E53935"));
|
||||
|
||||
uninstallApp = contentView.findViewById(R.id.app_settings_uninstall);
|
||||
uninstallApp.setOnClickListener(this);
|
||||
uninstallApp.setTextColor(Color.parseColor("#E53935"));
|
||||
|
||||
// Set proper text based on DB value
|
||||
if (DbUtils.isAppFrozen(activityName)) {
|
||||
freezeSize.setText(R.string.unfreeze_size);
|
||||
} else {
|
||||
freezeSize.setText(R.string.freeze_size);
|
||||
}
|
||||
|
||||
// Handle shortcut-specific settings
|
||||
if (appTextView.isShortcut()) {
|
||||
uninstallApp.setText(R.string.remove);
|
||||
hideApp.setVisibility(View.GONE);
|
||||
contentView.findViewById(R.id.app_settings_rename).setVisibility(View.GONE);
|
||||
contentView.findViewById(R.id.app_settings_app_info).setVisibility(View.GONE);
|
||||
} else {
|
||||
hideApp.setTextColor(Color.parseColor("#E53935"));
|
||||
}
|
||||
}
|
||||
|
||||
public void showAsDropDown(View anchor) {
|
||||
showAsDropDown(anchor, 0, 0, Gravity.START);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
int id = view.getId();
|
||||
if (id == R.id.app_settings_color) {
|
||||
launcherActivity.changeColorSize(activityName, appTextView);
|
||||
dismiss();
|
||||
} else if (id == R.id.app_settings_rename) {
|
||||
launcherActivity.renameApp(activityName, appTextView.getText().toString());
|
||||
dismiss();
|
||||
} else if (id == R.id.app_settings_freeze_size) {
|
||||
launcherActivity.freezeAppSize(activityName);
|
||||
dismiss();
|
||||
} else if (id == R.id.app_settings_app_info) {
|
||||
launcherActivity.showAppInfo(activityName);
|
||||
dismiss();
|
||||
} else if (id == R.id.app_settings_reset_color) {
|
||||
launcherActivity.resetAppColor(activityName);
|
||||
dismiss();
|
||||
} else if (id == R.id.app_settings_hide) {
|
||||
launcherActivity.hideApp(activityName);
|
||||
dismiss();
|
||||
} else if (id == R.id.app_settings_reset_to_default) {
|
||||
launcherActivity.resetApp(activityName);
|
||||
dismiss();
|
||||
} else if (id == R.id.app_settings_uninstall) {
|
||||
if (appTextView.isShortcut()) {
|
||||
launcherActivity.removeShortcut(appTextView);
|
||||
} else {
|
||||
launcherActivity.uninstallApp(activityName);
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Last Launcher
|
||||
* Copyright (C) 2019 Shubham Tyagi
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.github.sankalp.lunox.dialogs;
|
||||
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import io.github.sankalp.lunox.LauncherActivity;
|
||||
import io.github.sankalp.lunox.R;
|
||||
import io.github.sankalp.lunox.utils.DbUtils;
|
||||
import io.github.sankalp.lunox.utils.DeviceAdminManager;
|
||||
|
||||
public class PermissionDialog extends Dialog implements View.OnClickListener {
|
||||
|
||||
private final LauncherActivity context;
|
||||
private TextView usageAccessButton;
|
||||
private TextView deviceAdminButton;
|
||||
private TextView continueButton;
|
||||
|
||||
public PermissionDialog(Context context, LauncherActivity launcherActivity) {
|
||||
super(context);
|
||||
this.context = launcherActivity;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
setContentView(R.layout.dialog_permission_setup);
|
||||
setCancelable(false);
|
||||
|
||||
// Initialize views
|
||||
usageAccessButton = findViewById(R.id.permission_usage_access);
|
||||
deviceAdminButton = findViewById(R.id.permission_device_admin);
|
||||
continueButton = findViewById(R.id.permission_continue);
|
||||
|
||||
// Set click listeners
|
||||
usageAccessButton.setOnClickListener(this);
|
||||
deviceAdminButton.setOnClickListener(this);
|
||||
continueButton.setOnClickListener(this);
|
||||
|
||||
// Update button states
|
||||
updatePermissionStates();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
int id = view.getId();
|
||||
|
||||
if (id == R.id.permission_usage_access) {
|
||||
openUsageAccessSettings();
|
||||
} else if (id == R.id.permission_device_admin) {
|
||||
enableDeviceAdmin();
|
||||
} else if (id == R.id.permission_continue) {
|
||||
continueToLauncher();
|
||||
}
|
||||
}
|
||||
|
||||
private void openUsageAccessSettings() {
|
||||
try {
|
||||
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
|
||||
context.startActivity(intent);
|
||||
Toast.makeText(context, "Please enable Usage Access for Lunox", Toast.LENGTH_LONG).show();
|
||||
} catch (Exception e) {
|
||||
// Fallback to general settings if specific intent fails
|
||||
Intent intent = new Intent(Settings.ACTION_SETTINGS);
|
||||
context.startActivity(intent);
|
||||
Toast.makeText(context, "Please find and enable Usage Access for Lunox in Settings", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
private void enableDeviceAdmin() {
|
||||
try {
|
||||
DeviceAdminManager.requestDeviceAdminPermission(context);
|
||||
Toast.makeText(context, "Please enable Device Admin for Lunox", Toast.LENGTH_LONG).show();
|
||||
} catch (Exception e) {
|
||||
Toast.makeText(context, "Unable to open Device Admin settings", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
private void continueToLauncher() {
|
||||
// Mark permission dialog as shown
|
||||
DbUtils.setPermissionDialogShown(true);
|
||||
|
||||
// Check if at least one permission is granted
|
||||
boolean hasUsageAccess = checkUsageAccessPermission();
|
||||
boolean hasDeviceAdmin = DeviceAdminManager.isDeviceAdminActive(context);
|
||||
|
||||
if (hasUsageAccess || hasDeviceAdmin) {
|
||||
dismiss();
|
||||
context.loadApps(); // Reload apps after permissions are granted
|
||||
} else {
|
||||
Toast.makeText(context, "Please grant at least one permission to continue", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkUsageAccessPermission() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
|
||||
AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
|
||||
int mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,
|
||||
android.os.Process.myUid(), context.getPackageName());
|
||||
return mode == AppOpsManager.MODE_ALLOWED;
|
||||
}
|
||||
return true; // For older versions, assume permission is granted
|
||||
}
|
||||
|
||||
private void updatePermissionStates() {
|
||||
// Update Usage Access button
|
||||
boolean hasUsageAccess = checkUsageAccessPermission();
|
||||
if (hasUsageAccess) {
|
||||
usageAccessButton.setText("Usage Access");
|
||||
usageAccessButton.setAlpha(0.7f);
|
||||
} else {
|
||||
usageAccessButton.setText("Enable Usage Access");
|
||||
usageAccessButton.setAlpha(1.0f);
|
||||
}
|
||||
|
||||
// Update Device Admin button
|
||||
boolean hasDeviceAdmin = DeviceAdminManager.isDeviceAdminActive(context);
|
||||
if (hasDeviceAdmin) {
|
||||
deviceAdminButton.setText("Device Admin");
|
||||
deviceAdminButton.setAlpha(0.7f);
|
||||
} else {
|
||||
deviceAdminButton.setText("Enable Device Admin");
|
||||
deviceAdminButton.setAlpha(1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
// Update permission states when dialog becomes visible
|
||||
updatePermissionStates();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
super.onWindowFocusChanged(hasFocus);
|
||||
if (hasFocus) {
|
||||
// Update permission states when user returns to the dialog
|
||||
updatePermissionStates();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,6 +79,11 @@ public class Gestures extends GestureDetector.SimpleOnGestureListener {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLongPress(MotionEvent e) {
|
||||
this.listener.onLongPress();
|
||||
}
|
||||
|
||||
|
||||
public enum Direction {
|
||||
SWIPE_UP, SWIPE_DOWN, SWIPE_LEFT, SWIPE_RIGHT
|
||||
@@ -88,6 +93,8 @@ public class Gestures extends GestureDetector.SimpleOnGestureListener {
|
||||
void onSwipe(Direction direction);
|
||||
|
||||
void onDoubleTap();
|
||||
|
||||
void onLongPress();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
|
||||
<!-- Black background like the dialog -->
|
||||
<solid android:color="@android:color/black" />
|
||||
|
||||
<!-- Border/stroke around the popup -->
|
||||
<stroke
|
||||
android:width="2dp"
|
||||
android:color="#DEDEDE" />
|
||||
|
||||
<!-- Rounded corners for better appearance -->
|
||||
<corners android:radius="4dp" />
|
||||
|
||||
</shape>
|
||||
@@ -1,10 +1,12 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/root_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/scroll_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Last Launcher
|
||||
~ Copyright (C) 2019 Shubham Tyagi
|
||||
~
|
||||
~ This program is free software: you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation, either version 3 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License
|
||||
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
|
||||
<LinearLayout
|
||||
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="10dp">
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/app_settings_color"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
android:gravity="center"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingBottom="5dp"
|
||||
android:text="@string/color_for_this_entry"
|
||||
android:textSize="20sp" />
|
||||
|
||||
<View
|
||||
android:layout_width="170dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_gravity="center|center_horizontal|center_vertical"
|
||||
android:background="#DEDEDE"
|
||||
android:foregroundGravity="center_vertical|center_horizontal" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/app_settings_rename"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingBottom="5dp"
|
||||
android:text="@string/rename"
|
||||
android:textSize="20sp" />
|
||||
|
||||
<View
|
||||
android:layout_width="170dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_gravity="center|center_horizontal|center_vertical"
|
||||
android:background="#DEDEDE"
|
||||
android:foregroundGravity="center_vertical|center_horizontal" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/app_settings_freeze_size"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingBottom="5dp"
|
||||
android:text="@string/freeze_size"
|
||||
android:textSize="20sp" />
|
||||
|
||||
<View
|
||||
android:layout_width="170dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_gravity="center|center_horizontal|center_vertical"
|
||||
android:background="#DEDEDE"
|
||||
android:foregroundGravity="center_vertical|center_horizontal" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/app_settings_app_info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingBottom="5dp"
|
||||
android:text="@string/app_info"
|
||||
android:textSize="20sp" />
|
||||
|
||||
<View
|
||||
android:layout_width="170dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_gravity="center|center_horizontal|center_vertical"
|
||||
android:background="#DEDEDE"
|
||||
android:foregroundGravity="center_vertical|center_horizontal" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/app_settings_reset_color"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingBottom="5dp"
|
||||
android:text="@string/reset_color"
|
||||
android:textSize="20sp" />
|
||||
|
||||
<View
|
||||
android:layout_width="170dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_gravity="center|center_horizontal|center_vertical"
|
||||
android:background="#DEDEDE"
|
||||
android:foregroundGravity="center_vertical|center_horizontal" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/app_settings_hide"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingBottom="5dp"
|
||||
|
||||
android:text="@string/hide"
|
||||
android:textSize="20sp" />
|
||||
|
||||
<View
|
||||
android:layout_width="170dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_gravity="center|center_horizontal|center_vertical"
|
||||
android:background="#DEDEDE"
|
||||
android:foregroundGravity="center_vertical|center_horizontal" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/app_settings_reset_to_default"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingBottom="5dp"
|
||||
|
||||
android:text="@string/reset_to_default"
|
||||
android:textSize="20sp" />
|
||||
|
||||
<View
|
||||
android:layout_width="170dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_gravity="center|center_horizontal|center_vertical"
|
||||
android:background="#DEDEDE"
|
||||
android:foregroundGravity="center_vertical|center_horizontal" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/app_settings_uninstall"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:paddingTop="5dp"
|
||||
|
||||
android:paddingBottom="5dp"
|
||||
android:text="@string/uninstall"
|
||||
android:textSize="20sp" />
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
@@ -0,0 +1,94 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Last Launcher
|
||||
~ Copyright (C) 2019 Shubham Tyagi
|
||||
~
|
||||
~ This program is free software: you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation, either version 3 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License
|
||||
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<LinearLayout android:id="@+id/permission_linear_layout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="20dp"
|
||||
android:gravity="center"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<!-- Title -->
|
||||
<TextView
|
||||
android:id="@+id/permission_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:padding="10dp"
|
||||
android:text="@string/permission_dialog_title"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<!-- Description -->
|
||||
<TextView
|
||||
android:id="@+id/permission_description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:padding="10dp"
|
||||
android:text="@string/permission_dialog_message"
|
||||
android:textSize="16sp"
|
||||
android:lineSpacingMultiplier="1.2" />
|
||||
|
||||
<!-- Usage Access Permission -->
|
||||
<TextView
|
||||
android:id="@+id/permission_usage_access"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:padding="15dp"
|
||||
android:layout_margin="5dp"
|
||||
android:text="Enable Usage Access"
|
||||
android:textSize="20sp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true" />
|
||||
|
||||
<!-- Device Admin Permission -->
|
||||
<TextView
|
||||
android:id="@+id/permission_device_admin"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:padding="15dp"
|
||||
android:layout_margin="5dp"
|
||||
android:text="Enable Device Admin"
|
||||
android:textSize="20sp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true" />
|
||||
|
||||
<!-- Continue Button -->
|
||||
<TextView
|
||||
android:id="@+id/permission_continue"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:padding="15dp"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:text="Continue to Lunox"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -90,12 +90,17 @@
|
||||
<!--Sort Apps IN : RECENTLY USED FIRST ORDER -->
|
||||
<string name="recently_first">Recently first</string>
|
||||
<string name="restart_launcher">Restart Launcher</string>
|
||||
|
||||
|
||||
<string name="device_admin_label">Lunox Device Admin</string>
|
||||
<string name="device_admin_description">Required for double-tap to lock screen functionality</string>
|
||||
<string name="device_admin_enable">Enable Device Admin</string>
|
||||
<string name="device_admin_disabled">Device Admin is required for lock screen functionality</string>
|
||||
|
||||
<!-- Permission Dialog Strings -->
|
||||
<string name="permission_dialog_title">Welcome to Lunox! 🚀</string>
|
||||
<string name="permission_dialog_message">To provide the best launcher experience, Lunox needs these permissions:\n\n<b>Usage Access</b> - Display all your apps\n<b>Device Admin</b> - Enable advanced features\n\nTap each permission below to enable it.</string>
|
||||
|
||||
|
||||
<!-- Frozen apps dialog title -->
|
||||
<string name="freezed_apps">Freezed Apps</string>
|
||||
<!-- Color source from ColorSniffer app -->
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 264 KiB |
Reference in new issue
Block a user