Java tutorial
/* * Copyright 2014-2016 Fukurou Mishiranu * * 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 com.mishiranu.dashchan.ui.gallery; import java.io.File; import java.util.ArrayList; import android.annotation.TargetApi; import android.app.ActionBar; import android.content.Intent; import android.content.res.Configuration; import android.graphics.Color; import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.media.AudioManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.support.v4.content.LocalBroadcastManager; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; import android.widget.FrameLayout; import android.widget.TextView; import chan.content.ChanLocator; import chan.content.ChanManager; import chan.util.StringUtils; import com.mishiranu.dashchan.C; import com.mishiranu.dashchan.R; import com.mishiranu.dashchan.content.CacheManager; import com.mishiranu.dashchan.content.DownloadManager; import com.mishiranu.dashchan.content.model.AttachmentItem; import com.mishiranu.dashchan.content.model.GalleryItem; import com.mishiranu.dashchan.graphics.ActionIconSet; import com.mishiranu.dashchan.graphics.GalleryBackgroundDrawable; import com.mishiranu.dashchan.preference.Preferences; import com.mishiranu.dashchan.ui.ActionMenuConfigurator; import com.mishiranu.dashchan.ui.ForegroundManager; import com.mishiranu.dashchan.ui.StateActivity; import com.mishiranu.dashchan.util.AnimationUtils; import com.mishiranu.dashchan.util.FlagUtils; import com.mishiranu.dashchan.util.NavigationUtils; import com.mishiranu.dashchan.util.ToastUtils; import com.mishiranu.dashchan.util.ViewUtils; import com.mishiranu.dashchan.widget.WindowControlFrameLayout; public class GalleryActivity extends StateActivity implements GalleryInstance.Callback, WindowControlFrameLayout.OnApplyWindowPaddingsListener { private static final String EXTRA_POSITION = "position"; private static final String EXTRA_GALLERY_WINDOW = "galleryWindow"; private static final String EXTRA_GALLERY_MODE = "galleryMode"; private static final String EXTRA_SYSTEM_UI_VISIBILITY = "systemUIVisibility"; private String threadTitle; private final GalleryInstance instance = new GalleryInstance(this, this); private View actionBar; private WindowControlFrameLayout rootView; private GalleryBackgroundDrawable backgroundDrawable; private boolean galleryWindow, galleryMode; private boolean allowNavigatePost; private boolean overrideUpButton = false; private final boolean scrollThread = Preferences.isScrollThreadGallery(); private static final int ACTION_BAR_COLOR = 0xaa202020; private static final int BACKGROUND_COLOR = 0xf0101010; private final ActionMenuConfigurator actionMenuConfigurator = new ActionMenuConfigurator(); private PagerUnit pagerUnit; private ListUnit listUnit; @TargetApi(Build.VERSION_CODES.LOLLIPOP) private void applyStatusNavigationTranslucency() { if (C.API_LOLLIPOP) { Window window = getWindow(); int color = ACTION_BAR_COLOR; window.setStatusBarColor(color); window.setNavigationBarColor(color); window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); } } @Override public void onCreate(Bundle savedInstanceState) { getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); int[] imageViewPosition = savedInstanceState == null ? getIntent().getIntArrayExtra(C.EXTRA_VIEW_POSITION) : null; if (!C.API_LOLLIPOP || imageViewPosition == null) { overridePendingTransition(R.anim.fast_fade_in, 0); } applyStatusNavigationTranslucency(); super.onCreate(savedInstanceState); setVolumeControlStream(AudioManager.STREAM_MUSIC); getActionBar().setDisplayHomeAsUpEnabled(true); ViewUtils.applyToolbarStyle(this, null); expandedScreen = getIntent().getBooleanExtra(C.EXTRA_ALLOW_EXPANDED_SCREEN, false); instance.actionBarColor = ACTION_BAR_COLOR; boolean obtainImages = getIntent().getBooleanExtra(C.EXTRA_OBTAIN_ITEMS, false); ArrayList<GalleryItem> galleryItems = obtainImages ? NavigationUtils.obtainImagesProvider(this) : null; String chanName = getIntent().getStringExtra(C.EXTRA_CHAN_NAME); Uri uri = getIntent().getData(); int imagePosition = savedInstanceState != null ? savedInstanceState.getInt(EXTRA_POSITION, -1) : -1; if (chanName == null && uri != null) { chanName = ChanManager.getInstance().getChanNameByHost(uri.getAuthority()); } ChanLocator locator = null; if (chanName != null) { locator = ChanLocator.get(chanName); } threadTitle = getIntent().getStringExtra(C.EXTRA_THREAD_TITLE); boolean defaultLocator = false; if (locator == null) { locator = ChanLocator.getDefault(); defaultLocator = true; } if (uri != null && galleryItems == null) { galleryItems = new ArrayList<>(1); String boardName = null; String threadNumber = null; if (!defaultLocator) { boardName = locator.safe(true).getBoardName(uri); threadNumber = locator.safe(true).getThreadNumber(uri); } galleryItems.add(new GalleryItem(uri, boardName, threadNumber)); overrideUpButton = true; imagePosition = 0; } else if (imagePosition == -1) { imagePosition = getIntent().getIntExtra(C.EXTRA_IMAGE_INDEX, 0); } instance.chanName = chanName; instance.locator = locator; instance.galleryItems = galleryItems; allowNavigatePost = getIntent().getBooleanExtra(C.EXTRA_ALLOW_NAVIGATE_POST, false); actionBar = findViewById(getResources().getIdentifier("action_bar", "id", "android")); rootView = new WindowControlFrameLayout(this); rootView.setOnApplyWindowPaddingsListener(this); rootView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); backgroundDrawable = new GalleryBackgroundDrawable(rootView, C.API_LOLLIPOP ? imageViewPosition : null, BACKGROUND_COLOR); rootView.setBackground(backgroundDrawable); setContentView(rootView); if (galleryItems == null || galleryItems.size() == 0) { View errorView = getLayoutInflater().inflate(R.layout.widget_error, rootView, false); TextView textView = (TextView) errorView.findViewById(R.id.error_text); textView.setText(R.string.message_empty_gallery); rootView.addView(errorView); } else { listUnit = new ListUnit(instance); pagerUnit = new PagerUnit(instance); rootView.addView(listUnit.getListView(), FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT); rootView.addView(pagerUnit.getView(), FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT); pagerUnit.addAndInitViews(rootView, imagePosition); if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_GALLERY_MODE)) { galleryMode = savedInstanceState.getBoolean(EXTRA_GALLERY_MODE); galleryWindow = savedInstanceState.getBoolean(EXTRA_GALLERY_WINDOW); switchMode(galleryMode, false); modifySystemUiVisibility(GalleryInstance.FLAG_LOCKED_USER, savedInstanceState.getBoolean(EXTRA_SYSTEM_UI_VISIBILITY)); } else { galleryWindow = imagePosition < 0 || getIntent().getBooleanExtra(C.EXTRA_GALLERY_MODE, false); if (galleryWindow && imagePosition >= 0) { listUnit.setListSelection(imagePosition, false); } switchMode(galleryWindow, false); } pagerUnit.onViewsCreated(imageViewPosition); } } @Override protected void onResume() { super.onResume(); if (pagerUnit != null) { pagerUnit.onResume(); } ForegroundManager.register(this); } @Override protected void onPause() { super.onPause(); if (pagerUnit != null) { pagerUnit.onPause(); } ForegroundManager.unregister(this); } @Override protected void onFinish() { super.onFinish(); if (listUnit != null) { listUnit.onFinish(); } if (pagerUnit != null) { pagerUnit.onFinish(); } } @Override public void finish() { super.finish(); overridePendingTransition(0, R.anim.fast_fade_out); } private void invalidateListPosition() { listUnit.setListSelection(pagerUnit.getCurrentIndex(), true); } private final Runnable returnToGalleryRunnable = () -> { switchMode(true, true); invalidateListPosition(); }; private boolean returnToGallery() { if (galleryWindow && !galleryMode) { pagerUnit.onBackToGallery(); rootView.post(returnToGalleryRunnable); return true; } return false; } @Override public void onBackPressed() { if (!returnToGallery()) { super.onBackPressed(); } } private static final int OPTIONS_MENU_SAVE = 0; private static final int OPTIONS_MENU_GALLERY = 1; private static final int OPTIONS_MENU_REFRESH = 2; private static final int OPTIONS_MENU_TECHNICAL_INFO = 3; private static final int OPTIONS_MENU_SEARCH_IMAGE = 4; private static final int OPTIONS_MENU_COPY_LINK = 5; private static final int OPTIONS_MENU_NAVIGATE_POST = 6; private static final int OPTIONS_MENU_SHARE_LINK = 7; private static final int OPTIONS_MENU_SHARE_FILE = 8; private static final int OPTIONS_MENU_SELECT = 9; @Override public boolean onCreateOptionsMenu(Menu menu) { ActionIconSet set = new ActionIconSet(this); menu.add(0, OPTIONS_MENU_SAVE, 0, R.string.action_save).setIcon(set.getId(R.attr.actionSave)) .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); menu.add(0, OPTIONS_MENU_GALLERY, 0, R.string.action_gallery); menu.add(0, OPTIONS_MENU_REFRESH, 0, R.string.action_refresh).setIcon(set.getId(R.attr.actionRefresh)) .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); menu.add(0, OPTIONS_MENU_TECHNICAL_INFO, 0, R.string.action_technical_info); menu.add(0, OPTIONS_MENU_SEARCH_IMAGE, 0, R.string.action_search_image); menu.add(0, OPTIONS_MENU_COPY_LINK, 0, R.string.action_copy_link); menu.add(0, OPTIONS_MENU_NAVIGATE_POST, 0, R.string.action_go_to_post); menu.add(0, OPTIONS_MENU_SHARE_LINK, 0, R.string.action_share_link); menu.add(0, OPTIONS_MENU_SHARE_FILE, 0, R.string.action_share_file); menu.add(0, OPTIONS_MENU_SELECT, 0, R.string.action_select).setIcon(set.getId(R.attr.actionSelect)) .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); actionMenuConfigurator.onAfterCreateOptionsMenu(menu); return true; } @Override public boolean onPrepareOptionsMenu(Menu menu) { for (int i = 0; i < menu.size(); i++) { menu.getItem(i).setVisible(false); } if (!galleryMode) { PagerUnit.OptionsMenuCapabilities capabilities = pagerUnit != null ? pagerUnit.obtainOptionsMenuCapabilities() : null; if (capabilities != null && capabilities.available) { menu.findItem(OPTIONS_MENU_SAVE).setVisible(capabilities.save); menu.findItem(OPTIONS_MENU_GALLERY).setVisible(!galleryWindow && instance.galleryItems.size() > 1); menu.findItem(OPTIONS_MENU_REFRESH).setVisible(capabilities.refresh); menu.findItem(OPTIONS_MENU_TECHNICAL_INFO).setVisible(capabilities.viewTechnicalInfo); menu.findItem(OPTIONS_MENU_SEARCH_IMAGE).setVisible(capabilities.searchImage); menu.findItem(OPTIONS_MENU_COPY_LINK).setVisible(true); menu.findItem(OPTIONS_MENU_NAVIGATE_POST) .setVisible(allowNavigatePost && !scrollThread && capabilities.navigatePost); menu.findItem(OPTIONS_MENU_SHARE_LINK).setVisible(true); menu.findItem(OPTIONS_MENU_SHARE_FILE).setVisible(capabilities.shareFile); } } else { menu.findItem(OPTIONS_MENU_SELECT).setVisible(listUnit.areItemsSelectable()); } actionMenuConfigurator.onAfterPrepareOptionsMenu(menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { GalleryItem galleryItem = pagerUnit != null ? pagerUnit.getCurrentGalleryItem() : null; switch (item.getItemId()) { case android.R.id.home: { NavigationUtils.handleGalleryUpButtonClick(this, overrideUpButton, instance.chanName, galleryItem); break; } case OPTIONS_MENU_SAVE: { downloadGalleryItem(galleryItem); break; } case OPTIONS_MENU_GALLERY: { galleryWindow = true; switchMode(true, true); invalidateListPosition(); break; } case OPTIONS_MENU_REFRESH: { pagerUnit.refreshCurrent(); break; } case OPTIONS_MENU_TECHNICAL_INFO: { pagerUnit.viewTechnicalInfo(); break; } case OPTIONS_MENU_SEARCH_IMAGE: { pagerUnit.forcePauseVideo(); NavigationUtils.searchImage(this, instance.chanName, galleryItem.getDisplayImageUri(instance.locator)); break; } case OPTIONS_MENU_COPY_LINK: { StringUtils.copyToClipboard(this, galleryItem.getFileUri(instance.locator).toString()); break; } case OPTIONS_MENU_NAVIGATE_POST: { navigatePost(galleryItem, true); break; } case OPTIONS_MENU_SHARE_LINK: { pagerUnit.forcePauseVideo(); NavigationUtils.share(this, galleryItem.getFileUri(instance.locator)); break; } case OPTIONS_MENU_SHARE_FILE: { pagerUnit.forcePauseVideo(); Uri uri = galleryItem.getFileUri(instance.locator); File file = CacheManager.getInstance().getMediaFile(uri, false); if (file == null) { ToastUtils.show(this, R.string.message_cache_unavailable); } else { NavigationUtils.shareFile(this, file, galleryItem.getFileName(instance.locator)); } break; } case OPTIONS_MENU_SELECT: { listUnit.startSelectionMode(); break; } } return true; } @Override public void downloadGalleryItem(GalleryItem galleryItem) { galleryItem.downloadStorage(this, instance.locator, threadTitle); } @Override public void downloadGalleryItems(ArrayList<GalleryItem> galleryItems) { String boardName = null; String threadNumber = null; ArrayList<DownloadManager.RequestItem> requestItems = new ArrayList<>(); for (GalleryItem galleryItem : galleryItems) { if (requestItems.size() == 0) { boardName = galleryItem.boardName; threadNumber = galleryItem.threadNumber; } else if (boardName != null || threadNumber != null) { if (!StringUtils.equals(boardName, galleryItem.boardName) || !StringUtils.equals(threadNumber, galleryItem.threadNumber)) { // Images from different threads, so don't use them to mark files and folders boardName = null; threadNumber = null; } } requestItems.add(new DownloadManager.RequestItem(galleryItem.getFileUri(instance.locator), galleryItem.getFileName(instance.locator), galleryItem.originalName)); } if (requestItems.size() > 0) { DownloadManager.getInstance().downloadStorage(this, requestItems, instance.chanName, boardName, threadNumber, threadTitle, true); } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); if (pagerUnit != null) { outState.putInt(EXTRA_POSITION, pagerUnit.getCurrentIndex()); } outState.putBoolean(EXTRA_GALLERY_WINDOW, galleryWindow); outState.putBoolean(EXTRA_GALLERY_MODE, galleryMode); outState.putBoolean(EXTRA_SYSTEM_UI_VISIBILITY, FlagUtils.get(systemUiVisibilityFlags, GalleryInstance.FLAG_LOCKED_USER)); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); ViewUtils.applyToolbarStyle(this, null); if (listUnit != null) { listUnit.onConfigurationChanged(newConfig); } if (pagerUnit != null) { pagerUnit.onConfigurationChanged(newConfig); } actionMenuConfigurator.onConfigurationChanged(newConfig); invalidateSystemUiVisibility(); } private static final int GALLERY_TRANSITION_DURATION = 150; private void switchMode(boolean galleryMode, boolean animated) { int duration = animated ? GALLERY_TRANSITION_DURATION : 0; pagerUnit.switchMode(galleryMode, duration); listUnit.switchMode(galleryMode, duration); if (galleryMode) { int count = instance.galleryItems.size(); setTitle(R.string.action_gallery); getActionBar().setSubtitle( getResources().getQuantityString(R.plurals.text_several_files_count_format, count, count)); } modifySystemUiVisibility(GalleryInstance.FLAG_LOCKED_GRID, galleryMode); this.galleryMode = galleryMode; if (galleryMode) { new CornerAnimator(0xa0, 0xc0); } else { int alpha = Color.alpha(ACTION_BAR_COLOR); new CornerAnimator(alpha, alpha); } invalidateOptionsMenu(); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) private class CornerAnimator implements Runnable { private final long startTime = System.currentTimeMillis(); private final int fromActionBarAlpha; private final int toActionBarAlpha; private final int fromStatusBarAlpha; private final int toStatusBarAlpha; private static final int INTERVAL = 200; public CornerAnimator(int actionBarAlpha, int statusBarAlpha) { Drawable drawable = actionBar.getBackground(); fromActionBarAlpha = Color.alpha( drawable instanceof ColorDrawable ? ((ColorDrawable) drawable).getColor() : statusBarAlpha); toActionBarAlpha = actionBarAlpha; if (C.API_LOLLIPOP) { fromStatusBarAlpha = Color.alpha(getWindow().getStatusBarColor()); toStatusBarAlpha = statusBarAlpha; } else { fromStatusBarAlpha = 0x00; toStatusBarAlpha = 0x00; } if (fromActionBarAlpha != toActionBarAlpha || fromStatusBarAlpha != toStatusBarAlpha) { run(); } } @Override public void run() { float t = Math.min((float) (System.currentTimeMillis() - startTime) / INTERVAL, 1f); int actionBarColorAlpha = (int) AnimationUtils.lerp(fromActionBarAlpha, toActionBarAlpha, t); actionBar.setBackgroundColor((actionBarColorAlpha << 24) | (0x00ffffff & ACTION_BAR_COLOR)); if (C.API_LOLLIPOP) { int statusBarColorAlpha = (int) AnimationUtils.lerp(fromStatusBarAlpha, toStatusBarAlpha, t); int color = (statusBarColorAlpha << 24) | (0x00ffffff & ACTION_BAR_COLOR); Window window = getWindow(); window.setStatusBarColor(color); window.setNavigationBarColor(color); } if (t < 1f) { rootView.postOnAnimation(this); } } } @Override public void modifyVerticalSwipeState(float value) { if (!galleryWindow) { backgroundDrawable.setAlpha((int) (0xff * (1f - value))); } } @Override public void updateTitle() { GalleryItem galleryItem = pagerUnit.getCurrentGalleryItem(); if (galleryItem != null) { setTitle(galleryItem, pagerUnit.getCurrentIndex(), galleryItem.size); } } private void setTitle(GalleryItem galleryItem, int position, int size) { String fileName = galleryItem.getFileName(instance.locator); String originalName = galleryItem.originalName; if (originalName != null) { fileName = originalName; } setTitle(fileName); int count = instance.galleryItems.size(); StringBuilder builder = new StringBuilder().append(position + 1).append('/').append(count); if (size > 0) { builder.append(", ").append(AttachmentItem.formatSize(size)); } getActionBar().setSubtitle(builder); } @Override public void navigateGalleryOrFinish() { if (!returnToGallery()) { finish(); } } @Override public void navigatePageFromList(int position) { switchMode(false, true); pagerUnit.navigatePageFromList(position, GALLERY_TRANSITION_DURATION); } @Override public void navigatePost(GalleryItem galleryItem, boolean force) { if (allowNavigatePost && (scrollThread || force)) { Intent intent = new Intent(C.ACTION_GALLERY_NAVIGATE_POST) .putExtra(C.EXTRA_CHAN_NAME, instance.chanName) .putExtra(C.EXTRA_BOARD_NAME, galleryItem.boardName) .putExtra(C.EXTRA_THREAD_NUMBER, galleryItem.threadNumber) .putExtra(C.EXTRA_POST_NUMBER, galleryItem.postNumber); LocalBroadcastManager.getInstance(GalleryActivity.this).sendBroadcast(intent); if (force) { finish(); } } } @Override public void setScreenOnFixed(boolean fixed) { Window window = getWindow(); if (fixed) { window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } else { window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } } @Override public boolean isGalleryWindow() { return galleryWindow; } @Override public boolean isGalleryMode() { return galleryMode; } private boolean expandedScreen; private int systemUiVisibilityFlags = GalleryInstance.FLAG_LOCKED_USER; @TargetApi(Build.VERSION_CODES.KITKAT) private void invalidateSystemUiVisibility() { ActionBar actionBar = getActionBar(); boolean visible = isSystemUiVisible(); if (visible) { actionBar.show(); } else { actionBar.hide(); } if (C.API_LOLLIPOP && expandedScreen) { View decorView = getWindow().getDecorView(); int visibility = decorView.getSystemUiVisibility(); visibility = FlagUtils.set(visibility, View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION, !visible); decorView.setSystemUiVisibility(visibility); } if (pagerUnit != null) { pagerUnit.invalidateControlsVisibility(); } } private void postInvalidateSystemUIVisibility() { rootView.post(() -> invalidateSystemUiVisibility()); } @Override public boolean isSystemUiVisible() { return systemUiVisibilityFlags != 0; } @Override public void modifySystemUiVisibility(int flag, boolean value) { systemUiVisibilityFlags = FlagUtils.set(systemUiVisibilityFlags, flag, value); invalidateSystemUiVisibility(); } @Override public void toggleSystemUIVisibility(int flag) { modifySystemUiVisibility(flag, !FlagUtils.get(systemUiVisibilityFlags, flag)); } @Override public void onApplyWindowPaddings(WindowControlFrameLayout view, Rect rect) { if (listUnit != null) { boolean invalidate = listUnit.onApplyWindowPaddings(rect); if (invalidate) { postInvalidateSystemUIVisibility(); } } if (pagerUnit != null) { pagerUnit.onApplyWindowPaddings(rect); } } }