diff options
| author | 2015-09-16 08:04:37 -0700 | |
|---|---|---|
| committer | 2015-09-18 13:53:41 -0700 | |
| commit | 3b19e31e18ab89acb22eefa8925f90ce6d63f7f7 (patch) | |
| tree | a1eae87375c6d000e5f33c4969d9dda44e034ebc | |
| parent | 7cc80013f38a60bea34c1a73c2df84bac8890382 (diff) | |
Replace error/info footers with a message bar.
- Remove footers from DirectoryFragment.
- Add a new MessageBar fragment that can display error/info messages.
BUG=22638983
Change-Id: I2075ae8e4dca8954a09c1fc57ed62bb6d3bff7a9
10 files changed, 285 insertions, 271 deletions
diff --git a/packages/DocumentsUI/res/layout/directory_cluster.xml b/packages/DocumentsUI/res/layout/directory_cluster.xml index e47e1960563c..8245e53097cd 100644 --- a/packages/DocumentsUI/res/layout/directory_cluster.xml +++ b/packages/DocumentsUI/res/layout/directory_cluster.xml @@ -18,6 +18,13 @@ android:layout_height="match_parent" android:orientation="vertical"> + <FrameLayout + android:id="@+id/container_message_bar" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:elevation="8dp" + android:background="@color/material_grey_50"/> + <com.android.documentsui.DirectoryContainerView android:id="@+id/container_directory" android:layout_width="match_parent" diff --git a/packages/DocumentsUI/res/layout/fragment_directory.xml b/packages/DocumentsUI/res/layout/fragment_directory.xml index 7aff497ccb44..f5c73d5269c2 100644 --- a/packages/DocumentsUI/res/layout/fragment_directory.xml +++ b/packages/DocumentsUI/res/layout/fragment_directory.xml @@ -34,18 +34,42 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> - <android.support.v7.widget.RecyclerView - android:id="@+id/recyclerView" - android:scrollbars="vertical" + <LinearLayout + android:id="@+id/content" android:layout_width="match_parent" android:layout_height="match_parent" - android:paddingStart="@dimen/grid_padding_horiz" - android:paddingEnd="@dimen/grid_padding_horiz" - android:paddingTop="@dimen/grid_padding_vert" - android:paddingBottom="@dimen/grid_padding_vert" - android:clipToPadding="false" - android:scrollbarStyle="outsideOverlay" - android:drawSelectorOnTop="true" - android:background="@color/directory_background" /> + android:orientation="vertical" + android:animateLayoutChanges="true"> + + <FrameLayout + android:id="@+id/container_message_bar" + android:layout_width="match_parent" + android:layout_height="wrap_content" + 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" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingStart="@dimen/grid_padding_horiz" + android:paddingEnd="@dimen/grid_padding_horiz" + android:paddingTop="@dimen/grid_padding_vert" + android:paddingBottom="@dimen/grid_padding_vert" + android:clipToPadding="false" + android:scrollbarStyle="outsideOverlay" + android:drawSelectorOnTop="true" + android:background="@color/directory_background" /> + + </FrameLayout> + + </LinearLayout> </com.android.documentsui.DirectoryView> diff --git a/packages/DocumentsUI/res/layout/fragment_message_bar.xml b/packages/DocumentsUI/res/layout/fragment_message_bar.xml new file mode 100644 index 000000000000..47e4e770b15c --- /dev/null +++ b/packages/DocumentsUI/res/layout/fragment_message_bar.xml @@ -0,0 +1,100 @@ +<?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. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:animateLayoutChanges="true" + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:minHeight="?android:attr/listPreferredItemHeightSmall" + android:orientation="vertical" + android:paddingLeft="@dimen/list_item_padding" + android:paddingRight="@dimen/list_item_padding" + android:paddingTop="@dimen/list_item_padding"> + + <LinearLayout + android:id="@+id/container_info" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:orientation="horizontal" + android:visibility="gone"> + + <FrameLayout + android:layout_height="@dimen/icon_size" + android:layout_width="@dimen/icon_size"> + + <ImageView + android:contentDescription="@null" + android:id="@+id/icon_info" + android:layout_height="match_parent" + android:layout_width="wrap_content" + android:scaleType="centerInside"/> + + </FrameLayout> + + <TextView + android:id="@+id/textview_info" + android:layout_gravity="center_vertical" + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:selectAllOnFocus="true"/> + + </LinearLayout> + + <LinearLayout + android:id="@+id/container_error" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:orientation="horizontal" + android:visibility="gone"> + + <FrameLayout + android:layout_height="@dimen/icon_size" + android:layout_width="@dimen/icon_size"> + + <ImageView + android:contentDescription="@null" + android:id="@+id/icon_error" + android:layout_height="match_parent" + android:layout_width="wrap_content" + android:scaleType="centerInside"/> + + </FrameLayout> + + <TextView + android:id="@+id/textview_error" + android:layout_gravity="center_vertical" + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:selectAllOnFocus="true"/> + + </LinearLayout> + + <LinearLayout + android:layout_gravity="right" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:orientation="horizontal"> + + <Button + android:id="@+id/button_dismiss" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/button_dismiss" + style="?android:attr/buttonBarPositiveButtonStyle"/> + + </LinearLayout> + +</LinearLayout> diff --git a/packages/DocumentsUI/res/layout/item_loading_grid.xml b/packages/DocumentsUI/res/layout/item_loading_grid.xml deleted file mode 100644 index 147dfd449724..000000000000 --- a/packages/DocumentsUI/res/layout/item_loading_grid.xml +++ /dev/null @@ -1,29 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2013 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. ---> - -<com.android.documentsui.GridItem xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="@dimen/grid_height" - android:orientation="horizontal"> - - <ProgressBar - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center" - android:indeterminate="true" - style="?android:attr/progressBarStyle" /> - -</com.android.documentsui.GridItem> diff --git a/packages/DocumentsUI/res/layout/item_loading_list.xml b/packages/DocumentsUI/res/layout/item_loading_list.xml deleted file mode 100644 index 6f214edea8c4..000000000000 --- a/packages/DocumentsUI/res/layout/item_loading_list.xml +++ /dev/null @@ -1,29 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2013 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. ---> - -<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:minHeight="@dimen/list_item_height"> - - <ProgressBar - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center" - android:indeterminate="true" - style="?android:attr/progressBarStyle" /> - -</FrameLayout> diff --git a/packages/DocumentsUI/res/layout/item_message_grid.xml b/packages/DocumentsUI/res/layout/item_message_grid.xml deleted file mode 100644 index 45d61a506bb5..000000000000 --- a/packages/DocumentsUI/res/layout/item_message_grid.xml +++ /dev/null @@ -1,51 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2013 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. ---> - -<com.android.documentsui.GridItem xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="@dimen/grid_height" - android:paddingStart="?android:attr/listPreferredItemPaddingStart" - android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" - android:paddingTop="8dp" - android:paddingBottom="8dp"> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical" - android:gravity="center"> - - <ImageView - android:id="@android:id/icon" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:contentDescription="@null" /> - - <TextView - android:id="@android:id/title" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:gravity="center" - android:maxLines="4" - android:ellipsize="end" - android:paddingTop="8dp" - android:textAlignment="viewStart" - android:textAppearance="@android:style/TextAppearance.Material.Body1" - android:textColor="?android:attr/textColorPrimary" /> - - </LinearLayout> - -</com.android.documentsui.GridItem> diff --git a/packages/DocumentsUI/res/layout/item_message_list.xml b/packages/DocumentsUI/res/layout/item_message_list.xml deleted file mode 100644 index 44c8baf8cb68..000000000000 --- a/packages/DocumentsUI/res/layout/item_message_list.xml +++ /dev/null @@ -1,54 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2013 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. ---> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:minHeight="@dimen/list_item_height" - android:paddingStart="@dimen/list_item_padding" - android:paddingEnd="@dimen/list_item_padding" - android:paddingTop="8dp" - android:paddingBottom="8dp" - android:gravity="center_vertical" - android:orientation="horizontal" - android:baselineAligned="false"> - - <FrameLayout - android:layout_width="@dimen/icon_size" - android:layout_height="@dimen/icon_size" - android:layout_marginEnd="16dp"> - - <ImageView - android:id="@android:id/icon" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:scaleType="centerInside" - android:contentDescription="@null" /> - - </FrameLayout> - - <TextView - android:id="@android:id/title" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:maxLines="2" - android:ellipsize="end" - android:textAlignment="viewStart" - android:textAppearance="@android:style/TextAppearance.Material.Body1" - android:textColor="?android:attr/textColorPrimary" /> - -</LinearLayout> diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml index 4b44d7c7dc16..28018f8eceec 100644 --- a/packages/DocumentsUI/res/values/strings.xml +++ b/packages/DocumentsUI/res/values/strings.xml @@ -79,6 +79,8 @@ <string name="button_copy">Copy</string> <!-- Button label that moves files to the current directory [CHAR LIMIT=24] --> <string name="button_move">Move</string> + <!-- Button label that hides the error bar [CHAR LIMIT=24] --> + <string name="button_dismiss">Dismiss</string> <!-- Mode that sorts documents by their display name alphabetically [CHAR LIMIT=24] --> <string name="sort_name">By name</string> diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java index e351d3ce02c7..8722082856a6 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java @@ -159,6 +159,8 @@ public class DirectoryFragment extends Fragment { private GridLayoutManager mGridLayout; private int mColumnCount = 1; // This will get updated when layout changes. + private MessageBar mMessageBar; + public static void showNormal(FragmentManager fm, RootInfo root, DocumentInfo doc, int anim) { show(fm, TYPE_NORMAL, root, doc, null, anim); } @@ -220,6 +222,8 @@ public class DirectoryFragment extends Fragment { final Resources res = context.getResources(); final View view = inflater.inflate(R.layout.fragment_directory, container, false); + mMessageBar = MessageBar.create(getChildFragmentManager()); + mEmptyView = view.findViewById(android.R.id.empty); mRecView = (RecyclerView) view.findViewById(R.id.recyclerView); @@ -611,7 +615,7 @@ public class DirectoryFragment extends Fragment { @Override public boolean onBeforeItemStateChange(int position, boolean selected) { - // Directories and footer items cannot be checked + // Directories cannot be checked if (selected) { final Cursor cursor = mModel.getItem(position); checkNotNull(cursor, "Cursor cannot be null."); @@ -870,79 +874,6 @@ public class DirectoryFragment extends Fragment { return ((BaseActivity) fragment.getActivity()).getDisplayState(); } - private static abstract class Footer { - private final int mItemViewType; - - public Footer(int itemViewType) { - mItemViewType = itemViewType; - } - - public abstract View getView(View convertView, ViewGroup parent); - - public int getItemViewType() { - return mItemViewType; - } - } - - private class LoadingFooter extends Footer { - public LoadingFooter() { - super(1); - } - - @Override - public View getView(View convertView, ViewGroup parent) { - final Context context = parent.getContext(); - final State state = getDisplayState(DirectoryFragment.this); - - if (convertView == null) { - final LayoutInflater inflater = LayoutInflater.from(context); - if (state.derivedMode == MODE_LIST) { - convertView = inflater.inflate(R.layout.item_loading_list, parent, false); - } else if (state.derivedMode == MODE_GRID) { - convertView = inflater.inflate(R.layout.item_loading_grid, parent, false); - } else { - throw new IllegalStateException(); - } - } - - return convertView; - } - } - - private class MessageFooter extends Footer { - private final int mIcon; - private final String mMessage; - - public MessageFooter(int itemViewType, int icon, String message) { - super(itemViewType); - mIcon = icon; - mMessage = message; - } - - @Override - public View getView(View convertView, ViewGroup parent) { - final Context context = parent.getContext(); - final State state = getDisplayState(DirectoryFragment.this); - - if (convertView == null) { - final LayoutInflater inflater = LayoutInflater.from(context); - if (state.derivedMode == MODE_LIST) { - convertView = inflater.inflate(R.layout.item_message_list, parent, false); - } else if (state.derivedMode == MODE_GRID) { - convertView = inflater.inflate(R.layout.item_message_grid, parent, false); - } else { - throw new IllegalStateException(); - } - } - - final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon); - final TextView title = (TextView) convertView.findViewById(android.R.id.title); - icon.setImageResource(mIcon); - title.setText(mMessage); - return convertView; - } - } - // Provide a reference to the views for each data item // Complex data items may need more than one view per item, and // you provide access to all the views for a data item in a view holder @@ -961,24 +892,18 @@ public class DirectoryFragment extends Fragment { private final Context mContext; private final LayoutInflater mInflater; - // TODO: Bring back support for footers. - private final List<Footer> mFooters = new ArrayList<>(); public DocumentsAdapter(Context context) { mContext = context; mInflater = LayoutInflater.from(context); } + @Override public void onModelUpdate(Model model) { - mFooters.clear(); - if (model.info != null) { - mFooters.add(new MessageFooter(2, R.drawable.ic_dialog_info, model.info)); - } - if (model.error != null) { - mFooters.add(new MessageFooter(3, R.drawable.ic_dialog_alert, model.error)); - } - if (model.isLoading()) { - mFooters.add(new LoadingFooter()); + if (model.info != null || model.error != null) { + mMessageBar.setInfo(model.info); + mMessageBar.setError(model.error); + mMessageBar.show(); } if (model.isEmpty()) { @@ -990,9 +915,10 @@ public class DirectoryFragment extends Fragment { notifyDataSetChanged(); } + @Override public void onModelUpdateFailed(Exception e) { + // TODO: deal with catastrophic update failures String error = getString(R.string.query_error); - mFooters.add(new MessageFooter(3, R.drawable.ic_dialog_alert, error)); notifyDataSetChanged(); } @@ -1212,19 +1138,8 @@ public class DirectoryFragment extends Fragment { @Override public int getItemCount() { return mModel.getItemCount(); - // return mCursorCount + mFooters.size(); } - @Override - public int getItemViewType(int position) { - final int itemCount = mModel.getItemCount(); - if (position < itemCount) { - return 0; - } else { - position -= itemCount; - return mFooters.get(position).getItemViewType(); - } - } } private static String formatTime(Context context, long when) { diff --git a/packages/DocumentsUI/src/com/android/documentsui/MessageBar.java b/packages/DocumentsUI/src/com/android/documentsui/MessageBar.java new file mode 100644 index 000000000000..a48fd5c268b4 --- /dev/null +++ b/packages/DocumentsUI/src/com/android/documentsui/MessageBar.java @@ -0,0 +1,129 @@ +/* + * 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. + */ + +package com.android.documentsui; + +import android.annotation.Nullable; +import android.app.Fragment; +import android.app.FragmentManager; +import android.app.FragmentTransaction; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; + +/** + * A message bar displaying some info/error messages and a Dismiss button. + */ +public class MessageBar extends Fragment { + private View mView; + private ViewGroup mContainer; + + /** + * Creates an instance of a MessageBar. Note that the new MessagBar is not visible by default, + * and has to be shown by calling MessageBar.show. + */ + public static MessageBar create(FragmentManager fm) { + final MessageBar fragment = new MessageBar(); + + final FragmentTransaction ft = fm.beginTransaction(); + ft.replace(R.id.container_message_bar, fragment); + ft.commitAllowingStateLoss(); + + return fragment; + } + + /** + * Sets the info message. Can be null, in which case no info message will be displayed. The + * message bar layout will be adjusted accordingly. + */ + public void setInfo(@Nullable String info) { + View infoContainer = mView.findViewById(R.id.container_info); + if (info != null) { + TextView infoText = (TextView) mView.findViewById(R.id.textview_info); + infoText.setText(info); + infoContainer.setVisibility(View.VISIBLE); + } else { + infoContainer.setVisibility(View.GONE); + } + } + + /** + * Sets the error message. Can be null, in which case no error message will be displayed. The + * message bar layout will be adjusted accordingly. + */ + public void setError(@Nullable String error) { + View errorView = mView.findViewById(R.id.container_message_bar); + if (error != null) { + TextView errorText = (TextView) mView.findViewById(R.id.textview_error); + errorText.setText(error); + errorView.setVisibility(View.VISIBLE); + } else { + errorView.setVisibility(View.GONE); + } + } + + @Override + public View onCreateView( + LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + mView = inflater.inflate(R.layout.fragment_message_bar, container, false); + + ImageView infoIcon = (ImageView) mView.findViewById(R.id.icon_info); + infoIcon.setImageResource(R.drawable.ic_dialog_info); + + ImageView errorIcon = (ImageView) mView.findViewById(R.id.icon_error); + errorIcon.setImageResource(R.drawable.ic_dialog_alert); + + Button dismiss = (Button) mView.findViewById(R.id.button_dismiss); + dismiss.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + hide(); + } + }); + + mContainer = container; + + return mView; + } + + void hide() { + // The container view is used to show/hide the error bar. If a container is not provided, + // fall back to showing/hiding the error bar View, which also works, but does not provide + // the same animated transition. + if (mContainer != null) { + mContainer.setVisibility(View.GONE); + } else { + mView.setVisibility(View.GONE); + } + } + + void show() { + // The container view is used to show/hide the error bar. If a container is not provided, + // fall back to showing/hiding the error bar View, which also works, but does not provide + // the same animated transition. + if (mContainer != null) { + mContainer.setVisibility(View.VISIBLE); + } else { + mView.setVisibility(View.VISIBLE); + } + } +} |