From 550e88b1e62228124f22b2d70ce3bf45fe9a1314 Mon Sep 17 00:00:00 2001 From: d34d Date: Mon, 29 Aug 2016 15:41:02 -0700 Subject: Fall cleaning * Change package name to org.cyanogenmod.theme.chooser2 to avoid theme collisions with old OSS chooser * Change parent theme to Theme.Material.Light * Change minSdkVersion to 21 since we are going material * Add selectors for bottom action buttons (app themer, shop themes) * Add selector, using app themer color, for app themer list view * Add selector for actions in theme cards * Bring back OSS app icon * Reduce log spam in ThemedTypefaceHelper * Localize "new" tag using a TextView instead of an image * Other random stuff Change-Id: I73ef0b9c9370284e29ee00add87273cf54c83e0e --- src/org/cyanogenmod/theme/chooser/AppReceiver.java | 73 - .../cyanogenmod/theme/chooser/BootReceiver.java | 56 - .../cyanogenmod/theme/chooser/ChooserActivity.java | 1191 -------- .../theme/chooser/ComponentCardView.java | 233 -- .../theme/chooser/ComponentSelector.java | 934 ------ .../theme/chooser/IconTransitionDrawable.java | 171 -- .../cyanogenmod/theme/chooser/MyThemeFragment.java | 707 ----- .../chooser/NewFragmentStatePagerAdapter.java | 333 --- .../chooser/NotificationHijackingService.java | 88 - .../cyanogenmod/theme/chooser/PagerContainer.java | 219 -- .../cyanogenmod/theme/chooser/ThemeFragment.java | 3059 -------------------- .../theme/chooser/WallpaperCardView.java | 160 - .../cyanogenmod/theme/chooser2/AppReceiver.java | 71 + .../cyanogenmod/theme/chooser2/BootReceiver.java | 56 + .../theme/chooser2/ChooserActivity.java | 1185 ++++++++ .../theme/chooser2/ComponentCardView.java | 232 ++ .../theme/chooser2/ComponentSelector.java | 934 ++++++ .../theme/chooser2/IconTransitionDrawable.java | 171 ++ .../theme/chooser2/MyThemeFragment.java | 707 +++++ .../chooser2/NewFragmentStatePagerAdapter.java | 333 +++ .../chooser2/NotificationHijackingService.java | 88 + .../cyanogenmod/theme/chooser2/PagerContainer.java | 219 ++ .../cyanogenmod/theme/chooser2/ThemeFragment.java | 3059 ++++++++++++++++++++ .../theme/chooser2/WallpaperCardView.java | 160 + .../theme/perapptheming/PerAppThemeListLayout.java | 3 +- .../theme/perapptheming/PerAppThemeListView.java | 2 +- .../theme/perapptheming/PerAppThemingWindow.java | 9 +- .../cyanogenmod/theme/util/NotificationHelper.java | 5 +- .../theme/util/ThemedTypefaceHelper.java | 4 +- src/org/cyanogenmod/theme/util/Utils.java | 3 +- .../theme/widget/ConfirmCancelOverlay.java | 2 +- src/org/cyanogenmod/theme/widget/LatoTextView.java | 2 +- .../cyanogenmod/theme/widget/ThemeTagLayout.java | 2 +- 33 files changed, 7231 insertions(+), 7240 deletions(-) delete mode 100644 src/org/cyanogenmod/theme/chooser/AppReceiver.java delete mode 100644 src/org/cyanogenmod/theme/chooser/BootReceiver.java delete mode 100644 src/org/cyanogenmod/theme/chooser/ChooserActivity.java delete mode 100644 src/org/cyanogenmod/theme/chooser/ComponentCardView.java delete mode 100644 src/org/cyanogenmod/theme/chooser/ComponentSelector.java delete mode 100644 src/org/cyanogenmod/theme/chooser/IconTransitionDrawable.java delete mode 100644 src/org/cyanogenmod/theme/chooser/MyThemeFragment.java delete mode 100644 src/org/cyanogenmod/theme/chooser/NewFragmentStatePagerAdapter.java delete mode 100644 src/org/cyanogenmod/theme/chooser/NotificationHijackingService.java delete mode 100644 src/org/cyanogenmod/theme/chooser/PagerContainer.java delete mode 100644 src/org/cyanogenmod/theme/chooser/ThemeFragment.java delete mode 100644 src/org/cyanogenmod/theme/chooser/WallpaperCardView.java create mode 100644 src/org/cyanogenmod/theme/chooser2/AppReceiver.java create mode 100644 src/org/cyanogenmod/theme/chooser2/BootReceiver.java create mode 100644 src/org/cyanogenmod/theme/chooser2/ChooserActivity.java create mode 100644 src/org/cyanogenmod/theme/chooser2/ComponentCardView.java create mode 100644 src/org/cyanogenmod/theme/chooser2/ComponentSelector.java create mode 100644 src/org/cyanogenmod/theme/chooser2/IconTransitionDrawable.java create mode 100644 src/org/cyanogenmod/theme/chooser2/MyThemeFragment.java create mode 100644 src/org/cyanogenmod/theme/chooser2/NewFragmentStatePagerAdapter.java create mode 100644 src/org/cyanogenmod/theme/chooser2/NotificationHijackingService.java create mode 100644 src/org/cyanogenmod/theme/chooser2/PagerContainer.java create mode 100644 src/org/cyanogenmod/theme/chooser2/ThemeFragment.java create mode 100644 src/org/cyanogenmod/theme/chooser2/WallpaperCardView.java (limited to 'src/org') diff --git a/src/org/cyanogenmod/theme/chooser/AppReceiver.java b/src/org/cyanogenmod/theme/chooser/AppReceiver.java deleted file mode 100644 index 0c3037e..0000000 --- a/src/org/cyanogenmod/theme/chooser/AppReceiver.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2016 Cyanogen, Inc. - * Copyright (C) 2016 The CyanogenMod Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.cyanogenmod.theme.chooser; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager.NameNotFoundException; -import android.net.Uri; -import android.text.TextUtils; - -import org.cyanogenmod.theme.util.NotificationHelper; -import org.cyanogenmod.theme.util.PreferenceUtils; -import org.cyanogenmod.theme.util.Utils; - -import cyanogenmod.providers.ThemesContract; - -public class AppReceiver extends BroadcastReceiver { - - @Override - public void onReceive(Context context, Intent intent) { - Uri uri = intent.getData(); - String pkgName = uri != null ? uri.getSchemeSpecificPart() : null; - String action = intent.getAction(); - - if (cyanogenmod.content.Intent.ACTION_THEME_INSTALLED.equals(action)) { - if (!pkgName.equals(Utils.getDefaultThemePackageName(context))) { - NotificationHelper.postThemeInstalledNotification(context, pkgName); - } - } else if (cyanogenmod.content.Intent.ACTION_THEME_REMOVED.equals(action)) { - // remove updated status for this theme (if one exists) - PreferenceUtils.removeUpdatedTheme(context, pkgName); - - // If the theme being removed was the currently applied theme we need - // to update the applied base theme in preferences to the default theme. - String appliedBaseTheme = PreferenceUtils.getAppliedBaseTheme(context); - if (!TextUtils.isEmpty(appliedBaseTheme) && appliedBaseTheme.equals(pkgName)) { - PreferenceUtils.setAppliedBaseTheme(context, - Utils.getDefaultThemePackageName(context)); - } - NotificationHelper.cancelNotifications(context); - } else if (cyanogenmod.content.Intent.ACTION_THEME_UPDATED.equals(action)) { - try { - if (isTheme(context, pkgName)) { - PreferenceUtils.addUpdatedTheme(context, pkgName); - } - } catch (NameNotFoundException e) { - } - } - } - - private boolean isTheme(Context context, String pkgName) throws NameNotFoundException { - PackageInfo pi = context.getPackageManager().getPackageInfo(pkgName, 0); - - return pi != null && pi.themeInfo != null; - } -} diff --git a/src/org/cyanogenmod/theme/chooser/BootReceiver.java b/src/org/cyanogenmod/theme/chooser/BootReceiver.java deleted file mode 100644 index 00a6723..0000000 --- a/src/org/cyanogenmod/theme/chooser/BootReceiver.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2016 Cyanogen, Inc. - * Copyright (C) 2016 The CyanogenMod Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.cyanogenmod.theme.chooser; - -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; - -public class BootReceiver extends BroadcastReceiver { - private static final String CHOOSER_PKG_NAME = "org.cyanogenmod.theme.chooser"; - private static final String CHOOSER_ACTIVITY = "org.cyanogenmod.theme.chooser.ChooserLauncher"; - - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - PackageManager pm = context.getPackageManager(); - if (Intent.ACTION_BOOT_COMPLETED.equals(action)) { - try { - PackageInfo info = pm.getPackageInfo(ChooserActivity.THEME_STORE_PACKAGE, 0); - if (info != null) { - ComponentName cn = new ComponentName(CHOOSER_PKG_NAME, CHOOSER_ACTIVITY); - pm.setComponentEnabledSetting(cn, - PackageManager.COMPONENT_ENABLED_STATE_DISABLED, - PackageManager.DONT_KILL_APP); - } - } catch (PackageManager.NameNotFoundException e) { - // no store so nothing to do. - } - - // now disable this receiver so we don't get called on future boots - ComponentName cn = new ComponentName(CHOOSER_PKG_NAME, - BootReceiver.class.getCanonicalName()); - pm.setComponentEnabledSetting(cn, - PackageManager.COMPONENT_ENABLED_STATE_DISABLED, - PackageManager.DONT_KILL_APP); - } - } -} diff --git a/src/org/cyanogenmod/theme/chooser/ChooserActivity.java b/src/org/cyanogenmod/theme/chooser/ChooserActivity.java deleted file mode 100644 index 081325d..0000000 --- a/src/org/cyanogenmod/theme/chooser/ChooserActivity.java +++ /dev/null @@ -1,1191 +0,0 @@ -/* - * Copyright (C) 2016 Cyanogen, Inc. - * Copyright (C) 2016 The CyanogenMod Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.cyanogenmod.theme.chooser; - -import android.animation.Animator; -import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; -import android.content.ActivityNotFoundException; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.IPackageDeleteObserver; -import android.content.pm.PackageManager; -import android.content.res.Resources; -import android.content.res.ThemeConfig; -import android.database.Cursor; -import android.graphics.Bitmap; -import android.graphics.ColorMatrix; -import android.graphics.ColorMatrixColorFilter; -import android.graphics.Paint; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.TransitionDrawable; -import android.net.Uri; -import android.os.AsyncTask; -import android.os.Bundle; -import android.os.Handler; -import android.os.RemoteException; -import android.provider.Settings; -import android.renderscript.Allocation; -import android.renderscript.Element; -import android.renderscript.RenderScript; -import android.renderscript.ScriptIntrinsicBlur; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentActivity; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.Loader; -import android.support.v4.view.ThemeViewPager; -import android.support.v4.view.ViewPager; -import android.text.TextUtils; -import android.util.DisplayMetrics; -import android.util.Log; -import android.util.MutableLong; -import android.util.TypedValue; -import android.view.View; -import android.view.ViewPropertyAnimator; -import android.view.animation.Animation; -import android.view.animation.AnimationUtils; -import android.view.animation.DecelerateInterpolator; -import android.widget.ImageView; -import android.widget.Toast; - -import org.cyanogenmod.theme.perapptheming.PerAppThemingWindow; -import org.cyanogenmod.theme.util.CursorLoaderHelper; -import org.cyanogenmod.theme.util.NotificationHelper; -import org.cyanogenmod.theme.util.PreferenceUtils; -import org.cyanogenmod.theme.util.TypefaceHelperCache; -import org.cyanogenmod.theme.util.Utils; - -import cyanogenmod.platform.Manifest; -import cyanogenmod.providers.ThemesContract; -import cyanogenmod.providers.ThemesContract.ThemesColumns; -import cyanogenmod.themes.ThemeManager; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_ALARMS; -import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_BOOT_ANIM; -import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_NOTIFICATIONS; -import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_RINGTONES; -import static org.cyanogenmod.theme.chooser.ComponentSelector.DEFAULT_COMPONENT_ID; -import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_INSTALLED_THEMES; -import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_APPLIED; - -public class ChooserActivity extends FragmentActivity - implements LoaderManager.LoaderCallbacks { - public static final String THEME_STORE_PACKAGE = "com.cyngn.theme.tore"; - private static final String TAG = ChooserActivity.class.getSimpleName(); - - public static final String DEFAULT = ThemeConfig.SYSTEM_DEFAULT; - public static final String EXTRA_PKGNAME = "pkgName"; - public static final String EXTRA_COMPONENTS = "components"; - - private static final int OFFSCREEN_PAGE_LIMIT = 3; - - private static final String THEME_STORE_ACTIVITY = THEME_STORE_PACKAGE + ".ui.StoreActivity"; - private static final String ACTION_APPLY_THEME = "android.intent.action.APPLY_THEME"; - - private static final String TYPE_IMAGE = "image/*"; - - private static final String ACTION_PICK_LOCK_SCREEN_WALLPAPER = - "com.cyngn.intent.action.PICK_LOCK_SCREEN_WALLPAPER"; - - /** - * Request code for picking an external wallpaper - */ - public static final int REQUEST_PICK_WALLPAPER_IMAGE = 2; - /** - * Request code for picking an external lockscreen wallpaper - */ - public static final int REQUEST_PICK_LOCKSCREEN_IMAGE = 3; - - /** - * Request code for enabling system alert window permission - */ - private static final int REQUEST_SYSTEM_WINDOW_PERMISSION = 4; - - private static final long ANIMATE_CONTENT_IN_SCALE_DURATION = 500; - private static final long ANIMATE_CONTENT_IN_ALPHA_DURATION = 750; - private static final long ANIMATE_CONTENT_IN_BLUR_DURATION = 250; - private static final long ANIMATE_CONTENT_DELAY = 250; - private static final long ANIMATE_SHOP_THEMES_HIDE_DURATION = 250; - private static final long ANIMATE_SHOP_THEMES_SHOW_DURATION = 500; - private static final long FINISH_ANIMATION_DELAY = ThemeFragment.ANIMATE_DURATION - + ThemeFragment.ANIMATE_START_DELAY + 250; - - private static final long ANIMATE_CARDS_IN_DURATION = 250; - private static final long ANIMATE_SAVE_APPLY_LAYOUT_DURATION = 300; - private static final float ANIMATE_SAVE_APPLY_DECELERATE_INTERPOLATOR_FACTOR = 3; - private static final long ONCLICK_SAVE_APPLY_FINISH_ANIMATION_DELAY = 400; - - private PagerContainer mContainer; - private ThemeViewPager mPager; - - private ThemesAdapter mAdapter; - private boolean mExpanded = false; - private ComponentSelector mSelector; - private View mSaveApplyLayout; - private int mContainerYOffset = 0; - private TypefaceHelperCache mTypefaceHelperCache; - private boolean mIsAnimating; - private Handler mHandler; - private View mBottomActionsLayout; - - private String mSelectedTheme; - private String mAppliedBaseTheme; - private boolean mThemeChanging = false; - private boolean mAnimateContentIn = false; - private long mAnimateContentInDelay; - private String mThemeToApply; - private ArrayList mComponentsToApply; - - ImageView mCustomBackground; - - // Current system theme configuration as component -> pkgName - private Map mCurrentTheme = new HashMap(); - private MutableLong mCurrentWallpaperCmpntId = new MutableLong(DEFAULT_COMPONENT_ID); - - private boolean mIsPickingImage = false; - private boolean mRestartLoaderOnCollapse = false; - private boolean mActivityResuming = false; - private boolean mShowLockScreenWallpaper = false; - - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); - NotificationHijackingService.ensureEnabled(this); - - if (savedInstanceState == null) { - handleIntent(getIntent()); - } - - mContainer = (PagerContainer) findViewById(R.id.pager_container); - mPager = (ThemeViewPager) findViewById(R.id.viewpager); - - mPager.setOnClickListener(mPagerClickListener); - mAdapter = new ThemesAdapter(); - mPager.setAdapter(mAdapter); - - DisplayMetrics dm = getResources().getDisplayMetrics(); - int margin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48, dm); - mPager.setPageMargin(-margin / 2); - mPager.setOffscreenPageLimit(OFFSCREEN_PAGE_LIMIT); - - mPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { - public void onPageSelected(int position) { - } - - public void onPageScrolled(int position, - float positionOffset, - int positionOffsetPixels) { - } - - public void onPageScrollStateChanged(int state) { - } - }); - - mSelector = (ComponentSelector) findViewById(R.id.component_selector); - mSelector.setOnOpenCloseListener(mOpenCloseListener); - - mBottomActionsLayout = findViewById(R.id.bottom_actions_layout); - - mSaveApplyLayout = findViewById(R.id.save_apply_layout); - mSaveApplyLayout.findViewById(R.id.save_apply_button).setOnClickListener( - new View.OnClickListener() { - @Override - public void onClick(View v) { - if (mIsAnimating) return; - hideSaveApplyButton(); - mContainer.setClickable(false); - final ThemeFragment f = getCurrentFragment(); - if (mSelector.isEnabled()) { - mSelector.hide(); - if (mContainerYOffset != 0) { - slideContentBack(-mContainerYOffset); - mContainerYOffset = 0; - } - if (f != null) f.fadeInCards(); - if (mShowLockScreenWallpaper) { - mShowLockScreenWallpaper = false; - mSelector.resetComponentType(); - } - } - - mHandler.postDelayed(new Runnable() { - @Override - public void run() { - collapse(true); - } - }, ONCLICK_SAVE_APPLY_FINISH_ANIMATION_DELAY); - } - }); - - mBottomActionsLayout.findViewById(R.id.shop_themes) - .setOnClickListener(mOnShopThemesClicked); - - mTypefaceHelperCache = TypefaceHelperCache.getInstance(); - mHandler = new Handler(); - mCustomBackground = (ImageView) findViewById(R.id.custom_bg); - mAnimateContentIn = true; - mAnimateContentInDelay = 0; - - mBottomActionsLayout.findViewById(R.id.per_app_theming).setOnClickListener( - new View.OnClickListener() { - @Override - public void onClick(View v) { - if (Settings.canDrawOverlays(ChooserActivity.this)) { - launchAppThemer(); - } else { - requestSystemWindowPermission(); - } - } - }); - - if (PreferenceUtils.getShowPerAppThemeNewTag(this)) { - View tag = mBottomActionsLayout.findViewById(R.id.new_tag); - if (tag != null) { - tag.setVisibility(View.VISIBLE); - } - } - } - - public void showSaveApplyButton() { - if (mSaveApplyLayout != null && mSaveApplyLayout.getVisibility() != View.VISIBLE) { - mHandler.post(new Runnable() { - @Override - public void run() { - int navBarHeight = 0; - if (Utils.hasNavigationBar(ChooserActivity.this.getApplicationContext())) { - navBarHeight = ChooserActivity.this.getResources() - .getDimensionPixelSize(R.dimen.navigation_bar_height); - } - mSaveApplyLayout.setTranslationY(mSaveApplyLayout.getMeasuredHeight()); - mSaveApplyLayout.setVisibility(View.VISIBLE); - mSaveApplyLayout.animate() - .setDuration(ANIMATE_SAVE_APPLY_LAYOUT_DURATION) - .setInterpolator( - new DecelerateInterpolator( - ANIMATE_SAVE_APPLY_DECELERATE_INTERPOLATOR_FACTOR)) - .translationY(-mSelector.getMeasuredHeight() - + navBarHeight); - } - }); - } - } - - public void hideSaveApplyButton() { - if (mSaveApplyLayout.getVisibility() != View.GONE) { - Animation anim = AnimationUtils.loadAnimation(this, - R.anim.component_selection_animate_out); - mSaveApplyLayout.startAnimation(anim); - anim.setAnimationListener(new Animation.AnimationListener() { - @Override - public void onAnimationStart(Animation animation) { - } - - @Override - public void onAnimationEnd(Animation animation) { - mSaveApplyLayout.setVisibility(View.GONE); - } - - @Override - public void onAnimationRepeat(Animation animation) { - } - }); - } - } - - private void hideBottomActionsLayout() { - final ViewPropertyAnimator anim = mBottomActionsLayout.animate(); - anim.alpha(0f).setDuration(ANIMATE_SHOP_THEMES_HIDE_DURATION); - anim.setListener(new Animator.AnimatorListener() { - @Override - public void onAnimationStart(Animator animation) { - } - - @Override - public void onAnimationEnd(Animator animation) { - mBottomActionsLayout.setVisibility(View.GONE); - } - - @Override - public void onAnimationCancel(Animator animation) { - } - - @Override - public void onAnimationRepeat(Animator animation) { - } - }); - } - - private void showBottomActionsLayout() { - mBottomActionsLayout.setVisibility(View.VISIBLE); - final ViewPropertyAnimator anim = mBottomActionsLayout.animate(); - anim.setListener(null); - anim.alpha(1f).setStartDelay(ThemeFragment.ANIMATE_DURATION) - .setDuration(ANIMATE_SHOP_THEMES_SHOW_DURATION); - } - - private void lauchGetThemes() { - String playStoreUrl = getString(R.string.play_store_url); - String wikiUrl = getString(R.string.wiki_url); - - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setData(Uri.parse(playStoreUrl)); - - // Try to launch play store - if (intent.resolveActivity(getPackageManager()) != null) { - startActivity(intent); - } else { - // If no play store, try to open wiki url - intent.setData(Uri.parse(wikiUrl)); - if (intent.resolveActivity(getPackageManager()) != null) { - startActivity(intent); - } else { - Toast.makeText(this, R.string.get_more_app_not_available, - Toast.LENGTH_LONG).show(); - } - } - } - - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); - if (Utils.isRecentTaskHome(this)) { - mContainer.setAlpha(0f); - mBottomActionsLayout.setAlpha(0f); - mAnimateContentIn = true; - mAnimateContentInDelay = ANIMATE_CONTENT_DELAY; - } - handleIntent(intent); - } - - private void handleIntent(Intent intent) { - String action = intent.getAction(); - if ((Intent.ACTION_MAIN.equals(action) || ACTION_APPLY_THEME.equals(action)) - && intent.hasExtra(EXTRA_PKGNAME)) { - if (intent.hasExtra(EXTRA_COMPONENTS)) { - mComponentsToApply = intent.getStringArrayListExtra(EXTRA_COMPONENTS); - } else { - mComponentsToApply = null; - } - mSelectedTheme = mComponentsToApply != null ? - PreferenceUtils.getAppliedBaseTheme(this) : - getSelectedTheme(intent.getStringExtra(EXTRA_PKGNAME)); - if (mPager != null) { - startLoader(LOADER_ID_INSTALLED_THEMES); - if (mExpanded) { - int collapseDelay = ThemeFragment.ANIMATE_START_DELAY; - if (mSelector.isEnabled()) { - // onBackPressed() has all the necessary logic for collapsing the - // component selector, so we call it here. - onBackPressed(); - collapseDelay += ThemeFragment.ANIMATE_DURATION; - } - mHandler.postDelayed(new Runnable() { - @Override - public void run() { - collapse(false); - } - }, collapseDelay); - } - } - - if (ACTION_APPLY_THEME.equals(action) && - getCallingPackage() != null && - PackageManager.PERMISSION_GRANTED == - getPackageManager() - .checkPermission(Manifest.permission.WRITE_THEMES, - getCallingPackage())) { - mThemeToApply = intent.getStringExtra(EXTRA_PKGNAME); - } - } else if (ACTION_PICK_LOCK_SCREEN_WALLPAPER.equals(action)) { - mShowLockScreenWallpaper = true; - } - } - - private String getSelectedTheme(String requestedTheme) { - String[] projection = { ThemesColumns.PRESENT_AS_THEME }; - String selection = ThemesColumns.PKG_NAME + "=?"; - String[] selectionArgs = { requestedTheme }; - - String selectedTheme = PreferenceUtils.getAppliedBaseTheme(this); - - Cursor cursor = getContentResolver().query(ThemesColumns.CONTENT_URI, - projection, selection, selectionArgs, null); - if (cursor != null) { - if (cursor.getCount() > 0 && cursor.moveToFirst()) { - if (cursor.getInt(0) == 1) { - selectedTheme = requestedTheme; - } - } - cursor.close(); - } - return selectedTheme; - } - - private void setAnimatingStateAndScheduleFinish() { - mIsAnimating = true; - mContainer.setIsAnimating(true); - mHandler.postDelayed(new Runnable() { - public void run() { - mIsAnimating = false; - mContainer.setIsAnimating(false); - if (mRestartLoaderOnCollapse) { - mRestartLoaderOnCollapse = false; - startLoader(LOADER_ID_INSTALLED_THEMES); - } - } - }, FINISH_ANIMATION_DELAY); - if (mExpanded) { - hideBottomActionsLayout(); - } else { - showBottomActionsLayout(); - } - } - - private void setCustomBackground(final ImageView iv, final boolean animate) { - final Context context = ChooserActivity.this; - iv.post(new Runnable() { - @Override - public void run() { - Bitmap tmpBmp; - try { - tmpBmp = Utils.getRegularWallpaperBitmap(context); - } catch (Throwable e) { - Log.w(TAG, "Failed to retrieve wallpaper", e); - tmpBmp = null; - } - // Show the grid background if no wallpaper is set. - // Note: no wallpaper is actually a 1x1 pixel black bitmap - if (tmpBmp == null || tmpBmp.getWidth() <= 1 || tmpBmp.getHeight() <= 1) { - iv.setImageResource(R.drawable.bg_grid); - // We need to change the ScaleType to FIT_XY otherwise the background is cut - // off a bit at the bottom. - iv.setScaleType(ImageView.ScaleType.FIT_XY); - return; - } - - // Since we are applying a blur, we can afford to scale the bitmap down and use a - // smaller blur radius. - Bitmap inBmp = Bitmap.createScaledBitmap(tmpBmp, tmpBmp.getWidth() / 4, - tmpBmp.getHeight() / 4, false); - Bitmap outBmp = Bitmap.createBitmap(inBmp.getWidth(), inBmp.getHeight(), - Bitmap.Config.ARGB_8888); - - // Blur the original bitmap - RenderScript rs = RenderScript.create(context); - ScriptIntrinsicBlur theIntrinsic = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); - Allocation tmpIn = Allocation.createFromBitmap(rs, inBmp); - Allocation tmpOut = Allocation.createFromBitmap(rs, outBmp); - theIntrinsic.setRadius(5.0f); - theIntrinsic.setInput(tmpIn); - theIntrinsic.forEach(tmpOut); - tmpOut.copyTo(outBmp); - - // Create a bitmap drawable and use a color matrix to de-saturate the image - BitmapDrawable[] layers = new BitmapDrawable[2]; - layers[0] = new BitmapDrawable(getResources(), tmpBmp); - layers[1] = new BitmapDrawable(getResources(), outBmp); - ColorMatrix cm = new ColorMatrix(); - cm.setSaturation(0); - Paint p = layers[0].getPaint(); - p.setColorFilter(new ColorMatrixColorFilter(cm)); - p = layers[1].getPaint(); - p.setColorFilter(new ColorMatrixColorFilter(cm)); - TransitionDrawable d = new TransitionDrawable(layers); - - // All done - iv.setScaleType(ImageView.ScaleType.CENTER_CROP); - if (!animate) { - iv.setImageDrawable(layers[1]); - } else { - iv.setImageDrawable(d); - } - } - }); - } - - /** - * Disable the ViewPager while a theme change is occuring - */ - public void themeChangeStart() { - lockPager(); - mThemeChanging = true; - ThemeFragment f = getCurrentFragment(); - if (f != null) { - mAppliedBaseTheme = f.getThemePackageName(); - PreferenceUtils.setAppliedBaseTheme(this, mAppliedBaseTheme); - } - } - - /** - * Re-enable the ViewPager and update the "My theme" fragment if available - */ - public void themeChangeEnd(boolean isSuccess) { - mThemeChanging = false; - ThemeFragment f = getCurrentFragment(); - if (f != null) { - // We currently need to recreate the adapter in order to load - // the changes otherwise the adapter returns the original fragments - // TODO: We'll need a better way to handle this to provide a good UX - if (!(f instanceof MyThemeFragment)) { - mAdapter = new ThemesAdapter(); - mPager.setAdapter(mAdapter); - } - if (!isSuccess) { - mAppliedBaseTheme = null; - } - startLoader(LOADER_ID_APPLIED); - } - unlockPager(); - } - - public void lockPager() { - mPager.setScrollingEnabled(false); - } - - public void unlockPager() { - mPager.setScrollingEnabled(true); - } - - public ComponentSelector getComponentSelector() { - return mSelector; - } - - public void showComponentSelector(String component, View v) { - showComponentSelector(component, null, DEFAULT_COMPONENT_ID, v); - } - - public void showComponentSelector(String component, String selectedPkgName, - long selectedCmpntId, View v) { - if (component != null) { - final Resources res = getResources(); - int itemsPerPage = res.getInteger(R.integer.default_items_per_page); - int height = res.getDimensionPixelSize(R.dimen.component_selection_cell_height); - if (MODIFIES_BOOT_ANIM.equals(component)) { - itemsPerPage = res.getInteger(R.integer.bootani_items_per_page); - height = res.getDimensionPixelSize( - R.dimen.component_selection_cell_height_boot_anim); - } else if (MODIFIES_ALARMS.equals(component) || - MODIFIES_NOTIFICATIONS.equals(component) || - MODIFIES_RINGTONES.equals(component)) { - itemsPerPage = 2; - height = res.getDimensionPixelSize( - R.dimen.component_selection_cell_height_sounds); - } - if (mSaveApplyLayout.getVisibility() == View.VISIBLE) { - if (mSaveApplyLayout.getTranslationY() + height != 0) { - mSaveApplyLayout.animate() - .translationY(-height) - .setInterpolator( - new DecelerateInterpolator( - ANIMATE_SAVE_APPLY_DECELERATE_INTERPOLATOR_FACTOR)) - .setDuration(ANIMATE_SAVE_APPLY_LAYOUT_DURATION); - } - } - mSelector.show(component, selectedPkgName, selectedCmpntId, itemsPerPage, height); - - // determine if we need to shift the cards up - int[] coordinates = new int[2]; - v.getLocationOnScreen(coordinates); - final int top = coordinates[1]; - final int bottom = coordinates[1] + v.getHeight(); - final int statusBarHeight = res.getDimensionPixelSize(R.dimen.status_bar_height); - int selectorTop = getWindowManager().getDefaultDisplay().getHeight() - height; - if (bottom > selectorTop) { - slideContentIntoView(bottom - selectorTop, height); - } else if (top < statusBarHeight) { - slideContentIntoView(top - statusBarHeight, height); - } - } - } - - public void expand() { - if (!mExpanded && !mIsAnimating) { - mExpanded = true; - mContainer.setClickable(false); - mContainer.expand(); - ThemeFragment f = getCurrentFragment(); - if (f != null) { - f.expand(); - } - setAnimatingStateAndScheduleFinish(); - } - } - - public void collapse(final boolean applyTheme) { - mExpanded = false; - final ThemeFragment f = getCurrentFragment(); - if (f != null) { - f.fadeOutCards(new Runnable() { - public void run() { - mContainer.collapse(); - f.collapse(applyTheme); - } - }); - } - setAnimatingStateAndScheduleFinish(); - } - - public void pickExternalWallpaper() { - Intent intent = new Intent(Intent.ACTION_GET_CONTENT); - intent.setType(TYPE_IMAGE); - startActivityForResult(intent, REQUEST_PICK_WALLPAPER_IMAGE); - mIsPickingImage = true; - } - - public void pickExternalLockscreen() { - Intent intent = new Intent(Intent.ACTION_GET_CONTENT); - intent.setType(TYPE_IMAGE); - startActivityForResult(intent, REQUEST_PICK_LOCKSCREEN_IMAGE); - mIsPickingImage = true; - } - - public void uninstallTheme(String pkgName) { - PackageManager pm = getPackageManager(); - pm.deletePackage(pkgName, new PackageDeleteObserver(), PackageManager.DELETE_ALL_USERS); - } - - private void slideContentIntoView(int yDelta, int selectorHeight) { - ThemeFragment f = getCurrentFragment(); - if (f != null) { - final int offset = getResources().getDimensionPixelSize(R.dimen.content_offset_padding); - if (yDelta > 0) { - yDelta += offset; - } else { - yDelta -= offset; - } - f.slideContentIntoView(yDelta, selectorHeight); - mContainerYOffset = yDelta; - } - } - - private void slideContentBack(final int yDelta) { - ThemeFragment f = getCurrentFragment(); - if (f != null) { - f.slideContentBack(yDelta); - } - } - - @Override - protected void onResume() { - super.onResume(); - setCustomBackground(mCustomBackground, mAnimateContentIn); - // clear out any notifications that are being displayed. - NotificationHelper.cancelNotifications(this); - - ThemeManager tm = ThemeManager.getInstance(this); - mThemeChanging = tm.isThemeApplying(); - - if (!mIsPickingImage) { - startLoader(LOADER_ID_APPLIED); - } else { - mIsPickingImage = false; - } - - IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED); - registerReceiver(mWallpaperChangeReceiver, filter); - } - - @Override - public void onBackPressed() { - final ThemeFragment f = getCurrentFragment(); - if (mSelector.isEnabled()) { - mSelector.hide(); - if (mContainerYOffset != 0) { - slideContentBack(-mContainerYOffset); - mContainerYOffset = 0; - } - if (f != null) f.fadeInCards(); - if (mShowLockScreenWallpaper) { - mShowLockScreenWallpaper = false; - mSelector.resetComponentType(); - } - } else if (mExpanded) { - if (mIsAnimating) { - return; - } - - if (mSaveApplyLayout.getVisibility() == View.VISIBLE) { - hideSaveApplyButton(); - if (f != null) f.clearChanges(); - } - collapse(false); - } else { - if (f != null && f.isShowingConfirmCancelOverlay()) { - f.hideConfirmCancelOverlay(); - } else if (f != null && f.isShowingCustomizeResetLayout()) { - f.hideCustomizeResetLayout(); - } else { - super.onBackPressed(); - } - } - } - - @Override - public void onPause() { - super.onPause(); - unregisterReceiver(mWallpaperChangeReceiver); - ThemeFragment f = getCurrentFragment(); - if (f != null) { - mSelectedTheme = f.getThemePackageName(); - } - } - - @Override - public void onDestroy() { - super.onDestroy(); - } - - @Override - protected void onStart() { - super.onStart(); - if (mTypefaceHelperCache.getTypefaceCount() <= 0) { - new TypefacePreloadTask().execute(); - } - mAnimateContentInDelay = ANIMATE_CONTENT_DELAY; - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if (resultCode == RESULT_OK && requestCode == REQUEST_PICK_WALLPAPER_IMAGE) { - if (data != null && data.getData() != null) { - Uri uri = data.getData(); - ThemeFragment f = getCurrentFragment(); - if (f != null) { - f.setWallpaperImageUri(uri); - showSaveApplyButton(); - } - } - } else if (resultCode == RESULT_OK && requestCode == REQUEST_PICK_LOCKSCREEN_IMAGE) { - if (data != null && data.getData() != null) { - Uri uri = data.getData(); - ThemeFragment f = getCurrentFragment(); - if (f != null) { - f.setLockscreenImageUri(uri); - showSaveApplyButton(); - } - } - } else if (requestCode == REQUEST_SYSTEM_WINDOW_PERMISSION) { - if (Settings.canDrawOverlays(this)) { - launchAppThemer(); - } - } - } - - private void animateContentIn() { - Drawable d = mCustomBackground.getDrawable(); - if (d instanceof TransitionDrawable) { - ((TransitionDrawable) d).startTransition((int) ANIMATE_CONTENT_IN_BLUR_DURATION); - } - - if (!mShowLockScreenWallpaper) { - AnimatorSet set = new AnimatorSet(); - set.play(ObjectAnimator.ofFloat(mContainer, "alpha", 0f, 1f) - .setDuration(ANIMATE_CONTENT_IN_ALPHA_DURATION)) - .with(ObjectAnimator.ofFloat(mContainer, "scaleX", 2f, 1f) - .setDuration(ANIMATE_CONTENT_IN_SCALE_DURATION)) - .with(ObjectAnimator.ofFloat(mContainer, "scaleY", 2f, 1f) - .setDuration(ANIMATE_CONTENT_IN_SCALE_DURATION)); - set.setStartDelay(mAnimateContentInDelay); - set.start(); - mBottomActionsLayout.setAlpha(0f); - mBottomActionsLayout.animate().alpha(1f).setStartDelay(mAnimateContentInDelay) - .setDuration(ANIMATE_CONTENT_IN_ALPHA_DURATION); - } else { - mContainer.setAlpha(0f); - mContainer.setVisibility(View.GONE); - } - mAnimateContentIn = false; - } - - private View.OnClickListener mPagerClickListener = new View.OnClickListener() { - @Override - public void onClick(View v) { - ThemeFragment f = getCurrentFragment(); - if (f != null && !mThemeChanging) { - f.performClick(mPager.isClickedOnContent()); - } - } - }; - - private BroadcastReceiver mWallpaperChangeReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (mCustomBackground != null) setCustomBackground(mCustomBackground, false); - } - }; - - private ComponentSelector.OnOpenCloseListener mOpenCloseListener = new ComponentSelector.OnOpenCloseListener() { - @Override - public void onSelectorOpened() { - } - - @Override - public void onSelectorClosed() { - } - - @Override - public void onSelectorClosing() { - ThemeFragment f = getCurrentFragment(); - if (f != null && f.componentsChanged() - && mSaveApplyLayout.getVisibility() == View.VISIBLE) { - mSaveApplyLayout.animate() - .translationY(0) - .setInterpolator(new DecelerateInterpolator()) - .setDuration(ANIMATE_SAVE_APPLY_LAYOUT_DURATION); - } - } - }; - - private ThemeFragment getCurrentFragment() { - // instantiateItem will return the fragment if it already exists and not instantiate it, - // which should be the case for the current fragment. - ThemeFragment f; - try { - f = (mAdapter == null || mPager == null || mAdapter.getCount() <= 0) ? null : - (ThemeFragment) mAdapter.instantiateItem(mPager, mPager.getCurrentItem()); - } catch (Exception e) { - f = null; - Log.e(TAG, "Unable to get current fragment", e); - } - return f; - } - - private void populateCurrentTheme(Cursor c) { - c.moveToPosition(-1); - //Default to first wallpaper - mCurrentWallpaperCmpntId.value = DEFAULT_COMPONENT_ID; - // clear out the previous map - mCurrentTheme.clear(); - while(c.moveToNext()) { - int mixkeyIdx = c.getColumnIndex(ThemesContract.MixnMatchColumns.COL_KEY); - int pkgIdx = c.getColumnIndex(ThemesContract.MixnMatchColumns.COL_VALUE); - int cmpntIdIdx = c.getColumnIndex(ThemesContract.MixnMatchColumns.COL_COMPONENT_ID); - String mixkey = c.getString(mixkeyIdx); - String component = ThemesContract.MixnMatchColumns.mixNMatchKeyToComponent(mixkey); - String pkg = c.getString(pkgIdx); - mCurrentTheme.put(component, pkg); - if (TextUtils.equals(component, ThemesColumns.MODIFIES_LIVE_LOCK_SCREEN)) { - mCurrentTheme.remove(ThemesColumns.MODIFIES_LOCKSCREEN); - } - if (TextUtils.equals(component, ThemesColumns.MODIFIES_LOCKSCREEN)) { - mCurrentTheme.remove(ThemesColumns.MODIFIES_LIVE_LOCK_SCREEN); - } - if (cmpntIdIdx >= 0 && TextUtils.equals(component, ThemesColumns.MODIFIES_LAUNCHER)) { - mCurrentWallpaperCmpntId.value = c.getLong(cmpntIdIdx); - } - } - } - - private View.OnClickListener mOnShopThemesClicked = new View.OnClickListener() { - @Override - public void onClick(View v) { - Intent intent = new Intent(); - intent.setClassName(THEME_STORE_PACKAGE, THEME_STORE_ACTIVITY); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - try { - startActivity(intent); - } catch (ActivityNotFoundException e) { - lauchGetThemes(); - } - } - }; - - private void startLoader(int loaderId) { - final LoaderManager manager = getSupportLoaderManager(); - final Loader loader = manager.getLoader(loaderId); - if (loader != null) { - manager.restartLoader(loaderId, null, this); - } else { - manager.initLoader(loaderId, null, this); - } - } - - @Override - public void onLoadFinished(Loader loader, Cursor data) { - if (mThemeChanging) return; - - if (mExpanded && !mActivityResuming) { - mRestartLoaderOnCollapse = true; - return; - } - - switch (loader.getId()) { - case LOADER_ID_INSTALLED_THEMES: - // Swap the new cursor in. (The framework will take care of closing the - // old cursor once we return.) - int selectedThemeIndex = -1; - if (TextUtils.isEmpty(mSelectedTheme)) mSelectedTheme = mAppliedBaseTheme; - while(data.moveToNext()) { - if (mSelectedTheme.equals(data.getString( - data.getColumnIndex(ThemesColumns.PKG_NAME)))) { - // we need to add one here since the first card is "My theme" - selectedThemeIndex = data.getPosition(); - mSelectedTheme = null; - break; - } - } - data.moveToFirst(); - mAdapter.swapCursor(data); - mAdapter.notifyDataSetChanged(); - if (selectedThemeIndex >= 0) { - mPager.setCurrentItem(selectedThemeIndex, false); - - if (mThemeToApply != null) { - ThemeFragment f = getCurrentFragment(); - f.applyThemeWhenPopulated(mThemeToApply, mComponentsToApply); - mThemeToApply = null; - } - } - if (mAnimateContentIn) animateContentIn(); - mActivityResuming = true; - break; - case LOADER_ID_APPLIED: - startLoader(LOADER_ID_INSTALLED_THEMES); - populateCurrentTheme(data); - break; - } - } - - @Override - public void onLoaderReset(Loader loader) { - switch (loader.getId()) { - case LOADER_ID_INSTALLED_THEMES: - mAdapter.swapCursor(null); - mAdapter.notifyDataSetChanged(); - break; - } - } - - @Override - public Loader onCreateLoader(int id, Bundle args) { - switch (id) { - case LOADER_ID_INSTALLED_THEMES: - mAppliedBaseTheme = PreferenceUtils.getAppliedBaseTheme(this); - break; - case LOADER_ID_APPLIED: - //TODO: Mix n match query should only be done once - break; - } - return CursorLoaderHelper.chooserActivityCursorLoader(this, id, mAppliedBaseTheme); - } - - public Map getSelectedComponentsMap() { - return getCurrentFragment().getSelectedComponentsMap(); - } - - public class ThemesAdapter extends NewFragmentStatePagerAdapter { - private ArrayList mInstalledThemes; - private String mAppliedThemeTitle; - private String mAppliedThemeAuthor; - private HashMap mRepositionedFragments; - - public ThemesAdapter() { - super(getSupportFragmentManager()); - mRepositionedFragments = new HashMap(); - } - - @Override - public Fragment getItem(int position) { - ThemeFragment f = null; - MutableLong wallpaperCmpntId; - if (mInstalledThemes != null) { - final String pkgName = mInstalledThemes.get(position); - if (pkgName.equals(mAppliedBaseTheme)) { - f = MyThemeFragment.newInstance(mAppliedBaseTheme, mAppliedThemeTitle, - mAppliedThemeAuthor, mAnimateContentIn, mShowLockScreenWallpaper); - wallpaperCmpntId = mCurrentWallpaperCmpntId; - } else { - f = ThemeFragment.newInstance(pkgName, mAnimateContentIn); - wallpaperCmpntId = new MutableLong(DEFAULT_COMPONENT_ID); - } - f.setCurrentTheme(mCurrentTheme, wallpaperCmpntId); - } - return f; - } - - @Override - public long getItemId(int position) { - if (mInstalledThemes != null) { - final String pkgName = mInstalledThemes.get(position); - return pkgName.hashCode(); - } - return 0; - } - - @Override - public int getItemPosition(Object object) { - final ThemeFragment f = (ThemeFragment) object; - final String pkgName = f != null ? f.getThemePackageName() : null; - if (pkgName != null && mRepositionedFragments.containsKey(pkgName)) { - final int position = mRepositionedFragments.get(pkgName); - mRepositionedFragments.remove(pkgName); - return position; - } - return super.getItemPosition(object); - } - - /** - * The first card should be the user's currently applied theme components so we - * will always return at least 1 or mCursor.getCount() + 1 - * @return - */ - public int getCount() { - return mInstalledThemes == null ? 0 : mInstalledThemes.size(); - } - - public void swapCursor(Cursor c) { - if (c != null && c.getCount() != 0) { - ArrayList previousOrder = mInstalledThemes == null ? null - : new ArrayList(mInstalledThemes); - mInstalledThemes = new ArrayList(c.getCount()); - mRepositionedFragments.clear(); - c.moveToPosition(-1); - while (c.moveToNext()) { - final int pkgIdx = c.getColumnIndex(ThemesColumns.PKG_NAME); - final String pkgName = c.getString(pkgIdx); - if (pkgName.equals(mAppliedBaseTheme)) { - final int titleIdx = c.getColumnIndex(ThemesColumns.TITLE); - final int authorIdx = c.getColumnIndex(ThemesColumns.AUTHOR); - mAppliedThemeTitle = c.getString(titleIdx); - mAppliedThemeAuthor = c.getString(authorIdx); - } - mInstalledThemes.add(pkgName); - - // track any themes that may have changed position - if (previousOrder != null && previousOrder.contains(pkgName)) { - int index = previousOrder.indexOf(pkgName); - if (index != c.getPosition()) { - mRepositionedFragments.put(pkgName, c.getPosition()); - } - } else { - mRepositionedFragments.put(pkgName, c.getPosition()); - } - } - // check if any themes are no longer in the new list - if (previousOrder != null) { - for (String pkgName : previousOrder) { - if (!mInstalledThemes.contains(pkgName)) { - mRepositionedFragments.put(pkgName, POSITION_NONE); - } - } - } - } else { - mInstalledThemes = null; - } - } - - public void removeTheme(String pkgName) { - if (mInstalledThemes == null) return; - - if (mInstalledThemes.contains(pkgName)) { - final int count = mInstalledThemes.size(); - final int index = mInstalledThemes.indexOf(pkgName); - // reposition all the fragments after the one being removed - for (int i = index + 1; i < count; i++) { - mRepositionedFragments.put(mInstalledThemes.get(i), i - 1); - } - // Now remove this theme and add it to mRepositionedFragments with POSITION_NONE - mInstalledThemes.remove(pkgName); - mRepositionedFragments.put(pkgName, POSITION_NONE); - // now we can call notifyDataSetChanged() - notifyDataSetChanged(); - } - } - } - - private class TypefacePreloadTask extends AsyncTask { - - @Override - protected Object doInBackground(Object[] params) { - String[] projection = { ThemesColumns.PKG_NAME }; - String selection = ThemesColumns.MODIFIES_FONTS + "=?"; - String[] selectionArgs = { "1" }; - Cursor c = getContentResolver().query(ThemesColumns.CONTENT_URI, projection, selection, - selectionArgs, null); - if (c != null) { - while (c.moveToNext()) { - mTypefaceHelperCache.getHelperForTheme(ChooserActivity.this, c.getString(0)); - } - c.close(); - } - return null; - } - } - - /** - * Internal delete callback from the system - */ - class PackageDeleteObserver extends IPackageDeleteObserver.Stub { - public void packageDeleted(final String packageName, int returnCode) throws RemoteException { - if (returnCode == PackageManager.DELETE_SUCCEEDED) { - Log.d(TAG, "Delete succeeded"); - mHandler.post(new Runnable() { - @Override - public void run() { - mAdapter.removeTheme(packageName); - } - }); - } else { - Log.e(TAG, "Delete failed with returnCode " + returnCode); - } - } - } - - public void expandContentAndAnimateLockScreenCardIn() { - mHandler.post(new Runnable() { - @Override - public void run() { - expand(); - mHandler.postDelayed(new Runnable() { - @Override - public void run() { - AnimatorSet set = new AnimatorSet(); - set.play(ObjectAnimator.ofFloat(mContainer, "alpha", 0f, 1f) - .setDuration(ANIMATE_CARDS_IN_DURATION)); - set.setStartDelay(mAnimateContentInDelay); - set.start(); - mContainer.setVisibility(View.VISIBLE); - getCurrentFragment().showLockScreenCard(); - } - }, ANIMATE_CARDS_IN_DURATION); - } - }); - } - - private void launchAppThemer() { - PreferenceUtils.setShowPerAppThemeNewTag(ChooserActivity.this, false); - Intent intent = new Intent(ChooserActivity.this, PerAppThemingWindow.class); - startService(intent); - finish(); - } - - private void requestSystemWindowPermission() { - Intent intent = new Intent (Settings.ACTION_MANAGE_OVERLAY_PERMISSION, - Uri.parse("package:" + getPackageName())); - startActivityForResult(intent, REQUEST_SYSTEM_WINDOW_PERMISSION); - } -} diff --git a/src/org/cyanogenmod/theme/chooser/ComponentCardView.java b/src/org/cyanogenmod/theme/chooser/ComponentCardView.java deleted file mode 100644 index 54d97c9..0000000 --- a/src/org/cyanogenmod/theme/chooser/ComponentCardView.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (C) 2016 Cyanogen, Inc. - * Copyright (C) 2016 The CyanogenMod Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.cyanogenmod.theme.chooser; - -import android.animation.Animator; -import android.animation.AnimatorSet; -import android.animation.IntEvaluator; -import android.animation.ObjectAnimator; -import android.animation.ValueAnimator; -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.TransitionDrawable; -import android.util.AttributeSet; -import android.view.View; -import android.view.ViewOverlay; -import android.widget.LinearLayout; -import android.widget.TextView; - -public class ComponentCardView extends LinearLayout { - public static final int CARD_FADE_DURATION = 300; - - private static final float SEMI_OPAQUE_ALPHA = 0.4f; - - protected TextView mLabel; - protected View mEmptyView; - protected View mContentView; - - // Expanded Padding - int mExpandPadLeft; - int mExpandPadTop; - int mExpandPadRight; - int mExpandPadBottom; - - // The background drawable is returning an alpha of 0 regardless of what we set it to - // so this will help us keep track of what the drawable's alpha is at. - private int mBackgroundAlpha = 255; - - public ComponentCardView(Context context) { - this(context, null); - } - - public ComponentCardView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public ComponentCardView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - setEnabled(false); - } - - @Override - protected void onFinishInflate() { - mLabel = (TextView) findViewById(R.id.label); - - Resources r = getContext().getResources(); - mExpandPadLeft = - (int) r.getDimension(R.dimen.card_padding_left_right) + getPaddingLeft(); - mExpandPadTop = - (int) r.getDimension(R.dimen.card_padding_top) + getPaddingTop(); - mExpandPadRight = - (int) r.getDimension(R.dimen.card_padding_left_right) + getPaddingRight(); - mExpandPadBottom = - (int) r.getDimension(R.dimen.card_padding_bottom) + getPaddingBottom(); - mEmptyView = findViewById(R.id.empty); - mContentView = findViewById(R.id.content); - } - - public void expand(boolean showLabel) { - setEnabled(true); - TransitionDrawable bg = null; - if (getBackground() instanceof TransitionDrawable) { - bg = (TransitionDrawable) getBackground(); - } - if (bg != null) { - Rect paddingRect = new Rect(); - bg.getPadding(paddingRect); - } - - setPadding(mExpandPadLeft, 0, mExpandPadRight, mExpandPadBottom); - - if (mLabel != null) { - mLabel.setAlpha(showLabel ? 1f : 0f); - mLabel.setVisibility(View.VISIBLE); - } - } - - public void animateExpand() { - if (getBackground() instanceof TransitionDrawable) { - TransitionDrawable background = (TransitionDrawable) getBackground(); - if (mLabel != null) { - mLabel.setVisibility(View.VISIBLE); - mLabel.setAlpha(0f); - mLabel.animate().alpha(1f).setDuration(CARD_FADE_DURATION).start(); - } - background.startTransition(CARD_FADE_DURATION); - } - } - - public void collapse() { - setEnabled(false); - if (mLabel != null) { - mLabel.setVisibility(View.GONE); - } - setPadding(0, 0, 0, 0); - } - - public void animateFadeOut() { - if (mLabel != null) { - mLabel.animate().alpha(0f).setDuration(CARD_FADE_DURATION); - } - - if (getBackground() instanceof TransitionDrawable) { - TransitionDrawable background = (TransitionDrawable) getBackground(); - background.reverseTransition(CARD_FADE_DURATION); - } - } - - /** - * Animates the card background and the title to 20% opacity. - */ - public void animateCardFadeOut() { - this.animate().alpha(SEMI_OPAQUE_ALPHA).setDuration(CARD_FADE_DURATION); - } - - /** - * Animates the card background and the title back to full opacity. - */ - public void animateCardFadeIn() { - this.animate().alpha(1f).setDuration(CARD_FADE_DURATION); - } - - /** - * Animates a change in the content of the card - * @param v View in card to animate - * @param overlay Drawable to animate as a ViewOverlay - * @param duration Duration of animation - */ - public void animateContentChange(View v, final Drawable overlay, long duration) { - final ViewOverlay viewOverlay = this.getOverlay(); - viewOverlay.add(overlay); - final int x = getRelativeLeft(v); - final int y = getRelativeTop(v); - final int width = v.getWidth(); - final int height = v.getHeight(); - overlay.setBounds(x, y, x + v.getWidth(), y + v.getHeight()); - - final ValueAnimator overlayAnimator = ValueAnimator.ofFloat(1f, 0f); - overlayAnimator.setDuration(duration); - overlayAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - float value = (Float) animation.getAnimatedValue(); - overlay.setAlpha((int) (255 * value)); - int newWidth = (int) (value * width); - int newHeight = (int) (value * height); - int dw = (width - newWidth) / 2; - int dh = (height - newHeight) / 2; - overlay.setBounds(x + dw, y + dh, x + dw + newWidth, y + dh + newHeight); - } - }); - overlayAnimator.addListener(new Animator.AnimatorListener() { - @Override - public void onAnimationStart(Animator animation) {} - - @Override - public void onAnimationEnd(Animator animation) { - // Clear out the ViewOverlay now that we are done animating - viewOverlay.clear(); - } - - @Override - public void onAnimationCancel(Animator animation) {} - - @Override - public void onAnimationRepeat(Animator animation) {} - }); - - AnimatorSet set = new AnimatorSet(); - set.play(ObjectAnimator.ofFloat(v, "alpha", 0f, 1f)) - .with(ObjectAnimator.ofFloat(v, "scaleX", 0f, 1f)) - .with(ObjectAnimator.ofFloat(v, "scaleY", 0f, 1f)); - set.setDuration(duration); - - set.start(); - overlayAnimator.start(); - } - - public void setEmptyViewEnabled(boolean enabled) { - if (mEmptyView != null) { - mEmptyView.setVisibility(enabled ? View.VISIBLE : View.GONE); - } - if (mContentView != null) { - mContentView.setVisibility(enabled ? View.INVISIBLE : View.VISIBLE); - } - } - - public boolean isShowingEmptyView() { - return mEmptyView != null && mEmptyView.getVisibility() == View.VISIBLE; - } - - private int getRelativeTop(View v) { - if (v.getParent() == this) { - return v.getTop(); - } else { - return v.getTop() + ((View) v.getParent()).getTop(); - } - } - - private int getRelativeLeft(View v) { - if (v.getParent() == this) { - return v.getLeft(); - } else { - return v.getLeft() + ((View) v.getParent()).getLeft(); - } - } -} diff --git a/src/org/cyanogenmod/theme/chooser/ComponentSelector.java b/src/org/cyanogenmod/theme/chooser/ComponentSelector.java deleted file mode 100644 index ad0b68c..0000000 --- a/src/org/cyanogenmod/theme/chooser/ComponentSelector.java +++ /dev/null @@ -1,934 +0,0 @@ -/* - * Copyright (C) 2016 Cyanogen, Inc. - * Copyright (C) 2016 The CyanogenMod Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.cyanogenmod.theme.chooser; - -import android.content.Context; -import android.content.pm.PackageManager; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.database.ContentObserver; -import android.database.Cursor; -import android.database.MatrixCursor; -import android.graphics.Typeface; -import android.graphics.drawable.BitmapDrawable; -import android.media.MediaPlayer; -import android.media.RingtoneManager; -import android.os.AsyncTask; -import android.os.Bundle; -import android.support.v4.app.FragmentActivity; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.Loader; -import android.text.TextUtils; -import android.util.AttributeSet; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.animation.Animation; -import android.view.animation.Animation.AnimationListener; -import android.view.animation.AnimationUtils; -import android.widget.ComponentSelectorLinearLayout; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; -import android.widget.Toast; - -import org.cyanogenmod.theme.util.AudioUtils; -import org.cyanogenmod.theme.util.CursorLoaderHelper; -import org.cyanogenmod.theme.util.ThemedTypefaceHelper; -import org.cyanogenmod.theme.util.TypefaceHelperCache; -import org.cyanogenmod.theme.util.Utils; - -import cyanogenmod.providers.ThemesContract; -import cyanogenmod.providers.ThemesContract.PreviewColumns; -import cyanogenmod.providers.ThemesContract.ThemesColumns; - -import java.util.Map; - -import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_ALARMS; -import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_BOOT_ANIM; -import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_LAUNCHER; -import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_LIVE_LOCK_SCREEN; -import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_LOCKSCREEN; -import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_NOTIFICATIONS; -import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_OVERLAYS; -import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_RINGTONES; -import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_STATUS_BAR; -import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_NAVIGATION_BAR; -import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_ICONS; -import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_FONTS; - -import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_STATUS_BAR; -import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_FONT; -import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_ICONS; -import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_WALLPAPER; -import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_NAVIGATION_BAR; -import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_LOCKSCREEN; -import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_STYLE; -import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_BOOT_ANIMATION; -import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_RINGTONE; -import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_NOTIFICATION; -import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_ALARM; - -public class ComponentSelector extends LinearLayout - implements LoaderManager.LoaderCallbacks { - private static final String TAG = ComponentSelector.class.getSimpleName(); - - public static final boolean DEBUG_SELECTOR = false; - - public static final String EXTERNAL_WALLPAPER = "external"; - - public static final String MOD_LOCK = "mod_lock"; - - private static final int EXTRA_WALLPAPER_COMPONENTS = 2; - - private static final int EXTRA_LOCK_SCREEN_WALLPAPER_COMPONENTS = 3; - - protected static final long DEFAULT_COMPONENT_ID = 0; - - private Context mContext; - private LayoutInflater mInflater; - private ComponentSelectorLinearLayout mContent; - private LinearLayout.LayoutParams mItemParams; - private LinearLayout.LayoutParams mSoundItemParams = - new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, 0, 1.0f); - - private String mComponentType; - private int mBatteryStyle; - private int mItemsPerPage; - private String mAppliedComponentPkgName; - private String mSelectedComponentPkgName; - private long mSelectedComponentId; - - // animations for bringing selector in and out of view - private Animation mAnimateIn; - private Animation mAnimateOut; - - private OnItemClickedListener mListener; - - private OnOpenCloseListener mOpenCloseListener; - - private MediaPlayer mMediaPlayer; - private ImageView mCurrentPlayPause; - - private TypefaceHelperCache mTypefaceCache; - - private ThemesObserver mThemesObserver; - - public static final String IS_LIVE_LOCK_SCREEN_VIEW = "is_live_lock_screen_view"; - private View mPrevLockScreenView; - - public ComponentSelector(Context context, AttributeSet attrs) { - super(context, attrs); - - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ComponentSelector); - mItemsPerPage = a.getInt(R.styleable.ComponentSelector_itemsPerPage, - context.getResources().getInteger(R.integer.default_items_per_page)); - a.recycle(); - - mContext = context; - mInflater = LayoutInflater.from(context); - // TODO: Load from settings once available - mBatteryStyle = 0; /*Settings.System.getInt(context.getContentResolver(), - Settings.System.STATUS_BAR_BATTERY_STYLE, 0);*/ - - mAnimateIn = AnimationUtils.loadAnimation(mContext, - R.anim.component_selection_animate_in); - mAnimateOut = AnimationUtils.loadAnimation(mContext, - R.anim.component_selection_animate_out); - mAnimateIn.setAnimationListener(new AnimationListener() { - @Override - public void onAnimationStart(Animation animation) { - } - - @Override - public void onAnimationEnd(Animation animation) { - if (mOpenCloseListener != null) mOpenCloseListener.onSelectorOpened(); - } - - @Override - public void onAnimationRepeat(Animation animation) { - } - }); - mAnimateOut.setAnimationListener(new AnimationListener() { - @Override - public void onAnimationStart(Animation animation) { - if (mOpenCloseListener != null) mOpenCloseListener.onSelectorClosing(); - } - - @Override - public void onAnimationEnd(Animation animation) { - setVisibility(View.GONE); - } - - @Override - public void onAnimationRepeat(Animation animation) { - } - }); - mMediaPlayer = new MediaPlayer(); - mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { - @Override - public void onCompletion(MediaPlayer mp) { - if (mCurrentPlayPause != null) { - mCurrentPlayPause.setImageResource(R.drawable.media_sound_selector_preview); - mCurrentPlayPause = null; - } - } - }); - mTypefaceCache = TypefaceHelperCache.getInstance(); - mThemesObserver = new ThemesObserver(); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - mContent = (ComponentSelectorLinearLayout) findViewById(R.id.content); - setEnabled(false); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - mThemesObserver.register(); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - mThemesObserver.unregister(); - } - - @Override - protected void onWindowVisibilityChanged(int visibility) { - super.onWindowVisibilityChanged(visibility); - // Window visibility transitions as follows - // VISIBLE -> INVISIBLE -> GONE - // GONE -> INVISIBLE -> VISIBLE - if (visibility == View.GONE) { - mThemesObserver.unregister(); - } else if (visibility == View.VISIBLE) { - mThemesObserver.register(); - } - } - - public void resetComponentType() { - mComponentType = null; - } - - public void setComponentType(String component) { - setComponentType(component, null, DEFAULT_COMPONENT_ID); - } - - public void setComponentType(String component, String selectedPkgName) { - setComponentType(component, null, DEFAULT_COMPONENT_ID); - } - - public void setComponentType(String component, String selectedPkgName, - long selectedComponentId) { - mSelectedComponentPkgName = selectedPkgName; - mSelectedComponentId = selectedComponentId; - if (mComponentType == null || !mComponentType.equals(component)) { - mContent.removeAllViews(); - mComponentType = component; - ((FragmentActivity) mContext).getSupportLoaderManager().restartLoader( - getLoaderIdFromComponent(component), null, this); - } else if (mComponentType != null) { - int count = mContent.getChildCount(); - final Resources res = getResources(); - boolean highlightTitle; - Map selectedComponents = null; - if (mComponentType.equals(MODIFIES_LOCKSCREEN)) { - selectedComponents = ((ChooserActivity)mContext) - .getSelectedComponentsMap(); - } - for (int i = 0; i < count; i++) { - final View child = mContent.getChildAt(i); - final TextView tv = (TextView) child.findViewById(R.id.title); - // The child itself may have the tag, or in the case of sounds its the grandchild, - // either way the parent of the textview will have the pkgName in its tag - final View viewWithTag = (View) tv.getParent(); - final String pkgName = (String) viewWithTag.getTag(R.id.tag_key_package_name); - Long cmpntId = (Long) viewWithTag.getTag(R.id.tag_key_component_id); - if (cmpntId == null) { - cmpntId = DEFAULT_COMPONENT_ID; - } - Boolean isLLS = (Boolean) viewWithTag.getTag(R.id.tag_key_live_lock_screen); - highlightTitle = false; - if (selectedComponents != null && isLLS != null) { - if ((TextUtils.equals(selectedComponents.get(MODIFIES_LOCKSCREEN), pkgName) - && !isLLS) || (TextUtils.equals(selectedComponents.get( - MODIFIES_LIVE_LOCK_SCREEN), pkgName) && isLLS)) { - highlightTitle = true; - } - } else if (pkgName.equals(selectedPkgName) && cmpntId == selectedComponentId) { - highlightTitle = true; - } - if (highlightTitle) { - tv.setTextColor(res.getColor(R.color.component_selection_current_text_color)); - } else { - tv.setTextColor(res.getColor(android.R.color.white)); - } - } - } - } - - public String getComponentType() { - return mComponentType; - } - - public void setNumItemsPerPage(int itemsPerPage) { - if (mItemsPerPage != itemsPerPage) { - mItemsPerPage = itemsPerPage; - } - } - - public void setHeight(int height) { - ViewGroup.LayoutParams params = mContent.getLayoutParams(); - if (params.height != height) { - params.height = height; - mContent.setLayoutParams(params); - requestLayout(); - } - } - - public void show(String componentType, int itemsPerPage, int height) { - show(componentType, null, itemsPerPage, height); - } - - public void show(String componentType, String selectedPkgName, int itemsPerPage, int height) { - show(componentType, selectedPkgName, DEFAULT_COMPONENT_ID, itemsPerPage, height); - } - - public void show(String componentType, String selectedPkgName, long selectedComponentId, - int itemsPerPage, int height) { - setNumItemsPerPage(itemsPerPage); - setHeight(height); - setComponentType(componentType, selectedPkgName, selectedComponentId); - show(); - } - - public void show() { - if (getVisibility() == View.GONE) { - setEnabled(true); - setVisibility(View.VISIBLE); - startAnimation(mAnimateIn); - } - } - - public void hide() { - if (getVisibility() == View.VISIBLE && isEnabled()) { - setEnabled(false); - startAnimation(mAnimateOut); - } - if (mMediaPlayer != null && mMediaPlayer.isPlaying()) mMediaPlayer.stop(); - } - - private int getLoaderIdFromComponent(String component) { - if (MODIFIES_STATUS_BAR.equals(component)) { - return LOADER_ID_STATUS_BAR; - } - if (MODIFIES_NAVIGATION_BAR.equals(component)) { - return LOADER_ID_NAVIGATION_BAR; - } - if (MODIFIES_FONTS.equals(component)) { - return LOADER_ID_FONT; - } - if (MODIFIES_ICONS.equals(component)) { - return LOADER_ID_ICONS; - } - if (MODIFIES_OVERLAYS.equals(component)) { - return LOADER_ID_STYLE; - } - if (MODIFIES_LAUNCHER.equals(component)) { - return LOADER_ID_WALLPAPER; - } - if (MODIFIES_BOOT_ANIM.equals(component)) { - return LOADER_ID_BOOT_ANIMATION; - } - if (MODIFIES_RINGTONES.equals(component)) { - return LOADER_ID_RINGTONE; - } - if (MODIFIES_NOTIFICATIONS.equals(component)) { - return LOADER_ID_NOTIFICATION; - } - if (MODIFIES_ALARMS.equals(component)) { - return LOADER_ID_ALARM; - } - if (MODIFIES_LOCKSCREEN.equals(component)) { - return LOADER_ID_LOCKSCREEN; - } - return -1; - } - - @Override - public Loader onCreateLoader(int id, Bundle args) { - return CursorLoaderHelper.componentSelectorCursorLoader(mContext, id); - } - - @Override - public void onLoadFinished(Loader loader, final Cursor data) { - int currentLoaderId = loader.getId(); - int count = data.getCount(); - int screenWidth = mContext.getResources().getDisplayMetrics().widthPixels; - final Resources res = getResources(); - int dividerPadding = res.getDimensionPixelSize(R.dimen.component_divider_padding_top); - int dividerHeight = res.getDimensionPixelSize(R.dimen.component_divider_height); - MatrixCursor lockScreenMatrixCursor = null; - - switch (currentLoaderId) { - case LOADER_ID_ALARM: - case LOADER_ID_NOTIFICATION: - case LOADER_ID_RINGTONE: - mItemParams = new LayoutParams(screenWidth, - ViewGroup.LayoutParams.MATCH_PARENT); - // Sounds are a special case where there are two items laid out - // vertically. This layout is added as a single item so we need to - // adjust the count by dividing by the number of items per page and - // rounding up so we include all items. - count = (int) Math.ceil((double)count / mItemsPerPage); - mContent.setShowDividers(LinearLayout.SHOW_DIVIDER_NONE); - break; - case LOADER_ID_BOOT_ANIMATION: - dividerPadding = res.getDimensionPixelSize( - R.dimen.component_divider_padding_top_bootani); - dividerHeight = res.getDimensionPixelSize(R.dimen.component_divider_height_bootani); - // fall through to default - default: - mItemParams = new LayoutParams(screenWidth / mItemsPerPage, - ViewGroup.LayoutParams.MATCH_PARENT); - if (currentLoaderId == LOADER_ID_WALLPAPER || - currentLoaderId == LOADER_ID_LOCKSCREEN) { - count += EXTRA_WALLPAPER_COMPONENTS; - } - - if (currentLoaderId == LOADER_ID_LOCKSCREEN) { - lockScreenMatrixCursor = splitLockScreenCursor(data); - if (lockScreenMatrixCursor != null) { - count = lockScreenMatrixCursor.getCount() + EXTRA_WALLPAPER_COMPONENTS; - } - } - - mContent.setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE); - break; - } - - mContent.setDividerPadding(dividerPadding); - mContent.setDividerHeight(dividerHeight); - - new LoadItemsTask().execute((lockScreenMatrixCursor != null) - ? lockScreenMatrixCursor : data, count); - } - - /* Some themes might contain a lock wallpaper AND a live lock screen. - * ThemesProvider will return one single row containing both thumbnail paths - * (ThemesProvider groups by theme_id) so we need to create a cursor on the - * fly to split that row into 2 to properly generate a view for each thumbnail - */ - private MatrixCursor splitLockScreenCursor(Cursor data) { - int lockWallPaperThumbnailIndx, llsThumbnailIndx, pkgIndx; - String lockWallPaperThumbnail, liveLockScreenThumbnail, pkgName; - MatrixCursor lockScreenMatrixCursor; - int needToSplitRowAt = -1; - - lockWallPaperThumbnailIndx = data.getColumnIndex(PreviewColumns.LOCK_WALLPAPER_THUMBNAIL); - llsThumbnailIndx = data.getColumnIndex(PreviewColumns.LIVE_LOCK_SCREEN_THUMBNAIL); - pkgIndx = data.getColumnIndex(ThemesColumns.PKG_NAME); - - if (lockWallPaperThumbnailIndx < 0 || llsThumbnailIndx < 0 || pkgIndx < 0) { - //An invalid cursor was provided, we can't continue processing - Log.e(TAG, "Failed to process cursor due to missing columns"); - return null; - } - - //Let's find out if we really need to allocate a MatrixCursor. - //If we find at least one row with valid data in lock_wallpaper_thumbnail AND - //live_lock_screen_thumbnail it means we do. - data.moveToPosition(-1); - while (data.moveToNext()) { - lockWallPaperThumbnail = data.getString(lockWallPaperThumbnailIndx); - liveLockScreenThumbnail = data.getString(llsThumbnailIndx); - if (!TextUtils.isEmpty(lockWallPaperThumbnail) - && !TextUtils.isEmpty(liveLockScreenThumbnail)) { - needToSplitRowAt = data.getPosition(); - break; - } - } - - if (needToSplitRowAt == -1) return null; - - lockScreenMatrixCursor = new MatrixCursor(data.getColumnNames()); - //Clone all the *regular* rows up to needToSplitRowAt - for (int indx = 0; indx < needToSplitRowAt; indx++) { - data.moveToPosition(indx); - lockScreenMatrixCursor.addRow(CursorLoaderHelper.getRowFromCursor(data)); - } - if (needToSplitRowAt == 0) { - data.moveToPosition(-1); - } - while (data.moveToNext()) { - lockWallPaperThumbnail = data.getString(lockWallPaperThumbnailIndx); - liveLockScreenThumbnail = data.getString(llsThumbnailIndx); - if (!TextUtils.isEmpty(lockWallPaperThumbnail) - && !TextUtils.isEmpty(liveLockScreenThumbnail)) { - pkgName = data.getString(pkgIndx); - - MatrixCursor.RowBuilder lockWallpaperRow = lockScreenMatrixCursor.newRow(); - MatrixCursor.RowBuilder liveLockScreenRow = lockScreenMatrixCursor.newRow(); - - for (String col : data.getColumnNames()) { - if (TextUtils.equals(col, PreviewColumns.LOCK_WALLPAPER_THUMBNAIL)) { - lockWallpaperRow.add(PreviewColumns.LOCK_WALLPAPER_THUMBNAIL, - lockWallPaperThumbnail); - liveLockScreenRow.add(PreviewColumns.LOCK_WALLPAPER_THUMBNAIL, null); - } else if (TextUtils.equals(col, PreviewColumns.LIVE_LOCK_SCREEN_THUMBNAIL)) { - lockWallpaperRow.add(PreviewColumns.LIVE_LOCK_SCREEN_THUMBNAIL, null); - liveLockScreenRow.add(PreviewColumns.LIVE_LOCK_SCREEN_THUMBNAIL, - liveLockScreenThumbnail); - } else if (TextUtils.equals(col, MODIFIES_LIVE_LOCK_SCREEN)) { - lockWallpaperRow.add(MODIFIES_LIVE_LOCK_SCREEN, 0); - liveLockScreenRow.add(MODIFIES_LIVE_LOCK_SCREEN, 1); - } else { - int colIndx = data.getColumnIndex(col); - lockWallpaperRow.add(col, CursorLoaderHelper.getFieldValueFromRow(data, - colIndx)); - liveLockScreenRow.add(col, CursorLoaderHelper.getFieldValueFromRow(data, - colIndx)); - } - } - } else { - //This is a regular row, so just clone it - lockScreenMatrixCursor.addRow(CursorLoaderHelper.getRowFromCursor(data)); - } - } - return lockScreenMatrixCursor; - } - - @Override - public void onLoaderReset(Loader loader) { - } - - public void setOnItemClickedListener(OnItemClickedListener listener) { - mListener = listener; - } - - public void setOnOpenCloseListener(OnOpenCloseListener listener) { - mOpenCloseListener = listener; - } - - private View newView(Cursor cursor, int position, ViewGroup container) { - if (MODIFIES_STATUS_BAR.equals(mComponentType)) { - return newStatusBarView(cursor, container, position); - } - if (MODIFIES_NAVIGATION_BAR.equals(mComponentType)) { - return newNavBarView(cursor, container, position); - } - if (MODIFIES_FONTS.equals(mComponentType)) { - return newFontView(cursor, container, position); - } - if (MODIFIES_ICONS.equals(mComponentType)) { - return newIconView(cursor, container, position); - } - if (MODIFIES_OVERLAYS.equals(mComponentType)) { - return newStyleView(cursor, container, position); - } - if (MODIFIES_LAUNCHER.equals(mComponentType)) { - return newWallpapersView(cursor, container, position, - cursor.getColumnIndex(PreviewColumns.WALLPAPER_THUMBNAIL), false, - EXTRA_WALLPAPER_COMPONENTS); - } - if (MODIFIES_BOOT_ANIM.equals(mComponentType)) { - return newBootanimationView(cursor, container, position); - } - if (MODIFIES_RINGTONES.equals(mComponentType) || - MODIFIES_NOTIFICATIONS.equals(mComponentType) || - MODIFIES_ALARMS.equals(mComponentType)) { - return newSoundView(cursor, container, position, mComponentType); - } - if (MODIFIES_LOCKSCREEN.equals(mComponentType)) { - boolean isLiveLockScreen = false; - if (position >= EXTRA_LOCK_SCREEN_WALLPAPER_COMPONENTS) { - cursor.moveToPosition(position - EXTRA_LOCK_SCREEN_WALLPAPER_COMPONENTS); - int liveLockIndex = cursor.getColumnIndex(MODIFIES_LIVE_LOCK_SCREEN); - isLiveLockScreen = liveLockIndex >= 0 && - cursor.getInt(liveLockIndex) == 1; - } - int index = isLiveLockScreen - ? cursor.getColumnIndex(PreviewColumns.LIVE_LOCK_SCREEN_THUMBNAIL) - : cursor.getColumnIndex(PreviewColumns.LOCK_WALLPAPER_THUMBNAIL); - return newWallpapersView(cursor, container, position, index, isLiveLockScreen, - EXTRA_LOCK_SCREEN_WALLPAPER_COMPONENTS); - } - return null; - } - - private View newStatusBarView(Cursor cursor, ViewGroup parent, int position) { - cursor.moveToPosition(position); - View v = mInflater.inflate(R.layout.status_bar_component_selection_item, - parent, false); - int wifiIndex = cursor.getColumnIndex(PreviewColumns.STATUSBAR_WIFI_ICON); - int signalIndex = cursor.getColumnIndex(PreviewColumns.STATUSBAR_SIGNAL_ICON); - int bluetoothIndex = cursor.getColumnIndex(PreviewColumns.STATUSBAR_BLUETOOTH_ICON); - int batteryIndex = cursor.getColumnIndex(Utils.getBatteryIndex(mBatteryStyle)); - int backgroundIndex = cursor.getColumnIndex(PreviewColumns.STATUSBAR_BACKGROUND); - int pkgNameIndex = cursor.getColumnIndex(ThemesContract.ThemesColumns.PKG_NAME); - - ((ImageView) v.findViewById(R.id.slot1)).setImageBitmap( - Utils.loadBitmapBlob(cursor, wifiIndex)); - ((ImageView) v.findViewById(R.id.slot2)).setImageBitmap( - Utils.loadBitmapBlob(cursor, signalIndex)); - ((ImageView) v.findViewById(R.id.slot3)).setImageBitmap( - Utils.loadBitmapBlob(cursor, bluetoothIndex)); - ((ImageView) v.findViewById(R.id.slot4)).setImageBitmap( - Utils.loadBitmapBlob(cursor, batteryIndex)); - setTitle(((TextView) v.findViewById(R.id.title)), cursor); - v.findViewById(R.id.container).setBackground( - new BitmapDrawable(Utils.loadBitmapBlob(cursor, backgroundIndex))); - v.setTag(R.id.tag_key_package_name, cursor.getString(pkgNameIndex)); - v.setOnClickListener(mItemClickListener); - return v; - } - - private View newNavBarView(Cursor cursor, ViewGroup parent, int position) { - cursor.moveToPosition(position); - View v = mInflater.inflate(R.layout.navigation_bar_component_selection_item, parent, - false); - int backIndex = cursor.getColumnIndex(PreviewColumns.NAVBAR_BACK_BUTTON); - int backgroundIndex = cursor.getColumnIndex(PreviewColumns.STATUSBAR_BACKGROUND); - int pkgNameIndex = cursor.getColumnIndex(ThemesContract.ThemesColumns.PKG_NAME); - - ((ImageView) v.findViewById(R.id.back)).setImageBitmap( - Utils.loadBitmapBlob(cursor, backIndex)); - setTitle(((TextView) v.findViewById(R.id.title)), cursor); - v.findViewById(R.id.container).setBackground( - new BitmapDrawable(Utils.loadBitmapBlob(cursor, backgroundIndex))); - v.setTag(R.id.tag_key_package_name, cursor.getString(pkgNameIndex)); - v.setOnClickListener(mItemClickListener); - return v; - } - - private View newFontView(Cursor cursor, ViewGroup parent, int position) { - cursor.moveToPosition(position); - View v = mInflater.inflate(R.layout.font_component_selection_item, parent, false); - int pkgNameIndex = cursor.getColumnIndex(ThemesContract.ThemesColumns.PKG_NAME); - - TextView preview = (TextView) v.findViewById(R.id.text_preview); - String pkgName = cursor.getString(pkgNameIndex); - - ThemedTypefaceHelper helper = mTypefaceCache.getHelperForTheme(mContext, pkgName); - Typeface typefaceNormal = helper.getTypeface(Typeface.NORMAL); - preview.setTypeface(typefaceNormal); - - setTitle(((TextView) v.findViewById(R.id.title)), cursor); - v.setTag(R.id.tag_key_package_name, cursor.getString(pkgNameIndex)); - v.setOnClickListener(mItemClickListener); - return v; - } - - private View newIconView(Cursor cursor, ViewGroup parent, int position) { - cursor.moveToPosition(position); - View v = mInflater.inflate(R.layout.icon_component_selection_item, parent, - false); - int iconIndex = cursor.getColumnIndex(PreviewColumns.ICON_PREVIEW_1); - int pkgNameIndex = cursor.getColumnIndex(ThemesContract.ThemesColumns.PKG_NAME); - - ((ImageView) v.findViewById(R.id.icon)).setImageBitmap( - Utils.loadBitmapBlob(cursor, iconIndex)); - setTitle(((TextView) v.findViewById(R.id.title)), cursor); - v.setTag(R.id.tag_key_package_name, cursor.getString(pkgNameIndex)); - v.setOnClickListener(mItemClickListener); - return v; - } - - private View newStyleView(Cursor cursor, ViewGroup parent, int position) { - cursor.moveToPosition(position); - View v = mInflater.inflate(R.layout.icon_component_selection_item, parent, - false); - int styleIndex = cursor.getColumnIndex(PreviewColumns.STYLE_THUMBNAIL); - int pkgNameIndex = cursor.getColumnIndex(ThemesContract.ThemesColumns.PKG_NAME); - - ((ImageView) v.findViewById(R.id.icon)).setImageBitmap( - Utils.loadBitmapBlob(cursor, styleIndex)); - setTitle(((TextView) v.findViewById(R.id.title)), cursor); - v.setTag(R.id.tag_key_package_name, cursor.getString(pkgNameIndex)); - v.setOnClickListener(mItemClickListener); - return v; - } - - private View newWallpapersView(Cursor cursor, ViewGroup parent, int position, - int wallpaperIndex, boolean isLiveLockScreen, int numExtraComponents) { - View v = mInflater.inflate(R.layout.wallpaper_component_selection_item, parent, - false); - ImageView iv = (ImageView) v.findViewById(R.id.icon); - if (position == 0) { - iv.setImageResource(R.drawable.img_wallpaper_none); - v.setTag(R.id.tag_key_package_name, ""); - ((TextView) v.findViewById(R.id.title)).setText(R.string.wallpaper_none_title); - } else if (position == 1) { - iv.setImageResource(R.drawable.img_wallpaper_external); - v.setTag(R.id.tag_key_package_name, EXTERNAL_WALLPAPER); - ((TextView) v.findViewById(R.id.title)) - .setText(R.string.wallpaper_external_title); - } else if (numExtraComponents == EXTRA_LOCK_SCREEN_WALLPAPER_COMPONENTS && position == 2) { - // TODO: update drawable once the asset is provided by design - iv.setImageResource(android.R.drawable.ic_lock_lock); - v.setTag(R.id.tag_key_package_name, MOD_LOCK); - ((TextView) v.findViewById(R.id.title)) - .setText(R.string.mod_lock_title); - } else { - cursor.moveToPosition(position - numExtraComponents); - int pkgNameIndex = cursor.getColumnIndex(ThemesContract.ThemesColumns.PKG_NAME); - int cmpntIdIndex = cursor.getColumnIndex(PreviewColumns.COMPONENT_ID); - long cmpntId = (cmpntIdIndex >= 0) ? - cursor.getLong(cmpntIdIndex) : DEFAULT_COMPONENT_ID; - iv.setImageBitmap( - Utils.loadBitmapBlob(cursor, wallpaperIndex)); - setTitle(((TextView) v.findViewById(R.id.title)), cursor); - v.setTag(R.id.tag_key_package_name, cursor.getString(pkgNameIndex)); - v.setTag(R.id.tag_key_component_id, cmpntId); - v.setTag(R.id.tag_key_live_lock_screen, isLiveLockScreen); - v.findViewById(R.id.live_lock_screen_badge) - .setVisibility(isLiveLockScreen ? View.VISIBLE : View.GONE); - } - v.setOnClickListener(mItemClickListener); - return v; - } - - private View newBootanimationView(Cursor cursor, ViewGroup parent, int position) { - cursor.moveToPosition(position); - View v = mInflater.inflate(R.layout.bootani_component_selection_item, parent, - false); - int wallpaperIndex = cursor.getColumnIndex(PreviewColumns.BOOTANIMATION_THUMBNAIL); - int pkgNameIndex = cursor.getColumnIndex(ThemesContract.ThemesColumns.PKG_NAME); - - ((ImageView) v.findViewById(R.id.preview)).setImageBitmap( - Utils.loadBitmapBlob(cursor, wallpaperIndex)); - setTitle(((TextView) v.findViewById(R.id.title)), cursor); - v.setTag(R.id.tag_key_package_name, cursor.getString(pkgNameIndex)); - v.setOnClickListener(mItemClickListener); - return v; - } - - private View newSoundView(Cursor cursor, ViewGroup parent, int position, - final String component) { - LinearLayout container = (LinearLayout) mInflater.inflate( - R.layout.component_selection_sounds_pager_item, parent, false); - container.setWeightSum(mItemsPerPage); - for (int i = 0; i < mItemsPerPage; i++) { - int index = position * mItemsPerPage + i; - if (cursor.getCount() <= index) continue; - cursor.moveToPosition(index); - View v = mInflater.inflate(R.layout.sound_component_selection_item, parent, - false); - final int pkgNameIndex = cursor.getColumnIndex(ThemesContract.ThemesColumns.PKG_NAME); - - setTitle(((TextView) v.findViewById(R.id.title)), cursor); - v.setTag(R.id.tag_key_package_name, cursor.getString(pkgNameIndex)); - v.setOnClickListener(mItemClickListener); - container.addView(v, mSoundItemParams); - final View playButton = v.findViewById(R.id.play_button); - playButton.setTag(cursor.getString(pkgNameIndex)); - playButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - int type; - String pkgName = (String) v.getTag(); - if (component.equals(MODIFIES_RINGTONES)) { - type = RingtoneManager.TYPE_RINGTONE; - } else if (component.equals(MODIFIES_NOTIFICATIONS)) { - type = RingtoneManager.TYPE_NOTIFICATION; - } else { - type = RingtoneManager.TYPE_ALARM; - } - boolean shouldStop = playButton == mCurrentPlayPause; - try { - if (mMediaPlayer != null && mMediaPlayer.isPlaying()) { - mMediaPlayer.stop(); - if (mCurrentPlayPause != null) { - mCurrentPlayPause.setImageResource( - R.drawable.media_sound_selector_preview); - } - mCurrentPlayPause = null; - } - if (mCurrentPlayPause != playButton && !shouldStop) { - AudioUtils.loadThemeAudible(mContext, type, pkgName, - mMediaPlayer); - mMediaPlayer.start(); - mCurrentPlayPause = (ImageView) playButton; - mCurrentPlayPause.setImageResource( - R.drawable.media_sound_selector_stop); - } - } catch (PackageManager.NameNotFoundException e) { - Log.w(TAG, "Unable to play preview sound", e); - } - } - }); - } - - return container; - } - - private class LoadItemsTask extends AsyncTask { - - @Override - protected Void doInBackground(Object... params) { - Cursor c = (Cursor) params[0]; - int count = (Integer) params[1]; - for (int i = 0; i < count && !isCancelled(); i++) { - final View v = newView(c, i, mContent); - mContent.post(new Runnable() { - @Override - public void run() { - mContent.addView(v, mItemParams); - } - }); - } - - if (c instanceof MatrixCursor) { - c.close(); - } - - // destroy the loader now that we are done with it - ComponentSelector.this.post(new Runnable() { - @Override - public void run() { - ((FragmentActivity)mContext).getSupportLoaderManager().destroyLoader( - getLoaderIdFromComponent(mComponentType)); - } - }); - return null; - } - } - - private void setTitle(TextView titleView, Cursor cursor) { - String pkgName = cursor.getString(cursor.getColumnIndex(ThemesColumns.PKG_NAME)); - int cmpntIdIndex = cursor.getColumnIndex(PreviewColumns.COMPONENT_ID); - long cmpntId = DEFAULT_COMPONENT_ID; - if (cmpntIdIndex >= 0) { - cmpntId = cursor.getLong(cmpntIdIndex); - } - if (Utils.getDefaultThemePackageName(mContext).equals(pkgName)) { - titleView.setText(mContext.getString(R.string.default_tag_text)); - titleView.setTypeface(titleView.getTypeface(), Typeface.BOLD); - } else { - titleView.setText(cursor.getString(cursor.getColumnIndex(ThemesColumns.TITLE))); - } - boolean highlightTitle = false; - if (mComponentType.equals(MODIFIES_LOCKSCREEN)) { - Map selectedComponents = ((ChooserActivity)mContext) - .getSelectedComponentsMap(); - int isLLS = cursor.getInt(cursor.getColumnIndex(MODIFIES_LIVE_LOCK_SCREEN)); - if ((TextUtils.equals(selectedComponents.get(MODIFIES_LOCKSCREEN), pkgName) - && isLLS == 0) || (TextUtils.equals( - selectedComponents.get(MODIFIES_LIVE_LOCK_SCREEN), pkgName) && isLLS == 1)) { - highlightTitle = true; - } - } else if (pkgName.equals(mSelectedComponentPkgName) && cmpntId == mSelectedComponentId) { - highlightTitle = true; - } - if (highlightTitle) { - titleView.setTextColor(getResources().getColor( - R.color.component_selection_current_text_color)); - } - } - - private OnClickListener mItemClickListener = new OnClickListener() { - @Override - public void onClick(View v) { - long cmpntId = DEFAULT_COMPONENT_ID; - String pkgName = (String) v.getTag(R.id.tag_key_package_name); - Long cmpntIdTag = (Long) v.getTag(R.id.tag_key_component_id); - if (cmpntIdTag != null) { - cmpntId = cmpntIdTag; - } - Boolean isLiveLock = (Boolean) v.getTag(R.id.tag_key_live_lock_screen); - boolean isSamePkgButDifferentLockScreen = false; - Bundle params = null; - if (isLiveLock != null) { - params = new Bundle(); - params.putBoolean(IS_LIVE_LOCK_SCREEN_VIEW, isLiveLock); - - if (pkgName.equals(mSelectedComponentPkgName) && v != mPrevLockScreenView) { - isSamePkgButDifferentLockScreen = true; - } - mPrevLockScreenView = v; - } - if (DEBUG_SELECTOR) Toast.makeText(mContext, pkgName, Toast.LENGTH_SHORT).show(); - if (mListener != null && (isSamePkgButDifferentLockScreen || - !pkgName.equals(mSelectedComponentPkgName) || - pkgName.equals(EXTERNAL_WALLPAPER) || cmpntId != mSelectedComponentId)) { - mSelectedComponentPkgName = pkgName; - mSelectedComponentId = cmpntId; - mListener.onItemClicked(pkgName, cmpntId, params); - final int count = mContent.getChildCount(); - final Resources res = getResources(); - for (int i = 0; i < count; i++) { - final View child = mContent.getChildAt(i); - final TextView tv = (TextView) child.findViewById(R.id.title); - if (tv != null) { - if (child == v) { - tv.setTextColor( - res.getColor(R.color.component_selection_current_text_color)); - } else { - tv.setTextColor(res.getColor(android.R.color.white)); - } - } - } - } - } - }; - - private class ThemesObserver extends ContentObserver { - public ThemesObserver() { - super(null); - } - - public void register() { - mContext.getContentResolver().registerContentObserver( - ThemesColumns.CONTENT_URI, false, this); - } - - public void unregister() { - mContext.getContentResolver().unregisterContentObserver(this); - } - - @Override - public void onChange(boolean selfChange) { - // reload items by calling setComponentType() - if (mComponentType != null) { - final String componentType = mComponentType; - mComponentType = null; - mContent.post(new Runnable() { - @Override - public void run() { - setComponentType(componentType, mSelectedComponentPkgName); - } - }); - } - } - } - - public interface OnItemClickedListener { - public void onItemClicked(String pkgName, long componentId, Bundle params); - } - - public interface OnOpenCloseListener { - public void onSelectorOpened(); - public void onSelectorClosed(); - public void onSelectorClosing(); - } -} \ No newline at end of file diff --git a/src/org/cyanogenmod/theme/chooser/IconTransitionDrawable.java b/src/org/cyanogenmod/theme/chooser/IconTransitionDrawable.java deleted file mode 100644 index 96547f3..0000000 --- a/src/org/cyanogenmod/theme/chooser/IconTransitionDrawable.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2016 Cyanogen, Inc. - * Copyright (C) 2016 The CyanogenMod Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.cyanogenmod.theme.chooser; - -import android.graphics.Canvas; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.LayerDrawable; -import android.os.SystemClock; - -/** - * An extension of LayerDrawables that is intended to cross-fade between - * the first and second layer. To start the transition, call {@link #startTransition(int)}. To - * display just the first layer, call {@link #resetTransition()}. - *

- * It can be defined in an XML file with the <transition> element. - * Each Drawable in the transition is defined in a nested <item>. For more - * information, see the guide to Drawable Resources.

- * - * @attr ref android.R.styleable#LayerDrawableItem_left - * @attr ref android.R.styleable#LayerDrawableItem_top - * @attr ref android.R.styleable#LayerDrawableItem_right - * @attr ref android.R.styleable#LayerDrawableItem_bottom - * @attr ref android.R.styleable#LayerDrawableItem_drawable - * @attr ref android.R.styleable#LayerDrawableItem_id - * - */ -public class IconTransitionDrawable extends LayerDrawable { - - /** - * A transition is about to start. - */ - private static final int TRANSITION_STARTING = 0; - - /** - * The transition has started and the animation is in progress - */ - private static final int TRANSITION_RUNNING = 1; - - /** - * No transition will be applied - */ - private static final int TRANSITION_NONE = 2; - - /** - * The current state of the transition. One of {@link #TRANSITION_STARTING}, - * {@link #TRANSITION_RUNNING} and {@link #TRANSITION_NONE} - */ - private int mTransitionState = TRANSITION_NONE; - - private long mStartTimeMillis; - private int mFrom; - private int mTo; - private int mDuration; - private int mAlpha = 0; - private float mFromScale; - private float mToScale; - - /** - * Create a new transition drawable with the specified list of layers. At least - * 2 layers are required for this drawable to work properly. - */ - public IconTransitionDrawable(Drawable[] layers) { - super(layers); - } - - /** - * Begin the second layer on top of the first layer. - * - * @param durationMillis The length of the transition in milliseconds - */ - public void startTransition(int durationMillis) { - mFrom = 0; - mTo = 255; - mAlpha = 0; - mFromScale = 0f; - mToScale = 1.0f; - mDuration = durationMillis; - mTransitionState = TRANSITION_STARTING; - invalidateSelf(); - } - - /** - * Show only the first layer. - */ - public void resetTransition() { - mAlpha = 0; - mTransitionState = TRANSITION_NONE; - invalidateSelf(); - } - - @Override - public void draw(Canvas canvas) { - boolean done = true; - float scale = 0f; - - switch (mTransitionState) { - case TRANSITION_STARTING: - mStartTimeMillis = SystemClock.uptimeMillis(); - done = false; - mTransitionState = TRANSITION_RUNNING; - break; - - case TRANSITION_RUNNING: - if (mStartTimeMillis >= 0) { - float normalized = (float) - (SystemClock.uptimeMillis() - mStartTimeMillis) / mDuration; - done = normalized >= 1.0f; - normalized = Math.min(normalized, 1.0f); - mAlpha = (int) (mFrom + (mTo - mFrom) * normalized); - scale = mFromScale + (mToScale - mFromScale) * normalized; - } - break; - } - - final int alpha = mAlpha; - - if (done) { - // the setAlpha() calls below trigger invalidation and redraw. If we're done, just draw - // the appropriate drawable[s] and return - if (alpha == 0) { - getDrawable(0).draw(canvas); - } - if (alpha == 0xFF) { - getDrawable(1).draw(canvas); - - } - return; - } - - Drawable d; - d = getDrawable(0); - d.setAlpha(255 - alpha); - int cx = getIntrinsicWidth() / 2; - int cy = getIntrinsicHeight() / 2; - canvas.save(); - canvas.scale(1.0f - scale, 1.0f - scale, cx, cy); - d.draw(canvas); - canvas.restore(); - d.setAlpha(0xFF); - - if (alpha > 0) { - d = getDrawable(1); - d.setAlpha(alpha); - canvas.save(); - canvas.scale(scale, scale, cx, cy); - d.draw(canvas); - canvas.restore(); - d.setAlpha(0xFF); - } - - if (!done) { - invalidateSelf(); - } - } -} diff --git a/src/org/cyanogenmod/theme/chooser/MyThemeFragment.java b/src/org/cyanogenmod/theme/chooser/MyThemeFragment.java deleted file mode 100644 index 90a3f05..0000000 --- a/src/org/cyanogenmod/theme/chooser/MyThemeFragment.java +++ /dev/null @@ -1,707 +0,0 @@ -/* - * Copyright (C) 2016 Cyanogen, Inc. - * Copyright (C) 2016 The CyanogenMod Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.cyanogenmod.theme.chooser; - -import android.app.WallpaperManager; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.res.Resources; -import android.database.Cursor; -import android.graphics.Bitmap; -import android.graphics.Typeface; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.media.MediaPlayer; -import android.media.Ringtone; -import android.media.RingtoneManager; -import android.net.Uri; -import android.os.Bundle; -import android.support.v4.content.Loader; -import android.util.Log; -import android.util.MutableLong; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.MenuItem; -import android.view.SurfaceView; -import android.view.View; -import android.view.ViewGroup; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.TextView; - -import org.cyanogenmod.theme.util.AudioUtils; -import org.cyanogenmod.theme.util.CursorLoaderHelper; -import org.cyanogenmod.theme.util.PreferenceUtils; -import org.cyanogenmod.theme.util.ThemedTypefaceHelper; -import org.cyanogenmod.theme.util.TypefaceHelperCache; -import org.cyanogenmod.theme.util.Utils; - -import cyanogenmod.providers.ThemesContract; -import cyanogenmod.providers.ThemesContract.PreviewColumns; -import cyanogenmod.providers.ThemesContract.ThemesColumns; -import cyanogenmod.themes.ThemeChangeRequest; -import cyanogenmod.themes.ThemeChangeRequest.RequestType; -import cyanogenmod.themes.ThemeManager; - -import org.cyanogenmod.internal.util.ThemeUtils; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_ALL; - -public class MyThemeFragment extends ThemeFragment { - private static final String TAG = MyThemeFragment.class.getSimpleName(); - - private static final String ARG_BASE_THEME_PACKAGE_NAME = "baseThemePkgName"; - private static final String ARG_BASE_THEME_NAME = "baseThemeName"; - private static final String ARG_BASE_THEME_AUTHOR = "baseThemeAuthor"; - - private String mBaseThemeName; - private String mBaseThemeAuthor; - - private SurfaceView mSurfaceView; - - static MyThemeFragment newInstance(String baseThemePkgName, String baseThemeName, - String baseThemeAuthor, boolean skipLoadingAnim, - boolean animateToLockScreenCard) { - MyThemeFragment f = new MyThemeFragment(); - Bundle args = new Bundle(); - args.putString(ARG_PACKAGE_NAME, CURRENTLY_APPLIED_THEME); - args.putString(ARG_BASE_THEME_PACKAGE_NAME, baseThemePkgName); - args.putString(ARG_BASE_THEME_NAME, baseThemeName); - args.putString(ARG_BASE_THEME_AUTHOR, baseThemeAuthor); - args.putBoolean(ARG_SKIP_LOADING_ANIM, skipLoadingAnim); - args.putBoolean(ARG_ANIMATE_TO_LOCK_SCREEN_CARD, animateToLockScreenCard); - f.setArguments(args); - return f; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - final Context context = getActivity(); - ThemedTypefaceHelper helper = sTypefaceHelperCache.getHelperForTheme(context, - getAppliedFontPackageName()); - mTypefaceNormal = helper.getTypeface(Typeface.NORMAL); - mBaseThemePkgName = getArguments().getString(ARG_BASE_THEME_PACKAGE_NAME); - mBaseThemeName = getArguments().getString(ARG_BASE_THEME_NAME); - mBaseThemeAuthor = getArguments().getString(ARG_BASE_THEME_AUTHOR); - mShowLockScreenSelectorAfterContentLoaded = getArguments().getBoolean( - ARG_ANIMATE_TO_LOCK_SCREEN_CARD); - mSurfaceView = createSurfaceView(); - populateBaseThemeSupportedComponents(mBaseThemePkgName); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View v = super.onCreateView(inflater, container, savedInstanceState); - mThemeTagLayout.setAppliedTagEnabled(true); - if (mBaseThemePkgName.equals(Utils.getDefaultThemePackageName(getActivity()))) { - mThemeTagLayout.setDefaultTagEnabled(true); - } - if (PreferenceUtils.hasThemeBeenUpdated(getActivity(), mBaseThemePkgName)) { - mThemeTagLayout.setUpdatedTagEnabled(true); - } - mDelete.setVisibility(View.GONE); - setCustomized(isThemeCustomized()); - return v; - } - - @Override - public void onResume() { - super.onResume(); - if (!mExpanded && getLoaderManager().getLoader(0) != null) { - getLoaderManager().restartLoader(0, null, this); - } - - IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED); - getActivity().registerReceiver(mWallpaperChangeReceiver, filter); - } - - @Override - public void onPause() { - getActivity().unregisterReceiver(mWallpaperChangeReceiver); - super.onPause(); - } - - @Override - public void setUserVisibleHint(boolean isVisibleToUser) { - super.setUserVisibleHint(isVisibleToUser); - if (mThemeTagLayout == null) return; - - if (!isVisibleToUser) { - if (PreferenceUtils.hasThemeBeenUpdated(getActivity(), mBaseThemePkgName)) { - mThemeTagLayout.setUpdatedTagEnabled(true); - } - } else { - if (PreferenceUtils.hasThemeBeenUpdated(getActivity(), mBaseThemePkgName)) { - PreferenceUtils.removeUpdatedTheme(getActivity(), mBaseThemePkgName); - } - } - } - - @Override - protected boolean onPopupMenuItemClick(MenuItem item) { - switch(item.getItemId()) { - case R.id.menu_reset: - resetTheme(); - return true; - } - - return super.onPopupMenuItemClick(item); - } - - @Override - public void collapse(boolean applyTheme) { - super.collapse(applyTheme); - if (mSurfaceView != null) mSurfaceView.setVisibility(View.VISIBLE); - } - - @Override - public void expand() { - super.expand(); - if (mSurfaceView != null && mShadowFrame.indexOfChild(mSurfaceView) >= 0) { - mSurfaceView.setVisibility(View.GONE); - mWallpaper.setVisibility(View.INVISIBLE); - } - } - - @Override - public void performClick(boolean clickedOnContent) { - if (clickedOnContent) { - showCustomizeResetLayout(); - } else { - if (isShowingCustomizeResetLayout()) { - hideCustomizeResetLayout(); - } else { - super.performClick(clickedOnContent); - } - } - } - - @Override - public void setCurrentTheme(Map currentTheme, - MutableLong currentWallpaperComponentId) { - super.setCurrentTheme(currentTheme, currentWallpaperComponentId); - for (String key : currentTheme.keySet()) { - mSelectedComponentsMap.put(key, currentTheme.get(key)); - } - mSelectedWallpaperComponentId = currentWallpaperComponentId.value; - } - - @Override - public boolean componentsChanged() { - // If an external wallpaper/ls are set then something changed! - if (mExternalWallpaperUri != null || mExternalLockscreenUri != null) return true; - - for (String key : mSelectedComponentsMap.keySet()) { - String current = mCurrentTheme.get(key); - if (current == null || !current.equals(mSelectedComponentsMap.get(key))) { - return true; - } - if (ThemesColumns.MODIFIES_LAUNCHER.equals(key) && - mCurrentWallpaperComponentId.value != mSelectedWallpaperComponentId) { - return true; - } - } - return false; - } - - @Override - protected void applyThemeWhenPopulated(String pkgName, List components) { - super.applyThemeWhenPopulated(pkgName, components); - populateComponentsToApply(pkgName, components); - } - - private void populateComponentsToApply(String pkgName, List components) { - String selection = ThemesColumns.PKG_NAME + "=?"; - String[] selectionArgs = { pkgName }; - Cursor c = getActivity().getContentResolver().query(ThemesColumns.CONTENT_URI, - null, selection, selectionArgs, null); - if (c != null) { - if (c.getCount() > 0 && c.moveToFirst()) { - mSelectedComponentsMap.clear(); - if (c.getInt(c.getColumnIndex(ThemesColumns.MODIFIES_ALARMS)) == 1) { - mSelectedComponentsMap.put(ThemesColumns.MODIFIES_ALARMS, pkgName); - } - if (c.getInt(c.getColumnIndex(ThemesColumns.MODIFIES_BOOT_ANIM)) == 1) { - mSelectedComponentsMap.put(ThemesColumns.MODIFIES_BOOT_ANIM, pkgName); - } - if (c.getInt(c.getColumnIndex(ThemesColumns.MODIFIES_FONTS)) == 1) { - mSelectedComponentsMap.put(ThemesColumns.MODIFIES_FONTS, pkgName); - } - if (c.getInt(c.getColumnIndex(ThemesColumns.MODIFIES_ICONS)) == 1) { - mSelectedComponentsMap.put(ThemesColumns.MODIFIES_ICONS, pkgName); - } - if (c.getInt(c.getColumnIndex(ThemesColumns.MODIFIES_LAUNCHER)) == 1) { - mSelectedComponentsMap.put(ThemesColumns.MODIFIES_LAUNCHER, pkgName); - } - if (c.getInt(c.getColumnIndex(ThemesColumns.MODIFIES_LOCKSCREEN)) == 1) { - mSelectedComponentsMap.put(ThemesColumns.MODIFIES_LOCKSCREEN, pkgName); - } - if (c.getInt(c.getColumnIndex(ThemesColumns.MODIFIES_NAVIGATION_BAR)) == 1) { - mSelectedComponentsMap.put(ThemesColumns.MODIFIES_NAVIGATION_BAR, pkgName); - } - if (c.getInt(c.getColumnIndex(ThemesColumns.MODIFIES_NOTIFICATIONS)) == 1) { - mSelectedComponentsMap.put(ThemesColumns.MODIFIES_NOTIFICATIONS, pkgName); - } - if (c.getInt(c.getColumnIndex(ThemesColumns.MODIFIES_OVERLAYS)) == 1) { - mSelectedComponentsMap.put(ThemesColumns.MODIFIES_OVERLAYS, pkgName); - } - if (c.getInt(c.getColumnIndex(ThemesColumns.MODIFIES_RINGTONES)) == 1) { - mSelectedComponentsMap.put(ThemesColumns.MODIFIES_RINGTONES, pkgName); - } - if (c.getInt(c.getColumnIndex(ThemesColumns.MODIFIES_STATUS_BAR)) == 1) { - mSelectedComponentsMap.put(ThemesColumns.MODIFIES_STATUS_BAR, pkgName); - } - if (c.getInt(c.getColumnIndex(ThemesColumns.MODIFIES_LIVE_LOCK_SCREEN)) == 1) { - mSelectedComponentsMap.put(ThemesColumns.MODIFIES_LIVE_LOCK_SCREEN, pkgName); - } - } - c.close(); - } - - // strip out any components that are not in the components list - if (components != null) { - Iterator> iterator = - mSelectedComponentsMap.entrySet().iterator(); - while (iterator.hasNext()) { - Map.Entry entry = iterator.next(); - if (!components.contains(entry.getKey())) { - iterator.remove(); - } - } - } - } - - private void loadComponentsToApply() { - for (String component : mSelectedComponentsMap.keySet()) { - loadComponentFromPackage(mSelectedComponentsMap.get(component), component, - mSelectedWallpaperComponentId); - } - } - - private BroadcastReceiver mWallpaperChangeReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - // only update if we are the current visible fragment or if there is no theme - // being applied. - ThemeManager tm = getThemeManager(); - if (!tm.isThemeApplying() || getUserVisibleHint()) { - final WallpaperManager wm = WallpaperManager.getInstance(context); - if (wm.getWallpaperInfo() != null) { - addSurfaceView(mSurfaceView); - } else { - removeSurfaceView(mSurfaceView); - } - - Drawable wp = context == null ? null : wm.getDrawable(); - if (wp != null) { - mWallpaper.setImageDrawable(wp); - mWallpaperCard.setWallpaper(wp); - } - } - } - }; - - private void setCustomized(boolean customized) { - mReset.setVisibility(customized ? View.VISIBLE : View.GONE); - mThemeTagLayout.setCustomizedTagEnabled(customized); - } - - @Override - public Loader onCreateLoader(int id, Bundle args) { - switch (id) { - case LOADER_ID_ALL: - if (args != null) { - String pkgName = args.getString(ARG_PACKAGE_NAME); - if (pkgName != null) { - return super.onCreateLoader(id, args); - } - } - return CursorLoaderHelper.myThemeFragmentCursorLoader(getActivity(), id); - default: - // Only LOADER_ID_ALL differs for MyThemeFragment - return super.onCreateLoader(id, args); - } - } - - @Override - public void onLoadFinished(Loader loader, Cursor c) { - super.onLoadFinished(loader, c); - // if the theme is resetting, we need to apply these changes now that the supported - // theme components have been properly set. - if (loader.getId() == LOADER_ID_ALL) { - if (mThemeResetting) { - applyTheme(); - } else if (mApplyThemeOnPopulated) { - loadComponentsToApply(); - applyTheme(); - } else if (mSelectedComponentsMap.size() == 0) { - //Re-populates selected components with current theme. Why? - //We got here because the cursor was reloaded after the user pressed back and no - //changes were applied, causing the selected components map to be wiped out - mSelectedComponentsMap.putAll(mCurrentTheme); - } - } - } - - @Override - protected Map fillMissingComponentsWithDefault( - Map originalMap) { - // Only the ThemeFragment should be altering this, for the MyThemeFragment this is not - // desirable as it changes components the user did not even touch. - return originalMap; - } - - @Override - protected ThemeChangeRequest getThemeChangeRequestForComponents( - Map componentMap) { - return getThemeChangeRequestForComponents(componentMap, RequestType.USER_REQUEST_MIXNMATCH); - } - - @Override - protected Map getComponentsToApply() { - Map componentsToApply = mThemeResetting - ? getEmptyComponentsMap() - : new HashMap(); - if (mThemeResetting) { - final String pkgName = getThemePackageName(); - for (String component : mBaseThemeSupportedComponents) { - componentsToApply.put(component, pkgName); - } - } else { - // Only apply components that actually changed - for (String component : mSelectedComponentsMap.keySet()) { - String currentPkg = mCurrentTheme.get(component); - String selectedPkg = mSelectedComponentsMap.get(component); - if (currentPkg == null || mThemeResetting || !currentPkg.equals(selectedPkg) || - mCurrentWallpaperComponentId.value != mSelectedWallpaperComponentId) { - componentsToApply.put(component, selectedPkg); - } - } - if (mExternalLockscreenUri != null) { - if (mCurrentTheme.containsKey(ThemesColumns.MODIFIES_LIVE_LOCK_SCREEN)) { - componentsToApply.put(ThemesColumns.MODIFIES_LIVE_LOCK_SCREEN, LOCKSCREEN_NONE); - } - if (mCurrentTheme.containsKey(ThemesColumns.MODIFIES_LOCKSCREEN)) { - componentsToApply.put(ThemesColumns.MODIFIES_LOCKSCREEN, LOCKSCREEN_NONE); - } - } - } - return componentsToApply; - } - - @Override - protected void populateSupportedComponents(Cursor c) { - } - - @Override - protected Boolean shouldShowComponentCard(String component) { - return true; - } - - @Override - protected void loadTitle(Cursor c) { - mTitle.setText(mBaseThemeName); - mAuthor.setText(mBaseThemeAuthor); - } - - @Override - protected void loadWallpaper(Cursor c, boolean animate) { - mExternalWallpaperUri = null; - int pkgNameIdx = c.getColumnIndex(ThemesContract.ThemesColumns.PKG_NAME); - if (pkgNameIdx > -1) { - super.loadWallpaper(c, animate); - return; - } - Drawable overlay = null; - if (animate) { - overlay = getOverlayDrawable(mWallpaperCard, true); - } - - int wpIdx = c.getColumnIndex(PreviewColumns.WALLPAPER_PREVIEW); - final Resources res = getResources(); - final Context context = getActivity(); - final WallpaperManager wm = WallpaperManager.getInstance(context); - if (wm.getWallpaperInfo() != null) { - addSurfaceView(mSurfaceView); - } else { - removeSurfaceView(mSurfaceView); - } - - Drawable wp = context == null ? null : wm.getDrawable(); - if (wp == null) { - Bitmap bmp = Utils.loadBitmapBlob(c, wpIdx); - if (bmp != null) wp = new BitmapDrawable(res, bmp); - } - if (wp != null) { - mWallpaper.setImageDrawable(wp); - mWallpaperCard.setWallpaper(wp); - setCardTitle(mWallpaperCard, mCurrentTheme.get(ThemesColumns.MODIFIES_LAUNCHER), - getString(R.string.wallpaper_label)); - } else { - mWallpaperCard.clearWallpaper(); - mWallpaperCard.setEmptyViewEnabled(true); - setAddComponentTitle(mWallpaperCard, getString(R.string.wallpaper_label)); - } - - if (animate) { - animateContentChange(R.id.wallpaper_card, mWallpaperCard, overlay); - } - } - - @Override - protected void loadLockScreen(Cursor c, boolean animate) { - mExternalLockscreenUri = null; - int pkgNameIdx = c.getColumnIndex(ThemesContract.ThemesColumns.PKG_NAME); - if (pkgNameIdx > -1) { - super.loadLockScreen(c, animate); - return; - } - Drawable overlay = null; - if (animate) { - overlay = getOverlayDrawable(mLockScreenCard, true); - } - - //If the current theme includes a lock wallpaper, the WallpaperMgr will - //return a valid Drawable we can display in the card. However, if the user - //picked a LLS, we need to get the path from the provider and manually load the bitmap - int wpIdx = c.getColumnIndex(PreviewColumns.LIVE_LOCK_SCREEN_PREVIEW); - Drawable wp = null; - if (wpIdx >= 0) { - final Resources res = getResources(); - Bitmap bmp = Utils.loadBitmapBlob(c, wpIdx); - if (bmp != null) wp = new BitmapDrawable(res, bmp); - } else { - final Context context = getActivity(); - wp = context == null ? null : - WallpaperManager.getInstance(context).getFastKeyguardDrawable(); - } - if (wp != null) { - mLockScreenCard.setWallpaper(wp); - } else if (!mSelectedComponentsMap.containsKey(ThemesColumns.MODIFIES_LOCKSCREEN)) { - mLockScreenCard.clearWallpaper(); - mLockScreenCard.setEmptyViewEnabled(true); - setAddComponentTitle(mLockScreenCard, getString(R.string.lockscreen_label)); - } - - if (animate) { - animateContentChange(R.id.lockscreen_card, mLockScreenCard, overlay); - } - } - - @Override - protected void loadFont(Cursor c, boolean animate) { - int pkgNameIdx = c.getColumnIndex(ThemesContract.ThemesColumns.PKG_NAME); - if (pkgNameIdx > -1) { - super.loadFont(c, animate); - return; - } - Drawable overlay = null; - if (animate) { - overlay = getOverlayDrawable(mFontPreview, true); - } - setCardTitle(mFontCard, mCurrentTheme.get(ThemesColumns.MODIFIES_FONTS), - getString(R.string.font_label)); - - TypefaceHelperCache cache = TypefaceHelperCache.getInstance(); - ThemedTypefaceHelper helper = cache.getHelperForTheme(getActivity(), - getAppliedFontPackageName()); - mTypefaceNormal = helper.getTypeface(Typeface.NORMAL); - mFontPreview.setTypeface(mTypefaceNormal); - if (animate) { - animateContentChange(R.id.font_preview_container, mFontPreview, overlay); - } - } - - @Override - protected void loadAudible(int type, Cursor c, boolean animate) { - int pkgNameIdx = c.getColumnIndex(ThemesContract.ThemesColumns.PKG_NAME); - if (pkgNameIdx > -1) { - super.loadAudible(type, c, animate); - return; - } - ComponentCardView audibleContainer = null; - ImageView playPause = null; - String modsComponent = ""; - switch (type) { - case RingtoneManager.TYPE_RINGTONE: - audibleContainer = mRingtoneCard; - playPause = mRingtonePlayPause; - modsComponent = ThemesColumns.MODIFIES_RINGTONES; - break; - case RingtoneManager.TYPE_NOTIFICATION: - audibleContainer = mNotificationCard; - playPause = mNotificationPlayPause; - modsComponent = ThemesColumns.MODIFIES_NOTIFICATIONS; - break; - case RingtoneManager.TYPE_ALARM: - audibleContainer = mAlarmCard; - playPause = mAlarmPlayPause; - modsComponent = ThemesColumns.MODIFIES_ALARMS; - break; - } - if (audibleContainer == null) return; - - if (playPause == null) { - playPause = - (ImageView) audibleContainer.findViewById(R.id.play_pause); - } - TextView title = (TextView) audibleContainer.findViewById(R.id.audible_name); - MediaPlayer mp = mMediaPlayers.get(playPause); - if (mp == null) { - mp = new MediaPlayer(); - } - - final Context context = getActivity(); - Ringtone ringtone = null; - try { - Uri ringtoneUri = AudioUtils.loadDefaultAudible(context, type, mp); - if (ringtoneUri != null) ringtone = RingtoneManager.getRingtone(context, ringtoneUri); - } catch (IOException e) { - Log.w(TAG, "Unable to load default sound ", e); - } - - if (ringtone != null) { - title.setText(ringtone.getTitle(context)); - setCardTitle(audibleContainer, mCurrentTheme.get(modsComponent), - getAudibleLabel(type)); - } else { - title.setText(getString(R.string.audible_title_none)); - setAddComponentTitle(audibleContainer, getAudibleLabel(type)); - playPause.setVisibility(View.INVISIBLE); - audibleContainer.setEmptyViewEnabled(true); - } - - playPause.setTag(mp); - mMediaPlayers.put(playPause, mp); - playPause.setOnClickListener(mPlayPauseClickListener); - mp.setOnCompletionListener(mPlayCompletionListener); - } - - @Override - protected void loadStatusBar(Cursor c, boolean animate) { - super.loadStatusBar(c, animate); - setCardTitle(mStatusBarCard, mCurrentTheme.get(ThemesColumns.MODIFIES_STATUS_BAR), - getString(R.string.statusbar_label)); - } - - @Override - protected void loadIcons(Cursor c, boolean animate) { - super.loadIcons(c, animate); - setCardTitle(mIconCard, mCurrentTheme.get(ThemesColumns.MODIFIES_ICONS), - getString(R.string.icon_label)); - } - - @Override - protected void loadNavBar(Cursor c, boolean animate) { - super.loadNavBar(c, animate); - setCardTitle(mNavBarCard, mCurrentTheme.get(ThemesColumns.MODIFIES_NAVIGATION_BAR), - getString(R.string.navbar_label)); - } - - @Override - protected void loadStyle(Cursor c, boolean animate) { - super.loadStyle(c, animate); - setCardTitle(mStyleCard, mCurrentTheme.get(ThemesColumns.MODIFIES_OVERLAYS), - getString(R.string.style_label)); - } - - @Override - protected void loadBootAnimation(Cursor c) { - super.loadBootAnimation(c); - setCardTitle(mBootAnimationCard, mCurrentTheme.get(ThemesColumns.MODIFIES_BOOT_ANIM), - getString(R.string.boot_animation_label)); - } - - @Override - public String getThemePackageName() { - if (mBaseThemePkgName == null) { - // check if the package name is defined in the arguments bundle - Bundle bundle = getArguments(); - if (bundle != null) { - mBaseThemePkgName = bundle.getString(ARG_BASE_THEME_PACKAGE_NAME); - } - } - return mBaseThemePkgName; - } - - private SurfaceView createSurfaceView() { - final Context context = getActivity(); - if (context == null) return null; - - SurfaceView sv = new SurfaceView(context); - final Resources res = context.getResources(); - FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( - res.getDimensionPixelSize(R.dimen.wallpaper_preview_width), - res.getDimensionPixelSize(R.dimen.theme_preview_height), - Gravity.CENTER_HORIZONTAL); - sv.setLayoutParams(params); - - return sv; - } - - private void addSurfaceView(SurfaceView sv) { - if (mShadowFrame.indexOfChild(mSurfaceView) < 0) { - int idx = mShadowFrame.indexOfChild(mWallpaper); - mShadowFrame.addView(sv, idx + 1); - } - } - - private void removeSurfaceView(SurfaceView sv) { - if (mShadowFrame.indexOfChild(mSurfaceView) >= 0) { - mShadowFrame.removeView(sv); - } - } - - /** - * Populates mBaseThemeSupportedComponents. - * @param pkgName Package name of the base theme used - */ - private void populateBaseThemeSupportedComponents(String pkgName) { - String selection = ThemesColumns.PKG_NAME + "=?"; - String[] selectionArgs = { pkgName }; - Cursor c = getActivity().getContentResolver().query(ThemesColumns.CONTENT_URI, - null, selection, selectionArgs, null); - if (c != null) { - if (c.moveToFirst()) { - List components = ThemeUtils.getAllComponents(); - final String baseThemePackageName = getThemePackageName(); - for (String component : components) { - int pkgIdx = c.getColumnIndex(ThemesColumns.PKG_NAME); - int modifiesCompIdx = c.getColumnIndex(component); - - String pkg = pkgIdx >= 0 ? c.getString(pkgIdx) : null; - boolean supported = (modifiesCompIdx >= 0) && (c.getInt(modifiesCompIdx) == 1); - if (supported && baseThemePackageName.equals(pkg)) { - mBaseThemeSupportedComponents.add(component); - } - } - } - c.close(); - } - } -} diff --git a/src/org/cyanogenmod/theme/chooser/NewFragmentStatePagerAdapter.java b/src/org/cyanogenmod/theme/chooser/NewFragmentStatePagerAdapter.java deleted file mode 100644 index cefc344..0000000 --- a/src/org/cyanogenmod/theme/chooser/NewFragmentStatePagerAdapter.java +++ /dev/null @@ -1,333 +0,0 @@ -/* - * Copyright (C) 2016 Cyanogen, Inc. - * Copyright (C) 2016 The CyanogenMod Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.cyanogenmod.theme.chooser; - -import android.os.Bundle; -import android.os.Parcelable; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentTransaction; -import android.support.v4.view.PagerAdapter; -import android.util.Log; -import android.view.View; -import android.view.ViewGroup; - -import java.util.ArrayList; -import java.util.Arrays; - -/** - * Implementation of {@link android.support.v4.view.PagerAdapter} that - * uses a {@link android.support.v4.app.Fragment} to manage each page. This class also handles - * saving and restoring of fragment's state. - * - *

This version of the pager is more useful when there are a large number - * of pages, working more like a list view. When pages are not visible to - * the user, their entire fragment may be destroyed, only keeping the saved - * state of that fragment. This allows the pager to hold on to much less - * memory associated with each visited page as compared to - * {@link android.support.v4.app.FragmentPagerAdapter} at the cost of potentially more overhead when - * switching between pages. - * - *

When using FragmentPagerAdapter the host ViewPager must have a - * valid ID set.

- * - *

Subclasses only need to implement {@link #getItem(int)} - * and {@link #getCount()} to have a working adapter. - * - *

Here is an example implementation of a pager containing fragments of - * lists: - * - * {@sample development/samples/Support13Demos/src/com/example/android/supportv13/app/FragmentStatePagerSupport.java - * complete} - * - *

The R.layout.fragment_pager resource of the top-level fragment is: - * - * {@sample development/samples/Support13Demos/res/layout/fragment_pager.xml - * complete} - * - *

The R.layout.fragment_pager_list resource containing each - * individual fragment's layout is: - * - * {@sample development/samples/Support13Demos/res/layout/fragment_pager_list.xml - * complete} - */ -public abstract class NewFragmentStatePagerAdapter extends PagerAdapter { - private static final String TAG = NewFragmentStatePagerAdapter.class.getSimpleName(); - private static final boolean DEBUG = false; - - private final FragmentManager mFragmentManager; - private FragmentTransaction mCurTransaction = null; - - private long[] mItemIds = new long[] {}; - private ArrayList mSavedState = new ArrayList(); - private ArrayList mFragments = new ArrayList(); - private Fragment mCurrentPrimaryItem = null; - - public NewFragmentStatePagerAdapter(FragmentManager fm) { - - mFragmentManager = fm; - createIdCache(); - } - - /** - * Return the Fragment associated with a specified position. - */ - public abstract Fragment getItem(int position); - - /** - * Return a unique identifier for the item at the given position. - */ - public abstract long getItemId(int position); - - @Override - public void startUpdate(ViewGroup container) { - } - - private void checkForIdChanges() { - long[] newItemIds = new long[getCount()]; - for (int i = 0; i < newItemIds.length; i++) { - newItemIds[i] = getItemId(i); - } - - if (!Arrays.equals(mItemIds, newItemIds)) { - ArrayList newSavedState = new ArrayList(); - ArrayList newFragments = new ArrayList(); - - for (int oldPosition = 0; oldPosition < mItemIds.length; oldPosition++) { - int newPosition = POSITION_NONE; - for (int i = 0; i < newItemIds.length; i++) { - if (mItemIds[oldPosition] == newItemIds[i]) { - newPosition = i; - break; - } - } - if (newPosition >= 0) { - if (oldPosition < mSavedState.size()) { - Fragment.SavedState savedState = mSavedState.get(oldPosition); - if (savedState != null) { - while (newSavedState.size() <= newPosition) { - newSavedState.add(null); - } - newSavedState.set(newPosition, savedState); - } - } - if (oldPosition < mFragments.size()) { - Fragment fragment = mFragments.get(oldPosition); - if (fragment != null) { - while (newFragments.size() <= newPosition) { - newFragments.add(null); - } - newFragments.set(newPosition, fragment); - } - } - } - } - - mItemIds = newItemIds; - mSavedState = newSavedState; - mFragments = newFragments; - } - } - - @Override - public void notifyDataSetChanged() { - checkForIdChanges(); - - super.notifyDataSetChanged(); - } - - /** - * Create the initial set of item IDs. Run this after you have set your adapter data. - */ - public void createIdCache() { - // If we have already stored ids, don't overwrite them - if (mItemIds.length == 0) { - // getCount might have overhead, so run it as late as possible - final int count = getCount(); - if (count > 0) { - mItemIds = new long[count]; - for (int i = 0; i < count; i++) { - mItemIds[i] = getItemId(i); - } - } - } - } - - @Override - public Object instantiateItem(ViewGroup container, int position) { - - createIdCache(); - - // If we already have this item instantiated, there is nothing - // to do. This can happen when we are restoring the entire pager - // from its saved state, where the fragment manager has already - // taken care of restoring the fragments we previously had instantiated. - if (mFragments.size() > position) { - Fragment f = mFragments.get(position); - if (f != null) { - return f; - } - } - - if (mCurTransaction == null) { - mCurTransaction = mFragmentManager.beginTransaction(); - } - - Fragment fragment = getItem(position); - if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment); - if (mSavedState.size() > position) { - Fragment.SavedState fss = mSavedState.get(position); - if (fss != null) { - fragment.setInitialSavedState(fss); - } - } - while (mFragments.size() <= position) { - mFragments.add(null); - } - fragment.setMenuVisibility(false); - fragment.setUserVisibleHint(false); - mFragments.set(position, fragment); - mCurTransaction.add(container.getId(), fragment); - - return fragment; - } - - @Override - public void destroyItem(ViewGroup container, int position, Object object) { - Fragment fragment = (Fragment)object; - - if (mCurTransaction == null) { - mCurTransaction = mFragmentManager.beginTransaction(); - } - if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object - + " v=" + ((Fragment)object).getView()); - while (mSavedState.size() <= position) { - mSavedState.add(null); - } - mSavedState.set(position, mFragmentManager.saveFragmentInstanceState(fragment)); - - // Only set the position to null if the fragment being removed is at "position" - // We do this because checkForIdChanges updates the mFragments list and if a fragment - // was removed then the fragment at "position" is not the fragment that was removed. - if (position < mFragments.size() && fragment == mFragments.get(position)) { - mFragments.set(position, null); - } - mCurTransaction.remove(fragment); - } - - @Override - public void setPrimaryItem(ViewGroup container, int position, Object object) { - Fragment fragment = (Fragment)object; - if (fragment != mCurrentPrimaryItem) { - if (mCurrentPrimaryItem != null) { - mCurrentPrimaryItem.setMenuVisibility(false); - mCurrentPrimaryItem.setUserVisibleHint(false); - } - if (fragment != null) { - fragment.setMenuVisibility(true); - fragment.setUserVisibleHint(true); - } - mCurrentPrimaryItem = fragment; - } - } - - @Override - public void finishUpdate(ViewGroup container) { - if (mCurTransaction != null) { - mCurTransaction.commitAllowingStateLoss(); - mCurTransaction = null; - mFragmentManager.executePendingTransactions(); - } - } - - @Override - public boolean isViewFromObject(View view, Object object) { - return ((Fragment)object).getView() == view; - } - - @Override - public Parcelable saveState() { - Bundle state = null; - - mItemIds = new long[getCount()]; - for (int i = 0; i < mItemIds.length; i++) { - mItemIds[i] = getItemId(i); - } - if (mSavedState.size() > 0) { - state = new Bundle(); - - if (mItemIds.length > 0) { - state.putLongArray("itemids", mItemIds); - } - - Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()]; - mSavedState.toArray(fss); - state.putParcelableArray("states", fss); - } - for (int i=0; i keys = bundle.keySet(); - for (String key: keys) { - if (key.startsWith("f")) { - int index = Integer.parseInt(key.substring(1)); - Fragment f = mFragmentManager.getFragment(bundle, key); - if (f != null) { - while (mFragments.size() <= index) { - mFragments.add(null); - } - f.setMenuVisibility(false); - mFragments.set(index, f); - } else { - Log.w(TAG, "Bad fragment at key " + key); - } - } - } - checkForIdChanges(); - } - } -} \ No newline at end of file diff --git a/src/org/cyanogenmod/theme/chooser/NotificationHijackingService.java b/src/org/cyanogenmod/theme/chooser/NotificationHijackingService.java deleted file mode 100644 index dddd8f5..0000000 --- a/src/org/cyanogenmod/theme/chooser/NotificationHijackingService.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2016 Cyanogen, Inc. - * Copyright (C) 2016 The CyanogenMod Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.cyanogenmod.theme.chooser; - -import android.app.PendingIntent; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.provider.Settings; -import android.service.notification.NotificationListenerService; -import android.service.notification.StatusBarNotification; -import android.text.TextUtils; - -public class NotificationHijackingService extends NotificationListenerService { - private static final String TAG = NotificationHijackingService.class.getName(); - private static final String GOOGLE_PLAY_PACKAGE_NAME = "com.android.vending"; - private static final String ACTION_INSTALLED = - "com.android.vending.SUCCESSFULLY_INSTALLED_CLICKED"; - private static final String EXTRA_PACKAGE_NAME = "package_name"; - - @Override - public void onNotificationPosted(StatusBarNotification sbn) { - if (GOOGLE_PLAY_PACKAGE_NAME.equals(sbn.getPackageName())) { - PendingIntent contentIntent = sbn.getNotification().contentIntent; - if (contentIntent == null) return; - Intent intent = contentIntent.getIntent(); - if (intent == null) return; - String action = intent.getAction(); - if (ACTION_INSTALLED.equals(action)) { - String pkgName = intent.getStringExtra(EXTRA_PACKAGE_NAME); - try { - PackageInfo pi = getPackageManager().getPackageInfo(pkgName, 0); - if (pi != null) { - if (pi.themeInfo != null) { - cancelNotification(sbn.getKey()); - } - } - } catch (PackageManager.NameNotFoundException e) { - } - } - } - } - - @Override - public void onNotificationRemoved(StatusBarNotification sbn) { - } - - // ensure that this notification listener is enabled. - // the service watches for google play notifications - public static void ensureEnabled(Context context) { - ComponentName me = new ComponentName(context, NotificationHijackingService.class); - String meFlattened = me.flattenToString(); - - String existingListeners = Settings.Secure.getString(context.getContentResolver(), - Settings.Secure.ENABLED_NOTIFICATION_LISTENERS); - - if (!TextUtils.isEmpty(existingListeners)) { - if (existingListeners.contains(meFlattened)) { - return; - } else { - existingListeners += ":" + meFlattened; - } - } else { - existingListeners = meFlattened; - } - - Settings.Secure.putString(context.getContentResolver(), - Settings.Secure.ENABLED_NOTIFICATION_LISTENERS, - existingListeners); - } -} diff --git a/src/org/cyanogenmod/theme/chooser/PagerContainer.java b/src/org/cyanogenmod/theme/chooser/PagerContainer.java deleted file mode 100644 index 852b847..0000000 --- a/src/org/cyanogenmod/theme/chooser/PagerContainer.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (C) 2016 Cyanogen, Inc. - * Copyright (C) 2016 The CyanogenMod Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.cyanogenmod.theme.chooser; - -import android.content.Context; -import android.graphics.Point; -import android.support.v4.view.ThemeViewPager; -import android.support.v4.view.ViewPager; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewTreeObserver; -import android.view.animation.AccelerateInterpolator; -import android.view.animation.DecelerateInterpolator; -import android.widget.FrameLayout; -import android.widget.LinearLayout; - -/** - * PagerContainer: A layout that displays a ViewPager with its children that are outside - * the typical pager bounds. - */ -public class PagerContainer extends FrameLayout implements ViewPager.OnPageChangeListener { - private static final int ANIMATE_OUT_DURATION = 300; - private static final int ANIMATE_OUT_INTERPOLATE_FACTOR = 1; - private static final int ANIMATE_IN_DURATION = 300; - private static final int ANIMATE_IN_INTERPOLATE_FACTOR = 2; - - private ThemeViewPager mPager; - private Point mCenter = new Point(); - private Point mInitialTouch = new Point(); - private int mCollapsedHeight; - private boolean mIsAnimating = false; - - boolean mNeedsRedraw = false; - - public PagerContainer(Context context) { - this(context, null, 0); - } - - public PagerContainer(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public PagerContainer(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - mCollapsedHeight = generateLayoutParams(attrs).height; - - //Disable clipping of children so non-selected pages are visible - setClipChildren(false); - } - - @Override - protected void onFinishInflate() { - try { - mPager = (ThemeViewPager) getChildAt(0); - mPager.setOnPageChangeListener(this); - } catch (Exception e) { - throw new IllegalStateException("The root child of PagerContainer must be a ViewPager"); - } - } - - public ThemeViewPager getViewPager() { - return mPager; - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - mCenter.x = w / 2; - mCenter.y = h / 2; - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - if (mIsAnimating) return true; - return super.onInterceptTouchEvent(ev); - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - // Do not allow touch events to propagate if we are animating - if (mIsAnimating) return true; - - //We capture any touches not already handled by the ViewPager - // to implement scrolling from a touch outside the pager bounds. - switch (ev.getAction()) { - case MotionEvent.ACTION_DOWN: - mInitialTouch.x = (int)ev.getX(); - mInitialTouch.y = (int)ev.getY(); - default: - ev.offsetLocation(mCenter.x - mInitialTouch.x, mCenter.y - mInitialTouch.y); - break; - } - - return mPager.dispatchTouchEvent(ev); - } - - @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - //Force the container to redraw on scrolling. - //Without this the outer pages render initially and then stay static - if (mNeedsRedraw) invalidate(); - } - - @Override - public void onPageSelected(int position) { } - - @Override - public void onPageScrollStateChanged(int state) { - mNeedsRedraw = (state != ThemeViewPager.SCROLL_STATE_IDLE); - } - - public void setIsAnimating(boolean isAnimating) { - mIsAnimating = isAnimating; - } - - public void expand() { - LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(getLayoutParams()); - params.height = LinearLayout.LayoutParams.MATCH_PARENT; - setLayoutParams(params); - - mPager.setExpanded(true); - - final int current = mPager.getCurrentItem(); - final int prevY = (int) getY(); - - //Since our viewpager's width is changing to fill the screen - //we must start the left/right children of the current page inwards on first draw - final int lChildPrevXf; - final int rChildPrevXf; - - if (current != 0) { - final View lchild = mPager.getViewForPosition(current - 1); - lChildPrevXf = (int) lchild.getX(); - } else { - lChildPrevXf = 0; - } - - if (current < mPager.getAdapter().getCount() - 1) { - View rchild = mPager.getViewForPosition(current + 1); - rChildPrevXf = (int) rchild.getX(); - } else { - rChildPrevXf = 0; - } - - - final ViewTreeObserver observer = mPager.getViewTreeObserver(); - observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { - public boolean onPreDraw() { - observer.removeOnPreDrawListener(this); - if (current != 0) { - View lchild = mPager.getViewForPosition(current - 1); - lchild.setTranslationY(prevY - getY()); - lchild.setX(lChildPrevXf); - animateChildOut(lchild, -getWidth()); - } - - if (current < mPager.getAdapter().getCount() - 1) { - View rchild = mPager.getViewForPosition(current + 1); - rchild.setX(rChildPrevXf); - rchild.setTranslationY(prevY - getY()); - animateChildOut(rchild, getWidth()); - } - return false; - } - }); - } - - public void collapse() { - LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(getLayoutParams()); - params.height = mCollapsedHeight; - setLayoutParams(params); - - mPager.setExpanded(false); - int current = mPager.getCurrentItem(); - final int prevY = (int) getY(); - - if (current != 0) { - View lchild = mPager.getViewForPosition(current - 1); - lchild.setTranslationY(0); - animateChildIn(lchild); - } - - if (current < mPager.getAdapter().getCount() - 1) { - View rchild = mPager.getViewForPosition(current + 1); - rchild.setTranslationY(0); - animateChildIn(rchild); - } - } - - private void animateChildOut(final View v, float endX) { - v.animate() - .translationX(endX) - .setDuration(ANIMATE_OUT_DURATION) - .setInterpolator(new AccelerateInterpolator(ANIMATE_OUT_INTERPOLATE_FACTOR)); - } - - private void animateChildIn(final View v) { - v.animate() - .translationX(0) - .setDuration(ANIMATE_IN_DURATION) - .setInterpolator(new DecelerateInterpolator(ANIMATE_IN_INTERPOLATE_FACTOR)); - } -} \ No newline at end of file diff --git a/src/org/cyanogenmod/theme/chooser/ThemeFragment.java b/src/org/cyanogenmod/theme/chooser/ThemeFragment.java deleted file mode 100644 index d0891a7..0000000 --- a/src/org/cyanogenmod/theme/chooser/ThemeFragment.java +++ /dev/null @@ -1,3059 +0,0 @@ -/* - * Copyright (C) 2016 Cyanogen, Inc. - * Copyright (C) 2016 The CyanogenMod Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.cyanogenmod.theme.chooser; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; -import android.animation.IntEvaluator; -import android.animation.ObjectAnimator; -import android.animation.ValueAnimator; -import android.app.Activity; -import android.app.AlertDialog; -import android.app.WallpaperManager; -import android.content.ActivityNotFoundException; -import android.content.ComponentName; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.res.AssetManager; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.content.res.ThemeConfig; -import android.database.Cursor; -import android.graphics.Bitmap; -import android.graphics.Bitmap.Config; -import android.graphics.Color; -import android.graphics.Point; -import android.graphics.Rect; -import android.graphics.Typeface; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.NinePatchDrawable; -import android.media.MediaPlayer; -import android.media.RingtoneManager; -import android.net.Uri; -import android.os.AsyncTask; -import android.os.Build; -import android.os.Bundle; -import android.os.FileUtils; -import android.os.Handler; -import android.support.v4.app.Fragment; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.Loader; -import android.text.TextUtils; -import android.util.Log; -import android.util.MutableLong; -import android.util.SparseArray; -import android.view.Display; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewPropertyAnimator; -import android.view.ViewTreeObserver; -import android.view.animation.AccelerateInterpolator; -import android.view.animation.Animation; -import android.view.animation.DecelerateInterpolator; -import android.view.animation.ScaleAnimation; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.PopupMenu; -import android.widget.ProgressBar; -import android.widget.Space; -import android.widget.TextView; -import android.widget.Toast; - -import org.cyanogenmod.theme.chooser.ComponentSelector.OnItemClickedListener; -import org.cyanogenmod.theme.util.AudioUtils; -import org.cyanogenmod.theme.util.BootAnimationHelper; -import org.cyanogenmod.theme.util.CursorLoaderHelper; -import org.cyanogenmod.theme.util.IconPreviewHelper; -import org.cyanogenmod.theme.util.PreferenceUtils; -import org.cyanogenmod.theme.util.ThemedTypefaceHelper; -import org.cyanogenmod.theme.util.TypefaceHelperCache; -import org.cyanogenmod.theme.util.Utils; -import org.cyanogenmod.theme.util.WallpaperUtils; -import org.cyanogenmod.theme.widget.BootAniImageView; -import org.cyanogenmod.theme.widget.ConfirmCancelOverlay; -import org.cyanogenmod.theme.widget.LockableScrollView; -import org.cyanogenmod.theme.widget.ThemeTagLayout; - -import cyanogenmod.app.ThemeVersion; -import cyanogenmod.providers.CMSettings; -import cyanogenmod.providers.ThemesContract.PreviewColumns; -import cyanogenmod.providers.ThemesContract.ThemesColumns; -import cyanogenmod.themes.ThemeChangeRequest; -import cyanogenmod.themes.ThemeChangeRequest.RequestType; -import cyanogenmod.themes.ThemeManager; - -import org.cyanogenmod.internal.util.CmLockPatternUtils; -import org.cyanogenmod.internal.util.ThemeUtils; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.security.InvalidParameterException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.zip.ZipFile; - -import static android.Manifest.permission.READ_EXTERNAL_STORAGE; -import static android.content.pm.PackageManager.PERMISSION_GRANTED; - -import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_ALARMS; -import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_BOOT_ANIM; -import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_LAUNCHER; -import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_LIVE_LOCK_SCREEN; -import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_LOCKSCREEN; -import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_NOTIFICATIONS; -import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_OVERLAYS; -import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_RINGTONES; -import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_STATUS_BAR; -import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_NAVIGATION_BAR; -import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_ICONS; -import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_FONTS; - -import static org.cyanogenmod.theme.chooser.ComponentSelector.DEFAULT_COMPONENT_ID; - -import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_INVALID; -import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_ALL; -import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_STATUS_BAR; -import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_FONT; -import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_ICONS; -import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_WALLPAPER; -import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_NAVIGATION_BAR; -import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_LOCKSCREEN; -import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_STYLE; -import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_BOOT_ANIMATION; -import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_RINGTONE; -import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_NOTIFICATION; -import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_ALARM; -import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_LIVE_LOCK_SCREEN; - -import static cyanogenmod.providers.CMSettings.Secure.LIVE_LOCK_SCREEN_ENABLED; - -import static org.cyanogenmod.internal.util.ThemeUtils.SYSTEM_TARGET_API; - -public class ThemeFragment extends Fragment implements LoaderManager.LoaderCallbacks, - ThemeManager.ThemeChangeListener, ThemeManager.ThemeProcessingListener { - private static final String TAG = ThemeFragment.class.getSimpleName(); - - public static final int ANIMATE_START_DELAY = 200; - public static final int ANIMATE_DURATION = 300; - public static final int ANIMATE_INTERPOLATE_FACTOR = 3; - public static final int ANIMATE_COMPONENT_CHANGE_DURATION = 200; - public static final int ANIMATE_COMPONENT_ICON_DELAY = 50; - public static final int ANIMATE_PROGRESS_IN_DURATION = 500; - public static final int ANIMATE_TITLE_OUT_DURATION = 400; - public static final int ANIMATE_PROGRESS_OUT_DURATION = 400; - public static final int ANIMATE_TITLE_IN_DURATION = 500; - public static final int ANIMATE_APPLY_LAYOUT_DURATION = 300; - - public static final String CURRENTLY_APPLIED_THEME = "currently_applied_theme"; - - private static final ComponentName COMPONENT_DIALER = - new ComponentName("com.android.dialer", "com.android.dialer.DialtactsActivity"); - private static final ComponentName COMPONENT_DIALERNEXT = - new ComponentName("com.cyngn.dialer", "com.android.dialer.DialtactsActivity"); - private static final ComponentName COMPONENT_MESSAGING = - new ComponentName("com.android.mms", "com.android.mms.ui.ConversationList"); - private static final ComponentName COMPONENT_CAMERANEXT = - new ComponentName("com.cyngn.cameranext", "com.android.camera.CameraLauncher"); - private static final ComponentName COMPONENT_CAMERA = - new ComponentName("com.android.camera2", "com.android.camera.CameraActivity"); - private static final ComponentName COMPONENT_BROWSER = - new ComponentName("com.android.browser", "com.android.browser.BrowserActivity"); - private static final ComponentName COMPONENT_SETTINGS = - new ComponentName("com.android.settings", "com.android.settings.Settings"); - private static final ComponentName COMPONENT_CALENDAR = - new ComponentName("com.android.calendar", "com.android.calendar.AllInOneActivity"); - private static final ComponentName COMPONENT_GALERY = - new ComponentName("com.android.gallery3d", "com.android.gallery3d.app.GalleryActivity"); - - private static final String CAMERA_NEXT_PACKAGE = "com.cyngn.cameranext"; - private static final String DIALER_NEXT_PACKAGE = "com.cyngn.dialer"; - - private static final int ADDITIONAL_CONTENT_SPACE_ID = 123456; - private static final long SLIDE_CONTENT_ANIM_DURATION = 300L; - private static final long LOCK_SCREEN_CARD_SCROLL_ANIMATION_DURATION = 400; - private static final long SHOW_LOCK_SCREEN_CARD_DELAY = 500; - - private static final int DEFAULT_WIFI_MARGIN = 0; - private static final int DEFAULT_CLOCK_COLOR = Color.WHITE; - - protected static final String WALLPAPER_NONE = ""; - protected static final String LOCKSCREEN_NONE = ""; - - protected static final String ARG_PACKAGE_NAME = "pkgName"; - protected static final String ARG_COMPONENT_ID = "cmpntId"; - protected static final String ARG_SKIP_LOADING_ANIM = "skipLoadingAnim"; - protected static final String ARG_ANIMATE_TO_LOCK_SCREEN_CARD = "animateToLockScreenCard"; - - private static final String LLS_PACKAGE_NAME = "com.cyngn.lockscreen.live"; - private static final String LLS_PROVIDER_NAME = - "com.cyngn.lockscreen.live.LockScreenProviderService"; - - private static final int PERMISSION_REQUEST = 100; - - protected static ComponentName[] sIconComponents; - - protected static TypefaceHelperCache sTypefaceHelperCache; - - /** - * Maps the card's resource ID to a theme component - */ - private final SparseArray mCardIdsToComponentTypes = new SparseArray(); - - protected String mPkgName; - protected Typeface mTypefaceNormal; - protected int mBatteryStyle; - - protected LockableScrollView mScrollView; - protected ViewGroup mScrollContent; - protected ViewGroup mPreviewContent; // Contains icons, font, nav/status etc. Not wallpaper - protected View mLoadingView; - - //Status Bar Views - protected ComponentCardView mStatusBarCard; - protected ImageView mBluetooth; - protected ImageView mWifi; - protected ImageView mSignal; - protected ImageView mBattery; - protected TextView mClock; - - // Other Misc Preview Views - protected FrameLayout mShadowFrame; - protected ImageView mWallpaper; - protected ViewGroup mStatusBar; - protected TextView mFontPreview; - protected ComponentCardView mStyleCard; - protected ComponentCardView mFontCard; - protected ComponentCardView mIconCard; - protected ComponentCardView mBootAnimationCard; - protected BootAniImageView mBootAnimation; - - // Nav Bar Views - protected ComponentCardView mNavBarCard; - protected ViewGroup mNavBar; - protected ImageView mBackButton; - protected ImageView mHomeButton; - protected ImageView mRecentButton; - - // Title Card Views - protected ViewGroup mTitleCard; - protected ViewGroup mTitleLayout; - protected TextView mTitle; - protected TextView mAuthor; - protected ImageView mCustomize; - protected ImageView mOverflow; - protected ImageView mDelete; - protected ImageView mReset; - protected ProgressBar mProgress; - - // Additional Card Views - protected LinearLayout mAdditionalCards; - protected WallpaperCardView mWallpaperCard; - protected WallpaperCardView mLockScreenCard; - - // Style views - protected ImageView mStylePreview; - - // Sound cards - protected ComponentCardView mRingtoneCard; - protected ImageView mRingtonePlayPause; - protected ComponentCardView mNotificationCard; - protected ImageView mNotificationPlayPause; - protected ComponentCardView mAlarmCard; - protected ImageView mAlarmPlayPause; - protected Map mMediaPlayers; - - protected Handler mHandler; - - protected int mActiveCardId = -1; - protected ComponentSelector mSelector; - // Supported components for the theme this fragment represents - protected Map mSelectedComponentsMap = new HashMap(); - protected Long mSelectedWallpaperComponentId; - // Current system theme configuration as component -> pkgName - protected Map mCurrentTheme = new HashMap(); - protected MutableLong mCurrentWallpaperComponentId = new MutableLong(DEFAULT_COMPONENT_ID); - // Set of components available in the base theme - protected HashSet mBaseThemeSupportedComponents = new HashSet(); - protected Cursor mCurrentCursor; - protected int mCurrentLoaderId; - protected boolean mThemeResetting; - protected boolean mSkipLoadingAnim; - - // Accept/Cancel overlay - protected ConfirmCancelOverlay mConfirmCancelOverlay; - - // Customize/Reset theme layout - protected View mCustomizeResetLayout; - protected View mResetButton; - protected View mCustomizeButton; - protected View mDismissButton; - - // Processing theme layout - protected View mProcessingThemeLayout; - - protected ThemeTagLayout mThemeTagLayout; - - protected View mClickableView; - protected String mBaseThemePkgName; - - protected Uri mExternalWallpaperUri; - protected Uri mExternalLockscreenUri; - - protected boolean mExpanded; - protected boolean mProcessingResources; - protected boolean mApplyThemeOnPopulated; - - protected boolean mIsLegacyTheme; - - private Runnable mAfterPermissionGrantedRunnable; - - private static final int mThemeVersion = ThemeVersion.getVersion(); - - protected boolean mShowLockScreenSelectorAfterContentLoaded; - - protected enum CustomizeResetAction { - Customize, - Reset, - Dismiss - } - - static ThemeFragment newInstance(String pkgName, boolean skipLoadingAnim) { - ThemeFragment f = new ThemeFragment(); - Bundle args = new Bundle(); - args.putString(ARG_PACKAGE_NAME, pkgName); - args.putBoolean(ARG_SKIP_LOADING_ANIM, skipLoadingAnim); - args.putLong(ARG_COMPONENT_ID, DEFAULT_COMPONENT_ID); - f.setArguments(args); - return f; - } - - /** - * When creating, retrieve this instance's number from its arguments. - */ - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - final Context context = getActivity(); - mPkgName = getArguments().getString(ARG_PACKAGE_NAME); - mSkipLoadingAnim = getArguments().getBoolean(ARG_SKIP_LOADING_ANIM); - // TODO: Load from settings once available - mBatteryStyle = 0;/*Settings.System.getInt(context.getContentResolver(), - Settings.System.STATUS_BAR_BATTERY_STYLE, 0);*/ - - getIconComponents(context); - if (sTypefaceHelperCache == null) { - sTypefaceHelperCache = TypefaceHelperCache.getInstance(); - } - ThemedTypefaceHelper helper = sTypefaceHelperCache.getHelperForTheme(context, mPkgName); - mTypefaceNormal = helper.getTypeface(Typeface.NORMAL); - - mHandler = new Handler(); - - mCardIdsToComponentTypes.put(R.id.status_bar_container, MODIFIES_STATUS_BAR); - mCardIdsToComponentTypes.put(R.id.font_preview_container, MODIFIES_FONTS); - mCardIdsToComponentTypes.put(R.id.icon_container, MODIFIES_ICONS); - mCardIdsToComponentTypes.put(R.id.navigation_bar_container, MODIFIES_NAVIGATION_BAR); - mCardIdsToComponentTypes.put(R.id.wallpaper_card, MODIFIES_LAUNCHER); - mCardIdsToComponentTypes.put(R.id.lockscreen_card, MODIFIES_LOCKSCREEN); - mCardIdsToComponentTypes.put(R.id.style_card, MODIFIES_OVERLAYS); - mCardIdsToComponentTypes.put(R.id.bootani_preview_container, MODIFIES_BOOT_ANIM); - mCardIdsToComponentTypes.put(R.id.ringtone_preview_container, MODIFIES_RINGTONES); - mCardIdsToComponentTypes.put(R.id.notification_preview_container, MODIFIES_NOTIFICATIONS); - mCardIdsToComponentTypes.put(R.id.alarm_preview_container, MODIFIES_ALARMS); - - mMediaPlayers = new HashMap(3); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View v = inflater.inflate(R.layout.fragment_pager_list, container, false); - - mScrollView = (LockableScrollView) v.findViewById(android.R.id.list); - mScrollView.setScrollingEnabled(false); - mScrollContent = (ViewGroup) mScrollView.getChildAt(0); - mPreviewContent = (ViewGroup) v.findViewById(R.id.preview_container); - mLoadingView = v.findViewById(R.id.loading_view); - mThemeTagLayout = (ThemeTagLayout) v.findViewById(R.id.tag_layout); - - // Status Bar - mStatusBarCard = (ComponentCardView) v.findViewById(R.id.status_bar_container); - mStatusBar = (ViewGroup) v.findViewById(R.id.status_bar); - mBluetooth = (ImageView) v.findViewById(R.id.bluetooth_icon); - mWifi = (ImageView) v.findViewById(R.id.wifi_icon); - mSignal = (ImageView) v.findViewById(R.id.signal_icon); - mBattery = (ImageView) v.findViewById(R.id.battery); - mClock = (TextView) v.findViewById(R.id.clock); - - // Wallpaper / Font / Icons / etc - mWallpaper = (ImageView) v.findViewById(R.id.wallpaper); - mFontCard = (ComponentCardView) v.findViewById(R.id.font_preview_container); - mFontPreview = (TextView) v.findViewById(R.id.font_preview); - mFontPreview.setTypeface(mTypefaceNormal); - mIconCard = (ComponentCardView) v.findViewById(R.id.icon_container); - mShadowFrame = (FrameLayout) v.findViewById(R.id.shadow_frame); - mStyleCard = (ComponentCardView) v.findViewById(R.id.style_card); - mStylePreview = (ImageView) v.findViewById(R.id.style_preview); - mBootAnimationCard = (ComponentCardView) v.findViewById(R.id.bootani_preview_container); - mBootAnimation = - (BootAniImageView) mBootAnimationCard.findViewById(R.id.bootani_preview); - mRingtoneCard = (ComponentCardView) v.findViewById(R.id.ringtone_preview_container); - mRingtonePlayPause = (ImageView) mRingtoneCard.findViewById(R.id.play_pause); - mNotificationCard = (ComponentCardView) v.findViewById(R.id.notification_preview_container); - mNotificationPlayPause = (ImageView) mNotificationCard.findViewById(R.id.play_pause); - mAlarmCard = (ComponentCardView) v.findViewById(R.id.alarm_preview_container); - mAlarmPlayPause = (ImageView) mAlarmCard.findViewById(R.id.play_pause); - - // Nav Bar - mNavBarCard = (ComponentCardView) v.findViewById(R.id.navigation_bar_container); - mNavBar = (ViewGroup) v.findViewById(R.id.navigation_bar); - mBackButton = (ImageView) v.findViewById(R.id.back_button); - mHomeButton = (ImageView) v.findViewById(R.id.home_button); - mRecentButton = (ImageView) v.findViewById(R.id.recent_button); - - // Title Card - mTitleCard = (ViewGroup)v.findViewById(R.id.title_card); - mTitleLayout = (ViewGroup) v.findViewById(R.id.title_layout); - mTitle = (TextView) v.findViewById(R.id.title); - mAuthor = (TextView) v.findViewById(R.id.author); - mProgress = (ProgressBar) v.findViewById(R.id.apply_progress); - mOverflow = (ImageView) v.findViewById(R.id.overflow); - mOverflow.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (isShowingConfirmCancelOverlay()) { - hideConfirmCancelOverlay(); - } else if (isShowingCustomizeResetLayout()) { - hideCustomizeResetLayout(); - } - - PopupMenu popupmenu = new PopupMenu(getActivity(), mTitleCard, Gravity.END); - popupmenu.getMenuInflater().inflate(R.menu.overflow, popupmenu.getMenu()); - - Menu menu = popupmenu.getMenu(); - if (CURRENTLY_APPLIED_THEME.equals(mPkgName) || - mPkgName.equals(Utils.getDefaultThemePackageName(getActivity())) || - mPkgName.equals(ThemeConfig.SYSTEM_DEFAULT)) { - menu.findItem(R.id.menu_delete).setEnabled(false); - } - if (!mThemeTagLayout.isCustomizedTagEnabled()) { - menu.findItem(R.id.menu_reset).setVisible(false); - } - - popupmenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(MenuItem item) { - return onPopupMenuItemClick(item); - } - }); - popupmenu.show(); - } - }); - mCustomize = (ImageView) v.findViewById(R.id.customize); - mCustomize.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - if (!isShowingConfirmCancelOverlay() && !isShowingCustomizeResetLayout()) { - getChooserActivity().expand(); - } - } - }); - - mDelete = (ImageView) v.findViewById(R.id.delete); - mDelete.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - showDeleteThemeOverlay(); - } - }); - if (Utils.getDefaultThemePackageName(getActivity()).equals(mPkgName) || - ThemeConfig.SYSTEM_DEFAULT.equals(mPkgName)) { - mDelete.setVisibility(View.GONE); - } - - mReset = (ImageView) v.findViewById(R.id.reset); - mReset.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - showResetThemeOverlay(); - } - }); - mReset.setVisibility(View.GONE); - - if (!Utils.hasNavigationBar(getActivity())) { - adjustScrollViewPaddingTop(); - mNavBarCard.setVisibility(View.GONE); - } - - // Additional cards which should hang out offscreen until expanded - mAdditionalCards = (LinearLayout) v.findViewById(R.id.additional_cards); - - mWallpaperCard = (WallpaperCardView) v.findViewById(R.id.wallpaper_card); - mLockScreenCard = (WallpaperCardView) v.findViewById(R.id.lockscreen_card); - int translationY = getDistanceToMoveBelowScreen(mAdditionalCards); - mAdditionalCards.setTranslationY(translationY); - - mConfirmCancelOverlay = (ConfirmCancelOverlay) v.findViewById(R.id.confirm_cancel_overlay); - mClickableView = v.findViewById(R.id.clickable_view); - - mCustomizeResetLayout = v.findViewById(R.id.customize_reset_theme_layout); - mDismissButton = mCustomizeResetLayout.findViewById(R.id.btn_dismiss); - mDismissButton.setOnClickListener(mCustomizeResetClickListener); - mResetButton = mCustomizeResetLayout.findViewById(R.id.btn_reset); - mResetButton.setOnClickListener(mCustomizeResetClickListener); - mCustomizeButton = mCustomizeResetLayout.findViewById(R.id.btn_customize); - mCustomizeButton.setOnClickListener(mCustomizeResetClickListener); - - mProcessingThemeLayout = v.findViewById(R.id.processing_theme_layout); - - if (mPkgName.equals(Utils.getDefaultThemePackageName(getActivity()))) { - mThemeTagLayout.setDefaultTagEnabled(true); - } - if (PreferenceUtils.hasThemeBeenUpdated(getActivity(), mPkgName)) { - mThemeTagLayout.setUpdatedTagEnabled(true); - } - - if (mSkipLoadingAnim) { - mLoadingView.setVisibility(View.GONE); - mTitleLayout.setAlpha(1f); - } - - getLoaderManager().initLoader(LOADER_ID_ALL, null, this); - - setupCardClickListeners(v); - - return v; - } - - @Override - public void onPause() { - super.onPause(); - stopMediaPlayers(); - } - - @Override - public void onResume() { - super.onResume(); - ThemeManager tm = getThemeManager(); - if (tm != null) { - if (isThemeProcessing()) { - tm.registerProcessingListener(this); - mProcessingThemeLayout.setVisibility(View.VISIBLE); - mCustomize.setVisibility(View.INVISIBLE); - mCustomize.setAlpha(0f); - if (mDelete.getVisibility() != View.GONE) { - mDelete.setVisibility(View.INVISIBLE); - mDelete.setAlpha(0f); - } - mProcessingResources = true; - } else { - mCustomize.setVisibility(View.VISIBLE); - mCustomize.setAlpha(1f); - if (mDelete.getVisibility() != View.GONE) { - mDelete.setVisibility(View.VISIBLE); - mDelete.setAlpha(1f); - } - mProcessingResources = false; - } - } - } - - @Override - public void onDestroy() { - super.onDestroy(); - freeMediaPlayers(); - ThemeManager tm = getThemeManager(); - if (tm != null) { - tm.removeClient(this); - tm.unregisterProcessingListener(this); - } - } - - @Override - public void onRequestPermissionsResult(int requestCode, String[] permissions, - int[] grantResults) { - if (requestCode == PERMISSION_REQUEST) { - int N = permissions.length; - for (int i = 0; i < N; i++) { - if (READ_EXTERNAL_STORAGE.equals(permissions[i])) { - if (grantResults[i] == PERMISSION_GRANTED) { - // Run the runnable now that we have been granted permission - if (mAfterPermissionGrantedRunnable != null) { - mAfterPermissionGrantedRunnable.run(); - mAfterPermissionGrantedRunnable = null; - } - } else { - // inform the user that they will be unable to pick an image because - // we were not granted permission to do so - Toast.makeText(getActivity(), - R.string.read_external_permission_denied_message, - Toast.LENGTH_LONG).show(); - } - } - } - } - } - - @Override - public void onProgress(int progress) { - mProgress.setProgress(progress); - } - - private void setLiveLockScreenAsKeyguard(boolean setLLS) { - ComponentName cn = null; - if (setLLS) { - try { - final String[] permissions = Utils.getDangerousPermissionsNotGranted(getActivity(), - LLS_PACKAGE_NAME); - if (permissions.length > 0) { - Intent reqIntent = Utils.buildPermissionGrantRequestIntent(getActivity(), - LLS_PACKAGE_NAME, permissions); - if (reqIntent != null) { - startActivity(reqIntent); - } - } - cn = new ComponentName(LLS_PACKAGE_NAME, LLS_PROVIDER_NAME); - } catch (InvalidParameterException e) { - Log.e(TAG, "Package Manager couldn't find package " + LLS_PACKAGE_NAME, e); - return; - } - } - - CmLockPatternUtils lockPatternUtils = new CmLockPatternUtils(getActivity()); - try { - lockPatternUtils.setThirdPartyKeyguard(cn); - } catch (PackageManager.NameNotFoundException e) { - // we should not be here! - } - } - - @Override - public void onFinish(boolean isSuccess) { - // We post a runnable to mHandler so the client is removed from the same thread - mHandler.post(new Runnable() { - @Override - public void run() { - ThemeManager tm = getThemeManager(); - if (tm != null) tm.removeClient(ThemeFragment.this); - } - }); - if (isSuccess) { - if (mExternalLockscreenUri != null) { - // Handle setting an external wallpaper in a separate thread - // Need to do this AFTER ThemeMgr is done processing our change request. - // The external lock screen that we just applied would be removed when - // the change request is setting/clearing the lock screen - new Thread(mApplyExternalLockscreenRunnable).start(); - } - Map appliedComponents = getComponentsToApply(); - boolean modLLS = appliedComponents.containsKey(MODIFIES_LIVE_LOCK_SCREEN); - if (modLLS) { - String pkgName = appliedComponents.get(MODIFIES_LIVE_LOCK_SCREEN); - if (pkgName.equals(LOCKSCREEN_NONE)) { - setLiveLockScreenAsKeyguard(false); - } else { - setLiveLockScreenAsKeyguard(true); - } - } - mProgress.setProgress(100); - animateProgressOut(); - } - getChooserActivity().themeChangeEnd(isSuccess); - } - - @Override - public void onFinishedProcessing(String pkgName) { - if (pkgName.equals(mPkgName) || pkgName.equals(mBaseThemePkgName)) { - ThemeManager tm = getThemeManager(); - if (tm != null) { - tm.unregisterProcessingListener(this); - } - } - } - - @Override - public void setUserVisibleHint(boolean isVisibleToUser) { - super.setUserVisibleHint(isVisibleToUser); - if (mThemeTagLayout == null) return; - - if (!isVisibleToUser) { - if (PreferenceUtils.hasThemeBeenUpdated(getActivity(), mPkgName)) { - mThemeTagLayout.setUpdatedTagEnabled(true); - } - } else { - if (PreferenceUtils.hasThemeBeenUpdated(getActivity(), mPkgName)) { - PreferenceUtils.removeUpdatedTheme(getActivity(), mPkgName); - } - } - } - - public void setWallpaperImageUri(Uri uri) { - mExternalWallpaperUri = uri; - final Point size = new Point(mWallpaper.getWidth(), mWallpaper.getHeight()); - final Drawable wp = getWallpaperDrawableFromUri(uri, size); - mWallpaperCard.setWallpaper(wp); - mWallpaper.setImageDrawable(wp); - // remove the entry from mSelectedComponentsMap - mSelectedComponentsMap.remove(ThemesColumns.MODIFIES_LAUNCHER); - } - - public void setLockscreenImageUri(Uri uri) { - mExternalLockscreenUri = uri; - final Point size = new Point(mLockScreenCard.getWidth(), mLockScreenCard.getHeight()); - final Drawable wp = getWallpaperDrawableFromUri(uri, size); - if (mLockScreenCard.isShowingEmptyView()) { - mLockScreenCard.setEmptyViewEnabled(false); - } - mLockScreenCard.setWallpaper(wp); - // remove the entry from mSelectedComponentsMap - mSelectedComponentsMap.remove(ThemesColumns.MODIFIES_LIVE_LOCK_SCREEN); - mSelectedComponentsMap.remove(ThemesColumns.MODIFIES_LOCKSCREEN); - } - - protected Drawable getWallpaperDrawableFromUri(Uri uri, Point size) { - final Context context = getActivity(); - final Resources res = context.getResources(); - Bitmap bmp = WallpaperUtils.createPreview(size, context, uri, null, res, 0, 0, false); - if (bmp != null) { - return new BitmapDrawable(res, bmp); - } - return null; - } - - protected ChooserActivity getChooserActivity() { - return (ChooserActivity) getActivity(); - } - - private void adjustScrollViewPaddingTop() { - Resources res = getResources(); - int extraPadding = - res.getDimensionPixelSize(R.dimen.navigation_bar_height) / 2; - mScrollView.setPadding(mScrollView.getPaddingLeft(), - mScrollView.getPaddingTop() + extraPadding, mScrollView.getPaddingRight(), - mScrollView.getPaddingBottom()); - } - - protected boolean isThemeProcessing() { - ThemeManager tm = getThemeManager(); - if (tm != null) { - final String pkgName = mBaseThemePkgName != null ? mBaseThemePkgName : mPkgName; - return tm.isThemeBeingProcessed(pkgName); - } - return false; - } - - protected boolean onPopupMenuItemClick(MenuItem item) { - switch(item.getItemId()) { - /* TODO: Add back in once there is UX available for this feature - case R.id.menu_author: - Toast.makeText(getActivity(), - "Not supported", - Toast.LENGTH_LONG).show(); - break; - */ - case R.id.menu_delete: - showDeleteThemeOverlay(); - break; - } - - return true; - } - - public void expand() { - if (mCurrentLoaderId == LOADER_ID_ALL && mCurrentCursor != null) { - loadAdditionalCards(mCurrentCursor); - // we don't need this now that the additional cards are loaded, and - // we don't want to re-load these cards if the we expand again. - mCurrentCursor = null; - } - mClickableView.setVisibility(View.GONE); - mScrollView.setScrollingEnabled(true); - // Full width and height! - ViewGroup content = (ViewGroup) mScrollView.getParent(); - content.setPadding(0, 0, 0, 0); - ViewGroup.LayoutParams layoutParams = mPreviewContent.getLayoutParams(); - layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT; - mPreviewContent.setLayoutParams(layoutParams); - mScrollView.setPadding(0,0,0,0); - - // The parent of the wallpaper squishes the wp slightly because of padding from the 9 patch - // When the parent expands, the wallpaper returns to regular size which creates an - // undesireable effect. - Rect padding = new Rect(); - NinePatchDrawable bg = (NinePatchDrawable) mShadowFrame.getBackground(); - bg.getPadding(padding); - mIconCard.setPadding(padding.left, padding.top, padding.right, padding.bottom); - mShadowFrame.setBackground(null); - mShadowFrame.setPadding(0, 0, 0, 0); - - // Off screen cards will become visible and then be animated in - mWallpaperCard.setVisibility(View.VISIBLE); - - // Expand the children - int top = (int) getResources() - .getDimension(R.dimen.expanded_card_margin_top); - for (int i = 0; i < mPreviewContent.getChildCount(); i++) { - ComponentCardView child = (ComponentCardView) mPreviewContent.getChildAt(i); - - LinearLayout.LayoutParams lparams = - (LinearLayout.LayoutParams) child.getLayoutParams(); - if (child == mStatusBarCard) { - int statusBarHeight = getResources() - .getDimensionPixelSize(R.dimen.status_bar_height); - lparams.setMargins(0, top + statusBarHeight, 0, 0); - } else { - lparams.setMargins(0, top, 0, 0); - } - - child.setLayoutParams(lparams); - child.expand(false); - } - - // Expand the additional children. - mAdditionalCards.setVisibility(View.VISIBLE); - for (int i = 0; i < mAdditionalCards.getChildCount(); i++) { - View v = mAdditionalCards.getChildAt(i); - if (v instanceof ComponentCardView) { - ComponentCardView card = (ComponentCardView) v; - card.setVisibility(View.VISIBLE); - card.expand(true); - } - } - - // Collect the present position of all the children. The next layout/draw cycle will - // change these bounds since we just expanded them. Then we can animate from prev location - // to the new location. Note that the order of these calls matter as they all - // add themselves to the root layout as overlays - mScrollView.requestLayout(); - animateWallpaperOut(); - animateTitleCard(true, false); - animateChildren(true, getChildrensGlobalBounds(mPreviewContent)); - animateExtras(true); - mSelector = getChooserActivity().getComponentSelector(); - mSelector.setOnItemClickedListener(mOnComponentItemClicked); - if (mBootAnimation != null) mBootAnimation.start(); - hideThemeTagLayout(); - mExpanded = true; - } - - - - // Returns the boundaries for all the children of parent relative to the app window - private List getChildrensGlobalBounds(ViewGroup parent) { - List bounds = new ArrayList(); - for (int i = 0; i < parent.getChildCount(); i++) { - final View v = parent.getChildAt(i); - int[] pos = new int[2]; - v.getLocationInWindow(pos); - Rect boundary = new Rect(pos[0], pos[1], pos[0] + v.getWidth(), pos[1]+v.getHeight()); - bounds.add(boundary); - } - return bounds; - } - - public void performClick(boolean clickedOnContent) { - // Don't do anything if the theme is being processed - if (mProcessingThemeLayout.getVisibility() == View.VISIBLE) return; - - if (clickedOnContent) { - showApplyThemeOverlay(); - } else { - if (isShowingConfirmCancelOverlay()) { - hideConfirmCancelOverlay(); - } - } - } - - public void fadeOutCards(Runnable endAction) { - for (int i = 0; i < mPreviewContent.getChildCount(); i++) { - ComponentCardView v = (ComponentCardView) mPreviewContent.getChildAt(i); - v.animateFadeOut(); - } - mHandler.postDelayed(endAction, ComponentCardView.CARD_FADE_DURATION); - } - - public void collapse(final boolean applyTheme) { - mScrollView.setScrollingEnabled(false); - - // Pad the view so it appears thinner - ViewGroup content = (ViewGroup) mScrollView.getParent(); - Resources r = mScrollView.getContext().getResources(); - int leftRightPadding = (int) r.getDimension(R.dimen.collapsed_theme_page_padding); - content.setPadding(leftRightPadding, 0, leftRightPadding, 0); - - if (applyTheme) { - final boolean customized = isThemeCustomized(); - mThemeTagLayout.setCustomizedTagEnabled(customized); - mReset.setVisibility(customized ? View.VISIBLE : View.GONE); - } - - //Move the theme preview so that it is near the center of page per spec - int paddingTop = (int) r.getDimension(R.dimen.collapsed_theme_page_padding_top); - if (!Utils.hasNavigationBar(getActivity())) { - paddingTop += - r.getDimensionPixelSize(R.dimen.navigation_bar_height) / 2; - } - mScrollView.setPadding(0, paddingTop, 0, 0); - - // During expand the wallpaper size decreases slightly to makeup for 9patch padding - // so when we collapse we should increase it again. - mShadowFrame.setBackgroundResource(R.drawable.bg_themepreview_shadow); - Rect padding = new Rect(); - final NinePatchDrawable bg = (NinePatchDrawable) mShadowFrame.getBackground(); - bg.getPadding(padding); - mShadowFrame.setPadding(padding.left, padding.top, padding.right, padding.bottom); - - // Gradually fade the drop shadow back in or else it will be out of place - ValueAnimator shadowAnimation = ValueAnimator.ofObject(new IntEvaluator(), 0, 255); - shadowAnimation.setDuration(ANIMATE_DURATION); - shadowAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animator) { - bg.setAlpha((Integer) animator.getAnimatedValue()); - } - - }); - shadowAnimation.start(); - - //Move the title card back in - mTitleCard.setVisibility(View.VISIBLE); - mTitleCard.setTranslationY(0); - - // Shrink the height - ViewGroup.LayoutParams layoutParams = mPreviewContent.getLayoutParams(); - Resources resources = mPreviewContent.getResources(); - layoutParams.height = (int) resources.getDimension(R.dimen.theme_preview_height); - - mScrollView.requestLayout(); - List bounds = getChildrensGlobalBounds(mPreviewContent); - for (int i = 0; i < mPreviewContent.getChildCount(); i++) { - ComponentCardView child = (ComponentCardView) mPreviewContent.getChildAt(i); - LinearLayout.LayoutParams lparams = - (LinearLayout.LayoutParams) child.getLayoutParams(); - lparams.setMargins(0, 0, 0, 0); - - if (child.getId() == R.id.icon_container) { - int top = (int) child.getResources() - .getDimension(R.dimen.collapsed_icon_card_margin_top); - lparams.setMargins(0, top, 0, 0); - } else if (child.getId() == R.id.font_preview_container) { - int top = (int) child.getResources() - .getDimension(R.dimen.collapsed_font_card_margin_top); - lparams.setMargins(0, top, 0, 0); - } else if (child.getId() == R.id.navigation_bar_container) { - int top = (int) child.getResources() - .getDimension(R.dimen.collapsed_navbar_card_margin_top); - lparams.setMargins(0, top, 0, 0); - } - - child.getLayoutParams(); - child.collapse(); - } - - // Collapse additional cards - for (int i = 0; i < mAdditionalCards.getChildCount(); i++) { - View v = mAdditionalCards.getChildAt(i); - if (v instanceof ComponentCardView) { - ComponentCardView card = (ComponentCardView) v; - card.setVisibility(View.VISIBLE); - card.collapse(); - } - } - - animateChildren(false, bounds); - animateExtras(false); - animateWallpaperIn(); - animateTitleCard(false, applyTheme); - if (mBootAnimation != null) mBootAnimation.stop(); - stopMediaPlayers(); - showThemeTagLayout(); - - // Need to set the wallpaper background to black if the user has selected to apply - // the "none" wallpaper - if (applyTheme) { - String pkgName = mSelectedComponentsMap.get(ThemesColumns.MODIFIES_LAUNCHER); - if (pkgName != null && pkgName.length() == 0) { - mWallpaper.setImageResource(R.drawable.wallpaper_none_bg); - } - // we do this here instead of in applyTheme() because this can take a bit longer - // to propagate the change from WallpaperManager back to us - if (mExternalWallpaperUri != null) { - // Handle setting an external wallpaper in a separate thread - new Thread(mApplyExternalWallpaperRunnable).start(); - } - } - mExpanded = false; - } - - // This will animate the children's vertical positions between the previous bounds and the - // new bounds which occur on the next draw - private void animateChildren(final boolean isExpanding, final List prevBounds) { - final ViewGroup root = (ViewGroup) getActivity().getWindow() - .getDecorView().findViewById(android.R.id.content); - - final Resources res = getResources(); - final float yOffset = - res.getDimensionPixelSize(R.dimen.expand_collapse_child_offset) - * (isExpanding ? -1 : 1); - // Grab the child's new location and animate from prev to current loc. - final ViewTreeObserver observer = mScrollContent.getViewTreeObserver(); - observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { - public boolean onPreDraw() { - observer.removeOnPreDrawListener(this); - - for (int i = mPreviewContent.getChildCount() - 1; i >= 0; i--) { - final ComponentCardView v = (ComponentCardView) mPreviewContent.getChildAt(i); - - float prevY; - float endY; - float prevHeight; - float endHeight; - if (i >= prevBounds.size()) { - // View is being created - prevY = mPreviewContent.getTop() + mPreviewContent.getHeight(); - endY = v.getY(); - prevHeight = v.getHeight(); - endHeight = v.getHeight(); - } else { - Rect boundary = prevBounds.get(i); - prevY = boundary.top; - prevHeight = boundary.height(); - - int[] endPos = new int[2]; - v.getLocationInWindow(endPos); - endY = endPos[1]; - endHeight = v.getHeight(); - } - - int paddingTop = v.getPaddingTop() / 2; - float dy = (prevY - endY - paddingTop) + (prevHeight - endHeight) / 2; - dy += yOffset; - v.setTranslationY(dy); - root.getOverlay().add(v); - - // Expanding has a delay while the wallpaper begins to fade out - // Collapsing is opposite of this so wallpaper will have the delay instead - int startDelay = isExpanding ? ANIMATE_START_DELAY : 0; - - v.animate() - .setStartDelay(startDelay) - .translationY(0) - .setDuration(ANIMATE_DURATION) - .setInterpolator( - new DecelerateInterpolator(ANIMATE_INTERPOLATE_FACTOR)) - .withEndAction(new Runnable() { - public void run() { - root.getOverlay().remove(v); - mPreviewContent.addView(v, 0); - } - }); - v.postDelayed(new Runnable() { - public void run() { - if (isExpanding) { - v.animateExpand(); - } - } - }, ANIMATE_DURATION / 2); - } - return true; - } - }); - } - - private void animateExtras(final boolean isExpanding) { - int[] pos = new int[2]; - mAdditionalCards.getLocationInWindow(pos); - final ViewGroup parent = (ViewGroup) mAdditionalCards.getParent(); - final ViewGroup root = (ViewGroup) getActivity().getWindow() - .getDecorView().findViewById(android.R.id.content); - - // During a collapse we don't want the card to shrink so add it to the overlay now - // During an expand we want the card to expand so add it to the overlay post-layout - if (!isExpanding) { - root.getOverlay().add(mAdditionalCards); - } - - // Expanding has a delay while the wallpaper begins to fade out - // Collapsing is opposite of this so wallpaper will have the delay instead - final int startDelay = isExpanding ? ANIMATE_START_DELAY : 0; - final ViewTreeObserver observer = mScrollContent.getViewTreeObserver(); - observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { - public boolean onPreDraw() { - observer.removeOnPreDrawListener(this); - - int translationY = 0; - if (isExpanding) { - root.getOverlay().add(mAdditionalCards); - } else { - translationY = getDistanceToMoveBelowScreen(mAdditionalCards); - } - - int duration = isExpanding ? ANIMATE_DURATION + 100 : ANIMATE_DURATION; - mAdditionalCards.animate() - .setStartDelay(startDelay) - .translationY(translationY) - .setDuration(duration) - .setInterpolator( - new DecelerateInterpolator(ANIMATE_INTERPOLATE_FACTOR)) - .withEndAction(new Runnable() { - public void run() { - if (!isExpanding) { - mAdditionalCards.setVisibility(View.INVISIBLE); - } - root.getOverlay().remove(mAdditionalCards); - parent.addView(mAdditionalCards); - } - }); - return false; - } - }); - } - - private int getDistanceToMoveBelowScreen(View v) { - Display display = getActivity().getWindowManager().getDefaultDisplay(); - Point p = new Point(); - display.getSize(p); - int heightId = getResources() - .getIdentifier("navigation_bar_height", "dimen", "android"); - int navbar_height = getResources().getDimensionPixelSize(heightId); - int[] pos = new int[2]; - v.getLocationInWindow(pos); - return p.y + navbar_height - pos[1]; - } - - private void animateTitleCard(final boolean expand, final boolean applyTheme) { - final ViewGroup parent = (ViewGroup) mTitleCard.getParent(); - // Get current location of the title card - int[] location = new int[2]; - mTitleCard.getLocationOnScreen(location); - final int prevY = location[1]; - final int position = parent.indexOfChild(mTitleCard); - - final ViewTreeObserver observer = mScrollContent.getViewTreeObserver(); - observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { - public boolean onPreDraw() { - observer.removeOnPreDrawListener(this); - - final ViewGroup root = (ViewGroup) getActivity().getWindow() - .getDecorView().findViewById(android.R.id.content); - - root.getOverlay().add(mTitleCard); - - //Move title card back where it was before the relayout - float alpha = 1f; - if (expand) { - int[] endPos = new int[2]; - mTitleCard.getLocationInWindow(endPos); - int endY = endPos[1]; - mTitleCard.setTranslationY(prevY - endY); - alpha = 0; - } else { - } - - // Fade the title card and move it out of the way - mTitleCard.animate() - .alpha(alpha) - .setDuration(ANIMATE_DURATION) - .withEndAction(new Runnable() { - public void run() { - root.getOverlay().remove(mTitleCard); - parent.addView(mTitleCard, position); - if (expand) { - mTitleCard.setVisibility(View.INVISIBLE); - } else { - mTitleCard.setVisibility(View.VISIBLE); - mClickableView.setVisibility(View.VISIBLE); - if (applyTheme) { - // The title card is the last animation when collapsing so - // we will handle applying the theme, if applicable, here - applyTheme(); - } - } - } - }); - return true; - } - }); - } - - private void animateWallpaperOut() { - final ViewGroup root = (ViewGroup) getActivity().getWindow() - .getDecorView().findViewById(android.R.id.content); - - int[] location = new int[2]; - mWallpaper.getLocationOnScreen(location); - - final int prevY = location[1]; - - final ViewTreeObserver observer = mScrollContent.getViewTreeObserver(); - observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { - public boolean onPreDraw() { - observer.removeOnPreDrawListener(this); - root.getOverlay().add(mWallpaper); - - int[] location = new int[2]; - mWallpaper.getLocationOnScreen(location); - final int newY = location[1]; - - mWallpaper.setTranslationY(prevY - newY); - mWallpaper.animate() - .alpha(0f) - .setDuration(300) - .withEndAction(new Runnable() { - public void run() { - root.getOverlay().remove(mWallpaper); - mShadowFrame.addView(mWallpaper, 0); - mWallpaper.setVisibility(View.GONE); - } - }); - return true; - - } - }); - } - - private void animateWallpaperIn() { - mWallpaper.setVisibility(View.VISIBLE); - mWallpaper.setTranslationY(0); - mWallpaper.animate() - .alpha(1f) - .setDuration(300); - } - - protected String getAppliedFontPackageName() { - final Configuration config = getActivity().getResources().getConfiguration(); - final ThemeConfig themeConfig = config != null ? config.themeConfig : null; - return themeConfig != null ? themeConfig.getFontPkgName() : - ThemeConfig.getSystemTheme().getFontPkgName(); - } - - protected ThemeManager getThemeManager() { - return ThemeManager.getInstance(getActivity()); - } - - private void freeMediaPlayers() { - for (MediaPlayer mp : mMediaPlayers.values()) { - if (mp != null) { - mp.stop(); - mp.release(); - } - } - mMediaPlayers.clear(); - } - - protected View.OnClickListener mPlayPauseClickListener = new View.OnClickListener() { - @Override - public void onClick(View v) { - MediaPlayer mp = (MediaPlayer) v.getTag(); - if (mp != null) { - if (mp.isPlaying()) { - ((ImageView) v).setImageResource(R.drawable.media_sound_preview); - mp.pause(); - mp.seekTo(0); - } else { - stopMediaPlayers(); - ((ImageView) v).setImageResource(R.drawable.media_sound_stop); - mp.start(); - } - } - } - }; - - protected MediaPlayer.OnCompletionListener mPlayCompletionListener - = new MediaPlayer.OnCompletionListener() { - @Override - public void onCompletion(MediaPlayer mp) { - for (ImageView v : mMediaPlayers.keySet()) { - if (mp == mMediaPlayers.get(v)) { - if (v != null) { - v.setImageResource(R.drawable.media_sound_preview); - } - } - } - } - }; - - private void stopMediaPlayers() { - for (ImageView v : mMediaPlayers.keySet()) { - if (v != null) { - v.setImageResource(R.drawable.media_sound_preview); - } - MediaPlayer mp = mMediaPlayers.get(v); - if (mp != null && mp.isPlaying()) { - mp.pause(); - mp.seekTo(0); - } - } - } - - protected void resetTheme() { - mSelectedComponentsMap.clear(); - Bundle args = new Bundle(); - args.putString(ARG_PACKAGE_NAME, mBaseThemePkgName); - args.putLong(ARG_COMPONENT_ID, DEFAULT_COMPONENT_ID); - getLoaderManager().restartLoader(LOADER_ID_ALL, args, this); - mThemeResetting = true; - } - - @Override - public Loader onCreateLoader(int id, Bundle args) { - String pkgName = mPkgName; - long componentId = DEFAULT_COMPONENT_ID; - if (args != null) { - pkgName = args.getString(ARG_PACKAGE_NAME); - componentId = args.getLong(ARG_COMPONENT_ID, DEFAULT_COMPONENT_ID); - } - return CursorLoaderHelper.themeFragmentCursorLoader(getActivity(), id, pkgName, - componentId); - } - - @Override - public void onLoadFinished(Loader loader, Cursor c) { - if (c.getCount() == 0) return; - mCurrentCursor = c; - mCurrentLoaderId = loader.getId(); - c.moveToFirst(); - boolean animate = !mApplyThemeOnPopulated; - switch (mCurrentLoaderId) { - case LOADER_ID_ALL: - if (mProcessingResources && !isThemeProcessing()) { - mProcessingResources = false; - hideProcessingOverlay(); - } - loadLegacyThemeInfo(c); - populateSupportedComponents(c); - loadWallpaper(c, false); - loadStatusBar(c, false); - loadIcons(c, false); - loadNavBar(c, false); - loadTitle(c); - loadFont(c, false); - mHandler.post(new Runnable() { - @Override - public void run() { - animateContentIn(); - } - }); - if (mShowLockScreenSelectorAfterContentLoaded) { - getChooserActivity().expandContentAndAnimateLockScreenCardIn(); - mShowLockScreenSelectorAfterContentLoaded = false; - } - break; - case LOADER_ID_STATUS_BAR: - loadStatusBar(c, animate); - break; - case LOADER_ID_FONT: - loadFont(c, animate); - break; - case LOADER_ID_ICONS: - loadIcons(c, animate); - break; - case LOADER_ID_WALLPAPER: - loadWallpaper(c, animate); - break; - case LOADER_ID_NAVIGATION_BAR: - loadNavBar(c, animate); - break; - case LOADER_ID_LIVE_LOCK_SCREEN: - case LOADER_ID_LOCKSCREEN: - loadLockScreen(c, animate); - break; - case LOADER_ID_STYLE: - loadStyle(c, animate); - break; - case LOADER_ID_BOOT_ANIMATION: - loadBootAnimation(c); - break; - case LOADER_ID_RINGTONE: - loadAudible(RingtoneManager.TYPE_RINGTONE, c, animate); - break; - case LOADER_ID_NOTIFICATION: - loadAudible(RingtoneManager.TYPE_NOTIFICATION, c, animate); - break; - case LOADER_ID_ALARM: - loadAudible(RingtoneManager.TYPE_ALARM, c, animate); - break; - } - if (mCurrentLoaderId != LOADER_ID_ALL) { - if (!componentsChanged()) { - getChooserActivity().hideSaveApplyButton(); - } else if (!mApplyThemeOnPopulated) { - getChooserActivity().showSaveApplyButton(); - } - } - } - - @Override - public void onLoaderReset(Loader loader) {} - - private void loadAdditionalCards(Cursor c) { - for(int i=0; i < mAdditionalCards.getChildCount(); i++) { - View v = mAdditionalCards.getChildAt(i); - if (v instanceof ComponentCardView) { - String component = mCardIdsToComponentTypes.get(v.getId()); - loadAdditionalCard(c, component, shouldShowComponentCard(component)); - } - } - } - - private void loadAdditionalCard(Cursor c, String component, boolean hasContent) { - if (MODIFIES_LOCKSCREEN.equals(component)) { - if (hasContent) { - loadLockScreen(c, false); - } else { - mLockScreenCard.clearWallpaper(); - mLockScreenCard.setEmptyViewEnabled(true); - setAddComponentTitle(mLockScreenCard, getString(R.string.lockscreen_label)); - } - } else if (MODIFIES_LAUNCHER.equals(component)) { - // this was already loaded so no need to do this again. - } else if (MODIFIES_OVERLAYS.equals(component)) { - if (hasContent) { - loadStyle(c, false); - } else { - mStyleCard.setEmptyViewEnabled(true); - setAddComponentTitle(mStyleCard, - getString(R.string.style_label)); - } - } else if (MODIFIES_BOOT_ANIM.equals(component)) { - if (hasContent) { - loadBootAnimation(c); - } else { - mBootAnimationCard.setEmptyViewEnabled(true); - setAddComponentTitle(mBootAnimationCard, - getString(R.string.boot_animation_label)); - } - } else if (MODIFIES_RINGTONES.equals(component)) { - if (hasContent) { - loadAudible(RingtoneManager.TYPE_RINGTONE, c, false); - } else { - mRingtoneCard.setEmptyViewEnabled(true); - setAddComponentTitle(mRingtoneCard, - getAudibleLabel(RingtoneManager.TYPE_RINGTONE)); - } - } else if (MODIFIES_NOTIFICATIONS.equals(component)) { - if (hasContent) { - loadAudible(RingtoneManager.TYPE_NOTIFICATION, c, false); - } else { - mNotificationCard.setEmptyViewEnabled(true); - setAddComponentTitle(mNotificationCard, - getAudibleLabel(RingtoneManager.TYPE_NOTIFICATION)); - } - } else if (MODIFIES_ALARMS.equals(component)) { - if (hasContent) { - loadAudible(RingtoneManager.TYPE_ALARM, c, false); - } else { - mAlarmCard.setEmptyViewEnabled(true); - setAddComponentTitle(mAlarmCard, - getAudibleLabel(RingtoneManager.TYPE_ALARM)); - } - } else { - throw new IllegalArgumentException("Don't know how to load: " + component); - } - } - - protected void populateSupportedComponents(Cursor c) { - List components = ThemeUtils.getAllComponents(); - for(String component : components) { - int pkgIdx = c.getColumnIndex(ThemesColumns.PKG_NAME); - int modifiesCompIdx = c.getColumnIndex(component); - - String pkg = c.getString(pkgIdx); - boolean supported = (modifiesCompIdx >= 0) && (c.getInt(modifiesCompIdx) == 1); - if (supported) { - mBaseThemeSupportedComponents.add(component); - mSelectedComponentsMap.put(component, pkg); - } - } - - if (mApplyThemeOnPopulated) { - applyTheme(); - } - } - - /** - * Determines whether a card should be shown or not. - * UX Rules: - * 1) "My Theme" always shows all cards - * 2) Other themes only show what has been implemented in the theme - * - */ - protected Boolean shouldShowComponentCard(String component) { - String pkg = mSelectedComponentsMap.get(component); - return pkg != null && pkg.equals(mPkgName); - } - - protected void loadLegacyThemeInfo(Cursor c) { - int targetApiIdx = c.getColumnIndex(ThemesColumns.TARGET_API); - // If this is being called for a MyThemeFragment the index will be -1 so set to - // SYSTEM_TARGET_API so we don't display the tag. If the user applied a legacy theme - // then they should have already been warned. - int targetApi = targetApiIdx < 0 ? SYSTEM_TARGET_API : c.getInt(targetApiIdx); - mIsLegacyTheme = targetApi != SYSTEM_TARGET_API && targetApi <= Build.VERSION_CODES.KITKAT; - mThemeTagLayout.setLegacyTagEnabled(mIsLegacyTheme); - } - - protected void loadTitle(Cursor c) { - int titleIdx = c.getColumnIndex(ThemesColumns.TITLE); - int authorIdx = c.getColumnIndex(ThemesColumns.AUTHOR); - mTitle.setText(c.getString(titleIdx)); - mAuthor.setText(c.getString(authorIdx)); - } - - protected void loadWallpaper(Cursor c, boolean animate) { - mExternalWallpaperUri = null; - Drawable overlay = null; - if (animate) { - overlay = getOverlayDrawable(mWallpaperCard, true); - } - if (mWallpaperCard.isShowingEmptyView()) mWallpaperCard.setEmptyViewEnabled(false); - - int pkgNameIdx = c.getColumnIndex(ThemesColumns.PKG_NAME); - int wpIdx = c.getColumnIndex(PreviewColumns.WALLPAPER_PREVIEW); - int cmpntIdIdx = c.getColumnIndex(PreviewColumns.COMPONENT_ID); - final Resources res = getResources(); - Bitmap bitmap = Utils.loadBitmapBlob(c, wpIdx); - if (bitmap != null) { - mWallpaper.setImageBitmap(bitmap); - mWallpaperCard.setWallpaper(new BitmapDrawable(res, bitmap)); - String pkgName = c.getString(pkgNameIdx); - Long cmpntId = (cmpntIdIdx >= 0) ? c.getLong(cmpntIdIdx) : DEFAULT_COMPONENT_ID; - if (!mPkgName.equals(pkgName) || (mPkgName.equals(pkgName) - && mBaseThemeSupportedComponents.contains(MODIFIES_LAUNCHER))) { - mSelectedComponentsMap.put(MODIFIES_LAUNCHER, pkgName); - mSelectedWallpaperComponentId = cmpntId; - setCardTitle(mWallpaperCard, pkgName, getString(R.string.wallpaper_label)); - } - } else { - // Set the wallpaper to "None" - mWallpaperCard.setWallpaper(null); - setCardTitle(mWallpaperCard, WALLPAPER_NONE, getString(R.string.wallpaper_label)); - mSelectedComponentsMap.put(ThemesColumns.MODIFIES_LAUNCHER, WALLPAPER_NONE); - } - - if (animate) { - animateContentChange(R.id.wallpaper_card, mWallpaperCard, overlay); - } - } - - protected void loadLockScreen(Cursor c, boolean animate) { - mExternalLockscreenUri = null; - Drawable overlay = null; - if (animate) { - overlay = getOverlayDrawable(mLockScreenCard, true); - } - if (mLockScreenCard.isShowingEmptyView()) mLockScreenCard.setEmptyViewEnabled(false); - - int pkgNameIdx = c.getColumnIndex(ThemesColumns.PKG_NAME); - int liveLockIndex = c.getColumnIndex(MODIFIES_LIVE_LOCK_SCREEN); - boolean isLiveLockScreen = liveLockIndex >= 0 && c.getInt(liveLockIndex) == 1; - - int wpIdx = isLiveLockScreen - ? c.getColumnIndex(PreviewColumns.LIVE_LOCK_SCREEN_PREVIEW) - : c.getColumnIndex(PreviewColumns.LOCK_WALLPAPER_PREVIEW); - final Resources res = getResources(); - Bitmap bitmap = Utils.loadBitmapBlob(c, wpIdx); - if (bitmap != null) { - mLockScreenCard.setWallpaper(new BitmapDrawable(res, bitmap)); - String pkgName = c.getString(pkgNameIdx); - if (!mPkgName.equals(pkgName) || (mPkgName.equals(pkgName) - && (mBaseThemeSupportedComponents.contains(MODIFIES_LOCKSCREEN) || - mBaseThemeSupportedComponents.contains(MODIFIES_LIVE_LOCK_SCREEN)))) { - if (isLiveLockScreen) { - mSelectedComponentsMap.put(MODIFIES_LIVE_LOCK_SCREEN, pkgName); - if (mCurrentTheme.containsKey(MODIFIES_LOCKSCREEN)) { - mSelectedComponentsMap.put(MODIFIES_LOCKSCREEN, LOCKSCREEN_NONE); - } else { - mSelectedComponentsMap.remove(MODIFIES_LOCKSCREEN); - } - setCardTitle(mLockScreenCard, pkgName, - getString(R.string.live_lock_screen_label)); - } else { - mSelectedComponentsMap.put(MODIFIES_LOCKSCREEN, pkgName); - if (mCurrentTheme.containsKey(MODIFIES_LIVE_LOCK_SCREEN)) { - mSelectedComponentsMap.put(MODIFIES_LIVE_LOCK_SCREEN, LOCKSCREEN_NONE); - } else { - mSelectedComponentsMap.remove(MODIFIES_LIVE_LOCK_SCREEN); - } - setCardTitle(mLockScreenCard, pkgName, getString(R.string.lockscreen_label)); - } - } - } else { - // Set the lockscreen wallpaper to "None" - mLockScreenCard.setWallpaper(null); - setCardTitle(mLockScreenCard, WALLPAPER_NONE, getString(R.string.lockscreen_label)); - } - - if (animate) { - animateContentChange(R.id.lockscreen_card, mLockScreenCard, overlay); - } - } - - protected void loadStatusBar(Cursor c, boolean animate) { - int backgroundIdx = c.getColumnIndex(PreviewColumns.STATUSBAR_BACKGROUND); - int wifiIdx = c.getColumnIndex(PreviewColumns.STATUSBAR_WIFI_ICON); - int wifiMarginIdx = c.getColumnIndex(PreviewColumns.STATUSBAR_WIFI_COMBO_MARGIN_END); - int bluetoothIdx = c.getColumnIndex(PreviewColumns.STATUSBAR_BLUETOOTH_ICON); - int signalIdx = c.getColumnIndex(PreviewColumns.STATUSBAR_SIGNAL_ICON); - int batteryIdx = c.getColumnIndex(Utils.getBatteryIndex(mBatteryStyle)); - int clockColorIdx = c.getColumnIndex(PreviewColumns.STATUSBAR_CLOCK_TEXT_COLOR); - int pkgNameIdx = c.getColumnIndex(ThemesColumns.PKG_NAME); - - Bitmap background = Utils.loadBitmapBlob(c, backgroundIdx); - Bitmap bluetoothIcon = Utils.loadBitmapBlob(c, bluetoothIdx); - Bitmap wifiIcon = Utils.loadBitmapBlob(c, wifiIdx); - Bitmap signalIcon = Utils.loadBitmapBlob(c, signalIdx); - Bitmap batteryIcon = Utils.loadBitmapBlob(c, batteryIdx); - int wifiMargin = wifiMarginIdx != -1 ? c.getInt(wifiMarginIdx) : DEFAULT_WIFI_MARGIN; - int clockTextColor = clockColorIdx != -1 ? c.getInt(clockColorIdx) : DEFAULT_CLOCK_COLOR; - - Drawable overlay = null; - if (animate) { - overlay = getOverlayDrawable(mStatusBar, false); - } - if (mStatusBarCard.isShowingEmptyView()) mStatusBarCard.setEmptyViewEnabled(false); - - mStatusBar.setBackground(new BitmapDrawable(getActivity().getResources(), background)); - mBluetooth.setImageBitmap(bluetoothIcon); - mWifi.setImageBitmap(wifiIcon); - mSignal.setImageBitmap(signalIcon); - mBattery.setImageBitmap(batteryIcon); - mClock.setTextColor(clockTextColor); - - ViewGroup.MarginLayoutParams params = - (ViewGroup.MarginLayoutParams) mWifi.getLayoutParams(); - params.setMarginEnd(wifiMargin); - mWifi.setLayoutParams(params); - - if (mBatteryStyle == 4) { - mBattery.setVisibility(View.GONE); - } else { - mBattery.setVisibility(View.VISIBLE); - } - mStatusBar.post(new Runnable() { - @Override - public void run() { - mStatusBar.invalidate(); - } - }); - if (pkgNameIdx > -1) { - String pkgName = c.getString(pkgNameIdx); - if (!mPkgName.equals(pkgName) || (mPkgName.equals(pkgName) - && mBaseThemeSupportedComponents.contains(MODIFIES_STATUS_BAR))) { - mSelectedComponentsMap.put(MODIFIES_STATUS_BAR, pkgName); - setCardTitle(mStatusBarCard, pkgName, - getString(R.string.statusbar_label)); - } - } - if (animate) { - animateContentChange(R.id.status_bar_container, mStatusBar, overlay); - } - } - - protected void loadIcons(Cursor c, boolean animate) { - if (mIconCard.isShowingEmptyView()) { - mIconCard.setEmptyViewEnabled(false); - } - int[] iconIdx = new int[3]; - iconIdx[0] = c.getColumnIndex(PreviewColumns.ICON_PREVIEW_1); - iconIdx[1] = c.getColumnIndex(PreviewColumns.ICON_PREVIEW_2); - iconIdx[2] = c.getColumnIndex(PreviewColumns.ICON_PREVIEW_3); - int pkgNameIdx = c.getColumnIndex(ThemesColumns.PKG_NAME); - - // Set the icons. If the provider does not have an icon preview then - // fall back to the default icon set - IconPreviewHelper helper = new IconPreviewHelper(getActivity(), ""); - ViewGroup iconContainer = - (ViewGroup) mIconCard.findViewById(R.id.icon_preview_container); - int numOfChildren = iconContainer.getChildCount(); - - List iconViews = new ArrayList(numOfChildren); - for(int i=0; i < numOfChildren; i++) { - final View view = iconContainer.getChildAt(i); - if (!(view instanceof ImageView)) continue; - iconViews.add((ImageView) view); - } - - for(int i=0; i < iconViews.size() && i < iconIdx.length; i++) { - final ImageView v = iconViews.get(i); - Bitmap bitmap = Utils.loadBitmapBlob(c, iconIdx[i]); - Drawable oldIcon = v.getDrawable(); - Drawable newIcon; - if (bitmap == null) { - ComponentName component = sIconComponents[i]; - newIcon = helper.getDefaultIcon(component.getPackageName(), - component.getClassName()); - } else { - newIcon = new BitmapDrawable(getResources(), bitmap); - } - if (animate) { - Drawable[] layers = new Drawable[2]; - layers[0] = oldIcon instanceof IconTransitionDrawable ? - ((IconTransitionDrawable) oldIcon).getDrawable(1) : oldIcon; - layers[1] = newIcon; - final IconTransitionDrawable itd = new IconTransitionDrawable(layers); - v.postDelayed(new Runnable() { - @Override - public void run() { - itd.startTransition(ANIMATE_COMPONENT_CHANGE_DURATION); - v.setImageDrawable(itd); - } - }, ANIMATE_COMPONENT_ICON_DELAY * i); - } else { - v.setImageDrawable(newIcon); - } - } - if (pkgNameIdx > -1) { - String pkgName = c.getString(pkgNameIdx); - if (!mPkgName.equals(pkgName) || (mPkgName.equals(pkgName) - && mBaseThemeSupportedComponents.contains(MODIFIES_ICONS))) { - mSelectedComponentsMap.put(MODIFIES_ICONS, pkgName); - setCardTitle(mIconCard, pkgName, - getString(R.string.icon_label)); - } - } - } - - protected void loadNavBar(Cursor c, boolean animate) { - int backButtonIdx = c.getColumnIndex(PreviewColumns.NAVBAR_BACK_BUTTON); - int homeButtonIdx = c.getColumnIndex(PreviewColumns.NAVBAR_HOME_BUTTON); - int recentButtonIdx = c.getColumnIndex(PreviewColumns.NAVBAR_RECENT_BUTTON); - int backgroundIdx = c.getColumnIndex(PreviewColumns.NAVBAR_BACKGROUND); - if (backgroundIdx == -1) { - backgroundIdx = c.getColumnIndex(PreviewColumns.STATUSBAR_BACKGROUND); - } - int pkgNameIdx = c.getColumnIndex(ThemesColumns.PKG_NAME); - - Bitmap background = Utils.loadBitmapBlob(c, backgroundIdx); - Bitmap backButton = Utils.loadBitmapBlob(c, backButtonIdx); - Bitmap homeButton = Utils.loadBitmapBlob(c, homeButtonIdx); - Bitmap recentButton = Utils.loadBitmapBlob(c, recentButtonIdx); - - Drawable overlay = null; - if (animate) { - overlay = getOverlayDrawable(mNavBar, false); - } - if (mNavBarCard.isShowingEmptyView()) mNavBarCard.setEmptyViewEnabled(false); - - mNavBar.setBackground(new BitmapDrawable(getActivity().getResources(), background)); - mBackButton.setImageBitmap(backButton); - mHomeButton.setImageBitmap(homeButton); - mRecentButton.setImageBitmap(recentButton); - - if (pkgNameIdx > -1) { - String pkgName = c.getString(pkgNameIdx); - if (!mPkgName.equals(pkgName) || (mPkgName.equals(pkgName) - && mBaseThemeSupportedComponents.contains(MODIFIES_NAVIGATION_BAR))) { - mSelectedComponentsMap.put(MODIFIES_NAVIGATION_BAR, pkgName); - setCardTitle(mNavBarCard, pkgName, getString(R.string.navbar_label)); - } - } - if (animate) { - animateContentChange(R.id.navigation_bar_container, mNavBar, overlay); - } - } - - protected void loadFont(Cursor c, boolean animate) { - Drawable overlay = null; - if (animate) { - overlay = getOverlayDrawable(mFontPreview, true); - } - if (mFontCard.isShowingEmptyView()) mFontCard.setEmptyViewEnabled(false); - - int pkgNameIdx = c.getColumnIndex(ThemesColumns.PKG_NAME); - String pkgName = pkgNameIdx >= 0 ? c.getString(pkgNameIdx) : mPkgName; - TypefaceHelperCache cache = TypefaceHelperCache.getInstance(); - ThemedTypefaceHelper helper = cache.getHelperForTheme(getActivity(), pkgName); - mTypefaceNormal = helper.getTypeface(Typeface.NORMAL); - mFontPreview.setTypeface(mTypefaceNormal); - if (!mPkgName.equals(pkgName) || (mPkgName.equals(pkgName) - && mBaseThemeSupportedComponents.contains(MODIFIES_FONTS))) { - mSelectedComponentsMap.put(MODIFIES_FONTS, pkgName); - setCardTitle(mFontCard, pkgName, getString(R.string.font_label)); - } - - if (animate) { - animateContentChange(R.id.font_preview_container, mFontPreview, overlay); - } - } - - protected void loadStyle(Cursor c, boolean animate) { - Drawable overlay = null; - if (animate) { - overlay = getOverlayDrawable(mStylePreview, true); - } - if (mStyleCard.isShowingEmptyView()) { - mStyleCard.setEmptyViewEnabled(false); - } - - int pkgNameIdx = c.getColumnIndex(ThemesColumns.PKG_NAME); - int styleIdx = c.getColumnIndex(PreviewColumns.STYLE_PREVIEW); - mStylePreview.setImageBitmap(Utils.loadBitmapBlob(c, styleIdx)); - if (pkgNameIdx > -1) { - String pkgName = c.getString(pkgNameIdx); - if (!mPkgName.equals(pkgName) || (mPkgName.equals(pkgName) - && mBaseThemeSupportedComponents.contains(MODIFIES_OVERLAYS))) { - mSelectedComponentsMap.put(MODIFIES_OVERLAYS, pkgName); - setCardTitle(mStyleCard, pkgName, - getString(R.string.style_label)); - } - } - if (animate) { - animateContentChange(R.id.style_card, mStylePreview, overlay); - } - } - - protected void loadBootAnimation(Cursor c) { - if (mBootAnimationCard.isShowingEmptyView()) { - mBootAnimationCard.setEmptyViewEnabled(false); - } - int pkgNameIdx = c.getColumnIndex(ThemesColumns.PKG_NAME); - if (mBootAnimation != null) { - String pkgName; - if (pkgNameIdx > -1) { - pkgName = c.getString(pkgNameIdx); - if (!mPkgName.equals(pkgName) || (mPkgName.equals(pkgName) - && mBaseThemeSupportedComponents.contains(MODIFIES_BOOT_ANIM))) { - mSelectedComponentsMap.put(MODIFIES_BOOT_ANIM, pkgName); - setCardTitle(mBootAnimationCard, pkgName, - getString(R.string.boot_animation_label)); - } - } else { - pkgName = mCurrentTheme.get(MODIFIES_BOOT_ANIM); - } - mBootAnimation.stop(); - new AnimationLoader(getActivity(), pkgName, mBootAnimation).execute(); - } - } - - protected void loadAudible(int type, Cursor c, boolean animate) { - ComponentCardView audibleContainer = null; - ImageView playPause = null; - String component = null; - int parentResId = 0; - switch (type) { - case RingtoneManager.TYPE_RINGTONE: - audibleContainer = mRingtoneCard; - playPause = mRingtonePlayPause; - component = MODIFIES_RINGTONES; - parentResId = R.id.ringtone_preview_container; - break; - case RingtoneManager.TYPE_NOTIFICATION: - audibleContainer = mNotificationCard; - playPause = mNotificationPlayPause; - component = MODIFIES_NOTIFICATIONS; - parentResId = R.id.notification_preview_container; - break; - case RingtoneManager.TYPE_ALARM: - audibleContainer = mAlarmCard; - playPause = mAlarmPlayPause; - component = MODIFIES_ALARMS; - parentResId = R.id.alarm_preview_container; - break; - } - if (audibleContainer == null) return; - - View content = audibleContainer.findViewById(R.id.content); - Drawable overlay = null; - if (animate) { - overlay = getOverlayDrawable(content, true); - } - if (audibleContainer.isShowingEmptyView()) { - audibleContainer.setEmptyViewEnabled(false); - } - - int pkgNameIdx = c.getColumnIndex(ThemesColumns.PKG_NAME); - int titleIdx = c.getColumnIndex(ThemesColumns.TITLE); - if (playPause == null) { - playPause = (ImageView) audibleContainer.findViewById(R.id.play_pause); - } - TextView title = (TextView) audibleContainer.findViewById(R.id.audible_name); - MediaPlayer mp = mMediaPlayers.get(playPause); - if (mp == null) { - mp = new MediaPlayer(); - } - String pkgName = c.getString(pkgNameIdx); - setCardTitle(audibleContainer, pkgName, getAudibleLabel(type)); - AudibleLoadingThread thread = new AudibleLoadingThread(getActivity(), type, pkgName, mp); - title.setText(c.getString(titleIdx)); - if (!mPkgName.equals(pkgName) || (mPkgName.equals(pkgName) - && mBaseThemeSupportedComponents.contains(component))) { - mSelectedComponentsMap.put(component, pkgName); - } - - playPause.setVisibility(View.VISIBLE); - playPause.setTag(mp); - mMediaPlayers.put(playPause, mp); - playPause.setOnClickListener(mPlayPauseClickListener); - mp.setOnCompletionListener(mPlayCompletionListener); - if (animate) { - animateContentChange(parentResId, content, overlay); - } - thread.start(); - } - - protected Drawable getOverlayDrawable(View v, boolean requiresTransparency) { - if (!v.isDrawingCacheEnabled()) v.setDrawingCacheEnabled(true); - Bitmap cache = v.getDrawingCache(true).copy( - requiresTransparency ? Config.ARGB_8888 : Config.RGB_565, false); - Drawable d = cache != null ? new BitmapDrawable(getResources(), cache) : null; - v.destroyDrawingCache(); - - return d; - } - - protected String getAudibleLabel(int type) { - switch (type) { - case RingtoneManager.TYPE_RINGTONE: - return getString(R.string.ringtone_label); - case RingtoneManager.TYPE_NOTIFICATION: - return getString(R.string.notification_label); - case RingtoneManager.TYPE_ALARM: - return getString(R.string.alarm_label); - } - return null; - } - - protected void setCardTitle(ComponentCardView card, String pkgName, String title) { - TextView tv = (TextView) card.findViewById(R.id.label); - if (Utils.getDefaultThemePackageName(getActivity()).equals(pkgName)) { - tv.setText(getString(R.string.default_tag_text) + " " + title); - } else { - tv.setText(title); - } - } - - protected void setAddComponentTitle(ComponentCardView card, String title) { - TextView tv = (TextView) card.findViewById(R.id.label); - tv.setText(getString(R.string.add_component_text) + " " + title); - } - - public static ComponentName[] getIconComponents(Context context) { - if (sIconComponents == null || sIconComponents.length == 0) { - sIconComponents = new ComponentName[]{COMPONENT_DIALER, COMPONENT_MESSAGING, - COMPONENT_CAMERA, COMPONENT_BROWSER}; - - PackageManager pm = context.getPackageManager(); - - // if device does not have telephony replace dialer and mms - if (!pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { - sIconComponents[0] = COMPONENT_CALENDAR; - sIconComponents[1] = COMPONENT_GALERY; - } else { - // decide on which dialer icon to use - try { - if (pm.getPackageInfo(DIALER_NEXT_PACKAGE, 0) != null) { - sIconComponents[0] = COMPONENT_DIALERNEXT; - } - } catch (PackageManager.NameNotFoundException e) { - // default to COMPONENT_DIALER - } - } - - if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)) { - sIconComponents[2] = COMPONENT_SETTINGS; - } else { - // decide on which camera icon to use - try { - if (pm.getPackageInfo(CAMERA_NEXT_PACKAGE, 0) != null) { - sIconComponents[2] = COMPONENT_CAMERANEXT; - } - } catch (PackageManager.NameNotFoundException e) { - // default to COMPONENT_CAMERA - } - } - - } - return sIconComponents; - } - - private void setupCardClickListeners(View parent) { - for (int i = 0; i < mCardIdsToComponentTypes.size(); i++) { - parent.findViewById(mCardIdsToComponentTypes.keyAt(i)) - .setOnClickListener(mCardClickListener); - } - } - - private View.OnClickListener mCardClickListener = new View.OnClickListener() { - @Override - public void onClick(View v) { - if (isShowingConfirmCancelOverlay() || isShowingCustomizeResetLayout()) return; - if (mActiveCardId > 0) { - // need to fade the newly selected card in if another was currently selected. - ((ComponentCardView) v).animateCardFadeIn(); - } - mActiveCardId = v.getId(); - String component = mCardIdsToComponentTypes.get(mActiveCardId); - // Only pass on mSelectedWallpaperComponentId if dealing with mods_launcher - long selectedComponentId = (ThemesColumns.MODIFIES_LAUNCHER.equals(component)) ? - mSelectedWallpaperComponentId : DEFAULT_COMPONENT_ID; - String pkgName = mSelectedComponentsMap.get(component); - if (component.equals(MODIFIES_LOCKSCREEN) && TextUtils.isEmpty(pkgName)) { - String liveLockScreenPkg = mSelectedComponentsMap.get(MODIFIES_LIVE_LOCK_SCREEN); - if (liveLockScreenPkg != null) { - pkgName = liveLockScreenPkg; - } - } - getChooserActivity().showComponentSelector(component, pkgName, selectedComponentId, v); - fadeOutNonSelectedCards(mActiveCardId); - stopMediaPlayers(); - } - }; - - private ConfirmCancelOverlay.OnOverlayDismissedListener mApplyCancelListener = - new ConfirmCancelOverlay.OnOverlayDismissedListener() { - @Override - public void onDismissed(boolean accepted) { - hideConfirmCancelOverlay(accepted); - } - }; - - private ConfirmCancelOverlay.OnOverlayDismissedListener mDeleteConfirmationListener = - new ConfirmCancelOverlay.OnOverlayDismissedListener() { - @Override - public void onDismissed(boolean accepted) { - if (accepted) uninstallTheme(); - hideConfirmCancelOverlay(); - } - }; - - private ConfirmCancelOverlay.OnOverlayDismissedListener mResetConfirmationListener = - new ConfirmCancelOverlay.OnOverlayDismissedListener() { - @Override - public void onDismissed(boolean accepted) { - if (accepted) resetTheme(); - hideConfirmCancelOverlay(); - } - }; - - private View.OnClickListener mCustomizeResetClickListener = new View.OnClickListener() { - @Override - public void onClick(View v) { - if (v == mDismissButton) { - hideCustomizeResetLayout(CustomizeResetAction.Dismiss); - } else if (v == mResetButton) { - hideCustomizeResetLayout(CustomizeResetAction.Reset); - } else if (v == mCustomizeButton) { - hideCustomizeResetLayout(CustomizeResetAction.Customize); - } - } - }; - - protected void loadComponentFromPackage(String pkgName, String component, long componentId) { - Bundle args = new Bundle(); - args.putString(ARG_PACKAGE_NAME, pkgName); - args.putLong(ARG_COMPONENT_ID, componentId); - int loaderId = LOADER_ID_INVALID; - if (MODIFIES_STATUS_BAR.equals(component)) { - loaderId = LOADER_ID_STATUS_BAR; - } else if (MODIFIES_FONTS.equals(component)) { - loaderId = LOADER_ID_FONT; - } else if (MODIFIES_ICONS.equals(component)) { - loaderId = LOADER_ID_ICONS; - } else if (MODIFIES_NAVIGATION_BAR.equals(component)) { - loaderId = LOADER_ID_NAVIGATION_BAR; - } else if (MODIFIES_LAUNCHER.equals(component)) { - if (pkgName != null) { - if (TextUtils.isEmpty(pkgName)) { - mWallpaperCard.setWallpaper(null); - mSelectedComponentsMap.put(ThemesColumns.MODIFIES_LAUNCHER, WALLPAPER_NONE); - setCardTitle(mWallpaperCard, WALLPAPER_NONE, - getString(R.string.wallpaper_label)); - getChooserActivity().showSaveApplyButton(); - } else if (ComponentSelector.EXTERNAL_WALLPAPER.equals(pkgName)) { - // Check if we have READ_EXTERNAL_STORAGE permission and if not request it, - // otherwise let the user pick an image - if (getActivity().checkSelfPermission( - READ_EXTERNAL_STORAGE) != PERMISSION_GRANTED) { - mAfterPermissionGrantedRunnable = new Runnable() { - @Override - public void run() { - getChooserActivity().pickExternalWallpaper(); - setCardTitle(mWallpaperCard, WALLPAPER_NONE, - getString(R.string.wallpaper_label)); - } - }; - requestPermissions(new String[]{READ_EXTERNAL_STORAGE}, - PERMISSION_REQUEST); - } else { - getChooserActivity().pickExternalWallpaper(); - setCardTitle(mWallpaperCard, WALLPAPER_NONE, - getString(R.string.wallpaper_label)); - } - } else { - loaderId = LOADER_ID_WALLPAPER; - } - } - } else if (MODIFIES_LOCKSCREEN.equals(component) - || MODIFIES_LIVE_LOCK_SCREEN.equals(component)) { - if (pkgName != null && TextUtils.isEmpty(pkgName)) { - mLockScreenCard.setWallpaper(null); - mSelectedComponentsMap.put(ThemesColumns.MODIFIES_LOCKSCREEN, LOCKSCREEN_NONE); - - if(mSelectedComponentsMap.containsKey(MODIFIES_LIVE_LOCK_SCREEN)) { - mSelectedComponentsMap.put(MODIFIES_LIVE_LOCK_SCREEN, LOCKSCREEN_NONE); - } - setCardTitle(mLockScreenCard, WALLPAPER_NONE, - getString(R.string.lockscreen_label)); - if (mLockScreenCard.isShowingEmptyView()) { - mLockScreenCard.setEmptyViewEnabled(false); - } - getChooserActivity().showSaveApplyButton(); - } else if (ComponentSelector.EXTERNAL_WALLPAPER.equals(pkgName)) { - // Check if we have READ_EXTERNAL_STORAGE permission and if not request it, - // otherwise let the user pick an image - if (getActivity().checkSelfPermission( - READ_EXTERNAL_STORAGE) != PERMISSION_GRANTED) { - mAfterPermissionGrantedRunnable = new Runnable() { - @Override - public void run() { - getChooserActivity().pickExternalLockscreen(); - setCardTitle(mLockScreenCard, WALLPAPER_NONE, - getString(R.string.lockscreen_label)); - } - }; - requestPermissions(new String[] {READ_EXTERNAL_STORAGE}, - PERMISSION_REQUEST); - } else { - getChooserActivity().pickExternalLockscreen(); - setCardTitle(mLockScreenCard, WALLPAPER_NONE, - getString(R.string.lockscreen_label)); - } - } else if (ComponentSelector.MOD_LOCK.equals(pkgName)) { - startLiveLockScreenSettings(); - } else { - if (MODIFIES_LIVE_LOCK_SCREEN.equals(component)) { - loaderId = LOADER_ID_LIVE_LOCK_SCREEN; - } else { - loaderId = LOADER_ID_LOCKSCREEN; - } - } - } else if (MODIFIES_OVERLAYS.equals(component)) { - loaderId = LOADER_ID_STYLE; - } else if (MODIFIES_BOOT_ANIM.equals(component)) { - loaderId = LOADER_ID_BOOT_ANIMATION; - } else if (MODIFIES_RINGTONES.equals(component)) { - loaderId = LOADER_ID_RINGTONE; - } else if (MODIFIES_NOTIFICATIONS.equals(component)) { - loaderId = LOADER_ID_NOTIFICATION; - } else if (MODIFIES_ALARMS.equals(component)) { - loaderId = LOADER_ID_ALARM; - } else { - return; - } - - if (loaderId != LOADER_ID_INVALID) { - getLoaderManager().restartLoader(loaderId, args, ThemeFragment.this); - } - } - - private OnItemClickedListener mOnComponentItemClicked = new OnItemClickedListener() { - @Override - public void onItemClicked(String pkgName, long componentId, Bundle params) { - String component = mSelector.getComponentType(); - if (MODIFIES_LOCKSCREEN.equals(component) && params != null) { - boolean isLiveLockView = params.getBoolean( - ComponentSelector.IS_LIVE_LOCK_SCREEN_VIEW,false); - if (isLiveLockView) { - //We got here because an live lock thubmnail view was clicked. We need to - //replace the component to load the proper data from the provider. - component = MODIFIES_LIVE_LOCK_SCREEN; - } - } - loadComponentFromPackage(pkgName, component, componentId); - } - }; - - private void fadeOutNonSelectedCards(int selectedCardId) { - for (int i = 0; i < mCardIdsToComponentTypes.size(); i++) { - if (mCardIdsToComponentTypes.keyAt(i) != selectedCardId) { - ComponentCardView card = (ComponentCardView) getView().findViewById( - mCardIdsToComponentTypes.keyAt(i)); - if (card != null) card.animateCardFadeOut(); - } - } - } - - protected void animateContentChange(int parentId, View viewToAnimate, Drawable overlay) { - ((ComponentCardView) getView().findViewById(parentId)) - .animateContentChange(viewToAnimate, overlay, ANIMATE_COMPONENT_CHANGE_DURATION); - } - - private Runnable mApplyThemeRunnable = new Runnable() { - @Override - public void run() { - final Context context = getActivity(); - if (context != null) { - // Post this on mHandler so the client is added and removed from the same - // thread - mHandler.post(new Runnable() { - @Override - public void run() { - final Map componentsToApply = getComponentsToApply(); - if (componentsToApply != null && componentsToApply.size() > 0) { - final Map fullMap - = fillMissingComponentsWithDefault(componentsToApply); - ThemeManager tm = getThemeManager(); - if (tm != null) { - try { - tm.addClient(ThemeFragment.this); - } catch (IllegalArgumentException e) { - /* ignore since this means we already have a listener added */ - } - ThemeChangeRequest request = - getThemeChangeRequestForComponents(fullMap); - boolean value = request.getReqeustType(). - equals(RequestType.USER_REQUEST_MIXNMATCH); - - tm.requestThemeChange(request, !value); - } - mApplyThemeOnPopulated = false; - } else { - onFinish(true); - } - } - }); - } - } - }; - - protected Map fillMissingComponentsWithDefault( - Map originalMap) { - HashMap newMap = new HashMap(); - newMap.putAll(originalMap); - Map defaultMap = getEmptyComponentsMap(); - for(Map.Entry entry : defaultMap.entrySet()) { - String component = entry.getKey(); - String defaultPkg = entry.getValue(); - if (!newMap.containsKey(component)) { - newMap.put(component, defaultPkg); - } - } - return newMap; - } - - protected Map getEmptyComponentsMap() { - List componentsList = ThemeUtils.getAllComponents(); - Map defaultMap = new HashMap<>(componentsList.size()); - for (String component : componentsList) { - defaultMap.put(component, ""); - } - return defaultMap; - } - - /** - * This is the method that will be called when applying a theme and the idea is to override - * it in MyThemeFragment and pass in a different RequestType, once we have a type that indicates - * the user is mixing and matching instead of applying an entire theme. - * @param componentMap - * @return - */ - protected ThemeChangeRequest getThemeChangeRequestForComponents( - Map componentMap) { - return getThemeChangeRequestForComponents(componentMap, RequestType.USER_REQUEST); - } - - protected ThemeChangeRequest getThemeChangeRequestForComponents( - Map componentMap, RequestType requestType) { - ThemeChangeRequest.Builder builder = new ThemeChangeRequest.Builder(); - for (String component : componentMap.keySet()) { - builder.setComponent(component, componentMap.get(component)); - } - builder.setRequestType(requestType); - if (mThemeVersion >= 3) { - builder.setWallpaperId(mSelectedWallpaperComponentId != null - ? mSelectedWallpaperComponentId - : DEFAULT_COMPONENT_ID); - } - return builder.build(); - } - - protected Map getComponentsToApply() { - return mSelectedComponentsMap; - } - - private Runnable mApplyExternalWallpaperRunnable = new Runnable() { - @Override - public void run() { - // If an external image was selected for the wallpaper, we need to - // set that manually. - if (mExternalWallpaperUri != null) { - WallpaperManager wm = - WallpaperManager.getInstance(getActivity()); - final Context context = getActivity(); - final Resources res = context.getResources(); - final Point size = new Point(wm.getDesiredMinimumWidth(), - wm.getDesiredMinimumHeight()); - Bitmap bmp = WallpaperUtils.createPreview(size, context, mExternalWallpaperUri, - null, res, 0, 0, false); - try { - wm.setBitmap(bmp); - } catch (Exception e) { - Log.e(TAG, "Unable to set external wallpaper", e); - } - } - } - }; - - private Runnable mApplyExternalLockscreenRunnable = new Runnable() { - @Override - public void run() { - // If an external image was selected for the wallpaper, we need to - // set that manually. - if (mExternalLockscreenUri != null) { - WallpaperManager wm = - WallpaperManager.getInstance(getActivity()); - final Context context = getActivity(); - final Resources res = context.getResources(); - final Point size = new Point(); - ((Activity) context).getWindowManager().getDefaultDisplay().getRealSize(size); - Bitmap bmp = WallpaperUtils.createPreview(size, context, mExternalLockscreenUri, - null, res, 0, 0, false); - try { - wm.setKeyguardBitmap(bmp); - } catch (Exception e) { - Log.e(TAG, "Unable to set external lockscreen wallpaper", e); - } - } - } - }; - - class RestoreLockScreenCardRunnable implements Runnable { - - final private boolean mWasShowingNone; - private String mCurrentLockScreenPkgName; - - public RestoreLockScreenCardRunnable(boolean w, String pkgName) { - mWasShowingNone = w; - mCurrentLockScreenPkgName = pkgName; - } - - @Override - public void run() { - if (!TextUtils.isEmpty(mCurrentLockScreenPkgName)) { - loadComponentFromPackage(mCurrentLockScreenPkgName, - MODIFIES_LOCKSCREEN, 0); - } else if (mWasShowingNone) { - mLockScreenCard.setWallpaper(null); - TextView none = (TextView) mLockScreenCard.findViewById( - R.id.none); - if (none != null) { - none.setVisibility(View.VISIBLE); - } - mLockScreenCard.setEmptyViewEnabled(false); - } else { - mLockScreenCard.clearWallpaper(); - TextView none = (TextView) mLockScreenCard.findViewById( - R.id.none); - if (none != null) { - none.setVisibility(View.GONE); - } - mLockScreenCard.setEmptyViewEnabled(true); - setAddComponentTitle(mLockScreenCard, getString(R.string.lockscreen_label)); - } - } - } - - protected void applyTheme() { - if (mExternalWallpaperUri == null && mExternalLockscreenUri == null && - (mSelectedComponentsMap == null || mSelectedComponentsMap.size() <= 0)) { - return; - } - final Map componentsToApply = getComponentsToApply(); - boolean isLLSEnabled = CMSettings.Secure.getInt(getActivity().getContentResolver(), - LIVE_LOCK_SCREEN_ENABLED, 0) == 1; - if (!TextUtils.isEmpty(componentsToApply.get(MODIFIES_LIVE_LOCK_SCREEN)) && !isLLSEnabled) { - AlertDialog d = new AlertDialog.Builder(getActivity(), - android.R.style.Theme_Material_Dialog) - .setTitle(R.string.enable_live_lock_screen_dialog_title) - .setMessage(R.string.enable_live_lock_screen_dialog_message) - .setPositiveButton(R.string.enable_live_lock_screen_dialog_positive_btn_text, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - CMSettings.Secure.putInt(getActivity().getContentResolver(), - LIVE_LOCK_SCREEN_ENABLED, 1); - getChooserActivity().themeChangeStart(); - animateProgressIn(mApplyThemeRunnable); - } - }) - .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - mSelectedComponentsMap.remove(MODIFIES_LIVE_LOCK_SCREEN); - boolean wasNone = false; - if (TextUtils.equals("", mSelectedComponentsMap.get( - MODIFIES_LOCKSCREEN))) { - if (!TextUtils.isEmpty(mCurrentTheme.get(MODIFIES_LOCKSCREEN))) { - //The map entry was set to empty string because there's a - //lockscreen currently applied and setting this entry to empty - //would instruct the ThemeManager to clear the currently applied - //lockscreen, but the user decided not to enable LLS so we need - //to abort this change - mSelectedComponentsMap.put(MODIFIES_LOCKSCREEN, - mCurrentTheme.get(MODIFIES_LOCKSCREEN)); - } else { - wasNone = true; - } - } - //Restore the lockscreen card to its previous state - mHandler.post(new RestoreLockScreenCardRunnable(wasNone, - mCurrentTheme.get(MODIFIES_LOCKSCREEN))); - - //Did the user make more changes? - boolean modLLS = componentsToApply.containsKey( - MODIFIES_LIVE_LOCK_SCREEN); - boolean modLockscreen = componentsToApply.containsKey( - MODIFIES_LOCKSCREEN); - if (modLLS && ((modLockscreen && componentsToApply.size() > 2) || - (!modLockscreen && componentsToApply.size() > 1))) { - getChooserActivity().themeChangeStart(); - animateProgressIn(mApplyThemeRunnable); - } - } - }) - .setCancelable(false) - .create(); - d.setCanceledOnTouchOutside(false); - d.show(); - } else { - getChooserActivity().themeChangeStart(); - animateProgressIn(mApplyThemeRunnable); - } - } - - /** - * Use when applyTheme() might be too early. ie mSelectedComponentsMap is not pop. yet - * @param pkgName Only used in MyThemeFragment to apply components on top of current theme - * @param components Optional list of components to apply. - */ - protected void applyThemeWhenPopulated(String pkgName, List components) { - mApplyThemeOnPopulated = true; - } - - private void animateProgressIn(Runnable endAction) { - mProgress.setVisibility(View.VISIBLE); - mProgress.setProgress(0); - float pivotX = mTitleLayout.getWidth() - - getResources().getDimensionPixelSize(R.dimen.apply_progress_padding); - ScaleAnimation scaleAnim = new ScaleAnimation(0f, 1f, 1f, 1f, - pivotX, 0f); - scaleAnim.setDuration(ANIMATE_PROGRESS_IN_DURATION); - - mTitleLayout.animate() - .translationXBy(-(pivotX / 3)) - .alpha(0f) - .setDuration(ANIMATE_TITLE_OUT_DURATION) - .setInterpolator(new AccelerateInterpolator()) - .withEndAction(endAction).start(); - mProgress.startAnimation(scaleAnim); - } - - private void animateProgressOut() { - mProgress.setVisibility(View.VISIBLE); - float pivotX = mTitleLayout.getWidth() - - getResources().getDimensionPixelSize(R.dimen.apply_progress_padding); - ScaleAnimation scaleAnim = new ScaleAnimation(1f, 0f, 1f, 1f, - pivotX, 0f); - scaleAnim.setDuration(ANIMATE_PROGRESS_OUT_DURATION); - scaleAnim.setFillAfter(false); - scaleAnim.setAnimationListener(new Animation.AnimationListener() { - @Override - public void onAnimationStart(Animation animation) { - } - - @Override - public void onAnimationEnd(Animation animation) { - mProgress.setVisibility(View.GONE); - if (mThemeResetting) { - mThemeResetting = false; - mThemeTagLayout.setCustomizedTagEnabled(false); - } - } - - @Override - public void onAnimationRepeat(Animation animation) { - } - }); - - mTitleLayout.animate() - .translationXBy((pivotX / 3)) - .alpha(1f) - .setDuration(ANIMATE_TITLE_IN_DURATION) - .setInterpolator(new AccelerateInterpolator()) - .start(); - mProgress.startAnimation(scaleAnim); - if (mThemeResetting) mReset.setVisibility(View.GONE); - } - - private void animateContentIn() { - if (mSkipLoadingAnim) { - return; - } - AnimatorSet set = new AnimatorSet(); - set.setDuration(ANIMATE_TITLE_IN_DURATION); - set.play(ObjectAnimator.ofFloat(mLoadingView, "alpha", 1f, 0f)) - .with(ObjectAnimator.ofFloat(mTitleLayout, "alpha", 0f, 1f)); - set.addListener(new Animator.AnimatorListener() { - @Override - public void onAnimationStart(Animator animation) { - } - - @Override - public void onAnimationEnd(Animator animation) { - mLoadingView.setVisibility(View.GONE); - } - - @Override - public void onAnimationCancel(Animator animation) { - } - - @Override - public void onAnimationRepeat(Animator animation) { - } - }); - set.start(); - } - - private void disableActionButtons() { - mCustomize.setEnabled(false); - mDelete.setEnabled(false); - mReset.setEnabled(false); - } - - private void enableActionButtons() { - mCustomize.setEnabled(true); - mDelete.setEnabled(true); - mReset.setEnabled(true); - } - - public boolean isShowingConfirmCancelOverlay() { - return mConfirmCancelOverlay.getVisibility() == View.VISIBLE; - } - - public void showApplyThemeOverlay() { - if (mConfirmCancelOverlay.getVisibility() == View.VISIBLE) return; - mConfirmCancelOverlay.setTitle(R.string.apply_theme_overlay_title); - mConfirmCancelOverlay.setBackgroundColor(getActivity().getResources() - .getColor(R.color.apply_overlay_background)); - mConfirmCancelOverlay.setOnOverlayDismissedListener(mApplyCancelListener); - getChooserActivity().lockPager(); - ViewPropertyAnimator anim = mConfirmCancelOverlay.animate(); - mConfirmCancelOverlay.setVisibility(View.VISIBLE); - mConfirmCancelOverlay.setAlpha(0f); - anim.setListener(null); - anim.setDuration(ANIMATE_APPLY_LAYOUT_DURATION); - anim.alpha(1f).start(); - - if (mIsLegacyTheme) { - // Display cm11 theme warning message - TextView tv = (TextView) mConfirmCancelOverlay.findViewById(R.id.warning_message); - tv.setVisibility(View.VISIBLE); - tv.setText(String.format(getString(R.string.legacy_theme_warning), mTitle.getText())); - } else if (Utils.hasPerAppThemesApplied(getActivity())) { - // Display per app theme changes will be removed warning - TextView tv = (TextView) mConfirmCancelOverlay.findViewById(R.id.warning_message); - tv.setVisibility(View.VISIBLE); - tv.setText(String.format(getString(R.string.per_app_theme_removal_warning), - mTitle.getText())); - } - - disableActionButtons(); - mClickableView.setSoundEffectsEnabled(false); - } - - public void showDeleteThemeOverlay() { - if (mConfirmCancelOverlay.getVisibility() == View.VISIBLE) return; - mConfirmCancelOverlay.setTitle(R.string.delete_theme_overlay_title); - mConfirmCancelOverlay.setBackgroundColor(getActivity().getResources() - .getColor(R.color.delete_overlay_background)); - mConfirmCancelOverlay.setOnOverlayDismissedListener(mDeleteConfirmationListener); - getChooserActivity().lockPager(); - ViewPropertyAnimator anim = mConfirmCancelOverlay.animate(); - mConfirmCancelOverlay.setVisibility(View.VISIBLE); - mConfirmCancelOverlay.setAlpha(0f); - anim.setListener(null); - anim.setDuration(ANIMATE_APPLY_LAYOUT_DURATION); - anim.alpha(1f).start(); - - disableActionButtons(); - mClickableView.setSoundEffectsEnabled(false); - } - - public void showResetThemeOverlay() { - if (mConfirmCancelOverlay.getVisibility() == View.VISIBLE) return; - mConfirmCancelOverlay.setTitle(R.string.reset_theme_overlay_title); - mConfirmCancelOverlay.setBackgroundColor(getActivity().getResources() - .getColor(R.color.apply_overlay_background)); - mConfirmCancelOverlay.setOnOverlayDismissedListener(mResetConfirmationListener); - getChooserActivity().lockPager(); - ViewPropertyAnimator anim = mConfirmCancelOverlay.animate(); - mConfirmCancelOverlay.setVisibility(View.VISIBLE); - mConfirmCancelOverlay.setAlpha(0f); - anim.setListener(null); - anim.setDuration(ANIMATE_APPLY_LAYOUT_DURATION); - anim.alpha(1f).start(); - - disableActionButtons(); - mClickableView.setSoundEffectsEnabled(false); - } - - public void hideConfirmCancelOverlay() { - hideConfirmCancelOverlay(false); - } - - /** - * Hides the apply theme layout overlay and can apply the selected theme - * when the animation is finished. - * @param applyThemeWhenFinished If true, the current theme will be applied. - */ - private void hideConfirmCancelOverlay(final boolean applyThemeWhenFinished) { - getChooserActivity().unlockPager(); - ViewPropertyAnimator anim = mConfirmCancelOverlay.animate(); - mConfirmCancelOverlay.setVisibility(View.VISIBLE); - anim.setDuration(ANIMATE_APPLY_LAYOUT_DURATION); - anim.alpha(0f).start(); - anim.setListener(new Animator.AnimatorListener() { - @Override - public void onAnimationStart(Animator animation) { - } - - @Override - public void onAnimationEnd(Animator animation) { - mConfirmCancelOverlay.setVisibility(View.GONE); - if (applyThemeWhenFinished) applyTheme(); - } - - @Override - public void onAnimationCancel(Animator animation) { - } - - @Override - public void onAnimationRepeat(Animator animation) { - } - }); - - enableActionButtons(); - mClickableView.setSoundEffectsEnabled(true); - } - - public boolean isShowingCustomizeResetLayout() { - return mCustomizeResetLayout.getVisibility() == View.VISIBLE; - } - - public void showCustomizeResetLayout() { - if (mCustomizeResetLayout.getVisibility() == View.VISIBLE) return; - if (!mThemeTagLayout.isCustomizedTagEnabled()) { - mResetButton.setEnabled(false); - } else { - mResetButton.setEnabled(true); - } - getChooserActivity().lockPager(); - ViewPropertyAnimator anim = mCustomizeResetLayout.animate(); - mCustomizeResetLayout.setVisibility(View.VISIBLE); - mCustomizeResetLayout.setAlpha(0f); - anim.setListener(null); - anim.setDuration(ANIMATE_APPLY_LAYOUT_DURATION); - anim.alpha(1f).start(); - - disableActionButtons(); - mClickableView.setSoundEffectsEnabled(false); - } - - public void hideCustomizeResetLayout() { - hideCustomizeResetLayout(CustomizeResetAction.Dismiss); - } - - private void hideCustomizeResetLayout(final CustomizeResetAction action) { - getChooserActivity().unlockPager(); - ViewPropertyAnimator anim = mCustomizeResetLayout.animate(); - mCustomizeResetLayout.setVisibility(View.VISIBLE); - anim.setDuration(ANIMATE_APPLY_LAYOUT_DURATION); - anim.alpha(0f).start(); - anim.setListener(new Animator.AnimatorListener() { - @Override - public void onAnimationStart(Animator animation) { - } - - @Override - public void onAnimationEnd(Animator animation) { - mCustomizeResetLayout.setVisibility(View.GONE); - switch (action) { - case Customize: - getChooserActivity().expand(); - break; - case Reset: - resetTheme(); - break; - } - } - - @Override - public void onAnimationCancel(Animator animation) { - } - - @Override - public void onAnimationRepeat(Animator animation) { - } - }); - - enableActionButtons(); - mClickableView.setSoundEffectsEnabled(true); - } - - public void showThemeTagLayout() { - mThemeTagLayout.setVisibility(View.VISIBLE); - mThemeTagLayout.animate().alpha(1f).setStartDelay(ANIMATE_START_DELAY).start(); - } - - public void hideThemeTagLayout() { - mThemeTagLayout.setAlpha(0f); - mThemeTagLayout.setVisibility(View.GONE); - } - - public void hideProcessingOverlay() { - mProcessingThemeLayout.animate().alpha(0).withEndAction(new Runnable() { - @Override - public void run() { - mProcessingThemeLayout.setVisibility(View.GONE); - } - }).setDuration(ANIMATE_APPLY_LAYOUT_DURATION).start(); - mCustomize.setVisibility(View.VISIBLE); - mCustomize.setAlpha(0f); - mCustomize.animate().alpha(1f).setDuration(ANIMATE_APPLY_LAYOUT_DURATION).start(); - if (mDelete.getVisibility() != View.GONE) { - mDelete.setVisibility(View.VISIBLE); - mDelete.setAlpha(0f); - mDelete.animate().alpha(1f).setDuration(ANIMATE_APPLY_LAYOUT_DURATION).start(); - } - - enableActionButtons(); - mClickableView.setSoundEffectsEnabled(true); - } - - public void fadeInCards() { - for (int i = 0; i < mCardIdsToComponentTypes.size(); i++) { - final int key = mCardIdsToComponentTypes.keyAt(i); - if (key != mActiveCardId) { - ComponentCardView card = (ComponentCardView) getView().findViewById(key); - if (card != null) card.animateCardFadeIn(); - } - } - mActiveCardId = -1; - } - - public boolean componentsChanged() { - // If an external wallpaper/ls are set then something changed! - if (mExternalWallpaperUri != null || mExternalLockscreenUri != null) return true; - - for (String key : mSelectedComponentsMap.keySet()) { - if (!mPkgName.equals(mSelectedComponentsMap.get(key))) { - return true; - } - if (ThemesColumns.MODIFIES_LAUNCHER.equals(key) && - mCurrentWallpaperComponentId.value != mSelectedWallpaperComponentId) { - return true; - } - } - return false; - } - - protected boolean isThemeCustomized() { - final String themePkgName = getThemePackageName(); - for (String key : mSelectedComponentsMap.keySet()) { - final String selectedPkgName = mSelectedComponentsMap.get(key); - if (!themePkgName.equals(selectedPkgName)) { - return true; - } - if (mBaseThemeSupportedComponents.size() > 0 && - !mBaseThemeSupportedComponents.contains(key)) { - return true; - } - } - // finally check if we're missing anything from mBaseThemeSupportedComponents - for (String component : mBaseThemeSupportedComponents) { - if (!mSelectedComponentsMap.containsKey(component)) return true; - } - return false; - } - - public void clearChanges() { - mSelectedComponentsMap.clear(); - mExternalWallpaperUri = null; - mExternalLockscreenUri = null; - View none = mLockScreenCard.findViewById(R.id.none); - if (none != null && none.getVisibility() == View.VISIBLE) { - none.setVisibility(View.GONE); - } - TextView tv = (TextView) mLockScreenCard.findViewById(R.id.label); - if (tv != null) { - tv.setAlpha(1f); - tv.setBackgroundResource(R.drawable.wallpaper_label_bg); - } - getLoaderManager().restartLoader(LOADER_ID_ALL, null, ThemeFragment.this); - } - - public String getThemePackageName() { - if (mPkgName == null) { - // check if the package name is defined in the arguments bundle - Bundle bundle = getArguments(); - if (bundle != null) { - mPkgName = bundle.getString(ARG_PACKAGE_NAME); - } - } - return mPkgName; - } - - private void uninstallTheme() { - getChooserActivity().uninstallTheme(mPkgName); - } - - public void setCurrentTheme(Map currentTheme, - MutableLong currentWallpaperComponentId) { - mCurrentTheme = currentTheme; - mCurrentWallpaperComponentId = currentWallpaperComponentId; - } - - /** - * Slides the scrollview content up and adds a space view at the bottom - * of mAdditionalCards so all content can be visible above the selector. - * - * We are using a ValueAnimator here to scroll the content rather than calling - * mScrollView.smoothScrollBy() since the speed of that animation cannot be customized. - * @param yDelta - * @param selectorHeight - */ - public void slideContentIntoView(final int yDelta, int selectorHeight) { - Space space = (Space) mAdditionalCards.findViewById(ADDITIONAL_CONTENT_SPACE_ID); - if (space == null) { - // No space view yet so lets create it one - space = new Space(getActivity()); - space.setId(ADDITIONAL_CONTENT_SPACE_ID); - mAdditionalCards.addView(space, - new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, - selectorHeight)); - } else { - // Space view already exists so just update the LayoutParams - LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) space.getLayoutParams(); - params.height = selectorHeight; - space.setLayoutParams(params); - } - final int startY = mScrollView.getScrollY(); - final ValueAnimator scrollAnimator = - ValueAnimator.ofInt(startY, startY + yDelta); - scrollAnimator.setDuration(SLIDE_CONTENT_ANIM_DURATION); - scrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - int value = (Integer) animation.getAnimatedValue(); - mScrollView.scrollTo(0, value); - } - }); - scrollAnimator.start(); - } - - public Map getSelectedComponentsMap() { - return mSelectedComponentsMap; - } - - /** - * Slides the scrollview content down and removes a space view at the bottom - * of mAdditionalCards. - * - * We are using a ValueAnimator here to scroll the content rather than calling - * mScrollView.smoothScrollBy() since the speed of that animation cannot be customized. - * @param yDelta - */ - public void slideContentBack(int yDelta) { - final int startY = mScrollView.getScrollY(); - final ValueAnimator scrollAnimator = - ValueAnimator.ofInt(startY, startY + yDelta); - scrollAnimator.setDuration(SLIDE_CONTENT_ANIM_DURATION); - scrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - int value = (Integer) animation.getAnimatedValue(); - mScrollView.scrollTo(0, value); - } - }); - scrollAnimator.addListener(new Animator.AnimatorListener() { - @Override - public void onAnimationStart(Animator animation) { - } - - @Override - public void onAnimationEnd(Animator animation) { - View space = mAdditionalCards.findViewById(ADDITIONAL_CONTENT_SPACE_ID); - if (space != null) mAdditionalCards.removeView(space); - } - - @Override - public void onAnimationCancel(Animator animation) { - } - - @Override - public void onAnimationRepeat(Animator animation) { - } - }); - scrollAnimator.start(); - } - - public void showLockScreenCard() { - mHandler.postDelayed(new Runnable() { - @Override - public void run() { - final int scrollToY = mStatusBarCard.getMeasuredHeight() - + mFontCard.getMeasuredHeight() + mIconCard.getMeasuredHeight() - + mNavBarCard.getMeasuredHeight() + mWallpaperCard.getMeasuredHeight() / 2; - final ValueAnimator scrollAnimator = ValueAnimator.ofInt(0, scrollToY); - scrollAnimator.setDuration(LOCK_SCREEN_CARD_SCROLL_ANIMATION_DURATION); - scrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - int value = (Integer) animation.getAnimatedValue(); - mScrollView.scrollTo(0, value); - } - }); - scrollAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - super.onAnimationEnd(animation); - mCardClickListener.onClick(mLockScreenCard); - } - }); - scrollAnimator.start(); - } - }, SHOW_LOCK_SCREEN_CARD_DELAY); - } - - protected void startLiveLockScreenSettings() { - Intent intent = new Intent(cyanogenmod.content.Intent.ACTION_OPEN_LIVE_LOCKSCREEN_SETTINGS); - try { - startActivity(intent); - } catch (ActivityNotFoundException e) { - // TODO: inform user that this action failed (Toast?) - } - } - - class AnimationLoader extends AsyncTask { - Context mContext; - String mPkgName; - BootAniImageView mBootAnim; - - public AnimationLoader(Context context, String pkgName, BootAniImageView bootAnim) { - mContext = context; - mPkgName = pkgName; - mBootAnim = bootAnim; - } - - @Override - protected void onPreExecute() { - super.onPreExecute(); - } - - @Override - protected Boolean doInBackground(Void... params) { - if (mContext == null) { - return Boolean.FALSE; - } - ZipFile zip = null; - if (ThemeConfig.SYSTEM_DEFAULT.equals(mPkgName)) { - try { - zip = new ZipFile(new File(BootAnimationHelper.SYSTEM_BOOT_ANI_PATH)); - } catch (Exception e) { - Log.w(TAG, "Unable to load boot animation", e); - return Boolean.FALSE; - } - } else { - // check if the bootanimation is cached - File f = new File(mContext.getCacheDir(), - mPkgName + BootAnimationHelper.CACHED_SUFFIX); - if (!f.exists()) { - // go easy on cache storage and clear out any previous boot animations - BootAnimationHelper.clearBootAnimationCache(mContext); - try { - Context themeContext = mContext.createPackageContext(mPkgName, 0); - AssetManager am = themeContext.getAssets(); - InputStream is = am.open("bootanimation/bootanimation.zip"); - FileUtils.copyToFile(is, f); - is.close(); - } catch (Exception e) { - Log.w(TAG, "Unable to load boot animation", e); - return Boolean.FALSE; - } - } - try { - zip = new ZipFile(f); - } catch (IOException e) { - Log.w(TAG, "Unable to load boot animation", e); - return Boolean.FALSE; - } - } - if (zip != null) { - mBootAnim.setBootAnimation(zip); - } else { - return Boolean.FALSE; - } - return Boolean.TRUE; - } - - @Override - protected void onPostExecute(Boolean isSuccess) { - super.onPostExecute(isSuccess); - if (isSuccess) { - mBootAnim.start(); - } - } - } - - class AudibleLoadingThread extends Thread { - private Context mContext; - private int mType; - private String mPkgName; - private MediaPlayer mPlayer; - - public AudibleLoadingThread(Context context, int type, String pkgName, MediaPlayer mp) { - super(); - mContext = context; - mType = type; - mPkgName = pkgName; - mPlayer = mp; - } - - @Override - public void run() { - try { - AudioUtils.loadThemeAudible(mContext, mType, mPkgName, mPlayer); - } catch (PackageManager.NameNotFoundException e) { - Log.w(TAG, "Unable to load sound for " + mPkgName, e); - } - } - } -} diff --git a/src/org/cyanogenmod/theme/chooser/WallpaperCardView.java b/src/org/cyanogenmod/theme/chooser/WallpaperCardView.java deleted file mode 100644 index a3ed8ea..0000000 --- a/src/org/cyanogenmod/theme/chooser/WallpaperCardView.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (C) 2016 Cyanogen, Inc. - * Copyright (C) 2016 The CyanogenMod Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.cyanogenmod.theme.chooser; - -import android.animation.Animator; -import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; -import android.animation.ValueAnimator; -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.drawable.Drawable; -import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewOverlay; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.TextView; - -public class WallpaperCardView extends ComponentCardView { - protected ImageView mImage; - protected TextView mLabel; - - public WallpaperCardView(Context context) { - this(context, null); - } - - public WallpaperCardView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public WallpaperCardView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.WallpaperCardView); - String labelText = a.getString(R.styleable.WallpaperCardView_labelText); - a.recycle(); - - setOrientation(VERTICAL); - - setBackgroundResource(R.drawable.card_bg); - - LayoutInflater inflater = LayoutInflater.from(mContext); - FrameLayout frameLayout = - (FrameLayout) inflater.inflate(R.layout.wallpaper_card, this, false); - addView(frameLayout); - mLabel = (TextView) frameLayout.findViewById(R.id.label); - mImage = (ImageView) frameLayout.findViewById(R.id.image); - - mLabel.setText(labelText); - } - - public void setWallpaper(Drawable drawable) { - mImage.setImageDrawable(drawable); - View none = findViewById(R.id.none); - if (drawable == null) { - setBackgroundResource(R.drawable.card_wallpapertoggled_bg); - if (none != null) { - none.setVisibility(View.VISIBLE); - } - if (mLabel != null) { - mLabel.setBackgroundResource(0); - } - } else { - setBackgroundResource(0); - - if (none != null) { - none.setVisibility(View.GONE); - } - if (mLabel != null) { - mLabel.setBackgroundResource(R.drawable.wallpaper_label_bg); - } - } - } - - public void clearWallpaper() { - mImage.setImageDrawable(null); - setBackgroundResource(R.drawable.card_bg); - } - - public Drawable getWallpaperDrawable() { - return mImage.getDrawable(); - } - - @Override - public void expand(boolean showLabel) { - setEnabled(true); - } - - @Override - public void collapse() { - setEnabled(false); - } - - /** - * Animates a change in the content of the card - * @param v View in card to animate - * @param overlay Drawable to animate as a ViewOverlay - * @param duration Duration of animation - */ - @Override - public void animateContentChange(View v, final Drawable overlay, long duration) { - // Since the wallpaper IS the content, we will ignore the view passed in and animate - // the entire card - final ViewOverlay viewOverlay = this.getOverlay(); - viewOverlay.add(overlay); - final int x = 0; - final int y = 0; - final int width = v.getWidth(); - final int height = v.getHeight(); - overlay.setBounds(x, y, x + width, y + height); - - final ValueAnimator overlayAnimator = ValueAnimator.ofFloat(1f, 0f); - overlayAnimator.setDuration(duration); - overlayAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - float value = (Float) animation.getAnimatedValue(); - overlay.setAlpha((int) (255 * value)); - } - - }); - overlayAnimator.addListener(new Animator.AnimatorListener() { - @Override - public void onAnimationStart(Animator animation) {} - - @Override - public void onAnimationEnd(Animator animation) { - // Clear out the ViewOverlay now that we are done animating - viewOverlay.clear(); - } - - @Override - public void onAnimationCancel(Animator animation) {} - - @Override - public void onAnimationRepeat(Animator animation) {} - }); - - AnimatorSet set = new AnimatorSet(); - set.play(ObjectAnimator.ofFloat(overlay, "alpha", 0f, 1f)) - .with(overlayAnimator); - set.start(); - } -} diff --git a/src/org/cyanogenmod/theme/chooser2/AppReceiver.java b/src/org/cyanogenmod/theme/chooser2/AppReceiver.java new file mode 100644 index 0000000..9ac3f91 --- /dev/null +++ b/src/org/cyanogenmod/theme/chooser2/AppReceiver.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2016 Cyanogen, Inc. + * Copyright (C) 2016 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cyanogenmod.theme.chooser2; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager.NameNotFoundException; +import android.net.Uri; +import android.text.TextUtils; + +import org.cyanogenmod.theme.util.NotificationHelper; +import org.cyanogenmod.theme.util.PreferenceUtils; +import org.cyanogenmod.theme.util.Utils; + +public class AppReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + Uri uri = intent.getData(); + String pkgName = uri != null ? uri.getSchemeSpecificPart() : null; + String action = intent.getAction(); + + if (cyanogenmod.content.Intent.ACTION_THEME_INSTALLED.equals(action)) { + if (!pkgName.equals(Utils.getDefaultThemePackageName(context))) { + NotificationHelper.postThemeInstalledNotification(context, pkgName); + } + } else if (cyanogenmod.content.Intent.ACTION_THEME_REMOVED.equals(action)) { + // remove updated status for this theme (if one exists) + PreferenceUtils.removeUpdatedTheme(context, pkgName); + + // If the theme being removed was the currently applied theme we need + // to update the applied base theme in preferences to the default theme. + String appliedBaseTheme = PreferenceUtils.getAppliedBaseTheme(context); + if (!TextUtils.isEmpty(appliedBaseTheme) && appliedBaseTheme.equals(pkgName)) { + PreferenceUtils.setAppliedBaseTheme(context, + Utils.getDefaultThemePackageName(context)); + } + NotificationHelper.cancelNotifications(context); + } else if (cyanogenmod.content.Intent.ACTION_THEME_UPDATED.equals(action)) { + try { + if (isTheme(context, pkgName)) { + PreferenceUtils.addUpdatedTheme(context, pkgName); + } + } catch (NameNotFoundException e) { + } + } + } + + private boolean isTheme(Context context, String pkgName) throws NameNotFoundException { + PackageInfo pi = context.getPackageManager().getPackageInfo(pkgName, 0); + + return pi != null && pi.themeInfo != null; + } +} diff --git a/src/org/cyanogenmod/theme/chooser2/BootReceiver.java b/src/org/cyanogenmod/theme/chooser2/BootReceiver.java new file mode 100644 index 0000000..02dc107 --- /dev/null +++ b/src/org/cyanogenmod/theme/chooser2/BootReceiver.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 Cyanogen, Inc. + * Copyright (C) 2016 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cyanogenmod.theme.chooser2; + +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; + +public class BootReceiver extends BroadcastReceiver { + private static final String CHOOSER_PKG_NAME = "org.cyanogenmod.theme.chooser"; + private static final String CHOOSER_ACTIVITY = "org.cyanogenmod.theme.chooser.ChooserLauncher"; + + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + PackageManager pm = context.getPackageManager(); + if (Intent.ACTION_BOOT_COMPLETED.equals(action)) { + try { + PackageInfo info = pm.getPackageInfo(ChooserActivity.THEME_STORE_PACKAGE, 0); + if (info != null) { + ComponentName cn = new ComponentName(CHOOSER_PKG_NAME, CHOOSER_ACTIVITY); + pm.setComponentEnabledSetting(cn, + PackageManager.COMPONENT_ENABLED_STATE_DISABLED, + PackageManager.DONT_KILL_APP); + } + } catch (PackageManager.NameNotFoundException e) { + // no store so nothing to do. + } + + // now disable this receiver so we don't get called on future boots + ComponentName cn = new ComponentName(CHOOSER_PKG_NAME, + BootReceiver.class.getCanonicalName()); + pm.setComponentEnabledSetting(cn, + PackageManager.COMPONENT_ENABLED_STATE_DISABLED, + PackageManager.DONT_KILL_APP); + } + } +} diff --git a/src/org/cyanogenmod/theme/chooser2/ChooserActivity.java b/src/org/cyanogenmod/theme/chooser2/ChooserActivity.java new file mode 100644 index 0000000..3e63dfa --- /dev/null +++ b/src/org/cyanogenmod/theme/chooser2/ChooserActivity.java @@ -0,0 +1,1185 @@ +/* + * Copyright (C) 2016 Cyanogen, Inc. + * Copyright (C) 2016 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cyanogenmod.theme.chooser2; + +import android.animation.Animator; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.content.ActivityNotFoundException; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.IPackageDeleteObserver; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.content.res.ThemeConfig; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; +import android.graphics.Paint; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.TransitionDrawable; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Handler; +import android.os.RemoteException; +import android.provider.Settings; +import android.renderscript.Allocation; +import android.renderscript.Element; +import android.renderscript.RenderScript; +import android.renderscript.ScriptIntrinsicBlur; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentActivity; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.Loader; +import android.support.v4.view.ThemeViewPager; +import android.support.v4.view.ViewPager; +import android.text.TextUtils; +import android.util.DisplayMetrics; +import android.util.Log; +import android.util.MutableLong; +import android.util.TypedValue; +import android.view.View; +import android.view.ViewPropertyAnimator; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; +import android.view.animation.DecelerateInterpolator; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.Toast; + +import org.cyanogenmod.theme.perapptheming.PerAppThemingWindow; +import org.cyanogenmod.theme.util.CursorLoaderHelper; +import org.cyanogenmod.theme.util.NotificationHelper; +import org.cyanogenmod.theme.util.PreferenceUtils; +import org.cyanogenmod.theme.util.TypefaceHelperCache; +import org.cyanogenmod.theme.util.Utils; + +import cyanogenmod.platform.Manifest; +import cyanogenmod.providers.ThemesContract; +import cyanogenmod.providers.ThemesContract.ThemesColumns; +import cyanogenmod.themes.ThemeManager; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_ALARMS; +import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_BOOT_ANIM; +import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_NOTIFICATIONS; +import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_RINGTONES; +import static org.cyanogenmod.theme.chooser2.ComponentSelector.DEFAULT_COMPONENT_ID; +import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_INSTALLED_THEMES; +import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_APPLIED; + +public class ChooserActivity extends FragmentActivity + implements LoaderManager.LoaderCallbacks { + public static final String THEME_STORE_PACKAGE = "com.cyngn.theme.tore"; + private static final String TAG = ChooserActivity.class.getSimpleName(); + + public static final String DEFAULT = ThemeConfig.SYSTEM_DEFAULT; + public static final String EXTRA_PKGNAME = "pkgName"; + public static final String EXTRA_COMPONENTS = "components"; + + private static final int OFFSCREEN_PAGE_LIMIT = 3; + + private static final String THEME_STORE_ACTIVITY = THEME_STORE_PACKAGE + ".ui.StoreActivity"; + private static final String ACTION_APPLY_THEME = "android.intent.action.APPLY_THEME"; + + private static final String TYPE_IMAGE = "image/*"; + + private static final String ACTION_PICK_LOCK_SCREEN_WALLPAPER = + "com.cyngn.intent.action.PICK_LOCK_SCREEN_WALLPAPER"; + + /** + * Request code for picking an external wallpaper + */ + public static final int REQUEST_PICK_WALLPAPER_IMAGE = 2; + /** + * Request code for picking an external lockscreen wallpaper + */ + public static final int REQUEST_PICK_LOCKSCREEN_IMAGE = 3; + + /** + * Request code for enabling system alert window permission + */ + private static final int REQUEST_SYSTEM_WINDOW_PERMISSION = 4; + + private static final long ANIMATE_CONTENT_IN_SCALE_DURATION = 500; + private static final long ANIMATE_CONTENT_IN_ALPHA_DURATION = 750; + private static final long ANIMATE_CONTENT_IN_BLUR_DURATION = 250; + private static final long ANIMATE_CONTENT_DELAY = 250; + private static final long ANIMATE_SHOP_THEMES_HIDE_DURATION = 250; + private static final long ANIMATE_SHOP_THEMES_SHOW_DURATION = 500; + private static final long FINISH_ANIMATION_DELAY = ThemeFragment.ANIMATE_DURATION + + ThemeFragment.ANIMATE_START_DELAY + 250; + + private static final long ANIMATE_CARDS_IN_DURATION = 250; + private static final long ANIMATE_SAVE_APPLY_LAYOUT_DURATION = 300; + private static final float ANIMATE_SAVE_APPLY_DECELERATE_INTERPOLATOR_FACTOR = 3; + private static final long ONCLICK_SAVE_APPLY_FINISH_ANIMATION_DELAY = 400; + + private PagerContainer mContainer; + private ThemeViewPager mPager; + + private ThemesAdapter mAdapter; + private boolean mExpanded = false; + private ComponentSelector mSelector; + private Button mSaveApplyButton; + private int mContainerYOffset = 0; + private TypefaceHelperCache mTypefaceHelperCache; + private boolean mIsAnimating; + private Handler mHandler; + private View mBottomActionsLayout; + + private String mSelectedTheme; + private String mAppliedBaseTheme; + private boolean mThemeChanging = false; + private boolean mAnimateContentIn = false; + private long mAnimateContentInDelay; + private String mThemeToApply; + private ArrayList mComponentsToApply; + + ImageView mCustomBackground; + + // Current system theme configuration as component -> pkgName + private Map mCurrentTheme = new HashMap(); + private MutableLong mCurrentWallpaperCmpntId = new MutableLong(DEFAULT_COMPONENT_ID); + + private boolean mIsPickingImage = false; + private boolean mRestartLoaderOnCollapse = false; + private boolean mActivityResuming = false; + private boolean mShowLockScreenWallpaper = false; + + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); + NotificationHijackingService.ensureEnabled(this); + + if (savedInstanceState == null) { + handleIntent(getIntent()); + } + + mContainer = (PagerContainer) findViewById(R.id.pager_container); + mPager = (ThemeViewPager) findViewById(R.id.viewpager); + + mPager.setOnClickListener(mPagerClickListener); + mAdapter = new ThemesAdapter(); + mPager.setAdapter(mAdapter); + + DisplayMetrics dm = getResources().getDisplayMetrics(); + int margin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48, dm); + mPager.setPageMargin(-margin / 2); + mPager.setOffscreenPageLimit(OFFSCREEN_PAGE_LIMIT); + mPager.setClipChildren(false); + mPager.setClipToPadding(false); + + mPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { + public void onPageSelected(int position) { + } + + public void onPageScrolled(int position, + float positionOffset, + int positionOffsetPixels) { + } + + public void onPageScrollStateChanged(int state) { + } + }); + + mSelector = (ComponentSelector) findViewById(R.id.component_selector); + mSelector.setOnOpenCloseListener(mOpenCloseListener); + + mBottomActionsLayout = findViewById(R.id.bottom_actions_layout); + + mSaveApplyButton = (Button) findViewById(R.id.save_apply_button); + mSaveApplyButton.setOnClickListener(mOnSaveApplyClicked); + + mBottomActionsLayout.findViewById(R.id.shop_themes) + .setOnClickListener(mOnShopThemesClicked); + + mTypefaceHelperCache = TypefaceHelperCache.getInstance(); + mHandler = new Handler(); + mCustomBackground = (ImageView) findViewById(R.id.custom_bg); + mAnimateContentIn = true; + mAnimateContentInDelay = 0; + + mBottomActionsLayout.findViewById(R.id.per_app_theming).setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + if (Settings.canDrawOverlays(ChooserActivity.this)) { + launchAppThemer(); + } else { + requestSystemWindowPermission(); + } + } + }); + + if (PreferenceUtils.getShowPerAppThemeNewTag(this)) { + View tag = mBottomActionsLayout.findViewById(R.id.new_tag); + if (tag != null) { + tag.setVisibility(View.VISIBLE); + } + } + } + + public void showSaveApplyButton() { + if (mSaveApplyButton != null && mSaveApplyButton.getVisibility() != View.VISIBLE) { + mHandler.post(new Runnable() { + @Override + public void run() { + mSaveApplyButton.setTranslationY(mSaveApplyButton.getMeasuredHeight()); + mSaveApplyButton.setVisibility(View.VISIBLE); + mSaveApplyButton.animate() + .setDuration(ANIMATE_SAVE_APPLY_LAYOUT_DURATION) + .setInterpolator( + new DecelerateInterpolator( + ANIMATE_SAVE_APPLY_DECELERATE_INTERPOLATOR_FACTOR)) + .translationY(-mSelector.getMeasuredHeight()); + } + }); + } + } + + public void hideSaveApplyButton() { + if (mSaveApplyButton.getVisibility() != View.GONE) { + Animation anim = AnimationUtils.loadAnimation(this, + R.anim.component_selection_animate_out); + mSaveApplyButton.startAnimation(anim); + anim.setAnimationListener(new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + } + + @Override + public void onAnimationEnd(Animation animation) { + mSaveApplyButton.setVisibility(View.GONE); + } + + @Override + public void onAnimationRepeat(Animation animation) { + } + }); + } + } + + private void hideBottomActionsLayout() { + final ViewPropertyAnimator anim = mBottomActionsLayout.animate(); + anim.alpha(0f).setDuration(ANIMATE_SHOP_THEMES_HIDE_DURATION); + anim.setListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animation) { + } + + @Override + public void onAnimationEnd(Animator animation) { + mBottomActionsLayout.setVisibility(View.GONE); + } + + @Override + public void onAnimationCancel(Animator animation) { + } + + @Override + public void onAnimationRepeat(Animator animation) { + } + }); + } + + private void showBottomActionsLayout() { + mBottomActionsLayout.setVisibility(View.VISIBLE); + final ViewPropertyAnimator anim = mBottomActionsLayout.animate(); + anim.setListener(null); + anim.alpha(1f).setStartDelay(ThemeFragment.ANIMATE_DURATION) + .setDuration(ANIMATE_SHOP_THEMES_SHOW_DURATION); + } + + private void lauchGetThemes() { + String playStoreUrl = getString(R.string.play_store_url); + String wikiUrl = getString(R.string.wiki_url); + + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse(playStoreUrl)); + + // Try to launch play store + if (intent.resolveActivity(getPackageManager()) != null) { + startActivity(intent); + } else { + // If no play store, try to open wiki url + intent.setData(Uri.parse(wikiUrl)); + if (intent.resolveActivity(getPackageManager()) != null) { + startActivity(intent); + } else { + Toast.makeText(this, R.string.get_more_app_not_available, + Toast.LENGTH_LONG).show(); + } + } + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); + if (Utils.isRecentTaskHome(this)) { + mContainer.setAlpha(0f); + mBottomActionsLayout.setAlpha(0f); + mAnimateContentIn = true; + mAnimateContentInDelay = ANIMATE_CONTENT_DELAY; + } + handleIntent(intent); + } + + private void handleIntent(Intent intent) { + String action = intent.getAction(); + if ((Intent.ACTION_MAIN.equals(action) || ACTION_APPLY_THEME.equals(action)) + && intent.hasExtra(EXTRA_PKGNAME)) { + if (intent.hasExtra(EXTRA_COMPONENTS)) { + mComponentsToApply = intent.getStringArrayListExtra(EXTRA_COMPONENTS); + } else { + mComponentsToApply = null; + } + mSelectedTheme = mComponentsToApply != null ? + PreferenceUtils.getAppliedBaseTheme(this) : + getSelectedTheme(intent.getStringExtra(EXTRA_PKGNAME)); + if (mPager != null) { + startLoader(LOADER_ID_INSTALLED_THEMES); + if (mExpanded) { + int collapseDelay = ThemeFragment.ANIMATE_START_DELAY; + if (mSelector.isEnabled()) { + // onBackPressed() has all the necessary logic for collapsing the + // component selector, so we call it here. + onBackPressed(); + collapseDelay += ThemeFragment.ANIMATE_DURATION; + } + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + collapse(false); + } + }, collapseDelay); + } + } + + if (ACTION_APPLY_THEME.equals(action) && + getCallingPackage() != null && + PackageManager.PERMISSION_GRANTED == + getPackageManager() + .checkPermission(Manifest.permission.WRITE_THEMES, + getCallingPackage())) { + mThemeToApply = intent.getStringExtra(EXTRA_PKGNAME); + } + } else if (ACTION_PICK_LOCK_SCREEN_WALLPAPER.equals(action)) { + mShowLockScreenWallpaper = true; + } + } + + private String getSelectedTheme(String requestedTheme) { + String[] projection = { ThemesColumns.PRESENT_AS_THEME }; + String selection = ThemesColumns.PKG_NAME + "=?"; + String[] selectionArgs = { requestedTheme }; + + String selectedTheme = PreferenceUtils.getAppliedBaseTheme(this); + + Cursor cursor = getContentResolver().query(ThemesColumns.CONTENT_URI, + projection, selection, selectionArgs, null); + if (cursor != null) { + if (cursor.getCount() > 0 && cursor.moveToFirst()) { + if (cursor.getInt(0) == 1) { + selectedTheme = requestedTheme; + } + } + cursor.close(); + } + return selectedTheme; + } + + private void setAnimatingStateAndScheduleFinish() { + mIsAnimating = true; + mContainer.setIsAnimating(true); + mHandler.postDelayed(new Runnable() { + public void run() { + mIsAnimating = false; + mContainer.setIsAnimating(false); + if (mRestartLoaderOnCollapse) { + mRestartLoaderOnCollapse = false; + startLoader(LOADER_ID_INSTALLED_THEMES); + } + } + }, FINISH_ANIMATION_DELAY); + if (mExpanded) { + hideBottomActionsLayout(); + } else { + showBottomActionsLayout(); + } + } + + private void setCustomBackground(final ImageView iv, final boolean animate) { + final Context context = ChooserActivity.this; + iv.post(new Runnable() { + @Override + public void run() { + Bitmap tmpBmp; + try { + tmpBmp = Utils.getRegularWallpaperBitmap(context); + } catch (Throwable e) { + Log.w(TAG, "Failed to retrieve wallpaper", e); + tmpBmp = null; + } + // Show the grid background if no wallpaper is set. + // Note: no wallpaper is actually a 1x1 pixel black bitmap + if (tmpBmp == null || tmpBmp.getWidth() <= 1 || tmpBmp.getHeight() <= 1) { + iv.setImageResource(R.drawable.bg_grid); + // We need to change the ScaleType to FIT_XY otherwise the background is cut + // off a bit at the bottom. + iv.setScaleType(ImageView.ScaleType.FIT_XY); + return; + } + + // Since we are applying a blur, we can afford to scale the bitmap down and use a + // smaller blur radius. + Bitmap inBmp = Bitmap.createScaledBitmap(tmpBmp, tmpBmp.getWidth() / 4, + tmpBmp.getHeight() / 4, false); + Bitmap outBmp = Bitmap.createBitmap(inBmp.getWidth(), inBmp.getHeight(), + Bitmap.Config.ARGB_8888); + + // Blur the original bitmap + RenderScript rs = RenderScript.create(context); + ScriptIntrinsicBlur theIntrinsic = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); + Allocation tmpIn = Allocation.createFromBitmap(rs, inBmp); + Allocation tmpOut = Allocation.createFromBitmap(rs, outBmp); + theIntrinsic.setRadius(5.0f); + theIntrinsic.setInput(tmpIn); + theIntrinsic.forEach(tmpOut); + tmpOut.copyTo(outBmp); + + // Create a bitmap drawable and use a color matrix to de-saturate the image + BitmapDrawable[] layers = new BitmapDrawable[2]; + layers[0] = new BitmapDrawable(getResources(), tmpBmp); + layers[1] = new BitmapDrawable(getResources(), outBmp); + ColorMatrix cm = new ColorMatrix(); + cm.setSaturation(0); + Paint p = layers[0].getPaint(); + p.setColorFilter(new ColorMatrixColorFilter(cm)); + p = layers[1].getPaint(); + p.setColorFilter(new ColorMatrixColorFilter(cm)); + TransitionDrawable d = new TransitionDrawable(layers); + + // All done + iv.setScaleType(ImageView.ScaleType.CENTER_CROP); + if (!animate) { + iv.setImageDrawable(layers[1]); + } else { + iv.setImageDrawable(d); + } + } + }); + } + + /** + * Disable the ViewPager while a theme change is occuring + */ + public void themeChangeStart() { + lockPager(); + mThemeChanging = true; + ThemeFragment f = getCurrentFragment(); + if (f != null) { + mAppliedBaseTheme = f.getThemePackageName(); + PreferenceUtils.setAppliedBaseTheme(this, mAppliedBaseTheme); + } + } + + /** + * Re-enable the ViewPager and update the "My theme" fragment if available + */ + public void themeChangeEnd(boolean isSuccess) { + mThemeChanging = false; + ThemeFragment f = getCurrentFragment(); + if (f != null) { + // We currently need to recreate the adapter in order to load + // the changes otherwise the adapter returns the original fragments + // TODO: We'll need a better way to handle this to provide a good UX + if (!(f instanceof MyThemeFragment)) { + mAdapter = new ThemesAdapter(); + mPager.setAdapter(mAdapter); + } + if (!isSuccess) { + mAppliedBaseTheme = null; + } + startLoader(LOADER_ID_APPLIED); + } + unlockPager(); + } + + public void lockPager() { + mPager.setScrollingEnabled(false); + } + + public void unlockPager() { + mPager.setScrollingEnabled(true); + } + + public ComponentSelector getComponentSelector() { + return mSelector; + } + + public void showComponentSelector(String component, String selectedPkgName, + long selectedCmpntId, View v) { + if (component != null) { + final Resources res = getResources(); + int itemsPerPage = res.getInteger(R.integer.default_items_per_page); + int height = res.getDimensionPixelSize(R.dimen.component_selection_cell_height); + if (MODIFIES_BOOT_ANIM.equals(component)) { + itemsPerPage = res.getInteger(R.integer.bootani_items_per_page); + height = res.getDimensionPixelSize( + R.dimen.component_selection_cell_height_boot_anim); + } else if (MODIFIES_ALARMS.equals(component) || + MODIFIES_NOTIFICATIONS.equals(component) || + MODIFIES_RINGTONES.equals(component)) { + itemsPerPage = 2; + height = res.getDimensionPixelSize( + R.dimen.component_selection_cell_height_sounds); + } + if (mSaveApplyButton.getVisibility() == View.VISIBLE) { + if (mSaveApplyButton.getTranslationY() + height != 0) { + mSaveApplyButton.animate() + .translationY(-height) + .setInterpolator( + new AccelerateDecelerateInterpolator()) + .setDuration(ANIMATE_SAVE_APPLY_LAYOUT_DURATION); + } + } + mSelector.show(component, selectedPkgName, selectedCmpntId, itemsPerPage, height); + + // determine if we need to shift the cards up + int[] coordinates = new int[2]; + v.getLocationOnScreen(coordinates); + final int top = coordinates[1]; + final int bottom = coordinates[1] + v.getHeight(); + final int statusBarHeight = res.getDimensionPixelSize(R.dimen.status_bar_height); + int selectorTop = getWindowManager().getDefaultDisplay().getHeight() - height; + if (bottom > selectorTop) { + slideContentIntoView(bottom - selectorTop, height); + } else if (top < statusBarHeight) { + slideContentIntoView(top - statusBarHeight, height); + } + } + } + + public void expand() { + if (!mExpanded && !mIsAnimating) { + mExpanded = true; + mContainer.setClickable(false); + mContainer.expand(); + ThemeFragment f = getCurrentFragment(); + if (f != null) { + f.expand(); + } + setAnimatingStateAndScheduleFinish(); + } + } + + public void collapse(final boolean applyTheme) { + mExpanded = false; + final ThemeFragment f = getCurrentFragment(); + if (f != null) { + f.fadeOutCards(new Runnable() { + public void run() { + mContainer.collapse(); + f.collapse(applyTheme); + } + }); + } + setAnimatingStateAndScheduleFinish(); + } + + public void pickExternalWallpaper() { + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.setType(TYPE_IMAGE); + startActivityForResult(intent, REQUEST_PICK_WALLPAPER_IMAGE); + mIsPickingImage = true; + } + + public void pickExternalLockscreen() { + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.setType(TYPE_IMAGE); + startActivityForResult(intent, REQUEST_PICK_LOCKSCREEN_IMAGE); + mIsPickingImage = true; + } + + public void uninstallTheme(String pkgName) { + PackageManager pm = getPackageManager(); + pm.deletePackage(pkgName, new PackageDeleteObserver(), PackageManager.DELETE_ALL_USERS); + } + + private void slideContentIntoView(int yDelta, int selectorHeight) { + ThemeFragment f = getCurrentFragment(); + if (f != null) { + final int offset = getResources().getDimensionPixelSize(R.dimen.content_offset_padding); + if (yDelta > 0) { + yDelta += offset; + } else { + yDelta -= offset; + } + f.slideContentIntoView(yDelta, selectorHeight); + mContainerYOffset = yDelta; + } + } + + private void slideContentBack(final int yDelta) { + ThemeFragment f = getCurrentFragment(); + if (f != null) { + f.slideContentBack(yDelta); + } + } + + @Override + protected void onResume() { + super.onResume(); + setCustomBackground(mCustomBackground, mAnimateContentIn); + // clear out any notifications that are being displayed. + NotificationHelper.cancelNotifications(this); + + ThemeManager tm = ThemeManager.getInstance(this); + mThemeChanging = tm.isThemeApplying(); + + if (!mIsPickingImage) { + startLoader(LOADER_ID_APPLIED); + } else { + mIsPickingImage = false; + } + + IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED); + registerReceiver(mWallpaperChangeReceiver, filter); + } + + @Override + public void onBackPressed() { + final ThemeFragment f = getCurrentFragment(); + if (mSelector.isEnabled()) { + mSelector.hide(); + if (mContainerYOffset != 0) { + slideContentBack(-mContainerYOffset); + mContainerYOffset = 0; + } + if (f != null) f.fadeInCards(); + if (mShowLockScreenWallpaper) { + mShowLockScreenWallpaper = false; + mSelector.resetComponentType(); + } + } else if (mExpanded) { + if (mIsAnimating) { + return; + } + + if (mSaveApplyButton.getVisibility() == View.VISIBLE) { + hideSaveApplyButton(); + if (f != null) f.clearChanges(); + } + collapse(false); + } else { + if (f != null && f.isShowingConfirmCancelOverlay()) { + f.hideConfirmCancelOverlay(); + } else if (f != null && f.isShowingCustomizeResetLayout()) { + f.hideCustomizeResetLayout(); + } else { + super.onBackPressed(); + } + } + } + + @Override + public void onPause() { + super.onPause(); + unregisterReceiver(mWallpaperChangeReceiver); + ThemeFragment f = getCurrentFragment(); + if (f != null) { + mSelectedTheme = f.getThemePackageName(); + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + @Override + protected void onStart() { + super.onStart(); + if (mTypefaceHelperCache.getTypefaceCount() <= 0) { + new TypefacePreloadTask().execute(); + } + mAnimateContentInDelay = ANIMATE_CONTENT_DELAY; + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (resultCode == RESULT_OK && requestCode == REQUEST_PICK_WALLPAPER_IMAGE) { + if (data != null && data.getData() != null) { + Uri uri = data.getData(); + ThemeFragment f = getCurrentFragment(); + if (f != null) { + f.setWallpaperImageUri(uri); + showSaveApplyButton(); + } + } + } else if (resultCode == RESULT_OK && requestCode == REQUEST_PICK_LOCKSCREEN_IMAGE) { + if (data != null && data.getData() != null) { + Uri uri = data.getData(); + ThemeFragment f = getCurrentFragment(); + if (f != null) { + f.setLockscreenImageUri(uri); + showSaveApplyButton(); + } + } + } else if (requestCode == REQUEST_SYSTEM_WINDOW_PERMISSION) { + if (Settings.canDrawOverlays(this)) { + launchAppThemer(); + } + } + } + + private void animateContentIn() { + Drawable d = mCustomBackground.getDrawable(); + if (d instanceof TransitionDrawable) { + ((TransitionDrawable) d).startTransition((int) ANIMATE_CONTENT_IN_BLUR_DURATION); + } + + if (!mShowLockScreenWallpaper) { + AnimatorSet set = new AnimatorSet(); + set.play(ObjectAnimator.ofFloat(mContainer, "alpha", 0f, 1f) + .setDuration(ANIMATE_CONTENT_IN_ALPHA_DURATION)) + .with(ObjectAnimator.ofFloat(mContainer, "scaleX", 2f, 1f) + .setDuration(ANIMATE_CONTENT_IN_SCALE_DURATION)) + .with(ObjectAnimator.ofFloat(mContainer, "scaleY", 2f, 1f) + .setDuration(ANIMATE_CONTENT_IN_SCALE_DURATION)); + set.setStartDelay(mAnimateContentInDelay); + set.start(); + mBottomActionsLayout.setAlpha(0f); + mBottomActionsLayout.animate().alpha(1f).setStartDelay(mAnimateContentInDelay) + .setDuration(ANIMATE_CONTENT_IN_ALPHA_DURATION); + } else { + mContainer.setAlpha(0f); + mContainer.setVisibility(View.GONE); + } + mAnimateContentIn = false; + } + + private View.OnClickListener mPagerClickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + ThemeFragment f = getCurrentFragment(); + if (f != null && !mThemeChanging) { + f.performClick(mPager.isClickedOnContent()); + } + } + }; + + private BroadcastReceiver mWallpaperChangeReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (mCustomBackground != null) setCustomBackground(mCustomBackground, false); + } + }; + + private ComponentSelector.OnOpenCloseListener mOpenCloseListener = new ComponentSelector.OnOpenCloseListener() { + @Override + public void onSelectorOpened() { + } + + @Override + public void onSelectorClosed() { + } + + @Override + public void onSelectorClosing() { + ThemeFragment f = getCurrentFragment(); + if (f != null && f.componentsChanged() + && mSaveApplyButton.getVisibility() == View.VISIBLE) { + mSaveApplyButton.animate() + .translationY(0) + .setInterpolator(new DecelerateInterpolator()) + .setDuration(ANIMATE_SAVE_APPLY_LAYOUT_DURATION); + } + } + }; + + private ThemeFragment getCurrentFragment() { + // instantiateItem will return the fragment if it already exists and not instantiate it, + // which should be the case for the current fragment. + ThemeFragment f; + try { + f = (mAdapter == null || mPager == null || mAdapter.getCount() <= 0) ? null : + (ThemeFragment) mAdapter.instantiateItem(mPager, mPager.getCurrentItem()); + } catch (Exception e) { + f = null; + Log.e(TAG, "Unable to get current fragment", e); + } + return f; + } + + private void populateCurrentTheme(Cursor c) { + c.moveToPosition(-1); + //Default to first wallpaper + mCurrentWallpaperCmpntId.value = DEFAULT_COMPONENT_ID; + // clear out the previous map + mCurrentTheme.clear(); + while(c.moveToNext()) { + int mixkeyIdx = c.getColumnIndex(ThemesContract.MixnMatchColumns.COL_KEY); + int pkgIdx = c.getColumnIndex(ThemesContract.MixnMatchColumns.COL_VALUE); + int cmpntIdIdx = c.getColumnIndex(ThemesContract.MixnMatchColumns.COL_COMPONENT_ID); + String mixkey = c.getString(mixkeyIdx); + String component = ThemesContract.MixnMatchColumns.mixNMatchKeyToComponent(mixkey); + String pkg = c.getString(pkgIdx); + mCurrentTheme.put(component, pkg); + if (TextUtils.equals(component, ThemesColumns.MODIFIES_LIVE_LOCK_SCREEN)) { + mCurrentTheme.remove(ThemesColumns.MODIFIES_LOCKSCREEN); + } + if (TextUtils.equals(component, ThemesColumns.MODIFIES_LOCKSCREEN)) { + mCurrentTheme.remove(ThemesColumns.MODIFIES_LIVE_LOCK_SCREEN); + } + if (cmpntIdIdx >= 0 && TextUtils.equals(component, ThemesColumns.MODIFIES_LAUNCHER)) { + mCurrentWallpaperCmpntId.value = c.getLong(cmpntIdIdx); + } + } + } + + private View.OnClickListener mOnShopThemesClicked = new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(); + intent.setClassName(THEME_STORE_PACKAGE, THEME_STORE_ACTIVITY); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + startActivity(intent); + } catch (ActivityNotFoundException e) { + lauchGetThemes(); + } + } + }; + + private View.OnClickListener mOnSaveApplyClicked = new View.OnClickListener() { + @Override + public void onClick(View v) { + if (mIsAnimating) return; + hideSaveApplyButton(); + mContainer.setClickable(false); + final ThemeFragment f = getCurrentFragment(); + if (mSelector.isEnabled()) { + mSelector.hide(); + if (mContainerYOffset != 0) { + slideContentBack(-mContainerYOffset); + mContainerYOffset = 0; + } + if (f != null) f.fadeInCards(); + if (mShowLockScreenWallpaper) { + mShowLockScreenWallpaper = false; + mSelector.resetComponentType(); + } + } + + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + collapse(true); + } + }, ONCLICK_SAVE_APPLY_FINISH_ANIMATION_DELAY); + } + }; + + private void startLoader(int loaderId) { + final LoaderManager manager = getSupportLoaderManager(); + final Loader loader = manager.getLoader(loaderId); + if (loader != null) { + manager.restartLoader(loaderId, null, this); + } else { + manager.initLoader(loaderId, null, this); + } + } + + @Override + public void onLoadFinished(Loader loader, Cursor data) { + if (mThemeChanging) return; + + if (mExpanded && !mActivityResuming) { + mRestartLoaderOnCollapse = true; + return; + } + + switch (loader.getId()) { + case LOADER_ID_INSTALLED_THEMES: + // Swap the new cursor in. (The framework will take care of closing the + // old cursor once we return.) + int selectedThemeIndex = -1; + if (TextUtils.isEmpty(mSelectedTheme)) mSelectedTheme = mAppliedBaseTheme; + while(data.moveToNext()) { + if (mSelectedTheme.equals(data.getString( + data.getColumnIndex(ThemesColumns.PKG_NAME)))) { + // we need to add one here since the first card is "My theme" + selectedThemeIndex = data.getPosition(); + mSelectedTheme = null; + break; + } + } + data.moveToFirst(); + mAdapter.swapCursor(data); + mAdapter.notifyDataSetChanged(); + if (selectedThemeIndex >= 0) { + mPager.setCurrentItem(selectedThemeIndex, false); + + if (mThemeToApply != null) { + ThemeFragment f = getCurrentFragment(); + f.applyThemeWhenPopulated(mThemeToApply, mComponentsToApply); + mThemeToApply = null; + } + } + if (mAnimateContentIn) animateContentIn(); + mActivityResuming = true; + break; + case LOADER_ID_APPLIED: + startLoader(LOADER_ID_INSTALLED_THEMES); + populateCurrentTheme(data); + break; + } + } + + @Override + public void onLoaderReset(Loader loader) { + switch (loader.getId()) { + case LOADER_ID_INSTALLED_THEMES: + mAdapter.swapCursor(null); + mAdapter.notifyDataSetChanged(); + break; + } + } + + @Override + public Loader onCreateLoader(int id, Bundle args) { + switch (id) { + case LOADER_ID_INSTALLED_THEMES: + mAppliedBaseTheme = PreferenceUtils.getAppliedBaseTheme(this); + break; + case LOADER_ID_APPLIED: + //TODO: Mix n match query should only be done once + break; + } + return CursorLoaderHelper.chooserActivityCursorLoader(this, id, mAppliedBaseTheme); + } + + public Map getSelectedComponentsMap() { + return getCurrentFragment().getSelectedComponentsMap(); + } + + public class ThemesAdapter extends NewFragmentStatePagerAdapter { + private ArrayList mInstalledThemes; + private String mAppliedThemeTitle; + private String mAppliedThemeAuthor; + private HashMap mRepositionedFragments; + + public ThemesAdapter() { + super(getSupportFragmentManager()); + mRepositionedFragments = new HashMap(); + } + + @Override + public Fragment getItem(int position) { + ThemeFragment f = null; + MutableLong wallpaperCmpntId; + if (mInstalledThemes != null) { + final String pkgName = mInstalledThemes.get(position); + if (pkgName.equals(mAppliedBaseTheme)) { + f = MyThemeFragment.newInstance(mAppliedBaseTheme, mAppliedThemeTitle, + mAppliedThemeAuthor, mAnimateContentIn, mShowLockScreenWallpaper); + wallpaperCmpntId = mCurrentWallpaperCmpntId; + } else { + f = ThemeFragment.newInstance(pkgName, mAnimateContentIn); + wallpaperCmpntId = new MutableLong(DEFAULT_COMPONENT_ID); + } + f.setCurrentTheme(mCurrentTheme, wallpaperCmpntId); + } + return f; + } + + @Override + public long getItemId(int position) { + if (mInstalledThemes != null) { + final String pkgName = mInstalledThemes.get(position); + return pkgName.hashCode(); + } + return 0; + } + + @Override + public int getItemPosition(Object object) { + final ThemeFragment f = (ThemeFragment) object; + final String pkgName = f != null ? f.getThemePackageName() : null; + if (pkgName != null && mRepositionedFragments.containsKey(pkgName)) { + final int position = mRepositionedFragments.get(pkgName); + mRepositionedFragments.remove(pkgName); + return position; + } + return super.getItemPosition(object); + } + + /** + * The first card should be the user's currently applied theme components so we + * will always return at least 1 or mCursor.getCount() + 1 + * @return + */ + public int getCount() { + return mInstalledThemes == null ? 0 : mInstalledThemes.size(); + } + + public void swapCursor(Cursor c) { + if (c != null && c.getCount() != 0) { + ArrayList previousOrder = mInstalledThemes == null ? null + : new ArrayList(mInstalledThemes); + mInstalledThemes = new ArrayList(c.getCount()); + mRepositionedFragments.clear(); + c.moveToPosition(-1); + while (c.moveToNext()) { + final int pkgIdx = c.getColumnIndex(ThemesColumns.PKG_NAME); + final String pkgName = c.getString(pkgIdx); + if (pkgName.equals(mAppliedBaseTheme)) { + final int titleIdx = c.getColumnIndex(ThemesColumns.TITLE); + final int authorIdx = c.getColumnIndex(ThemesColumns.AUTHOR); + mAppliedThemeTitle = c.getString(titleIdx); + mAppliedThemeAuthor = c.getString(authorIdx); + } + mInstalledThemes.add(pkgName); + + // track any themes that may have changed position + if (previousOrder != null && previousOrder.contains(pkgName)) { + int index = previousOrder.indexOf(pkgName); + if (index != c.getPosition()) { + mRepositionedFragments.put(pkgName, c.getPosition()); + } + } else { + mRepositionedFragments.put(pkgName, c.getPosition()); + } + } + // check if any themes are no longer in the new list + if (previousOrder != null) { + for (String pkgName : previousOrder) { + if (!mInstalledThemes.contains(pkgName)) { + mRepositionedFragments.put(pkgName, POSITION_NONE); + } + } + } + } else { + mInstalledThemes = null; + } + } + + public void removeTheme(String pkgName) { + if (mInstalledThemes == null) return; + + if (mInstalledThemes.contains(pkgName)) { + final int count = mInstalledThemes.size(); + final int index = mInstalledThemes.indexOf(pkgName); + // reposition all the fragments after the one being removed + for (int i = index + 1; i < count; i++) { + mRepositionedFragments.put(mInstalledThemes.get(i), i - 1); + } + // Now remove this theme and add it to mRepositionedFragments with POSITION_NONE + mInstalledThemes.remove(pkgName); + mRepositionedFragments.put(pkgName, POSITION_NONE); + // now we can call notifyDataSetChanged() + notifyDataSetChanged(); + } + } + } + + private class TypefacePreloadTask extends AsyncTask { + + @Override + protected Object doInBackground(Object[] params) { + String[] projection = { ThemesColumns.PKG_NAME }; + String selection = ThemesColumns.MODIFIES_FONTS + "=?"; + String[] selectionArgs = { "1" }; + Cursor c = getContentResolver().query(ThemesColumns.CONTENT_URI, projection, selection, + selectionArgs, null); + if (c != null) { + while (c.moveToNext()) { + mTypefaceHelperCache.getHelperForTheme(ChooserActivity.this, c.getString(0)); + } + c.close(); + } + return null; + } + } + + /** + * Internal delete callback from the system + */ + class PackageDeleteObserver extends IPackageDeleteObserver.Stub { + public void packageDeleted(final String packageName, int returnCode) throws RemoteException { + if (returnCode == PackageManager.DELETE_SUCCEEDED) { + Log.d(TAG, "Delete succeeded"); + mHandler.post(new Runnable() { + @Override + public void run() { + mAdapter.removeTheme(packageName); + } + }); + } else { + Log.e(TAG, "Delete failed with returnCode " + returnCode); + } + } + } + + public void expandContentAndAnimateLockScreenCardIn() { + mHandler.post(new Runnable() { + @Override + public void run() { + expand(); + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + AnimatorSet set = new AnimatorSet(); + set.play(ObjectAnimator.ofFloat(mContainer, "alpha", 0f, 1f) + .setDuration(ANIMATE_CARDS_IN_DURATION)); + set.setStartDelay(mAnimateContentInDelay); + set.start(); + mContainer.setVisibility(View.VISIBLE); + getCurrentFragment().showLockScreenCard(); + } + }, ANIMATE_CARDS_IN_DURATION); + } + }); + } + + private void launchAppThemer() { + PreferenceUtils.setShowPerAppThemeNewTag(ChooserActivity.this, false); + Intent intent = new Intent(ChooserActivity.this, PerAppThemingWindow.class); + startService(intent); + finish(); + } + + private void requestSystemWindowPermission() { + Intent intent = new Intent (Settings.ACTION_MANAGE_OVERLAY_PERMISSION, + Uri.parse("package:" + getPackageName())); + startActivityForResult(intent, REQUEST_SYSTEM_WINDOW_PERMISSION); + } +} diff --git a/src/org/cyanogenmod/theme/chooser2/ComponentCardView.java b/src/org/cyanogenmod/theme/chooser2/ComponentCardView.java new file mode 100644 index 0000000..f9578c7 --- /dev/null +++ b/src/org/cyanogenmod/theme/chooser2/ComponentCardView.java @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2016 Cyanogen, Inc. + * Copyright (C) 2016 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cyanogenmod.theme.chooser2; + +import android.animation.Animator; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.TransitionDrawable; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewOverlay; +import android.widget.LinearLayout; +import android.widget.TextView; + +public class ComponentCardView extends LinearLayout { + public static final int CARD_FADE_DURATION = 300; + + private static final float SEMI_OPAQUE_ALPHA = 0.4f; + + protected TextView mLabel; + protected View mEmptyView; + protected View mContentView; + + // Expanded Padding + int mExpandPadLeft; + int mExpandPadTop; + int mExpandPadRight; + int mExpandPadBottom; + + // The background drawable is returning an alpha of 0 regardless of what we set it to + // so this will help us keep track of what the drawable's alpha is at. + private int mBackgroundAlpha = 255; + + public ComponentCardView(Context context) { + this(context, null); + } + + public ComponentCardView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ComponentCardView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + setEnabled(false); + } + + @Override + protected void onFinishInflate() { + mLabel = (TextView) findViewById(R.id.label); + + Resources r = getContext().getResources(); + mExpandPadLeft = + (int) r.getDimension(R.dimen.card_padding_left_right) + getPaddingLeft(); + mExpandPadTop = + (int) r.getDimension(R.dimen.card_padding_top) + getPaddingTop(); + mExpandPadRight = + (int) r.getDimension(R.dimen.card_padding_left_right) + getPaddingRight(); + mExpandPadBottom = + (int) r.getDimension(R.dimen.card_padding_bottom) + getPaddingBottom(); + mEmptyView = findViewById(R.id.empty); + mContentView = findViewById(R.id.content); + } + + public void expand(boolean showLabel) { + setEnabled(true); + TransitionDrawable bg = null; + if (getBackground() instanceof TransitionDrawable) { + bg = (TransitionDrawable) getBackground(); + } + if (bg != null) { + Rect paddingRect = new Rect(); + bg.getPadding(paddingRect); + } + + setPadding(mExpandPadLeft, 0, mExpandPadRight, mExpandPadBottom); + + if (mLabel != null) { + mLabel.setAlpha(showLabel ? 1f : 0f); + mLabel.setVisibility(View.VISIBLE); + } + } + + public void animateExpand() { + if (getBackground() instanceof TransitionDrawable) { + TransitionDrawable background = (TransitionDrawable) getBackground(); + if (mLabel != null) { + mLabel.setVisibility(View.VISIBLE); + mLabel.setAlpha(0f); + mLabel.animate().alpha(1f).setDuration(CARD_FADE_DURATION).start(); + } + background.startTransition(CARD_FADE_DURATION); + } + } + + public void collapse() { + setEnabled(false); + if (mLabel != null) { + mLabel.setVisibility(View.GONE); + } + setPadding(0, 0, 0, 0); + } + + public void animateFadeOut() { + if (mLabel != null) { + mLabel.animate().alpha(0f).setDuration(CARD_FADE_DURATION); + } + + if (getBackground() instanceof TransitionDrawable) { + TransitionDrawable background = (TransitionDrawable) getBackground(); + background.reverseTransition(CARD_FADE_DURATION); + } + } + + /** + * Animates the card background and the title to 20% opacity. + */ + public void animateCardFadeOut() { + this.animate().alpha(SEMI_OPAQUE_ALPHA).setDuration(CARD_FADE_DURATION); + } + + /** + * Animates the card background and the title back to full opacity. + */ + public void animateCardFadeIn() { + this.animate().alpha(1f).setDuration(CARD_FADE_DURATION); + } + + /** + * Animates a change in the content of the card + * @param v View in card to animate + * @param overlay Drawable to animate as a ViewOverlay + * @param duration Duration of animation + */ + public void animateContentChange(View v, final Drawable overlay, long duration) { + final ViewOverlay viewOverlay = this.getOverlay(); + viewOverlay.add(overlay); + final int x = getRelativeLeft(v); + final int y = getRelativeTop(v); + final int width = v.getWidth(); + final int height = v.getHeight(); + overlay.setBounds(x, y, x + v.getWidth(), y + v.getHeight()); + + final ValueAnimator overlayAnimator = ValueAnimator.ofFloat(1f, 0f); + overlayAnimator.setDuration(duration); + overlayAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + float value = (Float) animation.getAnimatedValue(); + overlay.setAlpha((int) (255 * value)); + int newWidth = (int) (value * width); + int newHeight = (int) (value * height); + int dw = (width - newWidth) / 2; + int dh = (height - newHeight) / 2; + overlay.setBounds(x + dw, y + dh, x + dw + newWidth, y + dh + newHeight); + } + }); + overlayAnimator.addListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animation) {} + + @Override + public void onAnimationEnd(Animator animation) { + // Clear out the ViewOverlay now that we are done animating + viewOverlay.clear(); + } + + @Override + public void onAnimationCancel(Animator animation) {} + + @Override + public void onAnimationRepeat(Animator animation) {} + }); + + AnimatorSet set = new AnimatorSet(); + set.play(ObjectAnimator.ofFloat(v, "alpha", 0f, 1f)) + .with(ObjectAnimator.ofFloat(v, "scaleX", 0f, 1f)) + .with(ObjectAnimator.ofFloat(v, "scaleY", 0f, 1f)); + set.setDuration(duration); + + set.start(); + overlayAnimator.start(); + } + + public void setEmptyViewEnabled(boolean enabled) { + if (mEmptyView != null) { + mEmptyView.setVisibility(enabled ? View.VISIBLE : View.GONE); + } + if (mContentView != null) { + mContentView.setVisibility(enabled ? View.INVISIBLE : View.VISIBLE); + } + } + + public boolean isShowingEmptyView() { + return mEmptyView != null && mEmptyView.getVisibility() == View.VISIBLE; + } + + private int getRelativeTop(View v) { + if (v.getParent() == this) { + return v.getTop(); + } else { + return v.getTop() + ((View) v.getParent()).getTop(); + } + } + + private int getRelativeLeft(View v) { + if (v.getParent() == this) { + return v.getLeft(); + } else { + return v.getLeft() + ((View) v.getParent()).getLeft(); + } + } +} diff --git a/src/org/cyanogenmod/theme/chooser2/ComponentSelector.java b/src/org/cyanogenmod/theme/chooser2/ComponentSelector.java new file mode 100644 index 0000000..178c9b6 --- /dev/null +++ b/src/org/cyanogenmod/theme/chooser2/ComponentSelector.java @@ -0,0 +1,934 @@ +/* + * Copyright (C) 2016 Cyanogen, Inc. + * Copyright (C) 2016 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cyanogenmod.theme.chooser2; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.database.ContentObserver; +import android.database.Cursor; +import android.database.MatrixCursor; +import android.graphics.Typeface; +import android.graphics.drawable.BitmapDrawable; +import android.media.MediaPlayer; +import android.media.RingtoneManager; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.v4.app.FragmentActivity; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.Loader; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.Animation; +import android.view.animation.Animation.AnimationListener; +import android.view.animation.AnimationUtils; +import android.widget.ComponentSelectorLinearLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import org.cyanogenmod.theme.util.AudioUtils; +import org.cyanogenmod.theme.util.CursorLoaderHelper; +import org.cyanogenmod.theme.util.ThemedTypefaceHelper; +import org.cyanogenmod.theme.util.TypefaceHelperCache; +import org.cyanogenmod.theme.util.Utils; + +import cyanogenmod.providers.ThemesContract; +import cyanogenmod.providers.ThemesContract.PreviewColumns; +import cyanogenmod.providers.ThemesContract.ThemesColumns; + +import java.util.Map; + +import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_ALARMS; +import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_BOOT_ANIM; +import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_LAUNCHER; +import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_LIVE_LOCK_SCREEN; +import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_LOCKSCREEN; +import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_NOTIFICATIONS; +import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_OVERLAYS; +import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_RINGTONES; +import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_STATUS_BAR; +import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_NAVIGATION_BAR; +import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_ICONS; +import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_FONTS; + +import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_STATUS_BAR; +import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_FONT; +import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_ICONS; +import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_WALLPAPER; +import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_NAVIGATION_BAR; +import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_LOCKSCREEN; +import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_STYLE; +import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_BOOT_ANIMATION; +import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_RINGTONE; +import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_NOTIFICATION; +import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_ALARM; + +public class ComponentSelector extends LinearLayout + implements LoaderManager.LoaderCallbacks { + private static final String TAG = ComponentSelector.class.getSimpleName(); + + public static final boolean DEBUG_SELECTOR = false; + + public static final String EXTERNAL_WALLPAPER = "external"; + + public static final String MOD_LOCK = "mod_lock"; + + private static final int EXTRA_WALLPAPER_COMPONENTS = 2; + + private static final int EXTRA_LOCK_SCREEN_WALLPAPER_COMPONENTS = 3; + + protected static final long DEFAULT_COMPONENT_ID = 0; + + private Context mContext; + private LayoutInflater mInflater; + private ComponentSelectorLinearLayout mContent; + private LinearLayout.LayoutParams mItemParams; + private LinearLayout.LayoutParams mSoundItemParams = + new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, 0, 1.0f); + + private String mComponentType; + private int mBatteryStyle; + private int mItemsPerPage; + private String mAppliedComponentPkgName; + private String mSelectedComponentPkgName; + private long mSelectedComponentId; + + // animations for bringing selector in and out of view + private Animation mAnimateIn; + private Animation mAnimateOut; + + private OnItemClickedListener mListener; + + private OnOpenCloseListener mOpenCloseListener; + + private MediaPlayer mMediaPlayer; + private ImageView mCurrentPlayPause; + + private TypefaceHelperCache mTypefaceCache; + + private ThemesObserver mThemesObserver; + + public static final String IS_LIVE_LOCK_SCREEN_VIEW = "is_live_lock_screen_view"; + private View mPrevLockScreenView; + + public ComponentSelector(Context context, AttributeSet attrs) { + super(context, attrs); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ComponentSelector); + mItemsPerPage = a.getInt(R.styleable.ComponentSelector_itemsPerPage, + context.getResources().getInteger(R.integer.default_items_per_page)); + a.recycle(); + + mContext = context; + mInflater = LayoutInflater.from(context); + // TODO: Load from settings once available + mBatteryStyle = 0; /*Settings.System.getInt(context.getContentResolver(), + Settings.System.STATUS_BAR_BATTERY_STYLE, 0);*/ + + mAnimateIn = AnimationUtils.loadAnimation(mContext, + R.anim.component_selection_animate_in); + mAnimateOut = AnimationUtils.loadAnimation(mContext, + R.anim.component_selection_animate_out); + mAnimateIn.setAnimationListener(new AnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + } + + @Override + public void onAnimationEnd(Animation animation) { + if (mOpenCloseListener != null) mOpenCloseListener.onSelectorOpened(); + } + + @Override + public void onAnimationRepeat(Animation animation) { + } + }); + mAnimateOut.setAnimationListener(new AnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + if (mOpenCloseListener != null) mOpenCloseListener.onSelectorClosing(); + } + + @Override + public void onAnimationEnd(Animation animation) { + setVisibility(View.GONE); + } + + @Override + public void onAnimationRepeat(Animation animation) { + } + }); + mMediaPlayer = new MediaPlayer(); + mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + if (mCurrentPlayPause != null) { + mCurrentPlayPause.setImageResource(R.drawable.media_sound_selector_preview); + mCurrentPlayPause = null; + } + } + }); + mTypefaceCache = TypefaceHelperCache.getInstance(); + mThemesObserver = new ThemesObserver(); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mContent = (ComponentSelectorLinearLayout) findViewById(R.id.content); + setEnabled(false); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mThemesObserver.register(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + mThemesObserver.unregister(); + } + + @Override + protected void onWindowVisibilityChanged(int visibility) { + super.onWindowVisibilityChanged(visibility); + // Window visibility transitions as follows + // VISIBLE -> INVISIBLE -> GONE + // GONE -> INVISIBLE -> VISIBLE + if (visibility == View.GONE) { + mThemesObserver.unregister(); + } else if (visibility == View.VISIBLE) { + mThemesObserver.register(); + } + } + + public void resetComponentType() { + mComponentType = null; + } + + public void setComponentType(String component) { + setComponentType(component, null, DEFAULT_COMPONENT_ID); + } + + public void setComponentType(String component, String selectedPkgName) { + setComponentType(component, null, DEFAULT_COMPONENT_ID); + } + + public void setComponentType(String component, String selectedPkgName, + long selectedComponentId) { + mSelectedComponentPkgName = selectedPkgName; + mSelectedComponentId = selectedComponentId; + if (mComponentType == null || !mComponentType.equals(component)) { + mContent.removeAllViews(); + mComponentType = component; + ((FragmentActivity) mContext).getSupportLoaderManager().restartLoader( + getLoaderIdFromComponent(component), null, this); + } else if (mComponentType != null) { + int count = mContent.getChildCount(); + final Resources res = getResources(); + boolean highlightTitle; + Map selectedComponents = null; + if (mComponentType.equals(MODIFIES_LOCKSCREEN)) { + selectedComponents = ((ChooserActivity)mContext) + .getSelectedComponentsMap(); + } + for (int i = 0; i < count; i++) { + final View child = mContent.getChildAt(i); + final TextView tv = (TextView) child.findViewById(R.id.title); + // The child itself may have the tag, or in the case of sounds its the grandchild, + // either way the parent of the textview will have the pkgName in its tag + final View viewWithTag = (View) tv.getParent(); + final String pkgName = (String) viewWithTag.getTag(R.id.tag_key_package_name); + Long cmpntId = (Long) viewWithTag.getTag(R.id.tag_key_component_id); + if (cmpntId == null) { + cmpntId = DEFAULT_COMPONENT_ID; + } + Boolean isLLS = (Boolean) viewWithTag.getTag(R.id.tag_key_live_lock_screen); + highlightTitle = false; + if (selectedComponents != null && isLLS != null) { + if ((TextUtils.equals(selectedComponents.get(MODIFIES_LOCKSCREEN), pkgName) + && !isLLS) || (TextUtils.equals(selectedComponents.get( + MODIFIES_LIVE_LOCK_SCREEN), pkgName) && isLLS)) { + highlightTitle = true; + } + } else if (pkgName.equals(selectedPkgName) && cmpntId == selectedComponentId) { + highlightTitle = true; + } + if (highlightTitle) { + tv.setTextColor(res.getColor(R.color.component_selection_current_text_color)); + } else { + tv.setTextColor(res.getColor(android.R.color.white)); + } + } + } + } + + public String getComponentType() { + return mComponentType; + } + + public void setNumItemsPerPage(int itemsPerPage) { + if (mItemsPerPage != itemsPerPage) { + mItemsPerPage = itemsPerPage; + } + } + + public void setHeight(int height) { + ViewGroup.LayoutParams params = mContent.getLayoutParams(); + if (params.height != height) { + params.height = height; + mContent.setLayoutParams(params); + requestLayout(); + } + } + + public void show(String componentType, int itemsPerPage, int height) { + show(componentType, null, itemsPerPage, height); + } + + public void show(String componentType, String selectedPkgName, int itemsPerPage, int height) { + show(componentType, selectedPkgName, DEFAULT_COMPONENT_ID, itemsPerPage, height); + } + + public void show(String componentType, String selectedPkgName, long selectedComponentId, + int itemsPerPage, int height) { + setNumItemsPerPage(itemsPerPage); + setHeight(height); + setComponentType(componentType, selectedPkgName, selectedComponentId); + show(); + } + + public void show() { + if (getVisibility() == View.GONE) { + setEnabled(true); + setVisibility(View.VISIBLE); + startAnimation(mAnimateIn); + } + } + + public void hide() { + if (getVisibility() == View.VISIBLE && isEnabled()) { + setEnabled(false); + startAnimation(mAnimateOut); + } + if (mMediaPlayer != null && mMediaPlayer.isPlaying()) mMediaPlayer.stop(); + } + + private int getLoaderIdFromComponent(String component) { + if (MODIFIES_STATUS_BAR.equals(component)) { + return LOADER_ID_STATUS_BAR; + } + if (MODIFIES_NAVIGATION_BAR.equals(component)) { + return LOADER_ID_NAVIGATION_BAR; + } + if (MODIFIES_FONTS.equals(component)) { + return LOADER_ID_FONT; + } + if (MODIFIES_ICONS.equals(component)) { + return LOADER_ID_ICONS; + } + if (MODIFIES_OVERLAYS.equals(component)) { + return LOADER_ID_STYLE; + } + if (MODIFIES_LAUNCHER.equals(component)) { + return LOADER_ID_WALLPAPER; + } + if (MODIFIES_BOOT_ANIM.equals(component)) { + return LOADER_ID_BOOT_ANIMATION; + } + if (MODIFIES_RINGTONES.equals(component)) { + return LOADER_ID_RINGTONE; + } + if (MODIFIES_NOTIFICATIONS.equals(component)) { + return LOADER_ID_NOTIFICATION; + } + if (MODIFIES_ALARMS.equals(component)) { + return LOADER_ID_ALARM; + } + if (MODIFIES_LOCKSCREEN.equals(component)) { + return LOADER_ID_LOCKSCREEN; + } + return -1; + } + + @Override + public Loader onCreateLoader(int id, Bundle args) { + return CursorLoaderHelper.componentSelectorCursorLoader(mContext, id); + } + + @Override + public void onLoadFinished(Loader loader, final Cursor data) { + int currentLoaderId = loader.getId(); + int count = data.getCount(); + int screenWidth = mContext.getResources().getDisplayMetrics().widthPixels; + final Resources res = getResources(); + int dividerPadding = res.getDimensionPixelSize(R.dimen.component_divider_padding_top); + int dividerHeight = res.getDimensionPixelSize(R.dimen.component_divider_height); + MatrixCursor lockScreenMatrixCursor = null; + + switch (currentLoaderId) { + case LOADER_ID_ALARM: + case LOADER_ID_NOTIFICATION: + case LOADER_ID_RINGTONE: + mItemParams = new LayoutParams(screenWidth, + ViewGroup.LayoutParams.MATCH_PARENT); + // Sounds are a special case where there are two items laid out + // vertically. This layout is added as a single item so we need to + // adjust the count by dividing by the number of items per page and + // rounding up so we include all items. + count = (int) Math.ceil((double)count / mItemsPerPage); + mContent.setShowDividers(LinearLayout.SHOW_DIVIDER_NONE); + break; + case LOADER_ID_BOOT_ANIMATION: + dividerPadding = res.getDimensionPixelSize( + R.dimen.component_divider_padding_top_bootani); + dividerHeight = res.getDimensionPixelSize(R.dimen.component_divider_height_bootani); + // fall through to default + default: + mItemParams = new LayoutParams(screenWidth / mItemsPerPage, + ViewGroup.LayoutParams.MATCH_PARENT); + if (currentLoaderId == LOADER_ID_WALLPAPER || + currentLoaderId == LOADER_ID_LOCKSCREEN) { + count += EXTRA_WALLPAPER_COMPONENTS; + } + + if (currentLoaderId == LOADER_ID_LOCKSCREEN) { + lockScreenMatrixCursor = splitLockScreenCursor(data); + if (lockScreenMatrixCursor != null) { + count = lockScreenMatrixCursor.getCount() + EXTRA_WALLPAPER_COMPONENTS; + } + } + + mContent.setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE); + break; + } + + mContent.setDividerPadding(dividerPadding); + mContent.setDividerHeight(dividerHeight); + + new LoadItemsTask().execute((lockScreenMatrixCursor != null) + ? lockScreenMatrixCursor : data, count); + } + + /* Some themes might contain a lock wallpaper AND a live lock screen. + * ThemesProvider will return one single row containing both thumbnail paths + * (ThemesProvider groups by theme_id) so we need to create a cursor on the + * fly to split that row into 2 to properly generate a view for each thumbnail + */ + private MatrixCursor splitLockScreenCursor(Cursor data) { + int lockWallPaperThumbnailIndx, llsThumbnailIndx, pkgIndx; + String lockWallPaperThumbnail, liveLockScreenThumbnail, pkgName; + MatrixCursor lockScreenMatrixCursor; + int needToSplitRowAt = -1; + + lockWallPaperThumbnailIndx = data.getColumnIndex(PreviewColumns.LOCK_WALLPAPER_THUMBNAIL); + llsThumbnailIndx = data.getColumnIndex(PreviewColumns.LIVE_LOCK_SCREEN_THUMBNAIL); + pkgIndx = data.getColumnIndex(ThemesColumns.PKG_NAME); + + if (lockWallPaperThumbnailIndx < 0 || llsThumbnailIndx < 0 || pkgIndx < 0) { + //An invalid cursor was provided, we can't continue processing + Log.e(TAG, "Failed to process cursor due to missing columns"); + return null; + } + + //Let's find out if we really need to allocate a MatrixCursor. + //If we find at least one row with valid data in lock_wallpaper_thumbnail AND + //live_lock_screen_thumbnail it means we do. + data.moveToPosition(-1); + while (data.moveToNext()) { + lockWallPaperThumbnail = data.getString(lockWallPaperThumbnailIndx); + liveLockScreenThumbnail = data.getString(llsThumbnailIndx); + if (!TextUtils.isEmpty(lockWallPaperThumbnail) + && !TextUtils.isEmpty(liveLockScreenThumbnail)) { + needToSplitRowAt = data.getPosition(); + break; + } + } + + if (needToSplitRowAt == -1) return null; + + lockScreenMatrixCursor = new MatrixCursor(data.getColumnNames()); + //Clone all the *regular* rows up to needToSplitRowAt + for (int indx = 0; indx < needToSplitRowAt; indx++) { + data.moveToPosition(indx); + lockScreenMatrixCursor.addRow(CursorLoaderHelper.getRowFromCursor(data)); + } + if (needToSplitRowAt == 0) { + data.moveToPosition(-1); + } + while (data.moveToNext()) { + lockWallPaperThumbnail = data.getString(lockWallPaperThumbnailIndx); + liveLockScreenThumbnail = data.getString(llsThumbnailIndx); + if (!TextUtils.isEmpty(lockWallPaperThumbnail) + && !TextUtils.isEmpty(liveLockScreenThumbnail)) { + pkgName = data.getString(pkgIndx); + + MatrixCursor.RowBuilder lockWallpaperRow = lockScreenMatrixCursor.newRow(); + MatrixCursor.RowBuilder liveLockScreenRow = lockScreenMatrixCursor.newRow(); + + for (String col : data.getColumnNames()) { + if (TextUtils.equals(col, PreviewColumns.LOCK_WALLPAPER_THUMBNAIL)) { + lockWallpaperRow.add(PreviewColumns.LOCK_WALLPAPER_THUMBNAIL, + lockWallPaperThumbnail); + liveLockScreenRow.add(PreviewColumns.LOCK_WALLPAPER_THUMBNAIL, null); + } else if (TextUtils.equals(col, PreviewColumns.LIVE_LOCK_SCREEN_THUMBNAIL)) { + lockWallpaperRow.add(PreviewColumns.LIVE_LOCK_SCREEN_THUMBNAIL, null); + liveLockScreenRow.add(PreviewColumns.LIVE_LOCK_SCREEN_THUMBNAIL, + liveLockScreenThumbnail); + } else if (TextUtils.equals(col, MODIFIES_LIVE_LOCK_SCREEN)) { + lockWallpaperRow.add(MODIFIES_LIVE_LOCK_SCREEN, 0); + liveLockScreenRow.add(MODIFIES_LIVE_LOCK_SCREEN, 1); + } else { + int colIndx = data.getColumnIndex(col); + lockWallpaperRow.add(col, CursorLoaderHelper.getFieldValueFromRow(data, + colIndx)); + liveLockScreenRow.add(col, CursorLoaderHelper.getFieldValueFromRow(data, + colIndx)); + } + } + } else { + //This is a regular row, so just clone it + lockScreenMatrixCursor.addRow(CursorLoaderHelper.getRowFromCursor(data)); + } + } + return lockScreenMatrixCursor; + } + + @Override + public void onLoaderReset(Loader loader) { + } + + public void setOnItemClickedListener(OnItemClickedListener listener) { + mListener = listener; + } + + public void setOnOpenCloseListener(OnOpenCloseListener listener) { + mOpenCloseListener = listener; + } + + private View newView(Cursor cursor, int position, ViewGroup container) { + if (MODIFIES_STATUS_BAR.equals(mComponentType)) { + return newStatusBarView(cursor, container, position); + } + if (MODIFIES_NAVIGATION_BAR.equals(mComponentType)) { + return newNavBarView(cursor, container, position); + } + if (MODIFIES_FONTS.equals(mComponentType)) { + return newFontView(cursor, container, position); + } + if (MODIFIES_ICONS.equals(mComponentType)) { + return newIconView(cursor, container, position); + } + if (MODIFIES_OVERLAYS.equals(mComponentType)) { + return newStyleView(cursor, container, position); + } + if (MODIFIES_LAUNCHER.equals(mComponentType)) { + return newWallpapersView(cursor, container, position, + cursor.getColumnIndex(PreviewColumns.WALLPAPER_THUMBNAIL), false, + EXTRA_WALLPAPER_COMPONENTS); + } + if (MODIFIES_BOOT_ANIM.equals(mComponentType)) { + return newBootanimationView(cursor, container, position); + } + if (MODIFIES_RINGTONES.equals(mComponentType) || + MODIFIES_NOTIFICATIONS.equals(mComponentType) || + MODIFIES_ALARMS.equals(mComponentType)) { + return newSoundView(cursor, container, position, mComponentType); + } + if (MODIFIES_LOCKSCREEN.equals(mComponentType)) { + boolean isLiveLockScreen = false; + if (position >= EXTRA_LOCK_SCREEN_WALLPAPER_COMPONENTS) { + cursor.moveToPosition(position - EXTRA_LOCK_SCREEN_WALLPAPER_COMPONENTS); + int liveLockIndex = cursor.getColumnIndex(MODIFIES_LIVE_LOCK_SCREEN); + isLiveLockScreen = liveLockIndex >= 0 && + cursor.getInt(liveLockIndex) == 1; + } + int index = isLiveLockScreen + ? cursor.getColumnIndex(PreviewColumns.LIVE_LOCK_SCREEN_THUMBNAIL) + : cursor.getColumnIndex(PreviewColumns.LOCK_WALLPAPER_THUMBNAIL); + return newWallpapersView(cursor, container, position, index, isLiveLockScreen, + EXTRA_LOCK_SCREEN_WALLPAPER_COMPONENTS); + } + return null; + } + + private View newStatusBarView(Cursor cursor, ViewGroup parent, int position) { + cursor.moveToPosition(position); + View v = mInflater.inflate(R.layout.status_bar_component_selection_item, + parent, false); + int wifiIndex = cursor.getColumnIndex(PreviewColumns.STATUSBAR_WIFI_ICON); + int signalIndex = cursor.getColumnIndex(PreviewColumns.STATUSBAR_SIGNAL_ICON); + int bluetoothIndex = cursor.getColumnIndex(PreviewColumns.STATUSBAR_BLUETOOTH_ICON); + int batteryIndex = cursor.getColumnIndex(Utils.getBatteryIndex(mBatteryStyle)); + int backgroundIndex = cursor.getColumnIndex(PreviewColumns.STATUSBAR_BACKGROUND); + int pkgNameIndex = cursor.getColumnIndex(ThemesContract.ThemesColumns.PKG_NAME); + + ((ImageView) v.findViewById(R.id.slot1)).setImageBitmap( + Utils.loadBitmapBlob(cursor, wifiIndex)); + ((ImageView) v.findViewById(R.id.slot2)).setImageBitmap( + Utils.loadBitmapBlob(cursor, signalIndex)); + ((ImageView) v.findViewById(R.id.slot3)).setImageBitmap( + Utils.loadBitmapBlob(cursor, bluetoothIndex)); + ((ImageView) v.findViewById(R.id.slot4)).setImageBitmap( + Utils.loadBitmapBlob(cursor, batteryIndex)); + setTitle(((TextView) v.findViewById(R.id.title)), cursor); + v.findViewById(R.id.container).setBackground( + new BitmapDrawable(Utils.loadBitmapBlob(cursor, backgroundIndex))); + v.setTag(R.id.tag_key_package_name, cursor.getString(pkgNameIndex)); + v.setOnClickListener(mItemClickListener); + return v; + } + + private View newNavBarView(Cursor cursor, ViewGroup parent, int position) { + cursor.moveToPosition(position); + View v = mInflater.inflate(R.layout.navigation_bar_component_selection_item, parent, + false); + int backIndex = cursor.getColumnIndex(PreviewColumns.NAVBAR_BACK_BUTTON); + int backgroundIndex = cursor.getColumnIndex(PreviewColumns.STATUSBAR_BACKGROUND); + int pkgNameIndex = cursor.getColumnIndex(ThemesContract.ThemesColumns.PKG_NAME); + + ((ImageView) v.findViewById(R.id.back)).setImageBitmap( + Utils.loadBitmapBlob(cursor, backIndex)); + setTitle(((TextView) v.findViewById(R.id.title)), cursor); + v.findViewById(R.id.container).setBackground( + new BitmapDrawable(Utils.loadBitmapBlob(cursor, backgroundIndex))); + v.setTag(R.id.tag_key_package_name, cursor.getString(pkgNameIndex)); + v.setOnClickListener(mItemClickListener); + return v; + } + + private View newFontView(Cursor cursor, ViewGroup parent, int position) { + cursor.moveToPosition(position); + View v = mInflater.inflate(R.layout.font_component_selection_item, parent, false); + int pkgNameIndex = cursor.getColumnIndex(ThemesContract.ThemesColumns.PKG_NAME); + + TextView preview = (TextView) v.findViewById(R.id.text_preview); + String pkgName = cursor.getString(pkgNameIndex); + + ThemedTypefaceHelper helper = mTypefaceCache.getHelperForTheme(mContext, pkgName); + Typeface typefaceNormal = helper.getTypeface(Typeface.NORMAL); + preview.setTypeface(typefaceNormal); + + setTitle(((TextView) v.findViewById(R.id.title)), cursor); + v.setTag(R.id.tag_key_package_name, cursor.getString(pkgNameIndex)); + v.setOnClickListener(mItemClickListener); + return v; + } + + private View newIconView(Cursor cursor, ViewGroup parent, int position) { + cursor.moveToPosition(position); + View v = mInflater.inflate(R.layout.icon_component_selection_item, parent, + false); + int iconIndex = cursor.getColumnIndex(PreviewColumns.ICON_PREVIEW_1); + int pkgNameIndex = cursor.getColumnIndex(ThemesContract.ThemesColumns.PKG_NAME); + + ((ImageView) v.findViewById(R.id.icon)).setImageBitmap( + Utils.loadBitmapBlob(cursor, iconIndex)); + setTitle(((TextView) v.findViewById(R.id.title)), cursor); + v.setTag(R.id.tag_key_package_name, cursor.getString(pkgNameIndex)); + v.setOnClickListener(mItemClickListener); + return v; + } + + private View newStyleView(Cursor cursor, ViewGroup parent, int position) { + cursor.moveToPosition(position); + View v = mInflater.inflate(R.layout.icon_component_selection_item, parent, + false); + int styleIndex = cursor.getColumnIndex(PreviewColumns.STYLE_THUMBNAIL); + int pkgNameIndex = cursor.getColumnIndex(ThemesContract.ThemesColumns.PKG_NAME); + + ((ImageView) v.findViewById(R.id.icon)).setImageBitmap( + Utils.loadBitmapBlob(cursor, styleIndex)); + setTitle(((TextView) v.findViewById(R.id.title)), cursor); + v.setTag(R.id.tag_key_package_name, cursor.getString(pkgNameIndex)); + v.setOnClickListener(mItemClickListener); + return v; + } + + private View newWallpapersView(Cursor cursor, ViewGroup parent, int position, + int wallpaperIndex, boolean isLiveLockScreen, int numExtraComponents) { + View v = mInflater.inflate(R.layout.wallpaper_component_selection_item, parent, + false); + ImageView iv = (ImageView) v.findViewById(R.id.icon); + if (position == 0) { + iv.setImageResource(R.drawable.img_wallpaper_none); + v.setTag(R.id.tag_key_package_name, ""); + ((TextView) v.findViewById(R.id.title)).setText(R.string.wallpaper_none_title); + } else if (position == 1) { + iv.setImageResource(R.drawable.img_wallpaper_external); + v.setTag(R.id.tag_key_package_name, EXTERNAL_WALLPAPER); + ((TextView) v.findViewById(R.id.title)) + .setText(R.string.wallpaper_external_title); + } else if (numExtraComponents == EXTRA_LOCK_SCREEN_WALLPAPER_COMPONENTS && position == 2) { + // TODO: update drawable once the asset is provided by design + iv.setImageResource(android.R.drawable.ic_lock_lock); + v.setTag(R.id.tag_key_package_name, MOD_LOCK); + ((TextView) v.findViewById(R.id.title)) + .setText(R.string.mod_lock_title); + } else { + cursor.moveToPosition(position - numExtraComponents); + int pkgNameIndex = cursor.getColumnIndex(ThemesContract.ThemesColumns.PKG_NAME); + int cmpntIdIndex = cursor.getColumnIndex(PreviewColumns.COMPONENT_ID); + long cmpntId = (cmpntIdIndex >= 0) ? + cursor.getLong(cmpntIdIndex) : DEFAULT_COMPONENT_ID; + iv.setImageBitmap( + Utils.loadBitmapBlob(cursor, wallpaperIndex)); + setTitle(((TextView) v.findViewById(R.id.title)), cursor); + v.setTag(R.id.tag_key_package_name, cursor.getString(pkgNameIndex)); + v.setTag(R.id.tag_key_component_id, cmpntId); + v.setTag(R.id.tag_key_live_lock_screen, isLiveLockScreen); + v.findViewById(R.id.live_lock_screen_badge) + .setVisibility(isLiveLockScreen ? View.VISIBLE : View.GONE); + } + v.setOnClickListener(mItemClickListener); + return v; + } + + private View newBootanimationView(Cursor cursor, ViewGroup parent, int position) { + cursor.moveToPosition(position); + View v = mInflater.inflate(R.layout.bootani_component_selection_item, parent, + false); + int wallpaperIndex = cursor.getColumnIndex(PreviewColumns.BOOTANIMATION_THUMBNAIL); + int pkgNameIndex = cursor.getColumnIndex(ThemesContract.ThemesColumns.PKG_NAME); + + ((ImageView) v.findViewById(R.id.preview)).setImageBitmap( + Utils.loadBitmapBlob(cursor, wallpaperIndex)); + setTitle(((TextView) v.findViewById(R.id.title)), cursor); + v.setTag(R.id.tag_key_package_name, cursor.getString(pkgNameIndex)); + v.setOnClickListener(mItemClickListener); + return v; + } + + private View newSoundView(Cursor cursor, ViewGroup parent, int position, + final String component) { + LinearLayout container = (LinearLayout) mInflater.inflate( + R.layout.component_selection_sounds_pager_item, parent, false); + container.setWeightSum(mItemsPerPage); + for (int i = 0; i < mItemsPerPage; i++) { + int index = position * mItemsPerPage + i; + if (cursor.getCount() <= index) continue; + cursor.moveToPosition(index); + View v = mInflater.inflate(R.layout.sound_component_selection_item, parent, + false); + final int pkgNameIndex = cursor.getColumnIndex(ThemesContract.ThemesColumns.PKG_NAME); + + setTitle(((TextView) v.findViewById(R.id.title)), cursor); + v.setTag(R.id.tag_key_package_name, cursor.getString(pkgNameIndex)); + v.setOnClickListener(mItemClickListener); + container.addView(v, mSoundItemParams); + final View playButton = v.findViewById(R.id.play_button); + playButton.setTag(cursor.getString(pkgNameIndex)); + playButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + int type; + String pkgName = (String) v.getTag(); + if (component.equals(MODIFIES_RINGTONES)) { + type = RingtoneManager.TYPE_RINGTONE; + } else if (component.equals(MODIFIES_NOTIFICATIONS)) { + type = RingtoneManager.TYPE_NOTIFICATION; + } else { + type = RingtoneManager.TYPE_ALARM; + } + boolean shouldStop = playButton == mCurrentPlayPause; + try { + if (mMediaPlayer != null && mMediaPlayer.isPlaying()) { + mMediaPlayer.stop(); + if (mCurrentPlayPause != null) { + mCurrentPlayPause.setImageResource( + R.drawable.media_sound_selector_preview); + } + mCurrentPlayPause = null; + } + if (mCurrentPlayPause != playButton && !shouldStop) { + AudioUtils.loadThemeAudible(mContext, type, pkgName, + mMediaPlayer); + mMediaPlayer.start(); + mCurrentPlayPause = (ImageView) playButton; + mCurrentPlayPause.setImageResource( + R.drawable.media_sound_selector_stop); + } + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, "Unable to play preview sound", e); + } + } + }); + } + + return container; + } + + private class LoadItemsTask extends AsyncTask { + + @Override + protected Void doInBackground(Object... params) { + Cursor c = (Cursor) params[0]; + int count = (Integer) params[1]; + for (int i = 0; i < count && !isCancelled(); i++) { + final View v = newView(c, i, mContent); + mContent.post(new Runnable() { + @Override + public void run() { + mContent.addView(v, mItemParams); + } + }); + } + + if (c instanceof MatrixCursor) { + c.close(); + } + + // destroy the loader now that we are done with it + ComponentSelector.this.post(new Runnable() { + @Override + public void run() { + ((FragmentActivity)mContext).getSupportLoaderManager().destroyLoader( + getLoaderIdFromComponent(mComponentType)); + } + }); + return null; + } + } + + private void setTitle(TextView titleView, Cursor cursor) { + String pkgName = cursor.getString(cursor.getColumnIndex(ThemesColumns.PKG_NAME)); + int cmpntIdIndex = cursor.getColumnIndex(PreviewColumns.COMPONENT_ID); + long cmpntId = DEFAULT_COMPONENT_ID; + if (cmpntIdIndex >= 0) { + cmpntId = cursor.getLong(cmpntIdIndex); + } + if (Utils.getDefaultThemePackageName(mContext).equals(pkgName)) { + titleView.setText(mContext.getString(R.string.default_tag_text)); + titleView.setTypeface(titleView.getTypeface(), Typeface.BOLD); + } else { + titleView.setText(cursor.getString(cursor.getColumnIndex(ThemesColumns.TITLE))); + } + boolean highlightTitle = false; + if (mComponentType.equals(MODIFIES_LOCKSCREEN)) { + Map selectedComponents = ((ChooserActivity)mContext) + .getSelectedComponentsMap(); + int isLLS = cursor.getInt(cursor.getColumnIndex(MODIFIES_LIVE_LOCK_SCREEN)); + if ((TextUtils.equals(selectedComponents.get(MODIFIES_LOCKSCREEN), pkgName) + && isLLS == 0) || (TextUtils.equals( + selectedComponents.get(MODIFIES_LIVE_LOCK_SCREEN), pkgName) && isLLS == 1)) { + highlightTitle = true; + } + } else if (pkgName.equals(mSelectedComponentPkgName) && cmpntId == mSelectedComponentId) { + highlightTitle = true; + } + if (highlightTitle) { + titleView.setTextColor(getResources().getColor( + R.color.component_selection_current_text_color)); + } + } + + private OnClickListener mItemClickListener = new OnClickListener() { + @Override + public void onClick(View v) { + long cmpntId = DEFAULT_COMPONENT_ID; + String pkgName = (String) v.getTag(R.id.tag_key_package_name); + Long cmpntIdTag = (Long) v.getTag(R.id.tag_key_component_id); + if (cmpntIdTag != null) { + cmpntId = cmpntIdTag; + } + Boolean isLiveLock = (Boolean) v.getTag(R.id.tag_key_live_lock_screen); + boolean isSamePkgButDifferentLockScreen = false; + Bundle params = null; + if (isLiveLock != null) { + params = new Bundle(); + params.putBoolean(IS_LIVE_LOCK_SCREEN_VIEW, isLiveLock); + + if (pkgName.equals(mSelectedComponentPkgName) && v != mPrevLockScreenView) { + isSamePkgButDifferentLockScreen = true; + } + mPrevLockScreenView = v; + } + if (DEBUG_SELECTOR) Toast.makeText(mContext, pkgName, Toast.LENGTH_SHORT).show(); + if (mListener != null && (isSamePkgButDifferentLockScreen || + !pkgName.equals(mSelectedComponentPkgName) || + pkgName.equals(EXTERNAL_WALLPAPER) || cmpntId != mSelectedComponentId)) { + mSelectedComponentPkgName = pkgName; + mSelectedComponentId = cmpntId; + mListener.onItemClicked(pkgName, cmpntId, params); + final int count = mContent.getChildCount(); + final Resources res = getResources(); + for (int i = 0; i < count; i++) { + final View child = mContent.getChildAt(i); + final TextView tv = (TextView) child.findViewById(R.id.title); + if (tv != null) { + if (child == v) { + tv.setTextColor( + res.getColor(R.color.component_selection_current_text_color)); + } else { + tv.setTextColor(res.getColor(android.R.color.white)); + } + } + } + } + } + }; + + private class ThemesObserver extends ContentObserver { + public ThemesObserver() { + super(null); + } + + public void register() { + mContext.getContentResolver().registerContentObserver( + ThemesColumns.CONTENT_URI, false, this); + } + + public void unregister() { + mContext.getContentResolver().unregisterContentObserver(this); + } + + @Override + public void onChange(boolean selfChange) { + // reload items by calling setComponentType() + if (mComponentType != null) { + final String componentType = mComponentType; + mComponentType = null; + mContent.post(new Runnable() { + @Override + public void run() { + setComponentType(componentType, mSelectedComponentPkgName); + } + }); + } + } + } + + public interface OnItemClickedListener { + public void onItemClicked(String pkgName, long componentId, Bundle params); + } + + public interface OnOpenCloseListener { + public void onSelectorOpened(); + public void onSelectorClosed(); + public void onSelectorClosing(); + } +} \ No newline at end of file diff --git a/src/org/cyanogenmod/theme/chooser2/IconTransitionDrawable.java b/src/org/cyanogenmod/theme/chooser2/IconTransitionDrawable.java new file mode 100644 index 0000000..08cc910 --- /dev/null +++ b/src/org/cyanogenmod/theme/chooser2/IconTransitionDrawable.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2016 Cyanogen, Inc. + * Copyright (C) 2016 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cyanogenmod.theme.chooser2; + +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; +import android.os.SystemClock; + +/** + * An extension of LayerDrawables that is intended to cross-fade between + * the first and second layer. To start the transition, call {@link #startTransition(int)}. To + * display just the first layer, call {@link #resetTransition()}. + *

+ * It can be defined in an XML file with the <transition> element. + * Each Drawable in the transition is defined in a nested <item>. For more + * information, see the guide to Drawable Resources.

+ * + * @attr ref android.R.styleable#LayerDrawableItem_left + * @attr ref android.R.styleable#LayerDrawableItem_top + * @attr ref android.R.styleable#LayerDrawableItem_right + * @attr ref android.R.styleable#LayerDrawableItem_bottom + * @attr ref android.R.styleable#LayerDrawableItem_drawable + * @attr ref android.R.styleable#LayerDrawableItem_id + * + */ +public class IconTransitionDrawable extends LayerDrawable { + + /** + * A transition is about to start. + */ + private static final int TRANSITION_STARTING = 0; + + /** + * The transition has started and the animation is in progress + */ + private static final int TRANSITION_RUNNING = 1; + + /** + * No transition will be applied + */ + private static final int TRANSITION_NONE = 2; + + /** + * The current state of the transition. One of {@link #TRANSITION_STARTING}, + * {@link #TRANSITION_RUNNING} and {@link #TRANSITION_NONE} + */ + private int mTransitionState = TRANSITION_NONE; + + private long mStartTimeMillis; + private int mFrom; + private int mTo; + private int mDuration; + private int mAlpha = 0; + private float mFromScale; + private float mToScale; + + /** + * Create a new transition drawable with the specified list of layers. At least + * 2 layers are required for this drawable to work properly. + */ + public IconTransitionDrawable(Drawable[] layers) { + super(layers); + } + + /** + * Begin the second layer on top of the first layer. + * + * @param durationMillis The length of the transition in milliseconds + */ + public void startTransition(int durationMillis) { + mFrom = 0; + mTo = 255; + mAlpha = 0; + mFromScale = 0f; + mToScale = 1.0f; + mDuration = durationMillis; + mTransitionState = TRANSITION_STARTING; + invalidateSelf(); + } + + /** + * Show only the first layer. + */ + public void resetTransition() { + mAlpha = 0; + mTransitionState = TRANSITION_NONE; + invalidateSelf(); + } + + @Override + public void draw(Canvas canvas) { + boolean done = true; + float scale = 0f; + + switch (mTransitionState) { + case TRANSITION_STARTING: + mStartTimeMillis = SystemClock.uptimeMillis(); + done = false; + mTransitionState = TRANSITION_RUNNING; + break; + + case TRANSITION_RUNNING: + if (mStartTimeMillis >= 0) { + float normalized = (float) + (SystemClock.uptimeMillis() - mStartTimeMillis) / mDuration; + done = normalized >= 1.0f; + normalized = Math.min(normalized, 1.0f); + mAlpha = (int) (mFrom + (mTo - mFrom) * normalized); + scale = mFromScale + (mToScale - mFromScale) * normalized; + } + break; + } + + final int alpha = mAlpha; + + if (done) { + // the setAlpha() calls below trigger invalidation and redraw. If we're done, just draw + // the appropriate drawable[s] and return + if (alpha == 0) { + getDrawable(0).draw(canvas); + } + if (alpha == 0xFF) { + getDrawable(1).draw(canvas); + + } + return; + } + + Drawable d; + d = getDrawable(0); + d.setAlpha(255 - alpha); + int cx = getIntrinsicWidth() / 2; + int cy = getIntrinsicHeight() / 2; + canvas.save(); + canvas.scale(1.0f - scale, 1.0f - scale, cx, cy); + d.draw(canvas); + canvas.restore(); + d.setAlpha(0xFF); + + if (alpha > 0) { + d = getDrawable(1); + d.setAlpha(alpha); + canvas.save(); + canvas.scale(scale, scale, cx, cy); + d.draw(canvas); + canvas.restore(); + d.setAlpha(0xFF); + } + + if (!done) { + invalidateSelf(); + } + } +} diff --git a/src/org/cyanogenmod/theme/chooser2/MyThemeFragment.java b/src/org/cyanogenmod/theme/chooser2/MyThemeFragment.java new file mode 100644 index 0000000..490b568 --- /dev/null +++ b/src/org/cyanogenmod/theme/chooser2/MyThemeFragment.java @@ -0,0 +1,707 @@ +/* + * Copyright (C) 2016 Cyanogen, Inc. + * Copyright (C) 2016 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cyanogenmod.theme.chooser2; + +import android.app.WallpaperManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.res.Resources; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.Typeface; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.media.MediaPlayer; +import android.media.Ringtone; +import android.media.RingtoneManager; +import android.net.Uri; +import android.os.Bundle; +import android.support.v4.content.Loader; +import android.util.Log; +import android.util.MutableLong; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.SurfaceView; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import org.cyanogenmod.theme.util.AudioUtils; +import org.cyanogenmod.theme.util.CursorLoaderHelper; +import org.cyanogenmod.theme.util.PreferenceUtils; +import org.cyanogenmod.theme.util.ThemedTypefaceHelper; +import org.cyanogenmod.theme.util.TypefaceHelperCache; +import org.cyanogenmod.theme.util.Utils; + +import cyanogenmod.providers.ThemesContract; +import cyanogenmod.providers.ThemesContract.PreviewColumns; +import cyanogenmod.providers.ThemesContract.ThemesColumns; +import cyanogenmod.themes.ThemeChangeRequest; +import cyanogenmod.themes.ThemeChangeRequest.RequestType; +import cyanogenmod.themes.ThemeManager; + +import org.cyanogenmod.internal.util.ThemeUtils; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_ALL; + +public class MyThemeFragment extends ThemeFragment { + private static final String TAG = MyThemeFragment.class.getSimpleName(); + + private static final String ARG_BASE_THEME_PACKAGE_NAME = "baseThemePkgName"; + private static final String ARG_BASE_THEME_NAME = "baseThemeName"; + private static final String ARG_BASE_THEME_AUTHOR = "baseThemeAuthor"; + + private String mBaseThemeName; + private String mBaseThemeAuthor; + + private SurfaceView mSurfaceView; + + static MyThemeFragment newInstance(String baseThemePkgName, String baseThemeName, + String baseThemeAuthor, boolean skipLoadingAnim, + boolean animateToLockScreenCard) { + MyThemeFragment f = new MyThemeFragment(); + Bundle args = new Bundle(); + args.putString(ARG_PACKAGE_NAME, CURRENTLY_APPLIED_THEME); + args.putString(ARG_BASE_THEME_PACKAGE_NAME, baseThemePkgName); + args.putString(ARG_BASE_THEME_NAME, baseThemeName); + args.putString(ARG_BASE_THEME_AUTHOR, baseThemeAuthor); + args.putBoolean(ARG_SKIP_LOADING_ANIM, skipLoadingAnim); + args.putBoolean(ARG_ANIMATE_TO_LOCK_SCREEN_CARD, animateToLockScreenCard); + f.setArguments(args); + return f; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + final Context context = getActivity(); + ThemedTypefaceHelper helper = sTypefaceHelperCache.getHelperForTheme(context, + getAppliedFontPackageName()); + mTypefaceNormal = helper.getTypeface(Typeface.NORMAL); + mBaseThemePkgName = getArguments().getString(ARG_BASE_THEME_PACKAGE_NAME); + mBaseThemeName = getArguments().getString(ARG_BASE_THEME_NAME); + mBaseThemeAuthor = getArguments().getString(ARG_BASE_THEME_AUTHOR); + mShowLockScreenSelectorAfterContentLoaded = getArguments().getBoolean( + ARG_ANIMATE_TO_LOCK_SCREEN_CARD); + mSurfaceView = createSurfaceView(); + populateBaseThemeSupportedComponents(mBaseThemePkgName); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View v = super.onCreateView(inflater, container, savedInstanceState); + mThemeTagLayout.setAppliedTagEnabled(true); + if (mBaseThemePkgName.equals(Utils.getDefaultThemePackageName(getActivity()))) { + mThemeTagLayout.setDefaultTagEnabled(true); + } + if (PreferenceUtils.hasThemeBeenUpdated(getActivity(), mBaseThemePkgName)) { + mThemeTagLayout.setUpdatedTagEnabled(true); + } + mDelete.setVisibility(View.GONE); + setCustomized(isThemeCustomized()); + return v; + } + + @Override + public void onResume() { + super.onResume(); + if (!mExpanded && getLoaderManager().getLoader(0) != null) { + getLoaderManager().restartLoader(0, null, this); + } + + IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED); + getActivity().registerReceiver(mWallpaperChangeReceiver, filter); + } + + @Override + public void onPause() { + getActivity().unregisterReceiver(mWallpaperChangeReceiver); + super.onPause(); + } + + @Override + public void setUserVisibleHint(boolean isVisibleToUser) { + super.setUserVisibleHint(isVisibleToUser); + if (mThemeTagLayout == null) return; + + if (!isVisibleToUser) { + if (PreferenceUtils.hasThemeBeenUpdated(getActivity(), mBaseThemePkgName)) { + mThemeTagLayout.setUpdatedTagEnabled(true); + } + } else { + if (PreferenceUtils.hasThemeBeenUpdated(getActivity(), mBaseThemePkgName)) { + PreferenceUtils.removeUpdatedTheme(getActivity(), mBaseThemePkgName); + } + } + } + + @Override + protected boolean onPopupMenuItemClick(MenuItem item) { + switch(item.getItemId()) { + case R.id.menu_reset: + resetTheme(); + return true; + } + + return super.onPopupMenuItemClick(item); + } + + @Override + public void collapse(boolean applyTheme) { + super.collapse(applyTheme); + if (mSurfaceView != null) mSurfaceView.setVisibility(View.VISIBLE); + } + + @Override + public void expand() { + super.expand(); + if (mSurfaceView != null && mShadowFrame.indexOfChild(mSurfaceView) >= 0) { + mSurfaceView.setVisibility(View.GONE); + mWallpaper.setVisibility(View.INVISIBLE); + } + } + + @Override + public void performClick(boolean clickedOnContent) { + if (clickedOnContent) { + showCustomizeResetLayout(); + } else { + if (isShowingCustomizeResetLayout()) { + hideCustomizeResetLayout(); + } else { + super.performClick(clickedOnContent); + } + } + } + + @Override + public void setCurrentTheme(Map currentTheme, + MutableLong currentWallpaperComponentId) { + super.setCurrentTheme(currentTheme, currentWallpaperComponentId); + for (String key : currentTheme.keySet()) { + mSelectedComponentsMap.put(key, currentTheme.get(key)); + } + mSelectedWallpaperComponentId = currentWallpaperComponentId.value; + } + + @Override + public boolean componentsChanged() { + // If an external wallpaper/ls are set then something changed! + if (mExternalWallpaperUri != null || mExternalLockscreenUri != null) return true; + + for (String key : mSelectedComponentsMap.keySet()) { + String current = mCurrentTheme.get(key); + if (current == null || !current.equals(mSelectedComponentsMap.get(key))) { + return true; + } + if (ThemesColumns.MODIFIES_LAUNCHER.equals(key) && + mCurrentWallpaperComponentId.value != mSelectedWallpaperComponentId) { + return true; + } + } + return false; + } + + @Override + protected void applyThemeWhenPopulated(String pkgName, List components) { + super.applyThemeWhenPopulated(pkgName, components); + populateComponentsToApply(pkgName, components); + } + + private void populateComponentsToApply(String pkgName, List components) { + String selection = ThemesColumns.PKG_NAME + "=?"; + String[] selectionArgs = { pkgName }; + Cursor c = getActivity().getContentResolver().query(ThemesColumns.CONTENT_URI, + null, selection, selectionArgs, null); + if (c != null) { + if (c.getCount() > 0 && c.moveToFirst()) { + mSelectedComponentsMap.clear(); + if (c.getInt(c.getColumnIndex(ThemesColumns.MODIFIES_ALARMS)) == 1) { + mSelectedComponentsMap.put(ThemesColumns.MODIFIES_ALARMS, pkgName); + } + if (c.getInt(c.getColumnIndex(ThemesColumns.MODIFIES_BOOT_ANIM)) == 1) { + mSelectedComponentsMap.put(ThemesColumns.MODIFIES_BOOT_ANIM, pkgName); + } + if (c.getInt(c.getColumnIndex(ThemesColumns.MODIFIES_FONTS)) == 1) { + mSelectedComponentsMap.put(ThemesColumns.MODIFIES_FONTS, pkgName); + } + if (c.getInt(c.getColumnIndex(ThemesColumns.MODIFIES_ICONS)) == 1) { + mSelectedComponentsMap.put(ThemesColumns.MODIFIES_ICONS, pkgName); + } + if (c.getInt(c.getColumnIndex(ThemesColumns.MODIFIES_LAUNCHER)) == 1) { + mSelectedComponentsMap.put(ThemesColumns.MODIFIES_LAUNCHER, pkgName); + } + if (c.getInt(c.getColumnIndex(ThemesColumns.MODIFIES_LOCKSCREEN)) == 1) { + mSelectedComponentsMap.put(ThemesColumns.MODIFIES_LOCKSCREEN, pkgName); + } + if (c.getInt(c.getColumnIndex(ThemesColumns.MODIFIES_NAVIGATION_BAR)) == 1) { + mSelectedComponentsMap.put(ThemesColumns.MODIFIES_NAVIGATION_BAR, pkgName); + } + if (c.getInt(c.getColumnIndex(ThemesColumns.MODIFIES_NOTIFICATIONS)) == 1) { + mSelectedComponentsMap.put(ThemesColumns.MODIFIES_NOTIFICATIONS, pkgName); + } + if (c.getInt(c.getColumnIndex(ThemesColumns.MODIFIES_OVERLAYS)) == 1) { + mSelectedComponentsMap.put(ThemesColumns.MODIFIES_OVERLAYS, pkgName); + } + if (c.getInt(c.getColumnIndex(ThemesColumns.MODIFIES_RINGTONES)) == 1) { + mSelectedComponentsMap.put(ThemesColumns.MODIFIES_RINGTONES, pkgName); + } + if (c.getInt(c.getColumnIndex(ThemesColumns.MODIFIES_STATUS_BAR)) == 1) { + mSelectedComponentsMap.put(ThemesColumns.MODIFIES_STATUS_BAR, pkgName); + } + if (c.getInt(c.getColumnIndex(ThemesColumns.MODIFIES_LIVE_LOCK_SCREEN)) == 1) { + mSelectedComponentsMap.put(ThemesColumns.MODIFIES_LIVE_LOCK_SCREEN, pkgName); + } + } + c.close(); + } + + // strip out any components that are not in the components list + if (components != null) { + Iterator> iterator = + mSelectedComponentsMap.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + if (!components.contains(entry.getKey())) { + iterator.remove(); + } + } + } + } + + private void loadComponentsToApply() { + for (String component : mSelectedComponentsMap.keySet()) { + loadComponentFromPackage(mSelectedComponentsMap.get(component), component, + mSelectedWallpaperComponentId); + } + } + + private BroadcastReceiver mWallpaperChangeReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + // only update if we are the current visible fragment or if there is no theme + // being applied. + ThemeManager tm = getThemeManager(); + if (!tm.isThemeApplying() || getUserVisibleHint()) { + final WallpaperManager wm = WallpaperManager.getInstance(context); + if (wm.getWallpaperInfo() != null) { + addSurfaceView(mSurfaceView); + } else { + removeSurfaceView(mSurfaceView); + } + + Drawable wp = context == null ? null : wm.getDrawable(); + if (wp != null) { + mWallpaper.setImageDrawable(wp); + mWallpaperCard.setWallpaper(wp); + } + } + } + }; + + private void setCustomized(boolean customized) { + mReset.setVisibility(customized ? View.VISIBLE : View.GONE); + mThemeTagLayout.setCustomizedTagEnabled(customized); + } + + @Override + public Loader onCreateLoader(int id, Bundle args) { + switch (id) { + case LOADER_ID_ALL: + if (args != null) { + String pkgName = args.getString(ARG_PACKAGE_NAME); + if (pkgName != null) { + return super.onCreateLoader(id, args); + } + } + return CursorLoaderHelper.myThemeFragmentCursorLoader(getActivity(), id); + default: + // Only LOADER_ID_ALL differs for MyThemeFragment + return super.onCreateLoader(id, args); + } + } + + @Override + public void onLoadFinished(Loader loader, Cursor c) { + super.onLoadFinished(loader, c); + // if the theme is resetting, we need to apply these changes now that the supported + // theme components have been properly set. + if (loader.getId() == LOADER_ID_ALL) { + if (mThemeResetting) { + applyTheme(); + } else if (mApplyThemeOnPopulated) { + loadComponentsToApply(); + applyTheme(); + } else if (mSelectedComponentsMap.size() == 0) { + //Re-populates selected components with current theme. Why? + //We got here because the cursor was reloaded after the user pressed back and no + //changes were applied, causing the selected components map to be wiped out + mSelectedComponentsMap.putAll(mCurrentTheme); + } + } + } + + @Override + protected Map fillMissingComponentsWithDefault( + Map originalMap) { + // Only the ThemeFragment should be altering this, for the MyThemeFragment this is not + // desirable as it changes components the user did not even touch. + return originalMap; + } + + @Override + protected ThemeChangeRequest getThemeChangeRequestForComponents( + Map componentMap) { + return getThemeChangeRequestForComponents(componentMap, RequestType.USER_REQUEST_MIXNMATCH); + } + + @Override + protected Map getComponentsToApply() { + Map componentsToApply = mThemeResetting + ? getEmptyComponentsMap() + : new HashMap(); + if (mThemeResetting) { + final String pkgName = getThemePackageName(); + for (String component : mBaseThemeSupportedComponents) { + componentsToApply.put(component, pkgName); + } + } else { + // Only apply components that actually changed + for (String component : mSelectedComponentsMap.keySet()) { + String currentPkg = mCurrentTheme.get(component); + String selectedPkg = mSelectedComponentsMap.get(component); + if (currentPkg == null || mThemeResetting || !currentPkg.equals(selectedPkg) || + mCurrentWallpaperComponentId.value != mSelectedWallpaperComponentId) { + componentsToApply.put(component, selectedPkg); + } + } + if (mExternalLockscreenUri != null) { + if (mCurrentTheme.containsKey(ThemesColumns.MODIFIES_LIVE_LOCK_SCREEN)) { + componentsToApply.put(ThemesColumns.MODIFIES_LIVE_LOCK_SCREEN, LOCKSCREEN_NONE); + } + if (mCurrentTheme.containsKey(ThemesColumns.MODIFIES_LOCKSCREEN)) { + componentsToApply.put(ThemesColumns.MODIFIES_LOCKSCREEN, LOCKSCREEN_NONE); + } + } + } + return componentsToApply; + } + + @Override + protected void populateSupportedComponents(Cursor c) { + } + + @Override + protected Boolean shouldShowComponentCard(String component) { + return true; + } + + @Override + protected void loadTitle(Cursor c) { + mTitle.setText(mBaseThemeName); + mAuthor.setText(mBaseThemeAuthor); + } + + @Override + protected void loadWallpaper(Cursor c, boolean animate) { + mExternalWallpaperUri = null; + int pkgNameIdx = c.getColumnIndex(ThemesContract.ThemesColumns.PKG_NAME); + if (pkgNameIdx > -1) { + super.loadWallpaper(c, animate); + return; + } + Drawable overlay = null; + if (animate) { + overlay = getOverlayDrawable(mWallpaperCard, true); + } + + int wpIdx = c.getColumnIndex(PreviewColumns.WALLPAPER_PREVIEW); + final Resources res = getResources(); + final Context context = getActivity(); + final WallpaperManager wm = WallpaperManager.getInstance(context); + if (wm.getWallpaperInfo() != null) { + addSurfaceView(mSurfaceView); + } else { + removeSurfaceView(mSurfaceView); + } + + Drawable wp = context == null ? null : wm.getDrawable(); + if (wp == null) { + Bitmap bmp = Utils.loadBitmapBlob(c, wpIdx); + if (bmp != null) wp = new BitmapDrawable(res, bmp); + } + if (wp != null) { + mWallpaper.setImageDrawable(wp); + mWallpaperCard.setWallpaper(wp); + setCardTitle(mWallpaperCard, mCurrentTheme.get(ThemesColumns.MODIFIES_LAUNCHER), + getString(R.string.wallpaper_label)); + } else { + mWallpaperCard.clearWallpaper(); + mWallpaperCard.setEmptyViewEnabled(true); + setAddComponentTitle(mWallpaperCard, getString(R.string.wallpaper_label)); + } + + if (animate) { + animateContentChange(R.id.wallpaper_card, mWallpaperCard, overlay); + } + } + + @Override + protected void loadLockScreen(Cursor c, boolean animate) { + mExternalLockscreenUri = null; + int pkgNameIdx = c.getColumnIndex(ThemesContract.ThemesColumns.PKG_NAME); + if (pkgNameIdx > -1) { + super.loadLockScreen(c, animate); + return; + } + Drawable overlay = null; + if (animate) { + overlay = getOverlayDrawable(mLockScreenCard, true); + } + + //If the current theme includes a lock wallpaper, the WallpaperMgr will + //return a valid Drawable we can display in the card. However, if the user + //picked a LLS, we need to get the path from the provider and manually load the bitmap + int wpIdx = c.getColumnIndex(PreviewColumns.LIVE_LOCK_SCREEN_PREVIEW); + Drawable wp = null; + if (wpIdx >= 0) { + final Resources res = getResources(); + Bitmap bmp = Utils.loadBitmapBlob(c, wpIdx); + if (bmp != null) wp = new BitmapDrawable(res, bmp); + } else { + final Context context = getActivity(); + wp = context == null ? null : + WallpaperManager.getInstance(context).getFastKeyguardDrawable(); + } + if (wp != null) { + mLockScreenCard.setWallpaper(wp); + } else if (!mSelectedComponentsMap.containsKey(ThemesColumns.MODIFIES_LOCKSCREEN)) { + mLockScreenCard.clearWallpaper(); + mLockScreenCard.setEmptyViewEnabled(true); + setAddComponentTitle(mLockScreenCard, getString(R.string.lockscreen_label)); + } + + if (animate) { + animateContentChange(R.id.lockscreen_card, mLockScreenCard, overlay); + } + } + + @Override + protected void loadFont(Cursor c, boolean animate) { + int pkgNameIdx = c.getColumnIndex(ThemesContract.ThemesColumns.PKG_NAME); + if (pkgNameIdx > -1) { + super.loadFont(c, animate); + return; + } + Drawable overlay = null; + if (animate) { + overlay = getOverlayDrawable(mFontPreview, true); + } + setCardTitle(mFontCard, mCurrentTheme.get(ThemesColumns.MODIFIES_FONTS), + getString(R.string.font_label)); + + TypefaceHelperCache cache = TypefaceHelperCache.getInstance(); + ThemedTypefaceHelper helper = cache.getHelperForTheme(getActivity(), + getAppliedFontPackageName()); + mTypefaceNormal = helper.getTypeface(Typeface.NORMAL); + mFontPreview.setTypeface(mTypefaceNormal); + if (animate) { + animateContentChange(R.id.font_preview_container, mFontPreview, overlay); + } + } + + @Override + protected void loadAudible(int type, Cursor c, boolean animate) { + int pkgNameIdx = c.getColumnIndex(ThemesContract.ThemesColumns.PKG_NAME); + if (pkgNameIdx > -1) { + super.loadAudible(type, c, animate); + return; + } + ComponentCardView audibleContainer = null; + ImageView playPause = null; + String modsComponent = ""; + switch (type) { + case RingtoneManager.TYPE_RINGTONE: + audibleContainer = mRingtoneCard; + playPause = mRingtonePlayPause; + modsComponent = ThemesColumns.MODIFIES_RINGTONES; + break; + case RingtoneManager.TYPE_NOTIFICATION: + audibleContainer = mNotificationCard; + playPause = mNotificationPlayPause; + modsComponent = ThemesColumns.MODIFIES_NOTIFICATIONS; + break; + case RingtoneManager.TYPE_ALARM: + audibleContainer = mAlarmCard; + playPause = mAlarmPlayPause; + modsComponent = ThemesColumns.MODIFIES_ALARMS; + break; + } + if (audibleContainer == null) return; + + if (playPause == null) { + playPause = + (ImageView) audibleContainer.findViewById(R.id.play_pause); + } + TextView title = (TextView) audibleContainer.findViewById(R.id.audible_name); + MediaPlayer mp = mMediaPlayers.get(playPause); + if (mp == null) { + mp = new MediaPlayer(); + } + + final Context context = getActivity(); + Ringtone ringtone = null; + try { + Uri ringtoneUri = AudioUtils.loadDefaultAudible(context, type, mp); + if (ringtoneUri != null) ringtone = RingtoneManager.getRingtone(context, ringtoneUri); + } catch (IOException e) { + Log.w(TAG, "Unable to load default sound ", e); + } + + if (ringtone != null) { + title.setText(ringtone.getTitle(context)); + setCardTitle(audibleContainer, mCurrentTheme.get(modsComponent), + getAudibleLabel(type)); + } else { + title.setText(getString(R.string.audible_title_none)); + setAddComponentTitle(audibleContainer, getAudibleLabel(type)); + playPause.setVisibility(View.INVISIBLE); + audibleContainer.setEmptyViewEnabled(true); + } + + playPause.setTag(mp); + mMediaPlayers.put(playPause, mp); + playPause.setOnClickListener(mPlayPauseClickListener); + mp.setOnCompletionListener(mPlayCompletionListener); + } + + @Override + protected void loadStatusBar(Cursor c, boolean animate) { + super.loadStatusBar(c, animate); + setCardTitle(mStatusBarCard, mCurrentTheme.get(ThemesColumns.MODIFIES_STATUS_BAR), + getString(R.string.statusbar_label)); + } + + @Override + protected void loadIcons(Cursor c, boolean animate) { + super.loadIcons(c, animate); + setCardTitle(mIconCard, mCurrentTheme.get(ThemesColumns.MODIFIES_ICONS), + getString(R.string.icon_label)); + } + + @Override + protected void loadNavBar(Cursor c, boolean animate) { + super.loadNavBar(c, animate); + setCardTitle(mNavBarCard, mCurrentTheme.get(ThemesColumns.MODIFIES_NAVIGATION_BAR), + getString(R.string.navbar_label)); + } + + @Override + protected void loadStyle(Cursor c, boolean animate) { + super.loadStyle(c, animate); + setCardTitle(mStyleCard, mCurrentTheme.get(ThemesColumns.MODIFIES_OVERLAYS), + getString(R.string.style_label)); + } + + @Override + protected void loadBootAnimation(Cursor c) { + super.loadBootAnimation(c); + setCardTitle(mBootAnimationCard, mCurrentTheme.get(ThemesColumns.MODIFIES_BOOT_ANIM), + getString(R.string.boot_animation_label)); + } + + @Override + public String getThemePackageName() { + if (mBaseThemePkgName == null) { + // check if the package name is defined in the arguments bundle + Bundle bundle = getArguments(); + if (bundle != null) { + mBaseThemePkgName = bundle.getString(ARG_BASE_THEME_PACKAGE_NAME); + } + } + return mBaseThemePkgName; + } + + private SurfaceView createSurfaceView() { + final Context context = getActivity(); + if (context == null) return null; + + SurfaceView sv = new SurfaceView(context); + final Resources res = context.getResources(); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( + res.getDimensionPixelSize(R.dimen.wallpaper_preview_width), + res.getDimensionPixelSize(R.dimen.theme_preview_height), + Gravity.CENTER_HORIZONTAL); + sv.setLayoutParams(params); + + return sv; + } + + private void addSurfaceView(SurfaceView sv) { + if (mShadowFrame.indexOfChild(mSurfaceView) < 0) { + int idx = mShadowFrame.indexOfChild(mWallpaper); + mShadowFrame.addView(sv, idx + 1); + } + } + + private void removeSurfaceView(SurfaceView sv) { + if (mShadowFrame.indexOfChild(mSurfaceView) >= 0) { + mShadowFrame.removeView(sv); + } + } + + /** + * Populates mBaseThemeSupportedComponents. + * @param pkgName Package name of the base theme used + */ + private void populateBaseThemeSupportedComponents(String pkgName) { + String selection = ThemesColumns.PKG_NAME + "=?"; + String[] selectionArgs = { pkgName }; + Cursor c = getActivity().getContentResolver().query(ThemesColumns.CONTENT_URI, + null, selection, selectionArgs, null); + if (c != null) { + if (c.moveToFirst()) { + List components = ThemeUtils.getAllComponents(); + final String baseThemePackageName = getThemePackageName(); + for (String component : components) { + int pkgIdx = c.getColumnIndex(ThemesColumns.PKG_NAME); + int modifiesCompIdx = c.getColumnIndex(component); + + String pkg = pkgIdx >= 0 ? c.getString(pkgIdx) : null; + boolean supported = (modifiesCompIdx >= 0) && (c.getInt(modifiesCompIdx) == 1); + if (supported && baseThemePackageName.equals(pkg)) { + mBaseThemeSupportedComponents.add(component); + } + } + } + c.close(); + } + } +} diff --git a/src/org/cyanogenmod/theme/chooser2/NewFragmentStatePagerAdapter.java b/src/org/cyanogenmod/theme/chooser2/NewFragmentStatePagerAdapter.java new file mode 100644 index 0000000..e108a76 --- /dev/null +++ b/src/org/cyanogenmod/theme/chooser2/NewFragmentStatePagerAdapter.java @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2016 Cyanogen, Inc. + * Copyright (C) 2016 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cyanogenmod.theme.chooser2; + +import android.os.Bundle; +import android.os.Parcelable; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; +import android.support.v4.view.PagerAdapter; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; + +import java.util.ArrayList; +import java.util.Arrays; + +/** + * Implementation of {@link android.support.v4.view.PagerAdapter} that + * uses a {@link android.support.v4.app.Fragment} to manage each page. This class also handles + * saving and restoring of fragment's state. + * + *

This version of the pager is more useful when there are a large number + * of pages, working more like a list view. When pages are not visible to + * the user, their entire fragment may be destroyed, only keeping the saved + * state of that fragment. This allows the pager to hold on to much less + * memory associated with each visited page as compared to + * {@link android.support.v4.app.FragmentPagerAdapter} at the cost of potentially more overhead when + * switching between pages. + * + *

When using FragmentPagerAdapter the host ViewPager must have a + * valid ID set.

+ * + *

Subclasses only need to implement {@link #getItem(int)} + * and {@link #getCount()} to have a working adapter. + * + *

Here is an example implementation of a pager containing fragments of + * lists: + * + * {@sample development/samples/Support13Demos/src/com/example/android/supportv13/app/FragmentStatePagerSupport.java + * complete} + * + *

The R.layout.fragment_pager resource of the top-level fragment is: + * + * {@sample development/samples/Support13Demos/res/layout/fragment_pager.xml + * complete} + * + *

The R.layout.fragment_pager_list resource containing each + * individual fragment's layout is: + * + * {@sample development/samples/Support13Demos/res/layout/fragment_pager_list.xml + * complete} + */ +public abstract class NewFragmentStatePagerAdapter extends PagerAdapter { + private static final String TAG = NewFragmentStatePagerAdapter.class.getSimpleName(); + private static final boolean DEBUG = false; + + private final FragmentManager mFragmentManager; + private FragmentTransaction mCurTransaction = null; + + private long[] mItemIds = new long[] {}; + private ArrayList mSavedState = new ArrayList(); + private ArrayList mFragments = new ArrayList(); + private Fragment mCurrentPrimaryItem = null; + + public NewFragmentStatePagerAdapter(FragmentManager fm) { + + mFragmentManager = fm; + createIdCache(); + } + + /** + * Return the Fragment associated with a specified position. + */ + public abstract Fragment getItem(int position); + + /** + * Return a unique identifier for the item at the given position. + */ + public abstract long getItemId(int position); + + @Override + public void startUpdate(ViewGroup container) { + } + + private void checkForIdChanges() { + long[] newItemIds = new long[getCount()]; + for (int i = 0; i < newItemIds.length; i++) { + newItemIds[i] = getItemId(i); + } + + if (!Arrays.equals(mItemIds, newItemIds)) { + ArrayList newSavedState = new ArrayList(); + ArrayList newFragments = new ArrayList(); + + for (int oldPosition = 0; oldPosition < mItemIds.length; oldPosition++) { + int newPosition = POSITION_NONE; + for (int i = 0; i < newItemIds.length; i++) { + if (mItemIds[oldPosition] == newItemIds[i]) { + newPosition = i; + break; + } + } + if (newPosition >= 0) { + if (oldPosition < mSavedState.size()) { + Fragment.SavedState savedState = mSavedState.get(oldPosition); + if (savedState != null) { + while (newSavedState.size() <= newPosition) { + newSavedState.add(null); + } + newSavedState.set(newPosition, savedState); + } + } + if (oldPosition < mFragments.size()) { + Fragment fragment = mFragments.get(oldPosition); + if (fragment != null) { + while (newFragments.size() <= newPosition) { + newFragments.add(null); + } + newFragments.set(newPosition, fragment); + } + } + } + } + + mItemIds = newItemIds; + mSavedState = newSavedState; + mFragments = newFragments; + } + } + + @Override + public void notifyDataSetChanged() { + checkForIdChanges(); + + super.notifyDataSetChanged(); + } + + /** + * Create the initial set of item IDs. Run this after you have set your adapter data. + */ + public void createIdCache() { + // If we have already stored ids, don't overwrite them + if (mItemIds.length == 0) { + // getCount might have overhead, so run it as late as possible + final int count = getCount(); + if (count > 0) { + mItemIds = new long[count]; + for (int i = 0; i < count; i++) { + mItemIds[i] = getItemId(i); + } + } + } + } + + @Override + public Object instantiateItem(ViewGroup container, int position) { + + createIdCache(); + + // If we already have this item instantiated, there is nothing + // to do. This can happen when we are restoring the entire pager + // from its saved state, where the fragment manager has already + // taken care of restoring the fragments we previously had instantiated. + if (mFragments.size() > position) { + Fragment f = mFragments.get(position); + if (f != null) { + return f; + } + } + + if (mCurTransaction == null) { + mCurTransaction = mFragmentManager.beginTransaction(); + } + + Fragment fragment = getItem(position); + if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment); + if (mSavedState.size() > position) { + Fragment.SavedState fss = mSavedState.get(position); + if (fss != null) { + fragment.setInitialSavedState(fss); + } + } + while (mFragments.size() <= position) { + mFragments.add(null); + } + fragment.setMenuVisibility(false); + fragment.setUserVisibleHint(false); + mFragments.set(position, fragment); + mCurTransaction.add(container.getId(), fragment); + + return fragment; + } + + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + Fragment fragment = (Fragment)object; + + if (mCurTransaction == null) { + mCurTransaction = mFragmentManager.beginTransaction(); + } + if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object + + " v=" + ((Fragment)object).getView()); + while (mSavedState.size() <= position) { + mSavedState.add(null); + } + mSavedState.set(position, mFragmentManager.saveFragmentInstanceState(fragment)); + + // Only set the position to null if the fragment being removed is at "position" + // We do this because checkForIdChanges updates the mFragments list and if a fragment + // was removed then the fragment at "position" is not the fragment that was removed. + if (position < mFragments.size() && fragment == mFragments.get(position)) { + mFragments.set(position, null); + } + mCurTransaction.remove(fragment); + } + + @Override + public void setPrimaryItem(ViewGroup container, int position, Object object) { + Fragment fragment = (Fragment)object; + if (fragment != mCurrentPrimaryItem) { + if (mCurrentPrimaryItem != null) { + mCurrentPrimaryItem.setMenuVisibility(false); + mCurrentPrimaryItem.setUserVisibleHint(false); + } + if (fragment != null) { + fragment.setMenuVisibility(true); + fragment.setUserVisibleHint(true); + } + mCurrentPrimaryItem = fragment; + } + } + + @Override + public void finishUpdate(ViewGroup container) { + if (mCurTransaction != null) { + mCurTransaction.commitAllowingStateLoss(); + mCurTransaction = null; + mFragmentManager.executePendingTransactions(); + } + } + + @Override + public boolean isViewFromObject(View view, Object object) { + return ((Fragment)object).getView() == view; + } + + @Override + public Parcelable saveState() { + Bundle state = null; + + mItemIds = new long[getCount()]; + for (int i = 0; i < mItemIds.length; i++) { + mItemIds[i] = getItemId(i); + } + if (mSavedState.size() > 0) { + state = new Bundle(); + + if (mItemIds.length > 0) { + state.putLongArray("itemids", mItemIds); + } + + Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()]; + mSavedState.toArray(fss); + state.putParcelableArray("states", fss); + } + for (int i=0; i keys = bundle.keySet(); + for (String key: keys) { + if (key.startsWith("f")) { + int index = Integer.parseInt(key.substring(1)); + Fragment f = mFragmentManager.getFragment(bundle, key); + if (f != null) { + while (mFragments.size() <= index) { + mFragments.add(null); + } + f.setMenuVisibility(false); + mFragments.set(index, f); + } else { + Log.w(TAG, "Bad fragment at key " + key); + } + } + } + checkForIdChanges(); + } + } +} \ No newline at end of file diff --git a/src/org/cyanogenmod/theme/chooser2/NotificationHijackingService.java b/src/org/cyanogenmod/theme/chooser2/NotificationHijackingService.java new file mode 100644 index 0000000..cee1b4f --- /dev/null +++ b/src/org/cyanogenmod/theme/chooser2/NotificationHijackingService.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2016 Cyanogen, Inc. + * Copyright (C) 2016 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cyanogenmod.theme.chooser2; + +import android.app.PendingIntent; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.provider.Settings; +import android.service.notification.NotificationListenerService; +import android.service.notification.StatusBarNotification; +import android.text.TextUtils; + +public class NotificationHijackingService extends NotificationListenerService { + private static final String TAG = NotificationHijackingService.class.getName(); + private static final String GOOGLE_PLAY_PACKAGE_NAME = "com.android.vending"; + private static final String ACTION_INSTALLED = + "com.android.vending.SUCCESSFULLY_INSTALLED_CLICKED"; + private static final String EXTRA_PACKAGE_NAME = "package_name"; + + @Override + public void onNotificationPosted(StatusBarNotification sbn) { + if (GOOGLE_PLAY_PACKAGE_NAME.equals(sbn.getPackageName())) { + PendingIntent contentIntent = sbn.getNotification().contentIntent; + if (contentIntent == null) return; + Intent intent = contentIntent.getIntent(); + if (intent == null) return; + String action = intent.getAction(); + if (ACTION_INSTALLED.equals(action)) { + String pkgName = intent.getStringExtra(EXTRA_PACKAGE_NAME); + try { + PackageInfo pi = getPackageManager().getPackageInfo(pkgName, 0); + if (pi != null) { + if (pi.themeInfo != null) { + cancelNotification(sbn.getKey()); + } + } + } catch (PackageManager.NameNotFoundException e) { + } + } + } + } + + @Override + public void onNotificationRemoved(StatusBarNotification sbn) { + } + + // ensure that this notification listener is enabled. + // the service watches for google play notifications + public static void ensureEnabled(Context context) { + ComponentName me = new ComponentName(context, NotificationHijackingService.class); + String meFlattened = me.flattenToString(); + + String existingListeners = Settings.Secure.getString(context.getContentResolver(), + Settings.Secure.ENABLED_NOTIFICATION_LISTENERS); + + if (!TextUtils.isEmpty(existingListeners)) { + if (existingListeners.contains(meFlattened)) { + return; + } else { + existingListeners += ":" + meFlattened; + } + } else { + existingListeners = meFlattened; + } + + Settings.Secure.putString(context.getContentResolver(), + Settings.Secure.ENABLED_NOTIFICATION_LISTENERS, + existingListeners); + } +} diff --git a/src/org/cyanogenmod/theme/chooser2/PagerContainer.java b/src/org/cyanogenmod/theme/chooser2/PagerContainer.java new file mode 100644 index 0000000..a4349bd --- /dev/null +++ b/src/org/cyanogenmod/theme/chooser2/PagerContainer.java @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2016 Cyanogen, Inc. + * Copyright (C) 2016 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cyanogenmod.theme.chooser2; + +import android.content.Context; +import android.graphics.Point; +import android.support.v4.view.ThemeViewPager; +import android.support.v4.view.ViewPager; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewTreeObserver; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.DecelerateInterpolator; +import android.widget.FrameLayout; +import android.widget.LinearLayout; + +/** + * PagerContainer: A layout that displays a ViewPager with its children that are outside + * the typical pager bounds. + */ +public class PagerContainer extends FrameLayout implements ViewPager.OnPageChangeListener { + private static final int ANIMATE_OUT_DURATION = 300; + private static final int ANIMATE_OUT_INTERPOLATE_FACTOR = 1; + private static final int ANIMATE_IN_DURATION = 300; + private static final int ANIMATE_IN_INTERPOLATE_FACTOR = 2; + + private ThemeViewPager mPager; + private Point mCenter = new Point(); + private Point mInitialTouch = new Point(); + private int mCollapsedHeight; + private boolean mIsAnimating = false; + + boolean mNeedsRedraw = false; + + public PagerContainer(Context context) { + this(context, null, 0); + } + + public PagerContainer(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public PagerContainer(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + mCollapsedHeight = generateLayoutParams(attrs).height; + + //Disable clipping of children so non-selected pages are visible + setClipChildren(false); + } + + @Override + protected void onFinishInflate() { + try { + mPager = (ThemeViewPager) getChildAt(0); + mPager.setOnPageChangeListener(this); + } catch (Exception e) { + throw new IllegalStateException("The root child of PagerContainer must be a ViewPager"); + } + } + + public ThemeViewPager getViewPager() { + return mPager; + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + mCenter.x = w / 2; + mCenter.y = h / 2; + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + if (mIsAnimating) return true; + return super.onInterceptTouchEvent(ev); + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + // Do not allow touch events to propagate if we are animating + if (mIsAnimating) return true; + + //We capture any touches not already handled by the ViewPager + // to implement scrolling from a touch outside the pager bounds. + switch (ev.getAction()) { + case MotionEvent.ACTION_DOWN: + mInitialTouch.x = (int)ev.getX(); + mInitialTouch.y = (int)ev.getY(); + default: + ev.offsetLocation(mCenter.x - mInitialTouch.x, mCenter.y - mInitialTouch.y); + break; + } + + return mPager.dispatchTouchEvent(ev); + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + //Force the container to redraw on scrolling. + //Without this the outer pages render initially and then stay static + if (mNeedsRedraw) invalidate(); + } + + @Override + public void onPageSelected(int position) { } + + @Override + public void onPageScrollStateChanged(int state) { + mNeedsRedraw = (state != ThemeViewPager.SCROLL_STATE_IDLE); + } + + public void setIsAnimating(boolean isAnimating) { + mIsAnimating = isAnimating; + } + + public void expand() { + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(getLayoutParams()); + params.height = LinearLayout.LayoutParams.MATCH_PARENT; + setLayoutParams(params); + + mPager.setExpanded(true); + + final int current = mPager.getCurrentItem(); + final int prevY = (int) getY(); + + //Since our viewpager's width is changing to fill the screen + //we must start the left/right children of the current page inwards on first draw + final int lChildPrevXf; + final int rChildPrevXf; + + if (current != 0) { + final View lchild = mPager.getViewForPosition(current - 1); + lChildPrevXf = (int) lchild.getX(); + } else { + lChildPrevXf = 0; + } + + if (current < mPager.getAdapter().getCount() - 1) { + View rchild = mPager.getViewForPosition(current + 1); + rChildPrevXf = (int) rchild.getX(); + } else { + rChildPrevXf = 0; + } + + + final ViewTreeObserver observer = mPager.getViewTreeObserver(); + observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { + public boolean onPreDraw() { + observer.removeOnPreDrawListener(this); + if (current != 0) { + View lchild = mPager.getViewForPosition(current - 1); + lchild.setTranslationY(prevY - getY()); + lchild.setX(lChildPrevXf); + animateChildOut(lchild, -getWidth()); + } + + if (current < mPager.getAdapter().getCount() - 1) { + View rchild = mPager.getViewForPosition(current + 1); + rchild.setX(rChildPrevXf); + rchild.setTranslationY(prevY - getY()); + animateChildOut(rchild, getWidth()); + } + return false; + } + }); + } + + public void collapse() { + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(getLayoutParams()); + params.height = mCollapsedHeight; + setLayoutParams(params); + + mPager.setExpanded(false); + int current = mPager.getCurrentItem(); + final int prevY = (int) getY(); + + if (current != 0) { + View lchild = mPager.getViewForPosition(current - 1); + lchild.setTranslationY(0); + animateChildIn(lchild); + } + + if (current < mPager.getAdapter().getCount() - 1) { + View rchild = mPager.getViewForPosition(current + 1); + rchild.setTranslationY(0); + animateChildIn(rchild); + } + } + + private void animateChildOut(final View v, float endX) { + v.animate() + .translationX(endX) + .setDuration(ANIMATE_OUT_DURATION) + .setInterpolator(new AccelerateInterpolator(ANIMATE_OUT_INTERPOLATE_FACTOR)); + } + + private void animateChildIn(final View v) { + v.animate() + .translationX(0) + .setDuration(ANIMATE_IN_DURATION) + .setInterpolator(new DecelerateInterpolator(ANIMATE_IN_INTERPOLATE_FACTOR)); + } +} \ No newline at end of file diff --git a/src/org/cyanogenmod/theme/chooser2/ThemeFragment.java b/src/org/cyanogenmod/theme/chooser2/ThemeFragment.java new file mode 100644 index 0000000..6a73598 --- /dev/null +++ b/src/org/cyanogenmod/theme/chooser2/ThemeFragment.java @@ -0,0 +1,3059 @@ +/* + * Copyright (C) 2016 Cyanogen, Inc. + * Copyright (C) 2016 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cyanogenmod.theme.chooser2; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.IntEvaluator; +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; +import android.app.Activity; +import android.app.AlertDialog; +import android.app.WallpaperManager; +import android.content.ActivityNotFoundException; +import android.content.ComponentName; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.res.AssetManager; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.content.res.ThemeConfig; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.Bitmap.Config; +import android.graphics.Color; +import android.graphics.Point; +import android.graphics.Rect; +import android.graphics.Typeface; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.NinePatchDrawable; +import android.media.MediaPlayer; +import android.media.RingtoneManager; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Build; +import android.os.Bundle; +import android.os.FileUtils; +import android.os.Handler; +import android.support.v4.app.Fragment; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.Loader; +import android.text.TextUtils; +import android.util.Log; +import android.util.MutableLong; +import android.util.SparseArray; +import android.view.Display; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewPropertyAnimator; +import android.view.ViewTreeObserver; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.Animation; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.ScaleAnimation; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.PopupMenu; +import android.widget.ProgressBar; +import android.widget.Space; +import android.widget.TextView; +import android.widget.Toast; + +import org.cyanogenmod.theme.chooser2.ComponentSelector.OnItemClickedListener; +import org.cyanogenmod.theme.util.AudioUtils; +import org.cyanogenmod.theme.util.BootAnimationHelper; +import org.cyanogenmod.theme.util.CursorLoaderHelper; +import org.cyanogenmod.theme.util.IconPreviewHelper; +import org.cyanogenmod.theme.util.PreferenceUtils; +import org.cyanogenmod.theme.util.ThemedTypefaceHelper; +import org.cyanogenmod.theme.util.TypefaceHelperCache; +import org.cyanogenmod.theme.util.Utils; +import org.cyanogenmod.theme.util.WallpaperUtils; +import org.cyanogenmod.theme.widget.BootAniImageView; +import org.cyanogenmod.theme.widget.ConfirmCancelOverlay; +import org.cyanogenmod.theme.widget.LockableScrollView; +import org.cyanogenmod.theme.widget.ThemeTagLayout; + +import cyanogenmod.app.ThemeVersion; +import cyanogenmod.providers.CMSettings; +import cyanogenmod.providers.ThemesContract.PreviewColumns; +import cyanogenmod.providers.ThemesContract.ThemesColumns; +import cyanogenmod.themes.ThemeChangeRequest; +import cyanogenmod.themes.ThemeChangeRequest.RequestType; +import cyanogenmod.themes.ThemeManager; + +import org.cyanogenmod.internal.util.CmLockPatternUtils; +import org.cyanogenmod.internal.util.ThemeUtils; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.security.InvalidParameterException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.zip.ZipFile; + +import static android.Manifest.permission.READ_EXTERNAL_STORAGE; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; + +import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_ALARMS; +import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_BOOT_ANIM; +import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_LAUNCHER; +import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_LIVE_LOCK_SCREEN; +import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_LOCKSCREEN; +import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_NOTIFICATIONS; +import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_OVERLAYS; +import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_RINGTONES; +import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_STATUS_BAR; +import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_NAVIGATION_BAR; +import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_ICONS; +import static cyanogenmod.providers.ThemesContract.ThemesColumns.MODIFIES_FONTS; + +import static org.cyanogenmod.theme.chooser2.ComponentSelector.DEFAULT_COMPONENT_ID; + +import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_INVALID; +import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_ALL; +import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_STATUS_BAR; +import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_FONT; +import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_ICONS; +import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_WALLPAPER; +import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_NAVIGATION_BAR; +import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_LOCKSCREEN; +import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_STYLE; +import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_BOOT_ANIMATION; +import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_RINGTONE; +import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_NOTIFICATION; +import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_ALARM; +import static org.cyanogenmod.theme.util.CursorLoaderHelper.LOADER_ID_LIVE_LOCK_SCREEN; + +import static cyanogenmod.providers.CMSettings.Secure.LIVE_LOCK_SCREEN_ENABLED; + +import static org.cyanogenmod.internal.util.ThemeUtils.SYSTEM_TARGET_API; + +public class ThemeFragment extends Fragment implements LoaderManager.LoaderCallbacks, + ThemeManager.ThemeChangeListener, ThemeManager.ThemeProcessingListener { + private static final String TAG = ThemeFragment.class.getSimpleName(); + + public static final int ANIMATE_START_DELAY = 200; + public static final int ANIMATE_DURATION = 300; + public static final int ANIMATE_INTERPOLATE_FACTOR = 3; + public static final int ANIMATE_COMPONENT_CHANGE_DURATION = 200; + public static final int ANIMATE_COMPONENT_ICON_DELAY = 50; + public static final int ANIMATE_PROGRESS_IN_DURATION = 500; + public static final int ANIMATE_TITLE_OUT_DURATION = 400; + public static final int ANIMATE_PROGRESS_OUT_DURATION = 400; + public static final int ANIMATE_TITLE_IN_DURATION = 500; + public static final int ANIMATE_APPLY_LAYOUT_DURATION = 300; + + public static final String CURRENTLY_APPLIED_THEME = "currently_applied_theme"; + + private static final ComponentName COMPONENT_DIALER = + new ComponentName("com.android.dialer", "com.android.dialer.DialtactsActivity"); + private static final ComponentName COMPONENT_DIALERNEXT = + new ComponentName("com.cyngn.dialer", "com.android.dialer.DialtactsActivity"); + private static final ComponentName COMPONENT_MESSAGING = + new ComponentName("com.android.mms", "com.android.mms.ui.ConversationList"); + private static final ComponentName COMPONENT_CAMERANEXT = + new ComponentName("com.cyngn.cameranext", "com.android.camera.CameraLauncher"); + private static final ComponentName COMPONENT_CAMERA = + new ComponentName("com.android.camera2", "com.android.camera.CameraActivity"); + private static final ComponentName COMPONENT_BROWSER = + new ComponentName("com.android.browser", "com.android.browser.BrowserActivity"); + private static final ComponentName COMPONENT_SETTINGS = + new ComponentName("com.android.settings", "com.android.settings.Settings"); + private static final ComponentName COMPONENT_CALENDAR = + new ComponentName("com.android.calendar", "com.android.calendar.AllInOneActivity"); + private static final ComponentName COMPONENT_GALERY = + new ComponentName("com.android.gallery3d", "com.android.gallery3d.app.GalleryActivity"); + + private static final String CAMERA_NEXT_PACKAGE = "com.cyngn.cameranext"; + private static final String DIALER_NEXT_PACKAGE = "com.cyngn.dialer"; + + private static final int ADDITIONAL_CONTENT_SPACE_ID = 123456; + private static final long SLIDE_CONTENT_ANIM_DURATION = 300L; + private static final long LOCK_SCREEN_CARD_SCROLL_ANIMATION_DURATION = 400; + private static final long SHOW_LOCK_SCREEN_CARD_DELAY = 500; + + private static final int DEFAULT_WIFI_MARGIN = 0; + private static final int DEFAULT_CLOCK_COLOR = Color.WHITE; + + protected static final String WALLPAPER_NONE = ""; + protected static final String LOCKSCREEN_NONE = ""; + + protected static final String ARG_PACKAGE_NAME = "pkgName"; + protected static final String ARG_COMPONENT_ID = "cmpntId"; + protected static final String ARG_SKIP_LOADING_ANIM = "skipLoadingAnim"; + protected static final String ARG_ANIMATE_TO_LOCK_SCREEN_CARD = "animateToLockScreenCard"; + + private static final String LLS_PACKAGE_NAME = "com.cyngn.lockscreen.live"; + private static final String LLS_PROVIDER_NAME = + "com.cyngn.lockscreen.live.LockScreenProviderService"; + + private static final int PERMISSION_REQUEST = 100; + + protected static ComponentName[] sIconComponents; + + protected static TypefaceHelperCache sTypefaceHelperCache; + + /** + * Maps the card's resource ID to a theme component + */ + private final SparseArray mCardIdsToComponentTypes = new SparseArray(); + + protected String mPkgName; + protected Typeface mTypefaceNormal; + protected int mBatteryStyle; + + protected LockableScrollView mScrollView; + protected ViewGroup mScrollContent; + protected ViewGroup mPreviewContent; // Contains icons, font, nav/status etc. Not wallpaper + protected View mLoadingView; + + //Status Bar Views + protected ComponentCardView mStatusBarCard; + protected ImageView mBluetooth; + protected ImageView mWifi; + protected ImageView mSignal; + protected ImageView mBattery; + protected TextView mClock; + + // Other Misc Preview Views + protected FrameLayout mShadowFrame; + protected ImageView mWallpaper; + protected ViewGroup mStatusBar; + protected TextView mFontPreview; + protected ComponentCardView mStyleCard; + protected ComponentCardView mFontCard; + protected ComponentCardView mIconCard; + protected ComponentCardView mBootAnimationCard; + protected BootAniImageView mBootAnimation; + + // Nav Bar Views + protected ComponentCardView mNavBarCard; + protected ViewGroup mNavBar; + protected ImageView mBackButton; + protected ImageView mHomeButton; + protected ImageView mRecentButton; + + // Title Card Views + protected ViewGroup mTitleCard; + protected ViewGroup mTitleLayout; + protected TextView mTitle; + protected TextView mAuthor; + protected ImageView mCustomize; + protected ImageView mOverflow; + protected ImageView mDelete; + protected ImageView mReset; + protected ProgressBar mProgress; + + // Additional Card Views + protected LinearLayout mAdditionalCards; + protected WallpaperCardView mWallpaperCard; + protected WallpaperCardView mLockScreenCard; + + // Style views + protected ImageView mStylePreview; + + // Sound cards + protected ComponentCardView mRingtoneCard; + protected ImageView mRingtonePlayPause; + protected ComponentCardView mNotificationCard; + protected ImageView mNotificationPlayPause; + protected ComponentCardView mAlarmCard; + protected ImageView mAlarmPlayPause; + protected Map mMediaPlayers; + + protected Handler mHandler; + + protected int mActiveCardId = -1; + protected ComponentSelector mSelector; + // Supported components for the theme this fragment represents + protected Map mSelectedComponentsMap = new HashMap(); + protected Long mSelectedWallpaperComponentId; + // Current system theme configuration as component -> pkgName + protected Map mCurrentTheme = new HashMap(); + protected MutableLong mCurrentWallpaperComponentId = new MutableLong(DEFAULT_COMPONENT_ID); + // Set of components available in the base theme + protected HashSet mBaseThemeSupportedComponents = new HashSet(); + protected Cursor mCurrentCursor; + protected int mCurrentLoaderId; + protected boolean mThemeResetting; + protected boolean mSkipLoadingAnim; + + // Accept/Cancel overlay + protected ConfirmCancelOverlay mConfirmCancelOverlay; + + // Customize/Reset theme layout + protected View mCustomizeResetLayout; + protected View mResetButton; + protected View mCustomizeButton; + protected View mDismissButton; + + // Processing theme layout + protected View mProcessingThemeLayout; + + protected ThemeTagLayout mThemeTagLayout; + + protected View mClickableView; + protected String mBaseThemePkgName; + + protected Uri mExternalWallpaperUri; + protected Uri mExternalLockscreenUri; + + protected boolean mExpanded; + protected boolean mProcessingResources; + protected boolean mApplyThemeOnPopulated; + + protected boolean mIsLegacyTheme; + + private Runnable mAfterPermissionGrantedRunnable; + + private static final int mThemeVersion = ThemeVersion.getVersion(); + + protected boolean mShowLockScreenSelectorAfterContentLoaded; + + protected enum CustomizeResetAction { + Customize, + Reset, + Dismiss + } + + static ThemeFragment newInstance(String pkgName, boolean skipLoadingAnim) { + ThemeFragment f = new ThemeFragment(); + Bundle args = new Bundle(); + args.putString(ARG_PACKAGE_NAME, pkgName); + args.putBoolean(ARG_SKIP_LOADING_ANIM, skipLoadingAnim); + args.putLong(ARG_COMPONENT_ID, DEFAULT_COMPONENT_ID); + f.setArguments(args); + return f; + } + + /** + * When creating, retrieve this instance's number from its arguments. + */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + final Context context = getActivity(); + mPkgName = getArguments().getString(ARG_PACKAGE_NAME); + mSkipLoadingAnim = getArguments().getBoolean(ARG_SKIP_LOADING_ANIM); + // TODO: Load from settings once available + mBatteryStyle = 0;/*Settings.System.getInt(context.getContentResolver(), + Settings.System.STATUS_BAR_BATTERY_STYLE, 0);*/ + + getIconComponents(context); + if (sTypefaceHelperCache == null) { + sTypefaceHelperCache = TypefaceHelperCache.getInstance(); + } + ThemedTypefaceHelper helper = sTypefaceHelperCache.getHelperForTheme(context, mPkgName); + mTypefaceNormal = helper.getTypeface(Typeface.NORMAL); + + mHandler = new Handler(); + + mCardIdsToComponentTypes.put(R.id.status_bar_container, MODIFIES_STATUS_BAR); + mCardIdsToComponentTypes.put(R.id.font_preview_container, MODIFIES_FONTS); + mCardIdsToComponentTypes.put(R.id.icon_container, MODIFIES_ICONS); + mCardIdsToComponentTypes.put(R.id.navigation_bar_container, MODIFIES_NAVIGATION_BAR); + mCardIdsToComponentTypes.put(R.id.wallpaper_card, MODIFIES_LAUNCHER); + mCardIdsToComponentTypes.put(R.id.lockscreen_card, MODIFIES_LOCKSCREEN); + mCardIdsToComponentTypes.put(R.id.style_card, MODIFIES_OVERLAYS); + mCardIdsToComponentTypes.put(R.id.bootani_preview_container, MODIFIES_BOOT_ANIM); + mCardIdsToComponentTypes.put(R.id.ringtone_preview_container, MODIFIES_RINGTONES); + mCardIdsToComponentTypes.put(R.id.notification_preview_container, MODIFIES_NOTIFICATIONS); + mCardIdsToComponentTypes.put(R.id.alarm_preview_container, MODIFIES_ALARMS); + + mMediaPlayers = new HashMap(3); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View v = inflater.inflate(R.layout.fragment_pager_list, container, false); + + mScrollView = (LockableScrollView) v.findViewById(android.R.id.list); + mScrollView.setScrollingEnabled(false); + mScrollContent = (ViewGroup) mScrollView.getChildAt(0); + mPreviewContent = (ViewGroup) v.findViewById(R.id.preview_container); + mLoadingView = v.findViewById(R.id.loading_view); + mThemeTagLayout = (ThemeTagLayout) v.findViewById(R.id.tag_layout); + + // Status Bar + mStatusBarCard = (ComponentCardView) v.findViewById(R.id.status_bar_container); + mStatusBar = (ViewGroup) v.findViewById(R.id.status_bar); + mBluetooth = (ImageView) v.findViewById(R.id.bluetooth_icon); + mWifi = (ImageView) v.findViewById(R.id.wifi_icon); + mSignal = (ImageView) v.findViewById(R.id.signal_icon); + mBattery = (ImageView) v.findViewById(R.id.battery); + mClock = (TextView) v.findViewById(R.id.clock); + + // Wallpaper / Font / Icons / etc + mWallpaper = (ImageView) v.findViewById(R.id.wallpaper); + mFontCard = (ComponentCardView) v.findViewById(R.id.font_preview_container); + mFontPreview = (TextView) v.findViewById(R.id.font_preview); + mFontPreview.setTypeface(mTypefaceNormal); + mIconCard = (ComponentCardView) v.findViewById(R.id.icon_container); + mShadowFrame = (FrameLayout) v.findViewById(R.id.shadow_frame); + mStyleCard = (ComponentCardView) v.findViewById(R.id.style_card); + mStylePreview = (ImageView) v.findViewById(R.id.style_preview); + mBootAnimationCard = (ComponentCardView) v.findViewById(R.id.bootani_preview_container); + mBootAnimation = + (BootAniImageView) mBootAnimationCard.findViewById(R.id.bootani_preview); + mRingtoneCard = (ComponentCardView) v.findViewById(R.id.ringtone_preview_container); + mRingtonePlayPause = (ImageView) mRingtoneCard.findViewById(R.id.play_pause); + mNotificationCard = (ComponentCardView) v.findViewById(R.id.notification_preview_container); + mNotificationPlayPause = (ImageView) mNotificationCard.findViewById(R.id.play_pause); + mAlarmCard = (ComponentCardView) v.findViewById(R.id.alarm_preview_container); + mAlarmPlayPause = (ImageView) mAlarmCard.findViewById(R.id.play_pause); + + // Nav Bar + mNavBarCard = (ComponentCardView) v.findViewById(R.id.navigation_bar_container); + mNavBar = (ViewGroup) v.findViewById(R.id.navigation_bar); + mBackButton = (ImageView) v.findViewById(R.id.back_button); + mHomeButton = (ImageView) v.findViewById(R.id.home_button); + mRecentButton = (ImageView) v.findViewById(R.id.recent_button); + + // Title Card + mTitleCard = (ViewGroup)v.findViewById(R.id.title_card); + mTitleLayout = (ViewGroup) v.findViewById(R.id.title_layout); + mTitle = (TextView) v.findViewById(R.id.title); + mAuthor = (TextView) v.findViewById(R.id.author); + mProgress = (ProgressBar) v.findViewById(R.id.apply_progress); + mOverflow = (ImageView) v.findViewById(R.id.overflow); + mOverflow.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (isShowingConfirmCancelOverlay()) { + hideConfirmCancelOverlay(); + } else if (isShowingCustomizeResetLayout()) { + hideCustomizeResetLayout(); + } + + PopupMenu popupmenu = new PopupMenu(getActivity(), mTitleCard, Gravity.END); + popupmenu.getMenuInflater().inflate(R.menu.overflow, popupmenu.getMenu()); + + Menu menu = popupmenu.getMenu(); + if (CURRENTLY_APPLIED_THEME.equals(mPkgName) || + mPkgName.equals(Utils.getDefaultThemePackageName(getActivity())) || + mPkgName.equals(ThemeConfig.SYSTEM_DEFAULT)) { + menu.findItem(R.id.menu_delete).setEnabled(false); + } + if (!mThemeTagLayout.isCustomizedTagEnabled()) { + menu.findItem(R.id.menu_reset).setVisible(false); + } + + popupmenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem item) { + return onPopupMenuItemClick(item); + } + }); + popupmenu.show(); + } + }); + mCustomize = (ImageView) v.findViewById(R.id.customize); + mCustomize.setOnClickListener(new View.OnClickListener() { + public void onClick(View v) { + if (!isShowingConfirmCancelOverlay() && !isShowingCustomizeResetLayout()) { + getChooserActivity().expand(); + } + } + }); + + mDelete = (ImageView) v.findViewById(R.id.delete); + mDelete.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + showDeleteThemeOverlay(); + } + }); + if (Utils.getDefaultThemePackageName(getActivity()).equals(mPkgName) || + ThemeConfig.SYSTEM_DEFAULT.equals(mPkgName)) { + mDelete.setVisibility(View.GONE); + } + + mReset = (ImageView) v.findViewById(R.id.reset); + mReset.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + showResetThemeOverlay(); + } + }); + mReset.setVisibility(View.GONE); + + if (!Utils.hasNavigationBar(getActivity())) { + adjustScrollViewPaddingTop(); + mNavBarCard.setVisibility(View.GONE); + } + + // Additional cards which should hang out offscreen until expanded + mAdditionalCards = (LinearLayout) v.findViewById(R.id.additional_cards); + + mWallpaperCard = (WallpaperCardView) v.findViewById(R.id.wallpaper_card); + mLockScreenCard = (WallpaperCardView) v.findViewById(R.id.lockscreen_card); + int translationY = getDistanceToMoveBelowScreen(mAdditionalCards); + mAdditionalCards.setTranslationY(translationY); + + mConfirmCancelOverlay = (ConfirmCancelOverlay) v.findViewById(R.id.confirm_cancel_overlay); + mClickableView = v.findViewById(R.id.clickable_view); + + mCustomizeResetLayout = v.findViewById(R.id.customize_reset_theme_layout); + mDismissButton = mCustomizeResetLayout.findViewById(R.id.btn_dismiss); + mDismissButton.setOnClickListener(mCustomizeResetClickListener); + mResetButton = mCustomizeResetLayout.findViewById(R.id.btn_reset); + mResetButton.setOnClickListener(mCustomizeResetClickListener); + mCustomizeButton = mCustomizeResetLayout.findViewById(R.id.btn_customize); + mCustomizeButton.setOnClickListener(mCustomizeResetClickListener); + + mProcessingThemeLayout = v.findViewById(R.id.processing_theme_layout); + + if (mPkgName.equals(Utils.getDefaultThemePackageName(getActivity()))) { + mThemeTagLayout.setDefaultTagEnabled(true); + } + if (PreferenceUtils.hasThemeBeenUpdated(getActivity(), mPkgName)) { + mThemeTagLayout.setUpdatedTagEnabled(true); + } + + if (mSkipLoadingAnim) { + mLoadingView.setVisibility(View.GONE); + mTitleLayout.setAlpha(1f); + } + + getLoaderManager().initLoader(LOADER_ID_ALL, null, this); + + setupCardClickListeners(v); + + return v; + } + + @Override + public void onPause() { + super.onPause(); + stopMediaPlayers(); + } + + @Override + public void onResume() { + super.onResume(); + ThemeManager tm = getThemeManager(); + if (tm != null) { + if (isThemeProcessing()) { + tm.registerProcessingListener(this); + mProcessingThemeLayout.setVisibility(View.VISIBLE); + mCustomize.setVisibility(View.INVISIBLE); + mCustomize.setAlpha(0f); + if (mDelete.getVisibility() != View.GONE) { + mDelete.setVisibility(View.INVISIBLE); + mDelete.setAlpha(0f); + } + mProcessingResources = true; + } else { + mCustomize.setVisibility(View.VISIBLE); + mCustomize.setAlpha(1f); + if (mDelete.getVisibility() != View.GONE) { + mDelete.setVisibility(View.VISIBLE); + mDelete.setAlpha(1f); + } + mProcessingResources = false; + } + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + freeMediaPlayers(); + ThemeManager tm = getThemeManager(); + if (tm != null) { + tm.removeClient(this); + tm.unregisterProcessingListener(this); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, String[] permissions, + int[] grantResults) { + if (requestCode == PERMISSION_REQUEST) { + int N = permissions.length; + for (int i = 0; i < N; i++) { + if (READ_EXTERNAL_STORAGE.equals(permissions[i])) { + if (grantResults[i] == PERMISSION_GRANTED) { + // Run the runnable now that we have been granted permission + if (mAfterPermissionGrantedRunnable != null) { + mAfterPermissionGrantedRunnable.run(); + mAfterPermissionGrantedRunnable = null; + } + } else { + // inform the user that they will be unable to pick an image because + // we were not granted permission to do so + Toast.makeText(getActivity(), + R.string.read_external_permission_denied_message, + Toast.LENGTH_LONG).show(); + } + } + } + } + } + + @Override + public void onProgress(int progress) { + mProgress.setProgress(progress); + } + + private void setLiveLockScreenAsKeyguard(boolean setLLS) { + ComponentName cn = null; + if (setLLS) { + try { + final String[] permissions = Utils.getDangerousPermissionsNotGranted(getActivity(), + LLS_PACKAGE_NAME); + if (permissions.length > 0) { + Intent reqIntent = Utils.buildPermissionGrantRequestIntent(getActivity(), + LLS_PACKAGE_NAME, permissions); + if (reqIntent != null) { + startActivity(reqIntent); + } + } + cn = new ComponentName(LLS_PACKAGE_NAME, LLS_PROVIDER_NAME); + } catch (InvalidParameterException e) { + Log.e(TAG, "Package Manager couldn't find package " + LLS_PACKAGE_NAME, e); + return; + } + } + + CmLockPatternUtils lockPatternUtils = new CmLockPatternUtils(getActivity()); + try { + lockPatternUtils.setThirdPartyKeyguard(cn); + } catch (PackageManager.NameNotFoundException e) { + // we should not be here! + } + } + + @Override + public void onFinish(boolean isSuccess) { + // We post a runnable to mHandler so the client is removed from the same thread + mHandler.post(new Runnable() { + @Override + public void run() { + ThemeManager tm = getThemeManager(); + if (tm != null) tm.removeClient(ThemeFragment.this); + } + }); + if (isSuccess) { + if (mExternalLockscreenUri != null) { + // Handle setting an external wallpaper in a separate thread + // Need to do this AFTER ThemeMgr is done processing our change request. + // The external lock screen that we just applied would be removed when + // the change request is setting/clearing the lock screen + new Thread(mApplyExternalLockscreenRunnable).start(); + } + Map appliedComponents = getComponentsToApply(); + boolean modLLS = appliedComponents.containsKey(MODIFIES_LIVE_LOCK_SCREEN); + if (modLLS) { + String pkgName = appliedComponents.get(MODIFIES_LIVE_LOCK_SCREEN); + if (pkgName.equals(LOCKSCREEN_NONE)) { + setLiveLockScreenAsKeyguard(false); + } else { + setLiveLockScreenAsKeyguard(true); + } + } + mProgress.setProgress(100); + animateProgressOut(); + } + getChooserActivity().themeChangeEnd(isSuccess); + } + + @Override + public void onFinishedProcessing(String pkgName) { + if (pkgName.equals(mPkgName) || pkgName.equals(mBaseThemePkgName)) { + ThemeManager tm = getThemeManager(); + if (tm != null) { + tm.unregisterProcessingListener(this); + } + } + } + + @Override + public void setUserVisibleHint(boolean isVisibleToUser) { + super.setUserVisibleHint(isVisibleToUser); + if (mThemeTagLayout == null) return; + + if (!isVisibleToUser) { + if (PreferenceUtils.hasThemeBeenUpdated(getActivity(), mPkgName)) { + mThemeTagLayout.setUpdatedTagEnabled(true); + } + } else { + if (PreferenceUtils.hasThemeBeenUpdated(getActivity(), mPkgName)) { + PreferenceUtils.removeUpdatedTheme(getActivity(), mPkgName); + } + } + } + + public void setWallpaperImageUri(Uri uri) { + mExternalWallpaperUri = uri; + final Point size = new Point(mWallpaper.getWidth(), mWallpaper.getHeight()); + final Drawable wp = getWallpaperDrawableFromUri(uri, size); + mWallpaperCard.setWallpaper(wp); + mWallpaper.setImageDrawable(wp); + // remove the entry from mSelectedComponentsMap + mSelectedComponentsMap.remove(ThemesColumns.MODIFIES_LAUNCHER); + } + + public void setLockscreenImageUri(Uri uri) { + mExternalLockscreenUri = uri; + final Point size = new Point(mLockScreenCard.getWidth(), mLockScreenCard.getHeight()); + final Drawable wp = getWallpaperDrawableFromUri(uri, size); + if (mLockScreenCard.isShowingEmptyView()) { + mLockScreenCard.setEmptyViewEnabled(false); + } + mLockScreenCard.setWallpaper(wp); + // remove the entry from mSelectedComponentsMap + mSelectedComponentsMap.remove(ThemesColumns.MODIFIES_LIVE_LOCK_SCREEN); + mSelectedComponentsMap.remove(ThemesColumns.MODIFIES_LOCKSCREEN); + } + + protected Drawable getWallpaperDrawableFromUri(Uri uri, Point size) { + final Context context = getActivity(); + final Resources res = context.getResources(); + Bitmap bmp = WallpaperUtils.createPreview(size, context, uri, null, res, 0, 0, false); + if (bmp != null) { + return new BitmapDrawable(res, bmp); + } + return null; + } + + protected ChooserActivity getChooserActivity() { + return (ChooserActivity) getActivity(); + } + + private void adjustScrollViewPaddingTop() { + Resources res = getResources(); + int extraPadding = + res.getDimensionPixelSize(R.dimen.navigation_bar_height) / 2; + mScrollView.setPadding(mScrollView.getPaddingLeft(), + mScrollView.getPaddingTop() + extraPadding, mScrollView.getPaddingRight(), + mScrollView.getPaddingBottom()); + } + + protected boolean isThemeProcessing() { + ThemeManager tm = getThemeManager(); + if (tm != null) { + final String pkgName = mBaseThemePkgName != null ? mBaseThemePkgName : mPkgName; + return tm.isThemeBeingProcessed(pkgName); + } + return false; + } + + protected boolean onPopupMenuItemClick(MenuItem item) { + switch(item.getItemId()) { + /* TODO: Add back in once there is UX available for this feature + case R.id.menu_author: + Toast.makeText(getActivity(), + "Not supported", + Toast.LENGTH_LONG).show(); + break; + */ + case R.id.menu_delete: + showDeleteThemeOverlay(); + break; + } + + return true; + } + + public void expand() { + if (mCurrentLoaderId == LOADER_ID_ALL && mCurrentCursor != null) { + loadAdditionalCards(mCurrentCursor); + // we don't need this now that the additional cards are loaded, and + // we don't want to re-load these cards if the we expand again. + mCurrentCursor = null; + } + mClickableView.setVisibility(View.GONE); + mScrollView.setScrollingEnabled(true); + // Full width and height! + ViewGroup content = (ViewGroup) mScrollView.getParent(); + content.setPadding(0, 0, 0, 0); + ViewGroup.LayoutParams layoutParams = mPreviewContent.getLayoutParams(); + layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT; + mPreviewContent.setLayoutParams(layoutParams); + mScrollView.setPadding(0,0,0,0); + + // The parent of the wallpaper squishes the wp slightly because of padding from the 9 patch + // When the parent expands, the wallpaper returns to regular size which creates an + // undesireable effect. + Rect padding = new Rect(); + NinePatchDrawable bg = (NinePatchDrawable) mShadowFrame.getBackground(); + bg.getPadding(padding); + mIconCard.setPadding(padding.left, padding.top, padding.right, padding.bottom); + mShadowFrame.setBackground(null); + mShadowFrame.setPadding(0, 0, 0, 0); + + // Off screen cards will become visible and then be animated in + mWallpaperCard.setVisibility(View.VISIBLE); + + // Expand the children + int top = (int) getResources() + .getDimension(R.dimen.expanded_card_margin_top); + for (int i = 0; i < mPreviewContent.getChildCount(); i++) { + ComponentCardView child = (ComponentCardView) mPreviewContent.getChildAt(i); + + LinearLayout.LayoutParams lparams = + (LinearLayout.LayoutParams) child.getLayoutParams(); + if (child == mStatusBarCard) { + int statusBarHeight = getResources() + .getDimensionPixelSize(R.dimen.status_bar_height); + lparams.setMargins(0, top + statusBarHeight, 0, 0); + } else { + lparams.setMargins(0, top, 0, 0); + } + + child.setLayoutParams(lparams); + child.expand(false); + } + + // Expand the additional children. + mAdditionalCards.setVisibility(View.VISIBLE); + for (int i = 0; i < mAdditionalCards.getChildCount(); i++) { + View v = mAdditionalCards.getChildAt(i); + if (v instanceof ComponentCardView) { + ComponentCardView card = (ComponentCardView) v; + card.setVisibility(View.VISIBLE); + card.expand(true); + } + } + + // Collect the present position of all the children. The next layout/draw cycle will + // change these bounds since we just expanded them. Then we can animate from prev location + // to the new location. Note that the order of these calls matter as they all + // add themselves to the root layout as overlays + mScrollView.requestLayout(); + animateWallpaperOut(); + animateTitleCard(true, false); + animateChildren(true, getChildrensGlobalBounds(mPreviewContent)); + animateExtras(true); + mSelector = getChooserActivity().getComponentSelector(); + mSelector.setOnItemClickedListener(mOnComponentItemClicked); + if (mBootAnimation != null) mBootAnimation.start(); + hideThemeTagLayout(); + mExpanded = true; + } + + + + // Returns the boundaries for all the children of parent relative to the app window + private List getChildrensGlobalBounds(ViewGroup parent) { + List bounds = new ArrayList(); + for (int i = 0; i < parent.getChildCount(); i++) { + final View v = parent.getChildAt(i); + int[] pos = new int[2]; + v.getLocationInWindow(pos); + Rect boundary = new Rect(pos[0], pos[1], pos[0] + v.getWidth(), pos[1]+v.getHeight()); + bounds.add(boundary); + } + return bounds; + } + + public void performClick(boolean clickedOnContent) { + // Don't do anything if the theme is being processed + if (mProcessingThemeLayout.getVisibility() == View.VISIBLE) return; + + if (clickedOnContent) { + showApplyThemeOverlay(); + } else { + if (isShowingConfirmCancelOverlay()) { + hideConfirmCancelOverlay(); + } + } + } + + public void fadeOutCards(Runnable endAction) { + for (int i = 0; i < mPreviewContent.getChildCount(); i++) { + ComponentCardView v = (ComponentCardView) mPreviewContent.getChildAt(i); + v.animateFadeOut(); + } + mHandler.postDelayed(endAction, ComponentCardView.CARD_FADE_DURATION); + } + + public void collapse(final boolean applyTheme) { + mScrollView.setScrollingEnabled(false); + + // Pad the view so it appears thinner + ViewGroup content = (ViewGroup) mScrollView.getParent(); + Resources r = mScrollView.getContext().getResources(); + int leftRightPadding = (int) r.getDimension(R.dimen.collapsed_theme_page_padding); + content.setPadding(leftRightPadding, 0, leftRightPadding, 0); + + if (applyTheme) { + final boolean customized = isThemeCustomized(); + mThemeTagLayout.setCustomizedTagEnabled(customized); + mReset.setVisibility(customized ? View.VISIBLE : View.GONE); + } + + //Move the theme preview so that it is near the center of page per spec + int paddingTop = (int) r.getDimension(R.dimen.collapsed_theme_page_padding_top); + if (!Utils.hasNavigationBar(getActivity())) { + paddingTop += + r.getDimensionPixelSize(R.dimen.navigation_bar_height) / 2; + } + mScrollView.setPadding(0, paddingTop, 0, 0); + + // During expand the wallpaper size decreases slightly to makeup for 9patch padding + // so when we collapse we should increase it again. + mShadowFrame.setBackgroundResource(R.drawable.bg_themepreview_shadow); + Rect padding = new Rect(); + final NinePatchDrawable bg = (NinePatchDrawable) mShadowFrame.getBackground(); + bg.getPadding(padding); + mShadowFrame.setPadding(padding.left, padding.top, padding.right, padding.bottom); + + // Gradually fade the drop shadow back in or else it will be out of place + ValueAnimator shadowAnimation = ValueAnimator.ofObject(new IntEvaluator(), 0, 255); + shadowAnimation.setDuration(ANIMATE_DURATION); + shadowAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animator) { + bg.setAlpha((Integer) animator.getAnimatedValue()); + } + + }); + shadowAnimation.start(); + + //Move the title card back in + mTitleCard.setVisibility(View.VISIBLE); + mTitleCard.setTranslationY(0); + + // Shrink the height + ViewGroup.LayoutParams layoutParams = mPreviewContent.getLayoutParams(); + Resources resources = mPreviewContent.getResources(); + layoutParams.height = (int) resources.getDimension(R.dimen.theme_preview_height); + + mScrollView.requestLayout(); + List bounds = getChildrensGlobalBounds(mPreviewContent); + for (int i = 0; i < mPreviewContent.getChildCount(); i++) { + ComponentCardView child = (ComponentCardView) mPreviewContent.getChildAt(i); + LinearLayout.LayoutParams lparams = + (LinearLayout.LayoutParams) child.getLayoutParams(); + lparams.setMargins(0, 0, 0, 0); + + if (child.getId() == R.id.icon_container) { + int top = (int) child.getResources() + .getDimension(R.dimen.collapsed_icon_card_margin_top); + lparams.setMargins(0, top, 0, 0); + } else if (child.getId() == R.id.font_preview_container) { + int top = (int) child.getResources() + .getDimension(R.dimen.collapsed_font_card_margin_top); + lparams.setMargins(0, top, 0, 0); + } else if (child.getId() == R.id.navigation_bar_container) { + int top = (int) child.getResources() + .getDimension(R.dimen.collapsed_navbar_card_margin_top); + lparams.setMargins(0, top, 0, 0); + } + + child.getLayoutParams(); + child.collapse(); + } + + // Collapse additional cards + for (int i = 0; i < mAdditionalCards.getChildCount(); i++) { + View v = mAdditionalCards.getChildAt(i); + if (v instanceof ComponentCardView) { + ComponentCardView card = (ComponentCardView) v; + card.setVisibility(View.VISIBLE); + card.collapse(); + } + } + + animateChildren(false, bounds); + animateExtras(false); + animateWallpaperIn(); + animateTitleCard(false, applyTheme); + if (mBootAnimation != null) mBootAnimation.stop(); + stopMediaPlayers(); + showThemeTagLayout(); + + // Need to set the wallpaper background to black if the user has selected to apply + // the "none" wallpaper + if (applyTheme) { + String pkgName = mSelectedComponentsMap.get(ThemesColumns.MODIFIES_LAUNCHER); + if (pkgName != null && pkgName.length() == 0) { + mWallpaper.setImageResource(R.drawable.wallpaper_none_bg); + } + // we do this here instead of in applyTheme() because this can take a bit longer + // to propagate the change from WallpaperManager back to us + if (mExternalWallpaperUri != null) { + // Handle setting an external wallpaper in a separate thread + new Thread(mApplyExternalWallpaperRunnable).start(); + } + } + mExpanded = false; + } + + // This will animate the children's vertical positions between the previous bounds and the + // new bounds which occur on the next draw + private void animateChildren(final boolean isExpanding, final List prevBounds) { + final ViewGroup root = (ViewGroup) getActivity().getWindow() + .getDecorView().findViewById(android.R.id.content); + + final Resources res = getResources(); + final float yOffset = + res.getDimensionPixelSize(R.dimen.expand_collapse_child_offset) + * (isExpanding ? -1 : 1); + // Grab the child's new location and animate from prev to current loc. + final ViewTreeObserver observer = mScrollContent.getViewTreeObserver(); + observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { + public boolean onPreDraw() { + observer.removeOnPreDrawListener(this); + + for (int i = mPreviewContent.getChildCount() - 1; i >= 0; i--) { + final ComponentCardView v = (ComponentCardView) mPreviewContent.getChildAt(i); + + float prevY; + float endY; + float prevHeight; + float endHeight; + if (i >= prevBounds.size()) { + // View is being created + prevY = mPreviewContent.getTop() + mPreviewContent.getHeight(); + endY = v.getY(); + prevHeight = v.getHeight(); + endHeight = v.getHeight(); + } else { + Rect boundary = prevBounds.get(i); + prevY = boundary.top; + prevHeight = boundary.height(); + + int[] endPos = new int[2]; + v.getLocationInWindow(endPos); + endY = endPos[1]; + endHeight = v.getHeight(); + } + + int paddingTop = v.getPaddingTop() / 2; + float dy = (prevY - endY - paddingTop) + (prevHeight - endHeight) / 2; + dy += yOffset; + v.setTranslationY(dy); + root.getOverlay().add(v); + + // Expanding has a delay while the wallpaper begins to fade out + // Collapsing is opposite of this so wallpaper will have the delay instead + int startDelay = isExpanding ? ANIMATE_START_DELAY : 0; + + v.animate() + .setStartDelay(startDelay) + .translationY(0) + .setDuration(ANIMATE_DURATION) + .setInterpolator( + new DecelerateInterpolator(ANIMATE_INTERPOLATE_FACTOR)) + .withEndAction(new Runnable() { + public void run() { + root.getOverlay().remove(v); + mPreviewContent.addView(v, 0); + } + }); + v.postDelayed(new Runnable() { + public void run() { + if (isExpanding) { + v.animateExpand(); + } + } + }, ANIMATE_DURATION / 2); + } + return true; + } + }); + } + + private void animateExtras(final boolean isExpanding) { + int[] pos = new int[2]; + mAdditionalCards.getLocationInWindow(pos); + final ViewGroup parent = (ViewGroup) mAdditionalCards.getParent(); + final ViewGroup root = (ViewGroup) getActivity().getWindow() + .getDecorView().findViewById(android.R.id.content); + + // During a collapse we don't want the card to shrink so add it to the overlay now + // During an expand we want the card to expand so add it to the overlay post-layout + if (!isExpanding) { + root.getOverlay().add(mAdditionalCards); + } + + // Expanding has a delay while the wallpaper begins to fade out + // Collapsing is opposite of this so wallpaper will have the delay instead + final int startDelay = isExpanding ? ANIMATE_START_DELAY : 0; + final ViewTreeObserver observer = mScrollContent.getViewTreeObserver(); + observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { + public boolean onPreDraw() { + observer.removeOnPreDrawListener(this); + + int translationY = 0; + if (isExpanding) { + root.getOverlay().add(mAdditionalCards); + } else { + translationY = getDistanceToMoveBelowScreen(mAdditionalCards); + } + + int duration = isExpanding ? ANIMATE_DURATION + 100 : ANIMATE_DURATION; + mAdditionalCards.animate() + .setStartDelay(startDelay) + .translationY(translationY) + .setDuration(duration) + .setInterpolator( + new DecelerateInterpolator(ANIMATE_INTERPOLATE_FACTOR)) + .withEndAction(new Runnable() { + public void run() { + if (!isExpanding) { + mAdditionalCards.setVisibility(View.INVISIBLE); + } + root.getOverlay().remove(mAdditionalCards); + parent.addView(mAdditionalCards); + } + }); + return false; + } + }); + } + + private int getDistanceToMoveBelowScreen(View v) { + Display display = getActivity().getWindowManager().getDefaultDisplay(); + Point p = new Point(); + display.getSize(p); + int heightId = getResources() + .getIdentifier("navigation_bar_height", "dimen", "android"); + int navbar_height = getResources().getDimensionPixelSize(heightId); + int[] pos = new int[2]; + v.getLocationInWindow(pos); + return p.y + navbar_height - pos[1]; + } + + private void animateTitleCard(final boolean expand, final boolean applyTheme) { + final ViewGroup parent = (ViewGroup) mTitleCard.getParent(); + // Get current location of the title card + int[] location = new int[2]; + mTitleCard.getLocationOnScreen(location); + final int prevY = location[1]; + final int position = parent.indexOfChild(mTitleCard); + + final ViewTreeObserver observer = mScrollContent.getViewTreeObserver(); + observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { + public boolean onPreDraw() { + observer.removeOnPreDrawListener(this); + + final ViewGroup root = (ViewGroup) getActivity().getWindow() + .getDecorView().findViewById(android.R.id.content); + + root.getOverlay().add(mTitleCard); + + //Move title card back where it was before the relayout + float alpha = 1f; + if (expand) { + int[] endPos = new int[2]; + mTitleCard.getLocationInWindow(endPos); + int endY = endPos[1]; + mTitleCard.setTranslationY(prevY - endY); + alpha = 0; + } else { + } + + // Fade the title card and move it out of the way + mTitleCard.animate() + .alpha(alpha) + .setDuration(ANIMATE_DURATION) + .withEndAction(new Runnable() { + public void run() { + root.getOverlay().remove(mTitleCard); + parent.addView(mTitleCard, position); + if (expand) { + mTitleCard.setVisibility(View.INVISIBLE); + } else { + mTitleCard.setVisibility(View.VISIBLE); + mClickableView.setVisibility(View.VISIBLE); + if (applyTheme) { + // The title card is the last animation when collapsing so + // we will handle applying the theme, if applicable, here + applyTheme(); + } + } + } + }); + return true; + } + }); + } + + private void animateWallpaperOut() { + final ViewGroup root = (ViewGroup) getActivity().getWindow() + .getDecorView().findViewById(android.R.id.content); + + int[] location = new int[2]; + mWallpaper.getLocationOnScreen(location); + + final int prevY = location[1]; + + final ViewTreeObserver observer = mScrollContent.getViewTreeObserver(); + observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { + public boolean onPreDraw() { + observer.removeOnPreDrawListener(this); + root.getOverlay().add(mWallpaper); + + int[] location = new int[2]; + mWallpaper.getLocationOnScreen(location); + final int newY = location[1]; + + mWallpaper.setTranslationY(prevY - newY); + mWallpaper.animate() + .alpha(0f) + .setDuration(300) + .withEndAction(new Runnable() { + public void run() { + root.getOverlay().remove(mWallpaper); + mShadowFrame.addView(mWallpaper, 0); + mWallpaper.setVisibility(View.GONE); + } + }); + return true; + + } + }); + } + + private void animateWallpaperIn() { + mWallpaper.setVisibility(View.VISIBLE); + mWallpaper.setTranslationY(0); + mWallpaper.animate() + .alpha(1f) + .setDuration(300); + } + + protected String getAppliedFontPackageName() { + final Configuration config = getActivity().getResources().getConfiguration(); + final ThemeConfig themeConfig = config != null ? config.themeConfig : null; + return themeConfig != null ? themeConfig.getFontPkgName() : + ThemeConfig.getSystemTheme().getFontPkgName(); + } + + protected ThemeManager getThemeManager() { + return ThemeManager.getInstance(getActivity()); + } + + private void freeMediaPlayers() { + for (MediaPlayer mp : mMediaPlayers.values()) { + if (mp != null) { + mp.stop(); + mp.release(); + } + } + mMediaPlayers.clear(); + } + + protected View.OnClickListener mPlayPauseClickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + MediaPlayer mp = (MediaPlayer) v.getTag(); + if (mp != null) { + if (mp.isPlaying()) { + ((ImageView) v).setImageResource(R.drawable.media_sound_preview); + mp.pause(); + mp.seekTo(0); + } else { + stopMediaPlayers(); + ((ImageView) v).setImageResource(R.drawable.media_sound_stop); + mp.start(); + } + } + } + }; + + protected MediaPlayer.OnCompletionListener mPlayCompletionListener + = new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + for (ImageView v : mMediaPlayers.keySet()) { + if (mp == mMediaPlayers.get(v)) { + if (v != null) { + v.setImageResource(R.drawable.media_sound_preview); + } + } + } + } + }; + + private void stopMediaPlayers() { + for (ImageView v : mMediaPlayers.keySet()) { + if (v != null) { + v.setImageResource(R.drawable.media_sound_preview); + } + MediaPlayer mp = mMediaPlayers.get(v); + if (mp != null && mp.isPlaying()) { + mp.pause(); + mp.seekTo(0); + } + } + } + + protected void resetTheme() { + mSelectedComponentsMap.clear(); + Bundle args = new Bundle(); + args.putString(ARG_PACKAGE_NAME, mBaseThemePkgName); + args.putLong(ARG_COMPONENT_ID, DEFAULT_COMPONENT_ID); + getLoaderManager().restartLoader(LOADER_ID_ALL, args, this); + mThemeResetting = true; + } + + @Override + public Loader onCreateLoader(int id, Bundle args) { + String pkgName = mPkgName; + long componentId = DEFAULT_COMPONENT_ID; + if (args != null) { + pkgName = args.getString(ARG_PACKAGE_NAME); + componentId = args.getLong(ARG_COMPONENT_ID, DEFAULT_COMPONENT_ID); + } + return CursorLoaderHelper.themeFragmentCursorLoader(getActivity(), id, pkgName, + componentId); + } + + @Override + public void onLoadFinished(Loader loader, Cursor c) { + if (c.getCount() == 0) return; + mCurrentCursor = c; + mCurrentLoaderId = loader.getId(); + c.moveToFirst(); + boolean animate = !mApplyThemeOnPopulated; + switch (mCurrentLoaderId) { + case LOADER_ID_ALL: + if (mProcessingResources && !isThemeProcessing()) { + mProcessingResources = false; + hideProcessingOverlay(); + } + loadLegacyThemeInfo(c); + populateSupportedComponents(c); + loadWallpaper(c, false); + loadStatusBar(c, false); + loadIcons(c, false); + loadNavBar(c, false); + loadTitle(c); + loadFont(c, false); + mHandler.post(new Runnable() { + @Override + public void run() { + animateContentIn(); + } + }); + if (mShowLockScreenSelectorAfterContentLoaded) { + getChooserActivity().expandContentAndAnimateLockScreenCardIn(); + mShowLockScreenSelectorAfterContentLoaded = false; + } + break; + case LOADER_ID_STATUS_BAR: + loadStatusBar(c, animate); + break; + case LOADER_ID_FONT: + loadFont(c, animate); + break; + case LOADER_ID_ICONS: + loadIcons(c, animate); + break; + case LOADER_ID_WALLPAPER: + loadWallpaper(c, animate); + break; + case LOADER_ID_NAVIGATION_BAR: + loadNavBar(c, animate); + break; + case LOADER_ID_LIVE_LOCK_SCREEN: + case LOADER_ID_LOCKSCREEN: + loadLockScreen(c, animate); + break; + case LOADER_ID_STYLE: + loadStyle(c, animate); + break; + case LOADER_ID_BOOT_ANIMATION: + loadBootAnimation(c); + break; + case LOADER_ID_RINGTONE: + loadAudible(RingtoneManager.TYPE_RINGTONE, c, animate); + break; + case LOADER_ID_NOTIFICATION: + loadAudible(RingtoneManager.TYPE_NOTIFICATION, c, animate); + break; + case LOADER_ID_ALARM: + loadAudible(RingtoneManager.TYPE_ALARM, c, animate); + break; + } + if (mCurrentLoaderId != LOADER_ID_ALL) { + if (!componentsChanged()) { + getChooserActivity().hideSaveApplyButton(); + } else if (!mApplyThemeOnPopulated) { + getChooserActivity().showSaveApplyButton(); + } + } + } + + @Override + public void onLoaderReset(Loader loader) {} + + private void loadAdditionalCards(Cursor c) { + for(int i=0; i < mAdditionalCards.getChildCount(); i++) { + View v = mAdditionalCards.getChildAt(i); + if (v instanceof ComponentCardView) { + String component = mCardIdsToComponentTypes.get(v.getId()); + loadAdditionalCard(c, component, shouldShowComponentCard(component)); + } + } + } + + private void loadAdditionalCard(Cursor c, String component, boolean hasContent) { + if (MODIFIES_LOCKSCREEN.equals(component)) { + if (hasContent) { + loadLockScreen(c, false); + } else { + mLockScreenCard.clearWallpaper(); + mLockScreenCard.setEmptyViewEnabled(true); + setAddComponentTitle(mLockScreenCard, getString(R.string.lockscreen_label)); + } + } else if (MODIFIES_LAUNCHER.equals(component)) { + // this was already loaded so no need to do this again. + } else if (MODIFIES_OVERLAYS.equals(component)) { + if (hasContent) { + loadStyle(c, false); + } else { + mStyleCard.setEmptyViewEnabled(true); + setAddComponentTitle(mStyleCard, + getString(R.string.style_label)); + } + } else if (MODIFIES_BOOT_ANIM.equals(component)) { + if (hasContent) { + loadBootAnimation(c); + } else { + mBootAnimationCard.setEmptyViewEnabled(true); + setAddComponentTitle(mBootAnimationCard, + getString(R.string.boot_animation_label)); + } + } else if (MODIFIES_RINGTONES.equals(component)) { + if (hasContent) { + loadAudible(RingtoneManager.TYPE_RINGTONE, c, false); + } else { + mRingtoneCard.setEmptyViewEnabled(true); + setAddComponentTitle(mRingtoneCard, + getAudibleLabel(RingtoneManager.TYPE_RINGTONE)); + } + } else if (MODIFIES_NOTIFICATIONS.equals(component)) { + if (hasContent) { + loadAudible(RingtoneManager.TYPE_NOTIFICATION, c, false); + } else { + mNotificationCard.setEmptyViewEnabled(true); + setAddComponentTitle(mNotificationCard, + getAudibleLabel(RingtoneManager.TYPE_NOTIFICATION)); + } + } else if (MODIFIES_ALARMS.equals(component)) { + if (hasContent) { + loadAudible(RingtoneManager.TYPE_ALARM, c, false); + } else { + mAlarmCard.setEmptyViewEnabled(true); + setAddComponentTitle(mAlarmCard, + getAudibleLabel(RingtoneManager.TYPE_ALARM)); + } + } else { + throw new IllegalArgumentException("Don't know how to load: " + component); + } + } + + protected void populateSupportedComponents(Cursor c) { + List components = ThemeUtils.getAllComponents(); + for(String component : components) { + int pkgIdx = c.getColumnIndex(ThemesColumns.PKG_NAME); + int modifiesCompIdx = c.getColumnIndex(component); + + String pkg = c.getString(pkgIdx); + boolean supported = (modifiesCompIdx >= 0) && (c.getInt(modifiesCompIdx) == 1); + if (supported) { + mBaseThemeSupportedComponents.add(component); + mSelectedComponentsMap.put(component, pkg); + } + } + + if (mApplyThemeOnPopulated) { + applyTheme(); + } + } + + /** + * Determines whether a card should be shown or not. + * UX Rules: + * 1) "My Theme" always shows all cards + * 2) Other themes only show what has been implemented in the theme + * + */ + protected Boolean shouldShowComponentCard(String component) { + String pkg = mSelectedComponentsMap.get(component); + return pkg != null && pkg.equals(mPkgName); + } + + protected void loadLegacyThemeInfo(Cursor c) { + int targetApiIdx = c.getColumnIndex(ThemesColumns.TARGET_API); + // If this is being called for a MyThemeFragment the index will be -1 so set to + // SYSTEM_TARGET_API so we don't display the tag. If the user applied a legacy theme + // then they should have already been warned. + int targetApi = targetApiIdx < 0 ? SYSTEM_TARGET_API : c.getInt(targetApiIdx); + mIsLegacyTheme = targetApi != SYSTEM_TARGET_API && targetApi <= Build.VERSION_CODES.KITKAT; + mThemeTagLayout.setLegacyTagEnabled(mIsLegacyTheme); + } + + protected void loadTitle(Cursor c) { + int titleIdx = c.getColumnIndex(ThemesColumns.TITLE); + int authorIdx = c.getColumnIndex(ThemesColumns.AUTHOR); + mTitle.setText(c.getString(titleIdx)); + mAuthor.setText(c.getString(authorIdx)); + } + + protected void loadWallpaper(Cursor c, boolean animate) { + mExternalWallpaperUri = null; + Drawable overlay = null; + if (animate) { + overlay = getOverlayDrawable(mWallpaperCard, true); + } + if (mWallpaperCard.isShowingEmptyView()) mWallpaperCard.setEmptyViewEnabled(false); + + int pkgNameIdx = c.getColumnIndex(ThemesColumns.PKG_NAME); + int wpIdx = c.getColumnIndex(PreviewColumns.WALLPAPER_PREVIEW); + int cmpntIdIdx = c.getColumnIndex(PreviewColumns.COMPONENT_ID); + final Resources res = getResources(); + Bitmap bitmap = Utils.loadBitmapBlob(c, wpIdx); + if (bitmap != null) { + mWallpaper.setImageBitmap(bitmap); + mWallpaperCard.setWallpaper(new BitmapDrawable(res, bitmap)); + String pkgName = c.getString(pkgNameIdx); + Long cmpntId = (cmpntIdIdx >= 0) ? c.getLong(cmpntIdIdx) : DEFAULT_COMPONENT_ID; + if (!mPkgName.equals(pkgName) || (mPkgName.equals(pkgName) + && mBaseThemeSupportedComponents.contains(MODIFIES_LAUNCHER))) { + mSelectedComponentsMap.put(MODIFIES_LAUNCHER, pkgName); + mSelectedWallpaperComponentId = cmpntId; + setCardTitle(mWallpaperCard, pkgName, getString(R.string.wallpaper_label)); + } + } else { + // Set the wallpaper to "None" + mWallpaperCard.setWallpaper(null); + setCardTitle(mWallpaperCard, WALLPAPER_NONE, getString(R.string.wallpaper_label)); + mSelectedComponentsMap.put(ThemesColumns.MODIFIES_LAUNCHER, WALLPAPER_NONE); + } + + if (animate) { + animateContentChange(R.id.wallpaper_card, mWallpaperCard, overlay); + } + } + + protected void loadLockScreen(Cursor c, boolean animate) { + mExternalLockscreenUri = null; + Drawable overlay = null; + if (animate) { + overlay = getOverlayDrawable(mLockScreenCard, true); + } + if (mLockScreenCard.isShowingEmptyView()) mLockScreenCard.setEmptyViewEnabled(false); + + int pkgNameIdx = c.getColumnIndex(ThemesColumns.PKG_NAME); + int liveLockIndex = c.getColumnIndex(MODIFIES_LIVE_LOCK_SCREEN); + boolean isLiveLockScreen = liveLockIndex >= 0 && c.getInt(liveLockIndex) == 1; + + int wpIdx = isLiveLockScreen + ? c.getColumnIndex(PreviewColumns.LIVE_LOCK_SCREEN_PREVIEW) + : c.getColumnIndex(PreviewColumns.LOCK_WALLPAPER_PREVIEW); + final Resources res = getResources(); + Bitmap bitmap = Utils.loadBitmapBlob(c, wpIdx); + if (bitmap != null) { + mLockScreenCard.setWallpaper(new BitmapDrawable(res, bitmap)); + String pkgName = c.getString(pkgNameIdx); + if (!mPkgName.equals(pkgName) || (mPkgName.equals(pkgName) + && (mBaseThemeSupportedComponents.contains(MODIFIES_LOCKSCREEN) || + mBaseThemeSupportedComponents.contains(MODIFIES_LIVE_LOCK_SCREEN)))) { + if (isLiveLockScreen) { + mSelectedComponentsMap.put(MODIFIES_LIVE_LOCK_SCREEN, pkgName); + if (mCurrentTheme.containsKey(MODIFIES_LOCKSCREEN)) { + mSelectedComponentsMap.put(MODIFIES_LOCKSCREEN, LOCKSCREEN_NONE); + } else { + mSelectedComponentsMap.remove(MODIFIES_LOCKSCREEN); + } + setCardTitle(mLockScreenCard, pkgName, + getString(R.string.live_lock_screen_label)); + } else { + mSelectedComponentsMap.put(MODIFIES_LOCKSCREEN, pkgName); + if (mCurrentTheme.containsKey(MODIFIES_LIVE_LOCK_SCREEN)) { + mSelectedComponentsMap.put(MODIFIES_LIVE_LOCK_SCREEN, LOCKSCREEN_NONE); + } else { + mSelectedComponentsMap.remove(MODIFIES_LIVE_LOCK_SCREEN); + } + setCardTitle(mLockScreenCard, pkgName, getString(R.string.lockscreen_label)); + } + } + } else { + // Set the lockscreen wallpaper to "None" + mLockScreenCard.setWallpaper(null); + setCardTitle(mLockScreenCard, WALLPAPER_NONE, getString(R.string.lockscreen_label)); + } + + if (animate) { + animateContentChange(R.id.lockscreen_card, mLockScreenCard, overlay); + } + } + + protected void loadStatusBar(Cursor c, boolean animate) { + int backgroundIdx = c.getColumnIndex(PreviewColumns.STATUSBAR_BACKGROUND); + int wifiIdx = c.getColumnIndex(PreviewColumns.STATUSBAR_WIFI_ICON); + int wifiMarginIdx = c.getColumnIndex(PreviewColumns.STATUSBAR_WIFI_COMBO_MARGIN_END); + int bluetoothIdx = c.getColumnIndex(PreviewColumns.STATUSBAR_BLUETOOTH_ICON); + int signalIdx = c.getColumnIndex(PreviewColumns.STATUSBAR_SIGNAL_ICON); + int batteryIdx = c.getColumnIndex(Utils.getBatteryIndex(mBatteryStyle)); + int clockColorIdx = c.getColumnIndex(PreviewColumns.STATUSBAR_CLOCK_TEXT_COLOR); + int pkgNameIdx = c.getColumnIndex(ThemesColumns.PKG_NAME); + + Bitmap background = Utils.loadBitmapBlob(c, backgroundIdx); + Bitmap bluetoothIcon = Utils.loadBitmapBlob(c, bluetoothIdx); + Bitmap wifiIcon = Utils.loadBitmapBlob(c, wifiIdx); + Bitmap signalIcon = Utils.loadBitmapBlob(c, signalIdx); + Bitmap batteryIcon = Utils.loadBitmapBlob(c, batteryIdx); + int wifiMargin = wifiMarginIdx != -1 ? c.getInt(wifiMarginIdx) : DEFAULT_WIFI_MARGIN; + int clockTextColor = clockColorIdx != -1 ? c.getInt(clockColorIdx) : DEFAULT_CLOCK_COLOR; + + Drawable overlay = null; + if (animate) { + overlay = getOverlayDrawable(mStatusBar, false); + } + if (mStatusBarCard.isShowingEmptyView()) mStatusBarCard.setEmptyViewEnabled(false); + + mStatusBar.setBackground(new BitmapDrawable(getActivity().getResources(), background)); + mBluetooth.setImageBitmap(bluetoothIcon); + mWifi.setImageBitmap(wifiIcon); + mSignal.setImageBitmap(signalIcon); + mBattery.setImageBitmap(batteryIcon); + mClock.setTextColor(clockTextColor); + + ViewGroup.MarginLayoutParams params = + (ViewGroup.MarginLayoutParams) mWifi.getLayoutParams(); + params.setMarginEnd(wifiMargin); + mWifi.setLayoutParams(params); + + if (mBatteryStyle == 4) { + mBattery.setVisibility(View.GONE); + } else { + mBattery.setVisibility(View.VISIBLE); + } + mStatusBar.post(new Runnable() { + @Override + public void run() { + mStatusBar.invalidate(); + } + }); + if (pkgNameIdx > -1) { + String pkgName = c.getString(pkgNameIdx); + if (!mPkgName.equals(pkgName) || (mPkgName.equals(pkgName) + && mBaseThemeSupportedComponents.contains(MODIFIES_STATUS_BAR))) { + mSelectedComponentsMap.put(MODIFIES_STATUS_BAR, pkgName); + setCardTitle(mStatusBarCard, pkgName, + getString(R.string.statusbar_label)); + } + } + if (animate) { + animateContentChange(R.id.status_bar_container, mStatusBar, overlay); + } + } + + protected void loadIcons(Cursor c, boolean animate) { + if (mIconCard.isShowingEmptyView()) { + mIconCard.setEmptyViewEnabled(false); + } + int[] iconIdx = new int[3]; + iconIdx[0] = c.getColumnIndex(PreviewColumns.ICON_PREVIEW_1); + iconIdx[1] = c.getColumnIndex(PreviewColumns.ICON_PREVIEW_2); + iconIdx[2] = c.getColumnIndex(PreviewColumns.ICON_PREVIEW_3); + int pkgNameIdx = c.getColumnIndex(ThemesColumns.PKG_NAME); + + // Set the icons. If the provider does not have an icon preview then + // fall back to the default icon set + IconPreviewHelper helper = new IconPreviewHelper(getActivity(), ""); + ViewGroup iconContainer = + (ViewGroup) mIconCard.findViewById(R.id.icon_preview_container); + int numOfChildren = iconContainer.getChildCount(); + + List iconViews = new ArrayList(numOfChildren); + for(int i=0; i < numOfChildren; i++) { + final View view = iconContainer.getChildAt(i); + if (!(view instanceof ImageView)) continue; + iconViews.add((ImageView) view); + } + + for(int i=0; i < iconViews.size() && i < iconIdx.length; i++) { + final ImageView v = iconViews.get(i); + Bitmap bitmap = Utils.loadBitmapBlob(c, iconIdx[i]); + Drawable oldIcon = v.getDrawable(); + Drawable newIcon; + if (bitmap == null) { + ComponentName component = sIconComponents[i]; + newIcon = helper.getDefaultIcon(component.getPackageName(), + component.getClassName()); + } else { + newIcon = new BitmapDrawable(getResources(), bitmap); + } + if (animate) { + Drawable[] layers = new Drawable[2]; + layers[0] = oldIcon instanceof IconTransitionDrawable ? + ((IconTransitionDrawable) oldIcon).getDrawable(1) : oldIcon; + layers[1] = newIcon; + final IconTransitionDrawable itd = new IconTransitionDrawable(layers); + v.postDelayed(new Runnable() { + @Override + public void run() { + itd.startTransition(ANIMATE_COMPONENT_CHANGE_DURATION); + v.setImageDrawable(itd); + } + }, ANIMATE_COMPONENT_ICON_DELAY * i); + } else { + v.setImageDrawable(newIcon); + } + } + if (pkgNameIdx > -1) { + String pkgName = c.getString(pkgNameIdx); + if (!mPkgName.equals(pkgName) || (mPkgName.equals(pkgName) + && mBaseThemeSupportedComponents.contains(MODIFIES_ICONS))) { + mSelectedComponentsMap.put(MODIFIES_ICONS, pkgName); + setCardTitle(mIconCard, pkgName, + getString(R.string.icon_label)); + } + } + } + + protected void loadNavBar(Cursor c, boolean animate) { + int backButtonIdx = c.getColumnIndex(PreviewColumns.NAVBAR_BACK_BUTTON); + int homeButtonIdx = c.getColumnIndex(PreviewColumns.NAVBAR_HOME_BUTTON); + int recentButtonIdx = c.getColumnIndex(PreviewColumns.NAVBAR_RECENT_BUTTON); + int backgroundIdx = c.getColumnIndex(PreviewColumns.NAVBAR_BACKGROUND); + if (backgroundIdx == -1) { + backgroundIdx = c.getColumnIndex(PreviewColumns.STATUSBAR_BACKGROUND); + } + int pkgNameIdx = c.getColumnIndex(ThemesColumns.PKG_NAME); + + Bitmap background = Utils.loadBitmapBlob(c, backgroundIdx); + Bitmap backButton = Utils.loadBitmapBlob(c, backButtonIdx); + Bitmap homeButton = Utils.loadBitmapBlob(c, homeButtonIdx); + Bitmap recentButton = Utils.loadBitmapBlob(c, recentButtonIdx); + + Drawable overlay = null; + if (animate) { + overlay = getOverlayDrawable(mNavBar, false); + } + if (mNavBarCard.isShowingEmptyView()) mNavBarCard.setEmptyViewEnabled(false); + + mNavBar.setBackground(new BitmapDrawable(getActivity().getResources(), background)); + mBackButton.setImageBitmap(backButton); + mHomeButton.setImageBitmap(homeButton); + mRecentButton.setImageBitmap(recentButton); + + if (pkgNameIdx > -1) { + String pkgName = c.getString(pkgNameIdx); + if (!mPkgName.equals(pkgName) || (mPkgName.equals(pkgName) + && mBaseThemeSupportedComponents.contains(MODIFIES_NAVIGATION_BAR))) { + mSelectedComponentsMap.put(MODIFIES_NAVIGATION_BAR, pkgName); + setCardTitle(mNavBarCard, pkgName, getString(R.string.navbar_label)); + } + } + if (animate) { + animateContentChange(R.id.navigation_bar_container, mNavBar, overlay); + } + } + + protected void loadFont(Cursor c, boolean animate) { + Drawable overlay = null; + if (animate) { + overlay = getOverlayDrawable(mFontPreview, true); + } + if (mFontCard.isShowingEmptyView()) mFontCard.setEmptyViewEnabled(false); + + int pkgNameIdx = c.getColumnIndex(ThemesColumns.PKG_NAME); + String pkgName = pkgNameIdx >= 0 ? c.getString(pkgNameIdx) : mPkgName; + TypefaceHelperCache cache = TypefaceHelperCache.getInstance(); + ThemedTypefaceHelper helper = cache.getHelperForTheme(getActivity(), pkgName); + mTypefaceNormal = helper.getTypeface(Typeface.NORMAL); + mFontPreview.setTypeface(mTypefaceNormal); + if (!mPkgName.equals(pkgName) || (mPkgName.equals(pkgName) + && mBaseThemeSupportedComponents.contains(MODIFIES_FONTS))) { + mSelectedComponentsMap.put(MODIFIES_FONTS, pkgName); + setCardTitle(mFontCard, pkgName, getString(R.string.font_label)); + } + + if (animate) { + animateContentChange(R.id.font_preview_container, mFontPreview, overlay); + } + } + + protected void loadStyle(Cursor c, boolean animate) { + Drawable overlay = null; + if (animate) { + overlay = getOverlayDrawable(mStylePreview, true); + } + if (mStyleCard.isShowingEmptyView()) { + mStyleCard.setEmptyViewEnabled(false); + } + + int pkgNameIdx = c.getColumnIndex(ThemesColumns.PKG_NAME); + int styleIdx = c.getColumnIndex(PreviewColumns.STYLE_PREVIEW); + mStylePreview.setImageBitmap(Utils.loadBitmapBlob(c, styleIdx)); + if (pkgNameIdx > -1) { + String pkgName = c.getString(pkgNameIdx); + if (!mPkgName.equals(pkgName) || (mPkgName.equals(pkgName) + && mBaseThemeSupportedComponents.contains(MODIFIES_OVERLAYS))) { + mSelectedComponentsMap.put(MODIFIES_OVERLAYS, pkgName); + setCardTitle(mStyleCard, pkgName, + getString(R.string.style_label)); + } + } + if (animate) { + animateContentChange(R.id.style_card, mStylePreview, overlay); + } + } + + protected void loadBootAnimation(Cursor c) { + if (mBootAnimationCard.isShowingEmptyView()) { + mBootAnimationCard.setEmptyViewEnabled(false); + } + int pkgNameIdx = c.getColumnIndex(ThemesColumns.PKG_NAME); + if (mBootAnimation != null) { + String pkgName; + if (pkgNameIdx > -1) { + pkgName = c.getString(pkgNameIdx); + if (!mPkgName.equals(pkgName) || (mPkgName.equals(pkgName) + && mBaseThemeSupportedComponents.contains(MODIFIES_BOOT_ANIM))) { + mSelectedComponentsMap.put(MODIFIES_BOOT_ANIM, pkgName); + setCardTitle(mBootAnimationCard, pkgName, + getString(R.string.boot_animation_label)); + } + } else { + pkgName = mCurrentTheme.get(MODIFIES_BOOT_ANIM); + } + mBootAnimation.stop(); + new AnimationLoader(getActivity(), pkgName, mBootAnimation).execute(); + } + } + + protected void loadAudible(int type, Cursor c, boolean animate) { + ComponentCardView audibleContainer = null; + ImageView playPause = null; + String component = null; + int parentResId = 0; + switch (type) { + case RingtoneManager.TYPE_RINGTONE: + audibleContainer = mRingtoneCard; + playPause = mRingtonePlayPause; + component = MODIFIES_RINGTONES; + parentResId = R.id.ringtone_preview_container; + break; + case RingtoneManager.TYPE_NOTIFICATION: + audibleContainer = mNotificationCard; + playPause = mNotificationPlayPause; + component = MODIFIES_NOTIFICATIONS; + parentResId = R.id.notification_preview_container; + break; + case RingtoneManager.TYPE_ALARM: + audibleContainer = mAlarmCard; + playPause = mAlarmPlayPause; + component = MODIFIES_ALARMS; + parentResId = R.id.alarm_preview_container; + break; + } + if (audibleContainer == null) return; + + View content = audibleContainer.findViewById(R.id.content); + Drawable overlay = null; + if (animate) { + overlay = getOverlayDrawable(content, true); + } + if (audibleContainer.isShowingEmptyView()) { + audibleContainer.setEmptyViewEnabled(false); + } + + int pkgNameIdx = c.getColumnIndex(ThemesColumns.PKG_NAME); + int titleIdx = c.getColumnIndex(ThemesColumns.TITLE); + if (playPause == null) { + playPause = (ImageView) audibleContainer.findViewById(R.id.play_pause); + } + TextView title = (TextView) audibleContainer.findViewById(R.id.audible_name); + MediaPlayer mp = mMediaPlayers.get(playPause); + if (mp == null) { + mp = new MediaPlayer(); + } + String pkgName = c.getString(pkgNameIdx); + setCardTitle(audibleContainer, pkgName, getAudibleLabel(type)); + AudibleLoadingThread thread = new AudibleLoadingThread(getActivity(), type, pkgName, mp); + title.setText(c.getString(titleIdx)); + if (!mPkgName.equals(pkgName) || (mPkgName.equals(pkgName) + && mBaseThemeSupportedComponents.contains(component))) { + mSelectedComponentsMap.put(component, pkgName); + } + + playPause.setVisibility(View.VISIBLE); + playPause.setTag(mp); + mMediaPlayers.put(playPause, mp); + playPause.setOnClickListener(mPlayPauseClickListener); + mp.setOnCompletionListener(mPlayCompletionListener); + if (animate) { + animateContentChange(parentResId, content, overlay); + } + thread.start(); + } + + protected Drawable getOverlayDrawable(View v, boolean requiresTransparency) { + if (!v.isDrawingCacheEnabled()) v.setDrawingCacheEnabled(true); + Bitmap cache = v.getDrawingCache(true).copy( + requiresTransparency ? Config.ARGB_8888 : Config.RGB_565, false); + Drawable d = cache != null ? new BitmapDrawable(getResources(), cache) : null; + v.destroyDrawingCache(); + + return d; + } + + protected String getAudibleLabel(int type) { + switch (type) { + case RingtoneManager.TYPE_RINGTONE: + return getString(R.string.ringtone_label); + case RingtoneManager.TYPE_NOTIFICATION: + return getString(R.string.notification_label); + case RingtoneManager.TYPE_ALARM: + return getString(R.string.alarm_label); + } + return null; + } + + protected void setCardTitle(ComponentCardView card, String pkgName, String title) { + TextView tv = (TextView) card.findViewById(R.id.label); + if (Utils.getDefaultThemePackageName(getActivity()).equals(pkgName)) { + tv.setText(getString(R.string.default_tag_text) + " " + title); + } else { + tv.setText(title); + } + } + + protected void setAddComponentTitle(ComponentCardView card, String title) { + TextView tv = (TextView) card.findViewById(R.id.label); + tv.setText(getString(R.string.add_component_text) + " " + title); + } + + public static ComponentName[] getIconComponents(Context context) { + if (sIconComponents == null || sIconComponents.length == 0) { + sIconComponents = new ComponentName[]{COMPONENT_DIALER, COMPONENT_MESSAGING, + COMPONENT_CAMERA, COMPONENT_BROWSER}; + + PackageManager pm = context.getPackageManager(); + + // if device does not have telephony replace dialer and mms + if (!pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { + sIconComponents[0] = COMPONENT_CALENDAR; + sIconComponents[1] = COMPONENT_GALERY; + } else { + // decide on which dialer icon to use + try { + if (pm.getPackageInfo(DIALER_NEXT_PACKAGE, 0) != null) { + sIconComponents[0] = COMPONENT_DIALERNEXT; + } + } catch (PackageManager.NameNotFoundException e) { + // default to COMPONENT_DIALER + } + } + + if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)) { + sIconComponents[2] = COMPONENT_SETTINGS; + } else { + // decide on which camera icon to use + try { + if (pm.getPackageInfo(CAMERA_NEXT_PACKAGE, 0) != null) { + sIconComponents[2] = COMPONENT_CAMERANEXT; + } + } catch (PackageManager.NameNotFoundException e) { + // default to COMPONENT_CAMERA + } + } + + } + return sIconComponents; + } + + private void setupCardClickListeners(View parent) { + for (int i = 0; i < mCardIdsToComponentTypes.size(); i++) { + parent.findViewById(mCardIdsToComponentTypes.keyAt(i)) + .setOnClickListener(mCardClickListener); + } + } + + private View.OnClickListener mCardClickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + if (isShowingConfirmCancelOverlay() || isShowingCustomizeResetLayout()) return; + if (mActiveCardId > 0) { + // need to fade the newly selected card in if another was currently selected. + ((ComponentCardView) v).animateCardFadeIn(); + } + mActiveCardId = v.getId(); + String component = mCardIdsToComponentTypes.get(mActiveCardId); + // Only pass on mSelectedWallpaperComponentId if dealing with mods_launcher + long selectedComponentId = (ThemesColumns.MODIFIES_LAUNCHER.equals(component)) ? + mSelectedWallpaperComponentId : DEFAULT_COMPONENT_ID; + String pkgName = mSelectedComponentsMap.get(component); + if (component.equals(MODIFIES_LOCKSCREEN) && TextUtils.isEmpty(pkgName)) { + String liveLockScreenPkg = mSelectedComponentsMap.get(MODIFIES_LIVE_LOCK_SCREEN); + if (liveLockScreenPkg != null) { + pkgName = liveLockScreenPkg; + } + } + getChooserActivity().showComponentSelector(component, pkgName, selectedComponentId, v); + fadeOutNonSelectedCards(mActiveCardId); + stopMediaPlayers(); + } + }; + + private ConfirmCancelOverlay.OnOverlayDismissedListener mApplyCancelListener = + new ConfirmCancelOverlay.OnOverlayDismissedListener() { + @Override + public void onDismissed(boolean accepted) { + hideConfirmCancelOverlay(accepted); + } + }; + + private ConfirmCancelOverlay.OnOverlayDismissedListener mDeleteConfirmationListener = + new ConfirmCancelOverlay.OnOverlayDismissedListener() { + @Override + public void onDismissed(boolean accepted) { + if (accepted) uninstallTheme(); + hideConfirmCancelOverlay(); + } + }; + + private ConfirmCancelOverlay.OnOverlayDismissedListener mResetConfirmationListener = + new ConfirmCancelOverlay.OnOverlayDismissedListener() { + @Override + public void onDismissed(boolean accepted) { + if (accepted) resetTheme(); + hideConfirmCancelOverlay(); + } + }; + + private View.OnClickListener mCustomizeResetClickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + if (v == mDismissButton) { + hideCustomizeResetLayout(CustomizeResetAction.Dismiss); + } else if (v == mResetButton) { + hideCustomizeResetLayout(CustomizeResetAction.Reset); + } else if (v == mCustomizeButton) { + hideCustomizeResetLayout(CustomizeResetAction.Customize); + } + } + }; + + protected void loadComponentFromPackage(String pkgName, String component, long componentId) { + Bundle args = new Bundle(); + args.putString(ARG_PACKAGE_NAME, pkgName); + args.putLong(ARG_COMPONENT_ID, componentId); + int loaderId = LOADER_ID_INVALID; + if (MODIFIES_STATUS_BAR.equals(component)) { + loaderId = LOADER_ID_STATUS_BAR; + } else if (MODIFIES_FONTS.equals(component)) { + loaderId = LOADER_ID_FONT; + } else if (MODIFIES_ICONS.equals(component)) { + loaderId = LOADER_ID_ICONS; + } else if (MODIFIES_NAVIGATION_BAR.equals(component)) { + loaderId = LOADER_ID_NAVIGATION_BAR; + } else if (MODIFIES_LAUNCHER.equals(component)) { + if (pkgName != null) { + if (TextUtils.isEmpty(pkgName)) { + mWallpaperCard.setWallpaper(null); + mSelectedComponentsMap.put(ThemesColumns.MODIFIES_LAUNCHER, WALLPAPER_NONE); + setCardTitle(mWallpaperCard, WALLPAPER_NONE, + getString(R.string.wallpaper_label)); + getChooserActivity().showSaveApplyButton(); + } else if (ComponentSelector.EXTERNAL_WALLPAPER.equals(pkgName)) { + // Check if we have READ_EXTERNAL_STORAGE permission and if not request it, + // otherwise let the user pick an image + if (getActivity().checkSelfPermission( + READ_EXTERNAL_STORAGE) != PERMISSION_GRANTED) { + mAfterPermissionGrantedRunnable = new Runnable() { + @Override + public void run() { + getChooserActivity().pickExternalWallpaper(); + setCardTitle(mWallpaperCard, WALLPAPER_NONE, + getString(R.string.wallpaper_label)); + } + }; + requestPermissions(new String[]{READ_EXTERNAL_STORAGE}, + PERMISSION_REQUEST); + } else { + getChooserActivity().pickExternalWallpaper(); + setCardTitle(mWallpaperCard, WALLPAPER_NONE, + getString(R.string.wallpaper_label)); + } + } else { + loaderId = LOADER_ID_WALLPAPER; + } + } + } else if (MODIFIES_LOCKSCREEN.equals(component) + || MODIFIES_LIVE_LOCK_SCREEN.equals(component)) { + if (pkgName != null && TextUtils.isEmpty(pkgName)) { + mLockScreenCard.setWallpaper(null); + mSelectedComponentsMap.put(ThemesColumns.MODIFIES_LOCKSCREEN, LOCKSCREEN_NONE); + + if(mSelectedComponentsMap.containsKey(MODIFIES_LIVE_LOCK_SCREEN)) { + mSelectedComponentsMap.put(MODIFIES_LIVE_LOCK_SCREEN, LOCKSCREEN_NONE); + } + setCardTitle(mLockScreenCard, WALLPAPER_NONE, + getString(R.string.lockscreen_label)); + if (mLockScreenCard.isShowingEmptyView()) { + mLockScreenCard.setEmptyViewEnabled(false); + } + getChooserActivity().showSaveApplyButton(); + } else if (ComponentSelector.EXTERNAL_WALLPAPER.equals(pkgName)) { + // Check if we have READ_EXTERNAL_STORAGE permission and if not request it, + // otherwise let the user pick an image + if (getActivity().checkSelfPermission( + READ_EXTERNAL_STORAGE) != PERMISSION_GRANTED) { + mAfterPermissionGrantedRunnable = new Runnable() { + @Override + public void run() { + getChooserActivity().pickExternalLockscreen(); + setCardTitle(mLockScreenCard, WALLPAPER_NONE, + getString(R.string.lockscreen_label)); + } + }; + requestPermissions(new String[] {READ_EXTERNAL_STORAGE}, + PERMISSION_REQUEST); + } else { + getChooserActivity().pickExternalLockscreen(); + setCardTitle(mLockScreenCard, WALLPAPER_NONE, + getString(R.string.lockscreen_label)); + } + } else if (ComponentSelector.MOD_LOCK.equals(pkgName)) { + startLiveLockScreenSettings(); + } else { + if (MODIFIES_LIVE_LOCK_SCREEN.equals(component)) { + loaderId = LOADER_ID_LIVE_LOCK_SCREEN; + } else { + loaderId = LOADER_ID_LOCKSCREEN; + } + } + } else if (MODIFIES_OVERLAYS.equals(component)) { + loaderId = LOADER_ID_STYLE; + } else if (MODIFIES_BOOT_ANIM.equals(component)) { + loaderId = LOADER_ID_BOOT_ANIMATION; + } else if (MODIFIES_RINGTONES.equals(component)) { + loaderId = LOADER_ID_RINGTONE; + } else if (MODIFIES_NOTIFICATIONS.equals(component)) { + loaderId = LOADER_ID_NOTIFICATION; + } else if (MODIFIES_ALARMS.equals(component)) { + loaderId = LOADER_ID_ALARM; + } else { + return; + } + + if (loaderId != LOADER_ID_INVALID) { + getLoaderManager().restartLoader(loaderId, args, ThemeFragment.this); + } + } + + private OnItemClickedListener mOnComponentItemClicked = new OnItemClickedListener() { + @Override + public void onItemClicked(String pkgName, long componentId, Bundle params) { + String component = mSelector.getComponentType(); + if (MODIFIES_LOCKSCREEN.equals(component) && params != null) { + boolean isLiveLockView = params.getBoolean( + ComponentSelector.IS_LIVE_LOCK_SCREEN_VIEW,false); + if (isLiveLockView) { + //We got here because an live lock thubmnail view was clicked. We need to + //replace the component to load the proper data from the provider. + component = MODIFIES_LIVE_LOCK_SCREEN; + } + } + loadComponentFromPackage(pkgName, component, componentId); + } + }; + + private void fadeOutNonSelectedCards(int selectedCardId) { + for (int i = 0; i < mCardIdsToComponentTypes.size(); i++) { + if (mCardIdsToComponentTypes.keyAt(i) != selectedCardId) { + ComponentCardView card = (ComponentCardView) getView().findViewById( + mCardIdsToComponentTypes.keyAt(i)); + if (card != null) card.animateCardFadeOut(); + } + } + } + + protected void animateContentChange(int parentId, View viewToAnimate, Drawable overlay) { + ((ComponentCardView) getView().findViewById(parentId)) + .animateContentChange(viewToAnimate, overlay, ANIMATE_COMPONENT_CHANGE_DURATION); + } + + private Runnable mApplyThemeRunnable = new Runnable() { + @Override + public void run() { + final Context context = getActivity(); + if (context != null) { + // Post this on mHandler so the client is added and removed from the same + // thread + mHandler.post(new Runnable() { + @Override + public void run() { + final Map componentsToApply = getComponentsToApply(); + if (componentsToApply != null && componentsToApply.size() > 0) { + final Map fullMap + = fillMissingComponentsWithDefault(componentsToApply); + ThemeManager tm = getThemeManager(); + if (tm != null) { + try { + tm.addClient(ThemeFragment.this); + } catch (IllegalArgumentException e) { + /* ignore since this means we already have a listener added */ + } + ThemeChangeRequest request = + getThemeChangeRequestForComponents(fullMap); + boolean value = request.getReqeustType(). + equals(RequestType.USER_REQUEST_MIXNMATCH); + + tm.requestThemeChange(request, !value); + } + mApplyThemeOnPopulated = false; + } else { + onFinish(true); + } + } + }); + } + } + }; + + protected Map fillMissingComponentsWithDefault( + Map originalMap) { + HashMap newMap = new HashMap(); + newMap.putAll(originalMap); + Map defaultMap = getEmptyComponentsMap(); + for(Map.Entry entry : defaultMap.entrySet()) { + String component = entry.getKey(); + String defaultPkg = entry.getValue(); + if (!newMap.containsKey(component)) { + newMap.put(component, defaultPkg); + } + } + return newMap; + } + + protected Map getEmptyComponentsMap() { + List componentsList = ThemeUtils.getAllComponents(); + Map defaultMap = new HashMap<>(componentsList.size()); + for (String component : componentsList) { + defaultMap.put(component, ""); + } + return defaultMap; + } + + /** + * This is the method that will be called when applying a theme and the idea is to override + * it in MyThemeFragment and pass in a different RequestType, once we have a type that indicates + * the user is mixing and matching instead of applying an entire theme. + * @param componentMap + * @return + */ + protected ThemeChangeRequest getThemeChangeRequestForComponents( + Map componentMap) { + return getThemeChangeRequestForComponents(componentMap, RequestType.USER_REQUEST); + } + + protected ThemeChangeRequest getThemeChangeRequestForComponents( + Map componentMap, RequestType requestType) { + ThemeChangeRequest.Builder builder = new ThemeChangeRequest.Builder(); + for (String component : componentMap.keySet()) { + builder.setComponent(component, componentMap.get(component)); + } + builder.setRequestType(requestType); + if (mThemeVersion >= 3) { + builder.setWallpaperId(mSelectedWallpaperComponentId != null + ? mSelectedWallpaperComponentId + : DEFAULT_COMPONENT_ID); + } + return builder.build(); + } + + protected Map getComponentsToApply() { + return mSelectedComponentsMap; + } + + private Runnable mApplyExternalWallpaperRunnable = new Runnable() { + @Override + public void run() { + // If an external image was selected for the wallpaper, we need to + // set that manually. + if (mExternalWallpaperUri != null) { + WallpaperManager wm = + WallpaperManager.getInstance(getActivity()); + final Context context = getActivity(); + final Resources res = context.getResources(); + final Point size = new Point(wm.getDesiredMinimumWidth(), + wm.getDesiredMinimumHeight()); + Bitmap bmp = WallpaperUtils.createPreview(size, context, mExternalWallpaperUri, + null, res, 0, 0, false); + try { + wm.setBitmap(bmp); + } catch (Exception e) { + Log.e(TAG, "Unable to set external wallpaper", e); + } + } + } + }; + + private Runnable mApplyExternalLockscreenRunnable = new Runnable() { + @Override + public void run() { + // If an external image was selected for the wallpaper, we need to + // set that manually. + if (mExternalLockscreenUri != null) { + WallpaperManager wm = + WallpaperManager.getInstance(getActivity()); + final Context context = getActivity(); + final Resources res = context.getResources(); + final Point size = new Point(); + ((Activity) context).getWindowManager().getDefaultDisplay().getRealSize(size); + Bitmap bmp = WallpaperUtils.createPreview(size, context, mExternalLockscreenUri, + null, res, 0, 0, false); + try { + wm.setKeyguardBitmap(bmp); + } catch (Exception e) { + Log.e(TAG, "Unable to set external lockscreen wallpaper", e); + } + } + } + }; + + class RestoreLockScreenCardRunnable implements Runnable { + + final private boolean mWasShowingNone; + private String mCurrentLockScreenPkgName; + + public RestoreLockScreenCardRunnable(boolean w, String pkgName) { + mWasShowingNone = w; + mCurrentLockScreenPkgName = pkgName; + } + + @Override + public void run() { + if (!TextUtils.isEmpty(mCurrentLockScreenPkgName)) { + loadComponentFromPackage(mCurrentLockScreenPkgName, + MODIFIES_LOCKSCREEN, 0); + } else if (mWasShowingNone) { + mLockScreenCard.setWallpaper(null); + TextView none = (TextView) mLockScreenCard.findViewById( + R.id.none); + if (none != null) { + none.setVisibility(View.VISIBLE); + } + mLockScreenCard.setEmptyViewEnabled(false); + } else { + mLockScreenCard.clearWallpaper(); + TextView none = (TextView) mLockScreenCard.findViewById( + R.id.none); + if (none != null) { + none.setVisibility(View.GONE); + } + mLockScreenCard.setEmptyViewEnabled(true); + setAddComponentTitle(mLockScreenCard, getString(R.string.lockscreen_label)); + } + } + } + + protected void applyTheme() { + if (mExternalWallpaperUri == null && mExternalLockscreenUri == null && + (mSelectedComponentsMap == null || mSelectedComponentsMap.size() <= 0)) { + return; + } + final Map componentsToApply = getComponentsToApply(); + boolean isLLSEnabled = CMSettings.Secure.getInt(getActivity().getContentResolver(), + LIVE_LOCK_SCREEN_ENABLED, 0) == 1; + if (!TextUtils.isEmpty(componentsToApply.get(MODIFIES_LIVE_LOCK_SCREEN)) && !isLLSEnabled) { + AlertDialog d = new AlertDialog.Builder(getActivity(), + android.R.style.Theme_Material_Dialog) + .setTitle(R.string.enable_live_lock_screen_dialog_title) + .setMessage(R.string.enable_live_lock_screen_dialog_message) + .setPositiveButton(R.string.enable_live_lock_screen_dialog_positive_btn_text, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + CMSettings.Secure.putInt(getActivity().getContentResolver(), + LIVE_LOCK_SCREEN_ENABLED, 1); + getChooserActivity().themeChangeStart(); + animateProgressIn(mApplyThemeRunnable); + } + }) + .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + mSelectedComponentsMap.remove(MODIFIES_LIVE_LOCK_SCREEN); + boolean wasNone = false; + if (TextUtils.equals("", mSelectedComponentsMap.get( + MODIFIES_LOCKSCREEN))) { + if (!TextUtils.isEmpty(mCurrentTheme.get(MODIFIES_LOCKSCREEN))) { + //The map entry was set to empty string because there's a + //lockscreen currently applied and setting this entry to empty + //would instruct the ThemeManager to clear the currently applied + //lockscreen, but the user decided not to enable LLS so we need + //to abort this change + mSelectedComponentsMap.put(MODIFIES_LOCKSCREEN, + mCurrentTheme.get(MODIFIES_LOCKSCREEN)); + } else { + wasNone = true; + } + } + //Restore the lockscreen card to its previous state + mHandler.post(new RestoreLockScreenCardRunnable(wasNone, + mCurrentTheme.get(MODIFIES_LOCKSCREEN))); + + //Did the user make more changes? + boolean modLLS = componentsToApply.containsKey( + MODIFIES_LIVE_LOCK_SCREEN); + boolean modLockscreen = componentsToApply.containsKey( + MODIFIES_LOCKSCREEN); + if (modLLS && ((modLockscreen && componentsToApply.size() > 2) || + (!modLockscreen && componentsToApply.size() > 1))) { + getChooserActivity().themeChangeStart(); + animateProgressIn(mApplyThemeRunnable); + } + } + }) + .setCancelable(false) + .create(); + d.setCanceledOnTouchOutside(false); + d.show(); + } else { + getChooserActivity().themeChangeStart(); + animateProgressIn(mApplyThemeRunnable); + } + } + + /** + * Use when applyTheme() might be too early. ie mSelectedComponentsMap is not pop. yet + * @param pkgName Only used in MyThemeFragment to apply components on top of current theme + * @param components Optional list of components to apply. + */ + protected void applyThemeWhenPopulated(String pkgName, List components) { + mApplyThemeOnPopulated = true; + } + + private void animateProgressIn(Runnable endAction) { + mProgress.setVisibility(View.VISIBLE); + mProgress.setProgress(0); + float pivotX = mTitleLayout.getWidth() - + getResources().getDimensionPixelSize(R.dimen.apply_progress_padding); + ScaleAnimation scaleAnim = new ScaleAnimation(0f, 1f, 1f, 1f, + pivotX, 0f); + scaleAnim.setDuration(ANIMATE_PROGRESS_IN_DURATION); + + mTitleLayout.animate() + .translationXBy(-(pivotX / 3)) + .alpha(0f) + .setDuration(ANIMATE_TITLE_OUT_DURATION) + .setInterpolator(new AccelerateInterpolator()) + .withEndAction(endAction).start(); + mProgress.startAnimation(scaleAnim); + } + + private void animateProgressOut() { + mProgress.setVisibility(View.VISIBLE); + float pivotX = mTitleLayout.getWidth() - + getResources().getDimensionPixelSize(R.dimen.apply_progress_padding); + ScaleAnimation scaleAnim = new ScaleAnimation(1f, 0f, 1f, 1f, + pivotX, 0f); + scaleAnim.setDuration(ANIMATE_PROGRESS_OUT_DURATION); + scaleAnim.setFillAfter(false); + scaleAnim.setAnimationListener(new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + } + + @Override + public void onAnimationEnd(Animation animation) { + mProgress.setVisibility(View.GONE); + if (mThemeResetting) { + mThemeResetting = false; + mThemeTagLayout.setCustomizedTagEnabled(false); + } + } + + @Override + public void onAnimationRepeat(Animation animation) { + } + }); + + mTitleLayout.animate() + .translationXBy((pivotX / 3)) + .alpha(1f) + .setDuration(ANIMATE_TITLE_IN_DURATION) + .setInterpolator(new AccelerateInterpolator()) + .start(); + mProgress.startAnimation(scaleAnim); + if (mThemeResetting) mReset.setVisibility(View.GONE); + } + + private void animateContentIn() { + if (mSkipLoadingAnim) { + return; + } + AnimatorSet set = new AnimatorSet(); + set.setDuration(ANIMATE_TITLE_IN_DURATION); + set.play(ObjectAnimator.ofFloat(mLoadingView, "alpha", 1f, 0f)) + .with(ObjectAnimator.ofFloat(mTitleLayout, "alpha", 0f, 1f)); + set.addListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animation) { + } + + @Override + public void onAnimationEnd(Animator animation) { + mLoadingView.setVisibility(View.GONE); + } + + @Override + public void onAnimationCancel(Animator animation) { + } + + @Override + public void onAnimationRepeat(Animator animation) { + } + }); + set.start(); + } + + private void disableActionButtons() { + mCustomize.setEnabled(false); + mDelete.setEnabled(false); + mReset.setEnabled(false); + } + + private void enableActionButtons() { + mCustomize.setEnabled(true); + mDelete.setEnabled(true); + mReset.setEnabled(true); + } + + public boolean isShowingConfirmCancelOverlay() { + return mConfirmCancelOverlay.getVisibility() == View.VISIBLE; + } + + public void showApplyThemeOverlay() { + if (mConfirmCancelOverlay.getVisibility() == View.VISIBLE) return; + mConfirmCancelOverlay.setTitle(R.string.apply_theme_overlay_title); + mConfirmCancelOverlay.setBackgroundColor(getActivity().getResources() + .getColor(R.color.apply_overlay_background)); + mConfirmCancelOverlay.setOnOverlayDismissedListener(mApplyCancelListener); + getChooserActivity().lockPager(); + ViewPropertyAnimator anim = mConfirmCancelOverlay.animate(); + mConfirmCancelOverlay.setVisibility(View.VISIBLE); + mConfirmCancelOverlay.setAlpha(0f); + anim.setListener(null); + anim.setDuration(ANIMATE_APPLY_LAYOUT_DURATION); + anim.alpha(1f).start(); + + if (mIsLegacyTheme) { + // Display cm11 theme warning message + TextView tv = (TextView) mConfirmCancelOverlay.findViewById(R.id.warning_message); + tv.setVisibility(View.VISIBLE); + tv.setText(String.format(getString(R.string.legacy_theme_warning), mTitle.getText())); + } else if (Utils.hasPerAppThemesApplied(getActivity())) { + // Display per app theme changes will be removed warning + TextView tv = (TextView) mConfirmCancelOverlay.findViewById(R.id.warning_message); + tv.setVisibility(View.VISIBLE); + tv.setText(String.format(getString(R.string.per_app_theme_removal_warning), + mTitle.getText())); + } + + disableActionButtons(); + mClickableView.setSoundEffectsEnabled(false); + } + + public void showDeleteThemeOverlay() { + if (mConfirmCancelOverlay.getVisibility() == View.VISIBLE) return; + mConfirmCancelOverlay.setTitle(R.string.delete_theme_overlay_title); + mConfirmCancelOverlay.setBackgroundColor(getActivity().getResources() + .getColor(R.color.delete_overlay_background)); + mConfirmCancelOverlay.setOnOverlayDismissedListener(mDeleteConfirmationListener); + getChooserActivity().lockPager(); + ViewPropertyAnimator anim = mConfirmCancelOverlay.animate(); + mConfirmCancelOverlay.setVisibility(View.VISIBLE); + mConfirmCancelOverlay.setAlpha(0f); + anim.setListener(null); + anim.setDuration(ANIMATE_APPLY_LAYOUT_DURATION); + anim.alpha(1f).start(); + + disableActionButtons(); + mClickableView.setSoundEffectsEnabled(false); + } + + public void showResetThemeOverlay() { + if (mConfirmCancelOverlay.getVisibility() == View.VISIBLE) return; + mConfirmCancelOverlay.setTitle(R.string.reset_theme_overlay_title); + mConfirmCancelOverlay.setBackgroundColor(getActivity().getResources() + .getColor(R.color.apply_overlay_background)); + mConfirmCancelOverlay.setOnOverlayDismissedListener(mResetConfirmationListener); + getChooserActivity().lockPager(); + ViewPropertyAnimator anim = mConfirmCancelOverlay.animate(); + mConfirmCancelOverlay.setVisibility(View.VISIBLE); + mConfirmCancelOverlay.setAlpha(0f); + anim.setListener(null); + anim.setDuration(ANIMATE_APPLY_LAYOUT_DURATION); + anim.alpha(1f).start(); + + disableActionButtons(); + mClickableView.setSoundEffectsEnabled(false); + } + + public void hideConfirmCancelOverlay() { + hideConfirmCancelOverlay(false); + } + + /** + * Hides the apply theme layout overlay and can apply the selected theme + * when the animation is finished. + * @param applyThemeWhenFinished If true, the current theme will be applied. + */ + private void hideConfirmCancelOverlay(final boolean applyThemeWhenFinished) { + getChooserActivity().unlockPager(); + ViewPropertyAnimator anim = mConfirmCancelOverlay.animate(); + mConfirmCancelOverlay.setVisibility(View.VISIBLE); + anim.setDuration(ANIMATE_APPLY_LAYOUT_DURATION); + anim.alpha(0f).start(); + anim.setListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animation) { + } + + @Override + public void onAnimationEnd(Animator animation) { + mConfirmCancelOverlay.setVisibility(View.GONE); + if (applyThemeWhenFinished) applyTheme(); + } + + @Override + public void onAnimationCancel(Animator animation) { + } + + @Override + public void onAnimationRepeat(Animator animation) { + } + }); + + enableActionButtons(); + mClickableView.setSoundEffectsEnabled(true); + } + + public boolean isShowingCustomizeResetLayout() { + return mCustomizeResetLayout.getVisibility() == View.VISIBLE; + } + + public void showCustomizeResetLayout() { + if (mCustomizeResetLayout.getVisibility() == View.VISIBLE) return; + if (!mThemeTagLayout.isCustomizedTagEnabled()) { + mResetButton.setEnabled(false); + } else { + mResetButton.setEnabled(true); + } + getChooserActivity().lockPager(); + ViewPropertyAnimator anim = mCustomizeResetLayout.animate(); + mCustomizeResetLayout.setVisibility(View.VISIBLE); + mCustomizeResetLayout.setAlpha(0f); + anim.setListener(null); + anim.setDuration(ANIMATE_APPLY_LAYOUT_DURATION); + anim.alpha(1f).start(); + + disableActionButtons(); + mClickableView.setSoundEffectsEnabled(false); + } + + public void hideCustomizeResetLayout() { + hideCustomizeResetLayout(CustomizeResetAction.Dismiss); + } + + private void hideCustomizeResetLayout(final CustomizeResetAction action) { + getChooserActivity().unlockPager(); + ViewPropertyAnimator anim = mCustomizeResetLayout.animate(); + mCustomizeResetLayout.setVisibility(View.VISIBLE); + anim.setDuration(ANIMATE_APPLY_LAYOUT_DURATION); + anim.alpha(0f).start(); + anim.setListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animation) { + } + + @Override + public void onAnimationEnd(Animator animation) { + mCustomizeResetLayout.setVisibility(View.GONE); + switch (action) { + case Customize: + getChooserActivity().expand(); + break; + case Reset: + resetTheme(); + break; + } + } + + @Override + public void onAnimationCancel(Animator animation) { + } + + @Override + public void onAnimationRepeat(Animator animation) { + } + }); + + enableActionButtons(); + mClickableView.setSoundEffectsEnabled(true); + } + + public void showThemeTagLayout() { + mThemeTagLayout.setVisibility(View.VISIBLE); + mThemeTagLayout.animate().alpha(1f).setStartDelay(ANIMATE_START_DELAY).start(); + } + + public void hideThemeTagLayout() { + mThemeTagLayout.setAlpha(0f); + mThemeTagLayout.setVisibility(View.GONE); + } + + public void hideProcessingOverlay() { + mProcessingThemeLayout.animate().alpha(0).withEndAction(new Runnable() { + @Override + public void run() { + mProcessingThemeLayout.setVisibility(View.GONE); + } + }).setDuration(ANIMATE_APPLY_LAYOUT_DURATION).start(); + mCustomize.setVisibility(View.VISIBLE); + mCustomize.setAlpha(0f); + mCustomize.animate().alpha(1f).setDuration(ANIMATE_APPLY_LAYOUT_DURATION).start(); + if (mDelete.getVisibility() != View.GONE) { + mDelete.setVisibility(View.VISIBLE); + mDelete.setAlpha(0f); + mDelete.animate().alpha(1f).setDuration(ANIMATE_APPLY_LAYOUT_DURATION).start(); + } + + enableActionButtons(); + mClickableView.setSoundEffectsEnabled(true); + } + + public void fadeInCards() { + for (int i = 0; i < mCardIdsToComponentTypes.size(); i++) { + final int key = mCardIdsToComponentTypes.keyAt(i); + if (key != mActiveCardId) { + ComponentCardView card = (ComponentCardView) getView().findViewById(key); + if (card != null) card.animateCardFadeIn(); + } + } + mActiveCardId = -1; + } + + public boolean componentsChanged() { + // If an external wallpaper/ls are set then something changed! + if (mExternalWallpaperUri != null || mExternalLockscreenUri != null) return true; + + for (String key : mSelectedComponentsMap.keySet()) { + if (!mPkgName.equals(mSelectedComponentsMap.get(key))) { + return true; + } + if (ThemesColumns.MODIFIES_LAUNCHER.equals(key) && + mCurrentWallpaperComponentId.value != mSelectedWallpaperComponentId) { + return true; + } + } + return false; + } + + protected boolean isThemeCustomized() { + final String themePkgName = getThemePackageName(); + for (String key : mSelectedComponentsMap.keySet()) { + final String selectedPkgName = mSelectedComponentsMap.get(key); + if (!themePkgName.equals(selectedPkgName)) { + return true; + } + if (mBaseThemeSupportedComponents.size() > 0 && + !mBaseThemeSupportedComponents.contains(key)) { + return true; + } + } + // finally check if we're missing anything from mBaseThemeSupportedComponents + for (String component : mBaseThemeSupportedComponents) { + if (!mSelectedComponentsMap.containsKey(component)) return true; + } + return false; + } + + public void clearChanges() { + mSelectedComponentsMap.clear(); + mExternalWallpaperUri = null; + mExternalLockscreenUri = null; + View none = mLockScreenCard.findViewById(R.id.none); + if (none != null && none.getVisibility() == View.VISIBLE) { + none.setVisibility(View.GONE); + } + TextView tv = (TextView) mLockScreenCard.findViewById(R.id.label); + if (tv != null) { + tv.setAlpha(1f); + tv.setBackgroundResource(R.drawable.wallpaper_label_bg); + } + getLoaderManager().restartLoader(LOADER_ID_ALL, null, ThemeFragment.this); + } + + public String getThemePackageName() { + if (mPkgName == null) { + // check if the package name is defined in the arguments bundle + Bundle bundle = getArguments(); + if (bundle != null) { + mPkgName = bundle.getString(ARG_PACKAGE_NAME); + } + } + return mPkgName; + } + + private void uninstallTheme() { + getChooserActivity().uninstallTheme(mPkgName); + } + + public void setCurrentTheme(Map currentTheme, + MutableLong currentWallpaperComponentId) { + mCurrentTheme = currentTheme; + mCurrentWallpaperComponentId = currentWallpaperComponentId; + } + + /** + * Slides the scrollview content up and adds a space view at the bottom + * of mAdditionalCards so all content can be visible above the selector. + * + * We are using a ValueAnimator here to scroll the content rather than calling + * mScrollView.smoothScrollBy() since the speed of that animation cannot be customized. + * @param yDelta + * @param selectorHeight + */ + public void slideContentIntoView(final int yDelta, int selectorHeight) { + Space space = (Space) mAdditionalCards.findViewById(ADDITIONAL_CONTENT_SPACE_ID); + if (space == null) { + // No space view yet so lets create it one + space = new Space(getActivity()); + space.setId(ADDITIONAL_CONTENT_SPACE_ID); + mAdditionalCards.addView(space, + new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, + selectorHeight)); + } else { + // Space view already exists so just update the LayoutParams + LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) space.getLayoutParams(); + params.height = selectorHeight; + space.setLayoutParams(params); + } + final int startY = mScrollView.getScrollY(); + final ValueAnimator scrollAnimator = + ValueAnimator.ofInt(startY, startY + yDelta); + scrollAnimator.setDuration(SLIDE_CONTENT_ANIM_DURATION); + scrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + int value = (Integer) animation.getAnimatedValue(); + mScrollView.scrollTo(0, value); + } + }); + scrollAnimator.start(); + } + + public Map getSelectedComponentsMap() { + return mSelectedComponentsMap; + } + + /** + * Slides the scrollview content down and removes a space view at the bottom + * of mAdditionalCards. + * + * We are using a ValueAnimator here to scroll the content rather than calling + * mScrollView.smoothScrollBy() since the speed of that animation cannot be customized. + * @param yDelta + */ + public void slideContentBack(int yDelta) { + final int startY = mScrollView.getScrollY(); + final ValueAnimator scrollAnimator = + ValueAnimator.ofInt(startY, startY + yDelta); + scrollAnimator.setDuration(SLIDE_CONTENT_ANIM_DURATION); + scrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + int value = (Integer) animation.getAnimatedValue(); + mScrollView.scrollTo(0, value); + } + }); + scrollAnimator.addListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animation) { + } + + @Override + public void onAnimationEnd(Animator animation) { + View space = mAdditionalCards.findViewById(ADDITIONAL_CONTENT_SPACE_ID); + if (space != null) mAdditionalCards.removeView(space); + } + + @Override + public void onAnimationCancel(Animator animation) { + } + + @Override + public void onAnimationRepeat(Animator animation) { + } + }); + scrollAnimator.start(); + } + + public void showLockScreenCard() { + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + final int scrollToY = mStatusBarCard.getMeasuredHeight() + + mFontCard.getMeasuredHeight() + mIconCard.getMeasuredHeight() + + mNavBarCard.getMeasuredHeight() + mWallpaperCard.getMeasuredHeight() / 2; + final ValueAnimator scrollAnimator = ValueAnimator.ofInt(0, scrollToY); + scrollAnimator.setDuration(LOCK_SCREEN_CARD_SCROLL_ANIMATION_DURATION); + scrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + int value = (Integer) animation.getAnimatedValue(); + mScrollView.scrollTo(0, value); + } + }); + scrollAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + mCardClickListener.onClick(mLockScreenCard); + } + }); + scrollAnimator.start(); + } + }, SHOW_LOCK_SCREEN_CARD_DELAY); + } + + protected void startLiveLockScreenSettings() { + Intent intent = new Intent(cyanogenmod.content.Intent.ACTION_OPEN_LIVE_LOCKSCREEN_SETTINGS); + try { + startActivity(intent); + } catch (ActivityNotFoundException e) { + // TODO: inform user that this action failed (Toast?) + } + } + + class AnimationLoader extends AsyncTask { + Context mContext; + String mPkgName; + BootAniImageView mBootAnim; + + public AnimationLoader(Context context, String pkgName, BootAniImageView bootAnim) { + mContext = context; + mPkgName = pkgName; + mBootAnim = bootAnim; + } + + @Override + protected void onPreExecute() { + super.onPreExecute(); + } + + @Override + protected Boolean doInBackground(Void... params) { + if (mContext == null) { + return Boolean.FALSE; + } + ZipFile zip = null; + if (ThemeConfig.SYSTEM_DEFAULT.equals(mPkgName)) { + try { + zip = new ZipFile(new File(BootAnimationHelper.SYSTEM_BOOT_ANI_PATH)); + } catch (Exception e) { + Log.w(TAG, "Unable to load boot animation", e); + return Boolean.FALSE; + } + } else { + // check if the bootanimation is cached + File f = new File(mContext.getCacheDir(), + mPkgName + BootAnimationHelper.CACHED_SUFFIX); + if (!f.exists()) { + // go easy on cache storage and clear out any previous boot animations + BootAnimationHelper.clearBootAnimationCache(mContext); + try { + Context themeContext = mContext.createPackageContext(mPkgName, 0); + AssetManager am = themeContext.getAssets(); + InputStream is = am.open("bootanimation/bootanimation.zip"); + FileUtils.copyToFile(is, f); + is.close(); + } catch (Exception e) { + Log.w(TAG, "Unable to load boot animation", e); + return Boolean.FALSE; + } + } + try { + zip = new ZipFile(f); + } catch (IOException e) { + Log.w(TAG, "Unable to load boot animation", e); + return Boolean.FALSE; + } + } + if (zip != null) { + mBootAnim.setBootAnimation(zip); + } else { + return Boolean.FALSE; + } + return Boolean.TRUE; + } + + @Override + protected void onPostExecute(Boolean isSuccess) { + super.onPostExecute(isSuccess); + if (isSuccess) { + mBootAnim.start(); + } + } + } + + class AudibleLoadingThread extends Thread { + private Context mContext; + private int mType; + private String mPkgName; + private MediaPlayer mPlayer; + + public AudibleLoadingThread(Context context, int type, String pkgName, MediaPlayer mp) { + super(); + mContext = context; + mType = type; + mPkgName = pkgName; + mPlayer = mp; + } + + @Override + public void run() { + try { + AudioUtils.loadThemeAudible(mContext, mType, mPkgName, mPlayer); + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, "Unable to load sound for " + mPkgName, e); + } + } + } +} diff --git a/src/org/cyanogenmod/theme/chooser2/WallpaperCardView.java b/src/org/cyanogenmod/theme/chooser2/WallpaperCardView.java new file mode 100644 index 0000000..74c39f5 --- /dev/null +++ b/src/org/cyanogenmod/theme/chooser2/WallpaperCardView.java @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2016 Cyanogen, Inc. + * Copyright (C) 2016 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cyanogenmod.theme.chooser2; + +import android.animation.Animator; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewOverlay; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +public class WallpaperCardView extends ComponentCardView { + protected ImageView mImage; + protected TextView mLabel; + + public WallpaperCardView(Context context) { + this(context, null); + } + + public WallpaperCardView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public WallpaperCardView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.WallpaperCardView); + String labelText = a.getString(R.styleable.WallpaperCardView_labelText); + a.recycle(); + + setOrientation(VERTICAL); + + setBackgroundResource(R.drawable.card_bg); + + LayoutInflater inflater = LayoutInflater.from(mContext); + FrameLayout frameLayout = + (FrameLayout) inflater.inflate(R.layout.wallpaper_card, this, false); + addView(frameLayout); + mLabel = (TextView) frameLayout.findViewById(R.id.label); + mImage = (ImageView) frameLayout.findViewById(R.id.image); + + mLabel.setText(labelText); + } + + public void setWallpaper(Drawable drawable) { + mImage.setImageDrawable(drawable); + View none = findViewById(R.id.none); + if (drawable == null) { + setBackgroundResource(R.drawable.card_wallpapertoggled_bg); + if (none != null) { + none.setVisibility(View.VISIBLE); + } + if (mLabel != null) { + mLabel.setBackgroundResource(0); + } + } else { + setBackgroundResource(0); + + if (none != null) { + none.setVisibility(View.GONE); + } + if (mLabel != null) { + mLabel.setBackgroundResource(R.drawable.wallpaper_label_bg); + } + } + } + + public void clearWallpaper() { + mImage.setImageDrawable(null); + setBackgroundResource(R.drawable.card_bg); + } + + public Drawable getWallpaperDrawable() { + return mImage.getDrawable(); + } + + @Override + public void expand(boolean showLabel) { + setEnabled(true); + } + + @Override + public void collapse() { + setEnabled(false); + } + + /** + * Animates a change in the content of the card + * @param v View in card to animate + * @param overlay Drawable to animate as a ViewOverlay + * @param duration Duration of animation + */ + @Override + public void animateContentChange(View v, final Drawable overlay, long duration) { + // Since the wallpaper IS the content, we will ignore the view passed in and animate + // the entire card + final ViewOverlay viewOverlay = this.getOverlay(); + viewOverlay.add(overlay); + final int x = 0; + final int y = 0; + final int width = v.getWidth(); + final int height = v.getHeight(); + overlay.setBounds(x, y, x + width, y + height); + + final ValueAnimator overlayAnimator = ValueAnimator.ofFloat(1f, 0f); + overlayAnimator.setDuration(duration); + overlayAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + float value = (Float) animation.getAnimatedValue(); + overlay.setAlpha((int) (255 * value)); + } + + }); + overlayAnimator.addListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animation) {} + + @Override + public void onAnimationEnd(Animator animation) { + // Clear out the ViewOverlay now that we are done animating + viewOverlay.clear(); + } + + @Override + public void onAnimationCancel(Animator animation) {} + + @Override + public void onAnimationRepeat(Animator animation) {} + }); + + AnimatorSet set = new AnimatorSet(); + set.play(ObjectAnimator.ofFloat(overlay, "alpha", 0f, 1f)) + .with(overlayAnimator); + set.start(); + } +} diff --git a/src/org/cyanogenmod/theme/perapptheming/PerAppThemeListLayout.java b/src/org/cyanogenmod/theme/perapptheming/PerAppThemeListLayout.java index 424d640..fa3a5f0 100644 --- a/src/org/cyanogenmod/theme/perapptheming/PerAppThemeListLayout.java +++ b/src/org/cyanogenmod/theme/perapptheming/PerAppThemeListLayout.java @@ -29,10 +29,9 @@ import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.animation.AccelerateDecelerateInterpolator; -import android.view.animation.Animation; import android.widget.FrameLayout; -import org.cyanogenmod.theme.chooser.R; +import org.cyanogenmod.theme.chooser2.R; public class PerAppThemeListLayout extends FrameLayout { private PerAppThemingWindow mWindow; diff --git a/src/org/cyanogenmod/theme/perapptheming/PerAppThemeListView.java b/src/org/cyanogenmod/theme/perapptheming/PerAppThemeListView.java index 9986f60..ffc7016 100644 --- a/src/org/cyanogenmod/theme/perapptheming/PerAppThemeListView.java +++ b/src/org/cyanogenmod/theme/perapptheming/PerAppThemeListView.java @@ -23,7 +23,7 @@ import android.content.res.TypedArray; import android.util.AttributeSet; import android.widget.ListView; -import org.cyanogenmod.theme.chooser.R; +import org.cyanogenmod.theme.chooser2.R; import org.cyanogenmod.theme.util.Utils; public class PerAppThemeListView extends ListView { diff --git a/src/org/cyanogenmod/theme/perapptheming/PerAppThemingWindow.java b/src/org/cyanogenmod/theme/perapptheming/PerAppThemingWindow.java index 27db329..89401b4 100644 --- a/src/org/cyanogenmod/theme/perapptheming/PerAppThemingWindow.java +++ b/src/org/cyanogenmod/theme/perapptheming/PerAppThemingWindow.java @@ -51,7 +51,7 @@ import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; -import org.cyanogenmod.theme.chooser.R; +import org.cyanogenmod.theme.chooser2.R; import org.cyanogenmod.theme.util.Utils; import cyanogenmod.providers.ThemesContract.ThemesColumns; @@ -633,7 +633,9 @@ public class PerAppThemingWindow extends Service implements OnTouchListener, WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED | - WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, + WindowManager.LayoutParams.FLAG_SPLIT_TOUCH | + WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS | + WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN, PixelFormat.TRANSLUCENT); } mListLayoutParams.gravity = Gravity.TOP | @@ -663,9 +665,9 @@ public class PerAppThemingWindow extends Service implements OnTouchListener, } private void showScrim() { + mThemeListLayout.setEnabled(false); ValueAnimator animator = ValueAnimator.ofArgb(SCRIM_COLOR_TRANSPARENT, SCRIM_COLOR_OPAQUE); - mThemeListLayout.setEnabled(false); animator.setDuration(ANIMATION_DURATION) .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override @@ -681,6 +683,7 @@ public class PerAppThemingWindow extends Service implements OnTouchListener, } private void hideScrim() { + mThemeListLayout.setEnabled(true); ValueAnimator animator = ValueAnimator.ofArgb(SCRIM_COLOR_OPAQUE, SCRIM_COLOR_TRANSPARENT); animator.setDuration(ANIMATION_DURATION) .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { diff --git a/src/org/cyanogenmod/theme/util/NotificationHelper.java b/src/org/cyanogenmod/theme/util/NotificationHelper.java index ebbdb66..c6527ab 100644 --- a/src/org/cyanogenmod/theme/util/NotificationHelper.java +++ b/src/org/cyanogenmod/theme/util/NotificationHelper.java @@ -25,11 +25,10 @@ import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.Resources; -import android.graphics.BitmapFactory; import android.text.TextUtils; -import org.cyanogenmod.theme.chooser.ChooserActivity; -import org.cyanogenmod.theme.chooser.R; +import org.cyanogenmod.theme.chooser2.ChooserActivity; +import org.cyanogenmod.theme.chooser2.R; public class NotificationHelper { private static final int NOTIFICATION_ID = 0x434D5443; diff --git a/src/org/cyanogenmod/theme/util/ThemedTypefaceHelper.java b/src/org/cyanogenmod/theme/util/ThemedTypefaceHelper.java index cf5ddfc..2aba858 100644 --- a/src/org/cyanogenmod/theme/util/ThemedTypefaceHelper.java +++ b/src/org/cyanogenmod/theme/util/ThemedTypefaceHelper.java @@ -53,14 +53,14 @@ public class ThemedTypefaceHelper { return; } catch(Exception e) { Log.w(TAG, "Unable to parse and load themed fonts for " + pkgName + - ". Falling back to system fonts", e ); + ". Falling back to system fonts"); } try { loadSystemFonts(); return; } catch(Exception e) { - Log.e(TAG, "Parsing system fonts failed. Falling back to Typeface loaded fonts", e); + Log.e(TAG, "Parsing system fonts failed. Falling back to Typeface loaded fonts"); } // There is no reason for this to happen unless someone diff --git a/src/org/cyanogenmod/theme/util/Utils.java b/src/org/cyanogenmod/theme/util/Utils.java index 94afecb..9074ab3 100644 --- a/src/org/cyanogenmod/theme/util/Utils.java +++ b/src/org/cyanogenmod/theme/util/Utils.java @@ -38,7 +38,6 @@ import android.graphics.BitmapRegionDecoder; import android.graphics.Point; import android.graphics.Rect; import android.os.RemoteException; -import android.provider.Settings; import android.text.TextUtils; import android.util.Log; import android.util.TypedValue; @@ -46,7 +45,7 @@ import android.view.IWindowManager; import android.view.WindowManager; import android.view.WindowManagerGlobal; -import org.cyanogenmod.theme.chooser.ChooserActivity; +import org.cyanogenmod.theme.chooser2.ChooserActivity; import cyanogenmod.externalviews.KeyguardExternalView; import cyanogenmod.providers.CMSettings; diff --git a/src/org/cyanogenmod/theme/widget/ConfirmCancelOverlay.java b/src/org/cyanogenmod/theme/widget/ConfirmCancelOverlay.java index e00e67a..dcfcbfc 100644 --- a/src/org/cyanogenmod/theme/widget/ConfirmCancelOverlay.java +++ b/src/org/cyanogenmod/theme/widget/ConfirmCancelOverlay.java @@ -23,7 +23,7 @@ import android.view.View; import android.widget.FrameLayout; import android.widget.TextView; -import org.cyanogenmod.theme.chooser.R; +import org.cyanogenmod.theme.chooser2.R; public class ConfirmCancelOverlay extends FrameLayout { diff --git a/src/org/cyanogenmod/theme/widget/LatoTextView.java b/src/org/cyanogenmod/theme/widget/LatoTextView.java index 0cb02ae..a6056ee 100644 --- a/src/org/cyanogenmod/theme/widget/LatoTextView.java +++ b/src/org/cyanogenmod/theme/widget/LatoTextView.java @@ -24,7 +24,7 @@ import android.content.res.TypedArray; import android.graphics.Typeface; import android.util.AttributeSet; -import org.cyanogenmod.theme.chooser.R; +import org.cyanogenmod.theme.chooser2.R; import org.cyanogenmod.theme.util.Utils; import java.io.File; diff --git a/src/org/cyanogenmod/theme/widget/ThemeTagLayout.java b/src/org/cyanogenmod/theme/widget/ThemeTagLayout.java index 18e3da2..701b78b 100644 --- a/src/org/cyanogenmod/theme/widget/ThemeTagLayout.java +++ b/src/org/cyanogenmod/theme/widget/ThemeTagLayout.java @@ -25,7 +25,7 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; -import org.cyanogenmod.theme.chooser.R; +import org.cyanogenmod.theme.chooser2.R; public class ThemeTagLayout extends LinearLayout { private ImageView mAppliedTag; -- cgit v1.1