package com.quaap.launchtime.ui; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.app.WallpaperColors; import android.app.WallpaperInfo; import android.app.WallpaperManager; import android.content.Context; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Build; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.ViewPropertyAnimator; import android.view.animation.AccelerateInterpolator; import android.view.animation.CycleInterpolator; import android.view.animation.DecelerateInterpolator; import android.widget.LinearLayout; import android.widget.TextView; import com.quaap.launchtime.R; import java.util.HashMap; import java.util.Map; import java.util.WeakHashMap; /** * Copyright (C) 2017 Tom Kliethermes * * This file is part of LaunchTime and is 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. */ public class Style { private int cattabTextColor; private int cattabTextColorInvert; private int cattabBackground; private int cattabSelectedBackground; private int cattabSelectedText; private int dragoverBackground; private int textColor; private final int backgroundDefault = Color.TRANSPARENT; private int wallpaperColor = Color.TRANSPARENT; private int calculatedWallpaperColor = Color.TRANSPARENT; private int iconTint = Color.TRANSPARENT; private boolean leftHandCategories; private float categoryTabFontSize = 16; private int categoryTabPaddingHeight = 25; private int cattabBackgroundHighContrast; private int cattabSelectedBackgroundHighContrast; private boolean centeredIcons; private int launcherIconSize = 55; private int launcherSize = 80; private int launcherFontSize = 12; private int mAnimationDuration; private final SharedPreferences mAppPreferences; private final Context mContext; public Style(Context context, SharedPreferences appPreferences) { mContext = context; mAppPreferences = appPreferences; readPrefs(); } public int getWallpaperColor() { return wallpaperColor; } public enum CategoryTabStyle {Default, Normal, Selected, DragHover, Tiny, Hidden, None} public void styleCategoryStyle(final TextView categoryTab, CategoryTabStyle catstyle, boolean highContrast) { LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)categoryTab.getLayoutParams(); boolean isOnLeft = isLeftHandCategories(); int padRight = 2; int padLeft = 6; if (isOnLeft) { padRight = 6; padLeft = 2; } lp.leftMargin = 2; lp.rightMargin = 2; Rect pad = new Rect(); int bgcolor = 0; categoryTab.setBackground(null); categoryTab.setShadowLayer(0, 0, 0, 0); switch (catstyle) { case Hidden: bgcolor = cattabBackground; if (isOnLeft) { lp.rightMargin = 36; } else { lp.leftMargin = 36; } case Tiny: categoryTab.setTextColor(cattabTextColor); if (bgcolor==0) { bgcolor = highContrast ? cattabBackgroundHighContrast : cattabBackground; if (isOnLeft) { lp.rightMargin = 22; } else { lp.leftMargin = 22; } } pad.set(padLeft, categoryTabPaddingHeight/5, padRight, categoryTabPaddingHeight/5); categoryTab.setTextSize(categoryTabFontSize-3); break; case DragHover: categoryTab.setTextColor(cattabTextColor); bgcolor = dragoverBackground; pad.set(padLeft, categoryTabPaddingHeight, padRight, categoryTabPaddingHeight); categoryTab.setTextSize(categoryTabFontSize + 1); categoryTab.setTextSize(categoryTabFontSize); if (isOnLeft) { lp.rightMargin = 6; } else { lp.leftMargin = 6; } break; case Selected: categoryTab.setTextColor(cattabSelectedText); bgcolor = highContrast?cattabSelectedBackgroundHighContrast:cattabSelectedBackground; pad.set(padLeft, categoryTabPaddingHeight+2, padRight, categoryTabPaddingHeight+2); categoryTab.setTextSize(categoryTabFontSize + 1); categoryTab.setShadowLayer(8, 4, 4, cattabTextColorInvert); categoryTab.clearAnimation(); if (mAnimationDuration >0) { categoryTab.animate().scaleX(1.3f).scaleY(1.3f) .setInterpolator(new CycleInterpolator(1)) .setDuration(mAnimationDuration) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { categoryTab.setScaleX(1); categoryTab.setScaleY(1); } @Override public void onAnimationCancel(Animator animation) { categoryTab.setScaleX(1); categoryTab.setScaleY(1); } }).start(); } else { categoryTab.setScaleX(1); categoryTab.setScaleY(1); } lp.leftMargin = 1; lp.rightMargin = 1; break; case Normal: default: categoryTab.setTextColor(cattabTextColor); bgcolor = highContrast?cattabBackgroundHighContrast:cattabBackground; pad.set(padLeft, categoryTabPaddingHeight, padRight, categoryTabPaddingHeight); categoryTab.setTextSize(categoryTabFontSize); if (isOnLeft) { lp.rightMargin = 22; } else { lp.leftMargin = 22; } } categoryTab.setBackgroundColor(bgcolor); if (isRoundedTabs()) { categoryTab.setBackground(getBgDrawableFor(categoryTab,catstyle,highContrast)); } categoryTab.setPadding(pad.left, pad.top, pad.right, pad.bottom); if (highContrast) { if (categoryTab.getAlpha()<.89f) { categoryTab.setAlpha(.9f); } lp.topMargin=2; lp.bottomMargin=2; } else { lp.topMargin=3; lp.bottomMargin=3; } categoryTab.setLayoutParams(lp); } public int getLauncherIconSize() { return launcherIconSize; } public int getLauncherSize() { return launcherSize; } public int getLauncherFontSize() { return launcherFontSize; } public void readPrefs() { //Checks application preferences and adjust accordingly leftHandCategories = mAppPreferences.getString(mContext.getString(R.string.pref_key_categories_loc), "right").equals("left"); centeredIcons = mAppPreferences.getBoolean(mContext.getString(R.string.pref_key_center_sheet), true); float density = mContext.getResources().getDisplayMetrics().density / 2.0f; if (density<.75f) density = .75f; if (density>1.5f) density = 1.5f; int tabsizePref = Integer.parseInt(mAppPreferences.getString(mContext.getString(R.string.pref_key_tabsize), "1")); switch (tabsizePref) { case 0: //small categoryTabPaddingHeight = (int)(16 * density); categoryTabFontSize = 14; break; case 1: //medium categoryTabPaddingHeight = (int)(20 * density); categoryTabFontSize = 16; break; case 2: //large categoryTabPaddingHeight = (int)(25 * density); categoryTabFontSize = 18; break; case 3: //x-large categoryTabPaddingHeight = (int)(25 * density); categoryTabFontSize = 20; break; } mAnimationDuration = Integer.parseInt(mAppPreferences.getString(mContext.getString(R.string.pref_key_animate_duration), "150")); float iconsize = mContext.getResources().getDimension(R.dimen.icon_width); float iconfontsize = mContext.getResources().getDimension(R.dimen.launcher_fontsize); int iconsizePref = Integer.parseInt(mAppPreferences.getString(mContext.getString(R.string.pref_key_iconsize), "1")); switch (iconsizePref) { case 0: //small launcherIconSize = (int)(iconsize*.74); launcherFontSize = (int)(iconfontsize*.87); launcherSize = (int)(launcherIconSize*1.3); break; case 1: //medium launcherIconSize = (int)(iconsize*.95); launcherFontSize = (int)iconfontsize; launcherSize = (int)(launcherIconSize*1.32); break; case 2: //large launcherIconSize = (int)(iconsize*1.3); launcherFontSize = (int)(iconfontsize*1.3); launcherSize = (int)(launcherIconSize*1.33); break; case 3: //x-large launcherIconSize = (int)(iconsize*1.8); launcherFontSize = (int)(iconfontsize*1.7); launcherSize = (int)(launcherIconSize*1.3); break; } //Log.d("style", "launcherFontSize = " + launcherFontSize); cattabBackground = mAppPreferences.getInt(mContext.getString(R.string.pref_key_cattab_background), getResColor(R.color.cattab_background)); cattabSelectedBackground = mAppPreferences.getInt(mContext.getString(R.string.pref_key_cattabselected_background), getResColor(R.color.cattabselected_background)); cattabSelectedText = mAppPreferences.getInt(mContext.getString(R.string.pref_key_cattabselected_text), getResColor(R.color.cattabselected_text)); dragoverBackground = mAppPreferences.getInt(mContext.getString(R.string.pref_key_dragover_background), getResColor(R.color.dragover_background)); cattabTextColor = mAppPreferences.getInt(mContext.getString(R.string.pref_key_cattabtextcolor), getResColor(R.color.textcolor)); cattabTextColorInvert = mAppPreferences.getInt(mContext.getString(R.string.pref_key_cattabtextcolorinv), getResColor(R.color.textcolorinv)); textColor = mAppPreferences.getInt(mContext.getString(R.string.pref_key_textcolor), getResColor(R.color.textcolor)); wallpaperColor = mAppPreferences.getInt(mContext.getString(R.string.pref_key_wallpapercolor), getResColor(R.color.wallpaper_color)); iconTint = mAppPreferences.getInt(mContext.getString(R.string.pref_key_icon_tint), Color.TRANSPARENT); cattabBackgroundHighContrast = cattabBackground; int alpha; // = Color.alpha(cattabBackground); //if (alpha<80) alpha=80; // cattabBackgroundHighContrast = Color.argb(alpha, Color.red(cattabBackground), Color.green(cattabBackground), Color.blue(cattabBackground)); alpha = Color.alpha(cattabBackground); if (alpha<80) { alpha=80; cattabBackgroundHighContrast = Color.argb(alpha, Color.red(cattabBackground)*5/6, Color.green(cattabBackground)*5/6, Color.blue(cattabBackground)*5/6); } else { cattabBackgroundHighContrast = cattabBackground; } alpha = Color.alpha(cattabSelectedBackground); if (alpha<80) { alpha=80; cattabSelectedBackgroundHighContrast = Color.argb(alpha, Color.red(cattabSelectedBackground)*5/6, Color.green(cattabSelectedBackground)*5/6, Color.blue(cattabSelectedBackground)*5/6); } else { cattabSelectedBackgroundHighContrast = cattabSelectedBackground; } bgDrawables.clear(); calculateWallpaperColor(); } public void calculateWallpaperColor() { try { WallpaperManager wm = (WallpaperManager) mContext.getSystemService(Context.WALLPAPER_SERVICE); mWallpaper = null; if (wm != null) { WallpaperInfo wi = wm.getWallpaperInfo(); if (wi != null) { mWallpaper = wi.loadThumbnail(mContext.getPackageManager()); } if (mWallpaper == null) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1 || mContext.checkSelfPermission("android.permission.READ_EXTERNAL_STORAGE") == PackageManager.PERMISSION_GRANTED) { mWallpaper = wm.getDrawable(); } else { WallpaperColors wpc = wm.getWallpaperColors(WallpaperManager.FLAG_SYSTEM); if (wpc != null) { mWallpaper = new ColorDrawable(wpc.getPrimaryColor().toArgb()); } } } if (mWallpaper == null) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { mWallpaper = wm.getBuiltInDrawable(); } } } if (mWallpaper != null) { Drawable wallp = mWallpaper.mutate(); wallp.setColorFilter(wallpaperColor, PorterDuff.Mode.SRC_ATOP); //wallp = wallp.mutate(); Bitmap bm = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(); //c.drawColor(Color.TRANSPARENT, PorterDuff.Mode.SRC); c.setBitmap(bm); wallp.setBounds(0, 0, bm.getWidth(), bm.getHeight()); wallp.draw(c); calculatedWallpaperColor = bm.getPixel(0, 0); } else { calculatedWallpaperColor = wallpaperColor; } } catch (Exception e) { if (mWallpaper==null) { mWallpaper = new ColorDrawable(wallpaperColor); } if (calculatedWallpaperColor == Color.TRANSPARENT) { calculatedWallpaperColor = wallpaperColor; } } } public int getCalculatedWallpaperColor() { return calculatedWallpaperColor; } public Drawable getWallpaperDrawable() { return mWallpaper; } private Drawable mWallpaper; private final Map<String,Drawable> bgDrawables = new WeakHashMap<>(); public Drawable getBgDrawableFor(View view, CategoryTabStyle catstyle, boolean isHighContrast) { int color = -1; switch (catstyle) { case Selected: color = isHighContrast ? cattabSelectedBackgroundHighContrast : cattabSelectedBackground; break; case DragHover: color = dragoverBackground; break; case Hidden: color = cattabBackground; break; case Tiny: case Normal: case Default: color = isHighContrast ? cattabBackgroundHighContrast : cattabBackground; break; case None: default: } return getBgDrawableFor(view, color); } public Drawable getBgDrawableFor(View view, int color) { String key = view.toString() + color; Drawable newbg = bgDrawables.get(key); if (newbg==null) { Drawable base = mContext.getResources().getDrawable(R.drawable.rounded); if (base.getConstantState()==null) { newbg = base.mutate(); //shouldn't ever get here Log.d("Style", "base drawable had a null getConstantState"); } else { newbg = base.getConstantState().newDrawable().mutate(); } bgDrawables.put(key, newbg); } if (color!=-1) { newbg.setColorFilter(color, PorterDuff.Mode.MULTIPLY); } return newbg; } public boolean isRoundedTabs() { return mAppPreferences.getBoolean(mContext.getString(R.string.pref_key_rounded_tabs), true); } public int getMaxWCells() { int iconsizePref = Integer.parseInt(mAppPreferences.getString(mContext.getString(R.string.pref_key_iconsize), "1")); return 6-iconsizePref; } // public float getWidgetWidth(float minPixWidth) { // // return minPixWidth * getRatio(); // } // private float getRatio() { // float iconsize = mContext.getResources().getDimension(R.dimen.icon_width); // // return iconsize / launcherIconSize; // } private int getResColor(int res) { if (Build.VERSION.SDK_INT >= 23) { return mContext.getColor(res); } else { return mContext.getResources().getColor(res); } } public int getCattabTextColor() { return cattabTextColor; } public int getCattabTextColorInvert() { return cattabTextColorInvert; } public int getCattabBackground() { return cattabBackground; } public int getCattabSelectedBackground() { return cattabSelectedBackground; } public int getCattabSelectedText() { return cattabSelectedText; } public int getDragoverBackground() { return dragoverBackground; } public int getTextColor() { return textColor; } public int getBackgroundDefault() { return backgroundDefault; } public boolean isLeftHandCategories() { return leftHandCategories; } public boolean isCenteredIcons() { return centeredIcons; } public float getCategoryTabFontSize() { return categoryTabFontSize; } public int getCategoryTabPaddingHeight() { return categoryTabPaddingHeight; } public int getIconTint() { return iconTint; } public void animateUpShow(View view) { animateShow(view,AnimateDirection.Down); } public void animateDownHide(View view) { animateHide(view, AnimateDirection.Down,false, true); } public enum AnimateDirection {Left, Up, Right, Down} private final Map<View,Long> aniHideStarted = new HashMap<>(); public void animateHide(final View view, final AnimateDirection towards) { animateHide(view,towards, false, true); } public void animateHide(final View view, final AnimateDirection towards, final boolean andBack, final boolean bounce) { // Log.d(TAG, "animateHide " + view); if (mAnimationDuration==0) { view.clearAnimation(); if (andBack) { ensureVisibleNoAni(view); } else { view.setVisibility(View.GONE); } return; } long now = System.currentTimeMillis(); float fac = andBack?2.5f:1; Long then = aniHideStarted.get(view); if (then!=null && now - then < mAnimationDuration*fac) return; aniHideStarted.put(view,now); ViewPropertyAnimator animate = view.animate() .setDuration(mAnimationDuration) .setInterpolator(new AccelerateInterpolator()) .alpha(0) .scaleY(.6f) .scaleX(.6f) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); if (andBack) { animateShow(view, towards, !bounce); } else { view.setVisibility(View.GONE); } } @Override public void onAnimationCancel(Animator animation) { super.onAnimationCancel(animation); if (andBack) { ensureVisibleNoAni(view); } else { view.setVisibility(View.GONE); } } }); switch(towards) { case Down: animate.translationY(view.getHeight()); break; case Up: animate.translationY(-view.getHeight()); break; case Right: animate.translationX(view.getWidth()); break; case Left: animate.translationX(-view.getHeight()); break; } animate.setStartDelay(0).start(); } private void ensureVisibleNoAni(View view) { view.setAlpha(1); view.setScaleX(1); view.setScaleY(1); view.setTranslationX(0); view.setTranslationY(0); view.setVisibility(View.VISIBLE); } public void animateShow(final View view, AnimateDirection from) { animateShow(view, from,false); } private void animateShow(final View view, AnimateDirection from, boolean reverse) { if (mAnimationDuration==0) { view.clearAnimation(); ensureVisibleNoAni(view); //Log.d(TAG, "animateShow " + view); return; } if (reverse) { switch(from) { case Down: view.setTranslationY(-view.getHeight()); break; case Up: view.setTranslationY(view.getHeight()); break; case Right: view.setTranslationX(-view.getWidth()); break; case Left: view.setTranslationX(view.getWidth()); break; } } view.setVisibility(View.VISIBLE); ViewPropertyAnimator animate = view.animate() .setDuration(mAnimationDuration) .setInterpolator(new DecelerateInterpolator()) .alpha(1) .scaleY(1) .scaleX(1) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); ensureVisibleNoAni(view); } @Override public void onAnimationCancel(Animator animation) { super.onAnimationCancel(animation); ensureVisibleNoAni(view); } }); switch(from) { case Down: case Up: animate.translationY(0); break; case Right: case Left: animate.translationX(0); break; } } public void animateChangingSize(final View view, int startsize, int newsize, final Runnable before, final Runnable after) { final ViewGroup.LayoutParams lp = view.getLayoutParams(); lp.height = startsize; view.setLayoutParams(lp); ValueAnimator o = ValueAnimator.ofInt(startsize,newsize); o.setDuration(mAnimationDuration); o.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { lp.height = (int)valueAnimator.getAnimatedValue(); view.setLayoutParams(lp); } }); o.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { if (before!=null) before.run(); } @Override public void onAnimationEnd(Animator animation) { lp.height = ViewGroup.LayoutParams.WRAP_CONTENT; view.setLayoutParams(lp); if (after!=null) after.run(); } }); o.start(); } }