1d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu/*
2d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu * Copyright (C) 2013 The Android Open Source Project
3d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu *
4d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu * Licensed under the Apache License, Version 2.0 (the "License");
5d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu * you may not use this file except in compliance with the License.
6d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu * You may obtain a copy of the License at
7d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu *
8d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu *      http://www.apache.org/licenses/LICENSE-2.0
9d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu *
10d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu * Unless required by applicable law or agreed to in writing, software
11d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu * distributed under the License is distributed on an "AS IS" BASIS,
12d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu * See the License for the specific language governing permissions and
14d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu * limitations under the License.
15d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu */
16d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
17d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescupackage com.android.gallery3d.ingest;
18d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
19d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.app.Activity;
20d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.app.ProgressDialog;
21d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.content.ComponentName;
22d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.content.Context;
23d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.content.Intent;
24d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.content.ServiceConnection;
25c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescuimport android.content.res.Configuration;
26c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescuimport android.database.DataSetObserver;
27d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.mtp.MtpObjectInfo;
28d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.os.Bundle;
29d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.os.Handler;
30d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.os.IBinder;
31d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.os.Message;
32c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescuimport android.support.v4.view.ViewPager;
33d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.util.SparseBooleanArray;
34d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.view.ActionMode;
35d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.view.Menu;
36d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.view.MenuInflater;
37d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.view.MenuItem;
38d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.view.View;
39d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.widget.AbsListView.MultiChoiceModeListener;
40d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.widget.AdapterView;
41d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.widget.AdapterView.OnItemClickListener;
426516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescuimport android.widget.TextView;
43d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
44d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport com.android.gallery3d.R;
45c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescuimport com.android.gallery3d.ingest.adapter.CheckBroker;
46d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport com.android.gallery3d.ingest.adapter.MtpAdapter;
47c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescuimport com.android.gallery3d.ingest.adapter.MtpPagerAdapter;
48c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescuimport com.android.gallery3d.ingest.data.MtpBitmapFetch;
49f63e1f7ab9a4f4a97909564cfc5975cbac66872fBobby Georgescuimport com.android.gallery3d.ingest.ui.DateTileView;
50c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescuimport com.android.gallery3d.ingest.ui.IngestGridView;
51c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescuimport com.android.gallery3d.ingest.ui.IngestGridView.OnClearChoicesListener;
52d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
53d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport java.lang.ref.WeakReference;
54d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport java.util.Collection;
55d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
56d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescupublic class IngestActivity extends Activity implements
57d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        MtpDeviceIndex.ProgressListener, ImportTask.Listener {
58d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
59d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    private IngestService mHelperService;
60d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    private boolean mActive = false;
61c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    private IngestGridView mGridView;
62d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    private MtpAdapter mAdapter;
63d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    private Handler mHandler;
64d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    private ProgressDialog mProgressDialog;
65d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    private ActionMode mActiveActionMode;
66d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
67c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    private View mWarningView;
68c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    private TextView mWarningText;
69c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    private int mLastCheckedPosition = 0;
70c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
71c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    private ViewPager mFullscreenPager;
72c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    private MtpPagerAdapter mPagerAdapter;
73c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    private boolean mFullscreenPagerVisible = false;
74c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
75c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    private MenuItem mMenuSwitcherItem;
76c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    private MenuItem mActionMenuSwitcherItem;
776516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescu
780c63c43455348ce01aff5f50f8b50b4612c0f8bfBobby Georgescu    // The MTP framework components don't give us fine-grained file copy
790c63c43455348ce01aff5f50f8b50b4612c0f8bfBobby Georgescu    // progress updates, so for large photos and videos, we will be stuck
800c63c43455348ce01aff5f50f8b50b4612c0f8bfBobby Georgescu    // with a dialog not updating for a long time. To give the user feedback,
810c63c43455348ce01aff5f50f8b50b4612c0f8bfBobby Georgescu    // we switch to the animated indeterminate progress bar after the timeout
820c63c43455348ce01aff5f50f8b50b4612c0f8bfBobby Georgescu    // specified by INDETERMINATE_SWITCH_TIMEOUT_MS. On the next update from
830c63c43455348ce01aff5f50f8b50b4612c0f8bfBobby Georgescu    // the framework, we switch back to the normal progress bar.
840c63c43455348ce01aff5f50f8b50b4612c0f8bfBobby Georgescu    private static final int INDETERMINATE_SWITCH_TIMEOUT_MS = 3000;
850c63c43455348ce01aff5f50f8b50b4612c0f8bfBobby Georgescu
86d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    @Override
87d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    protected void onCreate(Bundle savedInstanceState) {
88d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        super.onCreate(savedInstanceState);
89d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        doBindHelperService();
90d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
91d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        setContentView(R.layout.ingest_activity_item_list);
92c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        mGridView = (IngestGridView) findViewById(R.id.ingest_gridview);
93d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        mAdapter = new MtpAdapter(this);
94c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        mAdapter.registerDataSetObserver(mMasterObserver);
95d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        mGridView.setAdapter(mAdapter);
96d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        mGridView.setMultiChoiceModeListener(mMultiChoiceModeListener);
97d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        mGridView.setOnItemClickListener(mOnItemClickListener);
98c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        mGridView.setOnClearChoicesListener(mPositionMappingCheckBroker);
99c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
100c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        mFullscreenPager = (ViewPager) findViewById(R.id.ingest_view_pager);
101d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
102d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        mHandler = new ItemListHandler(this);
103c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
104c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        MtpBitmapFetch.configureForContext(this);
105d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
106d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
107d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    private OnItemClickListener mOnItemClickListener = new OnItemClickListener() {
108d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        @Override
109d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        public void onItemClick(AdapterView<?> adapterView, View itemView, int position, long arg3) {
110c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            mLastCheckedPosition = position;
111d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            mGridView.setItemChecked(position, !mGridView.getCheckedItemPositions().get(position));
112d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        }
113d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    };
114d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
115d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    private MultiChoiceModeListener mMultiChoiceModeListener = new MultiChoiceModeListener() {
116d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        private boolean mIgnoreItemCheckedStateChanges = false;
117d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
118d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        private void updateSelectedTitle(ActionMode mode) {
119d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            int count = mGridView.getCheckedItemCount();
120d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            mode.setTitle(getResources().getQuantityString(
121d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                    R.plurals.number_of_items_selected, count, count));
122d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        }
123d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
124d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        @Override
125d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
126d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                boolean checked) {
127d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            if (mIgnoreItemCheckedStateChanges) return;
128d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            if (mAdapter.itemAtPositionIsBucket(position)) {
129d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                SparseBooleanArray checkedItems = mGridView.getCheckedItemPositions();
130d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                mIgnoreItemCheckedStateChanges = true;
131d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                mGridView.setItemChecked(position, false);
132d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
133d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                // Takes advantage of the fact that SectionIndexer imposes the
134d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                // need to clamp to the valid range
135d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                int nextSectionStart = mAdapter.getPositionForSection(
136d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                        mAdapter.getSectionForPosition(position) + 1);
137d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                if (nextSectionStart == position)
138d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                    nextSectionStart = mAdapter.getCount();
139d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
140d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                boolean rangeValue = false; // Value we want to set all of the bucket items to
141d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
142d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                // Determine if all the items in the bucket are currently checked, so that we
143d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                // can uncheck them, otherwise we will check all items in the bucket.
144d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                for (int i = position + 1; i < nextSectionStart; i++) {
145d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                    if (checkedItems.get(i) == false) {
146d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                        rangeValue = true;
147d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                        break;
148d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                    }
149d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                }
150d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
151d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                // Set all items in the bucket to the desired state
152d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                for (int i = position + 1; i < nextSectionStart; i++) {
153d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                    if (checkedItems.get(i) != rangeValue)
154d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                        mGridView.setItemChecked(i, rangeValue);
155d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                }
156d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
157c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu                mPositionMappingCheckBroker.onBulkCheckedChange();
158d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                mIgnoreItemCheckedStateChanges = false;
159c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            } else {
160c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu                mPositionMappingCheckBroker.onCheckedChange(position, checked);
161d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            }
162c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            mLastCheckedPosition = position;
163d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            updateSelectedTitle(mode);
164d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        }
165d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
166d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        @Override
167d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
168c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            return onOptionsItemSelected(item);
169d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        }
170d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
171d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        @Override
172d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
173d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            MenuInflater inflater = mode.getMenuInflater();
174d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            inflater.inflate(R.menu.ingest_menu_item_list_selection, menu);
175d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            updateSelectedTitle(mode);
176d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            mActiveActionMode = mode;
177c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            mActionMenuSwitcherItem = menu.findItem(R.id.ingest_switch_view);
178c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            setSwitcherMenuState(mActionMenuSwitcherItem, mFullscreenPagerVisible);
179d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            return true;
180d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        }
181d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
182d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        @Override
183d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        public void onDestroyActionMode(ActionMode mode) {
184d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            mActiveActionMode = null;
185c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            mActionMenuSwitcherItem = null;
186c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            mHandler.sendEmptyMessage(ItemListHandler.MSG_BULK_CHECKED_CHANGE);
187d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        }
188d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
189d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        @Override
190d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
191d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            updateSelectedTitle(mode);
192d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            return false;
193d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        }
194d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    };
195d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
196c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    public boolean onOptionsItemSelected(MenuItem item) {
197c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        switch (item.getItemId()) {
198c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            case R.id.import_items:
199c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu                if (mActiveActionMode != null) {
200c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu                    mHelperService.importSelectedItems(
201c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu                            mGridView.getCheckedItemPositions(),
202c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu                            mAdapter);
203c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu                    mActiveActionMode.finish();
204c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu                }
205c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu                return true;
206c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            case R.id.ingest_switch_view:
207c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu                setFullscreenPagerVisibility(!mFullscreenPagerVisible);
208c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu                return true;
209c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            default:
210c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu                return false;
211c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        }
212c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    }
213c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
214c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    @Override
215c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    public boolean onCreateOptionsMenu(Menu menu) {
216c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        MenuInflater inflater = getMenuInflater();
217c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        inflater.inflate(R.menu.ingest_menu_item_list_selection, menu);
218c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        mMenuSwitcherItem = menu.findItem(R.id.ingest_switch_view);
219c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        menu.findItem(R.id.import_items).setVisible(false);
220c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        setSwitcherMenuState(mMenuSwitcherItem, mFullscreenPagerVisible);
221c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        return true;
222c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    }
223c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
224d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    @Override
225d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    protected void onDestroy() {
226d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        super.onDestroy();
227d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        doUnbindHelperService();
228d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
229d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
230d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    @Override
231d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    protected void onResume() {
232f63e1f7ab9a4f4a97909564cfc5975cbac66872fBobby Georgescu        DateTileView.refreshLocale();
233d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        mActive = true;
234d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        if (mHelperService != null) mHelperService.setClientActivity(this);
235c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        updateWarningView();
236d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        super.onResume();
237d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
238d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
239d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    @Override
240d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    protected void onPause() {
241d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        if (mHelperService != null) mHelperService.setClientActivity(null);
242d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        mActive = false;
243d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        cleanupProgressDialog();
244d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        super.onPause();
245d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
246d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
247c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    @Override
248c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    public void onConfigurationChanged(Configuration newConfig) {
249c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        super.onConfigurationChanged(newConfig);
250c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        MtpBitmapFetch.configureForContext(this);
251c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    }
252c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
253c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    private void showWarningView(int textResId) {
254c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        if (mWarningView == null) {
255c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            mWarningView = findViewById(R.id.ingest_warning_view);
256c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            mWarningText =
257c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu                    (TextView)mWarningView.findViewById(R.id.ingest_warning_view_text);
2586516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescu        }
259c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        mWarningText.setText(textResId);
260c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        mWarningView.setVisibility(View.VISIBLE);
261c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        setFullscreenPagerVisibility(false);
2626516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescu        mGridView.setVisibility(View.GONE);
2636516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescu    }
2646516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescu
265c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    private void hideWarningView() {
266c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        if (mWarningView != null) {
267c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            mWarningView.setVisibility(View.GONE);
268c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            setFullscreenPagerVisibility(false);
2696516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescu        }
2706516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescu    }
2716516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescu
272c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    private PositionMappingCheckBroker mPositionMappingCheckBroker = new PositionMappingCheckBroker();
273c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
274c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    private class PositionMappingCheckBroker extends CheckBroker
275c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        implements OnClearChoicesListener {
276c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        private int mLastMappingPager = -1;
277c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        private int mLastMappingGrid = -1;
278c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
279c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        private int mapPagerToGridPosition(int position) {
280c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            if (position != mLastMappingPager) {
281c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu               mLastMappingPager = position;
282c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu               mLastMappingGrid = mAdapter.translatePositionWithoutLabels(position);
283c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            }
284c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            return mLastMappingGrid;
285c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        }
286c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
287c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        private int mapGridToPagerPosition(int position) {
288c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            if (position != mLastMappingGrid) {
289c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu                mLastMappingGrid = position;
290c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu                mLastMappingPager = mPagerAdapter.translatePositionWithLabels(position);
291c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            }
292c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            return mLastMappingPager;
293c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        }
294c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
295c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        @Override
296c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        public void setItemChecked(int position, boolean checked) {
297c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            mGridView.setItemChecked(mapPagerToGridPosition(position), checked);
298c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        }
299c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
300c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        @Override
301c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        public void onCheckedChange(int position, boolean checked) {
302c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            if (mPagerAdapter != null) {
303c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu                super.onCheckedChange(mapGridToPagerPosition(position), checked);
304c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            }
305c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        }
306c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
307c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        @Override
308c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        public boolean isItemChecked(int position) {
309c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            return mGridView.getCheckedItemPositions().get(mapPagerToGridPosition(position));
310c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        }
311c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
312c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        @Override
313c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        public void onClearChoices() {
314c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            onBulkCheckedChange();
315c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        }
316c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    };
317c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
318c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    private DataSetObserver mMasterObserver = new DataSetObserver() {
319c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        @Override
320c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        public void onChanged() {
321c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            if (mPagerAdapter != null) mPagerAdapter.notifyDataSetChanged();
322c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        }
323c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
324c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        @Override
325c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        public void onInvalidated() {
326c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            if (mPagerAdapter != null) mPagerAdapter.notifyDataSetChanged();
327c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        }
328c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    };
329c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
330c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    private int pickFullscreenStartingPosition() {
331c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        int firstVisiblePosition = mGridView.getFirstVisiblePosition();
332c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        if (mLastCheckedPosition <= firstVisiblePosition
333c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu                || mLastCheckedPosition > mGridView.getLastVisiblePosition()) {
334c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            return firstVisiblePosition;
335c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        } else {
336c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            return mLastCheckedPosition;
337c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        }
338c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    }
339c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
340c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    private void setSwitcherMenuState(MenuItem menuItem, boolean inFullscreenMode) {
341c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        if (menuItem == null) return;
342c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        if (!inFullscreenMode) {
343c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            menuItem.setIcon(android.R.drawable.ic_menu_zoom);
344c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            menuItem.setTitle(R.string.switch_photo_fullscreen);
345c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        } else {
346c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            menuItem.setIcon(android.R.drawable.ic_dialog_dialer);
347c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            menuItem.setTitle(R.string.switch_photo_grid);
348c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        }
349c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    }
350c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
351c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    private void setFullscreenPagerVisibility(boolean visible) {
352c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        mFullscreenPagerVisible = visible;
353c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        if (visible) {
354c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            if (mPagerAdapter == null) {
355c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu                mPagerAdapter = new MtpPagerAdapter(this, mPositionMappingCheckBroker);
356c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu                mPagerAdapter.setMtpDeviceIndex(mAdapter.getMtpDeviceIndex());
357c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            }
358c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            mFullscreenPager.setAdapter(mPagerAdapter);
359c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            mFullscreenPager.setCurrentItem(mPagerAdapter.translatePositionWithLabels(
360c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu                    pickFullscreenStartingPosition()), false);
361c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        } else if (mPagerAdapter != null) {
362c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            mGridView.setSelection(mAdapter.translatePositionWithoutLabels(
363c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu                    mFullscreenPager.getCurrentItem()));
364c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            mFullscreenPager.setAdapter(null);
365c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        }
366c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        mGridView.setVisibility(visible ? View.INVISIBLE : View.VISIBLE);
367c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        mFullscreenPager.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
368c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        if (mActionMenuSwitcherItem != null) {
369c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            setSwitcherMenuState(mActionMenuSwitcherItem, visible);
370c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        }
371c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        setSwitcherMenuState(mMenuSwitcherItem, visible);
372c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    }
373c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
374c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    private void updateWarningView() {
3756516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescu        if (!mAdapter.deviceConnected()) {
376c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            showWarningView(R.string.ingest_no_device);
3776516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescu        } else if (mAdapter.indexReady() && mAdapter.getCount() == 0) {
378c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            showWarningView(R.string.ingest_empty_device);
3796516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescu        } else {
380c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            hideWarningView();
3816516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescu        }
3826516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescu    }
3836516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescu
3846516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescu    private void UiThreadNotifyIndexChanged() {
385d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        mAdapter.notifyDataSetChanged();
386d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        if (mActiveActionMode != null) {
387d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            mActiveActionMode.finish();
388d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            mActiveActionMode = null;
389d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        }
390c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        updateWarningView();
3916516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescu    }
3926516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescu
3936516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescu    protected void notifyIndexChanged() {
3946516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescu        mHandler.sendEmptyMessage(ItemListHandler.MSG_NOTIFY_CHANGED);
395d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
396d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
397d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    private static class ProgressState {
398d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        String message;
399d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        String title;
400d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        int current;
401d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        int max;
402d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
403d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        public void reset() {
404d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            title = null;
405d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            message = null;
406d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            current = 0;
407d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            max = 0;
408d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        }
409d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
410d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
411d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    private ProgressState mProgressState = new ProgressState();
412d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
413d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    @Override
414d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    public void onObjectIndexed(MtpObjectInfo object, int numVisited) {
415d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        // Not guaranteed to be called on the UI thread
416d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        mProgressState.reset();
417d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        mProgressState.max = 0;
418d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        mProgressState.message = getResources().getQuantityString(
419d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                R.plurals.ingest_number_of_items_scanned, numVisited, numVisited);
420d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        mHandler.sendEmptyMessage(ItemListHandler.MSG_PROGRESS_UPDATE);
421d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
422d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
423d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    @Override
424d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    public void onSorting() {
425d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        // Not guaranteed to be called on the UI thread
426d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        mProgressState.reset();
427d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        mProgressState.max = 0;
428d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        mProgressState.message = getResources().getString(R.string.ingest_sorting);
429d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        mHandler.sendEmptyMessage(ItemListHandler.MSG_PROGRESS_UPDATE);
430d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
431d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
432d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    @Override
433d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    public void onIndexFinish() {
434d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        // Not guaranteed to be called on the UI thread
435d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        mHandler.sendEmptyMessage(ItemListHandler.MSG_PROGRESS_HIDE);
4366516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescu        mHandler.sendEmptyMessage(ItemListHandler.MSG_NOTIFY_CHANGED);
437d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
438d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
439d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    @Override
440d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    public void onImportProgress(final int visitedCount, final int totalCount,
441d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            String pathIfSuccessful) {
442d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        // Not guaranteed to be called on the UI thread
443d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        mProgressState.reset();
444d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        mProgressState.max = totalCount;
445d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        mProgressState.current = visitedCount;
446d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        mProgressState.title = getResources().getString(R.string.ingest_importing);
447d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        mHandler.sendEmptyMessage(ItemListHandler.MSG_PROGRESS_UPDATE);
4480c63c43455348ce01aff5f50f8b50b4612c0f8bfBobby Georgescu        mHandler.removeMessages(ItemListHandler.MSG_PROGRESS_INDETERMINATE);
4490c63c43455348ce01aff5f50f8b50b4612c0f8bfBobby Georgescu        mHandler.sendEmptyMessageDelayed(ItemListHandler.MSG_PROGRESS_INDETERMINATE,
4500c63c43455348ce01aff5f50f8b50b4612c0f8bfBobby Georgescu                INDETERMINATE_SWITCH_TIMEOUT_MS);
451d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
452d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
453d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    @Override
454384971f7ce93c98249825d0498ad4bcbd4104895Bobby Georgescu    public void onImportFinish(Collection<MtpObjectInfo> objectsNotImported,
455384971f7ce93c98249825d0498ad4bcbd4104895Bobby Georgescu            int numVisited) {
456d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        // Not guaranteed to be called on the UI thread
457d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        mHandler.sendEmptyMessage(ItemListHandler.MSG_PROGRESS_HIDE);
4580c63c43455348ce01aff5f50f8b50b4612c0f8bfBobby Georgescu        mHandler.removeMessages(ItemListHandler.MSG_PROGRESS_INDETERMINATE);
459d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        // TODO: maybe show an extra dialog listing the ones that failed
460d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        // importing, if any?
461d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
462d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
463d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    private ProgressDialog getProgressDialog() {
464d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        if (mProgressDialog == null || !mProgressDialog.isShowing()) {
465d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            mProgressDialog = new ProgressDialog(this);
466d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            mProgressDialog.setCancelable(false);
467d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        }
468d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        return mProgressDialog;
469d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
470d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
471d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    private void updateProgressDialog() {
472d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        ProgressDialog dialog = getProgressDialog();
473d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        boolean indeterminate = (mProgressState.max == 0);
474d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        dialog.setIndeterminate(indeterminate);
475d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        dialog.setProgressStyle(indeterminate ? ProgressDialog.STYLE_SPINNER
476d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                : ProgressDialog.STYLE_HORIZONTAL);
477d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        if (mProgressState.title != null) {
478d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            dialog.setTitle(mProgressState.title);
479d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        }
480d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        if (mProgressState.message != null) {
481d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            dialog.setMessage(mProgressState.message);
482d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        }
483d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        if (!indeterminate) {
484d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            dialog.setProgress(mProgressState.current);
485d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            dialog.setMax(mProgressState.max);
486d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        }
487d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        if (!dialog.isShowing()) {
488d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            dialog.show();
489d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        }
490d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
491d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
4920c63c43455348ce01aff5f50f8b50b4612c0f8bfBobby Georgescu    private void makeProgressDialogIndeterminate() {
4930c63c43455348ce01aff5f50f8b50b4612c0f8bfBobby Georgescu        ProgressDialog dialog = getProgressDialog();
4940c63c43455348ce01aff5f50f8b50b4612c0f8bfBobby Georgescu        dialog.setIndeterminate(true);
4950c63c43455348ce01aff5f50f8b50b4612c0f8bfBobby Georgescu    }
4960c63c43455348ce01aff5f50f8b50b4612c0f8bfBobby Georgescu
497d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    private void cleanupProgressDialog() {
498d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        if (mProgressDialog != null) {
499d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            mProgressDialog.hide();
500d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            mProgressDialog = null;
501d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        }
502d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
503d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
504d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    // This is static and uses a WeakReference in order to avoid leaking the Activity
505d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    private static class ItemListHandler extends Handler {
506d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        public static final int MSG_PROGRESS_UPDATE = 0;
507d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        public static final int MSG_PROGRESS_HIDE = 1;
5086516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescu        public static final int MSG_NOTIFY_CHANGED = 2;
509c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        public static final int MSG_BULK_CHECKED_CHANGE = 3;
5100c63c43455348ce01aff5f50f8b50b4612c0f8bfBobby Georgescu        public static final int MSG_PROGRESS_INDETERMINATE = 4;
511d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
512d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        WeakReference<IngestActivity> mParentReference;
513d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
514d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        public ItemListHandler(IngestActivity parent) {
515d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            super();
516d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            mParentReference = new WeakReference<IngestActivity>(parent);
517d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        }
518d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
519d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        public void handleMessage(Message message) {
520d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            IngestActivity parent = mParentReference.get();
521d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            if (parent == null || !parent.mActive)
522d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                return;
523d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            switch (message.what) {
524d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                case MSG_PROGRESS_HIDE:
525d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                    parent.cleanupProgressDialog();
526d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                    break;
527d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                case MSG_PROGRESS_UPDATE:
528d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                    parent.updateProgressDialog();
529d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                    break;
5306516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescu                case MSG_NOTIFY_CHANGED:
5316516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescu                    parent.UiThreadNotifyIndexChanged();
532d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                    break;
533c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu                case MSG_BULK_CHECKED_CHANGE:
534c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu                    parent.mPositionMappingCheckBroker.onBulkCheckedChange();
535c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu                    break;
5360c63c43455348ce01aff5f50f8b50b4612c0f8bfBobby Georgescu                case MSG_PROGRESS_INDETERMINATE:
5370c63c43455348ce01aff5f50f8b50b4612c0f8bfBobby Georgescu                    parent.makeProgressDialogIndeterminate();
5380c63c43455348ce01aff5f50f8b50b4612c0f8bfBobby Georgescu                    break;
539d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                default:
540d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                    break;
541d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            }
542d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        }
543d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
544d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
545d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    private ServiceConnection mHelperServiceConnection = new ServiceConnection() {
546d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        public void onServiceConnected(ComponentName className, IBinder service) {
547d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            mHelperService = ((IngestService.LocalBinder) service).getService();
548d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            mHelperService.setClientActivity(IngestActivity.this);
549c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            MtpDeviceIndex index = mHelperService.getIndex();
550c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            mAdapter.setMtpDeviceIndex(index);
551c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu            if (mPagerAdapter != null) mPagerAdapter.setMtpDeviceIndex(index);
552d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        }
553d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
554d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        public void onServiceDisconnected(ComponentName className) {
555d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            mHelperService = null;
556d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        }
557d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    };
558d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
559d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    private void doBindHelperService() {
560d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        bindService(new Intent(getApplicationContext(), IngestService.class),
561d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu                mHelperServiceConnection, Context.BIND_AUTO_CREATE);
562d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
563d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
564d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    private void doUnbindHelperService() {
565d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        if (mHelperService != null) {
566d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            mHelperService.setClientActivity(null);
567d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu            unbindService(mHelperServiceConnection);
568d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu        }
569d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
570d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu}
571