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