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
19f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport com.android.gallery3d.R;
20f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport com.android.gallery3d.ingest.adapter.CheckBroker;
21f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport com.android.gallery3d.ingest.adapter.MtpAdapter;
22f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport com.android.gallery3d.ingest.adapter.MtpPagerAdapter;
23f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport com.android.gallery3d.ingest.data.ImportTask;
24f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport com.android.gallery3d.ingest.data.IngestObjectInfo;
25f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport com.android.gallery3d.ingest.data.MtpBitmapFetch;
26f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport com.android.gallery3d.ingest.data.MtpDeviceIndex;
27f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport com.android.gallery3d.ingest.ui.DateTileView;
28f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport com.android.gallery3d.ingest.ui.IngestGridView;
29f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport com.android.gallery3d.ingest.ui.IngestGridView.OnClearChoicesListener;
30f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
31f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport android.annotation.TargetApi;
32d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.app.Activity;
33d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.app.ProgressDialog;
34d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.content.ComponentName;
35d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.content.Context;
36d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.content.Intent;
37d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.content.ServiceConnection;
38c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescuimport android.content.res.Configuration;
39c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescuimport android.database.DataSetObserver;
40f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport android.os.Build;
41d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.os.Bundle;
42d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.os.Handler;
43d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.os.IBinder;
44d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.os.Message;
45c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescuimport android.support.v4.view.ViewPager;
46d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.util.SparseBooleanArray;
47d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.view.ActionMode;
48d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.view.Menu;
49d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.view.MenuInflater;
50d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.view.MenuItem;
51d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.view.View;
52d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.widget.AbsListView.MultiChoiceModeListener;
53d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.widget.AdapterView;
54d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport android.widget.AdapterView.OnItemClickListener;
556516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescuimport android.widget.TextView;
56d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
57d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport java.lang.ref.WeakReference;
58d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescuimport java.util.Collection;
59d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
60f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu/**
61f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * MTP importer, main activity.
62f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu */
63f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
64d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescupublic class IngestActivity extends Activity implements
65f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    MtpDeviceIndex.ProgressListener, ImportTask.Listener {
66f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
67f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private IngestService mHelperService;
68f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private boolean mActive = false;
69f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private IngestGridView mGridView;
70f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private MtpAdapter mAdapter;
71f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private Handler mHandler;
72f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private ProgressDialog mProgressDialog;
73f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private ActionMode mActiveActionMode;
74f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
75f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private View mWarningView;
76f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private TextView mWarningText;
77f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private int mLastCheckedPosition = 0;
78f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
79f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private ViewPager mFullscreenPager;
80f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private MtpPagerAdapter mPagerAdapter;
81f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private boolean mFullscreenPagerVisible = false;
82f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
83f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private MenuItem mMenuSwitcherItem;
84f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private MenuItem mActionMenuSwitcherItem;
85f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
86f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  // The MTP framework components don't give us fine-grained file copy
87f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  // progress updates, so for large photos and videos, we will be stuck
88f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  // with a dialog not updating for a long time. To give the user feedback,
89f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  // we switch to the animated indeterminate progress bar after the timeout
90f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  // specified by INDETERMINATE_SWITCH_TIMEOUT_MS. On the next update from
91f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  // the framework, we switch back to the normal progress bar.
92f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private static final int INDETERMINATE_SWITCH_TIMEOUT_MS = 3000;
93f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
94f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  @Override
95f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  protected void onCreate(Bundle savedInstanceState) {
96f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    super.onCreate(savedInstanceState);
97f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    doBindHelperService();
98f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
99f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    setContentView(R.layout.ingest_activity_item_list);
100f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mGridView = (IngestGridView) findViewById(R.id.ingest_gridview);
101f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mAdapter = new MtpAdapter(this);
102f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mAdapter.registerDataSetObserver(mMasterObserver);
103f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mGridView.setAdapter(mAdapter);
104f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mGridView.setMultiChoiceModeListener(mMultiChoiceModeListener);
105f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mGridView.setOnItemClickListener(mOnItemClickListener);
106f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mGridView.setOnClearChoicesListener(mPositionMappingCheckBroker);
107f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
108f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mFullscreenPager = (ViewPager) findViewById(R.id.ingest_view_pager);
109f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
110f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mHandler = new ItemListHandler(this);
111f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
112f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    MtpBitmapFetch.configureForContext(this);
113f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
114f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
115f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private OnItemClickListener mOnItemClickListener = new OnItemClickListener() {
116d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    @Override
117f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    public void onItemClick(AdapterView<?> adapterView, View itemView, int position,
118f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        long arg3) {
119f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mLastCheckedPosition = position;
120f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mGridView.setItemChecked(position, !mGridView.getCheckedItemPositions().get(position));
121d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
122f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  };
123d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
124f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private MultiChoiceModeListener mMultiChoiceModeListener = new MultiChoiceModeListener() {
125f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    private boolean mIgnoreItemCheckedStateChanges = false;
126d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
127f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    private void updateSelectedTitle(ActionMode mode) {
128f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      int count = mGridView.getCheckedItemCount();
129f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mode.setTitle(getResources().getQuantityString(
130f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          R.plurals.ingest_number_of_items_selected, count, count));
131c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    }
132c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
133c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    @Override
134f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
135f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        boolean checked) {
136f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      if (mIgnoreItemCheckedStateChanges) {
137f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        return;
138f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      }
139f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      if (mAdapter.itemAtPositionIsBucket(position)) {
140f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        SparseBooleanArray checkedItems = mGridView.getCheckedItemPositions();
141f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        mIgnoreItemCheckedStateChanges = true;
142f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        mGridView.setItemChecked(position, false);
143f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
144f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        // Takes advantage of the fact that SectionIndexer imposes the
145f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        // need to clamp to the valid range
146f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        int nextSectionStart = mAdapter.getPositionForSection(
147f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu            mAdapter.getSectionForPosition(position) + 1);
148f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        if (nextSectionStart == position) {
149f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          nextSectionStart = mAdapter.getCount();
150f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        }
151f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
152f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        boolean rangeValue = false; // Value we want to set all of the bucket items to
153f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
154f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        // Determine if all the items in the bucket are currently checked, so that we
155f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        // can uncheck them, otherwise we will check all items in the bucket.
156f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        for (int i = position + 1; i < nextSectionStart; i++) {
157f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          if (!checkedItems.get(i)) {
158f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu            rangeValue = true;
159f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu            break;
160f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          }
161f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        }
162f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
163f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        // Set all items in the bucket to the desired state
164f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        for (int i = position + 1; i < nextSectionStart; i++) {
165f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          if (checkedItems.get(i) != rangeValue) {
166f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu            mGridView.setItemChecked(i, rangeValue);
167f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          }
168f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        }
169f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
170f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        mPositionMappingCheckBroker.onBulkCheckedChange();
171f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        mIgnoreItemCheckedStateChanges = false;
172f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      } else {
173f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        mPositionMappingCheckBroker.onCheckedChange(position, checked);
174f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      }
175f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mLastCheckedPosition = position;
176f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      updateSelectedTitle(mode);
177c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    }
178c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
179d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    @Override
180f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
181f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return onOptionsItemSelected(item);
182d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
183d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
184d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    @Override
185f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
186f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      MenuInflater inflater = mode.getMenuInflater();
187f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      inflater.inflate(R.menu.ingest_menu_item_list_selection, menu);
188f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      updateSelectedTitle(mode);
189f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mActiveActionMode = mode;
190f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mActionMenuSwitcherItem = menu.findItem(R.id.ingest_switch_view);
191f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      setSwitcherMenuState(mActionMenuSwitcherItem, mFullscreenPagerVisible);
192f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return true;
193d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
194d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
195d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    @Override
196f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    public void onDestroyActionMode(ActionMode mode) {
197f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mActiveActionMode = null;
198f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mActionMenuSwitcherItem = null;
199f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mHandler.sendEmptyMessage(ItemListHandler.MSG_BULK_CHECKED_CHANGE);
200d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
201d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
202c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    @Override
203f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
204f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      updateSelectedTitle(mode);
205f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return false;
2066516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescu    }
207f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  };
208f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
209f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  @Override
210f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public boolean onOptionsItemSelected(MenuItem item) {
211f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    int id = item.getItemId();
212f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (id == R.id.ingest_import_items) {
213f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      if (mActiveActionMode != null) {
214f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        mHelperService.importSelectedItems(
215f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu            mGridView.getCheckedItemPositions(),
216f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu            mAdapter);
217f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        mActiveActionMode.finish();
218f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      }
219f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return true;
220f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    } else if (id == R.id.ingest_switch_view) {
221f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      setFullscreenPagerVisibility(!mFullscreenPagerVisible);
222f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return true;
223f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    } else {
224f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return false;
2256516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescu    }
226f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
227f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
228f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  @Override
229f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public boolean onCreateOptionsMenu(Menu menu) {
230f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    MenuInflater inflater = getMenuInflater();
231f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    inflater.inflate(R.menu.ingest_menu_item_list_selection, menu);
232f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mMenuSwitcherItem = menu.findItem(R.id.ingest_switch_view);
233f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    menu.findItem(R.id.ingest_import_items).setVisible(false);
234f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    setSwitcherMenuState(mMenuSwitcherItem, mFullscreenPagerVisible);
235f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    return true;
236f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
237f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
238f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  @Override
239f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  protected void onDestroy() {
240f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    doUnbindHelperService();
241f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    super.onDestroy();
242f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
243f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
244f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  @Override
245f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  protected void onResume() {
246f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    DateTileView.refreshLocale();
247f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mActive = true;
248f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (mHelperService != null) {
249f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mHelperService.setClientActivity(this);
250c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    }
251f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    updateWarningView();
252f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    super.onResume();
253f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
254f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
255f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  @Override
256f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  protected void onPause() {
257f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (mHelperService != null) {
258f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mHelperService.setClientActivity(null);
259c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    }
260f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mActive = false;
261f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    cleanupProgressDialog();
262f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    super.onPause();
263f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
264f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
265f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  @Override
266f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public void onConfigurationChanged(Configuration newConfig) {
267f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    super.onConfigurationChanged(newConfig);
268f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    MtpBitmapFetch.configureForContext(this);
269f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
270f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
271f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private void showWarningView(int textResId) {
272f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (mWarningView == null) {
273f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mWarningView = findViewById(R.id.ingest_warning_view);
274f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mWarningText =
275f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          (TextView) mWarningView.findViewById(R.id.ingest_warning_view_text);
276c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    }
277f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mWarningText.setText(textResId);
278f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mWarningView.setVisibility(View.VISIBLE);
279f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    setFullscreenPagerVisibility(false);
280f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mGridView.setVisibility(View.GONE);
281f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    setSwitcherMenuVisibility(false);
282f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
283f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
284f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private void hideWarningView() {
285f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (mWarningView != null) {
286f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mWarningView.setVisibility(View.GONE);
287f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      setFullscreenPagerVisibility(false);
2886516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescu    }
289f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    setSwitcherMenuVisibility(true);
290f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
291f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
292f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private PositionMappingCheckBroker mPositionMappingCheckBroker =
293f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      new PositionMappingCheckBroker();
294f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
295f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private class PositionMappingCheckBroker extends CheckBroker
296f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      implements OnClearChoicesListener {
297f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    private int mLastMappingPager = -1;
298f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    private int mLastMappingGrid = -1;
299f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
300f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    private int mapPagerToGridPosition(int position) {
301f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      if (position != mLastMappingPager) {
302f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        mLastMappingPager = position;
303f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        mLastMappingGrid = mAdapter.translatePositionWithoutLabels(position);
304f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      }
305f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return mLastMappingGrid;
3066516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescu    }
3076516d271e11f9ae9928be3bb70c99531a842c577Bobby Georgescu
308f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    private int mapGridToPagerPosition(int position) {
309f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      if (position != mLastMappingGrid) {
310f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        mLastMappingGrid = position;
311f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        mLastMappingPager = mPagerAdapter.translatePositionWithLabels(position);
312f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      }
313f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return mLastMappingPager;
314d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
315d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
316f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    @Override
317f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    public void setItemChecked(int position, boolean checked) {
318f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mGridView.setItemChecked(mapPagerToGridPosition(position), checked);
319d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
320d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
321d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    @Override
322f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    public void onCheckedChange(int position, boolean checked) {
323f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      if (mPagerAdapter != null) {
324f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        super.onCheckedChange(mapGridToPagerPosition(position), checked);
325f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      }
326d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
327d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
328d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    @Override
329f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    public boolean isItemChecked(int position) {
330f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return mGridView.getCheckedItemPositions().get(mapPagerToGridPosition(position));
331d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
332d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
333d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    @Override
334f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    public void onClearChoices() {
335f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      onBulkCheckedChange();
336d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
337f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
338d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
339f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private DataSetObserver mMasterObserver = new DataSetObserver() {
340d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    @Override
341f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    public void onChanged() {
342f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      if (mPagerAdapter != null) {
343f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        mPagerAdapter.notifyDataSetChanged();
344f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      }
345d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
346d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
347d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    @Override
348f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    public void onInvalidated() {
349f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      if (mPagerAdapter != null) {
350f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        mPagerAdapter.notifyDataSetChanged();
351f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      }
352f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
353f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  };
354f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
355f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private int pickFullscreenStartingPosition() {
356f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    int firstVisiblePosition = mGridView.getFirstVisiblePosition();
357f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (mLastCheckedPosition <= firstVisiblePosition
358f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        || mLastCheckedPosition > mGridView.getLastVisiblePosition()) {
359f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return firstVisiblePosition;
360f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    } else {
361f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return mLastCheckedPosition;
362d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
363f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
364d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
365f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private void setSwitcherMenuState(MenuItem menuItem, boolean inFullscreenMode) {
366f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (menuItem == null) {
367f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return;
368f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
369f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (!inFullscreenMode) {
370f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      menuItem.setIcon(android.R.drawable.ic_menu_zoom);
371f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      menuItem.setTitle(R.string.ingest_switch_photo_fullscreen);
372f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    } else {
373f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      menuItem.setIcon(android.R.drawable.ic_dialog_dialer);
374f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      menuItem.setTitle(R.string.ingest_switch_photo_grid);
375f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
376f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
377f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
378f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private void setFullscreenPagerVisibility(boolean visible) {
379f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mFullscreenPagerVisible = visible;
380f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (visible) {
381f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      if (mPagerAdapter == null) {
382f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        mPagerAdapter = new MtpPagerAdapter(this, mPositionMappingCheckBroker);
383f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        mPagerAdapter.setMtpDeviceIndex(mAdapter.getMtpDeviceIndex());
384f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      }
385f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mFullscreenPager.setAdapter(mPagerAdapter);
386f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mFullscreenPager.setCurrentItem(mPagerAdapter.translatePositionWithLabels(
387f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          pickFullscreenStartingPosition()), false);
388f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    } else if (mPagerAdapter != null) {
389f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mGridView.setSelection(mAdapter.translatePositionWithoutLabels(
390f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          mFullscreenPager.getCurrentItem()));
391f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mFullscreenPager.setAdapter(null);
392f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
393f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mGridView.setVisibility(visible ? View.INVISIBLE : View.VISIBLE);
394f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mFullscreenPager.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
395f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (mActionMenuSwitcherItem != null) {
396f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      setSwitcherMenuState(mActionMenuSwitcherItem, visible);
397d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
398f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    setSwitcherMenuState(mMenuSwitcherItem, visible);
399f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
400d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
401f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private void setSwitcherMenuVisibility(boolean visible) {
402f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (mActionMenuSwitcherItem != null) {
403f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mActionMenuSwitcherItem.setVisible(visible);
4040c63c43455348ce01aff5f50f8b50b4612c0f8bfBobby Georgescu    }
405f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (mMenuSwitcherItem != null) {
406f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mMenuSwitcherItem.setVisible(visible);
407f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
408f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
409f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
410f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private void updateWarningView() {
411f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (!mAdapter.deviceConnected()) {
412f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      showWarningView(R.string.ingest_no_device);
413f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    } else if (mAdapter.indexReady() && mAdapter.getCount() == 0) {
414f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      showWarningView(R.string.ingest_empty_device);
415f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    } else {
416f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      hideWarningView();
417f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
418f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
4190c63c43455348ce01aff5f50f8b50b4612c0f8bfBobby Georgescu
420f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private void uiThreadNotifyIndexChanged() {
421f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mAdapter.notifyDataSetChanged();
422f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (mActiveActionMode != null) {
423f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mActiveActionMode.finish();
424f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mActiveActionMode = null;
425f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
426f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    updateWarningView();
427f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
428f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
429f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  protected void notifyIndexChanged() {
430f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mHandler.sendEmptyMessage(ItemListHandler.MSG_NOTIFY_CHANGED);
431f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
432f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
433f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private static class ProgressState {
434f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    String message;
435f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    String title;
436f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    int current;
437f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    int max;
438f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
439f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    public void reset() {
440f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      title = null;
441f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      message = null;
442f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      current = 0;
443f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      max = 0;
444f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
445f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
446f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
447f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private ProgressState mProgressState = new ProgressState();
448f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
449f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  @Override
450f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public void onObjectIndexed(IngestObjectInfo object, int numVisited) {
451f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    // Not guaranteed to be called on the UI thread
452f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mProgressState.reset();
453f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mProgressState.max = 0;
454f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mProgressState.message = getResources().getQuantityString(
455f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        R.plurals.ingest_number_of_items_scanned, numVisited, numVisited);
456f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mHandler.sendEmptyMessage(ItemListHandler.MSG_PROGRESS_UPDATE);
457f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
458f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
459f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  @Override
460f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public void onSortingStarted() {
461f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    // Not guaranteed to be called on the UI thread
462f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mProgressState.reset();
463f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mProgressState.max = 0;
464f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mProgressState.message = getResources().getString(R.string.ingest_sorting);
465f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mHandler.sendEmptyMessage(ItemListHandler.MSG_PROGRESS_UPDATE);
466f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
467f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
468f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  @Override
469f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public void onIndexingFinished() {
470f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    // Not guaranteed to be called on the UI thread
471f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mHandler.sendEmptyMessage(ItemListHandler.MSG_PROGRESS_HIDE);
472f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mHandler.sendEmptyMessage(ItemListHandler.MSG_NOTIFY_CHANGED);
473f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
474f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
475f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  @Override
476f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public void onImportProgress(final int visitedCount, final int totalCount,
477f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      String pathIfSuccessful) {
478f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    // Not guaranteed to be called on the UI thread
479f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mProgressState.reset();
480f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mProgressState.max = totalCount;
481f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mProgressState.current = visitedCount;
482f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mProgressState.title = getResources().getString(R.string.ingest_importing);
483f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mHandler.sendEmptyMessage(ItemListHandler.MSG_PROGRESS_UPDATE);
484f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mHandler.removeMessages(ItemListHandler.MSG_PROGRESS_INDETERMINATE);
485f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mHandler.sendEmptyMessageDelayed(ItemListHandler.MSG_PROGRESS_INDETERMINATE,
486f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        INDETERMINATE_SWITCH_TIMEOUT_MS);
487f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
488f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
489f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  @Override
490f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public void onImportFinish(Collection<IngestObjectInfo> objectsNotImported,
491f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      int numVisited) {
492f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    // Not guaranteed to be called on the UI thread
493f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mHandler.sendEmptyMessage(ItemListHandler.MSG_PROGRESS_HIDE);
494f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mHandler.removeMessages(ItemListHandler.MSG_PROGRESS_INDETERMINATE);
495f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    // TODO(georgescu): maybe show an extra dialog listing the ones that failed
496f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    // importing, if any?
497f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
498f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
499f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private ProgressDialog getProgressDialog() {
500f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (mProgressDialog == null || !mProgressDialog.isShowing()) {
501f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mProgressDialog = new ProgressDialog(this);
502f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mProgressDialog.setCancelable(false);
503f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
504f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    return mProgressDialog;
505f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
506f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
507f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private void updateProgressDialog() {
508f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    ProgressDialog dialog = getProgressDialog();
509f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    boolean indeterminate = (mProgressState.max == 0);
510f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    dialog.setIndeterminate(indeterminate);
511f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    dialog.setProgressStyle(indeterminate ? ProgressDialog.STYLE_SPINNER
512f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        : ProgressDialog.STYLE_HORIZONTAL);
513f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (mProgressState.title != null) {
514f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      dialog.setTitle(mProgressState.title);
515f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
516f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (mProgressState.message != null) {
517f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      dialog.setMessage(mProgressState.message);
518f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
519f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (!indeterminate) {
520f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      dialog.setProgress(mProgressState.current);
521f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      dialog.setMax(mProgressState.max);
522f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
523f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (!dialog.isShowing()) {
524f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      dialog.show();
525d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
526f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
527d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
528f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private void makeProgressDialogIndeterminate() {
529f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    ProgressDialog dialog = getProgressDialog();
530f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    dialog.setIndeterminate(true);
531f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
532d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
533f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private void cleanupProgressDialog() {
534f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (mProgressDialog != null) {
535f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mProgressDialog.dismiss();
536f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mProgressDialog = null;
537f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
538f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
539d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
540f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  // This is static and uses a WeakReference in order to avoid leaking the Activity
541f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private static class ItemListHandler extends Handler {
542f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    public static final int MSG_PROGRESS_UPDATE = 0;
543f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    public static final int MSG_PROGRESS_HIDE = 1;
544f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    public static final int MSG_NOTIFY_CHANGED = 2;
545f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    public static final int MSG_BULK_CHECKED_CHANGE = 3;
546f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    public static final int MSG_PROGRESS_INDETERMINATE = 4;
547d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
548f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    WeakReference<IngestActivity> mParentReference;
549f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
550f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    public ItemListHandler(IngestActivity parent) {
551f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      super();
552f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mParentReference = new WeakReference<IngestActivity>(parent);
553d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
554d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
555f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    @Override
556f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    public void handleMessage(Message message) {
557f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      IngestActivity parent = mParentReference.get();
558f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      if (parent == null || !parent.mActive) {
559f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        return;
560f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      }
561f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      switch (message.what) {
562f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        case MSG_PROGRESS_HIDE:
563f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          parent.cleanupProgressDialog();
564f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          break;
565f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        case MSG_PROGRESS_UPDATE:
566f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          parent.updateProgressDialog();
567f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          break;
568f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        case MSG_NOTIFY_CHANGED:
569f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          parent.uiThreadNotifyIndexChanged();
570f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          break;
571f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        case MSG_BULK_CHECKED_CHANGE:
572f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          parent.mPositionMappingCheckBroker.onBulkCheckedChange();
573f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          break;
574f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        case MSG_PROGRESS_INDETERMINATE:
575f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          parent.makeProgressDialogIndeterminate();
576f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          break;
577f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        default:
578f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          break;
579f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      }
580f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
581f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
582d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
583f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private ServiceConnection mHelperServiceConnection = new ServiceConnection() {
584f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    @Override
585f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    public void onServiceConnected(ComponentName className, IBinder service) {
586f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mHelperService = ((IngestService.LocalBinder) service).getService();
587f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mHelperService.setClientActivity(IngestActivity.this);
588f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      MtpDeviceIndex index = mHelperService.getIndex();
589f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mAdapter.setMtpDeviceIndex(index);
590f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      if (mPagerAdapter != null) {
591f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        mPagerAdapter.setMtpDeviceIndex(index);
592f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      }
593f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
594d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
595f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    @Override
596f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    public void onServiceDisconnected(ComponentName className) {
597f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mHelperService = null;
598d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
599f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  };
600d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu
601f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private void doBindHelperService() {
602f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    bindService(new Intent(getApplicationContext(), IngestService.class),
603f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        mHelperServiceConnection, Context.BIND_AUTO_CREATE);
604f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
605f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
606f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private void doUnbindHelperService() {
607f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (mHelperService != null) {
608f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mHelperService.setClientActivity(null);
609f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      unbindService(mHelperServiceConnection);
610d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu    }
611f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
612d3aac52ffb88ced53413d5eef29c641dd6982267Bobby Georgescu}
613