diff --git a/README.md b/README.md index a756628..bf94f32 100644 --- a/README.md +++ b/README.md @@ -12,3 +12,6 @@ Пример - при скролле списка не сетить Bitmap'ы в ImageView +# Demo + +![](demo.gif) diff --git a/app/build.gradle b/app/build.gradle index 445372a..b1b06a5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,7 +12,7 @@ android { buildToolsVersion versions.buildTools defaultConfig { - applicationId 'ru.yandex.yamblz' + applicationId 'ru.yandex.yamblz.euv.background' minSdkVersion versions.minSdk targetSdkVersion versions.targetSdk versionCode versions.code // Notice that you may want to use BUILD_NUMBER from CI in real project with own CI. diff --git a/app/src/main/java/ru/yandex/yamblz/App.java b/app/src/main/java/ru/yandex/yamblz/App.java index e5f9972..ae23fa6 100644 --- a/app/src/main/java/ru/yandex/yamblz/App.java +++ b/app/src/main/java/ru/yandex/yamblz/App.java @@ -2,12 +2,15 @@ import android.app.Application; import android.content.Context; +import android.os.Handler; import android.support.annotation.NonNull; import ru.yandex.yamblz.developer_settings.DevMetricsProxy; import ru.yandex.yamblz.developer_settings.DeveloperSettingsModel; import ru.yandex.yamblz.handler.CriticalSectionsManager; +import ru.yandex.yamblz.handler.DefaultCriticalSectionsHandler; import ru.yandex.yamblz.loader.CollageLoaderManager; +import ru.yandex.yamblz.loader.DefaultCollageLoader; import timber.log.Timber; public class App extends Application { @@ -34,8 +37,8 @@ public void onCreate() { devMetricsProxy.apply(); } - CollageLoaderManager.init(null); // add implementation - CriticalSectionsManager.init(null); // add implementation + CollageLoaderManager.init(new DefaultCollageLoader(getResources())); + CriticalSectionsManager.init(new DefaultCriticalSectionsHandler(new Handler(getMainLooper()))); } @NonNull diff --git a/app/src/main/java/ru/yandex/yamblz/handler/DefaultCriticalSectionsHandler.java b/app/src/main/java/ru/yandex/yamblz/handler/DefaultCriticalSectionsHandler.java new file mode 100644 index 0000000..ab53f7e --- /dev/null +++ b/app/src/main/java/ru/yandex/yamblz/handler/DefaultCriticalSectionsHandler.java @@ -0,0 +1,103 @@ +package ru.yandex.yamblz.handler; + +import android.os.Handler; + +import java.lang.ref.WeakReference; +import java.util.Collections; +import java.util.Map; +import java.util.Queue; +import java.util.Set; +import java.util.WeakHashMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; + +public class DefaultCriticalSectionsHandler implements CriticalSectionsHandler { + private final Handler uiThreadHandler; + private final Queue tasks = new ConcurrentLinkedQueue<>(); + private final Set sections = Collections.newSetFromMap(new ConcurrentHashMap<>()); + private final Map> futureTasks = Collections.synchronizedMap(new WeakHashMap<>()); + + public DefaultCriticalSectionsHandler(Handler uiThreadHandler) { + this.uiThreadHandler = uiThreadHandler; + } + + + @Override + public void startSection(int id) { + sections.add(id); + } + + + @Override + public void stopSection(int id) { + sections.remove(id); + if (sections.isEmpty()) { + runTasks(); + } + } + + + @Override + public void stopSections() { + sections.clear(); + runTasks(); + } + + + @Override + public void postLowPriorityTask(Task task) { + if (sections.isEmpty()) { + runTask(task); + } else { + tasks.add(task); + } + } + + + @Override + public void postLowPriorityTaskDelayed(Task task, int delay) { + if (delay <= 0) { + postLowPriorityTask(task); + return; + } + + Runnable futureTask = () -> postLowPriorityTask(task); + futureTasks.put(task, new WeakReference<>(futureTask)); + uiThreadHandler.postDelayed(futureTask, delay); + } + + + @Override + public void removeLowPriorityTask(Task task) { + tasks.remove(task); + + WeakReference refFutureTask = futureTasks.remove(task); + if (refFutureTask != null) { + Runnable futureTask = refFutureTask.get(); + if (futureTask != null) { + uiThreadHandler.removeCallbacks(futureTask); + } + } + } + + + @Override + public void removeLowPriorityTasks() { + for (Task task : tasks) { + removeLowPriorityTask(task); + } + } + + + private void runTasks() { + for (Task task : tasks) { + runTask(task); + } + } + + + private void runTask(Task task) { + tasks.remove(task); + uiThreadHandler.post(task::run); + } +} diff --git a/app/src/main/java/ru/yandex/yamblz/loader/CollageLoader.java b/app/src/main/java/ru/yandex/yamblz/loader/CollageLoader.java index dad5b76..a176d88 100644 --- a/app/src/main/java/ru/yandex/yamblz/loader/CollageLoader.java +++ b/app/src/main/java/ru/yandex/yamblz/loader/CollageLoader.java @@ -2,16 +2,14 @@ import android.widget.ImageView; -import java.util.List; - public interface CollageLoader { - void loadCollage(List urls, ImageView imageView); + void loadCollage(int[] ids, ImageView imageView); - void loadCollage(List urls, ImageTarget imageTarget); + void loadCollage(int[] ids, ImageTarget imageTarget); - void loadCollage(List urls, ImageView imageView, CollageStrategy collageStrategy); + void loadCollage(int[] ids, ImageView imageView, CollageStrategy collageStrategy); - void loadCollage(List urls, ImageTarget imageTarget, CollageStrategy collageStrategy); + void loadCollage(int[] ids, ImageTarget imageTarget, CollageStrategy collageStrategy); } diff --git a/app/src/main/java/ru/yandex/yamblz/loader/DefaultCollageLoader.java b/app/src/main/java/ru/yandex/yamblz/loader/DefaultCollageLoader.java new file mode 100644 index 0000000..79f281f --- /dev/null +++ b/app/src/main/java/ru/yandex/yamblz/loader/DefaultCollageLoader.java @@ -0,0 +1,196 @@ +package ru.yandex.yamblz.loader; + +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.AsyncTask; +import android.util.Log; +import android.util.LruCache; +import android.widget.ImageView; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.WeakHashMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import static android.os.Process.THREAD_PRIORITY_BACKGROUND; +import static android.os.Process.setThreadPriority; + +public class DefaultCollageLoader implements CollageLoader { + private static final String TAG = DefaultCollageLoader.class.getSimpleName(); + private static final long MEMORY_MAX = Runtime.getRuntime().maxMemory(); + private static final float MEMORY_USE_THRESHOLD = 0.9f; + + private static ExecutorService executorService = Executors.newCachedThreadPool(); + + private Resources resources; + private LruCache bitmapCache; + private Map> asyncLoaders = new WeakHashMap<>(); + + public DefaultCollageLoader(Resources resources) { + this.resources = resources; + + int maxCacheSize = (int) (MEMORY_MAX / 1024 / 2); + bitmapCache = new LruCache(maxCacheSize) { + @Override + protected int sizeOf(Integer key, Bitmap bitmap) { + return bitmap.getByteCount() / 1024; + } + }; + } + + + @Override + public void loadCollage(int[] ids, ImageView imageView) { + loadCollage(ids, imageView, null, null); + } + + + @Override + public void loadCollage(int[] ids, ImageTarget imageTarget) { + loadCollage(ids, null, imageTarget, null); + + } + + + @Override + public void loadCollage(int[] ids, ImageView imageView, CollageStrategy collageStrategy) { + loadCollage(ids, imageView, null, collageStrategy); + + } + + + @Override + public void loadCollage(int[] ids, ImageTarget imageTarget, CollageStrategy collageStrategy) { + loadCollage(ids, null, imageTarget, collageStrategy); + } + + + private void loadCollage(int[] ids, ImageView iv, ImageTarget it, CollageStrategy strategy) { + if (strategy == null) { + strategy = new SquareCollageStrategy(); + } + + // If there is a loader task for the same target, cancel it + Object key = (iv == null) ? it : iv; + WeakReference refLoader = asyncLoaders.remove(key); + if (refLoader != null) { + AsyncCollageLoader loader = refLoader.get(); + if (loader != null) { + loader.cancel(false); + } + } + + WeakReference refImageView = new WeakReference<>(iv); + WeakReference refImageTarget = new WeakReference<>(it); + + AsyncCollageLoader loader = new AsyncCollageLoader(ids, refImageView, refImageTarget, strategy); + loader.execute(); + + asyncLoaders.put(key, new WeakReference<>(loader)); + } + + + /** + * Asynchronously loads (or gets from cache) all the images whose ids are specified. + *

+ * There is a drawback in current architecture: since only a {@link CollageStrategy} + * knows all the details about collage management, we can't load only a useful + * part of images, nor we can load a scaled down images (the latter is also impossible + * since an {@link ImageTarget} is unable to tell the desired width and height). + */ + private class AsyncCollageLoader extends AsyncTask { + private int[] ids; + private WeakReference refImageView; + private WeakReference refImageTarget; + private CollageStrategy collageStrategy; + + AsyncCollageLoader(int[] ids, WeakReference iv, WeakReference it, CollageStrategy strategy) { + this.ids = ids; + this.refImageView = iv; + this.refImageTarget = it; + this.collageStrategy = strategy; + } + + + @Override + protected Bitmap doInBackground(Void... params) { + List> futures = new ArrayList<>(ids.length); + List bitmaps = new ArrayList<>(ids.length); + + for (int id : ids) { + Bitmap bitmap = bitmapCache.get(id); + if (bitmap == null) { + futures.add(executorService.submit(() -> { + setThreadPriority(THREAD_PRIORITY_BACKGROUND); + + Bitmap bmp = loadBitmap(id); + if (bmp == null) { + return null; + } + + bitmapCache.put(id, bmp); + return bmp; + })); + } else { + bitmaps.add(bitmap); + } + } + + for (Future future : futures) { + try { + Bitmap bitmap = future.get(); + if (bitmap != null) { + bitmaps.add(bitmap); + } + if (isCancelled()) return null; + } catch (InterruptedException | ExecutionException e) { + Log.e(TAG, Log.getStackTraceString(e)); + } + } + + return collageStrategy.create(bitmaps); + } + + + @Override + protected void onPostExecute(Bitmap bitmap) { + if (bitmap == null) { + return; + } + + ImageView imageView = refImageView.get(); + if (imageView != null) { + imageView.setAlpha(0f); + imageView.setImageBitmap(bitmap); + imageView.animate().alpha(1).setDuration(500).start(); + } + + ImageTarget imageTarget = refImageTarget.get(); + if (imageTarget != null) { + imageTarget.onLoadBitmap(bitmap); + } + } + + + private Bitmap loadBitmap(int resId) { + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeResource(resources, resId, options); + long bitmapSize = options.outWidth * options.outHeight * 4; + + long memoryRequired = Runtime.getRuntime().totalMemory() + bitmapSize; + if (memoryRequired > MEMORY_MAX * MEMORY_USE_THRESHOLD) { + Log.d(TAG, "Could not load a new image because of exceeding memory consumption limit"); + return null; + } + + return BitmapFactory.decodeResource(resources, resId); + } + } +} diff --git a/app/src/main/java/ru/yandex/yamblz/loader/ImageViewTarget.java b/app/src/main/java/ru/yandex/yamblz/loader/ImageViewTarget.java new file mode 100644 index 0000000..2ae505a --- /dev/null +++ b/app/src/main/java/ru/yandex/yamblz/loader/ImageViewTarget.java @@ -0,0 +1,22 @@ +package ru.yandex.yamblz.loader; + +import android.graphics.Bitmap; +import android.widget.ImageView; + +import java.lang.ref.WeakReference; + +public class ImageViewTarget implements ImageTarget { + private final WeakReference refImageView; + + public ImageViewTarget(ImageView imageView) { + refImageView = new WeakReference<>(imageView); + } + + @Override + public void onLoadBitmap(Bitmap bitmap) { + ImageView imageView = refImageView.get(); + if (imageView != null) { + imageView.setImageBitmap(bitmap); + } + } +} diff --git a/app/src/main/java/ru/yandex/yamblz/loader/SquareCollageStrategy.java b/app/src/main/java/ru/yandex/yamblz/loader/SquareCollageStrategy.java new file mode 100644 index 0000000..4c77800 --- /dev/null +++ b/app/src/main/java/ru/yandex/yamblz/loader/SquareCollageStrategy.java @@ -0,0 +1,53 @@ +package ru.yandex.yamblz.loader; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Rect; + +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import static android.graphics.Bitmap.Config.ARGB_8888; + +/** + * Simple {@link CollageStrategy}. + * Assumes that all given images have the same size and are square. + */ +public class SquareCollageStrategy implements CollageStrategy { + + @Override + public Bitmap create(List bitmaps) { + if (bitmaps == null || bitmaps.isEmpty()) { + return null; + } + + Collections.shuffle(bitmaps); + + int sectionsPerSide = (int) Math.sqrt(bitmaps.size()); + + return createSquareCollage(bitmaps, sectionsPerSide); + } + + + private Bitmap createSquareCollage(List bitmaps, int sectionsPerSide) { + int collageSize = bitmaps.get(0).getWidth(); + int sectionSize = collageSize / sectionsPerSide; + + Bitmap collage = Bitmap.createBitmap(collageSize, collageSize, ARGB_8888); + Canvas canvas = new Canvas(collage); + + Iterator iterator = bitmaps.iterator(); + for (int row = 0; row < sectionsPerSide; row++) { + for (int col = 0; col < sectionsPerSide; col++) { + int left = col * sectionSize; + int top = row * sectionSize; + int right = collageSize - (sectionsPerSide - 1 - col) * sectionSize; + int bottom = collageSize - (sectionsPerSide - 1 - row) * sectionSize; + canvas.drawBitmap(iterator.next(), null, new Rect(left, top, right, bottom), null); + } + } + + return collage; + } +} diff --git a/app/src/main/java/ru/yandex/yamblz/loader/StubCollageLoader.java b/app/src/main/java/ru/yandex/yamblz/loader/StubCollageLoader.java index 1dc051b..a755d00 100644 --- a/app/src/main/java/ru/yandex/yamblz/loader/StubCollageLoader.java +++ b/app/src/main/java/ru/yandex/yamblz/loader/StubCollageLoader.java @@ -2,28 +2,26 @@ import android.widget.ImageView; -import java.util.List; - public class StubCollageLoader implements CollageLoader { @Override - public void loadCollage(List urls, ImageView imageView) { + public void loadCollage(int[] ids, ImageView imageView) { } @Override - public void loadCollage(List urls, ImageTarget imageTarget) { + public void loadCollage(int[] ids, ImageTarget imageTarget) { } @Override - public void loadCollage(List urls, ImageView imageView, + public void loadCollage(int[] ids, ImageView imageView, CollageStrategy collageStrategy) { } @Override - public void loadCollage(List urls, ImageTarget imageTarget, + public void loadCollage(int[] ids, ImageTarget imageTarget, CollageStrategy collageStrategy) { } diff --git a/app/src/main/java/ru/yandex/yamblz/ui/adapters/CollageAdapter.java b/app/src/main/java/ru/yandex/yamblz/ui/adapters/CollageAdapter.java new file mode 100644 index 0000000..0edda7f --- /dev/null +++ b/app/src/main/java/ru/yandex/yamblz/ui/adapters/CollageAdapter.java @@ -0,0 +1,78 @@ +package ru.yandex.yamblz.ui.adapters; + +import android.support.v7.widget.RecyclerView.Adapter; +import android.support.v7.widget.RecyclerView.ViewHolder; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import java.lang.ref.WeakReference; +import java.util.Map; +import java.util.WeakHashMap; + +import ru.yandex.yamblz.R; +import ru.yandex.yamblz.handler.CriticalSectionsHandler; +import ru.yandex.yamblz.handler.CriticalSectionsManager; +import ru.yandex.yamblz.handler.Task; +import ru.yandex.yamblz.loader.CollageLoaderManager; +import ru.yandex.yamblz.ui.adapters.CollageAdapter.CollageHolder; +import ru.yandex.yamblz.ui.other.ImageType; + +public class CollageAdapter extends Adapter { + private Map> loaderTasks = new WeakHashMap<>(); + private Map images; + + public CollageAdapter(Map images) { + this.images = images; + } + + + static class CollageHolder extends ViewHolder { + TextView label; + ImageView collage; + + public CollageHolder(View view) { + super(view); + label = (TextView) view.findViewById(R.id.label); + collage = (ImageView) view.findViewById(R.id.collage); + } + } + + + @Override + public CollageHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.collage_view, parent, false); + return new CollageHolder(view); + } + + + @Override + public void onBindViewHolder(CollageHolder holder, int position) { + ImageType imageType = ImageType.values()[position]; + + holder.label.setText(imageType.getLabel()); + holder.collage.setImageBitmap(null); + + CriticalSectionsHandler sectionsHandler = CriticalSectionsManager.getHandler(); + + // If there is a pending task for the same image view, remove it + WeakReference refTask = loaderTasks.remove(holder.collage); + if (refTask != null) { + sectionsHandler.removeLowPriorityTask(refTask.get()); + } + + Task task = () -> CollageLoaderManager.getLoader().loadCollage(images.get(imageType), holder.collage); + + sectionsHandler.postLowPriorityTask(task); + + loaderTasks.put(holder.collage, new WeakReference<>(task)); + } + + + @Override + public int getItemCount() { + return images.size(); + } +} diff --git a/app/src/main/java/ru/yandex/yamblz/ui/fragments/ContentFragment.java b/app/src/main/java/ru/yandex/yamblz/ui/fragments/ContentFragment.java index d46490f..f2a73d1 100644 --- a/app/src/main/java/ru/yandex/yamblz/ui/fragments/ContentFragment.java +++ b/app/src/main/java/ru/yandex/yamblz/ui/fragments/ContentFragment.java @@ -3,16 +3,240 @@ import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.RecyclerView.OnScrollListener; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import java.util.HashMap; +import java.util.Map; + import ru.yandex.yamblz.R; +import ru.yandex.yamblz.handler.CriticalSectionsManager; +import ru.yandex.yamblz.ui.adapters.CollageAdapter; +import ru.yandex.yamblz.ui.other.ImageType; + +import static android.support.v7.widget.RecyclerView.SCROLL_STATE_IDLE; +import static ru.yandex.yamblz.ui.other.ImageType.*; public class ContentFragment extends BaseFragment { + @NonNull @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - return inflater.inflate(R.layout.fragment_content, container, false); + View view = inflater.inflate(R.layout.fragment_content, container, false); + + RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.recycler); + recyclerView.setHasFixedSize(true); + recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); + recyclerView.setAdapter(new CollageAdapter(getImages())); + recyclerView.addOnScrollListener(new OnScrollListener() { + int sectionNumber = 0; + + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + if (newState == SCROLL_STATE_IDLE) { + CriticalSectionsManager.getHandler().stopSections(); + } else { + CriticalSectionsManager.getHandler().startSection(sectionNumber++); + } + } + }); + + return view; + } + + + private Map getImages() { + Map images = new HashMap<>(); + + images.put(FOREST, new int[]{ + R.drawable.forest_1, + R.drawable.forest_2, + R.drawable.forest_3, + R.drawable.forest_4, + R.drawable.forest_5, + R.drawable.forest_6 + }); + + images.put(WATER, new int[]{ + R.drawable.water_1, + R.drawable.water_2, + R.drawable.water_3, + R.drawable.water_4, + R.drawable.water_5, + R.drawable.land_5, + R.drawable.mountain_1 + }); + + images.put(ANIMAL, new int[]{ + R.drawable.animal_1, + R.drawable.animal_2, + R.drawable.animal_3, + R.drawable.animal_4, + R.drawable.forest_2, + R.drawable.mountain_2 + }); + + + images.put(SUNSET, new int[]{ + R.drawable.car_4, + R.drawable.desert_2, + R.drawable.land_3, + R.drawable.land_4 + }); + + images.put(DESERT, new int[]{ + R.drawable.desert_1, + R.drawable.desert_2, + R.drawable.desert_3, + R.drawable.desert_4, + R.drawable.desert_5, + R.drawable.car_2 + }); + + images.put(MOUNTAIN, new int[]{ + R.drawable.mountain_1, + R.drawable.mountain_2, + R.drawable.mountain_3, + R.drawable.mountain_4, + R.drawable.mountain_5, + R.drawable.mountain_6, + R.drawable.desert_3, + R.drawable.desert_4 + }); + + + images.put(LANDSCAPE, new int[]{ + R.drawable.land_1, + R.drawable.land_2, + R.drawable.land_3, + R.drawable.land_4, + R.drawable.land_5, + R.drawable.desert_2, + R.drawable.mountain_1, + R.drawable.mountain_4 + }); + + images.put(CAR, new int[]{ + R.drawable.car_1, + R.drawable.car_2, + R.drawable.car_3, + R.drawable.car_4, + R.drawable.car_5, + R.drawable.car_6 + }); + + images.put(ONE, new int[]{ + R.drawable.mountain_5 + }); + + images.put(FOUR, new int[]{ + R.drawable.mountain_3, + R.drawable.desert_4, + R.drawable.land_3, + R.drawable.forest_3 + }); + + images.put(NINE, new int[]{ + R.drawable.mountain_1, + R.drawable.forest_1, + R.drawable.forest_2, + R.drawable.forest_3, + R.drawable.desert_2, + R.drawable.desert_3, + R.drawable.desert_5, + R.drawable.land_5, + R.drawable.car_2 + }); + images.put(SIXTEEN, new int[]{ + R.drawable.forest_3, + R.drawable.forest_6, + R.drawable.water_1, + R.drawable.water_4, + R.drawable.animal_2, + R.drawable.animal_3, + R.drawable.desert_3, + R.drawable.desert_4, + R.drawable.mountain_2, + R.drawable.mountain_3, + R.drawable.land_1, + R.drawable.land_3, + R.drawable.land_4, + R.drawable.car_1, + R.drawable.car_3, + R.drawable.car_4 + }); + + images.put(TWENTY_FIVE, new int[]{ + R.drawable.forest_3, + R.drawable.forest_4, + R.drawable.forest_6, + R.drawable.water_2, + R.drawable.water_3, + R.drawable.water_4, + R.drawable.animal_1, + R.drawable.animal_2, + R.drawable.animal_3, + R.drawable.desert_1, + R.drawable.desert_2, + R.drawable.desert_4, + R.drawable.desert_5, + R.drawable.mountain_1, + R.drawable.mountain_2, + R.drawable.mountain_4, + R.drawable.mountain_6, + R.drawable.land_1, + R.drawable.land_2, + R.drawable.land_3, + R.drawable.land_5, + R.drawable.car_1, + R.drawable.car_3, + R.drawable.car_5, + R.drawable.car_6 + }); + + images.put(THIRTY_SIX, new int[]{ + R.drawable.forest_1, + R.drawable.forest_2, + R.drawable.forest_3, + R.drawable.forest_4, + R.drawable.forest_5, + R.drawable.forest_6, + R.drawable.water_1, + R.drawable.water_2, + R.drawable.water_3, + R.drawable.water_4, + R.drawable.water_5, + R.drawable.animal_1, + R.drawable.animal_2, + R.drawable.animal_3, + R.drawable.animal_4, + R.drawable.desert_1, + R.drawable.desert_2, + R.drawable.desert_3, + R.drawable.desert_4, + R.drawable.mountain_1, + R.drawable.mountain_2, + R.drawable.mountain_3, + R.drawable.mountain_4, + R.drawable.mountain_5, + R.drawable.mountain_6, + R.drawable.land_1, + R.drawable.land_2, + R.drawable.land_3, + R.drawable.land_4, + R.drawable.land_5, + R.drawable.car_1, + R.drawable.car_2, + R.drawable.car_3, + R.drawable.car_4, + R.drawable.car_5, + R.drawable.car_6 + }); + + return images; } } diff --git a/app/src/main/java/ru/yandex/yamblz/ui/other/ImageType.java b/app/src/main/java/ru/yandex/yamblz/ui/other/ImageType.java new file mode 100644 index 0000000..dc363d1 --- /dev/null +++ b/app/src/main/java/ru/yandex/yamblz/ui/other/ImageType.java @@ -0,0 +1,28 @@ +package ru.yandex.yamblz.ui.other; + +public enum ImageType { + FOREST("Forest"), + WATER("Water"), + ANIMAL("Animal"), + SUNSET("Sunset"), + DESERT("Desert"), + MOUNTAIN("Mountain"), + LANDSCAPE("Landscape"), + CAR("Car"), + ONE("One"), + FOUR("Four"), + NINE("Nine"), + SIXTEEN("Sixteen"), + TWENTY_FIVE("Twenty Five"), + THIRTY_SIX("Thirty Six"); + + private final String label; + + ImageType(String label) { + this.label = label; + } + + public String getLabel() { + return label; + } +} diff --git a/app/src/main/res/drawable-nodpi/animal_1.jpg b/app/src/main/res/drawable-nodpi/animal_1.jpg new file mode 100644 index 0000000..2cfd88b Binary files /dev/null and b/app/src/main/res/drawable-nodpi/animal_1.jpg differ diff --git a/app/src/main/res/drawable-nodpi/animal_2.jpg b/app/src/main/res/drawable-nodpi/animal_2.jpg new file mode 100644 index 0000000..b4e40af Binary files /dev/null and b/app/src/main/res/drawable-nodpi/animal_2.jpg differ diff --git a/app/src/main/res/drawable-nodpi/animal_3.jpg b/app/src/main/res/drawable-nodpi/animal_3.jpg new file mode 100644 index 0000000..8fb903d Binary files /dev/null and b/app/src/main/res/drawable-nodpi/animal_3.jpg differ diff --git a/app/src/main/res/drawable-nodpi/animal_4.jpg b/app/src/main/res/drawable-nodpi/animal_4.jpg new file mode 100644 index 0000000..58d1472 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/animal_4.jpg differ diff --git a/app/src/main/res/drawable-nodpi/car_1.jpg b/app/src/main/res/drawable-nodpi/car_1.jpg new file mode 100644 index 0000000..9b395e8 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/car_1.jpg differ diff --git a/app/src/main/res/drawable-nodpi/car_2.jpg b/app/src/main/res/drawable-nodpi/car_2.jpg new file mode 100644 index 0000000..3b8f665 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/car_2.jpg differ diff --git a/app/src/main/res/drawable-nodpi/car_3.jpg b/app/src/main/res/drawable-nodpi/car_3.jpg new file mode 100644 index 0000000..4844d3f Binary files /dev/null and b/app/src/main/res/drawable-nodpi/car_3.jpg differ diff --git a/app/src/main/res/drawable-nodpi/car_4.jpg b/app/src/main/res/drawable-nodpi/car_4.jpg new file mode 100644 index 0000000..53f7d8c Binary files /dev/null and b/app/src/main/res/drawable-nodpi/car_4.jpg differ diff --git a/app/src/main/res/drawable-nodpi/car_5.jpg b/app/src/main/res/drawable-nodpi/car_5.jpg new file mode 100644 index 0000000..19c69d9 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/car_5.jpg differ diff --git a/app/src/main/res/drawable-nodpi/car_6.jpg b/app/src/main/res/drawable-nodpi/car_6.jpg new file mode 100644 index 0000000..a9dae44 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/car_6.jpg differ diff --git a/app/src/main/res/drawable-nodpi/desert_1.jpg b/app/src/main/res/drawable-nodpi/desert_1.jpg new file mode 100644 index 0000000..0c542bc Binary files /dev/null and b/app/src/main/res/drawable-nodpi/desert_1.jpg differ diff --git a/app/src/main/res/drawable-nodpi/desert_2.jpg b/app/src/main/res/drawable-nodpi/desert_2.jpg new file mode 100644 index 0000000..c5bc95e Binary files /dev/null and b/app/src/main/res/drawable-nodpi/desert_2.jpg differ diff --git a/app/src/main/res/drawable-nodpi/desert_3.jpg b/app/src/main/res/drawable-nodpi/desert_3.jpg new file mode 100644 index 0000000..676ce49 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/desert_3.jpg differ diff --git a/app/src/main/res/drawable-nodpi/desert_4.jpg b/app/src/main/res/drawable-nodpi/desert_4.jpg new file mode 100644 index 0000000..eef831b Binary files /dev/null and b/app/src/main/res/drawable-nodpi/desert_4.jpg differ diff --git a/app/src/main/res/drawable-nodpi/desert_5.jpg b/app/src/main/res/drawable-nodpi/desert_5.jpg new file mode 100644 index 0000000..538fcc3 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/desert_5.jpg differ diff --git a/app/src/main/res/drawable-nodpi/forest_1.jpg b/app/src/main/res/drawable-nodpi/forest_1.jpg new file mode 100644 index 0000000..cd28985 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/forest_1.jpg differ diff --git a/app/src/main/res/drawable-nodpi/forest_2.jpg b/app/src/main/res/drawable-nodpi/forest_2.jpg new file mode 100644 index 0000000..ffb4fef Binary files /dev/null and b/app/src/main/res/drawable-nodpi/forest_2.jpg differ diff --git a/app/src/main/res/drawable-nodpi/forest_3.jpg b/app/src/main/res/drawable-nodpi/forest_3.jpg new file mode 100644 index 0000000..569ea8d Binary files /dev/null and b/app/src/main/res/drawable-nodpi/forest_3.jpg differ diff --git a/app/src/main/res/drawable-nodpi/forest_4.jpg b/app/src/main/res/drawable-nodpi/forest_4.jpg new file mode 100644 index 0000000..e1f3dfb Binary files /dev/null and b/app/src/main/res/drawable-nodpi/forest_4.jpg differ diff --git a/app/src/main/res/drawable-nodpi/forest_5.jpg b/app/src/main/res/drawable-nodpi/forest_5.jpg new file mode 100644 index 0000000..263418b Binary files /dev/null and b/app/src/main/res/drawable-nodpi/forest_5.jpg differ diff --git a/app/src/main/res/drawable-nodpi/forest_6.jpg b/app/src/main/res/drawable-nodpi/forest_6.jpg new file mode 100644 index 0000000..4a9b644 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/forest_6.jpg differ diff --git a/app/src/main/res/drawable-nodpi/land_1.jpg b/app/src/main/res/drawable-nodpi/land_1.jpg new file mode 100644 index 0000000..761461f Binary files /dev/null and b/app/src/main/res/drawable-nodpi/land_1.jpg differ diff --git a/app/src/main/res/drawable-nodpi/land_2.jpg b/app/src/main/res/drawable-nodpi/land_2.jpg new file mode 100644 index 0000000..dcc740a Binary files /dev/null and b/app/src/main/res/drawable-nodpi/land_2.jpg differ diff --git a/app/src/main/res/drawable-nodpi/land_3.jpg b/app/src/main/res/drawable-nodpi/land_3.jpg new file mode 100644 index 0000000..1dad47a Binary files /dev/null and b/app/src/main/res/drawable-nodpi/land_3.jpg differ diff --git a/app/src/main/res/drawable-nodpi/land_4.jpg b/app/src/main/res/drawable-nodpi/land_4.jpg new file mode 100644 index 0000000..1382a60 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/land_4.jpg differ diff --git a/app/src/main/res/drawable-nodpi/land_5.jpg b/app/src/main/res/drawable-nodpi/land_5.jpg new file mode 100644 index 0000000..d443f4b Binary files /dev/null and b/app/src/main/res/drawable-nodpi/land_5.jpg differ diff --git a/app/src/main/res/drawable-nodpi/mountain_1.jpg b/app/src/main/res/drawable-nodpi/mountain_1.jpg new file mode 100644 index 0000000..59935b6 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/mountain_1.jpg differ diff --git a/app/src/main/res/drawable-nodpi/mountain_2.jpg b/app/src/main/res/drawable-nodpi/mountain_2.jpg new file mode 100644 index 0000000..a92ea55 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/mountain_2.jpg differ diff --git a/app/src/main/res/drawable-nodpi/mountain_3.jpg b/app/src/main/res/drawable-nodpi/mountain_3.jpg new file mode 100644 index 0000000..481fa30 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/mountain_3.jpg differ diff --git a/app/src/main/res/drawable-nodpi/mountain_4.jpg b/app/src/main/res/drawable-nodpi/mountain_4.jpg new file mode 100644 index 0000000..78a14cf Binary files /dev/null and b/app/src/main/res/drawable-nodpi/mountain_4.jpg differ diff --git a/app/src/main/res/drawable-nodpi/mountain_5.jpg b/app/src/main/res/drawable-nodpi/mountain_5.jpg new file mode 100644 index 0000000..a1a1acf Binary files /dev/null and b/app/src/main/res/drawable-nodpi/mountain_5.jpg differ diff --git a/app/src/main/res/drawable-nodpi/mountain_6.jpg b/app/src/main/res/drawable-nodpi/mountain_6.jpg new file mode 100644 index 0000000..efa4c3d Binary files /dev/null and b/app/src/main/res/drawable-nodpi/mountain_6.jpg differ diff --git a/app/src/main/res/drawable-nodpi/water_1.jpg b/app/src/main/res/drawable-nodpi/water_1.jpg new file mode 100644 index 0000000..ba7b96b Binary files /dev/null and b/app/src/main/res/drawable-nodpi/water_1.jpg differ diff --git a/app/src/main/res/drawable-nodpi/water_2.jpg b/app/src/main/res/drawable-nodpi/water_2.jpg new file mode 100644 index 0000000..7567c27 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/water_2.jpg differ diff --git a/app/src/main/res/drawable-nodpi/water_3.jpg b/app/src/main/res/drawable-nodpi/water_3.jpg new file mode 100644 index 0000000..f148bb5 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/water_3.jpg differ diff --git a/app/src/main/res/drawable-nodpi/water_4.jpg b/app/src/main/res/drawable-nodpi/water_4.jpg new file mode 100644 index 0000000..a429e4a Binary files /dev/null and b/app/src/main/res/drawable-nodpi/water_4.jpg differ diff --git a/app/src/main/res/drawable-nodpi/water_5.jpg b/app/src/main/res/drawable-nodpi/water_5.jpg new file mode 100644 index 0000000..a516ce6 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/water_5.jpg differ diff --git a/app/src/main/res/layout/collage_view.xml b/app/src/main/res/layout/collage_view.xml new file mode 100644 index 0000000..62bdcd0 --- /dev/null +++ b/app/src/main/res/layout/collage_view.xml @@ -0,0 +1,36 @@ + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_content.xml b/app/src/main/res/layout/fragment_content.xml index 81016ea..f4eba82 100644 --- a/app/src/main/res/layout/fragment_content.xml +++ b/app/src/main/res/layout/fragment_content.xml @@ -1,14 +1,12 @@ - - + - + android:scrollbars="vertical"/> - \ No newline at end of file + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7474f04..7ffd8f2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,4 +1,4 @@ - Yamblz + Background HW Hello diff --git a/demo.gif b/demo.gif new file mode 100644 index 0000000..6bcf3dd Binary files /dev/null and b/demo.gif differ diff --git a/dependencies.gradle b/dependencies.gradle index d9cb375..0b34035 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -7,7 +7,7 @@ ext.versions = [ compileSdk : 23, buildTools : '23.0.3', - androidGradlePlugin : '2.2.0-alpha4', + androidGradlePlugin : '2.1.2', aptGradlePlugin : '1.8', retrolambdaGradlePlugin : '3.2.5', lombokGradlePlugin : '0.2.3.a2',