Java tutorial
package com.serenegiant.aceparrot; /* * By downloading, copying, installing or using the software you agree to this license. * If you do not agree to this license, do not download, install, * copy or use the software. * * * License Agreement * (3-clause BSD License) * * Copyright (C) 2015-2017, saki t_saki@serenegiant.com * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * * Neither the names of the copyright holders nor the names of the contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * This software is provided by the copyright holders and contributors "as is" and * any express or implied warranties, including, but not limited to, the implied * warranties of merchantability and fitness for a particular purpose are disclaimed. * In no event shall copyright holders or contributors be liable for any direct, * indirect, incidental, special, exemplary, or consequential damages * (including, but not limited to, procurement of substitute goods or services; * loss of use, data, or profits; or business interruption) however caused * and on any theory of liability, whether in contract, strict liability, * or tort (including negligence or otherwise) arising in any way out of * the use of this software, even if advised of the possibility of such damage. */ import android.content.DialogInterface; import android.media.MediaScannerConnection; import android.os.Bundle; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.text.TextUtils; import android.util.Log; import android.util.SparseBooleanArray; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.CheckBox; import android.widget.ImageButton; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; import com.parrot.arsdk.ardiscovery.ARDiscoveryDeviceService; import com.parrot.arsdk.armedia.ARMediaObject; import com.serenegiant.dialog.ConfirmDialog; import com.serenegiant.dialog.OnDialogResultIntListener; import com.serenegiant.dialog.TransferProgressDialogFragment; import com.serenegiant.arflight.BuildConfig; import com.serenegiant.arflight.R; import java.io.File; import java.util.ArrayList; import java.util.List; import jp.co.rediscovery.arflight.DeviceInfo; import jp.co.rediscovery.arflight.FTPController; import jp.co.rediscovery.arflight.IDeviceController; public class MediaFragment extends BaseFlightControllerFragment implements TransferProgressDialogFragment.TransferProgressDialogListener, OnDialogResultIntListener { private static final boolean DEBUG = false; // FIXME ??false???? private static String TAG = MediaFragment.class.getSimpleName(); private static final int REQUEST_DELETE = 1; private static final int REQUEST_FETCH = 2; public static MediaFragment newInstance(final ARDiscoveryDeviceService device, final DeviceInfo info) { if (!BuildConfig.USE_SKYCONTROLLER) throw new RuntimeException("does not support skycontroller now"); final MediaFragment fragment = new MediaFragment(); fragment.setDevice(device, info); return fragment; } private FTPController mFTPController; private ViewPager mViewPager; private MediaPagerAdapter mPagerAdapter; private String mFreeSpaceFmt; public MediaFragment() { super(); // ?? } /* @Override public void onAttach(final Activity activity) { super.onAttach(activity); if (DEBUG) Log.v(TAG, "onAttach:"); } */ /* @Override public void onDetach() { if (DEBUG) Log.v(TAG, "onDetach:"); super.onDetach(); } */ @Override public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) { if (DEBUG) Log.v(TAG, "onCreateView:"); onBeforeCreateView(); mPagerAdapter = new MediaPagerAdapter(inflater); final LayoutInflater local_inflater = getThemedLayoutInflater(inflater); final View rootView = local_inflater.inflate(R.layout.fragment_media, container, false); mViewPager = (ViewPager) rootView.findViewById(R.id.pager); mViewPager.setAdapter(mPagerAdapter); mFreeSpaceFmt = getString(R.string.media_free_space); return rootView; } @Override public void onDestroy() { if (DEBUG) Log.v(TAG, "onDestroy:"); if (mFTPController != null) { mFTPController.release(); mFTPController = null; } super.onDestroy(); } @Override protected void internalOnResume() { super.internalOnResume(); if (DEBUG) Log.v(TAG, "internalOnResume:"); startDeviceController(); } @Override protected void onConnect(final IDeviceController controller) { if (DEBUG) Log.v(TAG, "#onConnect"); super.onConnect(controller); mFTPController = FTPController.newInstance(getActivity().getApplicationContext(), mController); mFTPController.setCallback(mCallback); queueEvent(mConnectCheckTask, 500); } @Override protected void updateStorageState(final int mass_storage_id, final int size, final int used_size, final boolean plugged, final boolean full, final boolean internal) { runOnUiThread(new Runnable() { @Override public void run() { if (mFreeSpaceProgressbar != null) { mFreeSpaceProgressbar.setProgress((int) (used_size / (float) size * 100f)); } if (mFreeSpaceText != null) { final String free_space = ARMediaObjectListAdapter .getSizeString(!full ? (size - used_size) * 1024f * 1024f : 0); mFreeSpaceText.setText(String.format(mFreeSpaceFmt, free_space)); } } }); } @Override protected void onDisconnect(final IDeviceController controller) { if (DEBUG) Log.v(TAG, "#onDisconnect"); requestPopBackStack(POP_BACK_STACK_DELAY); super.onDisconnect(controller); } @Override protected void updateBattery(final IDeviceController controller, final int percent) { } @Override protected void updateWiFiSignal(final IDeviceController controller, final int rssi) { } @Override protected void updateAlarmState(final IDeviceController controller, final int alert_state) { } @Override protected void updateFlyingState(final IDeviceController controller, final int state) { } /** * ?????????Runnable */ private final Runnable mConnectCheckTask = new Runnable() { @Override public void run() { if (DEBUG) Log.v(TAG, "mConnectCheckTask#run:"); final String mass_storage_name = mFlightController.getMassStorageName(); if (TextUtils.isEmpty(mass_storage_name)) { queueEvent(this, 1000); // ????????1?? } else { mFTPController.connect(); } } }; /** * FTPController??? */ private final FTPController.FTPControllerCallback mCallback = new FTPController.FTPControllerCallback() { @Override public boolean onError(final int requestCode, final Exception e) { Log.w(TAG, e); return false; } @Override public void onMediaListUpdated(final int requestCode, final List<ARMediaObject> medias) { runOnUiThread(new Runnable() { @Override public void run() { if (mARMediaObjectListAdapter != null) { mARMediaObjectListAdapter.clear(); mARMediaObjectListAdapter.addAll(medias); mARMediaObjectListAdapter.notifyDataSetChanged(); } } }); } @Override public void onProgress(final int requestCode, final float progress, final int current, final int total) { // if (DEBUG) Log.v(TAG, String.format("onProgress:%d,%f,%d/%d", cmd, progress, current, total)); if (mTransferProgressDialogFragment != null) { mTransferProgressDialogFragment.setProgress(current, total, progress); } } @Override public void onFinished(final int requestCode, final int error, final ARMediaObject[] medias) { if (DEBUG) Log.v(TAG, String.format("onFinished:%d,%d", requestCode, error)); hideTransferProgress(); if ((error == 0) && (requestCode == REQUEST_FETCH)) { new Thread(new Runnable() { @Override public void run() { final int n = medias != null ? medias.length : 0; if (n > 0) { final List<String> list = new ArrayList<String>(); for (final ARMediaObject mediaObject : medias) { try { final File file = new File(mediaObject.getFilePath()); if (file.exists() && (file.length() == mediaObject.getSize())) { list.add(mediaObject.getFilePath()); } } catch (final Exception e) { } } final int m = list.size(); if (m > 0) { final String[] paths = new String[m]; list.toArray(paths); runOnUiThread(new Runnable() { @Override public void run() { try { MediaScannerConnection.scanFile(getActivity().getApplicationContext(), paths, null, null); } catch (final Exception e) { Log.w(TAG, e); } } }); } } } }).start(); } } }; private final View.OnClickListener mOnClickListener = new View.OnClickListener() { @Override public void onClick(View view) { int i = view.getId(); if (i == R.id.delete_btn) {// ? ConfirmDialog.showDialog(MediaFragment.this, REQUEST_DELETE, getString(R.string.confirm_delete), null); } else if (i == R.id.fetch_btn) {// FIXME ??? transferMedias(); } } }; @Override public void onCancel(final int requestID) { mFTPController.cancel(); hideTransferProgress(); } @Override public void onDialogResult(final DialogInterface dialog, final int id, final int result) { if (result == DialogInterface.BUTTON_POSITIVE) { // OK?? switch (id) { case REQUEST_DELETE: deleteMedias(); break; } } } /** * ????? */ private void deleteMedias() { final ARMediaObject[] medias = getSelectedMedias(); if (medias != null && medias.length > 0) { mFTPController.delete(REQUEST_DELETE, medias); if (mARMediaObjectListAdapter != null) { for (final ARMediaObject mediaObject : medias) { mARMediaObjectListAdapter.remove(mediaObject); } } } } private TransferProgressDialogFragment mTransferProgressDialogFragment; /** * ?????? */ private void transferMedias() { final boolean needDelete = mDeleteAfterFetchCheckBox != null && mDeleteAfterFetchCheckBox.isChecked(); final ARMediaObject[] medias = getSelectedMedias(); if (medias != null) { mTransferProgressDialogFragment = TransferProgressDialogFragment.showDialog(this, getString(R.string.loading), null); mFTPController.transfer(REQUEST_FETCH, medias, needDelete); } } /** * ??? */ private void hideTransferProgress() { runOnUiThread(new Runnable() { @Override public void run() { if (mTransferProgressDialogFragment != null) { mTransferProgressDialogFragment.dismiss(); mTransferProgressDialogFragment = null; } if (mMediaListView != null) { mMediaListView.clearChoices(); mARMediaObjectListAdapter.notifyDataSetChanged(); } updateMediaList(); } }); } /** * (???UI??) */ private void updateMediaList() { runOnUiThread(mUpdateMediaListTask); } /** * ??on UI */ private final Runnable mUpdateMediaListTask = new Runnable() { @Override public void run() { if (DEBUG) Log.v(TAG, "mUpdateMediaListTask:count=" + mMediaListView.getCheckedItemCount()); final boolean selected = mMediaListView != null && mMediaListView.getCheckedItemCount() > 0; final int visibility = selected ? View.VISIBLE : View.INVISIBLE; if (mDeleteBtn != null) { mDeleteBtn.setVisibility(visibility); } if (mFetchBtn != null) { mFetchBtn.setVisibility(visibility); } if (mDeleteAfterFetchCheckBox != null) { if (visibility != mDeleteAfterFetchCheckBox.getVisibility()) { mDeleteAfterFetchCheckBox.setChecked(false); } mDeleteAfterFetchCheckBox.setVisibility(visibility); } } }; /** * ??? * @return */ private ARMediaObject[] getSelectedMedias() { ARMediaObject[] result = null; if (mMediaListView != null) { final SparseBooleanArray ids = mMediaListView.getCheckedItemPositions(); final int n = ids != null ? ids.size() : 0; if (n > 0) { final List<ARMediaObject> list = new ArrayList<ARMediaObject>(); for (int i = 0; i < n; i++) { if (ids.valueAt(i)) { final Object obj = mMediaListView.getItemAtPosition(ids.keyAt(i)); if (obj instanceof ARMediaObject) { list.add((ARMediaObject) obj); } } } final int m = list.size(); if (m > 0) { result = new ARMediaObject[m]; list.toArray(result); } } } return result; } private ARMediaObjectListAdapter mARMediaObjectListAdapter; // ????Adapter private ListView mMediaListView; private ImageButton mDeleteBtn; private ImageButton mFetchBtn; private CheckBox mDeleteAfterFetchCheckBox; private ProgressBar mFreeSpaceProgressbar; private TextView mFreeSpaceText; /** * ?? * @param rootView */ private void initMediaList(final View rootView) { mMediaListView = (ListView) rootView.findViewById(R.id.listView); if (mMediaListView != null) { mARMediaObjectListAdapter = new ARMediaObjectListAdapter(getActivity(), R.layout.list_item_media); final View empty_view = rootView.findViewById(R.id.empty_view); mMediaListView.setEmptyView(empty_view); mMediaListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(final AdapterView<?> parent, final View view, final int position, final long id) { // if (DEBUG) Log.v(TAG, "onItemClick:"); updateMediaList(); } }); mMediaListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); mMediaListView.setAdapter(mARMediaObjectListAdapter); } mFreeSpaceProgressbar = (ProgressBar) rootView.findViewById(R.id.frees_pace_progress); mFreeSpaceText = (TextView) rootView.findViewById(R.id.free_space_textview); mDeleteBtn = (ImageButton) rootView.findViewById(R.id.delete_btn); mDeleteBtn.setOnClickListener(mOnClickListener); mFetchBtn = (ImageButton) rootView.findViewById(R.id.fetch_btn); mFetchBtn.setOnClickListener(mOnClickListener); mDeleteAfterFetchCheckBox = (CheckBox) rootView.findViewById(R.id.delete_after_fetch_checkbox); updateMediaList(); } private static interface AdapterItemHandler { public void initialize(final MediaFragment parent, final View view); } private static final class PagerAdapterConfig { final int title_id; final int layout_id; final AdapterItemHandler handler; PagerAdapterConfig(final int _title_id, final int _layout_id, final AdapterItemHandler _handler) { title_id = _title_id; layout_id = _layout_id; handler = _handler; } } private static PagerAdapterConfig[] PAGER_MEDIA; static { PAGER_MEDIA = new PagerAdapterConfig[1]; PAGER_MEDIA[0] = new PagerAdapterConfig(R.string.media_title_list, R.layout.media_list, new AdapterItemHandler() { @Override public void initialize(final MediaFragment parent, final View view) { parent.initMediaList(view); } }); }; /** * ????View??????PagerAdapter */ private class MediaPagerAdapter extends PagerAdapter { private final LayoutInflater mInflater; public MediaPagerAdapter(final LayoutInflater inflater) { super(); mInflater = inflater; } @Override public synchronized Object instantiateItem(final ViewGroup container, final int position) { if (DEBUG) Log.v(TAG, "instantiateItem:position=" + position); View view = null; if ((position >= 0) && (position < PAGER_MEDIA.length)) { final PagerAdapterConfig config = PAGER_MEDIA[position]; view = mInflater.inflate(config.layout_id, container, false); config.handler.initialize(MediaFragment.this, view); } if (view != null) { container.addView(view); } return view; } @Override public synchronized void destroyItem(final ViewGroup container, final int position, final Object object) { if (DEBUG) Log.v(TAG, "destroyItem:position=" + position); if (object instanceof View) { container.removeView((View) object); } } @Override public int getCount() { return PAGER_MEDIA.length; } @Override public boolean isViewFromObject(final View view, final Object object) { return view.equals(object); } @Override public CharSequence getPageTitle(final int position) { if (DEBUG) Log.v(TAG, "getPageTitle:position=" + position); CharSequence result = null; if ((position >= 0) && (position < PAGER_MEDIA.length)) { result = getString(PAGER_MEDIA[position].title_id); } return result; } } }