diff --git a/.idea/misc.xml b/.idea/misc.xml
index e222ade..b9cc79a 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -8,6 +8,9 @@
+
+
+
diff --git a/app/build.gradle b/app/build.gradle
index af31321..5858121 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -13,8 +13,8 @@ android {
applicationId "com.factor.launcher"
minSdkVersion 22
targetSdkVersion 31
- versionCode 38
- versionName "0.66"
+ versionCode 40
+ versionName "0.7"
renderscriptTargetApi 31
renderscriptSupportModeEnabled true
diff --git a/app/src/main/java/com/factor/launcher/adapters/AppListAdapter.java b/app/src/main/java/com/factor/launcher/adapters/AppListAdapter.java
index f8ab34a..3be08e3 100644
--- a/app/src/main/java/com/factor/launcher/adapters/AppListAdapter.java
+++ b/app/src/main/java/com/factor/launcher/adapters/AppListAdapter.java
@@ -236,7 +236,8 @@ public AppListViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewT
MenuInflater inflater = activity.getMenuInflater();
inflater.inflate(R.menu.app_list_item_menu, menu);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
+ {
menu.setGroupDividerEnabled(true);
}
diff --git a/app/src/main/java/com/factor/launcher/adapters/RecentAppsAdapter.java b/app/src/main/java/com/factor/launcher/adapters/RecentAppsAdapter.java
index a969843..65be6e9 100644
--- a/app/src/main/java/com/factor/launcher/adapters/RecentAppsAdapter.java
+++ b/app/src/main/java/com/factor/launcher/adapters/RecentAppsAdapter.java
@@ -2,6 +2,7 @@
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -10,7 +11,7 @@
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.RecyclerView;
import com.factor.launcher.R;
-import com.factor.launcher.databinding.RecentAppsItemBinding;
+import com.factor.launcher.databinding.ItemRecentAppsBinding;
import com.factor.launcher.models.UserApp;
import com.factor.launcher.receivers.AppActionReceiver;
import com.factor.launcher.util.Constants;
@@ -41,7 +42,7 @@ public void addRecentBroadcast()
@Override
public RecentAppViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
{
- View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recent_apps_item, parent, false);
+ View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recent_apps, parent, false);
return new RecentAppViewHolder(view);
}
@@ -70,7 +71,7 @@ public int getItemCount()
static class RecentAppViewHolder extends RecyclerView.ViewHolder
{
- private final RecentAppsItemBinding binding;
+ private final ItemRecentAppsBinding binding;
public RecentAppViewHolder(@NonNull View itemView)
{
@@ -83,7 +84,13 @@ public void bind(String name, AppListManager appListManager)
binding.setPackageName(name);
try
{
- binding.recentIcon.setImageDrawable(appListManager.packageManager.getApplicationIcon(name));
+ Drawable icon;
+ if (appListManager.getIconPack() != null)
+ icon = appListManager.getIconPack().getDrawableIconForPackage(name, appListManager.packageManager.getApplicationIcon(name));
+ else
+ icon = appListManager.packageManager.getApplicationIcon(name);
+
+ binding.recentIcon.setImageDrawable(icon);
binding.recentIcon.setElevationDp(appListManager.settings.getShowShadowAroundIcon()? 30 : 0);
}
catch (PackageManager.NameNotFoundException ignored){}
diff --git a/app/src/main/java/com/factor/launcher/database/AppSettingsDatabase.kt b/app/src/main/java/com/factor/launcher/database/AppSettingsDatabase.kt
index 9ce01e7..6758b8a 100644
--- a/app/src/main/java/com/factor/launcher/database/AppSettingsDatabase.kt
+++ b/app/src/main/java/com/factor/launcher/database/AppSettingsDatabase.kt
@@ -6,7 +6,7 @@ import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import com.factor.launcher.models.AppSettings
-@Database(entities = [AppSettings::class], exportSchema = false, version = 3)
+@Database(entities = [AppSettings::class], exportSchema = false, version = 4)
abstract class AppSettingsDatabase : RoomDatabase()
{
abstract fun appSettingsDao(): AppSettingsDao
@@ -15,6 +15,7 @@ abstract class AppSettingsDatabase : RoomDatabase()
Room.databaseBuilder(it.applicationContext, AppSettingsDatabase::class.java, "factor_settings")
.addMigrations(SettingsMigrations.MIGRATION_CHANGE_TILE_LIST_RESIZING)
.addMigrations(SettingsMigrations.MIGRATION_STATIC_BLUR)
+ .addMigrations(SettingsMigrations.MIGRATION_ICON_PACK)
.fallbackToDestructiveMigration()
.allowMainThreadQueries()
.build()
@@ -56,6 +57,14 @@ abstract class AppSettingsDatabase : RoomDatabase()
database.execSQL("ALTER TABLE AppSettings ADD COLUMN static_blur INTEGER NOT NULL DEFAULT 0")
}
}
+
+ val MIGRATION_ICON_PACK = object : Migration(3, 4)
+ {
+ override fun migrate(database: SupportSQLiteDatabase)
+ {
+ database.execSQL("ALTER TABLE AppSettings ADD COLUMN icon_pack TEXT NOT NULL DEFAULT ''")
+ }
+ }
}
}
diff --git a/app/src/main/java/com/factor/launcher/fragments/SettingsFragment.java b/app/src/main/java/com/factor/launcher/fragments/SettingsFragment.java
index d95f42b..a3b0922 100644
--- a/app/src/main/java/com/factor/launcher/fragments/SettingsFragment.java
+++ b/app/src/main/java/com/factor/launcher/fragments/SettingsFragment.java
@@ -13,10 +13,7 @@
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
-import android.view.HapticFeedbackConstants;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
+import android.view.*;
import android.widget.EditText;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
@@ -27,6 +24,8 @@
import com.factor.launcher.R;
import com.factor.launcher.activities.EmptyHome;
import com.factor.launcher.databinding.FragmentSettingsBinding;
+import com.factor.launcher.models.IconPackProvider;
+import com.factor.launcher.ui.IconPackPickerView;
import com.factor.launcher.view_models.AppSettingsManager;
import com.factor.launcher.models.AppSettings;
import com.factor.launcher.ui.CustomFlag;
@@ -59,6 +58,8 @@ public class SettingsFragment extends Fragment implements LifecycleOwner
private Bitmap m;
+ private String iconPack = "";
+
public SettingsFragment()
{
// Required empty public constructor
@@ -305,6 +306,31 @@ public void afterTextChanged(Editable s) {}
binding.tileColorPickerButton.setOnClickListener(v -> showColorPickerDialog("Tile color"));
binding.searchBarColorPickerButton.setOnClickListener(v -> showColorPickerDialog("Search bar color"));
+
+ // Icon pack picker
+ iconPack = settings.getIconPackPackageName();
+ binding.iconPackPicker.setCurrentIconPack(iconPack);
+ binding.iconPackPicker.setOnIconPackClickedListener(new IconPackPickerView.OnIconPackClickedListener()
+ {
+ @Override
+ public void onIconPackClicked(IconPackProvider clickedIconPack)
+ {
+ if (clickedIconPack.isCurrentIconPack())
+ {
+ binding.demoIconPack.setImageDrawable(clickedIconPack.getIcon());
+ binding.demoIconPack.setVisibility(View.VISIBLE);
+ iconPack = clickedIconPack.getPackageName();
+ }
+ else
+ {
+ binding.demoIconPack.setVisibility(View.INVISIBLE);
+ iconPack = "";
+ }
+
+ binding.tileLabel.setText(binding.iconPackPicker.getCurrentIconPackName());
+ }
+ });
+
setUpUIState();
setUpDemoTile();
}
@@ -412,6 +438,8 @@ private void updateSettings()
updated.setTileThemeColor(tileColor);
updated.setSearchBarColor(searchColor);
+ updated.setIconPackPackageName(binding.iconPackPicker.getCurrentIconPackPackageName());
+
AppSettingsManager.getInstance(getActivity().getApplication()).setAppSettings(updated).updateSettings();
Intent intent = new Intent();
@@ -433,7 +461,8 @@ private boolean areSettingsChanged()
!tileColor.equals(settings.getTileThemeColor()) ||
!searchColor.equals(settings.getSearchBarColor()) ||
binding.iconShadowToggle.isChecked() != settings.getShowShadowAroundIcon() ||
- binding.staticBlurToggle.isChecked() != settings.getStaticBlur();
+ binding.staticBlurToggle.isChecked() != settings.getStaticBlur() ||
+ binding.iconPackPicker.getCurrentIconPackPackageName().equals(settings.getIconPackPackageName());
}
diff --git a/app/src/main/java/com/factor/launcher/models/AppSettings.kt b/app/src/main/java/com/factor/launcher/models/AppSettings.kt
index 0ecdd0a..45435d2 100644
--- a/app/src/main/java/com/factor/launcher/models/AppSettings.kt
+++ b/app/src/main/java/com/factor/launcher/models/AppSettings.kt
@@ -1,9 +1,11 @@
package com.factor.launcher.models
+import android.content.Context
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.factor.launcher.util.Constants
+import com.factor.launcher.util.IconPackManager
@Entity
@@ -44,4 +46,16 @@ class AppSettings
@ColumnInfo(name = "static_blur")
var staticBlur = false
+
+ @ColumnInfo(name = "icon_pack")
+ var iconPackPackageName = ""
+
+
+ fun getIconPackProvider(context: Context): IconPackManager.IconPack?
+ {
+ val iconPackManager = IconPackManager()
+ iconPackManager.setContext(context)
+ iconPackManager.getAvailableIconPacks(true)
+ return iconPackManager.getIconPackWithName(iconPackPackageName)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/factor/launcher/models/Factor.kt b/app/src/main/java/com/factor/launcher/models/Factor.kt
index fefc6ef..99088e8 100644
--- a/app/src/main/java/com/factor/launcher/models/Factor.kt
+++ b/app/src/main/java/com/factor/launcher/models/Factor.kt
@@ -1,5 +1,6 @@
package com.factor.launcher.models
+import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import androidx.room.ColumnInfo
import androidx.room.Entity
@@ -44,11 +45,18 @@ class Factor
fun getIcon() : Drawable? = this.userApp.icon
+ fun getBitmapIcon() : Bitmap? = this.userApp.bitmapIcon
+
fun setIcon(icon : Drawable)
{
this.userApp.icon = icon
}
+ fun setIcon(bitmap: Bitmap)
+ {
+ this.userApp.bitmapIcon = bitmap
+ }
+
object Size
{
const val small : Int = 1
diff --git a/app/src/main/java/com/factor/launcher/models/IconPackProvider.kt b/app/src/main/java/com/factor/launcher/models/IconPackProvider.kt
new file mode 100644
index 0000000..c289149
--- /dev/null
+++ b/app/src/main/java/com/factor/launcher/models/IconPackProvider.kt
@@ -0,0 +1,6 @@
+package com.factor.launcher.models
+
+class IconPackProvider : UserApp()
+{
+ var isCurrentIconPack = false
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/factor/launcher/models/UserApp.kt b/app/src/main/java/com/factor/launcher/models/UserApp.kt
index cdc842a..12cd3bc 100644
--- a/app/src/main/java/com/factor/launcher/models/UserApp.kt
+++ b/app/src/main/java/com/factor/launcher/models/UserApp.kt
@@ -1,5 +1,6 @@
package com.factor.launcher.models
+import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.view.View
@@ -14,7 +15,7 @@ import java.util.*
import kotlin.collections.ArrayList
@Entity
-class UserApp
+open class UserApp
{
@PrimaryKey
var packageName: String = ""
@@ -69,6 +70,9 @@ class UserApp
@Ignore
var icon: Drawable? = null
+ @Ignore
+ var bitmapIcon: Bitmap? = null
+
@Ignore
var isMediaTile = false
@@ -90,6 +94,11 @@ class UserApp
//...
}
+ fun equals(userApp: UserApp) : Boolean
+ {
+ return this.packageName.equals(userApp.packageName)
+ }
+
//generate new factor
fun toFactor(): Factor
{
@@ -113,8 +122,16 @@ class UserApp
{
return if (notification.title != notificationHolder.title || notification.text != notificationHolder.text)
{
- currentNotifications[currentNotifications.indexOf(notification)] = notificationHolder
- true
+ try
+ {
+ currentNotifications[currentNotifications.indexOf(notification)] = notificationHolder
+ return true
+ }
+ catch (e : IndexOutOfBoundsException)
+ {
+ return false
+ }
+
}
else false
}
diff --git a/app/src/main/java/com/factor/launcher/ui/IconPackPickerView.java b/app/src/main/java/com/factor/launcher/ui/IconPackPickerView.java
new file mode 100644
index 0000000..e8ed6a2
--- /dev/null
+++ b/app/src/main/java/com/factor/launcher/ui/IconPackPickerView.java
@@ -0,0 +1,231 @@
+package com.factor.launcher.ui;
+
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import androidx.annotation.NonNull;
+import androidx.appcompat.widget.AppCompatImageView;
+import androidx.appcompat.widget.AppCompatTextView;
+import androidx.cardview.widget.CardView;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import com.factor.bouncy.BouncyRecyclerView;
+import com.factor.launcher.R;
+import com.factor.launcher.models.IconPackProvider;
+import com.factor.launcher.util.IconPackManager;
+
+import java.util.ArrayList;
+
+
+public class IconPackPickerView extends CardView
+{
+ private IconPackProvider selectedIconPack;
+
+ private final ArrayList iconPacks = new ArrayList<>();
+
+ private final IconPackPickerAdapter adapter = new IconPackPickerAdapter();
+
+ private OnIconPackClickedListener listener;
+
+ public IconPackPickerView(Context context)
+ {
+ super(context);
+ init(context);
+ }
+
+ public IconPackPickerView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context);
+ }
+
+ public IconPackPickerView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init(context);
+ }
+
+ public void setOnIconPackClickedListener(OnIconPackClickedListener listener)
+ {
+ this.listener = listener;
+ }
+
+
+ public void setCurrentIconPack(String packageName)
+ {
+ selectedIconPack = new IconPackProvider();
+ selectedIconPack.setPackageName(packageName);
+ if (iconPacks.contains(selectedIconPack))
+ {
+ selectedIconPack.setCurrentIconPack(true);
+ adapter.notifyItemChanged(iconPacks.indexOf(selectedIconPack));
+ }
+
+ Log.d("Icon_pack", "current selected: " + packageName);
+ }
+ public String getCurrentIconPackName()
+ {
+ if (selectedIconPack.isCurrentIconPack() && iconPacks.contains(selectedIconPack))
+ return selectedIconPack.getLabelNew();
+ else return getContext().getString(R.string.no_icon_pack);
+ }
+
+
+ public String getCurrentIconPackPackageName()
+ {
+ for (IconPackProvider provider : iconPacks)
+ {
+ if (provider.isCurrentIconPack())
+ return provider.getPackageName();
+ }
+ return "";
+ }
+
+ private void init(Context context)
+ {
+ View.inflate(getContext(), R.layout.icon_pack_picker_view, this);
+ BouncyRecyclerView rc = findViewById(R.id.icon_pack_recyclerview);
+ rc.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false));
+ rc.setAdapter(adapter);
+
+ PackageManager pm = context.getPackageManager();
+ IconPackManager iconPackManager = new IconPackManager();
+ iconPackManager.setContext(context);
+
+ ArrayList iconPackArrayList = iconPackManager.getAvailableIconPacks(true);
+ Log.d("IconPack", "icon packs: " + iconPackArrayList.size());
+ for (IconPackManager.IconPack iconPack : iconPackArrayList)
+ {
+ try
+ {
+ IconPackProvider iconPackProvider = new IconPackProvider();
+ iconPackProvider.setPackageName(iconPack.packageName);
+ iconPackProvider.setLabelNew(iconPack.name);
+ iconPackProvider.setIcon(pm.getApplicationIcon(iconPackProvider.getPackageName()));
+ if (!iconPacks.contains(iconPackProvider))
+ {
+ iconPacks.add(iconPackProvider);
+ adapter.notifyItemInserted(iconPacks.indexOf(iconPackProvider));
+ }
+ Log.d("IconPack", "name: " + iconPackProvider.getPackageName());
+ }
+ catch (PackageManager.NameNotFoundException ignored){}
+
+ }
+
+
+
+ }
+
+
+ protected class IconPackPickerAdapter extends RecyclerView.Adapter
+ {
+
+ @NonNull
+ @Override
+ public IconPackViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
+ {
+ View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_icon_pack_picker, parent, false);
+ return new IconPackViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull IconPackViewHolder holder, int position)
+ {
+ holder.bind(iconPacks.get(position));
+ }
+
+ @Override
+ public int getItemCount()
+ {
+ return iconPacks.size();
+ }
+
+ private class IconPackViewHolder extends RecyclerView.ViewHolder
+ {
+
+ private final AppCompatTextView label;
+
+ private final AppCompatImageView icon;
+
+ private final CardView base;
+
+ public IconPackViewHolder(@NonNull View itemView)
+ {
+ super(itemView);
+ label = itemView.findViewById(R.id.icon_pack_label);
+ icon = itemView.findViewById(R.id.icon_pack_icon);
+ base = itemView.findViewById(R.id.icon_pack_base);
+ }
+
+ public void bind(IconPackProvider provider)
+ {
+ try
+ {
+ label.setText(provider.getLabelNew());
+ icon.setImageDrawable(provider.getIcon());
+ if (provider.isCurrentIconPack())
+ {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
+ {
+ base.setCardBackgroundColor(getContext().getResources().getColor(R.color.colorHalo, null));
+ }
+ else base.setCardBackgroundColor(getContext().getResources().getColor(R.color.colorHalo));
+ }
+ else
+ {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
+ {
+ base.setCardBackgroundColor(getContext().getResources().getColor(R.color.colorPrimaryDark, null));
+ }
+ else base.setCardBackgroundColor(getContext().getResources().getColor(R.color.colorPrimaryDark));
+ }
+
+ base.setOnClickListener(view ->
+ {
+ if (!provider.isCurrentIconPack()) //select as current icon pack
+ {
+ provider.setCurrentIconPack(true);
+ selectedIconPack = provider;
+ notifyItemChanged(iconPacks.indexOf(selectedIconPack));
+ for (IconPackProvider iconPack : iconPacks)
+ {
+ if (!iconPack.getPackageName().equals(selectedIconPack.getPackageName()) && iconPack.isCurrentIconPack())
+ {
+ iconPack.setCurrentIconPack(false);
+ notifyItemChanged(iconPacks.indexOf(iconPack));
+ }
+ }
+ }
+ else // clear icon pack
+ {
+ provider.setCurrentIconPack(false);
+ selectedIconPack = provider;
+ if (iconPacks.contains(selectedIconPack))
+ {
+ notifyItemChanged(iconPacks.indexOf(selectedIconPack));
+ }
+ }
+
+ if (listener != null)
+ listener.onIconPackClicked(selectedIconPack);
+ });
+ }
+ catch (NullPointerException | ActivityNotFoundException ignored){}
+ }
+ }
+ }
+
+ public abstract static class OnIconPackClickedListener
+ {
+ public void onIconPackClicked(IconPackProvider clickedIconPack)
+ {
+
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/factor/launcher/util/IconPackManager.java b/app/src/main/java/com/factor/launcher/util/IconPackManager.java
new file mode 100644
index 0000000..42be1eb
--- /dev/null
+++ b/app/src/main/java/com/factor/launcher/util/IconPackManager.java
@@ -0,0 +1,407 @@
+package com.factor.launcher.util;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.graphics.*;
+
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import androidx.annotation.Nullable;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.*;
+
+public class IconPackManager
+{
+ private Context mContext;
+
+ public void setContext (Context c)
+ {
+ mContext = c;
+ }
+
+ public class IconPack
+ {
+ public String packageName;
+ public String name;
+
+ private boolean mLoaded = false;
+ private final HashMap mPackagesDrawables = new HashMap<>();
+
+ private final List mBackImages = new ArrayList<>();
+ private Bitmap mMaskImage = null;
+ private Bitmap mFrontImage = null;
+ private float mFactor = 1.0f;
+ private int totalIcons;
+
+ Resources iconPackRes = null;
+
+ public void load()
+ {
+ // load appfilter.xml from the icon pack package
+ PackageManager pm = mContext.getPackageManager();
+ try
+ {
+ XmlPullParser xpp = null;
+
+ iconPackRes = pm.getResourcesForApplication(packageName);
+ int appFilterId = iconPackRes.getIdentifier("appfilter", "xml", packageName);
+ if (appFilterId > 0)
+ {
+ xpp = iconPackRes.getXml(appFilterId);
+ }
+ else
+ {
+ // no resource found, try to open it from assests folder
+ try
+ {
+ InputStream appFilterStream = iconPackRes.getAssets().open("appfilter.xml");
+
+ XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+ factory.setNamespaceAware(true);
+ xpp = factory.newPullParser();
+ xpp.setInput(appFilterStream, "utf-8");
+ }
+ catch (IOException e1)
+ {
+ //Ln.d("No appfilter.xml file");
+ }
+ }
+
+ if (xpp != null)
+ {
+ int eventType = xpp.getEventType();
+ while (eventType != XmlPullParser.END_DOCUMENT)
+ {
+ if(eventType == XmlPullParser.START_TAG)
+ {
+ if (xpp.getName().equals("iconback"))
+ {
+ for(int i=0; i 0 && xpp.getAttributeName(0).equals("img1"))
+ {
+ String drawableName = xpp.getAttributeValue(0);
+ mMaskImage = loadBitmap(drawableName);
+ }
+ }
+ else if (xpp.getName().equals("iconupon"))
+ {
+ if (xpp.getAttributeCount() > 0 && xpp.getAttributeName(0).equals("img1"))
+ {
+ String drawableName = xpp.getAttributeValue(0);
+ mFrontImage = loadBitmap(drawableName);
+ }
+ }
+ else if (xpp.getName().equals("scale"))
+ {
+ // mFactor
+ if (xpp.getAttributeCount() > 0 && xpp.getAttributeName(0).equals("factor"))
+ {
+ mFactor = Float.parseFloat(xpp.getAttributeValue(0));
+ }
+ }
+ else if (xpp.getName().equals("item"))
+ {
+ String componentName = null;
+ String drawableName = null;
+
+ for(int i=0; i 0)
+ {
+ Drawable bitmap = iconPackRes.getDrawable(id, null);
+ if (bitmap instanceof BitmapDrawable)
+ return ((BitmapDrawable)bitmap).getBitmap();
+ }
+ return null;
+ }
+
+ private Drawable loadDrawable(String drawableName)
+ {
+ int id = iconPackRes.getIdentifier(drawableName, "drawable", packageName);
+ if (id > 0)
+ {
+ return iconPackRes.getDrawable(id, null);
+ }
+ return null;
+ }
+
+ public Drawable getDrawableIconForPackage(String appPackageName, Drawable defaultDrawable) {
+ if (!mLoaded)
+ load();
+
+ PackageManager pm = mContext.getPackageManager();
+
+ Intent launchIntent = pm.getLaunchIntentForPackage(appPackageName);
+
+ String componentName = null;
+
+ if (launchIntent != null) componentName = pm.getLaunchIntentForPackage(appPackageName).getComponent().toString();
+
+ String drawable = mPackagesDrawables.get(componentName);
+
+ if (drawable != null)
+ {
+ return loadDrawable(drawable);
+ }
+
+ else
+ {
+ // try to get a resource with the component filename
+ if (componentName != null)
+ {
+ int start = componentName.indexOf("{")+1;
+ int end = componentName.indexOf("}", start);
+ if (end > start)
+ {
+ drawable = componentName.substring(start,end).toLowerCase(Locale.getDefault()).replace(".","_").replace("/", "_");
+ if (iconPackRes.getIdentifier(drawable, "drawable", packageName) > 0)
+ return loadDrawable(drawable);
+ }
+ }
+ }
+ return defaultDrawable;
+ }
+
+
+ @SuppressWarnings("unused")
+ public Bitmap getIconForPackage(String appPackageName, Bitmap defaultBitmap)
+ {
+ if (!mLoaded)
+ load();
+
+ PackageManager pm = mContext.getPackageManager();
+ Intent launchIntent = pm.getLaunchIntentForPackage(appPackageName);
+ String componentName = null;
+ if (launchIntent != null)
+ componentName = pm.getLaunchIntentForPackage(appPackageName).getComponent().toString();
+ String drawable = mPackagesDrawables.get(componentName);
+ if (drawable != null)
+ {
+ Bitmap BMP = loadBitmap(drawable);
+ if (BMP == null) {
+ return generateBitmap(defaultBitmap);
+ } else {
+ return BMP;
+ }
+ }
+ else
+ {
+ // try to get a resource with the component filename
+ if (componentName != null)
+ {
+ int start = componentName.indexOf("{")+1;
+ int end = componentName.indexOf("}", start);
+ if (end > start)
+ {
+ drawable = componentName.substring(start,end).toLowerCase(Locale.getDefault()).replace(".","_").replace("/", "_");
+ if (iconPackRes.getIdentifier(drawable, "drawable", packageName) > 0)
+ return loadBitmap(drawable);
+ }
+ }
+ }
+ return generateBitmap(defaultBitmap);
+ }
+
+ @SuppressWarnings("unused")
+ public int getTotalIcons() {
+ return totalIcons;
+ }
+
+
+ private Bitmap generateBitmap(Bitmap defaultBitmap)
+ {
+ // if no support images in the icon pack return the bitmap itself
+ if (mBackImages.size() == 0) return defaultBitmap;
+
+ Random r = new Random();
+ int backImageInd = r.nextInt(mBackImages.size());
+ Bitmap backImage = mBackImages.get(backImageInd);
+ int w = backImage.getWidth();
+ int h = backImage.getHeight();
+
+ // create a bitmap for the result
+ Bitmap result = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+ Canvas mCanvas = new Canvas(result);
+
+ // draw the background first
+ mCanvas.drawBitmap(backImage, 0, 0, null);
+
+ // create a mutable mask bitmap with the same mask
+ Bitmap scaledBitmap;
+ if (defaultBitmap.getWidth() > w || defaultBitmap.getHeight()> h) {
+ scaledBitmap = Bitmap.createScaledBitmap(defaultBitmap, (int)(w * mFactor), (int)(h * mFactor), false);
+ } else {
+ scaledBitmap = Bitmap.createBitmap(defaultBitmap);
+ }
+
+ Bitmap mutableMask = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+ Canvas maskCanvas = new Canvas(mutableMask);
+ if (mMaskImage != null)
+ {
+ // draw the scaled bitmap with mask
+ maskCanvas.drawBitmap(mMaskImage,0, 0, new Paint());
+
+ // paint the bitmap with mask into the result
+ Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
+ mCanvas.drawBitmap(scaledBitmap, ((float)(w - scaledBitmap.getWidth()))/2, ((float)(h - scaledBitmap.getHeight()))/2, null);
+ mCanvas.drawBitmap(mutableMask, 0, 0, paint);
+ paint.setXfermode(null);
+ }
+ else // draw the scaled bitmap with the back image as mask
+ {
+ maskCanvas.drawBitmap(backImage,0, 0, new Paint());
+
+ // paint the bitmap with mask into the result
+ Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
+ mCanvas.drawBitmap(scaledBitmap, ((float)(w - scaledBitmap.getWidth()))/2, ((float)(h - scaledBitmap.getHeight()))/2, null);
+ mCanvas.drawBitmap(mutableMask, 0, 0, paint);
+ paint.setXfermode(null);
+
+ }
+
+ // paint the front
+ if (mFrontImage != null)
+ {
+ mCanvas.drawBitmap(mFrontImage, 0, 0, null);
+ }
+
+ // store the bitmap in cache
+// BitmapCache.getInstance(mContext).putBitmap(key, result);
+
+ // return it
+ return result;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj)
+ {
+ if (obj instanceof IconPack)
+ {
+ return ((IconPack) obj).packageName.equals(this.packageName);
+ }
+ else return false;
+ }
+ }
+
+ private ArrayList iconPacks = null;
+
+ public ArrayList getAvailableIconPacks(boolean forceReload)
+ {
+ if (iconPacks == null || forceReload)
+ {
+ iconPacks = new ArrayList<>();
+
+ // find apps with intent-filter "com.gau.go.launcherex.theme" and return build the HashMap
+ PackageManager pm = mContext.getPackageManager();
+
+ List adwLauncherThemes = pm.queryIntentActivities(new Intent("org.adw.launcher.THEMES"), PackageManager.GET_META_DATA);
+ List goLauncherThemes = pm.queryIntentActivities(new Intent("com.gau.go.launcherex.theme"), PackageManager.GET_META_DATA);
+
+ // merge those lists
+ List resolveInfo = new ArrayList<>(adwLauncherThemes);
+ resolveInfo.addAll(goLauncherThemes);
+
+ for(ResolveInfo ri : resolveInfo)
+ {
+ IconPack ip = new IconPack();
+ ip.packageName = ri.activityInfo.packageName;
+
+ ApplicationInfo ai;
+ try
+ {
+ ai = pm.getApplicationInfo(ip.packageName, PackageManager.GET_META_DATA);
+ ip.name = mContext.getPackageManager().getApplicationLabel(ai).toString();
+ if (!iconPacks.contains(ip))
+ iconPacks.add(ip);
+ }
+ catch (PackageManager.NameNotFoundException e)
+ {
+ // shouldn't happen
+ e.printStackTrace();
+ }
+ }
+ }
+ return iconPacks;
+ }
+
+ public IconPack getIconPackWithName(String packageName)
+ {
+ PackageManager pm = mContext.getPackageManager();
+ IconPack targetPack = new IconPack();
+ targetPack.packageName = packageName;
+ if (iconPacks.contains(targetPack))
+ {
+ ApplicationInfo ai;
+ try
+ {
+ ai = pm.getApplicationInfo(targetPack.packageName, PackageManager.GET_META_DATA);
+ targetPack.name = mContext.getPackageManager().getApplicationLabel(ai).toString();
+ return targetPack;
+ }
+ catch (PackageManager.NameNotFoundException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/factor/launcher/view/FactorLargeView.java b/app/src/main/java/com/factor/launcher/view/FactorLargeView.java
index 65ce8c4..959710b 100644
--- a/app/src/main/java/com/factor/launcher/view/FactorLargeView.java
+++ b/app/src/main/java/com/factor/launcher/view/FactorLargeView.java
@@ -95,12 +95,14 @@ public FactorLargeView(Context context) {
init();
}
- public FactorLargeView(Context context, AttributeSet attrs) {
+ public FactorLargeView(Context context, AttributeSet attrs)
+ {
super(context, attrs);
init();
}
- public FactorLargeView(Context context, AttributeSet attrs, int defStyle) {
+ public FactorLargeView(Context context, AttributeSet attrs, int defStyle)
+ {
super(context, attrs, defStyle);
init();
}
@@ -477,7 +479,7 @@ public ShortcutsAdapter(List shortcuts, AppSettings appSettings)
@Override
public ShortcutViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
{
- View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.shortcut_item, parent, false);
+ View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_shortcut_holder, parent, false);
//resize to fit screen
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
diff --git a/app/src/main/java/com/factor/launcher/view_models/AppListManager.java b/app/src/main/java/com/factor/launcher/view_models/AppListManager.java
index a4bca9c..a33ed67 100644
--- a/app/src/main/java/com/factor/launcher/view_models/AppListManager.java
+++ b/app/src/main/java/com/factor/launcher/view_models/AppListManager.java
@@ -23,6 +23,7 @@
import com.factor.launcher.models.AppShortcut;
import com.factor.launcher.models.UserApp;
import com.factor.launcher.util.ChineseHelper;
+import com.factor.launcher.util.IconPackManager;
import java.text.Collator;
import java.util.*;
@@ -63,6 +64,8 @@ public class AppListManager extends ViewModel
public final AppSettings settings;
+ private IconPackManager.IconPack iconPack = null;
+
//constructor
public AppListManager(HomeScreenFragment fragment,
ViewGroup background,
@@ -74,11 +77,18 @@ public AppListManager(HomeScreenFragment fragment,
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1)
this.shortcutQuery = new LauncherApps.ShortcutQuery();
+ if (fragment.getContext() != null)
+ {
+ iconPack = settings.getIconPackProvider(fragment.getContext());
+ }
packageManager = fragment.requireActivity().getPackageManager();
launcherApps = (LauncherApps) fragment.requireActivity().getSystemService(Context.LAUNCHER_APPS_SERVICE);
adapter = new AppListAdapter(this, userApps, displayHidden, fragment.getActivity(), settings);
- factorManager = new FactorManager(fragment.requireActivity(), background, this, packageManager, launcherApps, shortcutQuery, isLiveWallpaper);
+
+
+
+ factorManager = new FactorManager(fragment.requireActivity(), background, this, packageManager, launcherApps, shortcutQuery, iconPack, isLiveWallpaper);
daoReference = AppListDatabase.Companion.getInstance(fragment.requireActivity().getApplicationContext()).appListDao();
factorSharedPreferences = fragment.requireActivity().getSharedPreferences(PACKAGE_NAME + "_FIRST_LAUNCH", Context.MODE_PRIVATE);
@@ -91,6 +101,13 @@ public AppListManager(HomeScreenFragment fragment,
loadApps(factorSharedPreferences.getBoolean("saved", false));
this.recentAppsHost = new RecentAppsHost(this);
+
+
+ }
+
+ public IconPackManager.IconPack getIconPack()
+ {
+ return this.iconPack;
}
//compare app label (new)
@@ -161,63 +178,71 @@ private void loadApps(Boolean isSaved)
new Thread(() ->
{
- Intent i = new Intent(Intent.ACTION_MAIN, null);
- i.addCategory(Intent.CATEGORY_LAUNCHER);
- List availableApps = packageManager.queryIntentActivities(i, 0);
- for (ResolveInfo r : availableApps)
+ Intent i = new Intent(Intent.ACTION_MAIN, null);
+ i.addCategory(Intent.CATEGORY_LAUNCHER);
+ List availableApps = packageManager.queryIntentActivities(i, 0);
+
+ for (ResolveInfo r : availableApps)
+ {
+ try
{
- try
+ if (!r.activityInfo.packageName.equals(PACKAGE_NAME))
{
- if (!r.activityInfo.packageName.equals(PACKAGE_NAME))
+ UserApp app = daoReference.findByPackage(r.activityInfo.packageName);
+ if (app == null) //package name does not exist in database
{
- UserApp app = daoReference.findByPackage(r.activityInfo.packageName);
- if (app == null) //package name does not exist in database
- {
- app = new UserApp();
- app.setLabelOld((String) r.loadLabel(packageManager));
- app.setLabelNew(app.getLabelOld());
- app.setPackageName(r.activityInfo.packageName);
- app.resetNotifications();
+ app = new UserApp();
+ app.setLabelOld((String) r.loadLabel(packageManager));
+ app.setLabelNew(app.getLabelOld());
+ app.setPackageName(r.activityInfo.packageName);
+ app.resetNotifications();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1)
- app.setShortCuts(getShortcutsFromApp(app));
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1)
+ app.setShortCuts(getShortcutsFromApp(app));
- app.setIcon(r.activityInfo.loadIcon(packageManager));
- userApps.add(app);
- daoReference.insert(app);
- }
- else {
- if (doesPackageExist(app) && packageManager.getApplicationInfo(app.getPackageName(), 0).enabled)
+
+ app.setIcon(r.activityInfo.loadIcon(packageManager));
+
+ userApps.add(app);
+ daoReference.insert(app);
+ }
+ else
+ {
+ if (doesPackageExist(app) && packageManager.getApplicationInfo(app.getPackageName(), 0).enabled)
+ {
+ if (iconPack != null)
{
+ app.setIcon(iconPack.getDrawableIconForPackage(app.getPackageName(), r.activityInfo.loadIcon(packageManager)));
+ }
+ else
app.setIcon(r.activityInfo.loadIcon(packageManager));
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1)
- app.setShortCuts(getShortcutsFromApp(app));
-
- userApps.add(app);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1)
+ app.setShortCuts(getShortcutsFromApp(app));
- app.setPinned(factorManager.isAppPinned(app));
+ userApps.add(app);
- try
- {
- Collections.sort(userApps, first_letter);
- }
- catch (ConcurrentModificationException ignored){}
+ app.setPinned(factorManager.isAppPinned(app));
+ try
+ {
+ Collections.sort(userApps, first_letter);
}
- else
- daoReference.delete(app);
- }
+ catch (ConcurrentModificationException ignored){}
+ }
+ else
+ daoReference.delete(app);
}
}
- catch (NullPointerException | PackageManager.NameNotFoundException ex)
- {
- ex.printStackTrace();
- }
-
}
- if (adapter!=null && getActivity() != null)
- getActivity().runOnUiThread(adapter::notifyDataSetChanged);
+ catch (NullPointerException | PackageManager.NameNotFoundException ex)
+ {
+ ex.printStackTrace();
+ }
+
+ }
+ if (adapter!=null && getActivity() != null)
+ getActivity().runOnUiThread(adapter::notifyDataSetChanged);
}).start();
}
diff --git a/app/src/main/java/com/factor/launcher/view_models/FactorManager.java b/app/src/main/java/com/factor/launcher/view_models/FactorManager.java
index d2dbc16..ae173a8 100644
--- a/app/src/main/java/com/factor/launcher/view_models/FactorManager.java
+++ b/app/src/main/java/com/factor/launcher/view_models/FactorManager.java
@@ -21,6 +21,7 @@
import com.factor.launcher.models.Factor;
import com.factor.launcher.models.UserApp;
import com.factor.launcher.models.Payload;
+import com.factor.launcher.util.IconPackManager;
import java.util.ArrayList;
import java.util.Collections;
@@ -47,6 +48,8 @@ public class FactorManager extends ViewModel
private final AppListManager appListManager;
+ private final IconPackManager.IconPack iconPack;
+
//constructor
public FactorManager(Activity activity,
ViewGroup background,
@@ -54,6 +57,7 @@ public FactorManager(Activity activity,
PackageManager pm,
LauncherApps launcherApps,
LauncherApps.ShortcutQuery shortcutQuery,
+ IconPackManager.IconPack iconPack,
Boolean isLiveWallpaper)
{
this.packageManager = pm;
@@ -61,6 +65,7 @@ public FactorManager(Activity activity,
this.shortcutQuery = shortcutQuery;
this.launcherApps = launcherApps;
this.appSettings = AppSettingsManager.getInstance(activity.getApplication()).getAppSettings();
+ this.iconPack = iconPack;
adapter = new FactorsAdapter(this, appSettings, activity, isLiveWallpaper, userFactors, background);
daoReference = FactorsDatabase.Companion.getInstance(activity.getApplicationContext()).factorsDao();
@@ -85,7 +90,15 @@ private void loadFactors()
try {
if (packageManager.getApplicationInfo(f.getPackageName(), 0).enabled)
{
- Drawable icon = packageManager.getApplicationIcon(f.getPackageName());
+ Drawable icon;
+
+ if (iconPack != null)
+ {
+ icon = iconPack.getDrawableIconForPackage(f.getPackageName(), packageManager.getApplicationIcon(f.getPackageName()));
+ }
+ else
+ icon = appListManager.packageManager.getApplicationIcon(f.getPackageName());
+
f.setIcon(icon);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1)
@@ -258,8 +271,19 @@ public void loadIcon(Factor factor)
{
try
{
+ Drawable icon;
if (packageManager.getApplicationInfo(factor.getPackageName(), 0).enabled)
- factor.setIcon(packageManager.getApplicationIcon(factor.getPackageName()));
+ {
+ if (iconPack != null)
+ {
+ icon = iconPack.getDrawableIconForPackage(factor.getPackageName(), packageManager.getApplicationIcon(factor.getPackageName()));
+ }
+ else
+ icon = appListManager.packageManager.getApplicationIcon(factor.getPackageName());
+
+ factor.setIcon(icon);
+
+ }
}
catch (Exception e)
{
diff --git a/app/src/main/res/layout/fragment_home_screen.xml b/app/src/main/res/layout/fragment_home_screen.xml
index e37db06..67f2dae 100644
--- a/app/src/main/res/layout/fragment_home_screen.xml
+++ b/app/src/main/res/layout/fragment_home_screen.xml
@@ -242,7 +242,6 @@
-
+
+
+
+
+
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toStartOf="@+id/blur_toggle"
+ android:layout_height="0dp"
+ android:layout_width="0dp"/>
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toStartOf="@+id/dark_text_toggle"/>
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toStartOf="@+id/dark_icon_toggle"/>
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toStartOf="@+id/icon_shadow_toggle"/>
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_icon_pack_picker.xml b/app/src/main/res/layout/item_icon_pack_picker.xml
new file mode 100644
index 0000000..4bd6a85
--- /dev/null
+++ b/app/src/main/res/layout/item_icon_pack_picker.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/recent_apps_item.xml b/app/src/main/res/layout/item_recent_apps.xml
similarity index 100%
rename from app/src/main/res/layout/recent_apps_item.xml
rename to app/src/main/res/layout/item_recent_apps.xml
diff --git a/app/src/main/res/layout/shortcut_item.xml b/app/src/main/res/layout/item_shortcut_holder.xml
similarity index 100%
rename from app/src/main/res/layout/shortcut_item.xml
rename to app/src/main/res/layout/item_shortcut_holder.xml
diff --git a/app/src/main/res/values/attrs_factor_small_view.xml b/app/src/main/res/values/attrs_factor_small_view.xml
deleted file mode 100644
index 10195d9..0000000
--- a/app/src/main/res/values/attrs_factor_small_view.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index ad42d2a..64af678 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -5,4 +5,8 @@
#0E7ED6
#B30E7ED6
#00000000
+ #FF29B6F6
+ #FF039BE5
+ #FFBDBDBD
+ #FF757575
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 134df15..60033bf 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -74,5 +74,5 @@
home screen
recently used apps
Blur wallpaper instead of tiles on the home screen (for better performance)
-
+ No Icon Pack
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 691b690..b55f2f8 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -35,7 +35,4 @@
-
-
-
\ No newline at end of file