diff options
7 files changed, 158 insertions, 62 deletions
diff --git a/packages/DocumentsUI/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml b/packages/DocumentsUI/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml new file mode 100644 index 000000000000..070b9a10351c --- /dev/null +++ b/packages/DocumentsUI/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- Variant of progress_indeterminate_horizontal_material in frameworks/base/core/res, which + draws the whole height of the progress bar instead having blank space above and below the + bar. --> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/vector_drawable_progress_indeterminate_horizontal_trimmed" > + <target + android:name="rect2_grp" + android:animation="@*android:anim/progress_indeterminate_horizontal_rect2" /> + <target + android:name="rect1_grp" + android:animation="@*android:anim/progress_indeterminate_horizontal_rect1" /> +</animated-vector> diff --git a/packages/DocumentsUI/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml b/packages/DocumentsUI/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml new file mode 100644 index 000000000000..39e3a3738e28 --- /dev/null +++ b/packages/DocumentsUI/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- Variant of vector_drawable_progress_indeterminate_horizontal in frameworks/base/core/res, which + draws the whole height of the progress bar instead having blank space above and below the + bar. --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="10dp" + android:width="360dp" + android:viewportHeight="10" + android:viewportWidth="360" > + <group + android:name="progress_group" + android:translateX="180" + android:translateY="5" > + <path + android:name="background_track" + android:pathData="M -180.0,-5.0 l 360.0,0 l 0,10.0 l -360.0,0 Z" + android:fillColor="?android:attr/colorControlActivated" + android:fillAlpha="?android:attr/disabledAlpha"/> + <group + android:name="rect2_grp" + android:translateX="-197.60001" + android:scaleX="0.1" > + <path + android:name="rect2" + android:pathData="M -144.0,-5.0 l 288.0,0 l 0,10.0 l -288.0,0 Z" + android:fillColor="?android:attr/colorControlActivated" /> + </group> + <group + android:name="rect1_grp" + android:translateX="-522.59998" + android:scaleX="0.1" > + <path + android:name="rect1" + android:pathData="M -144.0,-5.0 l 288.0,0 l 0,10.0 l -288.0,0 Z" + android:fillColor="?android:attr/colorControlActivated" /> + </group> + </group> +</vector> diff --git a/packages/DocumentsUI/res/layout/fragment_directory.xml b/packages/DocumentsUI/res/layout/fragment_directory.xml index f5c73d5269c2..6d8a913f74f1 100644 --- a/packages/DocumentsUI/res/layout/fragment_directory.xml +++ b/packages/DocumentsUI/res/layout/fragment_directory.xml @@ -41,6 +41,14 @@ android:orientation="vertical" android:animateLayoutChanges="true"> + <ProgressBar + android:id="@+id/progressbar" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:indeterminate="true" + style="@style/TrimmedHorizontalProgressBar" + android:visibility="gone"/> + <FrameLayout android:id="@+id/container_message_bar" android:layout_width="match_parent" @@ -48,12 +56,12 @@ android:elevation="8dp" android:background="@color/material_grey_50" android:visibility="gone"/> - + <!-- This FrameLayout works around b/24189541 --> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent"> - + <android.support.v7.widget.RecyclerView android:id="@+id/recyclerView" android:scrollbars="vertical" @@ -67,9 +75,9 @@ android:scrollbarStyle="outsideOverlay" android:drawSelectorOnTop="true" android:background="@color/directory_background" /> - + </FrameLayout> - + </LinearLayout> </com.android.documentsui.DirectoryView> diff --git a/packages/DocumentsUI/res/values/styles.xml b/packages/DocumentsUI/res/values/styles.xml index 8301816edaea..c13f144d0717 100644 --- a/packages/DocumentsUI/res/values/styles.xml +++ b/packages/DocumentsUI/res/values/styles.xml @@ -77,14 +77,20 @@ <item name="android:colorPrimaryDark">@color/platform_blue_700</item> <item name="android:colorPrimary">@color/platform_blue_500</item> <item name="android:colorAccent">@color/platform_blue_700</item> + <item name="colorControlActivated">@color/platform_blue_a100</item> <item name="android:actionModeStyle">@style/FilesActionModeStyle</item> <item name="colorActionMode">@color/platform_blue_700</item> - <item name="android:alertDialogTheme">@style/AlertDialogTheme</item> </style> <style name="FilesActionModeStyle" parent="@android:style/Widget.Material.Light.ActionMode"> <item name="android:background">@color/platform_blue_100</item> </style> - + + <style name="TrimmedHorizontalProgressBar" parent="android:Widget.Material.ProgressBar.Horizontal"> + <item name="android:indeterminateDrawable">@drawable/progress_indeterminate_horizontal_material_trimmed</item> + <item name="android:minHeight">3dp</item> + <item name="android:maxHeight">3dp</item> + </style> + </resources> diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java index c2821e13d7c3..b30cab6ccf9d 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java @@ -135,6 +135,7 @@ public class DirectoryFragment extends Fragment { private static final String EXTRA_IGNORE_STATE = "ignoreState"; private Model mModel; + private Model.UpdateListener mModelUpdateListener = new ModelUpdateListener(); private final Handler mHandler = new Handler(Looper.getMainLooper()); @@ -160,6 +161,7 @@ public class DirectoryFragment extends Fragment { private int mColumnCount = 1; // This will get updated when layout changes. private MessageBar mMessageBar; + private View mProgressBar; public static void showNormal(FragmentManager fm, RootInfo root, DocumentInfo doc, int anim) { show(fm, TYPE_NORMAL, root, doc, null, anim); @@ -223,6 +225,7 @@ public class DirectoryFragment extends Fragment { final View view = inflater.inflate(R.layout.fragment_directory, container, false); mMessageBar = MessageBar.create(getChildFragmentManager()); + mProgressBar = view.findViewById(R.id.progressbar); mEmptyView = view.findViewById(android.R.id.empty); @@ -311,9 +314,8 @@ public class DirectoryFragment extends Fragment { : MultiSelectManager.MODE_SINGLE); selMgr.addCallback(new SelectionModeListener()); - mModel = new Model(context, selMgr); - mModel.setSelectionManager(selMgr); - mModel.addUpdateListener(mAdapter); + mModel = new Model(context, selMgr, mAdapter); + mModel.addUpdateListener(mModelUpdateListener); mType = getArguments().getInt(EXTRA_TYPE); mStateKey = buildStateKey(root, doc); @@ -897,8 +899,7 @@ public class DirectoryFragment extends Fragment { } } - private final class DocumentsAdapter extends RecyclerView.Adapter<DocumentHolder> - implements Model.UpdateListener { + private final class DocumentsAdapter extends RecyclerView.Adapter<DocumentHolder> { private final Context mContext; private final LayoutInflater mInflater; @@ -909,30 +910,6 @@ public class DirectoryFragment extends Fragment { } @Override - public void onModelUpdate(Model model) { - if (model.info != null || model.error != null) { - mMessageBar.setInfo(model.info); - mMessageBar.setError(model.error); - mMessageBar.show(); - } - - if (model.isEmpty()) { - mEmptyView.setVisibility(View.VISIBLE); - } else { - mEmptyView.setVisibility(View.GONE); - } - - notifyDataSetChanged(); - } - - @Override - public void onModelUpdateFailed(Exception e) { - // TODO: deal with catastrophic update failures - String error = getString(R.string.query_error); - notifyDataSetChanged(); - } - - @Override public DocumentHolder onCreateViewHolder(ViewGroup parent, int viewType) { final State state = getDisplayState(DirectoryFragment.this); final LayoutInflater inflater = LayoutInflater.from(getContext()); @@ -1675,6 +1652,7 @@ public class DirectoryFragment extends Fragment { @VisibleForTesting public static final class Model implements DocumentContext { private MultiSelectManager mSelectionManager; + private RecyclerView.Adapter<?> mViewAdapter; private Context mContext; private int mCursorCount; private boolean mIsLoading; @@ -1684,17 +1662,11 @@ public class DirectoryFragment extends Fragment { @Nullable private String info; @Nullable private String error; - Model(Context context, MultiSelectManager selectionManager) { + Model(Context context, MultiSelectManager selectionManager, + RecyclerView.Adapter<?> viewAdapter) { mContext = context; mSelectionManager = selectionManager; - } - - /** - * Sets the selection manager used by the model. - * TODO: the model should instantiate the selection manager. See onActivityCreated. - */ - void setSelectionManager(MultiSelectManager mgr) { - mSelectionManager = mgr; + mViewAdapter = viewAdapter; } /** @@ -1859,7 +1831,7 @@ public class DirectoryFragment extends Fragment { int position = selected.get(i); if (DEBUG) Log.d(TAG, "Marked position " + position + " for deletion"); mMarkedForDeletion.append(position, true); - mUpdateListener.notifyItemRemoved(position); + mViewAdapter.notifyItemRemoved(position); } } @@ -1874,7 +1846,7 @@ public class DirectoryFragment extends Fragment { for (int i = 0; i < size; ++i) { final int position = mMarkedForDeletion.keyAt(i); mMarkedForDeletion.put(position, false); - mUpdateListener.notifyItemInserted(position); + mViewAdapter.notifyItemInserted(position); } // Then, clear the deletion list. @@ -1957,26 +1929,46 @@ public class DirectoryFragment extends Fragment { mUpdateListener = listener; } - interface UpdateListener { + static class UpdateListener { /** * Called when a successful update has occurred. */ - void onModelUpdate(Model model); + void onModelUpdate(Model model) {} /** * Called when an update has been attempted but failed. */ - void onModelUpdateFailed(Exception e); + void onModelUpdateFailed(Exception e) {} + } + } - /** - * Called when an item has been removed from the model. - */ - void notifyItemRemoved(int position); + private class ModelUpdateListener extends Model.UpdateListener { + @Override + public void onModelUpdate(Model model) { + if (model.info != null || model.error != null) { + mMessageBar.setInfo(model.info); + mMessageBar.setError(model.error); + mMessageBar.show(); + } - /** - * Called when an item has been added to the model. - */ - void notifyItemInserted(int position); + mProgressBar.setVisibility(model.isLoading() ? View.VISIBLE : View.GONE); + + if (model.isEmpty()) { + mEmptyView.setVisibility(View.VISIBLE); + mRecView.setVisibility(View.GONE); + } else { + mEmptyView.setVisibility(View.GONE); + mRecView.setVisibility(View.VISIBLE); + } + + mAdapter.notifyDataSetChanged(); + } + + @Override + public void onModelUpdateFailed(Exception e) { + // TODO: deal with catastrophic update failures + String error = getString(R.string.query_error); + mAdapter.notifyDataSetChanged(); } } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/MessageBar.java b/packages/DocumentsUI/src/com/android/documentsui/MessageBar.java index a48fd5c268b4..312d53b9dc1c 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/MessageBar.java +++ b/packages/DocumentsUI/src/com/android/documentsui/MessageBar.java @@ -69,7 +69,7 @@ public class MessageBar extends Fragment { * message bar layout will be adjusted accordingly. */ public void setError(@Nullable String error) { - View errorView = mView.findViewById(R.id.container_message_bar); + View errorView = mView.findViewById(R.id.container_error); if (error != null) { TextView errorText = (TextView) mView.findViewById(R.id.textview_error); errorText.setText(error); diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java index 5505f3546e5d..1895a6e66450 100644 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java @@ -22,9 +22,12 @@ import android.content.ContextWrapper; import android.database.Cursor; import android.database.MatrixCursor; import android.provider.DocumentsContract.Document; +import android.support.v7.widget.RecyclerView.ViewHolder; +import android.support.v7.widget.RecyclerView; import android.test.AndroidTestCase; import android.test.MoreAsserts; import android.test.mock.MockContentResolver; +import android.view.ViewGroup; import com.android.documentsui.DirectoryFragment.Model; import com.android.documentsui.MultiSelectManager.Selection; @@ -57,7 +60,8 @@ public class DirectoryFragmentModelTest extends AndroidTestCase { DirectoryResult r = new DirectoryResult(); r.cursor = cursor; - model = new Model(mContext, null); + // Instantiate the model with a dummy view adapter and listener that (for now) do nothing. + model = new Model(mContext, null, new DummyAdapter()); model.addUpdateListener(new DummyListener()); model.update(r); } @@ -160,11 +164,16 @@ public class DirectoryFragmentModelTest extends AndroidTestCase { return model.getDocuments(sel); } - private static class DummyListener implements Model.UpdateListener { + private static class DummyListener extends Model.UpdateListener { public void onModelUpdate(Model model) {} public void onModelUpdateFailed(Exception e) {} - public void notifyItemRemoved(int position) {} - public void notifyItemInserted(int position) {} } + private static class DummyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { + public int getItemCount() { return 0; } + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {} + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return null; + } + } } |