/* * Copyright (C) Winson Chiu * * 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 cw.kop.autobackground.sources; import android.animation.ArgbEvaluator; import android.animation.LayoutTransition; import android.animation.ValueAnimator; import android.app.Activity; import android.app.ActivityManager; import android.app.AlarmManager; import android.app.Fragment; import android.app.PendingIntent; import android.app.WallpaperManager; import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.PorterDuff; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.LayerDrawable; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Parcelable; import android.support.v4.app.FragmentTransaction; import android.support.v4.content.LocalBroadcastManager; import android.support.v7.widget.CardView; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.DecelerateInterpolator; import android.view.animation.ScaleAnimation; import android.view.animation.Transformation; import android.widget.AdapterView; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; import com.squareup.picasso.Cache; import com.squareup.picasso.Picasso; import java.io.File; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Calendar; import cw.kop.autobackground.DialogFactory; import cw.kop.autobackground.LiveWallpaperService; import cw.kop.autobackground.MainActivity; import cw.kop.autobackground.R; import cw.kop.autobackground.files.FileHandler; import cw.kop.autobackground.images.AdapterImages; import cw.kop.autobackground.images.FolderFragment; import cw.kop.autobackground.settings.AppSettings; public class SourceListFragment extends Fragment implements View.OnClickListener { // public static final String ADD_ENTRY = "cw.kop.autobackground.SourceListFragment.ADD_ENTRY"; // public static final String SET_ENTRY = "cw.kop.autobackground.SourceListFragment.SET_ENTRY"; private static final String TAG = SourceListFragment.class.getCanonicalName(); private static final int SCROLL_ANIMATION_TIME = 150; private static final int INFO_ANIMATION_TIME = 250; private static final int ADD_ANIMATION_TIME = 350; private static final long EXIT_ANIMATION_TIME = 200l; private static final long EXPAND_ACTION_DURATION = 200; private TextView alertText; private RecyclerView recyclerSources; private RecyclerView.LayoutManager layoutManager; private AdapterSources adapterSources; private Activity appContext; private Handler handler; private Button setButton; private ImageView addButtonBackground; private ImageView addButton; private Menu toolbarMenu; // Volatile variables to assure animations are reset properly private volatile boolean needsButtonReset = false; private volatile boolean needsListReset = false; // Hold screen dimensions to calculate animations private int screenHeight; private int screenWidth; /** * Receives DOWNLOAD_TERMINATED intent to reset download button icon and recount available images */ private BroadcastReceiver sourceListReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); switch (action) { case FileHandler.DOWNLOAD_TERMINATED: sourceListListener.getControllerSources().recount(); break; default: } } }; private Runnable resetRecyclerAnimation = new Runnable() { @Override public void run() { if (needsListReset) { Parcelable state = layoutManager.onSaveInstanceState(); recyclerSources.setAdapter(null); recyclerSources.setAdapter(adapterSources); layoutManager.onRestoreInstanceState(state); recyclerSources.setClickable(true); recyclerSources.setEnabled(true); needsListReset = false; addButton.clearAnimation(); addButtonBackground.clearAnimation(); } } }; private SourceListListener sourceListListener; private boolean needsUpdate; public SourceListFragment() { } @Override public void onCreate(Bundle savedInstanceState) { setHasOptionsMenu(true); super.onCreate(savedInstanceState); handler = new Handler(); screenHeight = getResources().getDisplayMetrics().heightPixels; screenWidth = getResources().getDisplayMetrics().widthPixels; AppSettings.resetVer1_30(); AppSettings.resetVer1_40(); AppSettings.resetVer2_00(); AppSettings.resetVer2_00_20(); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { // Inflate menu and hold reference in toolbarMenu inflater.inflate(R.menu.source_list_menu, menu); super.onCreateOptionsMenu(menu, inflater); toolbarMenu = menu; // Sets correct colors of toolbar icons int colorFilterInt = AppSettings.getColorFilterInt(appContext); menu.findItem(R.id.item_cycle).getIcon().setColorFilter(colorFilterInt, PorterDuff.Mode.MULTIPLY); menu.findItem(R.id.item_sort).getIcon().setColorFilter(colorFilterInt, PorterDuff.Mode.MULTIPLY); // Recounts images sourceListListener.getControllerSources().recount(); } @Override public void onAttach(Activity activity) { super.onAttach(activity); appContext = activity; sourceListListener = (SourceListListener) activity; sourceListListener.getControllerSources().setListener( new ControllerSources.SourceListener() { @Override public void notifyDataSetChanged() { if (adapterSources != null) { recyclerSources.post(new Runnable() { @Override public void run() { adapterSources.notifyDataSetChanged(); } }); } else { needsUpdate = true; } } @Override public void onChangeState() { alertText.post(new Runnable() { @Override public void run() { setAlertText(); } }); } }); needsUpdate = true; } @Override public void onDestroy() { // Attempt using Reflection to force clear Picasso cache to make sure previews are accurate try { Field clearCache = Class.forName("com.squareup.picasso.Picasso").getDeclaredField( "cache"); clearCache.setAccessible(true); Cache cache = (Cache) clearCache.get(Picasso.with(appContext)); cache.clear(); } catch (Exception e) { Log.d(TAG, "" + e); } super.onDestroy(); } @Override public void onDetach() { appContext = null; sourceListListener.getControllerSources().setListener(null); sourceListListener = null; super.onDetach(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_sources, container, false); final ImageView emptyArrow = (ImageView) view.findViewById(R.id.empty_arrow); alertText = (TextView) view.findViewById(R.id.source_alert_text); if (screenHeight > screenWidth) { layoutManager = new LinearLayoutManager(appContext, LinearLayoutManager.VERTICAL, false); } else { layoutManager = new GridLayoutManager(appContext, 2, LinearLayoutManager.VERTICAL, false); } recyclerSources = (RecyclerView) view.findViewById(R.id.source_list); recyclerSources.setLayoutManager(layoutManager); recyclerSources.setHasFixedSize(true); addButtonBackground = (ImageView) view.findViewById(R.id.floating_button); addButton = (ImageView) view.findViewById(R.id.floating_button_icon); addButton.setOnClickListener(this); resetAddButtonIcon(); setButton = (Button) view.findViewById(R.id.set_button); setButton.setOnClickListener(this); final AdapterSources.AdapterSourceListener listener = new AdapterSources.AdapterSourceListener() { @Override public void onDownloadClick(View view, Source source) { ArrayList<Source> sources = new ArrayList<>(1); sources.add(source); sourceListListener.getControllerSources().saveData(); if (FileHandler.isDownloading()) { DialogFactory.ActionDialogListener listener = new DialogFactory.ActionDialogListener() { @Override public void onClickRight(View v) { FileHandler.cancel(appContext); resetActionBarDownload(); dismissDialog(); } }; DialogFactory.showActionDialog(appContext, "", "Cancel download?", listener, -1, R.string.cancel_button, R.string.ok_button); } else if (FileHandler.download(appContext, sources)) { toolbarMenu.findItem(R.id.item_download).setIcon( R.drawable.ic_cancel_white_24dp); toolbarMenu.findItem(R.id.item_download).getIcon() .setColorFilter(AppSettings.getColorFilterInt(appContext), PorterDuff.Mode.MULTIPLY); if (AppSettings.resetOnManualDownload() && AppSettings.useTimer()) { Intent intent = new Intent(); intent.setAction(LiveWallpaperService.DOWNLOAD_WALLPAPER); intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); PendingIntent pendingIntent = PendingIntent.getBroadcast(appContext, 0, intent, 0); AlarmManager alarmManager = (AlarmManager) appContext.getSystemService(Context.ALARM_SERVICE); alarmManager.cancel(pendingIntent); alarmManager.setInexactRepeating(AlarmManager.RTC, System.currentTimeMillis() + AppSettings.getTimerDuration(), AppSettings.getTimerDuration(), pendingIntent); } } } @Override public void onDeleteClick(final View view, final int index) { sourceListListener.getControllerSources().saveData(); if (FileHandler.isDownloading()) { Toast.makeText(appContext, "Cannot delete while downloading", Toast.LENGTH_SHORT).show(); return; } Source item = sourceListListener.getControllerSources().get(index); String type = item.getType(); if (type.equals(AppSettings.FOLDER)) { DialogFactory.ActionDialogListener clickListener = new DialogFactory.ActionDialogListener() { @Override public void onClickRight(View v) { sourceListListener.getControllerSources().removeItem(index); sourceListListener.getControllerSources().recount(); this.dismissDialog(); } }; DialogFactory.showActionDialog(appContext, "", "Delete " + item.getTitle() + "?", clickListener, -1, R.string.cancel_button, R.string.ok_button); } else { DialogFactory.ActionDialogListener clickListener = new DialogFactory.ActionDialogListener() { @Override public void onClickMiddle(View v) { this.dismissDialog(); sourceListListener.getControllerSources().removeItem(index); sourceListListener.getControllerSources().recount(); } @Override public void onClickRight(View v) { Source source = sourceListListener.getControllerSources().get(index); FileHandler.deleteBitmaps(source); sendToast("Deleting " + source.getTitle() + " images"); sourceListListener.getControllerSources().removeItem(index); sourceListListener.getControllerSources().recount(); this.dismissDialog(); } }; DialogFactory.showActionDialog(appContext, "Delete images along with this source?", "This cannot be undone.", clickListener, R.string.cancel_button, R.string.no_button, R.string.yes_button); } } @Override public void onViewImageClick(View view, int index) { showViewImageFragment(view, index); } @Override public void onEditClick(View view, int index) { showSourceEditFragment(view, index); } @Override public void onLongClick(int position) { onItemLongClick(position); } @Override public Activity getActivity() { return appContext; } @Override public void setEmptyArrowVisibility(int visibility) { emptyArrow.setVisibility(visibility); } @Override public float getItemWidth() { if (layoutManager instanceof GridLayoutManager) { return recyclerSources.getWidth() / ((GridLayoutManager) layoutManager).getSpanCount(); } return recyclerSources.getWidth(); } @Override public int getSpanForPosition(int position) { if (layoutManager instanceof GridLayoutManager) { return position % 2; } return 0; } }; if (adapterSources == null) { adapterSources = new AdapterSources(getActivity(), sourceListListener.getControllerSources(), listener); } adapterSources.notifyDataSetChanged(); recyclerSources.setAdapter(adapterSources); return view; } @Override public void onClick(final View v) { switch (v.getId()) { case R.id.set_button: setWallpaper(); break; case R.id.floating_button_icon: final LayerDrawable circleDrawable = (LayerDrawable) getResources().getDrawable( R.drawable.floating_button_circle); final float scale = (float) ((Math.hypot(addButtonBackground.getX(), addButtonBackground.getY()) + addButtonBackground.getWidth() / 0.62f) / addButtonBackground.getWidth() / 0.62f * 2); Animation animation = new Animation() { private boolean needsFragment = true; private float pivot; @Override public void initialize(int width, int height, int parentWidth, int parentHeight) { super.initialize(width, height, parentWidth, parentHeight); pivot = resolveSize(RELATIVE_TO_SELF, 0.5f, width, parentWidth); } @Override protected void applyTransformation(float interpolatedTime, Transformation t) { if (needsFragment && interpolatedTime >= 1) { needsFragment = false; showSourceAddFragment(); } else { float scaleFactor = 1.0f + ((scale - 1.0f) * interpolatedTime); t.getMatrix().setScale(scaleFactor, scaleFactor, pivot, pivot); } } @Override public boolean willChangeBounds() { return true; } }; animation.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { ((GradientDrawable) circleDrawable.getDrawable(1)).setColor( getResources().getColor(R.color.ACCENT_OPAQUE)); addButtonBackground.setImageDrawable(circleDrawable); } @Override public void onAnimationEnd(Animation animation) { handler.postDelayed(new Runnable() { @Override public void run() { if (needsButtonReset) { addButton.setOnClickListener(SourceListFragment.this); addButtonBackground.setScaleX(1.0f); addButtonBackground.setScaleY(1.0f); addButtonBackground.clearAnimation(); ((GradientDrawable) circleDrawable.getDrawable(1)).setColor( getResources().getColor(R.color.ACCENT_OPAQUE)); addButtonBackground.setImageDrawable(circleDrawable); addButton.setVisibility(View.VISIBLE); } } }, 100); } @Override public void onAnimationRepeat(Animation animation) { } }); ValueAnimator buttonColorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), getResources().getColor(R.color.ACCENT_OPAQUE), getResources().getColor(AppSettings.getBackgroundColorResource())); buttonColorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { ((GradientDrawable) circleDrawable.getDrawable(1)).setColor( (Integer) animation.getAnimatedValue()); addButtonBackground.setImageDrawable(circleDrawable); } }); DecelerateInterpolator decelerateInterpolator = new DecelerateInterpolator(); animation.setDuration(ADD_ANIMATION_TIME); buttonColorAnimation.setDuration((long) (ADD_ANIMATION_TIME * 0.9)); buttonColorAnimation.setInterpolator(decelerateInterpolator); animation.setInterpolator(decelerateInterpolator); // Post a delayed Runnable to ensure reset even if animation is interrupted handler.postDelayed(new Runnable() { @Override public void run() { if (needsButtonReset) { addButtonBackground.setScaleX(1.0f); addButtonBackground.setScaleY(1.0f); addButtonBackground.clearAnimation(); ((GradientDrawable) circleDrawable.getDrawable(1)).setColor( getResources().getColor(R.color.ACCENT_OPAQUE)); addButtonBackground.setImageDrawable(circleDrawable); addButton.setVisibility(View.VISIBLE); needsButtonReset = false; } } }, (long) (ADD_ANIMATION_TIME * 1.1f)); needsButtonReset = true; addButton.setVisibility(View.GONE); buttonColorAnimation.start(); addButtonBackground.startAnimation(animation); break; default: } } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.item_cycle: cycleWallpaper(); sendToast("Cycling wallpaper..."); break; case R.id.item_download: startDownload(); break; case R.id.item_sort_activated: sourceListListener.getControllerSources().sortData(Source.USE); item.setEnabled(true); break; case R.id.item_sort_location: sourceListListener.getControllerSources().sortData(Source.DATA); item.setEnabled(true); break; case R.id.item_sort_name: sourceListListener.getControllerSources().sortData(Source.TITLE); item.setEnabled(true); break; case R.id.item_sort_number: sourceListListener.getControllerSources().sortData(Source.NUM); item.setEnabled(true); break; } return true; } /** * Saves data in list and sends Intent to cycle wallpaper */ private void cycleWallpaper() { sourceListListener.getControllerSources().saveData(); Intent intent = new Intent(); intent.setAction(LiveWallpaperService.CYCLE_IMAGE); intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); appContext.sendBroadcast(intent); } /** * Starts (or stops) download and sets download icon appropriately */ private void startDownload() { sourceListListener.getControllerSources().saveData(); if (FileHandler.isDownloading()) { DialogFactory.ActionDialogListener listener = new DialogFactory.ActionDialogListener() { @Override public void onClickRight(View v) { FileHandler.cancel(appContext); resetActionBarDownload(); dismissDialog(); } }; DialogFactory.showActionDialog(appContext, "", "Cancel download?", listener, -1, R.string.cancel_button, R.string.ok_button); } else if (FileHandler.download(appContext)) { toolbarMenu.findItem(R.id.item_download).setIcon(R.drawable.ic_cancel_white_24dp); toolbarMenu.findItem(R.id.item_download) .getIcon() .setColorFilter(AppSettings.getColorFilterInt(appContext), PorterDuff.Mode.MULTIPLY); if (AppSettings.resetOnManualDownload() && AppSettings.useTimer()) { Intent intent = new Intent(); intent.setAction(LiveWallpaperService.DOWNLOAD_WALLPAPER); intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); PendingIntent pendingIntent = PendingIntent.getBroadcast(appContext, 0, intent, 0); AlarmManager alarmManager = (AlarmManager) appContext.getSystemService(Context.ALARM_SERVICE); alarmManager.cancel(pendingIntent); Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); calendar.set(Calendar.HOUR_OF_DAY, AppSettings.getTimerHour()); calendar.set(Calendar.MINUTE, AppSettings.getTimerMinute()); if (calendar.getTimeInMillis() > System.currentTimeMillis()) { alarmManager.setInexactRepeating(AlarmManager.RTC, calendar.getTimeInMillis(), AppSettings.getTimerDuration(), pendingIntent); } else { alarmManager.setInexactRepeating(AlarmManager.RTC, calendar.getTimeInMillis() + AlarmManager.INTERVAL_DAY, AppSettings.getTimerDuration(), pendingIntent); } } } } /** * Shows LocalImageFragment to view images * * @param view source card which was selected * @param index position of source in adapterSources */ private void showViewImageFragment(final View view, final int index) { recyclerSources.setClickable(false); recyclerSources.setEnabled(false); sourceListListener.getControllerSources().saveData(); Source item = sourceListListener.getControllerSources().get(index); String type = item.getType(); File directory; if (type.equals(AppSettings.FOLDER)) { directory = new File(item.getData().split(AppSettings.DATA_SPLITTER)[0]); } else { directory = new File(AppSettings.getDownloadPath() + "/" + item.getTitle() + " " + AppSettings.getImagePrefix()); } Log.i(TAG, "Directory: " + directory); final RelativeLayout sourceContainer = (RelativeLayout) view.findViewById(R.id.source_container); final ImageView sourceImage = (ImageView) view.findViewById(R.id.source_image); final View imageOverlay = view.findViewById(R.id.source_image_overlay); final EditText sourceTitle = (EditText) view.findViewById(R.id.source_title); final Toolbar toolbarActions = (Toolbar) view.findViewById(R.id.toolbar_actions); final LinearLayout sourceExpandContainer = (LinearLayout) view.findViewById(R.id.source_expand_container); final boolean fadeView = directory.list() == null || directory.list().length == 0; final float viewStartHeight = sourceContainer.getHeight(); final float viewStartY = view.getY(); final float overlayStartAlpha = imageOverlay.getAlpha(); final float listHeight = recyclerSources.getHeight(); Log.i(TAG, "listHeight: " + listHeight); Log.i(TAG, "viewStartHeight: " + viewStartHeight); final FolderFragment folderFragment = new FolderFragment(); Bundle arguments = new Bundle(); arguments.putBoolean(FolderFragment.SHOW_DIRECTORY_TEXT, false); arguments.putBoolean(FolderFragment.USE_DIRECTORY, false); final AdapterImages adapter = new AdapterImages(appContext, directory, directory, folderFragment); folderFragment.setArguments(arguments); folderFragment.setAdapter(adapter); folderFragment.setListener(new FolderFragment.FolderEventListener() { public Activity dialogActivity; @Override public void onUseDirectoryClick() { // Not implemented } @Override public void onItemClick(final int positionInList) { File selectedFile = adapter.getItem(positionInList); if (selectedFile.exists() && selectedFile.isDirectory()) { adapter.setDirectory(selectedFile); } else if (FileHandler.getImageFileNameFilter().accept(null, adapter.getItem(positionInList).getName())) { DialogFactory.ListDialogListener clickListener = new DialogFactory.ListDialogListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int positionInDialog, long id) { switch (positionInDialog) { case 0: Intent galleryIntent = new Intent(); galleryIntent.setAction(Intent.ACTION_VIEW); galleryIntent.setDataAndType(Uri.fromFile(adapter.getItem( positionInList)), "image/*"); galleryIntent = Intent.createChooser(galleryIntent, "Open Image"); galleryIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); dialogActivity.startActivity(galleryIntent); break; case 1: File file = adapter.getItem(positionInList); if (file.exists() && file.isFile()) { if (FileHandler.getCurrentBitmapFile() != null && file.getAbsolutePath().equals(FileHandler.getCurrentBitmapFile().getAbsolutePath())) { Intent intent = new Intent(); intent.setAction(LiveWallpaperService.CYCLE_IMAGE); intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); dialogActivity.sendBroadcast(intent); } file.delete(); adapter.remove(positionInList); } } dismissDialog(); } }; DialogFactory.showListDialog(appContext, "", clickListener, R.array.history_menu); } } @Override public boolean onBackPressed() { return adapter.backDirectory(); } @Override public void setActivity(Activity activity) { this.dialogActivity = activity; } }); final boolean animateSideBySide; final View viewAdjacent; final RelativeLayout sourceContainerAdjacent; int indexAdjacent = index % 2 == 0 ? index + 1 : index - 1; if (indexAdjacent >=0 && indexAdjacent < adapterSources.getItemCount() && layoutManager instanceof GridLayoutManager) { animateSideBySide = true; viewAdjacent = recyclerSources.findViewHolderForPosition(indexAdjacent).itemView; sourceContainerAdjacent = (RelativeLayout) viewAdjacent.findViewById(R.id.source_container); } else if (index > 0) { RecyclerView.ViewHolder viewHolder = recyclerSources.findViewHolderForPosition(index - 1); if (viewHolder == null) { viewAdjacent = null; sourceContainerAdjacent = null; animateSideBySide = false; } else { animateSideBySide = true; viewAdjacent = viewHolder.itemView; sourceContainerAdjacent = (RelativeLayout) viewAdjacent.findViewById( R.id.source_container); } } else { viewAdjacent = null; sourceContainerAdjacent = null; animateSideBySide = false; } Animation animation = new Animation() { private boolean needsFragment = true; @Override protected void applyTransformation(float interpolatedTime, Transformation t) { if (needsFragment && interpolatedTime >= 1) { needsFragment = false; getFragmentManager().beginTransaction() .setCustomAnimations(R.animator.none, R.animator.slide_to_bottom, R.animator.none, R.animator.slide_to_bottom) .add(R.id.content_frame, folderFragment, "folder_fragment") .addToBackStack(null) .commit(); } sourceContainer.getLayoutParams().height = (int) (viewStartHeight + (listHeight - viewStartHeight) * interpolatedTime); sourceContainer.requestLayout(); view.setY(viewStartY - interpolatedTime * viewStartY); float newAlpha = 1.0f - interpolatedTime; toolbarActions.setAlpha(newAlpha); sourceTitle.setAlpha(newAlpha); sourceExpandContainer.setAlpha(newAlpha); if (fadeView) { sourceImage.setAlpha(1.0f - interpolatedTime); } if (animateSideBySide) { viewAdjacent.setAlpha(1.0f - interpolatedTime); viewAdjacent.requestLayout(); } view.requestLayout(); } @Override public boolean willChangeBounds() { return true; } }; animation.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { handler.postDelayed(resetRecyclerAnimation, (long) INFO_ANIMATION_TIME / 5); } @Override public void onAnimationRepeat(Animation animation) { } }); ValueAnimator cardColorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), AppSettings.getDialogColor(appContext), getResources().getColor(AppSettings.getBackgroundColorResource())); cardColorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { sourceContainer.setBackgroundColor((Integer) animation.getAnimatedValue()); if (animateSideBySide) { sourceContainerAdjacent.setBackgroundColor( (Integer) animation.getAnimatedValue()); } } }); ValueAnimator imageOverlayAlphaAnimation = ValueAnimator.ofFloat(imageOverlay.getAlpha(), 0f); imageOverlayAlphaAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { imageOverlay.setAlpha((Float) animation.getAnimatedValue()); } }); Animation buttonAlphaAnimation = new AlphaAnimation(1.0f, 0.0f); DecelerateInterpolator decelerateInterpolator = new DecelerateInterpolator(1.5f); animation.setDuration(INFO_ANIMATION_TIME); cardColorAnimation.setDuration(INFO_ANIMATION_TIME); imageOverlayAlphaAnimation.setDuration(INFO_ANIMATION_TIME); buttonAlphaAnimation.setDuration(INFO_ANIMATION_TIME); animation.setInterpolator(decelerateInterpolator); cardColorAnimation.setInterpolator(decelerateInterpolator); imageOverlayAlphaAnimation.setInterpolator(decelerateInterpolator); buttonAlphaAnimation.setInterpolator(decelerateInterpolator); handler.postDelayed(resetRecyclerAnimation, (long) (INFO_ANIMATION_TIME * 1.1f)); needsListReset = true; if (imageOverlay.getAlpha() > 0) { imageOverlayAlphaAnimation.start(); } cardColorAnimation.start(); view.startAnimation(animation); addButton.startAnimation(buttonAlphaAnimation); addButtonBackground.startAnimation(buttonAlphaAnimation); } /** * Show SourceInfoFragment with position -1 to add new source */ private void showSourceAddFragment() { final SourceInfoFragment sourceInfoFragment = new SourceInfoFragment(); Bundle arguments = new Bundle(); arguments.putInt(Source.POSITION, -1); arguments.putString(Source.TYPE, AppSettings.WEBSITE); arguments.putString(Source.TITLE, ""); arguments.putString(Source.DATA, ""); arguments.putInt(Source.NUM, -1); arguments.putString(Source.SORT, ""); arguments.putBoolean(Source.USE, true); arguments.putBoolean(Source.PREVIEW, true); arguments.putBoolean(Source.USE_TIME, false); arguments.putString(Source.TIME, "00:00 - 00:00"); arguments.putInt(SourceInfoFragment.LAYOUT_LANDSCAPE, R.layout.fragment_source_info_landscape_left); sourceInfoFragment.setArguments(arguments); getFragmentManager().beginTransaction() .add(R.id.content_frame, sourceInfoFragment, "sourceInfoFragment") .addToBackStack(null) .setTransition(FragmentTransaction.TRANSIT_NONE) .commit(); } /** * Sets up recyclerSources behavior * * @param savedInstanceState */ @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); } protected void setWallpaper() { final Intent intent = new Intent(); if (Build.VERSION.SDK_INT >= 16) { intent.setAction(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER); final String packageName = LiveWallpaperService.class.getPackage().getName(); final String className = LiveWallpaperService.class.getCanonicalName(); intent.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT, new ComponentName(packageName, className)); } else { intent.setAction(WallpaperManager.ACTION_LIVE_WALLPAPER_CHOOSER); } try { startActivityForResult(intent, 0); } catch (ActivityNotFoundException e) { sendToast("Error loading wallpaper chooser,\n" + "please set manually."); } } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); } @Override public void onDestroyView() { recyclerSources.setAdapter(null); super.onDestroyView(); } @Override public void onResume() { super.onResume(); addButton.setAlpha(1.0f); addButtonBackground.setAlpha(1.0f); sourceListListener.getControllerSources().recount(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(FileHandler.DOWNLOAD_TERMINATED); LocalBroadcastManager.getInstance(appContext).registerReceiver(sourceListReceiver, intentFilter); if (isServiceRunning(LiveWallpaperService.class.getName())) { setButton.setVisibility(View.GONE); } else { setButton.setVisibility(View.VISIBLE); } if (needsUpdate) { adapterSources.notifyDataSetChanged(); needsUpdate = false; } } @Override public void onPause() { ((MainActivity) getActivity()).getSupportActionBar().show(); sourceListListener.getControllerSources().saveData(); LocalBroadcastManager.getInstance(appContext).unregisterReceiver(sourceListReceiver); super.onPause(); } public void resetAddButtonIcon() { if (isAdded()) { Drawable addDrawable = getResources().getDrawable(R.drawable.ic_add_white_24dp); addDrawable.setColorFilter(AppSettings.getColorFilterInt(appContext), PorterDuff.Mode.MULTIPLY); addButton.setImageDrawable(addDrawable); } } public void resetActionBarDownload() { if (isAdded()) { if (toolbarMenu != null) { handler.post(new Runnable() { @Override public void run() { toolbarMenu.findItem(R.id.item_download).setIcon( R.drawable.ic_file_download_white_24dp); toolbarMenu.findItem(R.id.item_download).getIcon().setColorFilter( AppSettings.getColorFilterInt(appContext), PorterDuff.Mode.MULTIPLY); } }); } } } private boolean isServiceRunning(final String className) { final ActivityManager manager = (ActivityManager) appContext.getSystemService(Context.ACTIVITY_SERVICE); for (final ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { if (className.equals(service.service.getClassName())) { return true; } } return false; } public boolean onItemLongClick(int position) { sourceListListener.getControllerSources().toggleActivated(position); if (alertText.isShown()) { sourceListListener.getControllerSources().recount(); } adapterSources.notifyItemChanged(position); return true; } private void showSourceEditFragment(final View view, final int position) { recyclerSources.setClickable(false); recyclerSources.setEnabled(false); sourceListListener.getControllerSources().saveData(); Source dataItem = sourceListListener.getControllerSources().get(position); final SourceInfoFragment sourceInfoFragment = new SourceInfoFragment(); sourceInfoFragment.setImageDrawable(((ImageView) view.findViewById(R.id.source_image)).getDrawable()); Bundle arguments = new Bundle(); arguments.putInt(Source.POSITION, position); arguments.putString(Source.TYPE, dataItem.getType()); arguments.putString(Source.TITLE, dataItem.getTitle()); arguments.putString(Source.DATA, dataItem.getData()); arguments.putInt(Source.NUM, dataItem.getNum()); arguments.putBoolean(Source.USE, dataItem.isUse()); arguments.putString(Source.SORT, dataItem.getSort()); arguments.putBoolean(Source.PREVIEW, dataItem.isPreview()); if (dataItem.getImageFile() != null) { arguments.putString(Source.IMAGE_FILE, dataItem.getImageFile().getAbsolutePath()); } else { arguments.putString(Source.IMAGE_FILE, ""); } arguments.putBoolean(Source.USE_TIME, dataItem.isUseTime()); arguments.putString(Source.TIME, dataItem.getTime()); if (layoutManager instanceof GridLayoutManager) { arguments.putInt(SourceInfoFragment.LAYOUT_LANDSCAPE, position % 2 == 1 ? R.layout.fragment_source_info_landscape_right : R.layout.fragment_source_info_landscape_left); } else { arguments.putInt(SourceInfoFragment.LAYOUT_LANDSCAPE, R.layout.fragment_source_info_landscape_left); } sourceInfoFragment.setArguments(arguments); final RelativeLayout sourceContainer = (RelativeLayout) view.findViewById(R.id.source_container); final CardView sourceCard = (CardView) view.findViewById(R.id.source_card); final ImageView sourceImage = (ImageView) view.findViewById(R.id.source_image); final View imageOverlay = view.findViewById(R.id.source_image_overlay); final EditText sourceTitle = (EditText) view.findViewById(R.id.source_title); final Toolbar toolbarActions = (Toolbar) view.findViewById(R.id.toolbar_actions); final LinearLayout sourceExpandContainer = (LinearLayout) view.findViewById(R.id.source_expand_container); final int cardStartMarginVertical = ((LinearLayout.LayoutParams) sourceCard.getLayoutParams()).topMargin; final int cardStartMarginHorizontal = ((LinearLayout.LayoutParams) sourceCard.getLayoutParams()).leftMargin; final float viewStartHeight = sourceContainer.getHeight(); final float viewStartY = view.getY(); final int imageStartHeight = sourceImage.getHeight(); final int viewStartPaddingHorizontal = view.getPaddingLeft(); final int viewStartPaddingVertical = view.getPaddingTop(); final float textStartX = sourceTitle.getX(); final float textStartY = sourceTitle.getY(); final float textTranslationY = sourceTitle.getHeight(); final boolean animateSideBySide; final View viewAdjacent; final RelativeLayout sourceContainerAdjacent; int positionAdjacent = position % 2 == 0 ? position + 1 : position - 1; if (positionAdjacent >=0 && positionAdjacent < adapterSources.getItemCount() && layoutManager instanceof GridLayoutManager) { RecyclerView.ViewHolder viewHolder = recyclerSources.findViewHolderForPosition(positionAdjacent); if (viewHolder == null) { viewAdjacent = null; sourceContainerAdjacent = null; animateSideBySide = false; } else { animateSideBySide = true; viewAdjacent = viewHolder.itemView; sourceContainerAdjacent = (RelativeLayout) viewAdjacent.findViewById( R.id.source_container); } } else { viewAdjacent = null; sourceContainerAdjacent = null; animateSideBySide = false; } Animation animation = new Animation() { private boolean needsFragment = true; @Override protected void applyTransformation(float interpolatedTime, Transformation t) { if (needsFragment && interpolatedTime >= 0.99f) { needsFragment = false; getFragmentManager().beginTransaction() .add(R.id.content_frame, sourceInfoFragment, "sourceInfoFragment") .addToBackStack(null) .setTransition(FragmentTransaction.TRANSIT_NONE) .commit(); } int newPaddingHorizontal = Math.round(viewStartPaddingHorizontal * (1 - interpolatedTime)); int newPaddingVertical = Math.round(viewStartPaddingVertical * (1 - interpolatedTime)); int newCardMarginVertical = Math.round(cardStartMarginVertical * (1 - interpolatedTime)); int newCardMarginHorizontal = Math.round(cardStartMarginHorizontal * (1 - interpolatedTime)); ((LinearLayout.LayoutParams) sourceCard.getLayoutParams()).topMargin = newCardMarginVertical; ((LinearLayout.LayoutParams) sourceCard.getLayoutParams()).bottomMargin = newCardMarginVertical; ((LinearLayout.LayoutParams) sourceCard.getLayoutParams()).leftMargin = newCardMarginHorizontal; ((LinearLayout.LayoutParams) sourceCard.getLayoutParams()).rightMargin = newCardMarginHorizontal; view.setPadding(newPaddingHorizontal, newPaddingVertical, newPaddingHorizontal, view.getPaddingBottom()); view.setY(viewStartY - interpolatedTime * viewStartY); sourceContainer.getLayoutParams().height = (int) (viewStartHeight + (screenHeight - viewStartHeight) * interpolatedTime); sourceImage.getLayoutParams().height = imageStartHeight + 2 * (viewStartPaddingVertical - newPaddingVertical + cardStartMarginVertical - newCardMarginVertical); sourceTitle.setY( textStartY + interpolatedTime * (textTranslationY + 2 * (viewStartPaddingVertical - newPaddingVertical + cardStartMarginVertical - newCardMarginVertical))); sourceTitle.setX(textStartX + viewStartPaddingHorizontal - newPaddingHorizontal); float newAlpha = 1.0f - interpolatedTime; toolbarActions.setAlpha(newAlpha); sourceExpandContainer.setAlpha(newAlpha); sourceContainer.requestLayout(); sourceImage.requestLayout(); view.requestLayout(); if (animateSideBySide) { viewAdjacent.setAlpha(newAlpha); } } @Override public boolean willChangeBounds() { return true; } }; animation.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { handler.postDelayed(resetRecyclerAnimation, (long) INFO_ANIMATION_TIME / 5); } @Override public void onAnimationRepeat(Animation animation) { } }); ValueAnimator cardColorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), AppSettings.getDialogColor(appContext), getResources().getColor(AppSettings.getBackgroundColorResource())); cardColorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { sourceContainer.setBackgroundColor((Integer) animation.getAnimatedValue()); if (animateSideBySide) { sourceContainerAdjacent.setBackgroundColor((Integer) animation.getAnimatedValue()); } } }); ValueAnimator titleColorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), sourceTitle.getCurrentTextColor(), getResources().getColor(R.color.BLUE_OPAQUE)); titleColorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { sourceTitle.setTextColor((Integer) animation.getAnimatedValue()); } }); ValueAnimator titleShadowAlphaAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), AppSettings.getColorFilterInt(appContext), getResources().getColor(android.R.color.transparent)); titleShadowAlphaAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { sourceTitle.setShadowLayer(4, 0, 0, (Integer) animation.getAnimatedValue()); } }); ValueAnimator imageOverlayAlphaAnimation = ValueAnimator.ofFloat(imageOverlay.getAlpha(), 0f); imageOverlayAlphaAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { imageOverlay.setAlpha((Float) animation.getAnimatedValue()); } }); Animation buttonAlphaAnimation = new AlphaAnimation(1.0f, 0.0f); DecelerateInterpolator decelerateInterpolator = new DecelerateInterpolator(1.5f); animation.setDuration(INFO_ANIMATION_TIME); cardColorAnimation.setDuration(INFO_ANIMATION_TIME); titleColorAnimation.setDuration(INFO_ANIMATION_TIME); titleShadowAlphaAnimation.setDuration(INFO_ANIMATION_TIME); imageOverlayAlphaAnimation.setDuration(INFO_ANIMATION_TIME); buttonAlphaAnimation.setDuration(INFO_ANIMATION_TIME); animation.setInterpolator(decelerateInterpolator); cardColorAnimation.setInterpolator(decelerateInterpolator); titleColorAnimation.setInterpolator(decelerateInterpolator); titleShadowAlphaAnimation.setInterpolator(decelerateInterpolator); imageOverlayAlphaAnimation.setInterpolator(decelerateInterpolator); buttonAlphaAnimation.setInterpolator(decelerateInterpolator); handler.postDelayed(resetRecyclerAnimation, (long) (INFO_ANIMATION_TIME * 1.1f)); needsListReset = true; if (imageOverlay.getAlpha() > 0) { imageOverlayAlphaAnimation.start(); } view.startAnimation(animation); addButton.startAnimation(buttonAlphaAnimation); addButtonBackground.startAnimation(buttonAlphaAnimation); cardColorAnimation.start(); titleColorAnimation.start(); titleShadowAlphaAnimation.start(); } private void sendToast(String toast) { if (AppSettings.useToast()) { Toast.makeText(appContext, toast, Toast.LENGTH_SHORT).show(); } } private void setAlertText() { Log.i("SLA", "ImageCountTask onPostExecute"); if (!isAdded()) { return; } String sourceState = sourceListListener.getControllerSources().getState(); sourceListListener.getControllerSources().updateNum(); resetAddButtonIcon(); if (toolbarMenu != null) { toolbarMenu.findItem(R.id.item_download).setIcon(FileHandler.isDownloading() ? R.drawable.ic_cancel_white_24dp : R.drawable.ic_file_download_white_24dp); toolbarMenu.findItem(R.id.item_download).getIcon().setColorFilter( AppSettings.getColorFilterInt(appContext), PorterDuff.Mode.MULTIPLY); } alertText.setVisibility(sourceState.equals(ControllerSources.OKAY) ? View.GONE : View.VISIBLE); switch (sourceState) { case ControllerSources.NO_SOURCES: alertText.setText("Please add a source"); break; case ControllerSources.NO_ACTIVE_SOURCES: alertText.setText("No active sources"); break; case ControllerSources.NEED_DOWNLOAD: alertText.setText("No downloaded images"); if (!FileHandler.isDownloading() && toolbarMenu != null) { toolbarMenu.findItem(R.id.item_download).setIcon( R.drawable.ic_file_download_white_24dp); toolbarMenu.findItem(R.id.item_download).getIcon() .setColorFilter(getResources().getColor(R.color.ALERT_TEXT), PorterDuff.Mode.MULTIPLY); } break; case ControllerSources.NO_IMAGES: alertText.setText("No images found"); break; case ControllerSources.OKAY: break; } } public interface SourceListListener { ControllerSources getControllerSources(); } }