Java tutorial
/* * Copyright 2014 Uwe Trottmann * * 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.battlelancer.seriesguide.extensions; import android.content.ComponentName; import android.content.Context; import android.graphics.Point; import android.os.Bundle; import android.os.Vibrator; import android.support.v4.app.Fragment; import android.support.v4.app.LoaderManager; import android.support.v4.content.Loader; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.PopupMenu; import android.widget.Toast; import butterknife.ButterKnife; import butterknife.InjectView; import com.battlelancer.seriesguide.BuildConfig; import com.battlelancer.seriesguide.R; import com.battlelancer.seriesguide.adapters.ExtensionsAdapter; import com.battlelancer.seriesguide.loaders.AvailableExtensionsLoader; import com.battlelancer.seriesguide.util.Utils; import com.mobeta.android.dslv.DragSortController; import com.mobeta.android.dslv.DragSortListView; import de.greenrobot.event.EventBus; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import timber.log.Timber; /** * Provides tools to display all installed extensions and enable or disable them. */ public class ExtensionsConfigurationFragment extends Fragment implements AdapterView.OnItemClickListener { public static final int EXTENSION_LIMIT_FREE = 2; private static final String TAG = "Extension Configuration"; @InjectView(R.id.listViewExtensionsConfiguration) DragSortListView mListView; private ExtensionsAdapter mAdapter; private PopupMenu mAddExtensionPopupMenu; private List<ExtensionManager.Extension> mAvailableExtensions = new ArrayList<>(); private List<ComponentName> mEnabledExtensions; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_extensions_configuration, container, false); ButterKnife.inject(this, v); final ExtensionsDragSortController dragSortController = new ExtensionsDragSortController(); mListView.setFloatViewManager(dragSortController); mListView.setOnTouchListener(dragSortController); mListView.setDropListener(new DragSortListView.DropListener() { @Override public void drop(int from, int to) { ComponentName extension = mEnabledExtensions.remove(from); mEnabledExtensions.add(to, extension); getLoaderManager().restartLoader(ExtensionsConfigurationActivity.LOADER_ACTIONS_ID, null, mExtensionsLoaderCallbacks); } }); mListView.setOnItemClickListener(this); return v; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mAdapter = new ExtensionsAdapter(getActivity()); mListView.setAdapter(mAdapter); getLoaderManager().initLoader(ExtensionsConfigurationActivity.LOADER_ACTIONS_ID, null, mExtensionsLoaderCallbacks); setHasOptionsMenu(true); } @Override public void onResume() { super.onResume(); EventBus.getDefault().register(this); } @Override public void onPause() { super.onPause(); EventBus.getDefault().unregister(this); if (mEnabledExtensions != null) { // might not have finished loading, yet ExtensionManager.getInstance(getActivity()).setEnabledExtensions(mEnabledExtensions); } } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); inflater.inflate(R.menu.extensions_configuration_menu, menu); if (Utils.isAmazonVersion()) { // no third-party extensions supported on Amazon app store for now menu.findItem(R.id.menu_action_extensions_search).setVisible(false); menu.findItem(R.id.menu_action_extensions_search).setEnabled(false); } if (!BuildConfig.DEBUG) { menu.findItem(R.id.menu_action_extensions_enable).setVisible(false); menu.findItem(R.id.menu_action_extensions_disable).setVisible(false); } } @Override public boolean onOptionsItemSelected(MenuItem item) { int itemId = item.getItemId(); if (itemId == R.id.menu_action_extensions_search) { Utils.launchWebsite(getActivity(), getString(R.string.url_extensions_search), TAG, "Get more extensions"); return true; } if (itemId == R.id.menu_action_extensions_enable) { List<ExtensionManager.Extension> extensions = ExtensionManager.getInstance(getActivity()) .queryAllAvailableExtensions(); List<ComponentName> enabledExtensions = new ArrayList<>(); for (ExtensionManager.Extension extension : extensions) { enabledExtensions.add(extension.componentName); } ExtensionManager.getInstance(getActivity()).setEnabledExtensions(enabledExtensions); Toast.makeText(getActivity(), "Enabled all available extensions", Toast.LENGTH_LONG).show(); return true; } if (itemId == R.id.menu_action_extensions_disable) { ExtensionManager.getInstance(getActivity()).setEnabledExtensions(new ArrayList<ComponentName>()); Toast.makeText(getActivity(), "Disabled all available extensions", Toast.LENGTH_LONG).show(); return true; } return super.onOptionsItemSelected(item); } @Override public void onDestroyView() { super.onDestroyView(); ButterKnife.reset(this); } private LoaderManager.LoaderCallbacks<List<ExtensionManager.Extension>> mExtensionsLoaderCallbacks = new LoaderManager.LoaderCallbacks<List<ExtensionManager.Extension>>() { @Override public Loader<List<ExtensionManager.Extension>> onCreateLoader(int id, Bundle args) { return new AvailableExtensionsLoader(getActivity()); } @Override public void onLoadFinished(Loader<List<ExtensionManager.Extension>> loader, List<ExtensionManager.Extension> availableExtensions) { if (availableExtensions == null || availableExtensions.size() == 0) { Timber.d("Did not find any extension"); } else { Timber.d("Found " + availableExtensions.size() + " extensions"); } if (mEnabledExtensions == null) { mEnabledExtensions = ExtensionManager.getInstance(getActivity()).getEnabledExtensions(); } Set<ComponentName> enabledExtensions = new HashSet<>(mEnabledExtensions); // find all extensions not yet enabled mAvailableExtensions.clear(); Map<ComponentName, ExtensionManager.Extension> enabledExtensionsMap = new HashMap<>(); for (ExtensionManager.Extension extension : availableExtensions) { if (enabledExtensions.contains(extension.componentName)) { // extension is already enabled enabledExtensionsMap.put(extension.componentName, extension); continue; } mAvailableExtensions.add(extension); } // sort available extensions alphabetically Collections.sort(mAvailableExtensions, new Comparator<ExtensionManager.Extension>() { @Override public int compare(ExtensionManager.Extension extension1, ExtensionManager.Extension extension2) { String title1 = createTitle(extension1); String title2 = createTitle(extension2); return title1.compareToIgnoreCase(title2); } private String createTitle(ExtensionManager.Extension extension) { String title = extension.label; if (TextUtils.isEmpty(title)) { title = extension.componentName.flattenToShortString(); } return title; } }); // force re-creation of extension add menu if (mAddExtensionPopupMenu != null) { mAddExtensionPopupMenu.dismiss(); mAddExtensionPopupMenu = null; } // list enabled extensions in order dictated by extension manager List<ExtensionManager.Extension> enabledExtensionsList = new ArrayList<>(); List<ComponentName> enabledExtensionNames = new ArrayList<>(mEnabledExtensions); for (ComponentName extensionName : enabledExtensionNames) { ExtensionManager.Extension extension = enabledExtensionsMap.get(extensionName); if (extension == null) { // filter out any unavailable/uninstalled extensions mEnabledExtensions.remove(extensionName); continue; } enabledExtensionsList.add(extension); } // refresh enabled extensions list mAdapter.clear(); mAdapter.addAll(enabledExtensionsList); } @Override public void onLoaderReset(Loader<List<ExtensionManager.Extension>> loader) { mAdapter.clear(); } }; @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if (position == mAdapter.getCount() - 1) { // non-supporters only can add a few extensions if (mAdapter.getCount() - 1 == EXTENSION_LIMIT_FREE && !Utils.hasAccessToX(getActivity())) { Utils.advertiseSubscription(getActivity()); return; } showAddExtensionPopupMenu(view.findViewById(R.id.textViewItemExtensionAddLabel)); Utils.trackAction(getActivity(), TAG, "Add extension"); } } public void onEventMainThread(ExtensionsAdapter.ExtensionDisableRequestEvent event) { mEnabledExtensions.remove(event.position); getLoaderManager().restartLoader(ExtensionsConfigurationActivity.LOADER_ACTIONS_ID, null, mExtensionsLoaderCallbacks); Utils.trackAction(getActivity(), TAG, "Remove extension"); } private void showAddExtensionPopupMenu(View anchorView) { if (mAddExtensionPopupMenu != null) { mAddExtensionPopupMenu.dismiss(); } mAddExtensionPopupMenu = new PopupMenu(getActivity(), anchorView); for (int i = 0; i < mAvailableExtensions.size(); i++) { ExtensionManager.Extension extension = mAvailableExtensions.get(i); mAddExtensionPopupMenu.getMenu().add(Menu.NONE, i, Menu.NONE, extension.label); } mAddExtensionPopupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(android.view.MenuItem item) { // add to enabled extensions ExtensionManager.Extension extension = mAvailableExtensions.get(item.getItemId()); mEnabledExtensions.add(extension.componentName); // re-populate extension list getLoaderManager().restartLoader(ExtensionsConfigurationActivity.LOADER_ACTIONS_ID, null, mExtensionsLoaderCallbacks); // scroll to end of list mListView.smoothScrollToPosition(mAdapter.getCount() - 1); return true; } }); mAddExtensionPopupMenu.show(); } private class ExtensionsDragSortController extends DragSortController { private int mFloatViewOriginPosition; public ExtensionsDragSortController() { super(mListView, R.id.drag_handle, DragSortController.ON_DOWN, DragSortController.CLICK_REMOVE); setRemoveEnabled(false); } @Override public int startDragPosition(MotionEvent ev) { int hitPosition = super.dragHandleHitPosition(ev); if (hitPosition >= mAdapter.getCount() - 1) { return DragSortController.MISS; } return hitPosition; } @Override public View onCreateFloatView(int position) { // short vibrate to signal drag has started Vibrator v = (Vibrator) mListView.getContext().getSystemService(Context.VIBRATOR_SERVICE); v.vibrate(10); mFloatViewOriginPosition = position; return mAdapter.getView(position, null, mListView); } private int mFloatViewHeight = -1; // cache height @Override public void onDragFloatView(View floatView, Point floatPoint, Point touchPoint) { final int addButtonPosition = mAdapter.getCount() - 1; final int first = mListView.getFirstVisiblePosition(); final int lvDivHeight = mListView.getDividerHeight(); if (mFloatViewHeight == -1) { mFloatViewHeight = floatView.getHeight(); } View div = mListView.getChildAt(addButtonPosition - first); if (touchPoint.x > mListView.getWidth() / 2) { float scale = touchPoint.x - mListView.getWidth() / 2; scale /= (float) (mListView.getWidth() / 5); ViewGroup.LayoutParams lp = floatView.getLayoutParams(); lp.height = Math.max(mFloatViewHeight, (int) (scale * mFloatViewHeight)); floatView.setLayoutParams(lp); } if (div != null) { if (mFloatViewOriginPosition > addButtonPosition) { // don't allow floating View to go above // section divider final int limit = div.getBottom() + lvDivHeight; if (floatPoint.y < limit) { floatPoint.y = limit; } } else { // don't allow floating View to go below // section divider final int limit = div.getTop() - lvDivHeight - floatView.getHeight(); if (floatPoint.y > limit) { floatPoint.y = limit; } } } } @Override public void onDestroyFloatView(View floatView) { //do nothing; block super from crashing } } }