Iterate on storage UI.
Support both grid and list view of documents. Show breadcrumb navigation trail in action bar. Start supporting file and directory creation. Change-Id: I93a973da7b0d4387a57fe719e7bb20944adb0290
This commit is contained in:
@@ -7,13 +7,15 @@
|
||||
<activity
|
||||
android:name=".DocumentsActivity"
|
||||
android:finishOnCloseSystemDialogs="true"
|
||||
android:excludeFromRecents="true">
|
||||
android:excludeFromRecents="true"
|
||||
android:theme="@android:style/Theme.Holo.Light">
|
||||
<intent-filter android:priority="100">
|
||||
<action android:name="android.intent.action.OPEN_DOCUMENT" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
<intent-filter android:priority="100">
|
||||
<action android:name="android.intent.action.CREATE_DOCUMENT" />
|
||||
<data android:mimeType="*/*"/>
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
BIN
packages/DocumentsUI/res/drawable-hdpi/ic_dir.png
Normal file
BIN
packages/DocumentsUI/res/drawable-hdpi/ic_dir.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 294 B |
BIN
packages/DocumentsUI/res/drawable-hdpi/ic_menu_create_dir.png
Normal file
BIN
packages/DocumentsUI/res/drawable-hdpi/ic_menu_create_dir.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 332 B |
BIN
packages/DocumentsUI/res/drawable-hdpi/ic_menu_grid.png
Normal file
BIN
packages/DocumentsUI/res/drawable-hdpi/ic_menu_grid.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 219 B |
BIN
packages/DocumentsUI/res/drawable-hdpi/ic_menu_list.png
Normal file
BIN
packages/DocumentsUI/res/drawable-hdpi/ic_menu_list.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 243 B |
BIN
packages/DocumentsUI/res/drawable-hdpi/ic_menu_sort.png
Normal file
BIN
packages/DocumentsUI/res/drawable-hdpi/ic_menu_sort.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 371 B |
33
packages/DocumentsUI/res/layout/activity.xml
Normal file
33
packages/DocumentsUI/res/layout/activity.xml
Normal file
@@ -0,0 +1,33 @@
|
||||
<?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="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/directory"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/save"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
29
packages/DocumentsUI/res/layout/fragment_backend.xml
Normal file
29
packages/DocumentsUI/res/layout/fragment_backend.xml
Normal file
@@ -0,0 +1,29 @@
|
||||
<?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="match_parent">
|
||||
|
||||
<GridView
|
||||
android:id="@+id/grid"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:listSelector="@android:color/transparent"
|
||||
android:paddingTop="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart" />
|
||||
|
||||
</FrameLayout>
|
||||
34
packages/DocumentsUI/res/layout/fragment_directory.xml
Normal file
34
packages/DocumentsUI/res/layout/fragment_directory.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<?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="match_parent">
|
||||
|
||||
<ListView
|
||||
android:id="@+id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<GridView
|
||||
android:id="@+id/grid"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:listSelector="@android:color/transparent"
|
||||
android:paddingTop="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart" />
|
||||
|
||||
</FrameLayout>
|
||||
51
packages/DocumentsUI/res/layout/fragment_save.xml
Normal file
51
packages/DocumentsUI/res/layout/fragment_save.xml
Normal file
@@ -0,0 +1,51 @@
|
||||
<?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:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:background="@color/chip"
|
||||
android:minHeight="?android:attr/listPreferredItemHeightSmall">
|
||||
|
||||
<ImageView
|
||||
android:id="@android:id/icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:scaleType="centerInside"
|
||||
android:contentDescription="@null" />
|
||||
|
||||
<EditText
|
||||
android:id="@android:id/title"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:singleLine="true" />
|
||||
|
||||
<Button
|
||||
android:id="@android:id/button1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:text="@string/btn_save"
|
||||
android:textAllCaps="true"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:padding="8dp" />
|
||||
|
||||
</LinearLayout>
|
||||
58
packages/DocumentsUI/res/layout/item_backend.xml
Normal file
58
packages/DocumentsUI/res/layout/item_backend.xml
Normal file
@@ -0,0 +1,58 @@
|
||||
<?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:paddingBottom="?android:attr/listPreferredItemPaddingEnd"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/chip"
|
||||
android:foreground="?android:attr/selectableItemBackground"
|
||||
android:duplicateParentState="true">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@android:id/icon"
|
||||
android:layout_width="24dip"
|
||||
android:layout_height="24dip"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:scaleType="centerInside"
|
||||
android:contentDescription="@null" />
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/text1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="marquee"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textAlignment="viewStart" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</FrameLayout>
|
||||
60
packages/DocumentsUI/res/layout/item_doc_grid.xml
Normal file
60
packages/DocumentsUI/res/layout/item_doc_grid.xml
Normal file
@@ -0,0 +1,60 @@
|
||||
<?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="140dip"
|
||||
android:paddingBottom="?android:attr/listPreferredItemPaddingEnd"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/chip"
|
||||
android:foreground="?android:attr/selectableItemBackground"
|
||||
android:duplicateParentState="true">
|
||||
|
||||
<GridLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:columnCount="1">
|
||||
|
||||
<ImageView
|
||||
android:id="@android:id/icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_gravity="fill_vertical"
|
||||
android:background="#bbb"
|
||||
android:scaleType="centerInside"
|
||||
android:contentDescription="@null" />
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_marginStart="8dip"
|
||||
android:layout_marginEnd="8dip"
|
||||
android:layout_marginTop="8dip"
|
||||
android:layout_marginBottom="8dip"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="marquee"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textAlignment="viewStart" />
|
||||
|
||||
</GridLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</FrameLayout>
|
||||
61
packages/DocumentsUI/res/layout/item_doc_list.xml
Normal file
61
packages/DocumentsUI/res/layout/item_doc_list.xml
Normal file
@@ -0,0 +1,61 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||
android:paddingTop="8dip"
|
||||
android:paddingBottom="8dip"
|
||||
android:columnCount="3">
|
||||
|
||||
<ImageView
|
||||
android:id="@android:id/icon"
|
||||
android:layout_width="@android:dimen/app_icon_size"
|
||||
android:layout_height="@android:dimen/app_icon_size"
|
||||
android:layout_rowSpan="2"
|
||||
android:layout_marginEnd="8dip"
|
||||
android:scaleType="centerInside"
|
||||
android:contentDescription="@null" />
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/title"
|
||||
android:layout_width="0dip"
|
||||
android:layout_gravity="fill_horizontal"
|
||||
android:layout_marginTop="2dip"
|
||||
android:layout_columnSpan="2"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="marquee"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textAlignment="viewStart" />
|
||||
|
||||
<ImageView
|
||||
android:id="@android:id/icon1"
|
||||
android:layout_width="24dip"
|
||||
android:layout_height="24dip"
|
||||
android:layout_marginEnd="8dip"
|
||||
android:visibility="gone"
|
||||
android:scaleType="centerInside"
|
||||
android:contentDescription="@null" />
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/summary"
|
||||
android:layout_marginTop="2dip"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
|
||||
</GridLayout>
|
||||
22
packages/DocumentsUI/res/menu/activity.xml
Normal file
22
packages/DocumentsUI/res/menu/activity.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:id="@+id/menu_create_dir"
|
||||
android:title="@string/menu_create_dir"
|
||||
android:icon="@drawable/ic_menu_create_dir" />
|
||||
</menu>
|
||||
30
packages/DocumentsUI/res/menu/directory.xml
Normal file
30
packages/DocumentsUI/res/menu/directory.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:id="@+id/menu_grid"
|
||||
android:title="@string/menu_grid"
|
||||
android:icon="@drawable/ic_menu_grid" />
|
||||
<item
|
||||
android:id="@+id/menu_list"
|
||||
android:title="@string/menu_list"
|
||||
android:icon="@drawable/ic_menu_list" />
|
||||
<item
|
||||
android:id="@+id/menu_sort"
|
||||
android:title="@string/menu_sort"
|
||||
android:icon="@drawable/ic_menu_sort" />
|
||||
</menu>
|
||||
19
packages/DocumentsUI/res/values/colors.xml
Normal file
19
packages/DocumentsUI/res/values/colors.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<color name="chip">#ddd</color>
|
||||
</resources>
|
||||
@@ -16,4 +16,15 @@
|
||||
|
||||
<resources>
|
||||
<string name="app_label">Documents</string>
|
||||
|
||||
<string name="title_open">Open</string>
|
||||
<string name="title_save">Save</string>
|
||||
|
||||
<string name="menu_create_dir">Create folder</string>
|
||||
<string name="menu_grid">Grid view</string>
|
||||
<string name="menu_list">List view</string>
|
||||
<string name="menu_sort">Sort by</string>
|
||||
|
||||
<string name="btn_save">Save</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.documentsui;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.app.FragmentManager;
|
||||
import android.app.FragmentTransaction;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ProviderInfo;
|
||||
import android.os.Bundle;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.GridView;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.google.android.collect.Lists;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Display all known storage backends.
|
||||
*/
|
||||
public class BackendFragment extends Fragment {
|
||||
|
||||
// TODO: handle multiple accounts from single backend
|
||||
|
||||
private GridView mGridView;
|
||||
private BackendAdapter mAdapter;
|
||||
|
||||
public static void show(FragmentManager fm) {
|
||||
final BackendFragment fragment = new BackendFragment();
|
||||
|
||||
final FragmentTransaction ft = fm.beginTransaction();
|
||||
ft.replace(R.id.directory, fragment);
|
||||
ft.setBreadCrumbTitle("TOP");
|
||||
ft.commitAllowingStateLoss();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(
|
||||
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
final Context context = inflater.getContext();
|
||||
|
||||
// Gather known storage providers
|
||||
final List<ProviderInfo> providers = context.getPackageManager()
|
||||
.queryContentProviders(null, -1, PackageManager.GET_META_DATA);
|
||||
final List<ProviderInfo> backends = Lists.newArrayList();
|
||||
for (ProviderInfo info : providers) {
|
||||
if (info.metaData != null
|
||||
&& info.metaData.containsKey(DocumentsContract.META_DATA_DOCUMENT_PROVIDER)) {
|
||||
backends.add(info);
|
||||
}
|
||||
}
|
||||
|
||||
final View view = inflater.inflate(R.layout.fragment_backend, container, false);
|
||||
|
||||
mGridView = (GridView) view.findViewById(R.id.grid);
|
||||
mGridView.setOnItemClickListener(mItemListener);
|
||||
|
||||
mAdapter = new BackendAdapter(context, backends);
|
||||
mGridView.setAdapter(mAdapter);
|
||||
mGridView.setNumColumns(GridView.AUTO_FIT);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
private OnItemClickListener mItemListener = new OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
final ProviderInfo info = mAdapter.getItem(position);
|
||||
((DocumentsActivity) getActivity()).onBackendPicked(info);
|
||||
}
|
||||
};
|
||||
|
||||
public static class BackendAdapter extends ArrayAdapter<ProviderInfo> {
|
||||
public BackendAdapter(Context context, List<ProviderInfo> list) {
|
||||
super(context, android.R.layout.simple_list_item_1, list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
convertView = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.item_backend, parent, false);
|
||||
}
|
||||
|
||||
final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon);
|
||||
final TextView text1 = (TextView) convertView.findViewById(android.R.id.text1);
|
||||
|
||||
final PackageManager pm = parent.getContext().getPackageManager();
|
||||
final ProviderInfo info = getItem(position);
|
||||
icon.setImageDrawable(info.loadIcon(pm));
|
||||
text1.setText(info.loadLabel(pm));
|
||||
|
||||
return convertView;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.documentsui;
|
||||
|
||||
import android.database.DataSetObserver;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.ListView;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
/**
|
||||
* Adapter that wraps an existing adapter, presenting its contents in multiple
|
||||
* equally-sized horizontal columns.
|
||||
*/
|
||||
public class ColumnAdapter extends BaseAdapter {
|
||||
private final ListAdapter mWrapped;
|
||||
private final OnItemClickListener mListener;
|
||||
|
||||
private int mColumns = 1;
|
||||
|
||||
public interface OnItemClickListener {
|
||||
public void onItemClick(ListAdapter adapter, int position);
|
||||
}
|
||||
|
||||
public ColumnAdapter(ListAdapter wrapped, OnItemClickListener listener) {
|
||||
mWrapped = Preconditions.checkNotNull(wrapped);
|
||||
mListener = Preconditions.checkNotNull(listener);
|
||||
|
||||
if (!wrapped.areAllItemsEnabled()) {
|
||||
throw new IllegalStateException("All items must be enabled");
|
||||
}
|
||||
if (wrapped.getViewTypeCount() > 1) {
|
||||
throw new IllegalStateException("All items must be identical");
|
||||
}
|
||||
}
|
||||
|
||||
public static void prepare(ListView list) {
|
||||
list.setItemsCanFocus(true);
|
||||
}
|
||||
|
||||
public void setColumns(int columns) {
|
||||
mColumns = columns;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private View.OnClickListener mItemListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
final int position = (Integer) v.getTag();
|
||||
mListener.onItemClick(mWrapped, position);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return (mWrapped.getCount() + mColumns - 1) / mColumns;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
convertView = new LinearLayout(parent.getContext());
|
||||
}
|
||||
|
||||
final LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
||||
0, LinearLayout.LayoutParams.WRAP_CONTENT);
|
||||
params.weight = 1f / mColumns;
|
||||
|
||||
final LinearLayout row = (LinearLayout) convertView;
|
||||
final int first = position * mColumns;
|
||||
final int last = mWrapped.getCount() - 1;
|
||||
|
||||
for (int i = 0; i < mColumns; i++) {
|
||||
View convertItem = null;
|
||||
if (i < row.getChildCount()) {
|
||||
convertItem = row.getChildAt(i);
|
||||
}
|
||||
|
||||
final int pos = first + i;
|
||||
final int validPos = Math.min(pos, last);
|
||||
final View item = mWrapped.getView(validPos, convertItem, row);
|
||||
item.setTag(validPos);
|
||||
item.setOnClickListener(mItemListener);
|
||||
item.setFocusable(true);
|
||||
|
||||
if (pos == validPos) {
|
||||
item.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
item.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
if (convertItem == null) {
|
||||
row.addView(item, params);
|
||||
}
|
||||
}
|
||||
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerDataSetObserver(DataSetObserver observer) {
|
||||
super.registerDataSetObserver(observer);
|
||||
mWrapped.registerDataSetObserver(observer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterDataSetObserver(DataSetObserver observer) {
|
||||
super.unregisterDataSetObserver(observer);
|
||||
mWrapped.unregisterDataSetObserver(observer);
|
||||
}
|
||||
}
|
||||
@@ -16,9 +16,9 @@
|
||||
|
||||
package com.android.documentsui;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.app.FragmentManager;
|
||||
import android.app.FragmentTransaction;
|
||||
import android.app.ListFragment;
|
||||
import android.app.LoaderManager.LoaderCallbacks;
|
||||
import android.content.Context;
|
||||
import android.content.CursorLoader;
|
||||
@@ -28,49 +28,94 @@ import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.provider.DocumentsContract.DocumentColumns;
|
||||
import android.text.format.DateUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.CursorAdapter;
|
||||
import android.widget.GridView;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class DirectoryFragment extends ListFragment {
|
||||
import com.android.documentsui.DocumentsActivity.Document;
|
||||
|
||||
/**
|
||||
* Display the documents inside a single directory.
|
||||
*/
|
||||
public class DirectoryFragment extends Fragment {
|
||||
|
||||
// TODO: show storage backend in item views when requested
|
||||
// TODO: implement sorting dialog
|
||||
// TODO: support multiple selection with actionmode
|
||||
|
||||
private ListView mListView;
|
||||
private GridView mGridView;
|
||||
|
||||
private DocumentsAdapter mAdapter;
|
||||
private LoaderCallbacks<Cursor> mCallbacks;
|
||||
|
||||
private int mFlags;
|
||||
|
||||
private static final String EXTRA_URI = "uri";
|
||||
private static final String EXTRA_MODE = "display_mode";
|
||||
|
||||
private static final int MODE_LIST = 1;
|
||||
private static final int MODE_GRID = 2;
|
||||
|
||||
private static final int LOADER_DOCUMENTS = 2;
|
||||
|
||||
public static void show(FragmentManager fm, Uri uri, CharSequence title) {
|
||||
public static void show(FragmentManager fm, Uri uri, String displayName) {
|
||||
final Bundle args = new Bundle();
|
||||
args.putParcelable(EXTRA_URI, uri);
|
||||
args.putInt(EXTRA_MODE, MODE_LIST);
|
||||
|
||||
final DirectoryFragment fragment = new DirectoryFragment();
|
||||
fragment.setArguments(args);
|
||||
|
||||
final FragmentTransaction ft = fm.beginTransaction();
|
||||
ft.replace(android.R.id.content, fragment);
|
||||
ft.addToBackStack(title.toString());
|
||||
ft.setBreadCrumbTitle(title);
|
||||
ft.replace(R.id.directory, fragment);
|
||||
ft.addToBackStack(displayName);
|
||||
ft.setBreadCrumbTitle(displayName);
|
||||
ft.commitAllowingStateLoss();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(
|
||||
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
final Context context = inflater.getContext();
|
||||
|
||||
final View view = inflater.inflate(R.layout.fragment_directory, container, false);
|
||||
|
||||
mListView = (ListView) view.findViewById(R.id.list);
|
||||
mListView.setOnItemClickListener(mItemListener);
|
||||
|
||||
mGridView = (GridView) view.findViewById(R.id.grid);
|
||||
mGridView.setOnItemClickListener(mItemListener);
|
||||
|
||||
mAdapter = new DocumentsAdapter(context);
|
||||
setListAdapter(mAdapter);
|
||||
updateMode();
|
||||
|
||||
// TODO: migrate flags query to loader
|
||||
final Uri uri = getArguments().getParcelable(EXTRA_URI);
|
||||
mFlags = getDocumentFlags(context, uri);
|
||||
|
||||
mCallbacks = new LoaderCallbacks<Cursor>() {
|
||||
@Override
|
||||
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||
final Uri uri = args.getParcelable(EXTRA_URI);
|
||||
return new CursorLoader(context, uri, null, null, null, null);
|
||||
final Uri contentsUri = DocumentsContract.buildContentsUri(uri);
|
||||
return new CursorLoader(context, contentsUri, null, null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -84,13 +129,17 @@ public class DirectoryFragment extends ListFragment {
|
||||
}
|
||||
};
|
||||
|
||||
return super.onCreateView(inflater, container, savedInstanceState);
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
getLoaderManager().restartLoader(LOADER_DOCUMENTS, getArguments(), mCallbacks);
|
||||
|
||||
// TODO: clean up tracking of current directory
|
||||
final Uri uri = getArguments().getParcelable(EXTRA_URI);
|
||||
((DocumentsActivity) getActivity()).onDirectoryChanged(uri, mFlags);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -100,26 +149,70 @@ public class DirectoryFragment extends ListFragment {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onListItemClick(ListView l, View v, int position, long id) {
|
||||
final Cursor cursor = (Cursor) mAdapter.getItem(position);
|
||||
final String guid = getCursorString(cursor, DocumentColumns.GUID);
|
||||
final String mimeType = getCursorString(cursor, DocumentColumns.MIME_TYPE);
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
inflater.inflate(R.menu.directory, menu);
|
||||
}
|
||||
|
||||
final Uri uri = getArguments().getParcelable(EXTRA_URI);
|
||||
final Uri childUri = DocumentsContract.buildDocumentUri(uri.getAuthority(), guid);
|
||||
@Override
|
||||
public void onPrepareOptionsMenu(Menu menu) {
|
||||
super.onPrepareOptionsMenu(menu);
|
||||
final int mode = getMode();
|
||||
menu.findItem(R.id.menu_grid).setVisible(mode != MODE_GRID);
|
||||
menu.findItem(R.id.menu_list).setVisible(mode != MODE_LIST);
|
||||
}
|
||||
|
||||
if (DocumentsContract.MIME_TYPE_DIRECTORY.equals(mimeType)) {
|
||||
// Nested directory picked, recurse using new fragment
|
||||
final Uri childContentsUri = DocumentsContract.buildContentsUri(childUri);
|
||||
final String displayName = cursor.getString(
|
||||
cursor.getColumnIndex(DocumentColumns.DISPLAY_NAME));
|
||||
DirectoryFragment.show(getFragmentManager(), childContentsUri, displayName);
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
final int id = item.getItemId();
|
||||
if (id == R.id.menu_grid) {
|
||||
getArguments().putInt(EXTRA_MODE, MODE_GRID);
|
||||
updateMode();
|
||||
return true;
|
||||
} else if (id == R.id.menu_list) {
|
||||
getArguments().putInt(EXTRA_MODE, MODE_LIST);
|
||||
updateMode();
|
||||
return true;
|
||||
} else {
|
||||
// Explicit file picked, return
|
||||
((DocumentsActivity) getActivity()).onDocumentPicked(childUri);
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateMode() {
|
||||
final int mode = getMode();
|
||||
|
||||
mListView.setVisibility(mode == MODE_LIST ? View.VISIBLE : View.GONE);
|
||||
mGridView.setVisibility(mode == MODE_GRID ? View.VISIBLE : View.GONE);
|
||||
|
||||
if (mode == MODE_GRID) {
|
||||
mListView.setAdapter(null);
|
||||
mGridView.setAdapter(mAdapter);
|
||||
mGridView.setNumColumns(GridView.AUTO_FIT);
|
||||
} else {
|
||||
mGridView.setAdapter(null);
|
||||
mListView.setAdapter(mAdapter);
|
||||
}
|
||||
}
|
||||
|
||||
private OnItemClickListener mItemListener = new OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
final Cursor cursor = (Cursor) mAdapter.getItem(position);
|
||||
|
||||
final Uri uri = getArguments().getParcelable(EXTRA_URI);
|
||||
final Document doc = Document.fromCursor(uri.getAuthority(), cursor);
|
||||
((DocumentsActivity) getActivity()).onDocumentPicked(doc);
|
||||
}
|
||||
};
|
||||
|
||||
private boolean getSupportsCreate() {
|
||||
return (mFlags & DocumentsContract.FLAG_SUPPORTS_CREATE) != 0;
|
||||
}
|
||||
|
||||
private int getMode() {
|
||||
return getArguments().getInt(EXTRA_MODE, MODE_LIST);
|
||||
}
|
||||
|
||||
private class DocumentsAdapter extends CursorAdapter {
|
||||
public DocumentsAdapter(Context context) {
|
||||
super(context, null, false);
|
||||
@@ -127,8 +220,15 @@ public class DirectoryFragment extends ListFragment {
|
||||
|
||||
@Override
|
||||
public View newView(Context context, Cursor cursor, ViewGroup parent) {
|
||||
return LayoutInflater.from(context)
|
||||
.inflate(com.android.internal.R.layout.preference, parent, false);
|
||||
final LayoutInflater inflater = LayoutInflater.from(context);
|
||||
final int mode = getMode();
|
||||
if (mode == MODE_LIST) {
|
||||
return inflater.inflate(R.layout.item_doc_list, parent, false);
|
||||
} else if (mode == MODE_GRID) {
|
||||
return inflater.inflate(R.layout.item_doc_grid, parent, false);
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -137,12 +237,10 @@ public class DirectoryFragment extends ListFragment {
|
||||
final TextView summary = (TextView) view.findViewById(android.R.id.summary);
|
||||
final ImageView icon = (ImageView) view.findViewById(android.R.id.icon);
|
||||
|
||||
icon.setMaxWidth(128);
|
||||
icon.setMaxHeight(128);
|
||||
|
||||
final String guid = getCursorString(cursor, DocumentColumns.GUID);
|
||||
final String displayName = getCursorString(cursor, DocumentColumns.DISPLAY_NAME);
|
||||
final String mimeType = getCursorString(cursor, DocumentColumns.MIME_TYPE);
|
||||
final long lastModified = getCursorLong(cursor, DocumentColumns.LAST_MODIFIED);
|
||||
final int flags = getCursorInt(cursor, DocumentColumns.FLAGS);
|
||||
|
||||
if ((flags & DocumentsContract.FLAG_SUPPORTS_THUMBNAIL) != 0) {
|
||||
@@ -150,19 +248,39 @@ public class DirectoryFragment extends ListFragment {
|
||||
final Uri childUri = DocumentsContract.buildDocumentUri(uri.getAuthority(), guid);
|
||||
icon.setImageURI(childUri);
|
||||
} else {
|
||||
icon.setImageURI(null);
|
||||
icon.setImageDrawable(DocumentsActivity.resolveDocumentIcon(context, mimeType));
|
||||
}
|
||||
|
||||
title.setText(displayName);
|
||||
summary.setText(mimeType);
|
||||
if (summary != null) {
|
||||
summary.setText(DateUtils.getRelativeTimeSpanString(lastModified));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String getCursorString(Cursor cursor, String columnName) {
|
||||
|
||||
private static int getDocumentFlags(Context context, Uri uri) {
|
||||
final Cursor cursor = context.getContentResolver().query(uri, new String[] {
|
||||
DocumentColumns.FLAGS }, null, null, null);
|
||||
try {
|
||||
if (cursor.moveToFirst()) {
|
||||
return getCursorInt(cursor, DocumentColumns.FLAGS);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static String getCursorString(Cursor cursor, String columnName) {
|
||||
return cursor.getString(cursor.getColumnIndex(columnName));
|
||||
}
|
||||
|
||||
private static int getCursorInt(Cursor cursor, String columnName) {
|
||||
public static long getCursorLong(Cursor cursor, String columnName) {
|
||||
return cursor.getLong(cursor.getColumnIndex(columnName));
|
||||
}
|
||||
|
||||
public static int getCursorInt(Cursor cursor, String columnName) {
|
||||
return cursor.getInt(cursor.getColumnIndex(columnName));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,49 +16,229 @@
|
||||
|
||||
package com.android.documentsui;
|
||||
|
||||
import static com.android.documentsui.DirectoryFragment.getCursorString;
|
||||
|
||||
import android.app.ActionBar;
|
||||
import android.app.ActionBar.OnNavigationListener;
|
||||
import android.app.Activity;
|
||||
import android.app.FragmentManager;
|
||||
import android.app.FragmentTransaction;
|
||||
import android.app.ListFragment;
|
||||
import android.app.FragmentManager.BackStackEntry;
|
||||
import android.app.FragmentManager.OnBackStackChangedListener;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ProviderInfo;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.provider.DocumentsContract.DocumentColumns;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ListView;
|
||||
|
||||
import com.google.android.collect.Lists;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class DocumentsActivity extends Activity {
|
||||
private static final String TAG = "Documents";
|
||||
|
||||
// TODO: fragment to show recently opened documents
|
||||
// TODO: pull actionbar icon from current backend
|
||||
|
||||
private static final int MODE_OPEN = 1;
|
||||
private static final int MODE_CREATE = 2;
|
||||
|
||||
private int mMode;
|
||||
private boolean mIgnoreNextNavigation;
|
||||
|
||||
private Uri mCurrentDir;
|
||||
private boolean mCurrentSupportsCreate;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
|
||||
SourceFragment.show(getFragmentManager());
|
||||
final String action = getIntent().getAction();
|
||||
if (Intent.ACTION_OPEN_DOCUMENT.equals(action)) {
|
||||
mMode = MODE_OPEN;
|
||||
} else if (Intent.ACTION_CREATE_DOCUMENT.equals(action)) {
|
||||
mMode = MODE_CREATE;
|
||||
}
|
||||
|
||||
setResult(Activity.RESULT_CANCELED);
|
||||
setContentView(R.layout.activity);
|
||||
|
||||
getFragmentManager().addOnBackStackChangedListener(mStackListener);
|
||||
BackendFragment.show(getFragmentManager());
|
||||
|
||||
updateActionBar();
|
||||
|
||||
if (mMode == MODE_CREATE) {
|
||||
final String mimeType = getIntent().getType();
|
||||
final String title = getIntent().getStringExtra(Intent.EXTRA_TITLE);
|
||||
SaveFragment.show(getFragmentManager(), mimeType, title);
|
||||
}
|
||||
}
|
||||
|
||||
public void onDocumentPicked(Uri uri) {
|
||||
Log.d(TAG, "onDocumentPicked() " + uri);
|
||||
public void updateActionBar() {
|
||||
final FragmentManager fm = getFragmentManager();
|
||||
final ActionBar actionBar = getActionBar();
|
||||
|
||||
if (fm.getBackStackEntryCount() > 0) {
|
||||
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
|
||||
actionBar.setDisplayShowHomeEnabled(true);
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
actionBar.setTitle(null);
|
||||
actionBar.setListNavigationCallbacks(mStackAdapter, mNavigationListener);
|
||||
actionBar.setSelectedNavigationItem(mStackAdapter.getCount() - 1);
|
||||
mIgnoreNextNavigation = true;
|
||||
|
||||
} else {
|
||||
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
|
||||
actionBar.setDisplayShowHomeEnabled(false);
|
||||
actionBar.setDisplayHomeAsUpEnabled(false);
|
||||
|
||||
if (mMode == MODE_OPEN) {
|
||||
actionBar.setTitle(R.string.title_open);
|
||||
} else if (mMode == MODE_CREATE) {
|
||||
actionBar.setTitle(R.string.title_save);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
getMenuInflater().inflate(R.menu.activity, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
super.onPrepareOptionsMenu(menu);
|
||||
|
||||
final MenuItem createDir = menu.findItem(R.id.menu_create_dir);
|
||||
createDir.setVisible(mMode == MODE_CREATE);
|
||||
createDir.setEnabled(mCurrentSupportsCreate);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
final int id = item.getItemId();
|
||||
if (id == android.R.id.home) {
|
||||
getFragmentManager().popBackStack();
|
||||
updateActionBar();
|
||||
} else if (id == R.id.menu_create_dir) {
|
||||
// TODO: show dialog to create directory
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private OnBackStackChangedListener mStackListener = new OnBackStackChangedListener() {
|
||||
@Override
|
||||
public void onBackStackChanged() {
|
||||
updateActionBar();
|
||||
}
|
||||
};
|
||||
|
||||
private BaseAdapter mStackAdapter = new BaseAdapter() {
|
||||
@Override
|
||||
public int getCount() {
|
||||
return getFragmentManager().getBackStackEntryCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return getFragmentManager().getBackStackEntryAt(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return getFragmentManager().getBackStackEntryAt(position).getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
convertView = LayoutInflater.from(parent.getContext())
|
||||
.inflate(android.R.layout.simple_dropdown_item_1line, parent, false);
|
||||
}
|
||||
|
||||
final BackStackEntry entry = getFragmentManager().getBackStackEntryAt(position);
|
||||
final TextView text1 = (TextView) convertView.findViewById(android.R.id.text1);
|
||||
text1.setText(entry.getBreadCrumbTitle());
|
||||
|
||||
return convertView;
|
||||
}
|
||||
};
|
||||
|
||||
private OnNavigationListener mNavigationListener = new OnNavigationListener() {
|
||||
@Override
|
||||
public boolean onNavigationItemSelected(int itemPosition, long itemId) {
|
||||
if (mIgnoreNextNavigation) {
|
||||
mIgnoreNextNavigation = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
getFragmentManager().popBackStack((int) itemId, 0);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
public void onDirectoryChanged(Uri uri, int flags) {
|
||||
mCurrentDir = uri;
|
||||
mCurrentSupportsCreate = (flags & DocumentsContract.FLAG_SUPPORTS_CREATE) != 0;
|
||||
|
||||
if (mMode == MODE_CREATE) {
|
||||
final FragmentManager fm = getFragmentManager();
|
||||
SaveFragment.get(fm).setSaveEnabled(mCurrentSupportsCreate);
|
||||
}
|
||||
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
public void onBackendPicked(ProviderInfo info) {
|
||||
final Uri uri = DocumentsContract.buildDocumentUri(
|
||||
info.authority, DocumentsContract.ROOT_GUID);
|
||||
final CharSequence displayName = info.loadLabel(getPackageManager());
|
||||
DirectoryFragment.show(getFragmentManager(), uri, displayName.toString());
|
||||
}
|
||||
|
||||
public void onDocumentPicked(Document doc) {
|
||||
final FragmentManager fm = getFragmentManager();
|
||||
if (DocumentsContract.MIME_TYPE_DIRECTORY.equals(doc.mimeType)) {
|
||||
// Nested directory picked, recurse using new fragment
|
||||
DirectoryFragment.show(fm, doc.uri, doc.displayName);
|
||||
} else if (mMode == MODE_OPEN) {
|
||||
// Explicit file picked, return
|
||||
onFinished(doc.uri);
|
||||
} else if (mMode == MODE_CREATE) {
|
||||
// Overwrite current filename
|
||||
SaveFragment.get(fm).setDisplayName(doc.displayName);
|
||||
}
|
||||
}
|
||||
|
||||
public void onSaveRequested(String mimeType, String displayName) {
|
||||
// TODO: create file, confirming before overwriting
|
||||
onFinished(null);
|
||||
}
|
||||
|
||||
private void onFinished(Uri uri) {
|
||||
Log.d(TAG, "onFinished() " + uri);
|
||||
|
||||
final Intent intent = new Intent();
|
||||
intent.setData(uri);
|
||||
|
||||
intent.addFlags(
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_PERSIST_GRANT_URI_PERMISSION);
|
||||
if (Intent.ACTION_CREATE_DOCUMENT.equals(getIntent().getAction())) {
|
||||
if (mMode == MODE_CREATE) {
|
||||
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
}
|
||||
|
||||
@@ -66,50 +246,37 @@ public class DocumentsActivity extends Activity {
|
||||
finish();
|
||||
}
|
||||
|
||||
public static class SourceFragment extends ListFragment {
|
||||
private ArrayList<ProviderInfo> mProviders = Lists.newArrayList();
|
||||
private ArrayAdapter<ProviderInfo> mAdapter;
|
||||
public static class Document {
|
||||
public Uri uri;
|
||||
public String mimeType;
|
||||
public String displayName;
|
||||
|
||||
public static void show(FragmentManager fm) {
|
||||
final SourceFragment fragment = new SourceFragment();
|
||||
|
||||
final FragmentTransaction ft = fm.beginTransaction();
|
||||
ft.replace(android.R.id.content, fragment);
|
||||
ft.setBreadCrumbTitle("TOP");
|
||||
ft.commitAllowingStateLoss();
|
||||
public static Document fromCursor(String authority, Cursor cursor) {
|
||||
final Document doc = new Document();
|
||||
final String guid = getCursorString(cursor, DocumentColumns.GUID);
|
||||
doc.uri = DocumentsContract.buildDocumentUri(authority, guid);
|
||||
doc.mimeType = getCursorString(cursor, DocumentColumns.MIME_TYPE);
|
||||
doc.displayName = getCursorString(cursor, DocumentColumns.DISPLAY_NAME);
|
||||
return doc;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(
|
||||
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
final Context context = inflater.getContext();
|
||||
public static Drawable resolveDocumentIcon(Context context, String mimeType) {
|
||||
// TODO: allow backends to provide custom MIME icons
|
||||
if (DocumentsContract.MIME_TYPE_DIRECTORY.equals(mimeType)) {
|
||||
return context.getResources().getDrawable(R.drawable.ic_dir);
|
||||
} else {
|
||||
final PackageManager pm = context.getPackageManager();
|
||||
final Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setType(mimeType);
|
||||
|
||||
// Gather known storage providers
|
||||
mProviders.clear();
|
||||
final List<ProviderInfo> providers = context.getPackageManager()
|
||||
.queryContentProviders(null, -1, PackageManager.GET_META_DATA);
|
||||
for (ProviderInfo info : providers) {
|
||||
if (info.metaData != null
|
||||
&& info.metaData.containsKey(
|
||||
DocumentsContract.META_DATA_DOCUMENT_PROVIDER)) {
|
||||
mProviders.add(info);
|
||||
}
|
||||
final ResolveInfo info = pm.resolveActivity(
|
||||
intent, PackageManager.MATCH_DEFAULT_ONLY);
|
||||
if (info != null) {
|
||||
return info.loadIcon(pm);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
mAdapter = new ArrayAdapter<ProviderInfo>(
|
||||
context, android.R.layout.simple_list_item_1, mProviders);
|
||||
setListAdapter(mAdapter);
|
||||
|
||||
return super.onCreateView(inflater, container, savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onListItemClick(ListView l, View v, int position, long id) {
|
||||
final ProviderInfo info = mAdapter.getItem(position);
|
||||
final Uri uri = DocumentsContract.buildContentsUri(DocumentsContract.buildDocumentUri(
|
||||
info.authority, DocumentsContract.ROOT_GUID));
|
||||
final String displayName = info.name;
|
||||
DirectoryFragment.show(getFragmentManager(), uri, displayName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.documentsui;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.app.FragmentManager;
|
||||
import android.app.FragmentTransaction;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
|
||||
/**
|
||||
* Display document title editor and save button.
|
||||
*/
|
||||
public class SaveFragment extends Fragment {
|
||||
public static final String TAG = "SaveFragment";
|
||||
|
||||
private EditText mDisplayName;
|
||||
private Button mSave;
|
||||
|
||||
private static final String EXTRA_MIME_TYPE = "mime_type";
|
||||
private static final String EXTRA_DISPLAY_NAME = "display_name";
|
||||
|
||||
public static void show(FragmentManager fm, String mimeType, String displayName) {
|
||||
final Bundle args = new Bundle();
|
||||
args.putString(EXTRA_MIME_TYPE, mimeType);
|
||||
args.putString(EXTRA_DISPLAY_NAME, displayName);
|
||||
|
||||
final SaveFragment fragment = new SaveFragment();
|
||||
fragment.setArguments(args);
|
||||
|
||||
final FragmentTransaction ft = fm.beginTransaction();
|
||||
ft.replace(R.id.save, fragment, TAG);
|
||||
ft.commitAllowingStateLoss();
|
||||
}
|
||||
|
||||
public static SaveFragment get(FragmentManager fm) {
|
||||
return (SaveFragment) fm.findFragmentByTag(TAG);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(
|
||||
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
final Context context = inflater.getContext();
|
||||
|
||||
final View view = inflater.inflate(R.layout.fragment_save, container, false);
|
||||
|
||||
final ImageView icon = (ImageView) view.findViewById(android.R.id.icon);
|
||||
icon.setImageDrawable(DocumentsActivity.resolveDocumentIcon(
|
||||
context, getArguments().getString(EXTRA_MIME_TYPE)));
|
||||
|
||||
mDisplayName = (EditText) view.findViewById(android.R.id.title);
|
||||
mDisplayName.setText(getArguments().getString(EXTRA_DISPLAY_NAME));
|
||||
|
||||
mSave = (Button) view.findViewById(android.R.id.button1);
|
||||
mSave.setOnClickListener(mSaveListener);
|
||||
mSave.setEnabled(false);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
private View.OnClickListener mSaveListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
final String mimeType = getArguments().getString(EXTRA_MIME_TYPE);
|
||||
final String displayName = getArguments().getString(EXTRA_DISPLAY_NAME);
|
||||
((DocumentsActivity) getActivity()).onSaveRequested(mimeType, displayName);
|
||||
}
|
||||
};
|
||||
|
||||
public void setDisplayName(String displayName) {
|
||||
getArguments().putString(EXTRA_DISPLAY_NAME, displayName);
|
||||
mDisplayName.setText(displayName);
|
||||
}
|
||||
|
||||
public void setSaveEnabled(boolean enabled) {
|
||||
mSave.setEnabled(enabled);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user