blob: c83edc4014faf550b626174a6db0b7210fdc9c25 [file] [log] [blame]
Jeff Sharkey9e0036e2013-04-26 16:54:55 -07001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.documentsui;
18
Jeff Sharkey54e55b72013-06-30 20:02:59 -070019import static com.android.documentsui.DirectoryFragment.getCursorString;
20
21import android.app.ActionBar;
22import android.app.ActionBar.OnNavigationListener;
Jeff Sharkey9e0036e2013-04-26 16:54:55 -070023import android.app.Activity;
24import android.app.FragmentManager;
Jeff Sharkey54e55b72013-06-30 20:02:59 -070025import android.app.FragmentManager.BackStackEntry;
26import android.app.FragmentManager.OnBackStackChangedListener;
Jeff Sharkey9e0036e2013-04-26 16:54:55 -070027import android.content.Context;
28import android.content.Intent;
29import android.content.pm.PackageManager;
30import android.content.pm.ProviderInfo;
Jeff Sharkey54e55b72013-06-30 20:02:59 -070031import android.content.pm.ResolveInfo;
32import android.database.Cursor;
33import android.graphics.drawable.Drawable;
Jeff Sharkey9e0036e2013-04-26 16:54:55 -070034import android.net.Uri;
35import android.os.Bundle;
36import android.provider.DocumentsContract;
Jeff Sharkey54e55b72013-06-30 20:02:59 -070037import android.provider.DocumentsContract.DocumentColumns;
Jeff Sharkey9e0036e2013-04-26 16:54:55 -070038import android.util.Log;
39import android.view.LayoutInflater;
Jeff Sharkey54e55b72013-06-30 20:02:59 -070040import android.view.Menu;
41import android.view.MenuItem;
Jeff Sharkey9e0036e2013-04-26 16:54:55 -070042import android.view.View;
43import android.view.ViewGroup;
Jeff Sharkey54e55b72013-06-30 20:02:59 -070044import android.widget.BaseAdapter;
45import android.widget.TextView;
Jeff Sharkey9e0036e2013-04-26 16:54:55 -070046
47public class DocumentsActivity extends Activity {
48 private static final String TAG = "Documents";
49
Jeff Sharkey54e55b72013-06-30 20:02:59 -070050 // TODO: fragment to show recently opened documents
51 // TODO: pull actionbar icon from current backend
52
53 private static final int MODE_OPEN = 1;
54 private static final int MODE_CREATE = 2;
55
56 private int mMode;
57 private boolean mIgnoreNextNavigation;
58
59 private Uri mCurrentDir;
60 private boolean mCurrentSupportsCreate;
61
Jeff Sharkey9e0036e2013-04-26 16:54:55 -070062 @Override
63 public void onCreate(Bundle icicle) {
64 super.onCreate(icicle);
65
Jeff Sharkey54e55b72013-06-30 20:02:59 -070066 final String action = getIntent().getAction();
67 if (Intent.ACTION_OPEN_DOCUMENT.equals(action)) {
68 mMode = MODE_OPEN;
69 } else if (Intent.ACTION_CREATE_DOCUMENT.equals(action)) {
70 mMode = MODE_CREATE;
71 }
72
Jeff Sharkey9e0036e2013-04-26 16:54:55 -070073 setResult(Activity.RESULT_CANCELED);
Jeff Sharkey54e55b72013-06-30 20:02:59 -070074 setContentView(R.layout.activity);
75
76 getFragmentManager().addOnBackStackChangedListener(mStackListener);
77 BackendFragment.show(getFragmentManager());
78
79 updateActionBar();
80
81 if (mMode == MODE_CREATE) {
82 final String mimeType = getIntent().getType();
83 final String title = getIntent().getStringExtra(Intent.EXTRA_TITLE);
84 SaveFragment.show(getFragmentManager(), mimeType, title);
85 }
Jeff Sharkey9e0036e2013-04-26 16:54:55 -070086 }
87
Jeff Sharkey54e55b72013-06-30 20:02:59 -070088 public void updateActionBar() {
89 final FragmentManager fm = getFragmentManager();
90 final ActionBar actionBar = getActionBar();
91
92 if (fm.getBackStackEntryCount() > 0) {
93 actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
94 actionBar.setDisplayShowHomeEnabled(true);
95 actionBar.setDisplayHomeAsUpEnabled(true);
96 actionBar.setTitle(null);
97 actionBar.setListNavigationCallbacks(mStackAdapter, mNavigationListener);
98 actionBar.setSelectedNavigationItem(mStackAdapter.getCount() - 1);
99 mIgnoreNextNavigation = true;
100
101 } else {
102 actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
103 actionBar.setDisplayShowHomeEnabled(false);
104 actionBar.setDisplayHomeAsUpEnabled(false);
105
106 if (mMode == MODE_OPEN) {
107 actionBar.setTitle(R.string.title_open);
108 } else if (mMode == MODE_CREATE) {
109 actionBar.setTitle(R.string.title_save);
110 }
111 }
112 }
113
114 @Override
115 public boolean onCreateOptionsMenu(Menu menu) {
116 super.onCreateOptionsMenu(menu);
117 getMenuInflater().inflate(R.menu.activity, menu);
118 return true;
119 }
120
121 @Override
122 public boolean onPrepareOptionsMenu(Menu menu) {
123 super.onPrepareOptionsMenu(menu);
124
125 final MenuItem createDir = menu.findItem(R.id.menu_create_dir);
126 createDir.setVisible(mMode == MODE_CREATE);
127 createDir.setEnabled(mCurrentSupportsCreate);
128
129 return true;
130 }
131
132 @Override
133 public boolean onOptionsItemSelected(MenuItem item) {
134 final int id = item.getItemId();
135 if (id == android.R.id.home) {
136 getFragmentManager().popBackStack();
137 updateActionBar();
138 } else if (id == R.id.menu_create_dir) {
139 // TODO: show dialog to create directory
140 }
141 return super.onOptionsItemSelected(item);
142 }
143
144 private OnBackStackChangedListener mStackListener = new OnBackStackChangedListener() {
145 @Override
146 public void onBackStackChanged() {
147 updateActionBar();
148 }
149 };
150
151 private BaseAdapter mStackAdapter = new BaseAdapter() {
152 @Override
153 public int getCount() {
154 return getFragmentManager().getBackStackEntryCount();
155 }
156
157 @Override
158 public Object getItem(int position) {
159 return getFragmentManager().getBackStackEntryAt(position);
160 }
161
162 @Override
163 public long getItemId(int position) {
164 return getFragmentManager().getBackStackEntryAt(position).getId();
165 }
166
167 @Override
168 public View getView(int position, View convertView, ViewGroup parent) {
169 if (convertView == null) {
170 convertView = LayoutInflater.from(parent.getContext())
171 .inflate(android.R.layout.simple_dropdown_item_1line, parent, false);
172 }
173
174 final BackStackEntry entry = getFragmentManager().getBackStackEntryAt(position);
175 final TextView text1 = (TextView) convertView.findViewById(android.R.id.text1);
176 text1.setText(entry.getBreadCrumbTitle());
177
178 return convertView;
179 }
180 };
181
182 private OnNavigationListener mNavigationListener = new OnNavigationListener() {
183 @Override
184 public boolean onNavigationItemSelected(int itemPosition, long itemId) {
185 if (mIgnoreNextNavigation) {
186 mIgnoreNextNavigation = false;
187 return false;
188 }
189
190 getFragmentManager().popBackStack((int) itemId, 0);
191 return true;
192 }
193 };
194
195 public void onDirectoryChanged(Uri uri, int flags) {
196 mCurrentDir = uri;
197 mCurrentSupportsCreate = (flags & DocumentsContract.FLAG_SUPPORTS_CREATE) != 0;
198
199 if (mMode == MODE_CREATE) {
200 final FragmentManager fm = getFragmentManager();
201 SaveFragment.get(fm).setSaveEnabled(mCurrentSupportsCreate);
202 }
203
204 invalidateOptionsMenu();
205 }
206
207 public void onBackendPicked(ProviderInfo info) {
208 final Uri uri = DocumentsContract.buildDocumentUri(
209 info.authority, DocumentsContract.ROOT_GUID);
210 final CharSequence displayName = info.loadLabel(getPackageManager());
211 DirectoryFragment.show(getFragmentManager(), uri, displayName.toString());
212 }
213
214 public void onDocumentPicked(Document doc) {
215 final FragmentManager fm = getFragmentManager();
216 if (DocumentsContract.MIME_TYPE_DIRECTORY.equals(doc.mimeType)) {
217 // Nested directory picked, recurse using new fragment
218 DirectoryFragment.show(fm, doc.uri, doc.displayName);
219 } else if (mMode == MODE_OPEN) {
220 // Explicit file picked, return
221 onFinished(doc.uri);
222 } else if (mMode == MODE_CREATE) {
223 // Overwrite current filename
224 SaveFragment.get(fm).setDisplayName(doc.displayName);
225 }
226 }
227
228 public void onSaveRequested(String mimeType, String displayName) {
229 // TODO: create file, confirming before overwriting
230 onFinished(null);
231 }
232
233 private void onFinished(Uri uri) {
234 Log.d(TAG, "onFinished() " + uri);
Jeff Sharkey9e0036e2013-04-26 16:54:55 -0700235
236 final Intent intent = new Intent();
237 intent.setData(uri);
238
239 intent.addFlags(
240 Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_PERSIST_GRANT_URI_PERMISSION);
Jeff Sharkey54e55b72013-06-30 20:02:59 -0700241 if (mMode == MODE_CREATE) {
Jeff Sharkey9e0036e2013-04-26 16:54:55 -0700242 intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
243 }
244
245 setResult(Activity.RESULT_OK, intent);
246 finish();
247 }
248
Jeff Sharkey54e55b72013-06-30 20:02:59 -0700249 public static class Document {
250 public Uri uri;
251 public String mimeType;
252 public String displayName;
Jeff Sharkey9e0036e2013-04-26 16:54:55 -0700253
Jeff Sharkey54e55b72013-06-30 20:02:59 -0700254 public static Document fromCursor(String authority, Cursor cursor) {
255 final Document doc = new Document();
256 final String guid = getCursorString(cursor, DocumentColumns.GUID);
257 doc.uri = DocumentsContract.buildDocumentUri(authority, guid);
258 doc.mimeType = getCursorString(cursor, DocumentColumns.MIME_TYPE);
259 doc.displayName = getCursorString(cursor, DocumentColumns.DISPLAY_NAME);
260 return doc;
Jeff Sharkey9e0036e2013-04-26 16:54:55 -0700261 }
Jeff Sharkey54e55b72013-06-30 20:02:59 -0700262 }
Jeff Sharkey9e0036e2013-04-26 16:54:55 -0700263
Jeff Sharkey54e55b72013-06-30 20:02:59 -0700264 public static Drawable resolveDocumentIcon(Context context, String mimeType) {
265 // TODO: allow backends to provide custom MIME icons
266 if (DocumentsContract.MIME_TYPE_DIRECTORY.equals(mimeType)) {
267 return context.getResources().getDrawable(R.drawable.ic_dir);
268 } else {
269 final PackageManager pm = context.getPackageManager();
270 final Intent intent = new Intent(Intent.ACTION_VIEW);
271 intent.setType(mimeType);
Jeff Sharkey9e0036e2013-04-26 16:54:55 -0700272
Jeff Sharkey54e55b72013-06-30 20:02:59 -0700273 final ResolveInfo info = pm.resolveActivity(
274 intent, PackageManager.MATCH_DEFAULT_ONLY);
275 if (info != null) {
276 return info.loadIcon(pm);
277 } else {
278 return null;
Jeff Sharkey9e0036e2013-04-26 16:54:55 -0700279 }
Jeff Sharkey9e0036e2013-04-26 16:54:55 -0700280 }
281 }
282}