diff options
Diffstat (limited to 'packages')
146 files changed, 7974 insertions, 2481 deletions
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml index 27f93c0..d79f5c6 100644 --- a/packages/DocumentsUI/AndroidManifest.xml +++ b/packages/DocumentsUI/AndroidManifest.xml @@ -4,6 +4,7 @@ <uses-permission android:name="android.permission.MANAGE_DOCUMENTS" /> <application + android:name=".DocumentsApplication" android:label="@string/app_label" android:supportsRtl="true"> @@ -17,13 +18,27 @@ <intent-filter android:priority="100"> <action android:name="android.intent.action.OPEN_DOCUMENT" /> <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.OPENABLE" /> <data android:mimeType="*/*" /> </intent-filter> <intent-filter android:priority="100"> <action android:name="android.intent.action.CREATE_DOCUMENT" /> <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.OPENABLE" /> <data android:mimeType="*/*" /> </intent-filter> + <intent-filter android:priority="100"> + <action android:name="android.intent.action.GET_CONTENT" /> + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.OPENABLE" /> + <data android:mimeType="*/*" /> + </intent-filter> + <!-- data expected to point at existing root to manage --> + <intent-filter> + <action android:name="android.intent.action.MANAGE_DOCUMENT" /> + <category android:name="android.intent.category.DEFAULT" /> + <data android:mimeType="vnd.android.cursor.item/root" /> + </intent-filter> </activity> <activity @@ -37,6 +52,14 @@ android:authorities="com.android.documentsui.recents" android:exported="false" /> + <receiver android:name=".DocumentChangedReceiver"> + <intent-filter> + <action android:name="android.provider.action.DOCUMENT_CHANGED" /> + <data android:mimeType="vnd.android.cursor.dir/root" /> + <data android:mimeType="vnd.android.cursor.item/root" /> + </intent-filter> + </receiver> + <!-- TODO: remove when we have real clients --> <activity android:name=".TestActivity" android:enabled="false"> <intent-filter> diff --git a/packages/DocumentsUI/res/layout/fragment_directory.xml b/packages/DocumentsUI/res/layout/fragment_directory.xml index 8dbd1de..67c5954 100644 --- a/packages/DocumentsUI/res/layout/fragment_directory.xml +++ b/packages/DocumentsUI/res/layout/fragment_directory.xml @@ -42,4 +42,12 @@ android:paddingStart="?android:attr/listPreferredItemPaddingStart" android:visibility="gone" /> + <Button + android:id="@+id/more" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom" + android:text="@string/more" + android:visibility="gone" /> + </FrameLayout> diff --git a/packages/DocumentsUI/res/menu/mode_directory.xml b/packages/DocumentsUI/res/menu/mode_directory.xml index 6b6d7e9..624e024 100644 --- a/packages/DocumentsUI/res/menu/mode_directory.xml +++ b/packages/DocumentsUI/res/menu/mode_directory.xml @@ -19,4 +19,14 @@ android:id="@+id/menu_open" android:title="@string/menu_open" android:showAsAction="always" /> + <item + android:id="@+id/menu_share" + android:icon="@android:drawable/ic_menu_share" + android:title="@string/menu_share" + android:showAsAction="always" /> + <item + android:id="@+id/menu_delete" + android:icon="@android:drawable/ic_menu_delete" + android:title="@string/menu_delete" + android:showAsAction="always" /> </menu> diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml index 84f89b4..928ba85 100644 --- a/packages/DocumentsUI/res/values/strings.xml +++ b/packages/DocumentsUI/res/values/strings.xml @@ -29,6 +29,8 @@ <string name="menu_open">Open</string> <string name="menu_save">Save</string> + <string name="menu_share">Share</string> + <string name="menu_delete">Delete</string> <string name="mode_selected_count"><xliff:g id="count" example="3">%1$d</xliff:g> selected</string> @@ -47,6 +49,7 @@ <string name="root_type_service">Services</string> <string name="root_type_shortcut">Shortcuts</string> <string name="root_type_device">Devices</string> + <string name="root_type_apps">More apps</string> <string name="pref_advanced_devices">Display advanced devices</string> <string name="pref_file_size">Display file size</string> @@ -54,4 +57,10 @@ <string name="empty">No items</string> + <string name="toast_no_application">Can\'t open file</string> + <string name="toast_failed_delete">Unable to delete some documents</string> + + <string name="more">More</string> + <string name="loading">Loading\u2026</string> + </resources> diff --git a/packages/DocumentsUI/res/xml/document_provider.xml b/packages/DocumentsUI/res/xml/document_provider.xml new file mode 100644 index 0000000..77891cb --- /dev/null +++ b/packages/DocumentsUI/res/xml/document_provider.xml @@ -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. +--> + +<documents-provider xmlns:android="http://schemas.android.com/apk/res/android" + android:customRoots="true"> +</documents-provider> diff --git a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java index 313774b..575947f 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java @@ -27,8 +27,8 @@ import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.net.Uri; import android.os.Bundle; -import android.provider.DocumentsContract; import android.provider.DocumentsContract.DocumentColumns; +import android.provider.DocumentsContract.Documents; import android.view.LayoutInflater; import android.view.View; import android.widget.EditText; @@ -69,7 +69,7 @@ public class CreateDirectoryFragment extends DialogFragment { final String displayName = text1.getText().toString(); final ContentValues values = new ContentValues(); - values.put(DocumentColumns.MIME_TYPE, DocumentsContract.MIME_TYPE_DIRECTORY); + values.put(DocumentColumns.MIME_TYPE, Documents.MIME_TYPE_DIR); values.put(DocumentColumns.DISPLAY_NAME, displayName); final DocumentsActivity activity = (DocumentsActivity) getActivity(); diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java index 5a6060a..dd9aee5 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java @@ -16,17 +16,33 @@ package com.android.documentsui; +import static com.android.documentsui.DocumentsActivity.TAG; +import static com.android.documentsui.DocumentsActivity.DisplayState.ACTION_MANAGE; +import static com.android.documentsui.DocumentsActivity.DisplayState.MODE_GRID; +import static com.android.documentsui.DocumentsActivity.DisplayState.MODE_LIST; +import static com.android.documentsui.DocumentsActivity.DisplayState.SORT_ORDER_DATE; +import static com.android.documentsui.DocumentsActivity.DisplayState.SORT_ORDER_NAME; +import static com.android.documentsui.DocumentsActivity.DisplayState.SORT_ORDER_SIZE; + import android.app.Fragment; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.app.LoaderManager.LoaderCallbacks; +import android.content.ContentResolver; import android.content.Context; +import android.content.Intent; import android.content.Loader; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.Point; import android.net.Uri; +import android.os.AsyncTask; import android.os.Bundle; import android.provider.DocumentsContract; import android.text.format.DateUtils; import android.text.format.Formatter; +import android.text.format.Time; +import android.util.Log; import android.util.SparseBooleanArray; import android.view.ActionMode; import android.view.LayoutInflater; @@ -39,10 +55,12 @@ import android.widget.AbsListView.MultiChoiceModeListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; +import android.widget.Button; import android.widget.GridView; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; +import android.widget.Toast; import com.android.documentsui.DocumentsActivity.DisplayState; import com.android.documentsui.model.Document; @@ -50,7 +68,6 @@ import com.android.documentsui.model.Root; import com.android.internal.util.Predicate; import com.google.android.collect.Lists; -import java.text.DateFormat; import java.util.ArrayList; import java.util.Comparator; import java.util.List; @@ -64,6 +81,7 @@ public class DirectoryFragment extends Fragment { private View mEmptyView; private ListView mListView; private GridView mGridView; + private Button mMoreView; private AbsListView mCurrentView; @@ -75,8 +93,10 @@ public class DirectoryFragment extends Fragment { private int mType = TYPE_NORMAL; + private Point mThumbSize; + private DocumentsAdapter mAdapter; - private LoaderCallbacks<List<Document>> mCallbacks; + private LoaderCallbacks<DirectoryResult> mCallbacks; private static final String EXTRA_TYPE = "type"; private static final String EXTRA_URI = "uri"; @@ -133,18 +153,20 @@ public class DirectoryFragment extends Fragment { mGridView.setOnItemClickListener(mItemListener); mGridView.setMultiChoiceModeListener(mMultiListener); + mMoreView = (Button) view.findViewById(R.id.more); + mAdapter = new DocumentsAdapter(); final Uri uri = getArguments().getParcelable(EXTRA_URI); mType = getArguments().getInt(EXTRA_TYPE); - mCallbacks = new LoaderCallbacks<List<Document>>() { + mCallbacks = new LoaderCallbacks<DirectoryResult>() { @Override - public Loader<List<Document>> onCreateLoader(int id, Bundle args) { + public Loader<DirectoryResult> onCreateLoader(int id, Bundle args) { final DisplayState state = getDisplayState(DirectoryFragment.this); mFilter = new MimePredicate(state.acceptMimes); - final Uri contentsUri; + Uri contentsUri; if (mType == TYPE_NORMAL) { contentsUri = DocumentsContract.buildContentsUri(uri); } else if (mType == TYPE_RECENT_OPEN) { @@ -153,12 +175,16 @@ public class DirectoryFragment extends Fragment { contentsUri = uri; } + if (state.localOnly) { + contentsUri = DocumentsContract.setLocalOnly(contentsUri); + } + final Comparator<Document> sortOrder; - if (state.sortOrder == DisplayState.SORT_ORDER_DATE || mType == TYPE_RECENT_OPEN) { + if (state.sortOrder == SORT_ORDER_DATE || mType == TYPE_RECENT_OPEN) { sortOrder = new Document.DateComparator(); - } else if (state.sortOrder == DisplayState.SORT_ORDER_NAME) { + } else if (state.sortOrder == SORT_ORDER_NAME) { sortOrder = new Document.NameComparator(); - } else if (state.sortOrder == DisplayState.SORT_ORDER_SIZE) { + } else if (state.sortOrder == SORT_ORDER_SIZE) { sortOrder = new Document.SizeComparator(); } else { throw new IllegalArgumentException("Unknown sort order " + state.sortOrder); @@ -168,12 +194,34 @@ public class DirectoryFragment extends Fragment { } @Override - public void onLoadFinished(Loader<List<Document>> loader, List<Document> data) { - mAdapter.swapDocuments(data); + public void onLoadFinished(Loader<DirectoryResult> loader, DirectoryResult result) { + mAdapter.swapDocuments(result.contents); + + final Cursor cursor = result.cursor; + if (cursor != null && cursor.getExtras() + .getBoolean(DocumentsContract.EXTRA_HAS_MORE, false)) { + mMoreView.setText(R.string.more); + mMoreView.setVisibility(View.VISIBLE); + mMoreView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mMoreView.setText(R.string.loading); + final Bundle bundle = new Bundle(); + bundle.putBoolean(DocumentsContract.EXTRA_REQUEST_MORE, true); + try { + cursor.respond(bundle); + } catch (Exception e) { + Log.w(TAG, "Failed to respond: " + e); + } + } + }); + } else { + mMoreView.setVisibility(View.GONE); + } } @Override - public void onLoaderReset(Loader<List<Document>> loader) { + public void onLoaderReset(Loader<DirectoryResult> loader) { mAdapter.swapDocuments(null); } }; @@ -186,10 +234,6 @@ public class DirectoryFragment extends Fragment { @Override public void onStart() { super.onStart(); - - final Context context = getActivity(); - getDisplayState(this).showSize = SettingsActivity.getDisplayFileSize(context); - getLoaderManager().restartLoader(mLoaderId, getArguments(), mCallbacks); } @@ -207,8 +251,8 @@ public class DirectoryFragment extends Fragment { mListView.smoothScrollToPosition(0); mGridView.smoothScrollToPosition(0); - mListView.setVisibility(state.mode == DisplayState.MODE_LIST ? View.VISIBLE : View.GONE); - mGridView.setVisibility(state.mode == DisplayState.MODE_GRID ? View.VISIBLE : View.GONE); + mListView.setVisibility(state.mode == MODE_LIST ? View.VISIBLE : View.GONE); + mGridView.setVisibility(state.mode == MODE_GRID ? View.VISIBLE : View.GONE); final int choiceMode; if (state.allowMultiple) { @@ -217,7 +261,9 @@ public class DirectoryFragment extends Fragment { choiceMode = ListView.CHOICE_MODE_NONE; } - if (state.mode == DisplayState.MODE_GRID) { + final int thumbSize; + if (state.mode == MODE_GRID) { + thumbSize = getResources().getDimensionPixelSize(R.dimen.grid_width); mListView.setAdapter(null); mListView.setChoiceMode(ListView.CHOICE_MODE_NONE); mGridView.setAdapter(mAdapter); @@ -225,7 +271,8 @@ public class DirectoryFragment extends Fragment { mGridView.setNumColumns(GridView.AUTO_FIT); mGridView.setChoiceMode(choiceMode); mCurrentView = mGridView; - } else if (state.mode == DisplayState.MODE_LIST) { + } else if (state.mode == MODE_LIST) { + thumbSize = getResources().getDimensionPixelSize(android.R.dimen.app_icon_size); mGridView.setAdapter(null); mGridView.setChoiceMode(ListView.CHOICE_MODE_NONE); mListView.setAdapter(mAdapter); @@ -234,13 +281,17 @@ public class DirectoryFragment extends Fragment { } else { throw new IllegalStateException(); } + + mThumbSize = new Point(thumbSize, thumbSize); } private OnItemClickListener mItemListener = new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { final Document doc = mAdapter.getItem(position); - ((DocumentsActivity) getActivity()).onDocumentPicked(doc); + if (mFilter.apply(doc)) { + ((DocumentsActivity) getActivity()).onDocumentPicked(doc); + } } }; @@ -253,26 +304,45 @@ public class DirectoryFragment extends Fragment { @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + final DisplayState state = getDisplayState(DirectoryFragment.this); + + final MenuItem open = menu.findItem(R.id.menu_open); + final MenuItem share = menu.findItem(R.id.menu_share); + final MenuItem delete = menu.findItem(R.id.menu_delete); + + final boolean manageMode = state.action == ACTION_MANAGE; + open.setVisible(!manageMode); + share.setVisible(manageMode); + delete.setVisible(manageMode); + return true; } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { - if (item.getItemId() == R.id.menu_open) { - final Uri uri = getArguments().getParcelable(EXTRA_URI); - final SparseBooleanArray checked = mCurrentView.getCheckedItemPositions(); - final ArrayList<Document> docs = Lists.newArrayList(); - - final int size = checked.size(); - for (int i = 0; i < size; i++) { - if (checked.valueAt(i)) { - final Document doc = mAdapter.getItem(checked.keyAt(i)); - docs.add(doc); - } + final SparseBooleanArray checked = mCurrentView.getCheckedItemPositions(); + final ArrayList<Document> docs = Lists.newArrayList(); + final int size = checked.size(); + for (int i = 0; i < size; i++) { + if (checked.valueAt(i)) { + final Document doc = mAdapter.getItem(checked.keyAt(i)); + docs.add(doc); } + } - ((DocumentsActivity) getActivity()).onDocumentsPicked(docs); + final int id = item.getItemId(); + if (id == R.id.menu_open) { + DocumentsActivity.get(DirectoryFragment.this).onDocumentsPicked(docs); return true; + + } else if (id == R.id.menu_share) { + onShareDocuments(docs); + return true; + + } else if (id == R.id.menu_delete) { + onDeleteDocuments(docs); + return true; + } else { return false; } @@ -299,6 +369,58 @@ public class DirectoryFragment extends Fragment { } }; + private void onShareDocuments(List<Document> docs) { + final ArrayList<Uri> uris = Lists.newArrayList(); + for (Document doc : docs) { + uris.add(doc.uri); + } + + final Intent intent; + if (uris.size() > 1) { + intent = new Intent(Intent.ACTION_SEND_MULTIPLE); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.addCategory(Intent.CATEGORY_DEFAULT); + // TODO: find common mimetype + intent.setType("*/*"); + intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris); + } else { + intent = new Intent(Intent.ACTION_SEND); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.addCategory(Intent.CATEGORY_DEFAULT); + intent.setData(uris.get(0)); + } + + startActivity(intent); + } + + private void onDeleteDocuments(List<Document> docs) { + final Context context = getActivity(); + final ContentResolver resolver = context.getContentResolver(); + + boolean hadTrouble = false; + for (Document doc : docs) { + if (!doc.isDeleteSupported()) { + Log.w(TAG, "Skipping " + doc); + hadTrouble = true; + continue; + } + + try { + if (resolver.delete(doc.uri, null, null) != 1) { + Log.w(TAG, "Failed to delete " + doc); + hadTrouble = true; + } + } catch (Exception e) { + Log.w(TAG, "Failed to delete " + doc + ": " + e); + hadTrouble = true; + } + } + + if (hadTrouble) { + Toast.makeText(context, R.string.toast_failed_delete, Toast.LENGTH_SHORT).show(); + } + } + private static DisplayState getDisplayState(Fragment fragment) { return ((DocumentsActivity) fragment.getActivity()).getDisplayState(); } @@ -312,7 +434,7 @@ public class DirectoryFragment extends Fragment { public void swapDocuments(List<Document> documents) { mDocuments = documents; - if (documents != null && documents.isEmpty()) { + if (mDocuments != null && mDocuments.isEmpty()) { mEmptyView.setVisibility(View.VISIBLE); } else { mEmptyView.setVisibility(View.GONE); @@ -326,11 +448,15 @@ public class DirectoryFragment extends Fragment { final Context context = parent.getContext(); final DisplayState state = getDisplayState(DirectoryFragment.this); + final RootsCache roots = DocumentsApplication.getRootsCache(context); + final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache( + context, mThumbSize); + if (convertView == null) { final LayoutInflater inflater = LayoutInflater.from(context); - if (state.mode == DisplayState.MODE_LIST) { + if (state.mode == MODE_LIST) { convertView = inflater.inflate(R.layout.item_doc_list, parent, false); - } else if (state.mode == DisplayState.MODE_GRID) { + } else if (state.mode == MODE_GRID) { convertView = inflater.inflate(R.layout.item_doc_grid, parent, false); } else { throw new IllegalStateException(); @@ -347,11 +473,23 @@ public class DirectoryFragment extends Fragment { final TextView date = (TextView) convertView.findViewById(R.id.date); final TextView size = (TextView) convertView.findViewById(R.id.size); + final ThumbnailAsyncTask oldTask = (ThumbnailAsyncTask) icon.getTag(); + if (oldTask != null) { + oldTask.cancel(false); + } + if (doc.isThumbnailSupported()) { - // TODO: load thumbnails async - icon.setImageURI(doc.uri); + final Bitmap cachedResult = thumbs.get(doc.uri); + if (cachedResult != null) { + icon.setImageBitmap(cachedResult); + } else { + final ThumbnailAsyncTask task = new ThumbnailAsyncTask(icon, mThumbSize); + icon.setImageBitmap(null); + icon.setTag(task); + task.execute(doc.uri); + } } else { - icon.setImageDrawable(RootsCache.resolveDocumentIcon( + icon.setImageDrawable(roots.resolveDocumentIcon( context, doc.uri.getAuthority(), doc.mimeType)); } @@ -366,7 +504,7 @@ public class DirectoryFragment extends Fragment { summary.setVisibility(View.INVISIBLE); } } else if (mType == TYPE_RECENT_OPEN) { - final Root root = RootsCache.findRoot(context, doc); + final Root root = roots.findRoot(doc); icon1.setVisibility(View.VISIBLE); icon1.setImageDrawable(root.icon); summary.setText(root.getDirectoryString()); @@ -378,14 +516,15 @@ public class DirectoryFragment extends Fragment { (summary.getVisibility() == View.VISIBLE) ? View.VISIBLE : View.GONE); } - // TODO: omit year from format - date.setText(DateUtils.formatSameDayTime( - doc.lastModified, System.currentTimeMillis(), DateFormat.SHORT, - DateFormat.SHORT)); + if (doc.lastModified == -1) { + date.setText(null); + } else { + date.setText(formatTime(context, doc.lastModified)); + } if (state.showSize) { size.setVisibility(View.VISIBLE); - if (doc.isDirectory()) { + if (doc.isDirectory() || doc.size == -1) { size.setText(null); } else { size.setText(Formatter.formatFileSize(context, doc.size)); @@ -411,16 +550,69 @@ public class DirectoryFragment extends Fragment { public long getItemId(int position) { return getItem(position).uri.hashCode(); } + } + + private static class ThumbnailAsyncTask extends AsyncTask<Uri, Void, Bitmap> { + private final ImageView mTarget; + private final Point mThumbSize; + + public ThumbnailAsyncTask(ImageView target, Point thumbSize) { + mTarget = target; + mThumbSize = thumbSize; + } @Override - public boolean areAllItemsEnabled() { - return false; + protected void onPreExecute() { + mTarget.setTag(this); } @Override - public boolean isEnabled(int position) { - final Document doc = getItem(position); - return mFilter.apply(doc); + protected Bitmap doInBackground(Uri... params) { + final Context context = mTarget.getContext(); + final Uri uri = params[0]; + + Bitmap result = null; + try { + result = DocumentsContract.getThumbnail( + context.getContentResolver(), uri, mThumbSize); + if (result != null) { + final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache( + context, mThumbSize); + thumbs.put(uri, result); + } + } catch (Exception e) { + Log.w(TAG, "Failed to load thumbnail: " + e); + } + return result; + } + + @Override + protected void onPostExecute(Bitmap result) { + if (mTarget.getTag() == this) { + mTarget.setImageBitmap(result); + mTarget.setTag(null); + } + } + } + + private static String formatTime(Context context, long when) { + // TODO: DateUtils should make this easier + Time then = new Time(); + then.set(when); + Time now = new Time(); + now.setToNow(); + + int flags = DateUtils.FORMAT_NO_NOON | DateUtils.FORMAT_NO_MIDNIGHT + | DateUtils.FORMAT_ABBREV_ALL; + + if (then.year != now.year) { + flags |= DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_DATE; + } else if (then.yearDay != now.yearDay) { + flags |= DateUtils.FORMAT_SHOW_DATE; + } else { + flags |= DateUtils.FORMAT_SHOW_TIME; } + + return DateUtils.formatDateTime(context, when, flags); } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java index 94c2b61..14d6fd5 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java @@ -26,6 +26,7 @@ import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.os.CancellationSignal; +import android.provider.DocumentsContract.DocumentColumns; import android.util.Log; import com.android.documentsui.model.Document; @@ -35,12 +36,22 @@ import com.google.android.collect.Lists; import libcore.io.IoUtils; import java.io.FileNotFoundException; -import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; -public class DirectoryLoader extends UriDerivativeLoader<List<Document>> { +class DirectoryResult implements AutoCloseable { + Cursor cursor; + List<Document> contents = Lists.newArrayList(); + Exception e; + + @Override + public void close() throws Exception { + IoUtils.closeQuietly(cursor); + } +} + +public class DirectoryLoader extends UriDerivativeLoader<Uri, DirectoryResult> { private final int mType; private Predicate<Document> mFilter; @@ -55,43 +66,60 @@ public class DirectoryLoader extends UriDerivativeLoader<List<Document>> { } @Override - public List<Document> loadInBackground(Uri uri, CancellationSignal signal) { - final ArrayList<Document> result = Lists.newArrayList(); + public DirectoryResult loadInBackground(Uri uri, CancellationSignal signal) { + final DirectoryResult result = new DirectoryResult(); + try { + loadInBackgroundInternal(result, uri, signal); + } catch (Exception e) { + result.e = e; + } + return result; + } - // TODO: send selection and sorting hints to backend + private void loadInBackgroundInternal( + DirectoryResult result, Uri uri, CancellationSignal signal) { final ContentResolver resolver = getContext().getContentResolver(); - final Cursor cursor = resolver.query(uri, null, null, null, null, signal); - try { - while (cursor != null && cursor.moveToNext()) { - Document doc = null; - switch (mType) { - case TYPE_NORMAL: - case TYPE_SEARCH: - doc = Document.fromDirectoryCursor(uri, cursor); - break; - case TYPE_RECENT_OPEN: - try { - doc = Document.fromRecentOpenCursor(resolver, cursor); - } catch (FileNotFoundException e) { - Log.w(TAG, "Failed to find recent: " + e); - } - break; - default: - throw new IllegalArgumentException("Unknown type"); - } - - if (doc != null && (mFilter == null || mFilter.apply(doc))) { - result.add(doc); - } + final Cursor cursor = resolver.query(uri, null, null, null, getQuerySortOrder(), signal); + result.cursor = cursor; + result.cursor.registerContentObserver(mObserver); + + while (cursor.moveToNext()) { + Document doc = null; + switch (mType) { + case TYPE_NORMAL: + case TYPE_SEARCH: + doc = Document.fromDirectoryCursor(uri, cursor); + break; + case TYPE_RECENT_OPEN: + try { + doc = Document.fromRecentOpenCursor(resolver, cursor); + } catch (FileNotFoundException e) { + Log.w(TAG, "Failed to find recent: " + e); + } + break; + default: + throw new IllegalArgumentException("Unknown type"); + } + + if (doc != null && (mFilter == null || mFilter.apply(doc))) { + result.contents.add(doc); } - } finally { - IoUtils.closeQuietly(cursor); } if (mSortOrder != null) { - Collections.sort(result, mSortOrder); + Collections.sort(result.contents, mSortOrder); } + } - return result; + private String getQuerySortOrder() { + if (mSortOrder instanceof Document.DateComparator) { + return DocumentColumns.LAST_MODIFIED + " DESC"; + } else if (mSortOrder instanceof Document.NameComparator) { + return DocumentColumns.DISPLAY_NAME + " ASC"; + } else if (mSortOrder instanceof Document.SizeComparator) { + return DocumentColumns.SIZE + " DESC"; + } else { + return null; + } } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentChangedReceiver.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentChangedReceiver.java new file mode 100644 index 0000000..72afd9e --- /dev/null +++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentChangedReceiver.java @@ -0,0 +1,38 @@ +/* + * 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 static com.android.documentsui.DocumentsActivity.TAG; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +import com.android.documentsui.model.Root; + +/** + * Handles {@link Root} changes which invalidate cached data. + */ +public class DocumentChangedReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + Log.d(TAG, "Regenerating roots cache"); + DocumentsApplication.getRootsCache(context).update(); + // TODO: invalidate cached data in recents provider + } +} diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java index a536acb..091737d 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java @@ -16,19 +16,31 @@ package com.android.documentsui; +import static com.android.documentsui.DocumentsActivity.DisplayState.ACTION_CREATE; +import static com.android.documentsui.DocumentsActivity.DisplayState.ACTION_GET_CONTENT; +import static com.android.documentsui.DocumentsActivity.DisplayState.ACTION_MANAGE; +import static com.android.documentsui.DocumentsActivity.DisplayState.ACTION_OPEN; +import static com.android.documentsui.DocumentsActivity.DisplayState.MODE_GRID; +import static com.android.documentsui.DocumentsActivity.DisplayState.MODE_LIST; +import static com.android.documentsui.DocumentsActivity.DisplayState.SORT_ORDER_DATE; + import android.app.ActionBar; import android.app.ActionBar.OnNavigationListener; import android.app.Activity; import android.app.Fragment; import android.app.FragmentManager; +import android.content.ActivityNotFoundException; import android.content.ClipData; +import android.content.ComponentName; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Intent; +import android.content.pm.ResolveInfo; import android.database.Cursor; import android.graphics.drawable.ColorDrawable; import android.net.Uri; import android.os.Bundle; +import android.provider.DocumentsContract; import android.provider.DocumentsContract.DocumentColumns; import android.support.v4.app.ActionBarDrawerToggle; import android.support.v4.view.GravityCompat; @@ -58,9 +70,6 @@ import java.util.List; public class DocumentsActivity extends Activity { public static final String TAG = "Documents"; - public static final int ACTION_OPEN = 1; - public static final int ACTION_CREATE = 2; - private int mAction; private SearchView mSearchView; @@ -71,6 +80,8 @@ public class DocumentsActivity extends Activity { private final DisplayState mDisplayState = new DisplayState(); + private RootsCache mRoots; + /** Current user navigation stack; empty implies recents. */ private DocumentStack mStack = new DocumentStack(); /** Currently active search, overriding any stack. */ @@ -80,28 +91,38 @@ public class DocumentsActivity extends Activity { public void onCreate(Bundle icicle) { super.onCreate(icicle); + mRoots = DocumentsApplication.getRootsCache(this); + final Intent intent = getIntent(); final String action = intent.getAction(); if (Intent.ACTION_OPEN_DOCUMENT.equals(action)) { mAction = ACTION_OPEN; - mDisplayState.allowMultiple = intent.getBooleanExtra( - Intent.EXTRA_ALLOW_MULTIPLE, false); } else if (Intent.ACTION_CREATE_DOCUMENT.equals(action)) { mAction = ACTION_CREATE; - mDisplayState.allowMultiple = false; + } else if (Intent.ACTION_GET_CONTENT.equals(action)) { + mAction = ACTION_GET_CONTENT; + } else if (Intent.ACTION_MANAGE_DOCUMENT.equals(action)) { + mAction = ACTION_MANAGE; } - if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) { + // TODO: unify action in single place + mDisplayState.action = mAction; + + if (mAction == ACTION_OPEN || mAction == ACTION_GET_CONTENT) { + mDisplayState.allowMultiple = intent.getBooleanExtra( + Intent.EXTRA_ALLOW_MULTIPLE, false); + } + + if (mAction == ACTION_MANAGE) { + mDisplayState.acceptMimes = new String[] { "*/*" }; + mDisplayState.allowMultiple = true; + } else if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) { mDisplayState.acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES); } else { mDisplayState.acceptMimes = new String[] { intent.getType() }; } - if (MimePredicate.mimeMatches("image/*", mDisplayState.acceptMimes)) { - mDisplayState.mode = DisplayState.MODE_GRID; - } else { - mDisplayState.mode = DisplayState.MODE_LIST; - } + mDisplayState.localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false); setResult(Activity.RESULT_CANCELED); setContentView(R.layout.activity); @@ -112,7 +133,18 @@ public class DocumentsActivity extends Activity { SaveFragment.show(getFragmentManager(), mimeType, title); } - RootsFragment.show(getFragmentManager()); + if (mAction == ACTION_GET_CONTENT) { + final Intent moreApps = new Intent(getIntent()); + moreApps.setComponent(null); + moreApps.setPackage(null); + RootsFragment.show(getFragmentManager(), moreApps); + } else if (mAction == ACTION_OPEN || mAction == ACTION_CREATE) { + RootsFragment.show(getFragmentManager(), null); + } + + if (mAction == ACTION_MANAGE) { + mDisplayState.sortOrder = SORT_ORDER_DATE; + } mRootsContainer = findViewById(R.id.container_roots); @@ -124,26 +156,54 @@ public class DocumentsActivity extends Activity { mDrawerLayout.setDrawerListener(mDrawerListener); mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); - mDrawerLayout.openDrawer(mRootsContainer); + if (mAction == ACTION_MANAGE) { + mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); - // Restore last stack for calling package - // TODO: move into async loader - final String packageName = getCallingPackage(); - final Cursor cursor = getContentResolver() - .query(RecentsProvider.buildResume(packageName), null, null, null, null); - try { - if (cursor.moveToFirst()) { - final String raw = cursor.getString( - cursor.getColumnIndex(RecentsProvider.COL_PATH)); - mStack = DocumentStack.deserialize(getContentResolver(), raw); + final Uri rootUri = intent.getData(); + final String authority = rootUri.getAuthority(); + final String rootId = DocumentsContract.getRootId(rootUri); + + final Root root = mRoots.findRoot(authority, rootId); + if (root != null) { + onRootPicked(root, true); + } else { + Log.w(TAG, "Failed to find root: " + rootUri); + finish(); } - } catch (FileNotFoundException e) { - Log.w(TAG, "Failed to resume", e); - } finally { - cursor.close(); + + } else { + mDrawerLayout.openDrawer(mRootsContainer); + + // Restore last stack for calling package + // TODO: move into async loader + final String packageName = getCallingPackage(); + final Cursor cursor = getContentResolver() + .query(RecentsProvider.buildResume(packageName), null, null, null, null); + try { + if (cursor.moveToFirst()) { + final String raw = cursor.getString( + cursor.getColumnIndex(RecentsProvider.COL_PATH)); + mStack = DocumentStack.deserialize(getContentResolver(), raw); + } + } catch (FileNotFoundException e) { + Log.w(TAG, "Failed to resume", e); + } finally { + cursor.close(); + } + + onCurrentDirectoryChanged(); } + } - onCurrentDirectoryChanged(); + @Override + public void onStart() { + super.onStart(); + + if (mAction == ACTION_MANAGE) { + mDisplayState.showSize = true; + } else { + mDisplayState.showSize = SettingsActivity.getDisplayFileSize(this); + } } private DrawerListener mDrawerListener = new DrawerListener() { @@ -180,18 +240,20 @@ public class DocumentsActivity extends Activity { final ActionBar actionBar = getActionBar(); actionBar.setDisplayShowHomeEnabled(true); - actionBar.setDisplayHomeAsUpEnabled(true); if (mDrawerLayout.isDrawerOpen(mRootsContainer)) { actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); actionBar.setIcon(new ColorDrawable()); - if (mAction == ACTION_OPEN) { + if (mAction == ACTION_OPEN || mAction == ACTION_GET_CONTENT) { actionBar.setTitle(R.string.title_open); } else if (mAction == ACTION_CREATE) { actionBar.setTitle(R.string.title_save); } + actionBar.setDisplayHomeAsUpEnabled(true); + mDrawerToggle.setDrawerIndicatorEnabled(true); + } else { final Root root = getCurrentRoot(); actionBar.setIcon(root != null ? root.icon : null); @@ -207,8 +269,13 @@ public class DocumentsActivity extends Activity { } if (mStack.size() > 1) { + actionBar.setDisplayHomeAsUpEnabled(true); + mDrawerToggle.setDrawerIndicatorEnabled(false); + } else if (mAction == ACTION_MANAGE) { + actionBar.setDisplayHomeAsUpEnabled(false); mDrawerToggle.setDrawerIndicatorEnabled(false); } else { + actionBar.setDisplayHomeAsUpEnabled(true); mDrawerToggle.setDrawerIndicatorEnabled(true); } } @@ -259,9 +326,10 @@ public class DocumentsActivity extends Activity { final MenuItem search = menu.findItem(R.id.menu_search); final MenuItem grid = menu.findItem(R.id.menu_grid); final MenuItem list = menu.findItem(R.id.menu_list); + final MenuItem settings = menu.findItem(R.id.menu_settings); - grid.setVisible(mDisplayState.mode != DisplayState.MODE_GRID); - list.setVisible(mDisplayState.mode != DisplayState.MODE_LIST); + grid.setVisible(mDisplayState.mode != MODE_GRID); + list.setVisible(mDisplayState.mode != MODE_LIST); final boolean searchVisible; if (mAction == ACTION_CREATE) { @@ -283,6 +351,8 @@ public class DocumentsActivity extends Activity { // TODO: close any search in-progress when hiding search.setVisible(searchVisible); + settings.setVisible(mAction != ACTION_MANAGE); + return true; } @@ -302,12 +372,14 @@ public class DocumentsActivity extends Activity { } else if (id == R.id.menu_search) { return false; } else if (id == R.id.menu_grid) { - mDisplayState.mode = DisplayState.MODE_GRID; + // TODO: persist explicit user mode for cwd + mDisplayState.mode = MODE_GRID; updateDisplayState(); invalidateOptionsMenu(); return true; } else if (id == R.id.menu_list) { - mDisplayState.mode = DisplayState.MODE_LIST; + // TODO: persist explicit user mode for cwd + mDisplayState.mode = MODE_LIST; updateDisplayState(); invalidateOptionsMenu(); return true; @@ -408,9 +480,9 @@ public class DocumentsActivity extends Activity { public Root getCurrentRoot() { final Document cwd = getCurrentDirectory(); if (cwd != null) { - return RootsCache.findRoot(this, cwd); + return mRoots.findRoot(cwd); } else { - return RootsCache.getRecentsRoot(this); + return mRoots.getRecentsRoot(); } } @@ -484,27 +556,55 @@ public class DocumentsActivity extends Activity { } } + public void onAppPicked(ResolveInfo info) { + final Intent intent = new Intent(getIntent()); + intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); + intent.setComponent(new ComponentName( + info.activityInfo.applicationInfo.packageName, info.activityInfo.name)); + startActivity(intent); + finish(); + } + public void onDocumentPicked(Document doc) { final FragmentManager fm = getFragmentManager(); if (doc.isDirectory()) { + // TODO: query display mode user preference for this dir + if (doc.isGridPreferred()) { + mDisplayState.mode = MODE_GRID; + } else { + mDisplayState.mode = MODE_LIST; + } mStack.push(doc); onCurrentDirectoryChanged(); - } else if (mAction == ACTION_OPEN) { + } else if (mAction == ACTION_OPEN || mAction == ACTION_GET_CONTENT) { // Explicit file picked, return onFinished(doc.uri); } else if (mAction == ACTION_CREATE) { // Replace selected file SaveFragment.get(fm).setReplaceTarget(doc); + } else if (mAction == ACTION_MANAGE) { + // Open the document + // TODO: trampoline activity for launching downloaded APKs + final Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.setData(doc.uri); + try { + startActivity(intent); + } catch (ActivityNotFoundException ex) { + Toast.makeText(this, R.string.toast_no_application, Toast.LENGTH_SHORT).show(); + } } } public void onDocumentsPicked(List<Document> docs) { - final int size = docs.size(); - final Uri[] uris = new Uri[size]; - for (int i = 0; i < size; i++) { - uris[i] = docs.get(i).uri; + if (mAction == ACTION_OPEN || mAction == ACTION_GET_CONTENT) { + final int size = docs.size(); + final Uri[] uris = new Uri[size]; + for (int i = 0; i < size; i++) { + uris[i] = docs.get(i).uri; + } + onFinished(uris); } - onFinished(uris); } public void onSaveRequested(Document replaceTarget) { @@ -538,7 +638,7 @@ public class DocumentsActivity extends Activity { values.put(RecentsProvider.COL_PATH, rawStack); resolver.insert(RecentsProvider.buildRecentCreate(), values); - } else if (mAction == ACTION_OPEN) { + } else if (mAction == ACTION_OPEN || mAction == ACTION_GET_CONTENT) { // Remember opened items for (Uri uri : uris) { values.clear(); @@ -565,21 +665,31 @@ public class DocumentsActivity extends Activity { intent.setClipData(clipData); } - // TODO: omit WRITE and PERSIST for GET_CONTENT - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION - | Intent.FLAG_GRANT_WRITE_URI_PERMISSION - | Intent.FLAG_PERSIST_GRANT_URI_PERMISSION); + if (mAction == ACTION_GET_CONTENT) { + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + } else { + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION + | Intent.FLAG_GRANT_WRITE_URI_PERMISSION + | Intent.FLAG_PERSIST_GRANT_URI_PERMISSION); + } setResult(Activity.RESULT_OK, intent); finish(); } public static class DisplayState { + public int action; public int mode = MODE_LIST; public String[] acceptMimes; public int sortOrder = SORT_ORDER_NAME; public boolean allowMultiple = false; public boolean showSize = false; + public boolean localOnly = false; + + public static final int ACTION_OPEN = 1; + public static final int ACTION_CREATE = 2; + public static final int ACTION_GET_CONTENT = 3; + public static final int ACTION_MANAGE = 4; public static final int MODE_LIST = 0; public static final int MODE_GRID = 1; diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java new file mode 100644 index 0000000..0a6cbc0 --- /dev/null +++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java @@ -0,0 +1,80 @@ +/* + * 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.ActivityManager; +import android.app.Application; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.graphics.Point; + +public class DocumentsApplication extends Application { + private RootsCache mRoots; + private Point mThumbnailsSize; + private ThumbnailCache mThumbnails; + + public static RootsCache getRootsCache(Context context) { + return ((DocumentsApplication) context.getApplicationContext()).mRoots; + } + + public static ThumbnailCache getThumbnailsCache(Context context, Point size) { + final DocumentsApplication app = (DocumentsApplication) context.getApplicationContext(); + final ThumbnailCache thumbnails = app.mThumbnails; + if (!size.equals(app.mThumbnailsSize)) { + thumbnails.evictAll(); + app.mThumbnailsSize = size; + } + return thumbnails; + } + + @Override + public void onCreate() { + final ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); + final int memoryClassBytes = am.getMemoryClass() * 1024 * 1024; + + mRoots = new RootsCache(this); + mThumbnails = new ThumbnailCache(memoryClassBytes / 4); + + final IntentFilter packageFilter = new IntentFilter(); + packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED); + packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); + packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); + packageFilter.addDataScheme("package"); + registerReceiver(mPackageReceiver, packageFilter); + } + + @Override + public void onTrimMemory(int level) { + super.onTrimMemory(level); + + if (level >= TRIM_MEMORY_MODERATE) { + mThumbnails.evictAll(); + } else if (level >= TRIM_MEMORY_BACKGROUND) { + mThumbnails.trimToSize(mThumbnails.size() / 2); + } + } + + private BroadcastReceiver mPackageReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + // TODO: narrow changed/removed to only packages that have backends + mRoots.update(); + } + }; +} diff --git a/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java index f945c6a0..a9929de 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java +++ b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java @@ -49,7 +49,9 @@ public class MimePredicate implements Predicate<Document> { } public static boolean mimeMatches(String filter, String test) { - if (filter.equals(test)) { + if (test == null) { + return false; + } else if (filter.equals(test)) { return true; } else if ("*/*".equals(filter)) { return true; diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java index 5cdc915..5466dbf 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java @@ -124,7 +124,7 @@ public class RecentsCreateFragment extends Fragment { } }; - public static class RecentsCreateLoader extends UriDerivativeLoader<List<DocumentStack>> { + public static class RecentsCreateLoader extends UriDerivativeLoader<Uri, List<DocumentStack>> { public RecentsCreateLoader(Context context) { super(context, RecentsProvider.buildRecentCreate()); } @@ -169,6 +169,7 @@ public class RecentsCreateFragment extends Fragment { @Override public View getView(int position, View convertView, ViewGroup parent) { final Context context = parent.getContext(); + final RootsCache roots = DocumentsApplication.getRootsCache(context); if (convertView == null) { final LayoutInflater inflater = LayoutInflater.from(context); @@ -180,7 +181,7 @@ public class RecentsCreateFragment extends Fragment { final View summaryList = convertView.findViewById(R.id.summary_list); final DocumentStack stack = getItem(position); - final Root root = RootsCache.findRoot(context, stack.peek()); + final Root root = roots.findRoot(stack.peek()); icon.setImageDrawable(root != null ? root.icon : null); final StringBuilder builder = new StringBuilder(); diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java index 5268c1d..dbcb039 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java @@ -129,11 +129,11 @@ public class RecentsProvider extends ContentProvider { switch (sMatcher.match(uri)) { case URI_RECENT_OPEN: { return db.query(TABLE_RECENT_OPEN, projection, - buildWhereYounger(DateUtils.WEEK_IN_MILLIS), null, null, null, sortOrder); + buildWhereYounger(DateUtils.WEEK_IN_MILLIS), null, null, null, null); } case URI_RECENT_CREATE: { return db.query(TABLE_RECENT_CREATE, projection, - buildWhereYounger(DateUtils.WEEK_IN_MILLIS), null, null, null, sortOrder); + buildWhereYounger(DateUtils.WEEK_IN_MILLIS), null, null, null, null); } case URI_RESUME: { final String packageName = uri.getPathSegments().get(1); diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java index b26db3b..c3b498e 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java @@ -27,6 +27,7 @@ import android.database.Cursor; import android.graphics.drawable.Drawable; import android.net.Uri; import android.provider.DocumentsContract; +import android.provider.DocumentsContract.Documents; import android.util.Log; import android.util.Pair; @@ -49,106 +50,110 @@ import java.util.List; public class RootsCache { // TODO: cache roots in local provider to avoid spinning up backends + // TODO: root updates should trigger UI refresh - private static boolean sCached = false; + private final Context mContext; /** Map from authority to cached info */ - private static HashMap<String, DocumentsProviderInfo> sProviders = Maps.newHashMap(); + private HashMap<String, DocumentsProviderInfo> mProviders = Maps.newHashMap(); /** Map from (authority+rootId) to cached info */ - private static HashMap<Pair<String, String>, Root> sRoots = Maps.newHashMap(); + private HashMap<Pair<String, String>, Root> mRoots = Maps.newHashMap(); - public static ArrayList<Root> sRootsList = Lists.newArrayList(); + public ArrayList<Root> mRootsList = Lists.newArrayList(); - private static Root sRecentsRoot; + private Root mRecentsRoot; + + public RootsCache(Context context) { + mContext = context; + update(); + } /** * Gather roots from all known storage providers. */ - private static void ensureCache(Context context) { - if (sCached) return; - sCached = true; - - sProviders.clear(); - sRoots.clear(); - sRootsList.clear(); + @GuardedBy("ActivityThread") + public void update() { + mProviders.clear(); + mRoots.clear(); + mRootsList.clear(); { // Create special root for recents - final Root root = Root.buildRecents(context); - sRootsList.add(root); - sRecentsRoot = root; + final Root root = Root.buildRecents(mContext); + mRootsList.add(root); + mRecentsRoot = root; } // Query for other storage backends - final PackageManager pm = context.getPackageManager(); + final PackageManager pm = mContext.getPackageManager(); final List<ProviderInfo> providers = pm.queryContentProviders( null, -1, PackageManager.GET_META_DATA); for (ProviderInfo providerInfo : providers) { if (providerInfo.metaData != null && providerInfo.metaData.containsKey( DocumentsContract.META_DATA_DOCUMENT_PROVIDER)) { final DocumentsProviderInfo info = DocumentsProviderInfo.parseInfo( - context, providerInfo); + mContext, providerInfo); if (info == null) { Log.w(TAG, "Missing info for " + providerInfo); continue; } - sProviders.put(info.providerInfo.authority, info); + mProviders.put(info.providerInfo.authority, info); - // TODO: remove deprecated customRoots flag - // TODO: populate roots on background thread, and cache results - final Uri uri = DocumentsContract.buildRootsUri(providerInfo.authority); - final Cursor cursor = context.getContentResolver() - .query(uri, null, null, null, null); try { - while (cursor.moveToNext()) { - final Root root = Root.fromCursor(context, info, cursor); - sRoots.put(Pair.create(info.providerInfo.authority, root.rootId), root); - sRootsList.add(root); + // TODO: remove deprecated customRoots flag + // TODO: populate roots on background thread, and cache results + final Uri uri = DocumentsContract.buildRootsUri(providerInfo.authority); + final Cursor cursor = mContext.getContentResolver() + .query(uri, null, null, null, null); + try { + while (cursor.moveToNext()) { + final Root root = Root.fromCursor(mContext, info, cursor); + mRoots.put(Pair.create(info.providerInfo.authority, root.rootId), root); + mRootsList.add(root); + } + } finally { + cursor.close(); } - } finally { - cursor.close(); + } catch (Exception e) { + Log.w(TAG, "Failed to load some roots from " + info.providerInfo.authority + + ": " + e); } } } } @GuardedBy("ActivityThread") - public static DocumentsProviderInfo findProvider(Context context, String authority) { - ensureCache(context); - return sProviders.get(authority); + public DocumentsProviderInfo findProvider(String authority) { + return mProviders.get(authority); } @GuardedBy("ActivityThread") - public static Root findRoot(Context context, String authority, String rootId) { - ensureCache(context); - return sRoots.get(Pair.create(authority, rootId)); + public Root findRoot(String authority, String rootId) { + return mRoots.get(Pair.create(authority, rootId)); } @GuardedBy("ActivityThread") - public static Root findRoot(Context context, Document doc) { + public Root findRoot(Document doc) { final String authority = doc.uri.getAuthority(); final String rootId = DocumentsContract.getRootId(doc.uri); - return findRoot(context, authority, rootId); + return findRoot(authority, rootId); } @GuardedBy("ActivityThread") - public static Root getRecentsRoot(Context context) { - ensureCache(context); - return sRecentsRoot; + public Root getRecentsRoot() { + return mRecentsRoot; } @GuardedBy("ActivityThread") - public static Collection<Root> getRoots(Context context) { - ensureCache(context); - return sRootsList; + public Collection<Root> getRoots() { + return mRootsList; } @GuardedBy("ActivityThread") - public static Drawable resolveDocumentIcon(Context context, String authority, String mimeType) { + public Drawable resolveDocumentIcon(Context context, String authority, String mimeType) { // Custom icons take precedence - ensureCache(context); - final DocumentsProviderInfo info = sProviders.get(authority); + final DocumentsProviderInfo info = mProviders.get(authority); if (info != null) { for (Icon icon : info.customIcons) { if (MimePredicate.mimeMatches(icon.mimeType, mimeType)) { @@ -157,7 +162,7 @@ public class RootsCache { } } - if (DocumentsContract.MIME_TYPE_DIRECTORY.equals(mimeType)) { + if (Documents.MIME_TYPE_DIR.equals(mimeType)) { return context.getResources().getDrawable(R.drawable.ic_dir); } else { final PackageManager pm = context.getPackageManager(); diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java index 427ad42..8a48e2a 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java @@ -22,8 +22,11 @@ import android.app.Fragment; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.os.Bundle; -import android.provider.DocumentsContract; +import android.provider.DocumentsContract.Roots; import android.text.format.Formatter; import android.util.Log; import android.view.LayoutInflater; @@ -41,6 +44,7 @@ import com.android.documentsui.model.Root; import com.android.documentsui.model.Root.RootComparator; import java.util.Collection; +import java.util.List; /** * Display list of known storage backend roots. @@ -50,8 +54,14 @@ public class RootsFragment extends Fragment { private ListView mList; private SectionedRootsAdapter mAdapter; - public static void show(FragmentManager fm) { + private static final String EXTRA_INCLUDE_APPS = "includeApps"; + + public static void show(FragmentManager fm, Intent includeApps) { + final Bundle args = new Bundle(); + args.putParcelable(EXTRA_INCLUDE_APPS, includeApps); + final RootsFragment fragment = new RootsFragment(); + fragment.setArguments(args); final FragmentTransaction ft = fm.beginTransaction(); ft.replace(R.id.container_roots, fragment); @@ -66,14 +76,15 @@ public class RootsFragment extends Fragment { public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final Context context = inflater.getContext(); + final RootsCache roots = DocumentsApplication.getRootsCache(context); final View view = inflater.inflate(R.layout.fragment_roots, container, false); mList = (ListView) view.findViewById(android.R.id.list); - - mAdapter = new SectionedRootsAdapter(context, RootsCache.getRoots(context)); - mList.setAdapter(mAdapter); mList.setOnItemClickListener(mItemListener); + final Intent includeApps = getArguments().getParcelable(EXTRA_INCLUDE_APPS); + mAdapter = new SectionedRootsAdapter(context, roots.getRoots(), includeApps); + return view; } @@ -82,18 +93,26 @@ public class RootsFragment extends Fragment { super.onStart(); final Context context = getActivity(); - mAdapter.setShowAdvanced(SettingsActivity.getDisplayAdvancedDevices(context)); + mAdapter.updateVisible(SettingsActivity.getDisplayAdvancedDevices(context)); + mList.setAdapter(mAdapter); } private OnItemClickListener mItemListener = new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - final Root root = (Root) mAdapter.getItem(position); - ((DocumentsActivity) getActivity()).onRootPicked(root, true); + final DocumentsActivity activity = DocumentsActivity.get(RootsFragment.this); + final Object item = mAdapter.getItem(position); + if (item instanceof Root) { + activity.onRootPicked((Root) item, true); + } else if (item instanceof ResolveInfo) { + activity.onAppPicked((ResolveInfo) item); + } else { + throw new IllegalStateException("Unknown root: " + item); + } } }; - public static class RootsAdapter extends ArrayAdapter<Root> implements SectionAdapter { + private static class RootsAdapter extends ArrayAdapter<Root> implements SectionAdapter { private int mHeaderId; public RootsAdapter(Context context, int headerId) { @@ -119,8 +138,8 @@ public class RootsFragment extends Fragment { // Device summary is always available space final String summaryText; - if ((root.rootType == DocumentsContract.ROOT_TYPE_DEVICE - || root.rootType == DocumentsContract.ROOT_TYPE_DEVICE_ADVANCED) + if ((root.rootType == Roots.ROOT_TYPE_DEVICE + || root.rootType == Roots.ROOT_TYPE_DEVICE_ADVANCED) && root.availableBytes >= 0) { summaryText = context.getString(R.string.root_available_bytes, Formatter.formatFileSize(context, root.availableBytes)); @@ -148,37 +167,94 @@ public class RootsFragment extends Fragment { } } - public static class SectionedRootsAdapter extends SectionedListAdapter { + private static class AppsAdapter extends ArrayAdapter<ResolveInfo> implements SectionAdapter { + public AppsAdapter(Context context) { + super(context, 0); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + final Context context = parent.getContext(); + final PackageManager pm = context.getPackageManager(); + if (convertView == null) { + convertView = LayoutInflater.from(context) + .inflate(R.layout.item_root, parent, false); + } + + final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon); + final TextView title = (TextView) convertView.findViewById(android.R.id.title); + final TextView summary = (TextView) convertView.findViewById(android.R.id.summary); + + final ResolveInfo info = getItem(position); + icon.setImageDrawable(info.loadIcon(pm)); + title.setText(info.loadLabel(pm)); + + // TODO: match existing summary behavior from disambig dialog + summary.setVisibility(View.GONE); + + return convertView; + } + + @Override + public View getHeaderView(View convertView, ViewGroup parent) { + if (convertView == null) { + convertView = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.item_root_header, parent, false); + } + + final TextView title = (TextView) convertView.findViewById(android.R.id.title); + title.setText(R.string.root_type_apps); + + return convertView; + } + } + + private static class SectionedRootsAdapter extends SectionedListAdapter { private final RootsAdapter mServices; private final RootsAdapter mShortcuts; private final RootsAdapter mDevices; private final RootsAdapter mDevicesAdvanced; + private final AppsAdapter mApps; - public SectionedRootsAdapter(Context context, Collection<Root> roots) { + public SectionedRootsAdapter(Context context, Collection<Root> roots, Intent includeApps) { mServices = new RootsAdapter(context, R.string.root_type_service); mShortcuts = new RootsAdapter(context, R.string.root_type_shortcut); mDevices = new RootsAdapter(context, R.string.root_type_device); mDevicesAdvanced = new RootsAdapter(context, R.string.root_type_device); + mApps = new AppsAdapter(context); for (Root root : roots) { Log.d(TAG, "Found rootType=" + root.rootType); switch (root.rootType) { - case DocumentsContract.ROOT_TYPE_SERVICE: + case Roots.ROOT_TYPE_SERVICE: mServices.add(root); break; - case DocumentsContract.ROOT_TYPE_SHORTCUT: + case Roots.ROOT_TYPE_SHORTCUT: mShortcuts.add(root); break; - case DocumentsContract.ROOT_TYPE_DEVICE: + case Roots.ROOT_TYPE_DEVICE: mDevices.add(root); mDevicesAdvanced.add(root); break; - case DocumentsContract.ROOT_TYPE_DEVICE_ADVANCED: + case Roots.ROOT_TYPE_DEVICE_ADVANCED: mDevicesAdvanced.add(root); break; } } + if (includeApps != null) { + final PackageManager pm = context.getPackageManager(); + final List<ResolveInfo> infos = pm.queryIntentActivities( + includeApps, PackageManager.MATCH_DEFAULT_ONLY); + + // Omit ourselves from the list + for (ResolveInfo info : infos) { + if (!context.getPackageName().equals(info.activityInfo.packageName)) { + mApps.add(info); + } + } + } + final RootComparator comp = new RootComparator(); mServices.sort(comp); mShortcuts.sort(comp); @@ -186,7 +262,7 @@ public class RootsFragment extends Fragment { mDevicesAdvanced.sort(comp); } - public void setShowAdvanced(boolean showAdvanced) { + public void updateVisible(boolean showAdvanced) { clearSections(); if (mServices.getCount() > 0) { addSection(mServices); @@ -199,6 +275,10 @@ public class RootsFragment extends Fragment { if (devices.getCount() > 0) { addSection(devices); } + + if (mApps.getCount() > 0) { + addSection(mApps); + } } } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java index 69010dd..8eb81b8 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java @@ -68,11 +68,12 @@ public class SaveFragment extends Fragment { public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final Context context = inflater.getContext(); + final RootsCache roots = DocumentsApplication.getRootsCache(context); final View view = inflater.inflate(R.layout.fragment_save, container, false); final ImageView icon = (ImageView) view.findViewById(android.R.id.icon); - icon.setImageDrawable(RootsCache.resolveDocumentIcon( + icon.setImageDrawable(roots.resolveDocumentIcon( context, null, getArguments().getString(EXTRA_MIME_TYPE))); mDisplayName = (EditText) view.findViewById(android.R.id.title); diff --git a/packages/DocumentsUI/src/com/android/documentsui/SectionedListAdapter.java b/packages/DocumentsUI/src/com/android/documentsui/SectionedListAdapter.java index aacce65..088e3fa 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/SectionedListAdapter.java +++ b/packages/DocumentsUI/src/com/android/documentsui/SectionedListAdapter.java @@ -18,6 +18,7 @@ package com.android.documentsui; import android.view.View; import android.view.ViewGroup; +import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.ListAdapter; @@ -41,6 +42,11 @@ public class SectionedListAdapter extends BaseAdapter { notifyDataSetChanged(); } + /** + * After mutating sections, you <em>must</em> + * {@link AdapterView#setAdapter(android.widget.Adapter)} to correctly + * recount view types. + */ public void addSection(SectionAdapter adapter) { mSections.add(adapter); notifyDataSetChanged(); @@ -117,7 +123,7 @@ public class SectionedListAdapter extends BaseAdapter { if (position == 0) { return false; } else if (position < sectionSize) { - return section.isEnabled(position); + return section.isEnabled(position - 1); } // Otherwise jump into next section diff --git a/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java b/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java index a086a43..f6548e8 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java @@ -60,6 +60,7 @@ public class TestActivity extends Activity { @Override public void onClick(View v) { Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("*/*"); if (multiple.isChecked()) { intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); @@ -75,6 +76,7 @@ public class TestActivity extends Activity { @Override public void onClick(View v) { Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("image/*"); if (multiple.isChecked()) { intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); @@ -90,6 +92,7 @@ public class TestActivity extends Activity { @Override public void onClick(View v) { Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("*/*"); intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[] { "text/plain", "application/msword" }); @@ -107,6 +110,7 @@ public class TestActivity extends Activity { @Override public void onClick(View v) { Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_TITLE, "foobar.txt"); startActivityForResult(intent, 42); @@ -114,6 +118,22 @@ public class TestActivity extends Activity { }); view.addView(button); + button = new Button(context); + button.setText("GET_CONTENT */*"); + button.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType("*/*"); + if (multiple.isChecked()) { + intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); + } + startActivityForResult(Intent.createChooser(intent, "Kittens!"), 42); + } + }); + view.addView(button); + mResult = new TextView(context); view.addView(mResult); @@ -131,7 +151,7 @@ public class TestActivity extends Activity { is = getContentResolver().openInputStream(uri); final int length = Streams.readFullyNoClose(is).length; Log.d(TAG, "read length=" + length); - } catch (IOException e) { + } catch (Exception e) { Log.w(TAG, "Failed to read " + uri, e); } finally { IoUtils.closeQuietly(is); diff --git a/packages/SystemUI/res/values-sw600dp-port/refs.xml b/packages/DocumentsUI/src/com/android/documentsui/ThumbnailCache.java index 62fb77d..ad7cbf6 100644 --- a/packages/SystemUI/res/values-sw600dp-port/refs.xml +++ b/packages/DocumentsUI/src/com/android/documentsui/ThumbnailCache.java @@ -1,20 +1,32 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - * Copyright (c) 2013, The Android Open Source Project +/* + * 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 + * 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> - <item type="string" name="hiding_navigation_confirmation_message">@string/hiding_navigation_confirmation_message_long</item> -</resources> + */ + +package com.android.documentsui; + +import android.graphics.Bitmap; +import android.net.Uri; +import android.util.LruCache; + +public class ThumbnailCache extends LruCache<Uri, Bitmap> { + public ThumbnailCache(int maxSizeBytes) { + super(maxSizeBytes); + } + + @Override + protected int sizeOf(Uri key, Bitmap value) { + return value.getByteCount(); + } +} diff --git a/packages/DocumentsUI/src/com/android/documentsui/UriDerivativeLoader.java b/packages/DocumentsUI/src/com/android/documentsui/UriDerivativeLoader.java index 1b88af4..1a5bb0c 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/UriDerivativeLoader.java +++ b/packages/DocumentsUI/src/com/android/documentsui/UriDerivativeLoader.java @@ -19,7 +19,6 @@ package com.android.documentsui; import android.content.AsyncTaskLoader; import android.content.Context; import android.database.ContentObserver; -import android.net.Uri; import android.os.CancellationSignal; import android.os.OperationCanceledException; @@ -28,17 +27,16 @@ import android.os.OperationCanceledException; * changes while started, manages {@link CancellationSignal}, and caches * returned results. */ -public abstract class UriDerivativeLoader<T> extends AsyncTaskLoader<T> { - private final ForceLoadContentObserver mObserver; - private boolean mObserving; +public abstract class UriDerivativeLoader<P, R> extends AsyncTaskLoader<R> { + final ForceLoadContentObserver mObserver; - private final Uri mUri; + private final P mParam; - private T mResult; + private R mResult; private CancellationSignal mCancellationSignal; @Override - public final T loadInBackground() { + public final R loadInBackground() { synchronized (this) { if (isLoadInBackgroundCanceled()) { throw new OperationCanceledException(); @@ -46,7 +44,7 @@ public abstract class UriDerivativeLoader<T> extends AsyncTaskLoader<T> { mCancellationSignal = new CancellationSignal(); } try { - return loadInBackground(mUri, mCancellationSignal); + return loadInBackground(mParam, mCancellationSignal); } finally { synchronized (this) { mCancellationSignal = null; @@ -54,7 +52,7 @@ public abstract class UriDerivativeLoader<T> extends AsyncTaskLoader<T> { } } - public abstract T loadInBackground(Uri uri, CancellationSignal signal); + public abstract R loadInBackground(P param, CancellationSignal signal); @Override public void cancelLoadInBackground() { @@ -68,12 +66,12 @@ public abstract class UriDerivativeLoader<T> extends AsyncTaskLoader<T> { } @Override - public void deliverResult(T result) { + public void deliverResult(R result) { if (isReset()) { closeQuietly(result); return; } - T oldResult = mResult; + R oldResult = mResult; mResult = result; if (isStarted()) { @@ -85,18 +83,14 @@ public abstract class UriDerivativeLoader<T> extends AsyncTaskLoader<T> { } } - public UriDerivativeLoader(Context context, Uri uri) { + public UriDerivativeLoader(Context context, P param) { super(context); mObserver = new ForceLoadContentObserver(); - mUri = uri; + mParam = param; } @Override protected void onStartLoading() { - if (!mObserving) { - getContext().getContentResolver().registerContentObserver(mUri, false, mObserver); - mObserving = true; - } if (mResult != null) { deliverResult(mResult); } @@ -111,7 +105,7 @@ public abstract class UriDerivativeLoader<T> extends AsyncTaskLoader<T> { } @Override - public void onCanceled(T result) { + public void onCanceled(R result) { closeQuietly(result); } @@ -125,13 +119,10 @@ public abstract class UriDerivativeLoader<T> extends AsyncTaskLoader<T> { closeQuietly(mResult); mResult = null; - if (mObserving) { - getContext().getContentResolver().unregisterContentObserver(mObserver); - mObserving = false; - } + getContext().getContentResolver().unregisterContentObserver(mObserver); } - private void closeQuietly(T result) { + private void closeQuietly(R result) { if (result instanceof AutoCloseable) { try { ((AutoCloseable) result).close(); diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/Document.java b/packages/DocumentsUI/src/com/android/documentsui/model/Document.java index 95922b4..c0f21cb 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/model/Document.java +++ b/packages/DocumentsUI/src/com/android/documentsui/model/Document.java @@ -21,6 +21,7 @@ import android.database.Cursor; import android.net.Uri; import android.provider.DocumentsContract; import android.provider.DocumentsContract.DocumentColumns; +import android.provider.DocumentsContract.Documents; import com.android.documentsui.RecentsProvider; @@ -87,7 +88,7 @@ public class Document { final String mimeType = getCursorString(cursor, DocumentColumns.MIME_TYPE); final String displayName = getCursorString(cursor, DocumentColumns.DISPLAY_NAME); final int flags = getCursorInt(cursor, DocumentColumns.FLAGS) - & DocumentsContract.FLAG_SUPPORTS_THUMBNAIL; + & Documents.FLAG_SUPPORTS_THUMBNAIL; final String summary = getCursorString(cursor, DocumentColumns.SUMMARY); final long size = getCursorLong(cursor, DocumentColumns.SIZE); @@ -127,19 +128,27 @@ public class Document { } public boolean isCreateSupported() { - return (flags & DocumentsContract.FLAG_SUPPORTS_CREATE) != 0; + return (flags & Documents.FLAG_SUPPORTS_CREATE) != 0; } public boolean isSearchSupported() { - return (flags & DocumentsContract.FLAG_SUPPORTS_SEARCH) != 0; + return (flags & Documents.FLAG_SUPPORTS_SEARCH) != 0; } public boolean isThumbnailSupported() { - return (flags & DocumentsContract.FLAG_SUPPORTS_THUMBNAIL) != 0; + return (flags & Documents.FLAG_SUPPORTS_THUMBNAIL) != 0; } public boolean isDirectory() { - return DocumentsContract.MIME_TYPE_DIRECTORY.equals(mimeType); + return Documents.MIME_TYPE_DIR.equals(mimeType); + } + + public boolean isGridPreferred() { + return (flags & Documents.FLAG_PREFERS_GRID) != 0; + } + + public boolean isDeleteSupported() { + return (flags & Documents.FLAG_SUPPORTS_DELETE) != 0; } private static String getCursorString(Cursor cursor, String columnName) { @@ -147,9 +156,19 @@ public class Document { return (index != -1) ? cursor.getString(index) : null; } + /** + * Missing or null values are returned as -1. + */ private static long getCursorLong(Cursor cursor, String columnName) { final int index = cursor.getColumnIndex(columnName); - return (index != -1) ? cursor.getLong(index) : 0; + if (index == -1) return -1; + final String value = cursor.getString(index); + if (value == null) return -1; + try { + return Long.parseLong(value); + } catch (NumberFormatException e) { + return -1; + } } private static int getCursorInt(Cursor cursor, String columnName) { diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/Root.java b/packages/DocumentsUI/src/com/android/documentsui/model/Root.java index 0880731..23d16df 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/model/Root.java +++ b/packages/DocumentsUI/src/com/android/documentsui/model/Root.java @@ -24,7 +24,9 @@ import android.database.Cursor; import android.graphics.drawable.Drawable; import android.net.Uri; import android.provider.DocumentsContract; +import android.provider.DocumentsContract.Documents; import android.provider.DocumentsContract.RootColumns; +import android.provider.DocumentsContract.Roots; import com.android.documentsui.R; @@ -47,7 +49,7 @@ public class Root { final PackageManager pm = context.getPackageManager(); final Root root = new Root(); root.rootId = null; - root.rootType = DocumentsContract.ROOT_TYPE_SHORTCUT; + root.rootType = Roots.ROOT_TYPE_SHORTCUT; root.uri = null; root.icon = context.getResources().getDrawable(R.drawable.ic_dir); root.title = context.getString(R.string.root_recent); @@ -65,7 +67,7 @@ public class Root { root.rootId = cursor.getString(cursor.getColumnIndex(RootColumns.ROOT_ID)); root.rootType = cursor.getInt(cursor.getColumnIndex(RootColumns.ROOT_TYPE)); root.uri = DocumentsContract.buildDocumentUri( - info.providerInfo.authority, root.rootId, DocumentsContract.ROOT_DOC_ID); + info.providerInfo.authority, root.rootId, Documents.DOC_ID_ROOT); root.icon = info.providerInfo.loadIcon(pm); root.title = info.providerInfo.loadLabel(pm).toString(); root.availableBytes = cursor.getLong(cursor.getColumnIndex(RootColumns.AVAILABLE_BYTES)); diff --git a/packages/ExternalStorageProvider/AndroidManifest.xml b/packages/ExternalStorageProvider/AndroidManifest.xml index afdb6bb..8bd2a6d 100644 --- a/packages/ExternalStorageProvider/AndroidManifest.xml +++ b/packages/ExternalStorageProvider/AndroidManifest.xml @@ -7,7 +7,7 @@ <application android:label="@string/app_label"> <provider android:name=".ExternalStorageProvider" - android:authorities="com.android.externalstorage" + android:authorities="com.android.externalstorage.documents" android:grantUriPermissions="true" android:exported="true" android:permission="android.permission.MANAGE_DOCUMENTS"> @@ -15,5 +15,18 @@ android:name="android.content.DOCUMENT_PROVIDER" android:resource="@xml/document_provider" /> </provider> + + <!-- TODO: remove when we have real providers --> + <provider + android:name=".CloudTestDocumentsProvider" + android:authorities="com.android.externalstorage.cloudtest" + android:grantUriPermissions="true" + android:exported="true" + android:enabled="false" + android:permission="android.permission.MANAGE_DOCUMENTS"> + <meta-data + android:name="android.content.DOCUMENT_PROVIDER" + android:resource="@xml/document_provider" /> + </provider> </application> </manifest> diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/CloudTestDocumentsProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/CloudTestDocumentsProvider.java new file mode 100644 index 0000000..119d92e --- /dev/null +++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/CloudTestDocumentsProvider.java @@ -0,0 +1,253 @@ +/* + * 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.externalstorage; + +import android.content.ContentProvider; +import android.content.ContentValues; +import android.content.UriMatcher; +import android.database.Cursor; +import android.database.MatrixCursor; +import android.database.MatrixCursor.RowBuilder; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.ParcelFileDescriptor; +import android.os.SystemClock; +import android.provider.DocumentsContract; +import android.provider.DocumentsContract.DocumentColumns; +import android.provider.DocumentsContract.Documents; +import android.provider.DocumentsContract.RootColumns; +import android.provider.DocumentsContract.Roots; +import android.util.Log; + +import com.google.android.collect.Lists; + +import libcore.io.IoUtils; + +import java.io.FileNotFoundException; +import java.util.List; + +public class CloudTestDocumentsProvider extends ContentProvider { + private static final String TAG = "CloudTest"; + + private static final String AUTHORITY = "com.android.externalstorage.cloudtest"; + + private static final UriMatcher sMatcher = new UriMatcher(UriMatcher.NO_MATCH); + + private static final int URI_ROOTS = 1; + private static final int URI_ROOTS_ID = 2; + private static final int URI_DOCS_ID = 3; + private static final int URI_DOCS_ID_CONTENTS = 4; + private static final int URI_DOCS_ID_SEARCH = 5; + + static { + sMatcher.addURI(AUTHORITY, "roots", URI_ROOTS); + sMatcher.addURI(AUTHORITY, "roots/*", URI_ROOTS_ID); + sMatcher.addURI(AUTHORITY, "roots/*/docs/*", URI_DOCS_ID); + sMatcher.addURI(AUTHORITY, "roots/*/docs/*/contents", URI_DOCS_ID_CONTENTS); + sMatcher.addURI(AUTHORITY, "roots/*/docs/*/search", URI_DOCS_ID_SEARCH); + } + + private static final String[] ALL_ROOTS_COLUMNS = new String[] { + RootColumns.ROOT_ID, RootColumns.ROOT_TYPE, RootColumns.ICON, RootColumns.TITLE, + RootColumns.SUMMARY, RootColumns.AVAILABLE_BYTES + }; + + private static final String[] ALL_DOCUMENTS_COLUMNS = new String[] { + DocumentColumns.DOC_ID, DocumentColumns.DISPLAY_NAME, DocumentColumns.SIZE, + DocumentColumns.MIME_TYPE, DocumentColumns.LAST_MODIFIED, DocumentColumns.FLAGS + }; + + private List<String> mKnownDocs = Lists.newArrayList("meow.png", "kittens.pdf"); + + private int mPage; + + @Override + public boolean onCreate() { + return true; + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder) { + switch (sMatcher.match(uri)) { + case URI_ROOTS: { + final MatrixCursor result = new MatrixCursor( + projection != null ? projection : ALL_ROOTS_COLUMNS); + includeDefaultRoot(result); + return result; + } + case URI_ROOTS_ID: { + final MatrixCursor result = new MatrixCursor( + projection != null ? projection : ALL_ROOTS_COLUMNS); + includeDefaultRoot(result); + return result; + } + case URI_DOCS_ID: { + final String docId = DocumentsContract.getDocId(uri); + final MatrixCursor result = new MatrixCursor( + projection != null ? projection : ALL_DOCUMENTS_COLUMNS); + includeDoc(result, docId); + return result; + } + case URI_DOCS_ID_CONTENTS: { + final CloudCursor result = new CloudCursor( + projection != null ? projection : ALL_DOCUMENTS_COLUMNS, uri); + for (String docId : mKnownDocs) { + includeDoc(result, docId); + } + if (mPage < 3) { + result.setHasMore(); + } + result.setNotificationUri(getContext().getContentResolver(), uri); + return result; + } + default: { + throw new UnsupportedOperationException("Unsupported Uri " + uri); + } + } + } + + private void includeDefaultRoot(MatrixCursor result) { + final RowBuilder row = result.newRow(); + row.offer(RootColumns.ROOT_ID, "testroot"); + row.offer(RootColumns.ROOT_TYPE, Roots.ROOT_TYPE_SERVICE); + row.offer(RootColumns.TITLE, "_TestTitle"); + row.offer(RootColumns.SUMMARY, "_TestSummary"); + } + + private void includeDoc(MatrixCursor result, String docId) { + int flags = 0; + + final String mimeType; + if (Documents.DOC_ID_ROOT.equals(docId)) { + mimeType = Documents.MIME_TYPE_DIR; + } else { + mimeType = "application/octet-stream"; + } + + final RowBuilder row = result.newRow(); + row.offer(DocumentColumns.DOC_ID, docId); + row.offer(DocumentColumns.DISPLAY_NAME, docId); + row.offer(DocumentColumns.MIME_TYPE, mimeType); + row.offer(DocumentColumns.LAST_MODIFIED, System.currentTimeMillis()); + row.offer(DocumentColumns.FLAGS, flags); + } + + private class CloudCursor extends MatrixCursor { + private final Uri mUri; + private Bundle mExtras = new Bundle(); + + public CloudCursor(String[] columnNames, Uri uri) { + super(columnNames); + mUri = uri; + } + + public void setHasMore() { + mExtras.putBoolean(DocumentsContract.EXTRA_HAS_MORE, true); + } + + @Override + public Bundle getExtras() { + Log.d(TAG, "getExtras() " + mExtras); + return mExtras; + } + + @Override + public Bundle respond(Bundle extras) { + extras.size(); + Log.d(TAG, "respond() " + extras); + if (extras.getBoolean(DocumentsContract.EXTRA_REQUEST_MORE, false)) { + new CloudTask().execute(mUri); + } + return Bundle.EMPTY; + } + } + + private class CloudTask extends AsyncTask<Uri, Void, Void> { + @Override + protected Void doInBackground(Uri... uris) { + final Uri uri = uris[0]; + + SystemClock.sleep(1000); + + // Grab some files from the cloud + for (int i = 0; i < 5; i++) { + mKnownDocs.add("cloud-page" + mPage + "-file" + i); + } + mPage++; + + Log.d(TAG, "Loaded more; notifying " + uri); + getContext().getContentResolver().notifyChange(uri, null, false); + return null; + } + } + + private interface TypeQuery { + final String[] PROJECTION = { + DocumentColumns.MIME_TYPE }; + + final int MIME_TYPE = 0; + } + + @Override + public String getType(Uri uri) { + switch (sMatcher.match(uri)) { + case URI_ROOTS: { + return Roots.MIME_TYPE_DIR; + } + case URI_ROOTS_ID: { + return Roots.MIME_TYPE_ITEM; + } + case URI_DOCS_ID: { + final Cursor cursor = query(uri, TypeQuery.PROJECTION, null, null, null); + try { + if (cursor.moveToFirst()) { + return cursor.getString(TypeQuery.MIME_TYPE); + } else { + return null; + } + } finally { + IoUtils.closeQuietly(cursor); + } + } + default: { + throw new UnsupportedOperationException("Unsupported Uri " + uri); + } + } + } + + @Override + public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { + throw new UnsupportedOperationException("Unsupported Uri " + uri); + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + throw new UnsupportedOperationException("Unsupported Uri " + uri); + } + + @Override + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + throw new UnsupportedOperationException("Unsupported Uri " + uri); + } + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + throw new UnsupportedOperationException("Unsupported Uri " + uri); + } +} diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java index 5c12484..b4bf563 100644 --- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java +++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java @@ -22,13 +22,15 @@ import android.content.ContentValues; import android.content.UriMatcher; import android.database.Cursor; import android.database.MatrixCursor; +import android.database.MatrixCursor.RowBuilder; import android.net.Uri; import android.os.Environment; import android.os.ParcelFileDescriptor; -import android.provider.BaseColumns; import android.provider.DocumentsContract; import android.provider.DocumentsContract.DocumentColumns; +import android.provider.DocumentsContract.Documents; import android.provider.DocumentsContract.RootColumns; +import android.provider.DocumentsContract.Roots; import android.util.Log; import android.webkit.MimeTypeMap; @@ -43,7 +45,7 @@ import java.util.LinkedList; public class ExternalStorageProvider extends ContentProvider { private static final String TAG = "ExternalStorage"; - private static final String AUTHORITY = "com.android.externalstorage"; + private static final String AUTHORITY = "com.android.externalstorage.documents"; // TODO: support multiple storage devices @@ -55,6 +57,14 @@ public class ExternalStorageProvider extends ContentProvider { private static final int URI_DOCS_ID_CONTENTS = 4; private static final int URI_DOCS_ID_SEARCH = 5; + static { + sMatcher.addURI(AUTHORITY, "roots", URI_ROOTS); + sMatcher.addURI(AUTHORITY, "roots/*", URI_ROOTS_ID); + sMatcher.addURI(AUTHORITY, "roots/*/docs/*", URI_DOCS_ID); + sMatcher.addURI(AUTHORITY, "roots/*/docs/*/contents", URI_DOCS_ID_CONTENTS); + sMatcher.addURI(AUTHORITY, "roots/*/docs/*/search", URI_DOCS_ID_SEARCH); + } + private HashMap<String, Root> mRoots = Maps.newHashMap(); private static class Root { @@ -66,20 +76,22 @@ public class ExternalStorageProvider extends ContentProvider { public File path; } - static { - sMatcher.addURI(AUTHORITY, "roots", URI_ROOTS); - sMatcher.addURI(AUTHORITY, "roots/*", URI_ROOTS_ID); - sMatcher.addURI(AUTHORITY, "roots/*/docs/*", URI_DOCS_ID); - sMatcher.addURI(AUTHORITY, "roots/*/docs/*/contents", URI_DOCS_ID_CONTENTS); - sMatcher.addURI(AUTHORITY, "roots/*/docs/*/search", URI_DOCS_ID_SEARCH); - } + private static final String[] ALL_ROOTS_COLUMNS = new String[] { + RootColumns.ROOT_ID, RootColumns.ROOT_TYPE, RootColumns.ICON, RootColumns.TITLE, + RootColumns.SUMMARY, RootColumns.AVAILABLE_BYTES + }; + + private static final String[] ALL_DOCUMENTS_COLUMNS = new String[] { + DocumentColumns.DOC_ID, DocumentColumns.DISPLAY_NAME, DocumentColumns.SIZE, + DocumentColumns.MIME_TYPE, DocumentColumns.LAST_MODIFIED, DocumentColumns.FLAGS + }; @Override public boolean onCreate() { mRoots.clear(); final Root root = new Root(); - root.rootType = DocumentsContract.ROOT_TYPE_DEVICE_ADVANCED; + root.rootType = Roots.ROOT_TYPE_DEVICE_ADVANCED; root.name = "primary"; root.title = getContext().getString(R.string.root_internal_storage); root.path = Environment.getExternalStorageDirectory(); @@ -91,64 +103,59 @@ public class ExternalStorageProvider extends ContentProvider { @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { - - // TODO: support custom projections - final String[] rootsProjection = new String[] { - BaseColumns._ID, RootColumns.ROOT_ID, RootColumns.ROOT_TYPE, RootColumns.ICON, - RootColumns.TITLE, RootColumns.SUMMARY, RootColumns.AVAILABLE_BYTES }; - final String[] docsProjection = new String[] { - BaseColumns._ID, DocumentColumns.DISPLAY_NAME, DocumentColumns.SIZE, - DocumentColumns.DOC_ID, DocumentColumns.MIME_TYPE, DocumentColumns.LAST_MODIFIED, - DocumentColumns.FLAGS }; - switch (sMatcher.match(uri)) { case URI_ROOTS: { - final MatrixCursor cursor = new MatrixCursor(rootsProjection); + final MatrixCursor result = new MatrixCursor( + projection != null ? projection : ALL_ROOTS_COLUMNS); for (Root root : mRoots.values()) { - includeRoot(cursor, root); + includeRoot(result, root); } - return cursor; + return result; } case URI_ROOTS_ID: { final Root root = mRoots.get(DocumentsContract.getRootId(uri)); - final MatrixCursor cursor = new MatrixCursor(rootsProjection); - includeRoot(cursor, root); - return cursor; + final MatrixCursor result = new MatrixCursor( + projection != null ? projection : ALL_ROOTS_COLUMNS); + includeRoot(result, root); + return result; } case URI_DOCS_ID: { final Root root = mRoots.get(DocumentsContract.getRootId(uri)); final String docId = DocumentsContract.getDocId(uri); - final MatrixCursor cursor = new MatrixCursor(docsProjection); + final MatrixCursor result = new MatrixCursor( + projection != null ? projection : ALL_DOCUMENTS_COLUMNS); final File file = docIdToFile(root, docId); - includeFile(cursor, root, file); - return cursor; + includeFile(result, root, file); + return result; } case URI_DOCS_ID_CONTENTS: { final Root root = mRoots.get(DocumentsContract.getRootId(uri)); final String docId = DocumentsContract.getDocId(uri); - final MatrixCursor cursor = new MatrixCursor(docsProjection); + final MatrixCursor result = new MatrixCursor( + projection != null ? projection : ALL_DOCUMENTS_COLUMNS); final File parent = docIdToFile(root, docId); for (File file : parent.listFiles()) { - includeFile(cursor, root, file); + includeFile(result, root, file); } - return cursor; + return result; } case URI_DOCS_ID_SEARCH: { final Root root = mRoots.get(DocumentsContract.getRootId(uri)); final String docId = DocumentsContract.getDocId(uri); final String query = DocumentsContract.getSearchQuery(uri).toLowerCase(); - final MatrixCursor cursor = new MatrixCursor(docsProjection); + final MatrixCursor result = new MatrixCursor( + projection != null ? projection : ALL_DOCUMENTS_COLUMNS); final File parent = docIdToFile(root, docId); final LinkedList<File> pending = new LinkedList<File>(); pending.add(parent); - while (!pending.isEmpty() && cursor.getCount() < 20) { + while (!pending.isEmpty() && result.getCount() < 20) { final File file = pending.removeFirst(); if (file.isDirectory()) { for (File child : file.listFiles()) { @@ -156,12 +163,12 @@ public class ExternalStorageProvider extends ContentProvider { } } else { if (file.getName().toLowerCase().contains(query)) { - includeFile(cursor, root, file); + includeFile(result, root, file); } } } - return cursor; + return result; } default: { throw new UnsupportedOperationException("Unsupported Uri " + uri); @@ -173,7 +180,7 @@ public class ExternalStorageProvider extends ContentProvider { String rootPath = root.path.getAbsolutePath(); final String path = file.getAbsolutePath(); if (path.equals(rootPath)) { - return DocumentsContract.ROOT_DOC_ID; + return Documents.DOC_ID_ROOT; } if (!rootPath.endsWith("/")) { @@ -187,55 +194,69 @@ public class ExternalStorageProvider extends ContentProvider { } private File docIdToFile(Root root, String docId) { - if (DocumentsContract.ROOT_DOC_ID.equals(docId)) { + if (Documents.DOC_ID_ROOT.equals(docId)) { return root.path; } else { return new File(root.path, docId); } } - private void includeRoot(MatrixCursor cursor, Root root) { - cursor.addRow(new Object[] { - root.name.hashCode(), root.name, root.rootType, root.icon, root.title, root.summary, - root.path.getFreeSpace() }); + private void includeRoot(MatrixCursor result, Root root) { + final RowBuilder row = result.newRow(); + row.offer(RootColumns.ROOT_ID, root.name); + row.offer(RootColumns.ROOT_TYPE, root.rootType); + row.offer(RootColumns.ICON, root.icon); + row.offer(RootColumns.TITLE, root.title); + row.offer(RootColumns.SUMMARY, root.summary); + row.offer(RootColumns.AVAILABLE_BYTES, root.path.getFreeSpace()); } - private void includeFile(MatrixCursor cursor, Root root, File file) { + private void includeFile(MatrixCursor result, Root root, File file) { int flags = 0; if (file.isDirectory()) { - flags |= DocumentsContract.FLAG_SUPPORTS_SEARCH; + flags |= Documents.FLAG_SUPPORTS_SEARCH; } if (file.isDirectory() && file.canWrite()) { - flags |= DocumentsContract.FLAG_SUPPORTS_CREATE; + flags |= Documents.FLAG_SUPPORTS_CREATE; } if (file.canWrite()) { - flags |= DocumentsContract.FLAG_SUPPORTS_RENAME; - flags |= DocumentsContract.FLAG_SUPPORTS_DELETE; + flags |= Documents.FLAG_SUPPORTS_WRITE; + flags |= Documents.FLAG_SUPPORTS_RENAME; + flags |= Documents.FLAG_SUPPORTS_DELETE; } final String mimeType = getTypeForFile(file); if (mimeType.startsWith("image/")) { - flags |= DocumentsContract.FLAG_SUPPORTS_THUMBNAIL; + flags |= Documents.FLAG_SUPPORTS_THUMBNAIL; } final String docId = fileToDocId(root, file); - final long id = docId.hashCode(); - final String displayName; - if (DocumentsContract.ROOT_DOC_ID.equals(docId)) { + if (Documents.DOC_ID_ROOT.equals(docId)) { displayName = root.title; } else { displayName = file.getName(); } - cursor.addRow(new Object[] { - id, displayName, file.length(), docId, mimeType, file.lastModified(), flags }); + final RowBuilder row = result.newRow(); + row.offer(DocumentColumns.DOC_ID, docId); + row.offer(DocumentColumns.DISPLAY_NAME, displayName); + row.offer(DocumentColumns.SIZE, file.length()); + row.offer(DocumentColumns.MIME_TYPE, mimeType); + row.offer(DocumentColumns.LAST_MODIFIED, file.lastModified()); + row.offer(DocumentColumns.FLAGS, flags); } @Override public String getType(Uri uri) { switch (sMatcher.match(uri)) { + case URI_ROOTS: { + return Roots.MIME_TYPE_DIR; + } + case URI_ROOTS_ID: { + return Roots.MIME_TYPE_ITEM; + } case URI_DOCS_ID: { final Root root = mRoots.get(DocumentsContract.getRootId(uri)); final String docId = DocumentsContract.getDocId(uri); @@ -249,7 +270,7 @@ public class ExternalStorageProvider extends ContentProvider { private String getTypeForFile(File file) { if (file.isDirectory()) { - return DocumentsContract.MIME_TYPE_DIRECTORY; + return Documents.MIME_TYPE_DIR; } else { return getTypeForName(file.getName()); } @@ -299,7 +320,7 @@ public class ExternalStorageProvider extends ContentProvider { values.getAsString(DocumentColumns.DISPLAY_NAME), mimeType); final File file = new File(parent, name); - if (DocumentsContract.MIME_TYPE_DIRECTORY.equals(mimeType)) { + if (Documents.MIME_TYPE_DIR.equals(mimeType)) { if (!file.mkdir()) { return null; } @@ -359,7 +380,7 @@ public class ExternalStorageProvider extends ContentProvider { } private String validateDisplayName(String displayName, String mimeType) { - if (DocumentsContract.MIME_TYPE_DIRECTORY.equals(mimeType)) { + if (Documents.MIME_TYPE_DIR.equals(mimeType)) { return displayName; } else { // Try appending meaningful extension if needed diff --git a/packages/Keyguard/AndroidManifest.xml b/packages/Keyguard/AndroidManifest.xml index 7d77c48..f3106da 100644 --- a/packages/Keyguard/AndroidManifest.xml +++ b/packages/Keyguard/AndroidManifest.xml @@ -38,6 +38,9 @@ <uses-permission android:name="android.permission.BIND_DEVICE_ADMIN" /> <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" /> + <!-- Permission for the Hotword detector service --> + <uses-permission android:name="com.google.android.googlequicksearchbox.SEARCH_API" /> + <application android:label="@string/app_name" android:process="com.android.systemui" android:persistent="true" > diff --git a/packages/Keyguard/src/com/android/keyguard/HotwordServiceClient.java b/packages/Keyguard/src/com/android/keyguard/HotwordServiceClient.java new file mode 100644 index 0000000..94733d4 --- /dev/null +++ b/packages/Keyguard/src/com/android/keyguard/HotwordServiceClient.java @@ -0,0 +1,208 @@ +/* + * 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.keyguard; + +import android.app.SearchManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.os.RemoteException; +import android.os.UserHandle; +import android.util.Log; + +import com.google.android.search.service.IHotwordService; +import com.google.android.search.service.IHotwordServiceCallback; + +/** + * Utility class with its callbacks to simplify usage of {@link IHotwordService}. + * + * The client is meant to be used for a single hotword detection in a session. + * start() -> stop(); client is asked to stop & disconnect from the service. + * start() -> onHotwordDetected(); client disconnects from the service automatically. + */ +public class HotwordServiceClient implements Handler.Callback { + private static final String TAG = "HotwordServiceClient"; + private static final boolean DBG = true; + private static final String ACTION_HOTWORD = + "com.google.android.search.service.IHotwordService"; + + private static final int MSG_SERVICE_CONNECTED = 0; + private static final int MSG_SERVICE_DISCONNECTED = 1; + private static final int MSG_HOTWORD_STARTED = 2; + private static final int MSG_HOTWORD_STOPPED = 3; + private static final int MSG_HOTWORD_DETECTED = 4; + + private final Context mContext; + private final Callback mClientCallback; + private final Handler mHandler; + + private IHotwordService mService; + + public HotwordServiceClient(Context context, Callback callback) { + mContext = context; + mClientCallback = callback; + mHandler = new Handler(this); + } + + public interface Callback { + void onServiceConnected(); + void onServiceDisconnected(); + void onHotwordDetectionStarted(); + void onHotwordDetectionStopped(); + void onHotwordDetected(String action); + } + + /** + * Binds to the {@link IHotwordService} and starts hotword detection + * when the service is connected. + * + * @return false if the service can't be bound to. + */ + public synchronized boolean start() { + if (mService != null) { + if (DBG) Log.d(TAG, "Multiple call to start(), service was already bound"); + return true; + } else { + // TODO: The hotword service is currently hosted within the search app + // so the component handling the assist intent should handle hotwording + // as well. + final Intent intent = + ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) + .getAssistIntent(mContext, true, UserHandle.USER_CURRENT); + if (intent == null) { + return false; + } + + Intent hotwordIntent = new Intent(ACTION_HOTWORD); + hotwordIntent.fillIn(intent, Intent.FILL_IN_PACKAGE); + return mContext.bindService( + hotwordIntent, + mConnection, + Context.BIND_AUTO_CREATE); + } + } + + /** + * Unbinds from the the {@link IHotwordService}. + */ + public synchronized void stop() { + if (mService != null) { + mContext.unbindService(mConnection); + mService = null; + } + } + + @Override + public boolean handleMessage(Message msg) { + switch (msg.what) { + case MSG_SERVICE_CONNECTED: + handleServiceConnected(); + break; + case MSG_SERVICE_DISCONNECTED: + handleServiceDisconnected(); + break; + case MSG_HOTWORD_STARTED: + handleHotwordDetectionStarted(); + break; + case MSG_HOTWORD_STOPPED: + handleHotwordDetectionStopped(); + break; + case MSG_HOTWORD_DETECTED: + handleHotwordDetected((String) msg.obj); + break; + default: + if (DBG) Log.e(TAG, "Unhandled message"); + return false; + } + return true; + } + + private void handleServiceConnected() { + if (DBG) Log.d(TAG, "handleServiceConnected()"); + if (mClientCallback != null) mClientCallback.onServiceConnected(); + try { + mService.requestHotwordDetection(mServiceCallback); + } catch (RemoteException e) { + Log.e(TAG, "Exception while registering callback", e); + mHandler.sendEmptyMessage(MSG_SERVICE_DISCONNECTED); + } + } + + private void handleServiceDisconnected() { + if (DBG) Log.d(TAG, "handleServiceDisconnected()"); + mService = null; + if (mClientCallback != null) mClientCallback.onServiceDisconnected(); + } + + private void handleHotwordDetectionStarted() { + if (DBG) Log.d(TAG, "handleHotwordDetectionStarted()"); + if (mClientCallback != null) mClientCallback.onHotwordDetectionStarted(); + } + + private void handleHotwordDetectionStopped() { + if (DBG) Log.d(TAG, "handleHotwordDetectionStopped()"); + if (mClientCallback != null) mClientCallback.onHotwordDetectionStopped(); + } + + void handleHotwordDetected(final String action) { + if (DBG) Log.d(TAG, "handleHotwordDetected()"); + if (mClientCallback != null) mClientCallback.onHotwordDetected(action); + stop(); + } + + /** + * Implements service connection methods. + */ + private ServiceConnection mConnection = new ServiceConnection() { + /** + * Called when the service connects after calling bind(). + */ + public void onServiceConnected(ComponentName className, IBinder iservice) { + mService = IHotwordService.Stub.asInterface(iservice); + mHandler.sendEmptyMessage(MSG_SERVICE_CONNECTED); + } + + /** + * Called if the service unexpectedly disconnects. This indicates an error. + */ + public void onServiceDisconnected(ComponentName className) { + mService = null; + mHandler.sendEmptyMessage(MSG_SERVICE_DISCONNECTED); + } + }; + + /** + * Implements the AIDL IHotwordServiceCallback interface. + */ + private final IHotwordServiceCallback mServiceCallback = new IHotwordServiceCallback.Stub() { + + public void onHotwordDetectionStarted() { + mHandler.sendEmptyMessage(MSG_HOTWORD_STARTED); + } + + public void onHotwordDetectionStopped() { + mHandler.sendEmptyMessage(MSG_HOTWORD_STOPPED); + } + + public void onHotwordDetected(String action) { + mHandler.obtainMessage(MSG_HOTWORD_DETECTED, action).sendToTarget(); + } + }; +} diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSelectorView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSelectorView.java index 4d891be..1c658e3 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardSelectorView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSelectorView.java @@ -22,8 +22,11 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.graphics.drawable.Drawable; +import android.os.Build; +import android.os.PowerManager; import android.os.UserHandle; import android.provider.Settings; +import android.telephony.TelephonyManager; import android.util.AttributeSet; import android.util.Log; import android.util.Slog; @@ -34,12 +37,15 @@ import com.android.internal.telephony.IccCardConstants.State; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.multiwaveview.GlowPadView; import com.android.internal.widget.multiwaveview.GlowPadView.OnTriggerListener; +import com.android.keyguard.KeyguardHostView.OnDismissAction; public class KeyguardSelectorView extends LinearLayout implements KeyguardSecurityView { private static final boolean DEBUG = KeyguardHostView.DEBUG; private static final String TAG = "SecuritySelectorView"; private static final String ASSIST_ICON_METADATA_NAME = "com.android.systemui.action_assist_icon"; + // Flag to enable/disable hotword detection on lock screen. + private static final boolean FLAG_HOTWORD = true; private KeyguardSecurityCallback mCallback; private GlowPadView mGlowPadView; @@ -51,11 +57,15 @@ public class KeyguardSelectorView extends LinearLayout implements KeyguardSecuri private LockPatternUtils mLockPatternUtils; private SecurityMessageDisplay mSecurityMessageDisplay; private Drawable mBouncerFrame; + private HotwordServiceClient mHotwordClient; OnTriggerListener mOnTriggerListener = new OnTriggerListener() { public void onTrigger(View v, int target) { final int resId = mGlowPadView.getResourceIdForTarget(target); + if (FLAG_HOTWORD) { + maybeStopHotwordDetector(); + } switch (resId) { case R.drawable.ic_action_assist_generic: Intent assistIntent = @@ -103,7 +113,7 @@ public class KeyguardSelectorView extends LinearLayout implements KeyguardSecuri }; - KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() { + KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() { @Override public void onDevicePolicyManagerStateChanged() { @@ -114,6 +124,24 @@ public class KeyguardSelectorView extends LinearLayout implements KeyguardSecuri public void onSimStateChanged(State simState) { updateTargets(); } + + @Override + public void onPhoneStateChanged(int phoneState) { + if (FLAG_HOTWORD) { + // We need to stop the hotwording when a phone call comes in + // TODO(sansid): This is not really needed if onPause triggers + // when we navigate away from the keyguard + if (phoneState == TelephonyManager.CALL_STATE_RINGING) { + if (DEBUG) Log.d(TAG, "Stopping due to CALL_STATE_RINGING"); + maybeStopHotwordDetector(); + } + } + } + + @Override + public void onUserSwitching(int userId) { + maybeStopHotwordDetector(); + } }; private final KeyguardActivityLauncher mActivityLauncher = new KeyguardActivityLauncher() { @@ -152,6 +180,9 @@ public class KeyguardSelectorView extends LinearLayout implements KeyguardSecuri mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this); View bouncerFrameView = findViewById(R.id.keyguard_selector_view_frame); mBouncerFrame = bouncerFrameView.getBackground(); + if (FLAG_HOTWORD) { + mHotwordClient = new HotwordServiceClient(getContext(), mHotwordCallback); + } } public void setCarrierArea(View carrierArea) { @@ -254,12 +285,22 @@ public class KeyguardSelectorView extends LinearLayout implements KeyguardSecuri @Override public void onPause() { - KeyguardUpdateMonitor.getInstance(getContext()).removeCallback(mInfoCallback); + KeyguardUpdateMonitor.getInstance(getContext()).removeCallback(mUpdateCallback); } @Override public void onResume(int reason) { - KeyguardUpdateMonitor.getInstance(getContext()).registerCallback(mInfoCallback); + KeyguardUpdateMonitor.getInstance(getContext()).registerCallback(mUpdateCallback); + // TODO: Figure out if there's a better way to do it. + // Right now we don't get onPause at all, and onResume gets called + // multiple times (even when the screen is turned off with VIEW_REVEALED) + if (reason == SCREEN_ON) { + if (!KeyguardUpdateMonitor.getInstance(getContext()).isSwitchingUser()) { + maybeStartHotwordDetector(); + } + } else { + maybeStopHotwordDetector(); + } } @Override @@ -280,4 +321,83 @@ public class KeyguardSelectorView extends LinearLayout implements KeyguardSecuri KeyguardSecurityViewHelper. hideBouncer(mSecurityMessageDisplay, mFadeView, mBouncerFrame, duration); } + + /** + * Start the hotword detector if: + * <li> HOTWORDING_ENABLED is true and + * <li> HotwordUnlock is initialized and + * <li> TelephonyManager is in CALL_STATE_IDLE + * + * If this method is called when the screen is off, + * it attempts to stop hotwording if it's running. + */ + private void maybeStartHotwordDetector() { + if (FLAG_HOTWORD) { + if (DEBUG) Log.d(TAG, "maybeStartHotwordDetector()"); + // Don't start it if the screen is off or not showing + PowerManager powerManager = (PowerManager) getContext().getSystemService( + Context.POWER_SERVICE); + if (!powerManager.isScreenOn()) { + if (DEBUG) Log.d(TAG, "screen was off, not starting"); + return; + } + + KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(getContext()); + if (monitor.getPhoneState() != TelephonyManager.CALL_STATE_IDLE) { + if (DEBUG) Log.d(TAG, "Call underway, not starting"); + return; + } + if (!mHotwordClient.start()) { + Log.w(TAG, "Failed to start the hotword detector"); + } + } + } + + /** + * Stop hotword detector if HOTWORDING_ENABLED is true. + */ + private void maybeStopHotwordDetector() { + if (FLAG_HOTWORD) { + if (DEBUG) Log.d(TAG, "maybeStopHotwordDetector()"); + mHotwordClient.stop(); + } + } + + private final HotwordServiceClient.Callback mHotwordCallback = + new HotwordServiceClient.Callback() { + private static final String TAG = "HotwordServiceClient.Callback"; + + @Override + public void onServiceConnected() { + if (DEBUG) Log.d(TAG, "onServiceConnected()"); + } + + @Override + public void onServiceDisconnected() { + if (DEBUG) Log.d(TAG, "onServiceDisconnected()"); + } + + @Override + public void onHotwordDetectionStarted() { + if (DEBUG) Log.d(TAG, "onHotwordDetectionStarted()"); + // TODO: Change the usage of SecurityMessageDisplay to a better visual indication. + mSecurityMessageDisplay.setMessage("\"Ok Google...\"", true); + } + + @Override + public void onHotwordDetectionStopped() { + if (DEBUG) Log.d(TAG, "onHotwordDetectionStopped()"); + // TODO: Change the usage of SecurityMessageDisplay to a better visual indication. + } + + @Override + public void onHotwordDetected(String action) { + if (DEBUG) Log.d(TAG, "onHotwordDetected(" + action + ")"); + if (action != null) { + Intent intent = new Intent(action); + mActivityLauncher.launchActivity(intent, true, true, null, null); + } + mCallback.userActivity(0); + } + }; } diff --git a/packages/Keyguard/src/com/google/android/search/service/IHotwordService.aidl b/packages/Keyguard/src/com/google/android/search/service/IHotwordService.aidl new file mode 100644 index 0000000..e053d7d --- /dev/null +++ b/packages/Keyguard/src/com/google/android/search/service/IHotwordService.aidl @@ -0,0 +1,35 @@ +/* + * 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.google.android.search.service; + +import com.google.android.search.service.IHotwordServiceCallback; + +/** + * Interface exposing hotword detector as a service. + */ +oneway interface IHotwordService { + + /** + * Indicates a desire to start hotword detection. + * It's best-effort and the client should rely on + * the callbacks to figure out if hotwording was actually + * started or not. + * + * @param a callback to notify of hotword events. + */ + void requestHotwordDetection(in IHotwordServiceCallback callback); +} diff --git a/packages/Keyguard/src/com/google/android/search/service/IHotwordServiceCallback.aidl b/packages/Keyguard/src/com/google/android/search/service/IHotwordServiceCallback.aidl new file mode 100644 index 0000000..7b3765f --- /dev/null +++ b/packages/Keyguard/src/com/google/android/search/service/IHotwordServiceCallback.aidl @@ -0,0 +1,34 @@ +/* + * 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.google.android.search.service; + +/** + * Interface implemented by users of Hotword service to get callbacks + * for hotword events. + */ +oneway interface IHotwordServiceCallback { + + /** Hotword detection start/stop callbacks */ + void onHotwordDetectionStarted(); + void onHotwordDetectionStopped(); + + /** + * Called back when hotword is detected. + * The action tells the client what action to take, post hotword-detection. + */ + void onHotwordDetected(in String action); +} diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml index 74fd7a8..1f10af8 100644 --- a/packages/PrintSpooler/AndroidManifest.xml +++ b/packages/PrintSpooler/AndroidManifest.xml @@ -18,7 +18,7 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.printspooler" - android:sharedUserId="android.uid.printspooler" + android:sharedUserId="android.uid.system" android:versionName="1" android:versionCode="1" coreApp="true"> @@ -50,6 +50,13 @@ android:theme="@style/PrintJobConfigActivityTheme"> </activity> + <activity + android:name=".SelectPrinterActivity" + android:label="@string/all_printers_label" + android:theme="@style/SelectPrinterActivityTheme" + android:exported="false"> + </activity> + <receiver android:name=".NotificationController$NotificationBroadcastReceiver" android:exported="false" > diff --git a/packages/PrintSpooler/res/drawable-hdpi/ic_menu_add.png b/packages/PrintSpooler/res/drawable-hdpi/ic_menu_add.png Binary files differnew file mode 100644 index 0000000..4b68f52 --- /dev/null +++ b/packages/PrintSpooler/res/drawable-hdpi/ic_menu_add.png diff --git a/packages/PrintSpooler/res/drawable-mdpi/ic_menu_add.png b/packages/PrintSpooler/res/drawable-mdpi/ic_menu_add.png Binary files differnew file mode 100644 index 0000000..15ffadd --- /dev/null +++ b/packages/PrintSpooler/res/drawable-mdpi/ic_menu_add.png diff --git a/packages/PrintSpooler/res/drawable-xhdpi/ic_menu_add.png b/packages/PrintSpooler/res/drawable-xhdpi/ic_menu_add.png Binary files differnew file mode 100644 index 0000000..420510e --- /dev/null +++ b/packages/PrintSpooler/res/drawable-xhdpi/ic_menu_add.png diff --git a/packages/PrintSpooler/res/layout/print_job_config_activity_container.xml b/packages/PrintSpooler/res/layout/print_job_config_activity_container.xml index a0c111b..7817094 100644 --- a/packages/PrintSpooler/res/layout/print_job_config_activity_container.xml +++ b/packages/PrintSpooler/res/layout/print_job_config_activity_container.xml @@ -20,9 +20,4 @@ android:layout_height="wrap_content" android:layout_gravity="center" android:background="@color/container_background"> - - <include - layout="@layout/print_job_config_activity_content_editing"> - </include> - </FrameLayout> diff --git a/packages/PrintSpooler/res/layout/select_printer_activity.xml b/packages/PrintSpooler/res/layout/select_printer_activity.xml new file mode 100644 index 0000000..f4e1853 --- /dev/null +++ b/packages/PrintSpooler/res/layout/select_printer_activity.xml @@ -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:orientation="horizontal" + android:layout_width="fill_parent" + android:layout_height="wrap_content"> + + <fragment + android:name="com.android.printspooler.SelectPrinterFragment" + android:id="@+id/select_printer_fragment" + android:layout_width="fill_parent" + android:layout_height="wrap_content"> + </fragment> + +</FrameLayout>
\ No newline at end of file diff --git a/packages/PrintSpooler/res/layout/spinner_dropdown_item.xml b/packages/PrintSpooler/res/layout/spinner_dropdown_item.xml index 002cc14..d14c064 100644 --- a/packages/PrintSpooler/res/layout/spinner_dropdown_item.xml +++ b/packages/PrintSpooler/res/layout/spinner_dropdown_item.xml @@ -15,7 +15,7 @@ --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" + android:layout_width="fill_parent" android:layout_height="wrap_content" android:paddingStart="8dip" android:paddingEnd="8dip" diff --git a/packages/PrintSpooler/res/menu/select_printer_activity.xml b/packages/PrintSpooler/res/menu/select_printer_activity.xml new file mode 100644 index 0000000..28fbd35 --- /dev/null +++ b/packages/PrintSpooler/res/menu/select_printer_activity.xml @@ -0,0 +1,37 @@ +<?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/action_search" + android:title="@string/search" + android:icon="@*android:drawable/ic_menu_search_holo_light" + android:actionViewClass="android.widget.SearchView" + android:showAsAction="ifRoom" + android:alphabeticShortcut="f" + android:imeOptions="actionSearch"> + </item> + + <item + android:id="@+id/action_add_printer" + android:title="@null" + android:icon="@drawable/ic_menu_add" + android:showAsAction="ifRoom" + android:alphabeticShortcut="a"> + </item> + +</menu> diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml index 2086f58..41fc516 100644 --- a/packages/PrintSpooler/res/values/strings.xml +++ b/packages/PrintSpooler/res/values/strings.xml @@ -58,6 +58,32 @@ <!-- Title for the temporary dialog show while an app is generating a print job. [CHAR LIMIT=30] --> <string name="generating_print_job">Generating print job</string> + <!-- Title for the save as PDF option in the printer list. [CHAR LIMIT=30] --> + <string name="save_as_pdf">Save as PDF</string> + + <!-- Title for the open all printers UI option in the printer list. [CHAR LIMIT=30] --> + <string name="all_printers">All printers\.\.\.</string> + + <!-- Title for the searching for printers option in the printer list + (only option if not printers are available). [CHAR LIMIT=40] --> + <string name="searching_for_printers">Searching for printers\.\.\.</string> + + <!-- Select printer activity --> + + <!-- Title for the share action bar menu item. [CHAR LIMIT=20] --> + <string name="search">Search</string> + + <!-- Title for the select printer activity. [CHAR LIMIT=30] --> + <string name="all_printers_label">All printers</string> + + <!-- Add printer dialog --> + + <!-- Title for the alert dialog for selecting a print service. [CHAR LIMIT=50] --> + <string name="choose_print_service">Choose print service</string> + + <!-- Title for the button to search the play store for print services. [CHAR LIMIT=50] --> + <string name="search_play_store">Search in play store</string> + <!-- Notifications --> <!-- Template for the notificaiton label for a printing print job. [CHAR LIMIT=25] --> diff --git a/packages/PrintSpooler/res/values/themes.xml b/packages/PrintSpooler/res/values/themes.xml index ab16c65..831b0ec 100644 --- a/packages/PrintSpooler/res/values/themes.xml +++ b/packages/PrintSpooler/res/values/themes.xml @@ -24,4 +24,12 @@ <item name="android:colorBackgroundCacheHint">@android:color/transparent</item> </style> + <style name="SelectPrinterActivityTheme" parent="@android:style/Theme.Holo.Light"> + <item name="android:actionBarStyle">@style/SelectPrinterActivityActionBarStyle</item> + </style> + + <style name="SelectPrinterActivityActionBarStyle" parent="@android:style/Widget.Holo.ActionBar"> + <item name="android:displayOptions">showTitle</item> + </style> + </resources> diff --git a/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java b/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java new file mode 100644 index 0000000..6bad5b3 --- /dev/null +++ b/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java @@ -0,0 +1,575 @@ +/* + * 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.printspooler; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Loader; +import android.os.AsyncTask; +import android.os.Build; +import android.print.PrinterId; +import android.print.PrinterInfo; +import android.util.ArrayMap; +import android.util.AtomicFile; +import android.util.Log; +import android.util.Slog; +import android.util.Xml; + +import com.android.internal.util.FastXmlSerializer; +import com.android.printspooler.PrintSpoolerService.PrinterDiscoverySession; + +import libcore.io.IoUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * This class is responsible for loading printers by doing discovery + * and merging the discovered printers with the previously used ones. + */ +public class FusedPrintersProvider extends Loader<List<PrinterInfo>> { + private static final String LOG_TAG = "FusedPrintersProvider"; + + private static final boolean DEBUG = true && Build.IS_DEBUGGABLE; + + private static final double WEIGHT_DECAY_COEFFICIENT = 0.95f; + + private static final int MAX_HISTORY_LENGTH = 50; + + private static final int MAX_HISTORICAL_PRINTER_COUNT = 4; + + private final Map<PrinterId, PrinterInfo> mPrinters = + new LinkedHashMap<PrinterId, PrinterInfo>(); + + private final PersistenceManager mPersistenceManager; + + private PrinterDiscoverySession mDiscoverySession; + + private List<PrinterInfo> mFavoritePrinters; + + public FusedPrintersProvider(Context context) { + super(context); + mPersistenceManager = new PersistenceManager(context); + } + + public void addHistoricalPrinter(PrinterInfo printer) { + mPersistenceManager.addPrinterAndWritePrinterHistory(printer); + } + + public List<PrinterInfo> getPrinters() { + return new ArrayList<PrinterInfo>(mPrinters.values()); + } + + @Override + public void deliverResult(List<PrinterInfo> printers) { + if (isStarted()) { + super.deliverResult(printers); + } + } + + @Override + protected void onStartLoading() { + if (DEBUG) { + Log.i(LOG_TAG, "onStartLoading()"); + } + // The contract is that if we already have a valid, + // result the we have to deliver it immediately. + if (!mPrinters.isEmpty()) { + deliverResult(new ArrayList<PrinterInfo>(mPrinters.values())); + } + // If the data has changed since the last load + // or is not available, start a load. + if (takeContentChanged() || mPrinters.isEmpty()) { + onForceLoad(); + } + } + + @Override + protected void onStopLoading() { + if (DEBUG) { + Log.i(LOG_TAG, "onStopLoading()"); + } + onCancelLoad(); + } + + @Override + protected void onForceLoad() { + if (DEBUG) { + Log.i(LOG_TAG, "onForceLoad()"); + } + onCancelLoad(); + loadInternal(); + } + + private void loadInternal() { + if (mDiscoverySession == null) { + mDiscoverySession = new MyPrinterDiscoverySession(); + mPersistenceManager.readPrinterHistory(); + } + if (mPersistenceManager.isReadHistoryCompleted() + && !mDiscoverySession.isStarted()) { + final int favoriteCount = Math.min(MAX_HISTORICAL_PRINTER_COUNT, + mFavoritePrinters.size()); + List<PrinterId> printerIds = new ArrayList<PrinterId>(favoriteCount); + for (int i = 0; i < favoriteCount; i++) { + printerIds.add(mFavoritePrinters.get(i).getId()); + } + mDiscoverySession.startPrinterDisovery(printerIds); + } + } + + @Override + protected boolean onCancelLoad() { + if (DEBUG) { + Log.i(LOG_TAG, "onCancelLoad()"); + } + return cancelInternal(); + } + + private boolean cancelInternal() { + if (mDiscoverySession != null && mDiscoverySession.isStarted()) { + mDiscoverySession.stopPrinterDiscovery(); + return true; + } else if (mPersistenceManager.isReadHistoryInProgress()) { + return mPersistenceManager.stopReadPrinterHistory(); + } + return false; + } + + @Override + protected void onReset() { + if (DEBUG) { + Log.i(LOG_TAG, "onReset()"); + } + onStopLoading(); + mPrinters.clear(); + if (mDiscoverySession != null) { + mDiscoverySession.destroy(); + mDiscoverySession = null; + } + } + + @Override + protected void onAbandon() { + if (DEBUG) { + Log.i(LOG_TAG, "onAbandon()"); + } + onStopLoading(); + } + + public void refreshPrinter(PrinterId printerId) { + if (isStarted() && mDiscoverySession != null && mDiscoverySession.isStarted()) { + mDiscoverySession.requestPrinterUpdated(printerId); + } + } + + private final class MyPrinterDiscoverySession extends PrinterDiscoverySession { + + @Override + public void onPrintersAdded(List<PrinterInfo> printers) { + if (DEBUG) { + Log.i(LOG_TAG, "MyPrinterDiscoverySession#onPrintersAdded()"); + } + boolean printersAdded = false; + final int addedPrinterCount = printers.size(); + for (int i = 0; i < addedPrinterCount; i++) { + PrinterInfo printer = printers.get(i); + if (!mPrinters.containsKey(printer.getId())) { + mPrinters.put(printer.getId(), printer); + printersAdded = true; + } + } + if (printersAdded) { + deliverResult(new ArrayList<PrinterInfo>(mPrinters.values())); + } + } + + @Override + public void onPrintersRemoved(List<PrinterId> printerIds) { + if (DEBUG) { + Log.i(LOG_TAG, "MyPrinterDiscoverySession#onPrintersRemoved()"); + } + boolean removedPrinters = false; + final int removedPrinterCount = printerIds.size(); + for (int i = 0; i < removedPrinterCount; i++) { + PrinterId removedPrinterId = printerIds.get(i); + if (mPrinters.remove(removedPrinterId) != null) { + removedPrinters = true; + } + } + if (removedPrinters) { + deliverResult(new ArrayList<PrinterInfo>(mPrinters.values())); + } + } + + @Override + public void onPrintersUpdated(List<PrinterInfo> printers) { + if (DEBUG) { + Log.i(LOG_TAG, "MyPrinterDiscoverySession#onPrintersUpdated()"); + } + boolean updatedPrinters = false; + final int updatedPrinterCount = printers.size(); + for (int i = 0; i < updatedPrinterCount; i++) { + PrinterInfo updatedPrinter = printers.get(i); + if (mPrinters.containsKey(updatedPrinter.getId())) { + mPrinters.put(updatedPrinter.getId(), updatedPrinter); + updatedPrinters = true; + } + } + if (updatedPrinters) { + deliverResult(new ArrayList<PrinterInfo>(mPrinters.values())); + } + } + } + + private final class PersistenceManager { + private static final String PERSIST_FILE_NAME = "printer_history.xml"; + + private static final String TAG_PRINTERS = "printers"; + + private static final String TAG_PRINTER = "printer"; + private static final String TAG_PRINTER_ID = "printerId"; + + private static final String ATTR_LOCAL_ID = "localId"; + private static final String ATTR_SERVICE_NAME = "serviceName"; + + private static final String ATTR_NAME = "name"; + private static final String ATTR_DESCRIPTION = "description"; + private static final String ATTR_STATUS = "status"; + + private final AtomicFile mStatePersistFile; + + private List<PrinterInfo> mHistoricalPrinters; + + private boolean mReadHistoryCompleted; + private boolean mReadHistoryInProgress; + + private final AsyncTask<Void, Void, List<PrinterInfo>> mReadTask = + new AsyncTask<Void, Void, List<PrinterInfo>>() { + @Override + protected List<PrinterInfo> doInBackground(Void... args) { + return doReadPrinterHistory(); + } + + @Override + protected void onPostExecute(List<PrinterInfo> printers) { + if (DEBUG) { + Log.i(LOG_TAG, "read history completed"); + } + + mHistoricalPrinters = printers; + + // Compute the favorite printers. + mFavoritePrinters = computeFavoritePrinters(printers); + + // We want the first few favorite printers on top of the list. + final int favoriteCount = Math.min(mFavoritePrinters.size(), + MAX_HISTORICAL_PRINTER_COUNT); + for (int i = 0; i < favoriteCount; i++) { + PrinterInfo favoritePrinter = mFavoritePrinters.get(i); + mPrinters.put(favoritePrinter.getId(), favoritePrinter); + } + + mReadHistoryInProgress = false; + mReadHistoryCompleted = true; + + loadInternal(); + } + + private List<PrinterInfo> doReadPrinterHistory() { + FileInputStream in = null; + try { + in = mStatePersistFile.openRead(); + } catch (FileNotFoundException fnfe) { + Log.i(LOG_TAG, "No existing printer history."); + return new ArrayList<PrinterInfo>(); + } + try { + List<PrinterInfo> printers = new ArrayList<PrinterInfo>(); + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(in, null); + parseState(parser, printers); + return printers; + } catch (IllegalStateException ise) { + Slog.w(LOG_TAG, "Failed parsing ", ise); + } catch (NullPointerException npe) { + Slog.w(LOG_TAG, "Failed parsing ", npe); + } catch (NumberFormatException nfe) { + Slog.w(LOG_TAG, "Failed parsing ", nfe); + } catch (XmlPullParserException xppe) { + Slog.w(LOG_TAG, "Failed parsing ", xppe); + } catch (IOException ioe) { + Slog.w(LOG_TAG, "Failed parsing ", ioe); + } catch (IndexOutOfBoundsException iobe) { + Slog.w(LOG_TAG, "Failed parsing ", iobe); + } finally { + IoUtils.closeQuietly(in); + } + + return Collections.emptyList(); + } + + private void parseState(XmlPullParser parser, List<PrinterInfo> outPrinters) + throws IOException, XmlPullParserException { + parser.next(); + skipEmptyTextTags(parser); + expect(parser, XmlPullParser.START_TAG, TAG_PRINTERS); + parser.next(); + + while (parsePrinter(parser, outPrinters)) { + // Be nice and respond to cancellation + if (isCancelled()) { + return; + } + parser.next(); + } + + skipEmptyTextTags(parser); + expect(parser, XmlPullParser.END_TAG, TAG_PRINTERS); + } + + private boolean parsePrinter(XmlPullParser parser, List<PrinterInfo> outPrinters) + throws IOException, XmlPullParserException { + skipEmptyTextTags(parser); + if (!accept(parser, XmlPullParser.START_TAG, TAG_PRINTER)) { + return false; + } + + String name = parser.getAttributeValue(null, ATTR_NAME); + String description = parser.getAttributeValue(null, ATTR_DESCRIPTION); + final int status = Integer.parseInt(parser.getAttributeValue(null, ATTR_STATUS)); + + parser.next(); + + skipEmptyTextTags(parser); + expect(parser, XmlPullParser.START_TAG, TAG_PRINTER_ID); + String localId = parser.getAttributeValue(null, ATTR_LOCAL_ID); + ComponentName service = ComponentName.unflattenFromString(parser.getAttributeValue( + null, ATTR_SERVICE_NAME)); + PrinterId printerId = new PrinterId(service, localId); + parser.next(); + skipEmptyTextTags(parser); + expect(parser, XmlPullParser.END_TAG, TAG_PRINTER_ID); + parser.next(); + + PrinterInfo.Builder builder = new PrinterInfo.Builder(printerId, name, status); + builder.setDescription(description); + PrinterInfo printer = builder.create(); + + outPrinters.add(printer); + + if (DEBUG) { + Log.i(LOG_TAG, "[RESTORED] " + printer); + } + + skipEmptyTextTags(parser); + expect(parser, XmlPullParser.END_TAG, TAG_PRINTER); + + return true; + } + + private void expect(XmlPullParser parser, int type, String tag) + throws IOException, XmlPullParserException { + if (!accept(parser, type, tag)) { + throw new XmlPullParserException("Exepected event: " + type + + " and tag: " + tag + " but got event: " + parser.getEventType() + + " and tag:" + parser.getName()); + } + } + + private void skipEmptyTextTags(XmlPullParser parser) + throws IOException, XmlPullParserException { + while (accept(parser, XmlPullParser.TEXT, null) + && "\n".equals(parser.getText())) { + parser.next(); + } + } + + private boolean accept(XmlPullParser parser, int type, String tag) + throws IOException, XmlPullParserException { + if (parser.getEventType() != type) { + return false; + } + if (tag != null) { + if (!tag.equals(parser.getName())) { + return false; + } + } else if (parser.getName() != null) { + return false; + } + return true; + } + }; + + private final AsyncTask<List<PrinterInfo>, Void, Void> mWriteTask = + new AsyncTask<List<PrinterInfo>, Void, Void>() { + @Override + protected Void doInBackground(List<PrinterInfo>... printers) { + doWritePrinterHistory(printers[0]); + return null; + } + + private void doWritePrinterHistory(List<PrinterInfo> printers) { + FileOutputStream out = null; + try { + out = mStatePersistFile.startWrite(); + + XmlSerializer serializer = new FastXmlSerializer(); + serializer.setOutput(out, "utf-8"); + serializer.startDocument(null, true); + serializer.startTag(null, TAG_PRINTERS); + + final int printerCount = printers.size(); + for (int i = 0; i < printerCount; i++) { + PrinterInfo printer = printers.get(i); + + serializer.startTag(null, TAG_PRINTER); + + serializer.attribute(null, ATTR_NAME, printer.getName()); + serializer.attribute(null, ATTR_STATUS, String.valueOf( + printer.getStatus())); + String description = printer.getDescription(); + if (description != null) { + serializer.attribute(null, ATTR_DESCRIPTION, description); + } + + PrinterId printerId = printer.getId(); + serializer.startTag(null, TAG_PRINTER_ID); + serializer.attribute(null, ATTR_LOCAL_ID, printerId.getLocalId()); + serializer.attribute(null, ATTR_SERVICE_NAME, printerId.getServiceName() + .flattenToString()); + serializer.endTag(null, TAG_PRINTER_ID); + + serializer.endTag(null, TAG_PRINTER); + + if (DEBUG) { + Log.i(LOG_TAG, "[PERSISTED] " + printer); + } + } + + serializer.endTag(null, TAG_PRINTERS); + serializer.endDocument(); + mStatePersistFile.finishWrite(out); + + if (DEBUG) { + Log.i(LOG_TAG, "[PERSIST END]"); + } + } catch (IOException ioe) { + Slog.w(LOG_TAG, "Failed to write printer history, restoring backup.", ioe); + mStatePersistFile.failWrite(out); + } finally { + IoUtils.closeQuietly(out); + } + } + }; + + private PersistenceManager(Context context) { + mStatePersistFile = new AtomicFile(new File(context.getFilesDir(), + PERSIST_FILE_NAME)); + } + + public boolean isReadHistoryInProgress() { + return mReadHistoryInProgress; + } + + public boolean isReadHistoryCompleted() { + return mReadHistoryCompleted; + } + + public boolean stopReadPrinterHistory() { + return mReadTask.cancel(true); + } + + public void readPrinterHistory() { + if (DEBUG) { + Log.i(LOG_TAG, "read history started"); + } + mReadHistoryInProgress = true; + mReadTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null); + } + + @SuppressWarnings("unchecked") + public void addPrinterAndWritePrinterHistory(PrinterInfo printer) { + if (mHistoricalPrinters.size() >= MAX_HISTORY_LENGTH) { + mHistoricalPrinters.remove(0); + } + mHistoricalPrinters.add(printer); + mWriteTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, mHistoricalPrinters); + } + + private List<PrinterInfo> computeFavoritePrinters(List<PrinterInfo> printers) { + Map<PrinterId, PrinterRecord> recordMap = + new ArrayMap<PrinterId, PrinterRecord>(); + + // Recompute the weights. + float currentWeight = 1.0f; + final int printerCount = printers.size(); + for (int i = printerCount - 1; i >= 0; i--) { + PrinterInfo printer = printers.get(i); + // Aggregate weight for the same printer + PrinterRecord record = recordMap.get(printer.getId()); + if (record == null) { + record = new PrinterRecord(printer); + recordMap.put(printer.getId(), record); + } + record.weight += currentWeight; + currentWeight *= WEIGHT_DECAY_COEFFICIENT; + } + + // Soft the favorite printers. + List<PrinterRecord> favoriteRecords = new ArrayList<PrinterRecord>( + recordMap.values()); + Collections.sort(favoriteRecords); + + // Write the favorites to the output. + final int favoriteCount = favoriteRecords.size(); + List<PrinterInfo> favoritePrinters = new ArrayList<PrinterInfo>(favoriteCount); + for (int i = 0; i < favoriteCount; i++) { + PrinterInfo printer = favoriteRecords.get(i).printer; + favoritePrinters.add(printer); + } + + return favoritePrinters; + } + + private final class PrinterRecord implements Comparable<PrinterRecord> { + public final PrinterInfo printer; + public float weight; + + public PrinterRecord(PrinterInfo printer) { + this.printer = printer; + } + + @Override + public int compareTo(PrinterRecord another) { + return Float.floatToIntBits(another.weight) - Float.floatToIntBits(weight); + } + } + } +} diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java index 9160b7d..d3dd8c9 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java +++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java @@ -18,12 +18,17 @@ package com.android.printspooler; import android.app.Activity; import android.app.Dialog; +import android.app.LoaderManager; import android.content.Context; +import android.content.Intent; +import android.content.Loader; import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.database.DataSetObserver; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Handler; @@ -34,15 +39,15 @@ import android.os.Message; import android.os.RemoteException; import android.print.ILayoutResultCallback; import android.print.IPrintDocumentAdapter; -import android.print.IPrinterDiscoverySessionController; -import android.print.IPrinterDiscoverySessionObserver; import android.print.IWriteResultCallback; import android.print.PageRange; import android.print.PrintAttributes; import android.print.PrintAttributes.MediaSize; +import android.print.PrintAttributes.Resolution; import android.print.PrintDocumentAdapter; import android.print.PrintDocumentInfo; import android.print.PrintJobInfo; +import android.print.PrintManager; import android.print.PrinterCapabilitiesInfo; import android.print.PrinterId; import android.print.PrinterInfo; @@ -64,15 +69,23 @@ import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; +import android.widget.BaseAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.Spinner; import android.widget.TextView; +import libcore.io.IoUtils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; @@ -94,15 +107,32 @@ public class PrintJobConfigActivity extends Activity { public static final String EXTRA_PRINT_ATTRIBUTES = "printAttributes"; public static final String EXTRA_PRINT_JOB_ID = "printJobId"; - private static final int CONTROLLER_STATE_INITIALIZED = 1; - private static final int CONTROLLER_STATE_STARTED = 2; - private static final int CONTROLLER_STATE_LAYOUT_STARTED = 3; - private static final int CONTROLLER_STATE_LAYOUT_COMPLETED = 4; - private static final int CONTROLLER_STATE_WRITE_STARTED = 5; - private static final int CONTROLLER_STATE_WRITE_COMPLETED = 6; - private static final int CONTROLLER_STATE_FINISHED = 7; - private static final int CONTROLLER_STATE_FAILED = 8; - private static final int CONTROLLER_STATE_CANCELLED = 9; + public static final String INTENT_EXTRA_PRINTER_ID = "INTENT_EXTRA_PRINTER_ID"; + + private static final int LOADER_ID_PRINTERS_LOADER = 1; + + private static final int DEST_ADAPTER_MIN_ITEM_COUNT = 2; + private static final int DEST_ADAPTER_MAX_ITEM_COUNT = 9; + + private static final int DEST_ADAPTER_POSITION_SEARCHING_FOR_PRINTERS = 0; + private static final int DEST_ADAPTER_POSITION_SAVE_AS_PDF = 1; + + private static final int DEST_ADAPTER_ITEM_ID_SAVE_AS_PDF = Integer.MAX_VALUE; + private static final int DEST_ADAPTER_ITEM_ID_ALL_PRINTERS = Integer.MAX_VALUE - 1; + private static final int DEST_ADAPTER_ITEM_ID_SEARCHING_FOR_PRINTERS = Integer.MAX_VALUE - 2; + + private static final int ACTIVITY_REQUEST_CREATE_FILE = 1; + private static final int ACTIVITY_REQUEST_SELECT_PRINTER = 2; + + private static final int CONTROLLER_STATE_FINISHED = 1; + private static final int CONTROLLER_STATE_FAILED = 2; + private static final int CONTROLLER_STATE_CANCELLED = 3; + private static final int CONTROLLER_STATE_INITIALIZED = 4; + private static final int CONTROLLER_STATE_STARTED = 5; + private static final int CONTROLLER_STATE_LAYOUT_STARTED = 6; + private static final int CONTROLLER_STATE_LAYOUT_COMPLETED = 7; + private static final int CONTROLLER_STATE_WRITE_STARTED = 8; + private static final int CONTROLLER_STATE_WRITE_COMPLETED = 9; private static final int EDITOR_STATE_INITIALIZED = 1; private static final int EDITOR_STATE_CONFIRMED_PRINT = 2; @@ -110,6 +140,7 @@ public class PrintJobConfigActivity extends Activity { private static final int EDITOR_STATE_CANCELLED = 4; private static final int MIN_COPIES = 1; + private static final String MIN_COPIES_STRING = String.valueOf(MIN_COPIES); private static final Pattern PATTERN_DIGITS = Pattern.compile("\\d"); @@ -132,11 +163,9 @@ public class PrintJobConfigActivity extends Activity { } }; - private PrintSpooler mSpooler; private Editor mEditor; private Document mDocument; private PrintController mController; - private PrinterDiscoverySessionObserver mPrinterDiscoverySessionObserver; private int mPrintJobId; @@ -147,9 +176,6 @@ public class PrintJobConfigActivity extends Activity { @Override protected void onCreate(Bundle bundle) { super.onCreate(bundle); - setContentView(R.layout.print_job_config_activity_container); - - getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); Bundle extras = getIntent().getExtras(); @@ -168,12 +194,17 @@ public class PrintJobConfigActivity extends Activity { mCurrPrintAttributes.copyFrom(attributes); } - mSpooler = PrintSpooler.peekInstance(); + setContentView(R.layout.print_job_config_activity_container); + + // TODO: This should be on the style + getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); + + mEditor = new Editor(); mDocument = new Document(); mController = new PrintController(new RemotePrintDocumentAdapter( IPrintDocumentAdapter.Stub.asInterface(mIPrintDocumentAdapter), - mSpooler.generateFileForPrintJob(mPrintJobId))); + PrintSpoolerService.peekInstance().generateFileForPrintJob(mPrintJobId))); try { mIPrintDocumentAdapter.linkToDeath(mDeathRecipient, 0); @@ -184,9 +215,6 @@ public class PrintJobConfigActivity extends Activity { mController.initialize(); mEditor.initialize(); - mPrinterDiscoverySessionObserver = new PrinterDiscoverySessionObserver(mEditor, - getMainLooper()); - mSpooler.createPrinterDiscoverySession(mPrinterDiscoverySessionObserver); } @Override @@ -194,17 +222,14 @@ public class PrintJobConfigActivity extends Activity { // We can safely do the work in here since at this point // the system is bound to our (spooler) process which // guarantees that this process will not be killed. - mPrinterDiscoverySessionObserver.close(); - mPrinterDiscoverySessionObserver.destroy(); - mPrinterDiscoverySessionObserver = null; if (mController.hasStarted()) { mController.finish(); } if (mEditor.isPrintConfirmed() && mController.isFinished()) { - mSpooler.setPrintJobState(mPrintJobId, + PrintSpoolerService.peekInstance().setPrintJobState(mPrintJobId, PrintJobInfo.STATE_QUEUED, null); } else { - mSpooler.setPrintJobState(mPrintJobId, + PrintSpoolerService.peekInstance().setPrintJobState(mPrintJobId, PrintJobInfo.STATE_CANCELED, null); } mIPrintDocumentAdapter.unlinkToDeath(mDeathRecipient, 0); @@ -315,12 +340,13 @@ public class PrintJobConfigActivity extends Activity { public void update() { if (!printAttributesChanged()) { - // If the attributes changes, then we do not do a layout but may + // If the attributes changed, then we do not do a layout but may // have to ask the app to write some pages. Hence, pretend layout // completed and nothing changed, so we handle writing as usual. handleOnLayoutFinished(mDocument.info, false, mRequestCounter.get()); } else { - mSpooler.setPrintJobAttributesNoPersistence(mPrintJobId, mCurrPrintAttributes); + PrintSpoolerService.peekInstance().setPrintJobAttributesNoPersistence( + mPrintJobId, mCurrPrintAttributes); mMetadata.putBoolean(PrintDocumentAdapter.METADATA_KEY_PRINT_PREVIEW, !mEditor.isPrintConfirmed()); @@ -353,15 +379,14 @@ public class PrintJobConfigActivity extends Activity { } mControllerState = CONTROLLER_STATE_LAYOUT_COMPLETED; + mEditor.updateUi(); - // If the info changed, we update the document and the print job, - // and update the UI since the the page range selection may have - // become invalid. + // If the info changed, we update the document and the print job. final boolean infoChanged = !info.equals(mDocument.info); if (infoChanged) { mDocument.info = info; - mSpooler.setPrintJobPrintDocumentInfoNoPersistence(mPrintJobId, info); - mEditor.updateUi(); + PrintSpoolerService.peekInstance().setPrintJobPrintDocumentInfoNoPersistence( + mPrintJobId, info); } // If the document info or the layout changed, then @@ -447,11 +472,13 @@ public class PrintJobConfigActivity extends Activity { if (Arrays.equals(mDocument.pages, mRequestedPages)) { // We got a document with exactly the pages we wanted. Hence, // the printer has to print all pages in the data. - mSpooler.setPrintJobPagesNoPersistence(mPrintJobId, ALL_PAGES_ARRAY); + PrintSpoolerService.peekInstance().setPrintJobPagesNoPersistence(mPrintJobId, + ALL_PAGES_ARRAY); } else if (Arrays.equals(mDocument.pages, ALL_PAGES_ARRAY)) { // We requested specific pages but got all of them. Hence, // the printer has to print only the requested pages. - mSpooler.setPrintJobPagesNoPersistence(mPrintJobId, mRequestedPages); + PrintSpoolerService.peekInstance().setPrintJobPagesNoPersistence(mPrintJobId, + mRequestedPages); } else if (PageRangeUtils.contains(mDocument.pages, mRequestedPages)) { // We requested specific pages and got more but not all pages. // Hence, we have to offset appropriately the printed pages to @@ -460,14 +487,16 @@ public class PrintJobConfigActivity extends Activity { final int offset = mDocument.pages[0].getStart() - pages[0].getStart(); PageRange[] offsetPages = Arrays.copyOf(mDocument.pages, mDocument.pages.length); PageRangeUtils.offsetStart(offsetPages, offset); - mSpooler.setPrintJobPagesNoPersistence(mPrintJobId, offsetPages); + PrintSpoolerService.peekInstance().setPrintJobPagesNoPersistence(mPrintJobId, + offsetPages); } else if (Arrays.equals(mRequestedPages, ALL_PAGES_ARRAY) && mDocument.pages.length == 1 && mDocument.pages[0].getStart() == 0 && mDocument.pages[0].getEnd() == mDocument.info.getPageCount() - 1) { // We requested all pages via the special constant and got all // of them as an explicit enumeration. Hence, the printer has // to print only the requested pages. - mSpooler.setPrintJobPagesNoPersistence(mPrintJobId, mDocument.pages); + PrintSpoolerService.peekInstance().setPrintJobPagesNoPersistence(mPrintJobId, + mDocument.pages); } else { // We did not get the pages we requested, then the application // misbehaves, so we fail quickly. @@ -478,7 +507,16 @@ public class PrintJobConfigActivity extends Activity { } if (mEditor.isDone()) { - PrintJobConfigActivity.this.finish(); + if (mEditor.isPrintingToPdf()) { + PrintJobInfo printJob = PrintSpoolerService.peekInstance() + .getPrintJobInfo(mPrintJobId, PrintManager.APP_ID_ANY); + Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT); + intent.setType("application/pdf"); + intent.putExtra(Intent.EXTRA_TITLE, printJob.getLabel()); + startActivityForResult(intent, ACTIVITY_REQUEST_CREATE_FILE); + } else { + PrintJobConfigActivity.this.finish(); + } } } @@ -585,33 +623,111 @@ public class PrintJobConfigActivity extends Activity { } } + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + switch (requestCode) { + case ACTIVITY_REQUEST_CREATE_FILE: { + if (data != null) { + Uri uri = data.getData(); + writePrintJobDataAndFinish(uri); + } else { + mEditor.showUi(Editor.UI_EDITING_PRINT_JOB, + new Runnable() { + @Override + public void run() { + mEditor.initialize(); + mEditor.bindUi(); + mEditor.updateUi(); + } + }); + } + } break; + + case ACTIVITY_REQUEST_SELECT_PRINTER: { + if (resultCode == RESULT_OK) { + PrinterId printerId = (PrinterId) data.getParcelableExtra( + INTENT_EXTRA_PRINTER_ID); + // TODO: Make sure the selected printer is in the shown list. + mEditor.selectPrinter(printerId); + } + } break; + } + } + + private void writePrintJobDataAndFinish(final Uri uri) { + new AsyncTask<Void, Void, Void>() { + @Override + protected Void doInBackground(Void... params) { + InputStream in = null; + OutputStream out = null; + try { + PrintJobInfo printJob = PrintSpoolerService.peekInstance() + .getPrintJobInfo(mPrintJobId, PrintManager.APP_ID_ANY); + if (printJob == null) { + return null; + } + File file = PrintSpoolerService.peekInstance() + .generateFileForPrintJob(mPrintJobId); + in = new FileInputStream(file); + out = getContentResolver().openOutputStream(uri); + final byte[] buffer = new byte[8192]; + while (true) { + final int readByteCount = in.read(buffer); + if (readByteCount < 0) { + break; + } + out.write(buffer, 0, readByteCount); + } + } catch (FileNotFoundException fnfe) { + Log.e(LOG_TAG, "Error writing print job data!", fnfe); + } catch (IOException ioe) { + Log.e(LOG_TAG, "Error writing print job data!", ioe); + } finally { + IoUtils.closeQuietly(in); + IoUtils.closeQuietly(out); + } + return null; + } + + @Override + public void onPostExecute(Void result) { + mEditor.cancel(); + PrintJobConfigActivity.this.finish(); + } + }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null); + } + private final class Editor { - private final EditText mCopiesEditText; + private static final int UI_NONE = 0; + private static final int UI_EDITING_PRINT_JOB = 1; + private static final int UI_GENERATING_PRINT_JOB = 2; + + private EditText mCopiesEditText; - private final TextView mRangeTitle; - private final EditText mRangeEditText; + private TextView mRangeTitle; + private EditText mRangeEditText; - private final Spinner mDestinationSpinner; - private final ArrayAdapter<SpinnerItem<PrinterInfo>> mDestinationSpinnerAdapter; + private Spinner mDestinationSpinner; + private final DestinationAdapter mDestinationSpinnerAdapter; - private final Spinner mMediaSizeSpinner; + private Spinner mMediaSizeSpinner; private final ArrayAdapter<SpinnerItem<MediaSize>> mMediaSizeSpinnerAdapter; - private final Spinner mColorModeSpinner; + private Spinner mColorModeSpinner; private final ArrayAdapter<SpinnerItem<Integer>> mColorModeSpinnerAdapter; - private final Spinner mOrientationSpinner; + private Spinner mOrientationSpinner; private final ArrayAdapter<SpinnerItem<Integer>> mOrientationSpinnerAdapter; - private final Spinner mRangeOptionsSpinner; + private Spinner mRangeOptionsSpinner; private final ArrayAdapter<SpinnerItem<Integer>> mRangeOptionsSpinnerAdapter; private final SimpleStringSplitter mStringCommaSplitter = new SimpleStringSplitter(','); - private final View mContentContainer; + private View mContentContainer; - private final Button mPrintButton; + private Button mPrintButton; private final OnItemSelectedListener mOnItemSelectedListener = new AdapterView.OnItemSelectedListener() { @@ -622,16 +738,32 @@ public class PrintJobConfigActivity extends Activity { mIgnoreNextDestinationChange = false; return; } + if (id == DEST_ADAPTER_ITEM_ID_ALL_PRINTERS) { + mIgnoreNextDestinationChange = true; + mDestinationSpinner.setSelection(0); + Intent intent = new Intent(PrintJobConfigActivity.this, + SelectPrinterActivity.class); + startActivityForResult(intent, ACTIVITY_REQUEST_SELECT_PRINTER); + return; + } + mWaitingForPrinterCapabilities = false; mCurrPrintAttributes.clear(); - SpinnerItem<PrinterInfo> dstItem = mDestinationSpinnerAdapter.getItem(position); - if (dstItem != null) { - PrinterInfo printer = dstItem.value; - mSpooler.setPrintJobPrinterNoPersistence(mPrintJobId, printer); + PrinterInfo printer = (PrinterInfo) mDestinationSpinnerAdapter + .getItem(position); + if (printer != null) { + PrintSpoolerService.peekInstance().setPrintJobPrinterNoPersistence( + mPrintJobId, printer); PrinterCapabilitiesInfo capabilities = printer.getCapabilities(); if (capabilities == null) { List<PrinterId> printerIds = new ArrayList<PrinterId>(); printerIds.add(printer.getId()); - mPrinterDiscoverySessionObserver.requestPrinterUpdate(printer.getId()); + FusedPrintersProvider printersLoader = (FusedPrintersProvider) + (Loader<?>) getLoaderManager().getLoader( + LOADER_ID_PRINTERS_LOADER); + if (printersLoader != null) { + printersLoader.refreshPrinter(printer.getId()); + } + mWaitingForPrinterCapabilities = true; //TODO: We need a timeout for the update. } else { capabilities.getDefaults(mCurrPrintAttributes); @@ -643,6 +775,31 @@ public class PrintJobConfigActivity extends Activity { } } } + + // The printer changed so we want to start with a clean slate + // for the print options and let them be populated from the + // printer capabilities and use the printer defaults. + if (!mMediaSizeSpinnerAdapter.isEmpty()) { + mIgnoreNextMediaSizeChange = true; + mMediaSizeSpinnerAdapter.clear(); + } + if (!mColorModeSpinnerAdapter.isEmpty()) { + mIgnoreNextColorModeChange = true; + mColorModeSpinnerAdapter.clear(); + } + if (!mOrientationSpinnerAdapter.isEmpty()) { + mIgnoreNextOrientationChange = true; + mOrientationSpinnerAdapter.clear(); + } + if (mRangeOptionsSpinner.getSelectedItemPosition() != 0) { + mIgnoreNextRangeOptionChange = true; + mRangeOptionsSpinner.setSelection(0); + } + if (!TextUtils.isEmpty(mCopiesEditText.getText())) { + mIgnoreNextCopiesChange = true; + mCopiesEditText.setText(MIN_COPIES_STRING); + } + updateUi(); } else if (spinner == mMediaSizeSpinner) { if (mIgnoreNextMediaSizeChange) { @@ -728,7 +885,8 @@ public class PrintJobConfigActivity extends Activity { } mCopiesEditText.setError(null); - mSpooler.setPrintJobCopiesNoPersistence(mPrintJobId, copies); + PrintSpoolerService.peekInstance().setPrintJobCopiesNoPersistence( + mPrintJobId, copies); updateUi(); if (hadErrors && !hasErrors() && printAttributesChanged()) { @@ -805,54 +963,64 @@ public class PrintJobConfigActivity extends Activity { private boolean mIgnoreNextCopiesChange; private boolean mIgnoreNextRangeChange; - public Editor() { - // Content container - mContentContainer = findViewById(R.id.content_container); + private boolean mWaitingForPrinterCapabilities; - // Copies - mCopiesEditText = (EditText) findViewById(R.id.copies_edittext); - mCopiesEditText.setText(String.valueOf(MIN_COPIES)); - mSpooler.setPrintJobCopiesNoPersistence(mPrintJobId, MIN_COPIES); - mCopiesEditText.addTextChangedListener(mCopiesTextWatcher); - mCopiesEditText.selectAll(); + private int mCurrentUi = UI_NONE; + public Editor() { // Destination. - mDestinationSpinner = (Spinner) findViewById(R.id.destination_spinner); mDestinationSpinnerAdapter = new DestinationAdapter(); - mDestinationSpinner.setAdapter(mDestinationSpinnerAdapter); - mDestinationSpinner.setOnItemSelectedListener(mOnItemSelectedListener); + mDestinationSpinnerAdapter.registerDataSetObserver(new DataSetObserver() { + @Override + public void onChanged() { + final int selectedPosition = mDestinationSpinner.getSelectedItemPosition(); + if (mDestinationSpinnerAdapter.getCount() > 0) { + // Make sure we select the first printer if we have data. + if (selectedPosition == AdapterView.INVALID_POSITION) { + mDestinationSpinner.setSelection(0); + } + } else { + // Make sure we select no printer if we have no data. + mDestinationSpinner.setSelection(AdapterView.INVALID_POSITION); + } + + // Maybe we did not have capabilities when the current printer was + // selected, but now the selected printer has capabilities. Generate + // a fake selection so the code in the selection change handling takes + // care of updating everything. This way the logic is in one place. + if (mWaitingForPrinterCapabilities) { + mWaitingForPrinterCapabilities = false; + PrinterInfo printer = (PrinterInfo) mDestinationSpinner.getSelectedItem(); + if (printer != null && printer.getCapabilities() != null) { + mOnItemSelectedListener.onItemSelected(mDestinationSpinner, null, + selectedPosition, selectedPosition); + } + } + updateUi(); + } + + @Override + public void onInvalidated() { + updateUi(); + } + }); // Media size. - mMediaSizeSpinner = (Spinner) findViewById(R.id.paper_size_spinner); mMediaSizeSpinnerAdapter = new ArrayAdapter<SpinnerItem<MediaSize>>( PrintJobConfigActivity.this, R.layout.spinner_dropdown_item, R.id.title); - mMediaSizeSpinner.setAdapter(mMediaSizeSpinnerAdapter); - mMediaSizeSpinner.setOnItemSelectedListener(mOnItemSelectedListener); // Color mode. - mColorModeSpinner = (Spinner) findViewById(R.id.color_spinner); mColorModeSpinnerAdapter = new ArrayAdapter<SpinnerItem<Integer>>( PrintJobConfigActivity.this, R.layout.spinner_dropdown_item, R.id.title); - mColorModeSpinner.setAdapter(mColorModeSpinnerAdapter); - mColorModeSpinner.setOnItemSelectedListener(mOnItemSelectedListener); // Orientation - mOrientationSpinner = (Spinner) findViewById(R.id.orientation_spinner); mOrientationSpinnerAdapter = new ArrayAdapter<SpinnerItem<Integer>>( PrintJobConfigActivity.this, R.layout.spinner_dropdown_item, R.id.title); - mOrientationSpinner.setAdapter(mOrientationSpinnerAdapter); - mOrientationSpinner.setOnItemSelectedListener(mOnItemSelectedListener); - - // Range - mRangeTitle = (TextView) findViewById(R.id.page_range_title); - mRangeEditText = (EditText) findViewById(R.id.page_range_edittext); - mRangeEditText.addTextChangedListener(mRangeTextWatcher); // Range options - mRangeOptionsSpinner = (Spinner) findViewById(R.id.range_options_spinner); mRangeOptionsSpinnerAdapter = new ArrayAdapter<SpinnerItem<Integer>>( PrintJobConfigActivity.this, R.layout.spinner_dropdown_item, R.id.title); @@ -865,25 +1033,26 @@ public class PrintJobConfigActivity extends Activity { mRangeOptionsSpinnerAdapter.add(new SpinnerItem<Integer>( rangeOptionsValues[i], rangeOptionsLabels[i])); } - mRangeOptionsSpinner.setAdapter(mRangeOptionsSpinnerAdapter); - if (mRangeOptionsSpinner.getSelectedItemPosition() != 0) { - mIgnoreNextRangeOptionChange = true; - mRangeOptionsSpinner.setSelection(0); - } - // Print button - mPrintButton = (Button) findViewById(R.id.print_button); - mPrintButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - mEditor.confirmPrint(); - updateUi(); - mController.update(); - showGeneratingPrintJobUi(); + showUi(UI_EDITING_PRINT_JOB, null); + bindUi(); + updateUi(); + } + + public void selectPrinter(PrinterId printerId) { + final int printerCount = mDestinationSpinnerAdapter.getCount(); + for (int i = 0; i < printerCount; i++) { + PrinterInfo printer = (PrinterInfo) mDestinationSpinnerAdapter.getItem(i); + if (printer.getId().equals(printerId)) { + mDestinationSpinner.setSelection(i); + return; } - }); + } + } - updateUi(); + public boolean isPrintingToPdf() { + return mDestinationSpinner.getSelectedItem() + == mDestinationSpinnerAdapter.mFakePdfPrinter; } public boolean shouldCloseOnTouch(MotionEvent event) { @@ -913,19 +1082,104 @@ public class PrintJobConfigActivity extends Activity { } public boolean isShwoingGeneratingPrintJobUi() { - return (findViewById(R.id.content_generating) != null); + return (mCurrentUi == UI_GENERATING_PRINT_JOB); } - private void showGeneratingPrintJobUi() { - // Find everything we will shuffle around. - final ViewGroup contentContainer = (ViewGroup) findViewById(R.id.content_container); - final View contentEditing = contentContainer.findViewById(R.id.content_editing); - final View contentGenerating = getLayoutInflater().inflate( - R.layout.print_job_config_activity_content_generating, - contentContainer, false); + public void showUi(int ui, final Runnable postSwitchCallback) { + if (ui == UI_NONE) { + throw new IllegalStateException("cannot remove the ui"); + } + + if (mCurrentUi == ui) { + return; + } + + switch (mCurrentUi) { + case UI_NONE: { + switch (ui) { + case UI_EDITING_PRINT_JOB: { + doUiSwitch(R.layout.print_job_config_activity_content_editing); + registerPrintButtonClickListener(); + if (postSwitchCallback != null) { + postSwitchCallback.run(); + } + } break; - // Wire the cancel action. - Button cancelButton = (Button) contentGenerating.findViewById(R.id.cancel_button); + case UI_GENERATING_PRINT_JOB: { + doUiSwitch(R.layout.print_job_config_activity_content_generating); + registerCancelButtonClickListener(); + if (postSwitchCallback != null) { + postSwitchCallback.run(); + } + } break; + } + } break; + + case UI_EDITING_PRINT_JOB: { + switch (ui) { + case UI_GENERATING_PRINT_JOB: { + animateUiSwitch(R.layout.print_job_config_activity_content_generating, + new Runnable() { + @Override + public void run() { + registerCancelButtonClickListener(); + if (postSwitchCallback != null) { + postSwitchCallback.run(); + } + } + }); + } break; + } + } break; + + case UI_GENERATING_PRINT_JOB: { + switch (ui) { + case UI_EDITING_PRINT_JOB: { + animateUiSwitch(R.layout.print_job_config_activity_content_editing, + new Runnable() { + @Override + public void run() { + registerPrintButtonClickListener(); + if (postSwitchCallback != null) { + postSwitchCallback.run(); + } + } + }); + } break; + } + } break; + } + + mCurrentUi = ui; + } + + private void registerPrintButtonClickListener() { + Button printButton = (Button) findViewById(R.id.print_button); + printButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + PrinterInfo printer = (PrinterInfo) mDestinationSpinner.getSelectedItem(); + if (printer != null) { + mEditor.confirmPrint(); + mController.update(); + if (!printer.equals(mDestinationSpinnerAdapter.mFakePdfPrinter)) { + FusedPrintersProvider printersLoader = (FusedPrintersProvider) + (Loader<?>) getLoaderManager().getLoader( + LOADER_ID_PRINTERS_LOADER); + if (printersLoader != null) { + printersLoader.addHistoricalPrinter(printer); + } + } + } else { + mEditor.cancel(); + PrintJobConfigActivity.this.finish(); + } + } + }); + } + + private void registerCancelButtonClickListener() { + Button cancelButton = (Button) findViewById(R.id.cancel_button); cancelButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { @@ -935,24 +1189,38 @@ public class PrintJobConfigActivity extends Activity { mEditor.cancel(); } }); + } + + private void doUiSwitch(int showLayoutId) { + ViewGroup contentContainer = (ViewGroup) findViewById(R.id.content_container); + contentContainer.removeAllViews(); + getLayoutInflater().inflate(showLayoutId, contentContainer, true); + } + + private void animateUiSwitch(int showLayoutId, final Runnable postAnimateCommand) { + // Find everything we will shuffle around. + final ViewGroup contentContainer = (ViewGroup) findViewById(R.id.content_container); + final View hidingView = contentContainer.getChildAt(0); + final View showingView = getLayoutInflater().inflate(showLayoutId, + null, false); // First animation - fade out the old content. - contentEditing.animate().alpha(0.0f).withLayer().withEndAction(new Runnable() { + hidingView.animate().alpha(0.0f).withLayer().withEndAction(new Runnable() { @Override public void run() { - contentEditing.setVisibility(View.INVISIBLE); + hidingView.setVisibility(View.INVISIBLE); // Prepare the new content with correct size and alpha. - contentGenerating.setMinimumWidth(contentContainer.getWidth()); - contentGenerating.setAlpha(0.0f); + showingView.setMinimumWidth(contentContainer.getWidth()); + showingView.setAlpha(0.0f); - // Compute how to much shrink the container to fit around the new content. + // Compute how to much shrink /stretch the content. final int widthSpec = MeasureSpec.makeMeasureSpec( - contentContainer.getWidth(), MeasureSpec.AT_MOST); + contentContainer.getWidth(), MeasureSpec.UNSPECIFIED); final int heightSpec = MeasureSpec.makeMeasureSpec( - contentContainer.getHeight(), MeasureSpec.AT_MOST); - contentGenerating.measure(widthSpec, heightSpec); - final float scaleY = (float) contentGenerating.getMeasuredHeight() + contentContainer.getHeight(), MeasureSpec.UNSPECIFIED); + showingView.measure(widthSpec, heightSpec); + final float scaleY = (float) showingView.getMeasuredHeight() / (float) contentContainer.getHeight(); // Second animation - resize the container. @@ -963,10 +1231,16 @@ public class PrintJobConfigActivity extends Activity { // Swap the old and the new content. contentContainer.removeAllViews(); contentContainer.setScaleY(1.0f); - contentContainer.addView(contentGenerating); + contentContainer.addView(showingView); // Third animation - show the new content. - contentGenerating.animate().withLayer().alpha(1.0f); + showingView.animate().withLayer().alpha(1.0f).withEndAction( + new Runnable() { + @Override + public void run() { + postAnimateCommand.run(); + } + }); } }); } @@ -975,10 +1249,6 @@ public class PrintJobConfigActivity extends Activity { public void initialize() { mEditorState = EDITOR_STATE_INITIALIZED; - if (mDestinationSpinner.getSelectedItemPosition() != AdapterView.INVALID_POSITION) { - mIgnoreNextDestinationChange = true; - mDestinationSpinner.setSelection(AdapterView.INVALID_POSITION); - } } public boolean isCancelled() { @@ -1001,6 +1271,7 @@ public class PrintJobConfigActivity extends Activity { public void confirmPrint() { mEditorState = EDITOR_STATE_CONFIRMED_PRINT; + showUi(UI_GENERATING_PRINT_JOB, null); } public boolean isPreviewConfirmed() { @@ -1046,7 +1317,79 @@ public class PrintJobConfigActivity extends Activity { return ALL_PAGES_ARRAY; } + private void bindUi() { + if (mCurrentUi != UI_EDITING_PRINT_JOB) { + return; + } + + // Content container + mContentContainer = findViewById(R.id.content_container); + + // Copies + mCopiesEditText = (EditText) findViewById(R.id.copies_edittext); + mCopiesEditText.setText(MIN_COPIES_STRING); + mCopiesEditText.addTextChangedListener(mCopiesTextWatcher); + mCopiesEditText.selectAll(); + if (!TextUtils.equals(mCopiesEditText.getText(), MIN_COPIES_STRING)) { + mIgnoreNextCopiesChange = true; + } + PrintSpoolerService.peekInstance().setPrintJobCopiesNoPersistence( + mPrintJobId, MIN_COPIES); + + // Destination. + mDestinationSpinner = (Spinner) findViewById(R.id.destination_spinner); + mDestinationSpinner.setAdapter(mDestinationSpinnerAdapter); + mDestinationSpinner.setOnItemSelectedListener(mOnItemSelectedListener); + if (mDestinationSpinnerAdapter.getCount() > 0) { + mIgnoreNextDestinationChange = true; + } + + // Media size. + mMediaSizeSpinner = (Spinner) findViewById(R.id.paper_size_spinner); + mMediaSizeSpinner.setAdapter(mMediaSizeSpinnerAdapter); + mMediaSizeSpinner.setOnItemSelectedListener(mOnItemSelectedListener); + if (mMediaSizeSpinnerAdapter.getCount() > 0) { + mIgnoreNextMediaSizeChange = true; + } + + // Color mode. + mColorModeSpinner = (Spinner) findViewById(R.id.color_spinner); + mColorModeSpinner.setAdapter(mColorModeSpinnerAdapter); + mColorModeSpinner.setOnItemSelectedListener(mOnItemSelectedListener); + if (mColorModeSpinnerAdapter.getCount() > 0) { + mIgnoreNextColorModeChange = true; + } + + // Orientation + mOrientationSpinner = (Spinner) findViewById(R.id.orientation_spinner); + mOrientationSpinner.setAdapter(mOrientationSpinnerAdapter); + mOrientationSpinner.setOnItemSelectedListener(mOnItemSelectedListener); + if (mOrientationSpinnerAdapter.getCount() > 0) { + mIgnoreNextOrientationChange = true; + } + + // Range + mRangeTitle = (TextView) findViewById(R.id.page_range_title); + mRangeEditText = (EditText) findViewById(R.id.page_range_edittext); + mRangeEditText.addTextChangedListener(mRangeTextWatcher); + + // Range options + mRangeOptionsSpinner = (Spinner) findViewById(R.id.range_options_spinner); + mRangeOptionsSpinner.setAdapter(mRangeOptionsSpinnerAdapter); + mRangeOptionsSpinner.setOnItemSelectedListener(mOnItemSelectedListener); + if (mRangeOptionsSpinnerAdapter.getCount() > 0) { + mIgnoreNextRangeOptionChange = true; + } + + // Print button + mPrintButton = (Button) findViewById(R.id.print_button); + registerPrintButtonClickListener(); + } + public void updateUi() { + if (mCurrentUi != UI_EDITING_PRINT_JOB) { + return; + } if (isPrintConfirmed() || isPreviewConfirmed() || isCancelled()) { mDestinationSpinner.setEnabled(false); mCopiesEditText.setEnabled(false); @@ -1061,14 +1404,20 @@ public class PrintJobConfigActivity extends Activity { return; } + // If a printer with capabilities is selected, then we enabled all options. + boolean allOptionsEnabled = false; final int selectedIndex = mDestinationSpinner.getSelectedItemPosition(); + if (selectedIndex >= 0) { + Object item = mDestinationSpinnerAdapter.getItem(selectedIndex); + if (item instanceof PrinterInfo) { + PrinterInfo printer = (PrinterInfo) item; + if (printer.getCapabilities() != null) { + allOptionsEnabled = true; + } + } + } - if (selectedIndex < 0 || mDestinationSpinnerAdapter.getItem( - selectedIndex).value.getCapabilities() == null) { - - // Destination - mDestinationSpinner.setEnabled(false); - + if (!allOptionsEnabled) { String minCopiesString = String.valueOf(MIN_COPIES); if (!TextUtils.equals(mCopiesEditText.getText(), minCopiesString)) { mIgnoreNextCopiesChange = true; @@ -1121,17 +1470,10 @@ public class PrintJobConfigActivity extends Activity { mPrintButton.setEnabled(false); } else { PrintAttributes defaultAttributes = mTempPrintAttributes; - PrinterInfo printer = mDestinationSpinnerAdapter.getItem(selectedIndex).value; + PrinterInfo printer = (PrinterInfo) mDestinationSpinner.getSelectedItem(); PrinterCapabilitiesInfo capabilities = printer.getCapabilities(); printer.getCapabilities().getDefaults(defaultAttributes); - // Destination - if (mDestinationSpinnerAdapter.getCount() > 1) { - mDestinationSpinner.setEnabled(true); - } else { - mDestinationSpinner.setEnabled(false); - } - // Copies mCopiesEditText.setEnabled(true); @@ -1159,9 +1501,6 @@ public class PrintJobConfigActivity extends Activity { if (mediaSizeCount <= 0) { mMediaSizeSpinner.setEnabled(false); mMediaSizeSpinner.setSelection(AdapterView.INVALID_POSITION); - } else if (mediaSizeCount == 1) { - mMediaSizeSpinner.setEnabled(false); - mMediaSizeSpinner.setSelection(0); } else { mMediaSizeSpinner.setEnabled(true); final int selectedMediaSizeIndex = Math.max(mediaSizes.indexOf( @@ -1172,6 +1511,7 @@ public class PrintJobConfigActivity extends Activity { } } } + mMediaSizeSpinner.setEnabled(true); // Color mode. final int colorModes = capabilities.getColorModes(); @@ -1210,9 +1550,6 @@ public class PrintJobConfigActivity extends Activity { if (colorModeCount <= 0) { mColorModeSpinner.setEnabled(false); mColorModeSpinner.setSelection(AdapterView.INVALID_POSITION); - } else if (colorModeCount == 1) { - mColorModeSpinner.setEnabled(false); - mColorModeSpinner.setSelection(0); } else { mColorModeSpinner.setEnabled(true); final int selectedColorModeIndex = Integer.numberOfTrailingZeros( @@ -1223,6 +1560,7 @@ public class PrintJobConfigActivity extends Activity { } } } + mColorModeSpinner.setEnabled(true); // Orientation. final int orientations = capabilities.getOrientations(); @@ -1262,9 +1600,6 @@ public class PrintJobConfigActivity extends Activity { if (orientationCount <= 0) { mOrientationSpinner.setEnabled(false); mOrientationSpinner.setSelection(AdapterView.INVALID_POSITION); - } else if (orientationCount == 1) { - mOrientationSpinner.setEnabled(false); - mOrientationSpinner.setSelection(0); } else { mOrientationSpinner.setEnabled(true); final int selectedOrientationIndex = Integer.numberOfTrailingZeros( @@ -1276,20 +1611,25 @@ public class PrintJobConfigActivity extends Activity { } } } + mOrientationSpinner.setEnabled(true); // Range options PrintDocumentInfo info = mDocument.info; if (info != null && (info.getPageCount() > 1 || info.getPageCount() == PrintDocumentInfo.PAGE_COUNT_UNKNOWN)) { mRangeOptionsSpinner.setEnabled(true); - if (mRangeOptionsSpinner.getSelectedItemPosition() > 0 - && !mRangeEditText.isEnabled()) { - mRangeEditText.setEnabled(true); - mRangeEditText.setVisibility(View.VISIBLE); - mRangeEditText.requestFocus(); - InputMethodManager imm = (InputMethodManager) - getSystemService(INPUT_METHOD_SERVICE); - imm.showSoftInput(mRangeEditText, 0); + if (mRangeOptionsSpinner.getSelectedItemPosition() > 0) { + if (!mRangeEditText.isEnabled()) { + mRangeEditText.setEnabled(true); + mRangeEditText.setVisibility(View.VISIBLE); + mRangeEditText.requestFocus(); + InputMethodManager imm = (InputMethodManager) + getSystemService(INPUT_METHOD_SERVICE); + imm.showSoftInput(mRangeEditText, 0); + } + } else { + mRangeEditText.setEnabled(false); + mRangeEditText.setVisibility(View.INVISIBLE); } final int pageCount = mDocument.info.getPageCount(); mRangeTitle.setText(getString(R.string.label_pages, @@ -1307,6 +1647,7 @@ public class PrintJobConfigActivity extends Activity { mRangeEditText.setEnabled(false); mRangeEditText.setVisibility(View.INVISIBLE); } + mRangeOptionsSpinner.setEnabled(true); // Print/Print preview if ((mRangeOptionsSpinner.getSelectedItemPosition() == 1 @@ -1333,99 +1674,7 @@ public class PrintJobConfigActivity extends Activity { mCopiesEditText.selectAll(); mCopiesEditText.requestFocus(); } - } - } - - public void addPrinters(List<PrinterInfo> addedPrinters) { - final int addedPrinterCount = addedPrinters.size(); - for (int i = 0; i < addedPrinterCount; i++) { - PrinterInfo addedPrinter = addedPrinters.get(i); - boolean duplicate = false; - final int existingPrinterCount = mDestinationSpinnerAdapter.getCount(); - for (int j = 0; j < existingPrinterCount; j++) { - PrinterInfo existingPrinter = mDestinationSpinnerAdapter.getItem(j).value; - if (addedPrinter.getId().equals(existingPrinter.getId())) { - duplicate = true; - break; - } - } - if (!duplicate) { - mDestinationSpinnerAdapter.add(new SpinnerItem<PrinterInfo>( - addedPrinter, addedPrinter.getName())); - } else { - Log.w(LOG_TAG, "Skipping a duplicate printer: " + addedPrinter); - } - } - - if (mDestinationSpinner.getSelectedItemPosition() == AdapterView.INVALID_POSITION - && mDestinationSpinnerAdapter.getCount() > 0) { - mDestinationSpinner.setSelection(0); - } - - mEditor.updateUi(); - } - - public void removePrinters(List<PrinterId> pritnerIds) { - final int printerIdCount = pritnerIds.size(); - for (int i = 0; i < printerIdCount; i++) { - PrinterId removedPrinterId = pritnerIds.get(i); - boolean removed = false; - final int existingPrinterCount = mDestinationSpinnerAdapter.getCount(); - for (int j = 0; j < existingPrinterCount; j++) { - PrinterInfo existingPrinter = mDestinationSpinnerAdapter.getItem(j).value; - if (removedPrinterId.equals(existingPrinter.getId())) { - mDestinationSpinnerAdapter.remove(mDestinationSpinnerAdapter.getItem(j)); - removed = true; - break; - } - } - if (!removed) { - Log.w(LOG_TAG, "Ignoring not added printer with id: " + removedPrinterId); - } - } - - if (mDestinationSpinner.getSelectedItemPosition() != AdapterView.INVALID_POSITION - && mDestinationSpinnerAdapter.getCount() == 0) { - mDestinationSpinner.setSelection(AdapterView.INVALID_POSITION); - } - } - - @SuppressWarnings("unchecked") - public void updatePrinters(List<PrinterInfo> pritners) { - SpinnerItem<PrinterInfo> selectedItem = - (SpinnerItem<PrinterInfo>) mDestinationSpinner.getSelectedItem(); - PrinterId selectedPrinterId = (selectedItem != null) - ? selectedItem.value.getId() : null; - - boolean updated = false; - - final int printerCount = pritners.size(); - for (int i = 0; i < printerCount; i++) { - PrinterInfo updatedPrinter = pritners.get(i); - final int existingPrinterCount = mDestinationSpinnerAdapter.getCount(); - for (int j = 0; j < existingPrinterCount; j++) { - PrinterInfo existingPrinter = mDestinationSpinnerAdapter.getItem(j).value; - if (updatedPrinter.getId().equals(existingPrinter.getId())) { - existingPrinter.copyFrom(updatedPrinter); - updated = true; - if (selectedPrinterId != null - && selectedPrinterId.equals(updatedPrinter.getId())) { - // The selected printer was updated. We simulate a fake - // selection to reuse the normal printer change handling. - mOnItemSelectedListener.onItemSelected(mDestinationSpinner, - mDestinationSpinner.getSelectedView(), - mDestinationSpinner.getSelectedItemPosition(), - mDestinationSpinner.getSelectedItemId()); - // TODO: This will reset the UI to the defaults for the - // printer. We may need to revisit this. - - } - break; - } - } - } - if (updated) { - mDestinationSpinnerAdapter.notifyDataSetChanged(); + mCopiesEditText.setEnabled(true); } } @@ -1455,10 +1704,52 @@ public class PrintJobConfigActivity extends Activity { } } - private final class DestinationAdapter extends ArrayAdapter<SpinnerItem<PrinterInfo>> { + private final class DestinationAdapter extends BaseAdapter + implements LoaderManager.LoaderCallbacks<List<PrinterInfo>>{ + private final List<PrinterInfo> mPrinters = new ArrayList<PrinterInfo>(); + + public final PrinterInfo mFakePdfPrinter; public DestinationAdapter() { - super( PrintJobConfigActivity.this, R.layout.spinner_dropdown_item); + getLoaderManager().initLoader(LOADER_ID_PRINTERS_LOADER, null, this); + mFakePdfPrinter = createFakePdfPrinter(); + } + + @Override + public int getCount() { + return Math.max(Math.min(mPrinters.size(), DEST_ADAPTER_MAX_ITEM_COUNT), + DEST_ADAPTER_MIN_ITEM_COUNT); + } + + @Override + public Object getItem(int position) { + if (position == DEST_ADAPTER_POSITION_SAVE_AS_PDF) { + return mFakePdfPrinter; + } + if (!mPrinters.isEmpty()) { + if (position < DEST_ADAPTER_POSITION_SAVE_AS_PDF) { + return mPrinters.get(position); + } else if (position > DEST_ADAPTER_POSITION_SAVE_AS_PDF + && position < getCount() - 1) { + return mPrinters.get(position - 1); + } + } + return null; + } + + @Override + public long getItemId(int position) { + if (position == DEST_ADAPTER_POSITION_SAVE_AS_PDF) { + return DEST_ADAPTER_ITEM_ID_SAVE_AS_PDF; + } + if (mPrinters.isEmpty()) { + if (position == DEST_ADAPTER_POSITION_SEARCHING_FOR_PRINTERS) { + return DEST_ADAPTER_ITEM_ID_SEARCHING_FOR_PRINTERS; + } + } else if (position == getCount() - 1) { + return DEST_ADAPTER_ITEM_ID_ALL_PRINTERS; + } + return position; } @Override @@ -1474,149 +1765,91 @@ public class PrintJobConfigActivity extends Activity { R.layout.spinner_dropdown_item, parent, false); } - PrinterInfo printerInfo = getItem(position).value; - TextView title = (TextView) convertView.findViewById(R.id.title); - title.setText(printerInfo.getName()); - - try { - TextView subtitle = (TextView) - convertView.findViewById(R.id.subtitle); - PackageManager pm = getPackageManager(); - PackageInfo packageInfo = pm.getPackageInfo( - printerInfo.getId().getServiceName().getPackageName(), 0); - subtitle.setText(packageInfo.applicationInfo.loadLabel(pm)); - subtitle.setVisibility(View.VISIBLE); - } catch (NameNotFoundException nnfe) { - /* ignore */ - } - - return convertView; - } - } - } - - private static final class PrinterDiscoverySessionObserver - extends IPrinterDiscoverySessionObserver.Stub { - private static final int MSG_SET_CONTROLLER = 1; - private static final int MSG_ON_PRINTERS_ADDED = 2; - private static final int MSG_ON_PRINTERS_REMOVED = 3; - private static final int MSG_ON_PRINTERS_UPDATED = 4; - - private Handler mHandler; - private Editor mEditor; - private IPrinterDiscoverySessionController mController; - - @SuppressWarnings("unchecked") - public PrinterDiscoverySessionObserver(Editor editor, Looper looper) { - mEditor = editor; - mHandler = new Handler(looper, null, true) { - @Override - public void handleMessage(Message message) { - switch (message.what) { - case MSG_SET_CONTROLLER: { - mController = (IPrinterDiscoverySessionController) message.obj; - // TODO: This should be cleaned up - List<PrinterId> printerIds = Collections.emptyList(); - try { - mController.open(printerIds); - } catch (RemoteException e) { - Log.e(LOG_TAG, "Error starting printer discovery"); - } - } break; - - case MSG_ON_PRINTERS_ADDED: { - List<PrinterInfo> printers = (List<PrinterInfo>) message.obj; - mEditor.addPrinters(printers); - } break; - - case MSG_ON_PRINTERS_REMOVED: { - List<PrinterId> printerIds = (List<PrinterId>) message.obj; - mEditor.removePrinters(printerIds); - } break; + CharSequence title = null; + CharSequence subtitle = null; - case MSG_ON_PRINTERS_UPDATED: { - List<PrinterInfo> printers = (List<PrinterInfo>) message.obj; - mEditor.updatePrinters(printers); - } break; + if (mPrinters.isEmpty() + && position == DEST_ADAPTER_POSITION_SEARCHING_FOR_PRINTERS) { + title = getString(R.string.searching_for_printers); + } else { + if (position == DEST_ADAPTER_POSITION_SAVE_AS_PDF) { + PrinterInfo printer = (PrinterInfo) getItem(position); + title = printer.getName(); + } else if (position == getCount() - 1) { + title = getString(R.string.all_printers); + } else { + PrinterInfo printer = (PrinterInfo) getItem(position); + title = printer.getName(); + try { + PackageInfo packageInfo = getPackageManager().getPackageInfo( + printer.getId().getServiceName().getPackageName(), 0); + subtitle = packageInfo.applicationInfo.loadLabel(getPackageManager()); + } catch (NameNotFoundException nnfe) { + /* ignore */ + } } } - }; - } - public void open(List<PrinterId> priorityList) { - if (mController != null) { - try { - mController.open(priorityList); - } catch (RemoteException re) { - Log.e(LOG_TAG, "Error closing printer discovery session", re); - } - } - } - - public void close() { - if (mController != null) { - try { - mController.close(); - } catch (RemoteException re) { - Log.e(LOG_TAG, "Error closing printer discovery session", re); - } - } - } + TextView titleView = (TextView) convertView.findViewById(R.id.title); + titleView.setText(title); - public void requestPrinterUpdate(PrinterId printerId) { - if (mController != null) { - try { - mController.requestPrinterUpdate(printerId); - } catch (RemoteException re) { - Log.e(LOG_TAG, "Error requestin printer update", re); - } - } - } - - @Override - public void setController(IPrinterDiscoverySessionController controller) { - synchronized (this) { - if (mHandler != null) { - mHandler.obtainMessage(MSG_SET_CONTROLLER, controller) - .sendToTarget(); + TextView subtitleView = (TextView) convertView.findViewById(R.id.subtitle); + if (!TextUtils.isEmpty(subtitle)) { + subtitleView.setText(subtitle); + subtitleView.setVisibility(View.VISIBLE); + } else { + subtitleView.setText(null); + subtitleView.setVisibility(View.GONE); } - } - } - @Override - public void onPrintersAdded(List<PrinterInfo> printers) { - synchronized (this) { - if (mHandler != null) { - mHandler.obtainMessage(MSG_ON_PRINTERS_ADDED, printers) - .sendToTarget(); - } + return convertView; } - } - @Override - public void onPrintersRemoved(List<PrinterId> printers) { - synchronized (this) { - if (mHandler != null) { - mHandler.obtainMessage(MSG_ON_PRINTERS_REMOVED, printers) - .sendToTarget(); + @Override + public Loader<List<PrinterInfo>> onCreateLoader(int id, Bundle args) { + if (id == LOADER_ID_PRINTERS_LOADER) { + return new FusedPrintersProvider(PrintJobConfigActivity.this); } + return null; } - } - @Override - public void onPrintersUpdated(List<PrinterInfo> printers) { - synchronized (this) { - if (mHandler != null) { - mHandler.obtainMessage(MSG_ON_PRINTERS_UPDATED, printers) - .sendToTarget(); - } + @Override + public void onLoadFinished(Loader<List<PrinterInfo>> loader, + List<PrinterInfo> printers) { + mPrinters.clear(); + mPrinters.addAll(printers); + notifyDataSetChanged(); } - } - public void destroy() { - synchronized (this) { - mHandler = null; - mEditor = null; + @Override + public void onLoaderReset(Loader<List<PrinterInfo>> loader) { + mPrinters.clear(); + notifyDataSetInvalidated(); + } + + private PrinterInfo createFakePdfPrinter() { + PrinterId printerId = new PrinterId(getComponentName(), "PDF printer"); + + PrinterCapabilitiesInfo capabilities = + new PrinterCapabilitiesInfo.Builder(printerId) + .addMediaSize(MediaSize.createMediaSize(getPackageManager(), + MediaSize.ISO_A4), true) + .addMediaSize(MediaSize.createMediaSize(getPackageManager(), + MediaSize.NA_LETTER), false) + .addResolution(new Resolution("PDF resolution", "PDF resolution", + 300, 300), true) + .setColorModes(PrintAttributes.COLOR_MODE_COLOR + | PrintAttributes.COLOR_MODE_MONOCHROME, + PrintAttributes.COLOR_MODE_COLOR) + .setOrientations(PrintAttributes.ORIENTATION_PORTRAIT + | PrintAttributes.ORIENTATION_LANDSCAPE, + PrintAttributes.ORIENTATION_PORTRAIT) + .create(); + + return new PrinterInfo.Builder(printerId, getString(R.string.save_as_pdf), + PrinterInfo.STATUS_READY) + .setCapabilities(capabilities) + .create(); } } } diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java deleted file mode 100644 index 1b8b81a..0000000 --- a/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java +++ /dev/null @@ -1,979 +0,0 @@ -/* - * 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.printspooler; - -import android.content.ComponentName; -import android.content.Context; -import android.os.AsyncTask; -import android.os.ParcelFileDescriptor; -import android.print.IPrintClient; -import android.print.IPrinterDiscoverySessionObserver; -import android.print.PageRange; -import android.print.PrintAttributes; -import android.print.PrintAttributes.Margins; -import android.print.PrintAttributes.MediaSize; -import android.print.PrintAttributes.Resolution; -import android.print.PrintAttributes.Tray; -import android.print.PrintDocumentInfo; -import android.print.PrintJobInfo; -import android.print.PrintManager; -import android.print.PrinterId; -import android.print.PrinterInfo; -import android.util.AtomicFile; -import android.util.Log; -import android.util.Slog; -import android.util.Xml; - -import com.android.internal.util.FastXmlSerializer; - -import libcore.io.IoUtils; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlSerializer; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -public class PrintSpooler { - - private static final String LOG_TAG = "PrintSpooler"; - - private static final boolean DEBUG_PRINT_JOB_LIFECYCLE = true; - - private static final boolean DEBUG_PERSISTENCE = true; - - private static final boolean PERSISTNECE_MANAGER_ENABLED = true; - - private static final String PRINT_FILE_EXTENSION = "pdf"; - - private static int sPrintJobIdCounter; - - private static final Object sLock = new Object(); - - private static PrintSpooler sInstance; - - private final Object mLock = new Object(); - - private final List<PrintJobInfo> mPrintJobs = new ArrayList<PrintJobInfo>(); - - private final PersistenceManager mPersistanceManager; - - private final NotificationController mNotificationController; - - private final PrintSpoolerService mService; - - public static void destroyInstance() { - synchronized (sLock) { - sInstance = null; - } - } - - public static void createInstance(PrintSpoolerService service) { - synchronized (sLock) { - sInstance = new PrintSpooler(service); - } - } - - public static PrintSpooler peekInstance() { - synchronized (sLock) { - return sInstance; - } - } - - private PrintSpooler(PrintSpoolerService service) { - mService = service; - mPersistanceManager = new PersistenceManager(service); - mNotificationController = new NotificationController(service); - synchronized (mLock) { - mPersistanceManager.readStateLocked(); - handleReadPrintJobsLocked(); - } - } - - public List<PrintJobInfo> getPrintJobInfos(ComponentName componentName, - int state, int appId) { - List<PrintJobInfo> foundPrintJobs = null; - synchronized (mLock) { - final int printJobCount = mPrintJobs.size(); - for (int i = 0; i < printJobCount; i++) { - PrintJobInfo printJob = mPrintJobs.get(i); - PrinterId printerId = printJob.getPrinterId(); - final boolean sameComponent = (componentName == null - || (printerId != null - && componentName.equals(printerId.getServiceName()))); - final boolean sameAppId = appId == PrintManager.APP_ID_ANY - || printJob.getAppId() == appId; - final boolean sameState = (state == printJob.getState()) - || (state == PrintJobInfo.STATE_ANY) - || (state == PrintJobInfo.STATE_ANY_VISIBLE_TO_CLIENTS - && printJob.getState() > PrintJobInfo.STATE_CREATED); - if (sameComponent && sameAppId && sameState) { - if (foundPrintJobs == null) { - foundPrintJobs = new ArrayList<PrintJobInfo>(); - } - foundPrintJobs.add(printJob); - } - } - } - return foundPrintJobs; - } - - public PrintJobInfo getPrintJobInfo(int printJobId, int appId) { - synchronized (mLock) { - final int printJobCount = mPrintJobs.size(); - for (int i = 0; i < printJobCount; i++) { - PrintJobInfo printJob = mPrintJobs.get(i); - if (printJob.getId() == printJobId - && (appId == PrintManager.APP_ID_ANY - || appId == printJob.getAppId())) { - return printJob; - } - } - return null; - } - } - - public PrintJobInfo createPrintJob(CharSequence label, IPrintClient client, - PrintAttributes attributes, int appId) { - synchronized (mLock) { - final int printJobId = generatePrintJobIdLocked(); - PrintJobInfo printJob = new PrintJobInfo(); - printJob.setId(printJobId); - printJob.setAppId(appId); - printJob.setLabel(label); - printJob.setAttributes(attributes); - printJob.setState(PrintJobInfo.STATE_CREATED); - - addPrintJobLocked(printJob); - - return printJob; - } - } - - private void handleReadPrintJobsLocked() { - final int printJobCount = mPrintJobs.size(); - for (int i = 0; i < printJobCount; i++) { - PrintJobInfo printJob = mPrintJobs.get(i); - - // Update the notification. - mNotificationController.onPrintJobStateChanged(printJob); - - switch (printJob.getState()) { - case PrintJobInfo.STATE_QUEUED: - case PrintJobInfo.STATE_STARTED: { - // We have a print job that was queued or started in the past - // but the device battery died or a crash occurred. In this case - // we assume the print job failed and let the user decide whether - // to restart the job or just - setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED, - mService.getString(R.string.no_connection_to_printer)); - } break; - } - } - } - - public void checkAllPrintJobsHandled() { - synchronized (mLock) { - if (!hasActivePrintJobsLocked()) { - notifyOnAllPrintJobsHandled(); - } - } - } - - public void createPrinterDiscoverySession(IPrinterDiscoverySessionObserver observer) { - mService.createPrinterDiscoverySession(observer); - } - - private int generatePrintJobIdLocked() { - int printJobId = sPrintJobIdCounter++; - while (isDuplicatePrintJobId(printJobId)) { - printJobId = sPrintJobIdCounter++; - } - return printJobId; - } - - private boolean isDuplicatePrintJobId(int printJobId) { - final int printJobCount = mPrintJobs.size(); - for (int j = 0; j < printJobCount; j++) { - PrintJobInfo printJob = mPrintJobs.get(j); - if (printJob.getId() == printJobId) { - return true; - } - } - return false; - } - - public void writePrintJobData(final ParcelFileDescriptor fd, final int printJobId) { - final PrintJobInfo printJob; - synchronized (mLock) { - printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); - } - new AsyncTask<Void, Void, Void>() { - @Override - protected Void doInBackground(Void... params) { - FileInputStream in = null; - FileOutputStream out = null; - try { - if (printJob != null) { - File file = generateFileForPrintJob(printJobId); - in = new FileInputStream(file); - out = new FileOutputStream(fd.getFileDescriptor()); - } - final byte[] buffer = new byte[8192]; - while (true) { - final int readByteCount = in.read(buffer); - if (readByteCount < 0) { - return null; - } - out.write(buffer, 0, readByteCount); - } - } catch (FileNotFoundException fnfe) { - Log.e(LOG_TAG, "Error writing print job data!", fnfe); - } catch (IOException ioe) { - Log.e(LOG_TAG, "Error writing print job data!", ioe); - } finally { - IoUtils.closeQuietly(in); - IoUtils.closeQuietly(out); - IoUtils.closeQuietly(fd); - } - Log.i(LOG_TAG, "[END WRITE]"); - return null; - } - }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null); - } - - public File generateFileForPrintJob(int printJobId) { - return new File(mService.getFilesDir(), "print_job_" - + printJobId + "." + PRINT_FILE_EXTENSION); - } - - private void addPrintJobLocked(PrintJobInfo printJob) { - mPrintJobs.add(printJob); - if (DEBUG_PRINT_JOB_LIFECYCLE) { - Slog.i(LOG_TAG, "[ADD] " + printJob); - } - } - - private void removePrintJobLocked(PrintJobInfo printJob) { - if (mPrintJobs.remove(printJob)) { - generateFileForPrintJob(printJob.getId()).delete(); - if (DEBUG_PRINT_JOB_LIFECYCLE) { - Slog.i(LOG_TAG, "[REMOVE] " + printJob); - } - } - } - - public boolean setPrintJobState(int printJobId, int state, CharSequence error) { - boolean success = false; - - synchronized (mLock) { - PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); - if (printJob != null) { - success = true; - - printJob.setState(state); - printJob.setFailureReason(error); - mNotificationController.onPrintJobStateChanged(printJob); - - if (DEBUG_PRINT_JOB_LIFECYCLE) { - Slog.i(LOG_TAG, "[STATE CHANGED] " + printJob); - } - - switch (state) { - case PrintJobInfo.STATE_COMPLETED: - case PrintJobInfo.STATE_CANCELED: - removePrintJobLocked(printJob); - // $fall-through$ - case PrintJobInfo.STATE_FAILED: { - PrinterId printerId = printJob.getPrinterId(); - if (printerId != null) { - ComponentName service = printerId.getServiceName(); - if (!hasActivePrintJobsForServiceLocked(service)) { - mService.onAllPrintJobsForServiceHandled(service); - } - } - } break; - - case PrintJobInfo.STATE_QUEUED: { - mService.onPrintJobQueued(new PrintJobInfo(printJob)); - } break; - } - - if (shouldPersistPrintJob(printJob)) { - mPersistanceManager.writeStateLocked(); - } - - if (!hasActivePrintJobsLocked()) { - notifyOnAllPrintJobsHandled(); - } - } - } - - return success; - } - - public boolean hasActivePrintJobsLocked() { - final int printJobCount = mPrintJobs.size(); - for (int i = 0; i < printJobCount; i++) { - PrintJobInfo printJob = mPrintJobs.get(i); - if (isActiveState(printJob.getState())) { - return true; - } - } - return false; - } - - public boolean hasActivePrintJobsForServiceLocked(ComponentName service) { - final int printJobCount = mPrintJobs.size(); - for (int i = 0; i < printJobCount; i++) { - PrintJobInfo printJob = mPrintJobs.get(i); - if (isActiveState(printJob.getState()) - && printJob.getPrinterId().getServiceName().equals(service)) { - return true; - } - } - return false; - } - - private static boolean isActiveState(int printJobState) { - return printJobState == PrintJobInfo.STATE_CREATED - || printJobState == PrintJobInfo.STATE_QUEUED - || printJobState == PrintJobInfo.STATE_STARTED; - } - - public boolean setPrintJobTag(int printJobId, String tag) { - synchronized (mLock) { - PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); - if (printJob != null) { - String printJobTag = printJob.getTag(); - if (printJobTag == null) { - if (tag == null) { - return false; - } - } else if (printJobTag.equals(tag)) { - return false; - } - printJob.setTag(tag); - if (shouldPersistPrintJob(printJob)) { - mPersistanceManager.writeStateLocked(); - } - return true; - } - } - return false; - } - - public void setPrintJobCopiesNoPersistence(int printJobId, int copies) { - synchronized (mLock) { - PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); - if (printJob != null) { - printJob.setCopies(copies); - } - } - } - - public void setPrintJobPrintDocumentInfoNoPersistence(int printJobId, PrintDocumentInfo info) { - synchronized (mLock) { - PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); - if (printJob != null) { - printJob.setDocumentInfo(info); - } - } - } - - public void setPrintJobAttributesNoPersistence(int printJobId, PrintAttributes attributes) { - synchronized (mLock) { - PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); - if (printJob != null) { - printJob.setAttributes(attributes); - } - } - } - - public void setPrintJobPrinterNoPersistence(int printJobId, PrinterInfo printer) { - synchronized (mLock) { - PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); - if (printJob != null) { - printJob.setPrinterId(printer.getId()); - printJob.setPrinterName(printer.getName()); - } - } - } - - public void setPrintJobPagesNoPersistence(int printJobId, PageRange[] pages) { - synchronized (mLock) { - PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); - if (printJob != null) { - printJob.setPages(pages); - } - } - } - - private boolean shouldPersistPrintJob(PrintJobInfo printJob) { - return printJob.getState() >= PrintJobInfo.STATE_QUEUED; - } - - private void notifyOnAllPrintJobsHandled() { - // This has to run on the tread that is persisting the current state - // since this call may result in the system unbinding from the spooler - // and as a result the spooler process may get killed before the write - // completes. - new AsyncTask<Void, Void, Void>() { - @Override - protected Void doInBackground(Void... params) { - mService.onAllPrintJobsHandled(); - return null; - } - }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null); - } - - private final class PersistenceManager { - private static final String PERSIST_FILE_NAME = "print_spooler_state.xml"; - - private static final String TAG_SPOOLER = "spooler"; - private static final String TAG_JOB = "job"; - - private static final String TAG_PRINTER_ID = "printerId"; - private static final String TAG_PAGE_RANGE = "pageRange"; - private static final String TAG_ATTRIBUTES = "attributes"; - private static final String TAG_DOCUMENT_INFO = "documentInfo"; - - private static final String ATTR_ID = "id"; - private static final String ATTR_LABEL = "label"; - private static final String ATTR_STATE = "state"; - private static final String ATTR_APP_ID = "appId"; - private static final String ATTR_USER_ID = "userId"; - private static final String ATTR_TAG = "tag"; - private static final String ATTR_COPIES = "copies"; - - private static final String TAG_MEDIA_SIZE = "mediaSize"; - private static final String TAG_RESOLUTION = "resolution"; - private static final String TAG_MARGINS = "margins"; - private static final String TAG_INPUT_TRAY = "inputTray"; - private static final String TAG_OUTPUT_TRAY = "outputTray"; - - private static final String ATTR_DUPLEX_MODE = "duplexMode"; - private static final String ATTR_COLOR_MODE = "colorMode"; - private static final String ATTR_FITTING_MODE = "fittingMode"; - private static final String ATTR_ORIENTATION = "orientation"; - - private static final String ATTR_PRINTER_NAME = "printerName"; - private static final String ATTR_SERVICE_NAME = "serviceName"; - - private static final String ATTR_WIDTH_MILS = "widthMils"; - private static final String ATTR_HEIGHT_MILS = "heightMils"; - - private static final String ATTR_HORIZONTAL_DPI = "horizontalDip"; - private static final String ATTR_VERTICAL_DPI = "verticalDpi"; - - private static final String ATTR_LEFT_MILS = "leftMils"; - private static final String ATTR_TOP_MILS = "topMils"; - private static final String ATTR_RIGHT_MILS = "rightMils"; - private static final String ATTR_BOTTOM_MILS = "bottomMils"; - - private static final String ATTR_START = "start"; - private static final String ATTR_END = "end"; - - private static final String ATTR_NAME = "name"; - private static final String ATTR_PAGE_COUNT = "pageCount"; - private static final String ATTR_CONTENT_TYPE = "contentType"; - - private final AtomicFile mStatePersistFile; - - private boolean mWriteStateScheduled; - - private PersistenceManager(Context context) { - mStatePersistFile = new AtomicFile(new File(context.getFilesDir(), - PERSIST_FILE_NAME)); - } - - public void writeStateLocked() { - if (!PERSISTNECE_MANAGER_ENABLED) { - return; - } - if (mWriteStateScheduled) { - return; - } - mWriteStateScheduled = true; - new AsyncTask<Void, Void, Void>() { - @Override - protected Void doInBackground(Void... params) { - synchronized (mLock) { - mWriteStateScheduled = false; - doWriteStateLocked(); - } - return null; - } - }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null); - } - - private void doWriteStateLocked() { - if (DEBUG_PERSISTENCE) { - Log.i(LOG_TAG, "[PERSIST START]"); - } - FileOutputStream out = null; - try { - out = mStatePersistFile.startWrite(); - - XmlSerializer serializer = new FastXmlSerializer(); - serializer.setOutput(out, "utf-8"); - serializer.startDocument(null, true); - serializer.startTag(null, TAG_SPOOLER); - - List<PrintJobInfo> printJobs = mPrintJobs; - - final int printJobCount = printJobs.size(); - for (int j = 0; j < printJobCount; j++) { - PrintJobInfo printJob = printJobs.get(j); - - final int state = printJob.getState(); - if (state < PrintJobInfo.STATE_QUEUED - || state > PrintJobInfo.STATE_CANCELED) { - continue; - } - - serializer.startTag(null, TAG_JOB); - - serializer.attribute(null, ATTR_ID, String.valueOf(printJob.getId())); - serializer.attribute(null, ATTR_LABEL, printJob.getLabel().toString()); - serializer.attribute(null, ATTR_STATE, String.valueOf(printJob.getState())); - serializer.attribute(null, ATTR_APP_ID, String.valueOf(printJob.getAppId())); - serializer.attribute(null, ATTR_USER_ID, String.valueOf(printJob.getUserId())); - String tag = printJob.getTag(); - if (tag != null) { - serializer.attribute(null, ATTR_TAG, tag); - } - serializer.attribute(null, ATTR_COPIES, String.valueOf(printJob.getCopies())); - - PrinterId printerId = printJob.getPrinterId(); - if (printerId != null) { - serializer.startTag(null, TAG_PRINTER_ID); - serializer.attribute(null, ATTR_PRINTER_NAME, printerId.getLocalId()); - serializer.attribute(null, ATTR_SERVICE_NAME, printerId.getServiceName() - .flattenToString()); - serializer.endTag(null, TAG_PRINTER_ID); - } - - PageRange[] pages = printJob.getPages(); - if (pages != null) { - for (int i = 0; i < pages.length; i++) { - serializer.startTag(null, TAG_PAGE_RANGE); - serializer.attribute(null, ATTR_START, String.valueOf( - pages[i].getStart())); - serializer.attribute(null, ATTR_END, String.valueOf( - pages[i].getEnd())); - serializer.endTag(null, TAG_PAGE_RANGE); - } - } - - PrintAttributes attributes = printJob.getAttributes(); - if (attributes != null) { - serializer.startTag(null, TAG_ATTRIBUTES); - - final int duplexMode = attributes.getDuplexMode(); - serializer.attribute(null, ATTR_DUPLEX_MODE, - String.valueOf(duplexMode)); - - final int colorMode = attributes.getColorMode(); - serializer.attribute(null, ATTR_COLOR_MODE, - String.valueOf(colorMode)); - - final int fittingMode = attributes.getFittingMode(); - serializer.attribute(null, ATTR_FITTING_MODE, - String.valueOf(fittingMode)); - - final int orientation = attributes.getOrientation(); - serializer.attribute(null, ATTR_ORIENTATION, - String.valueOf(orientation)); - - MediaSize mediaSize = attributes.getMediaSize(); - if (mediaSize != null) { - serializer.startTag(null, TAG_MEDIA_SIZE); - serializer.attribute(null, ATTR_ID, mediaSize.getId()); - serializer.attribute(null, ATTR_LABEL, mediaSize.getLabel() - .toString()); - serializer.attribute(null, ATTR_WIDTH_MILS, String.valueOf( - mediaSize.getWidthMils())); - serializer.attribute(null, ATTR_HEIGHT_MILS,String.valueOf( - mediaSize.getHeightMils())); - serializer.endTag(null, TAG_MEDIA_SIZE); - } - - Resolution resolution = attributes.getResolution(); - if (resolution != null) { - serializer.startTag(null, TAG_RESOLUTION); - serializer.attribute(null, ATTR_ID, resolution.getId()); - serializer.attribute(null, ATTR_LABEL, resolution.getLabel() - .toString()); - serializer.attribute(null, ATTR_HORIZONTAL_DPI, String.valueOf( - resolution.getHorizontalDpi())); - serializer.attribute(null, ATTR_VERTICAL_DPI, String.valueOf( - resolution.getVerticalDpi())); - serializer.endTag(null, TAG_RESOLUTION); - } - - Margins margins = attributes.getMargins(); - if (margins != null) { - serializer.startTag(null, TAG_MARGINS); - serializer.attribute(null, ATTR_LEFT_MILS, String.valueOf( - margins.getLeftMils())); - serializer.attribute(null, ATTR_TOP_MILS, String.valueOf( - margins.getTopMils())); - serializer.attribute(null, ATTR_RIGHT_MILS, String.valueOf( - margins.getRightMils())); - serializer.attribute(null, ATTR_BOTTOM_MILS, String.valueOf( - margins.getBottomMils())); - serializer.endTag(null, TAG_MARGINS); - } - - Tray inputTray = attributes.getInputTray(); - if (inputTray != null) { - serializer.startTag(null, TAG_INPUT_TRAY); - serializer.attribute(null, ATTR_ID, inputTray.getId()); - serializer.attribute(null, ATTR_LABEL, inputTray.getLabel() - .toString()); - serializer.endTag(null, TAG_INPUT_TRAY); - } - - Tray outputTray = attributes.getOutputTray(); - if (outputTray != null) { - serializer.startTag(null, TAG_OUTPUT_TRAY); - serializer.attribute(null, ATTR_ID, outputTray.getId()); - serializer.attribute(null, ATTR_LABEL, outputTray.getLabel() - .toString()); - serializer.endTag(null, TAG_OUTPUT_TRAY); - } - - serializer.endTag(null, TAG_ATTRIBUTES); - } - - PrintDocumentInfo documentInfo = printJob.getDocumentInfo(); - if (documentInfo != null) { - serializer.startTag(null, TAG_DOCUMENT_INFO); - serializer.attribute(null, ATTR_NAME, documentInfo.getName()); - serializer.attribute(null, ATTR_CONTENT_TYPE, String.valueOf( - documentInfo.getContentType())); - serializer.attribute(null, ATTR_PAGE_COUNT, String.valueOf( - documentInfo.getPageCount())); - serializer.endTag(null, TAG_DOCUMENT_INFO); - } - - serializer.endTag(null, TAG_JOB); - - if (DEBUG_PERSISTENCE) { - Log.i(LOG_TAG, "[PERSISTED] " + printJob); - } - } - - serializer.endTag(null, TAG_SPOOLER); - serializer.endDocument(); - mStatePersistFile.finishWrite(out); - if (DEBUG_PERSISTENCE) { - Log.i(LOG_TAG, "[PERSIST END]"); - } - } catch (IOException e) { - Slog.w(LOG_TAG, "Failed to write state, restoring backup.", e); - mStatePersistFile.failWrite(out); - } finally { - if (out != null) { - try { - out.close(); - } catch (IOException ioe) { - /* ignore */ - } - } - } - } - - public void readStateLocked() { - if (!PERSISTNECE_MANAGER_ENABLED) { - return; - } - FileInputStream in = null; - try { - in = mStatePersistFile.openRead(); - } catch (FileNotFoundException e) { - Log.i(LOG_TAG, "No existing print spooler state."); - return; - } - try { - XmlPullParser parser = Xml.newPullParser(); - parser.setInput(in, null); - parseState(parser); - } catch (IllegalStateException ise) { - Slog.w(LOG_TAG, "Failed parsing ", ise); - } catch (NullPointerException npe) { - Slog.w(LOG_TAG, "Failed parsing ", npe); - } catch (NumberFormatException nfe) { - Slog.w(LOG_TAG, "Failed parsing ", nfe); - } catch (XmlPullParserException xppe) { - Slog.w(LOG_TAG, "Failed parsing ", xppe); - } catch (IOException ioe) { - Slog.w(LOG_TAG, "Failed parsing ", ioe); - } catch (IndexOutOfBoundsException iobe) { - Slog.w(LOG_TAG, "Failed parsing ", iobe); - } finally { - try { - in.close(); - } catch (IOException ioe) { - /* ignore */ - } - } - } - - private void parseState(XmlPullParser parser) - throws IOException, XmlPullParserException { - parser.next(); - skipEmptyTextTags(parser); - expect(parser, XmlPullParser.START_TAG, TAG_SPOOLER); - parser.next(); - - while (parsePrintJob(parser)) { - parser.next(); - } - - skipEmptyTextTags(parser); - expect(parser, XmlPullParser.END_TAG, TAG_SPOOLER); - } - - private boolean parsePrintJob(XmlPullParser parser) - throws IOException, XmlPullParserException { - skipEmptyTextTags(parser); - if (!accept(parser, XmlPullParser.START_TAG, TAG_JOB)) { - return false; - } - - PrintJobInfo printJob = new PrintJobInfo(); - - final int printJobId = Integer.parseInt(parser.getAttributeValue(null, ATTR_ID)); - printJob.setId(printJobId); - String label = parser.getAttributeValue(null, ATTR_LABEL); - printJob.setLabel(label); - final int state = Integer.parseInt(parser.getAttributeValue(null, ATTR_STATE)); - printJob.setState(state); - final int appId = Integer.parseInt(parser.getAttributeValue(null, ATTR_APP_ID)); - printJob.setAppId(appId); - final int userId = Integer.parseInt(parser.getAttributeValue(null, ATTR_USER_ID)); - printJob.setUserId(userId); - String tag = parser.getAttributeValue(null, ATTR_TAG); - printJob.setTag(tag); - String copies = parser.getAttributeValue(null, ATTR_COPIES); - printJob.setCopies(Integer.parseInt(copies)); - - parser.next(); - - skipEmptyTextTags(parser); - if (accept(parser, XmlPullParser.START_TAG, TAG_PRINTER_ID)) { - String localId = parser.getAttributeValue(null, ATTR_PRINTER_NAME); - ComponentName service = ComponentName.unflattenFromString(parser.getAttributeValue( - null, ATTR_SERVICE_NAME)); - printJob.setPrinterId(new PrinterId(service, localId)); - parser.next(); - skipEmptyTextTags(parser); - expect(parser, XmlPullParser.END_TAG, TAG_PRINTER_ID); - parser.next(); - } - - skipEmptyTextTags(parser); - List<PageRange> pageRanges = null; - while (accept(parser, XmlPullParser.START_TAG, TAG_PAGE_RANGE)) { - final int start = Integer.parseInt(parser.getAttributeValue(null, ATTR_START)); - final int end = Integer.parseInt(parser.getAttributeValue(null, ATTR_END)); - PageRange pageRange = new PageRange(start, end); - if (pageRanges == null) { - pageRanges = new ArrayList<PageRange>(); - } - pageRanges.add(pageRange); - parser.next(); - skipEmptyTextTags(parser); - expect(parser, XmlPullParser.END_TAG, TAG_PAGE_RANGE); - parser.next(); - } - if (pageRanges != null) { - PageRange[] pageRangesArray = new PageRange[pageRanges.size()]; - pageRanges.toArray(pageRangesArray); - printJob.setPages(pageRangesArray); - } - - skipEmptyTextTags(parser); - if (accept(parser, XmlPullParser.START_TAG, TAG_ATTRIBUTES)) { - - PrintAttributes.Builder builder = new PrintAttributes.Builder(); - - String duplexMode = parser.getAttributeValue(null, ATTR_DUPLEX_MODE); - builder.setDuplexMode(Integer.parseInt(duplexMode)); - - String colorMode = parser.getAttributeValue(null, ATTR_COLOR_MODE); - builder.setColorMode(Integer.parseInt(colorMode)); - - String fittingMode = parser.getAttributeValue(null, ATTR_FITTING_MODE); - builder.setFittingMode(Integer.parseInt(fittingMode)); - - String orientation = parser.getAttributeValue(null, ATTR_ORIENTATION); - builder.setOrientation(Integer.parseInt(orientation)); - - parser.next(); - - skipEmptyTextTags(parser); - if (accept(parser, XmlPullParser.START_TAG, TAG_MEDIA_SIZE)) { - String id = parser.getAttributeValue(null, ATTR_ID); - label = parser.getAttributeValue(null, ATTR_LABEL); - final int widthMils = Integer.parseInt(parser.getAttributeValue(null, - ATTR_WIDTH_MILS)); - final int heightMils = Integer.parseInt(parser.getAttributeValue(null, - ATTR_HEIGHT_MILS)); - MediaSize mediaSize = new MediaSize(id, label, widthMils, heightMils); - builder.setMediaSize(mediaSize); - parser.next(); - skipEmptyTextTags(parser); - expect(parser, XmlPullParser.END_TAG, TAG_MEDIA_SIZE); - parser.next(); - } - - skipEmptyTextTags(parser); - if (accept(parser, XmlPullParser.START_TAG, TAG_RESOLUTION)) { - String id = parser.getAttributeValue(null, ATTR_ID); - label = parser.getAttributeValue(null, ATTR_LABEL); - final int horizontalDpi = Integer.parseInt(parser.getAttributeValue(null, - ATTR_HORIZONTAL_DPI)); - final int verticalDpi = Integer.parseInt(parser.getAttributeValue(null, - ATTR_VERTICAL_DPI)); - Resolution resolution = new Resolution(id, label, horizontalDpi, verticalDpi); - builder.setResolution(resolution); - parser.next(); - skipEmptyTextTags(parser); - expect(parser, XmlPullParser.END_TAG, TAG_RESOLUTION); - parser.next(); - } - - skipEmptyTextTags(parser); - if (accept(parser, XmlPullParser.START_TAG, TAG_MARGINS)) { - final int leftMils = Integer.parseInt(parser.getAttributeValue(null, - ATTR_LEFT_MILS)); - final int topMils = Integer.parseInt(parser.getAttributeValue(null, - ATTR_TOP_MILS)); - final int rightMils = Integer.parseInt(parser.getAttributeValue(null, - ATTR_RIGHT_MILS)); - final int bottomMils = Integer.parseInt(parser.getAttributeValue(null, - ATTR_BOTTOM_MILS)); - Margins margins = new Margins(leftMils, topMils, rightMils, bottomMils); - builder.setMargins(margins); - parser.next(); - skipEmptyTextTags(parser); - expect(parser, XmlPullParser.END_TAG, TAG_MARGINS); - parser.next(); - } - - skipEmptyTextTags(parser); - if (accept(parser, XmlPullParser.START_TAG, TAG_INPUT_TRAY)) { - String id = parser.getAttributeValue(null, ATTR_ID); - label = parser.getAttributeValue(null, ATTR_LABEL); - Tray tray = new Tray(id, label); - builder.setInputTray(tray); - parser.next(); - skipEmptyTextTags(parser); - expect(parser, XmlPullParser.END_TAG, TAG_INPUT_TRAY); - parser.next(); - } - - skipEmptyTextTags(parser); - if (accept(parser, XmlPullParser.START_TAG, TAG_OUTPUT_TRAY)) { - String id = parser.getAttributeValue(null, ATTR_ID); - label = parser.getAttributeValue(null, ATTR_LABEL); - Tray tray = new Tray(id, label); - builder.setOutputTray(tray); - parser.next(); - skipEmptyTextTags(parser); - expect(parser, XmlPullParser.END_TAG, TAG_OUTPUT_TRAY); - parser.next(); - } - - printJob.setAttributes(builder.create()); - - skipEmptyTextTags(parser); - expect(parser, XmlPullParser.END_TAG, TAG_ATTRIBUTES); - parser.next(); - } - - skipEmptyTextTags(parser); - if (accept(parser, XmlPullParser.START_TAG, TAG_DOCUMENT_INFO)) { - String name = parser.getAttributeValue(null, ATTR_NAME); - final int pageCount = Integer.parseInt(parser.getAttributeValue(null, - ATTR_PAGE_COUNT)); - final int contentType = Integer.parseInt(parser.getAttributeValue(null, - ATTR_CONTENT_TYPE)); - PrintDocumentInfo info = new PrintDocumentInfo.Builder(name) - .setPageCount(pageCount) - .setContentType(contentType).create(); - printJob.setDocumentInfo(info); - parser.next(); - skipEmptyTextTags(parser); - expect(parser, XmlPullParser.END_TAG, TAG_DOCUMENT_INFO); - parser.next(); - } - - mPrintJobs.add(printJob); - - if (DEBUG_PERSISTENCE) { - Log.i(LOG_TAG, "[RESTORED] " + printJob); - } - - skipEmptyTextTags(parser); - expect(parser, XmlPullParser.END_TAG, TAG_JOB); - - return true; - } - - private void expect(XmlPullParser parser, int type, String tag) - throws IOException, XmlPullParserException { - if (!accept(parser, type, tag)) { - throw new XmlPullParserException("Exepected event: " + type - + " and tag: " + tag + " but got event: " + parser.getEventType() - + " and tag:" + parser.getName()); - } - } - - private void skipEmptyTextTags(XmlPullParser parser) - throws IOException, XmlPullParserException { - while (accept(parser, XmlPullParser.TEXT, null) - && "\n".equals(parser.getText())) { - parser.next(); - } - } - - private boolean accept(XmlPullParser parser, int type, String tag) - throws IOException, XmlPullParserException { - if (parser.getEventType() != type) { - return false; - } - if (tag != null) { - if (!tag.equals(parser.getName())) { - return false; - } - } else if (parser.getName() != null) { - return false; - } - return true; - } - } -} diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java index 4fab4f8..fda64c9 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java +++ b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java @@ -21,9 +21,8 @@ import android.app.Service; import android.content.ComponentName; import android.content.Intent; import android.content.IntentSender; -import android.os.Handler; +import android.os.AsyncTask; import android.os.IBinder; -import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.RemoteException; @@ -32,14 +31,38 @@ import android.print.IPrintDocumentAdapter; import android.print.IPrintSpooler; import android.print.IPrintSpoolerCallbacks; import android.print.IPrintSpoolerClient; -import android.print.IPrinterDiscoverySessionObserver; +import android.print.PageRange; import android.print.PrintAttributes; +import android.print.PrintAttributes.Margins; +import android.print.PrintAttributes.MediaSize; +import android.print.PrintAttributes.Resolution; +import android.print.PrintAttributes.Tray; +import android.print.PrintDocumentInfo; import android.print.PrintJobInfo; +import android.print.PrintManager; +import android.print.PrinterId; +import android.print.PrinterInfo; +import android.util.AtomicFile; import android.util.Log; import android.util.Slog; +import android.util.Xml; +import com.android.internal.os.HandlerCaller; import com.android.internal.os.SomeArgs; +import com.android.internal.util.FastXmlSerializer; +import libcore.io.IoUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; import java.util.List; /** @@ -48,22 +71,65 @@ import java.util.List; */ public final class PrintSpoolerService extends Service { + private static final String LOG_TAG = "PrintSpoolerService"; + + private static final boolean DEBUG_PRINT_JOB_LIFECYCLE = true; + + private static final boolean DEBUG_PERSISTENCE = true; + + private static final boolean PERSISTNECE_MANAGER_ENABLED = true; + private static final long CHECK_ALL_PRINTJOBS_HANDLED_DELAY = 5000; - private static final String LOG_TAG = "PrintSpoolerService"; + private static final String PRINT_FILE_EXTENSION = "pdf"; + + private static final Object sLock = new Object(); + + private final Object mLock = new Object(); + + private final List<PrintJobInfo> mPrintJobs = new ArrayList<PrintJobInfo>(); + + private static PrintSpoolerService sInstance; + + private static int sPrintJobIdCounter; private Intent mStartPrintJobConfigActivityIntent; private IPrintSpoolerClient mClient; - private Handler mHandler; + private HandlerCaller mHandlerCaller; + + private PersistenceManager mPersistanceManager; + + private NotificationController mNotificationController; + + private PrinterDiscoverySession mDiscoverySession; + + public static PrintSpoolerService peekInstance() { + synchronized (sLock) { + return sInstance; + } + } @Override public void onCreate() { super.onCreate(); mStartPrintJobConfigActivityIntent = new Intent(PrintSpoolerService.this, PrintJobConfigActivity.class); - mHandler = new MyHandler(getMainLooper()); + mHandlerCaller = new HandlerCaller(this, getMainLooper(), + new HandlerCallerCallback(), false); + + mPersistanceManager = new PersistenceManager(); + mNotificationController = new NotificationController(PrintSpoolerService.this); + + synchronized (mLock) { + mPersistanceManager.readStateLocked(); + handleReadPrintJobsLocked(); + } + + synchronized (sLock) { + sInstance = this; + } } @Override @@ -72,10 +138,10 @@ public final class PrintSpoolerService extends Service { @Override public void getPrintJobInfos(IPrintSpoolerCallbacks callback, ComponentName componentName, int state, int appId, int sequence) - throws RemoteException { + throws RemoteException { List<PrintJobInfo> printJobs = null; try { - printJobs = PrintSpooler.peekInstance().getPrintJobInfos( + printJobs = PrintSpoolerService.this.getPrintJobInfos( componentName, state, appId); } finally { callback.onGetPrintJobInfosResult(printJobs, sequence); @@ -87,7 +153,7 @@ public final class PrintSpoolerService extends Service { int appId, int sequence) throws RemoteException { PrintJobInfo printJob = null; try { - printJob = PrintSpooler.peekInstance().getPrintJobInfo(printJobId, appId); + printJob = PrintSpoolerService.this.getPrintJobInfo(printJobId, appId); } finally { callback.onGetPrintJobInfoResult(printJob, sequence); } @@ -98,11 +164,11 @@ public final class PrintSpoolerService extends Service { public void createPrintJob(String printJobName, IPrintClient client, IPrintDocumentAdapter printAdapter, PrintAttributes attributes, IPrintSpoolerCallbacks callback, int appId, int sequence) - throws RemoteException { + throws RemoteException { PrintJobInfo printJob = null; try { - printJob = PrintSpooler.peekInstance().createPrintJob(printJobName, client, - attributes, appId); + printJob = PrintSpoolerService.this.createPrintJob( + printJobName, client, attributes, appId); if (printJob != null) { Intent intent = mStartPrintJobConfigActivityIntent; intent.putExtra(PrintJobConfigActivity.EXTRA_PRINT_DOCUMENT_ADAPTER, @@ -113,13 +179,12 @@ public final class PrintSpoolerService extends Service { IntentSender sender = PendingIntent.getActivity( PrintSpoolerService.this, 0, intent, PendingIntent.FLAG_ONE_SHOT - | PendingIntent.FLAG_CANCEL_CURRENT).getIntentSender(); + | PendingIntent.FLAG_CANCEL_CURRENT).getIntentSender(); - SomeArgs args = SomeArgs.obtain(); - args.arg1 = client; - args.arg2 = sender; - mHandler.obtainMessage(MyHandler.MSG_START_PRINT_JOB_CONFIG_ACTIVITY, - args).sendToTarget(); + Message message = mHandlerCaller.obtainMessageOO( + HandlerCallerCallback.MSG_START_PRINT_JOB_CONFIG_ACTIVITY, + client, sender); + mHandlerCaller.executeOrSendMessage(message); } } finally { callback.onCreatePrintJobResult(printJob, sequence); @@ -127,11 +192,11 @@ public final class PrintSpoolerService extends Service { } @Override - public void setPrintJobState(int printJobId, int state, CharSequence error, + public void setPrintJobState(int printJobId, int state, String error, IPrintSpoolerCallbacks callback, int sequece) throws RemoteException { boolean success = false; try { - success = PrintSpooler.peekInstance().setPrintJobState( + success = PrintSpoolerService.this.setPrintJobState( printJobId, state, error); } finally { callback.onSetPrintJobStateResult(success, sequece); @@ -143,7 +208,7 @@ public final class PrintSpoolerService extends Service { IPrintSpoolerCallbacks callback, int sequece) throws RemoteException { boolean success = false; try { - success = PrintSpooler.peekInstance().setPrintJobTag(printJobId, tag); + success = PrintSpoolerService.this.setPrintJobTag(printJobId, tag); } finally { callback.onSetPrintJobTagResult(success, sequece); } @@ -151,60 +216,191 @@ public final class PrintSpoolerService extends Service { @Override public void writePrintJobData(ParcelFileDescriptor fd, int printJobId) { - PrintSpooler.peekInstance().writePrintJobData(fd, printJobId); + PrintSpoolerService.this.writePrintJobData(fd, printJobId); } @Override public void setClient(IPrintSpoolerClient client) { - mHandler.obtainMessage(MyHandler.MSG_SET_CLIENT, client).sendToTarget(); + Message message = mHandlerCaller.obtainMessageO( + HandlerCallerCallback.MSG_SET_CLIENT, client); + mHandlerCaller.executeOrSendMessage(message); + } + + @Override + public void onPrintersAdded(List<PrinterInfo> printers) { + Message message = mHandlerCaller.obtainMessageO( + HandlerCallerCallback.MSG_ON_PRINTERS_ADDED, printers); + mHandlerCaller.executeOrSendMessage(message); + } + + @Override + public void onPrintersRemoved(List<PrinterId> printerIds) { + Message message = mHandlerCaller.obtainMessageO( + HandlerCallerCallback.MSG_ON_PRINTERS_REMOVED, printerIds); + mHandlerCaller.executeOrSendMessage(message); + } + + @Override + public void onPrintersUpdated(List<PrinterInfo> printers) { + Message message = mHandlerCaller.obtainMessageO( + HandlerCallerCallback.MSG_ON_PRINTERS_UPDATED, printers); + mHandlerCaller.executeOrSendMessage(message); } }; } - public void onPrintJobQueued(PrintJobInfo printJob) { - mHandler.obtainMessage(MyHandler.MSG_ON_PRINT_JOB_QUEUED, - printJob).sendToTarget(); + public void createPrinterDiscoverySession() { + Message message = mHandlerCaller.obtainMessage( + HandlerCallerCallback.MSG_CREATE_PRINTER_DISCOVERY_SESSION); + mHandlerCaller.executeOrSendMessage(message); } - public void createPrinterDiscoverySession(IPrinterDiscoverySessionObserver observer) { - mHandler.obtainMessage(MyHandler.MSG_CREATE_PRINTER_DISCOVERY_SESSION, - observer).sendToTarget(); + public void destroyPrinterDiscoverySession() { + Message message = mHandlerCaller.obtainMessage( + HandlerCallerCallback.MSG_DESTROY_PRINTER_DISCOVERY_SESSION); + mHandlerCaller.executeOrSendMessage(message); } - public void onAllPrintJobsForServiceHandled(ComponentName service) { - mHandler.obtainMessage(MyHandler.MSG_ON_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED, - service).sendToTarget(); + public void startPrinterDiscovery(List<PrinterId> priorityList) { + Message message = mHandlerCaller.obtainMessageO( + HandlerCallerCallback.MSG_START_PRINTER_DISCOVERY, priorityList); + mHandlerCaller.executeOrSendMessage(message); } - public void onAllPrintJobsHandled() { - mHandler.sendEmptyMessage(MyHandler.MSG_ON_ALL_PRINT_JOBS_HANDLED); + public void stopPrinterDiscovery() { + Message message = mHandlerCaller.obtainMessage( + HandlerCallerCallback.MSG_STOP_PRINTER_DISCOVERY); + mHandlerCaller.executeOrSendMessage(message); } - private final class MyHandler extends Handler { - public static final int MSG_SET_CLIENT = 1; - public static final int MSG_START_PRINT_JOB_CONFIG_ACTIVITY = 2; - public static final int MSG_CREATE_PRINTER_DISCOVERY_SESSION = 3; - public static final int MSG_ON_PRINT_JOB_QUEUED = 5; - public static final int MSG_ON_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED = 6; - public static final int MSG_ON_ALL_PRINT_JOBS_HANDLED = 7; - public static final int MSG_CHECK_ALL_PRINTJOBS_HANDLED = 9; + public void requestPrinterUpdate(PrinterId pritnerId) { + Message message = mHandlerCaller.obtainMessageO( + HandlerCallerCallback.MSG_REQUEST_PRINTER_UPDATE, pritnerId); + mHandlerCaller.executeOrSendMessage(message); + } - public MyHandler(Looper looper) { - super(looper, null, false); - } + + private void sendOnPrintJobQueued(PrintJobInfo printJob) { + Message message = mHandlerCaller.obtainMessageO( + HandlerCallerCallback.MSG_ON_PRINT_JOB_QUEUED, printJob); + mHandlerCaller.executeOrSendMessage(message); + } + + private void sendOnAllPrintJobsForServiceHandled(ComponentName service) { + Message message = mHandlerCaller.obtainMessageO( + HandlerCallerCallback.MSG_ON_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED, service); + mHandlerCaller.executeOrSendMessage(message); + } + + private void sendOnAllPrintJobsHandled() { + Message message = mHandlerCaller.obtainMessage( + HandlerCallerCallback.MSG_ON_ALL_PRINT_JOBS_HANDLED); + mHandlerCaller.executeOrSendMessage(message); + } + + private final class HandlerCallerCallback implements HandlerCaller.Callback { + public static final int MSG_CREATE_PRINTER_DISCOVERY_SESSION = 1; + public static final int MSG_DESTROY_PRINTER_DISCOVERY_SESSION = 2; + public static final int MSG_START_PRINTER_DISCOVERY = 3; + public static final int MSG_STOP_PRINTER_DISCOVERY = 4; + public static final int MSG_REQUEST_PRINTER_UPDATE = 5; + + public static final int MSG_ON_PRINTERS_ADDED = 6; + public static final int MSG_ON_PRINTERS_REMOVED = 7; + public static final int MSG_ON_PRINTERS_UPDATED = 8; + + public static final int MSG_SET_CLIENT = 9; + public static final int MSG_START_PRINT_JOB_CONFIG_ACTIVITY = 10; + public static final int MSG_ON_PRINT_JOB_QUEUED = 11; + public static final int MSG_ON_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED = 12; + public static final int MSG_ON_ALL_PRINT_JOBS_HANDLED = 13; + public static final int MSG_CHECK_ALL_PRINTJOBS_HANDLED = 14; @Override - public void handleMessage(Message message) { + @SuppressWarnings("unchecked") + public void executeMessage(Message message) { switch (message.what) { + case MSG_CREATE_PRINTER_DISCOVERY_SESSION: { + final IPrintSpoolerClient client; + synchronized (mLock) { + client = mClient; + } + if (client != null) { + try { + client.createPrinterDiscoverySession(); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error creating printer discovery session.", re); + } + } + } break; + + case MSG_DESTROY_PRINTER_DISCOVERY_SESSION: { + final IPrintSpoolerClient client; + synchronized (mLock) { + client = mClient; + } + if (client != null) { + try { + client.destroyPrinterDiscoverySession(); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error destroying printer discovery session.", re); + } + } + } break; + + case MSG_START_PRINTER_DISCOVERY: { + final IPrintSpoolerClient client; + synchronized (mLock) { + client = mClient; + } + if (client != null) { + List<PrinterId> priorityList = (ArrayList<PrinterId>) message.obj; + try { + client.startPrinterDiscovery(priorityList); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error starting printer discovery.", re); + } + } + } break; + + case MSG_STOP_PRINTER_DISCOVERY: { + final IPrintSpoolerClient client; + synchronized (mLock) { + client = mClient; + } + if (client != null) { + try { + client.stopPrinterDiscovery(); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error stopping printer discovery.", re); + } + } + } break; + + case MSG_REQUEST_PRINTER_UPDATE: { + final IPrintSpoolerClient client; + synchronized (mLock) { + client = mClient; + } + if (client != null) { + PrinterId printerId = (PrinterId) message.obj; + try { + client.requestPrinterUpdate(printerId); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error requesing printer update.", re); + } + } + } break; + case MSG_SET_CLIENT: { - mClient = (IPrintSpoolerClient) message.obj; - if (mClient != null) { - PrintSpooler.createInstance(PrintSpoolerService.this); - mHandler.sendEmptyMessageDelayed( - MyHandler.MSG_CHECK_ALL_PRINTJOBS_HANDLED, - CHECK_ALL_PRINTJOBS_HANDLED_DELAY); - } else { - PrintSpooler.destroyInstance(); + synchronized (mLock) { + mClient = (IPrintSpoolerClient) message.obj; + if (mClient != null) { + Message msg = mHandlerCaller.obtainMessage( + HandlerCallerCallback.MSG_CHECK_ALL_PRINTJOBS_HANDLED); + mHandlerCaller.sendMessageDelayed(msg, + CHECK_ALL_PRINTJOBS_HANDLED_DELAY); + } } } break; @@ -220,18 +416,6 @@ public final class PrintSpoolerService extends Service { } } break; - case MSG_CREATE_PRINTER_DISCOVERY_SESSION: { - IPrinterDiscoverySessionObserver observer = - (IPrinterDiscoverySessionObserver) message.obj; - if (mClient != null) { - try { - mClient.createPrinterDiscoverySession(observer); - } catch (RemoteException re) { - Log.e(LOG_TAG, "Error creating printer discovery session.", re); - } - } - } break; - case MSG_ON_PRINT_JOB_QUEUED: { PrintJobInfo printJob = (PrintJobInfo) message.obj; if (mClient != null) { @@ -266,12 +450,948 @@ public final class PrintSpoolerService extends Service { } break; case MSG_CHECK_ALL_PRINTJOBS_HANDLED: { - PrintSpooler spooler = PrintSpooler.peekInstance(); - if (spooler != null) { - spooler.checkAllPrintJobsHandled(); + checkAllPrintJobsHandled(); + } break; + + case MSG_ON_PRINTERS_ADDED: { + final PrinterDiscoverySession session; + synchronized (mLock) { + session = mDiscoverySession; + } + if (session != null) { + List<PrinterInfo> printers = (ArrayList<PrinterInfo>) message.obj; + session.onPrintersAdded(printers); + } + } break; + + case MSG_ON_PRINTERS_REMOVED: { + final PrinterDiscoverySession session; + synchronized (mLock) { + session = mDiscoverySession; + } + if (session != null) { + List<PrinterId> printerIds = (ArrayList<PrinterId>) message.obj; + session.onPrintersRemoved(printerIds); + } + } break; + + case MSG_ON_PRINTERS_UPDATED: { + final PrinterDiscoverySession session; + synchronized (mLock) { + session = mDiscoverySession; + } + if (session != null) { + List<PrinterInfo> printers = (ArrayList<PrinterInfo>) message.obj; + session.onPrintersUpdated(printers); } } break; } } } + + public List<PrintJobInfo> getPrintJobInfos(ComponentName componentName, + int state, int appId) { + List<PrintJobInfo> foundPrintJobs = null; + synchronized (mLock) { + final int printJobCount = mPrintJobs.size(); + for (int i = 0; i < printJobCount; i++) { + PrintJobInfo printJob = mPrintJobs.get(i); + PrinterId printerId = printJob.getPrinterId(); + final boolean sameComponent = (componentName == null + || (printerId != null + && componentName.equals(printerId.getServiceName()))); + final boolean sameAppId = appId == PrintManager.APP_ID_ANY + || printJob.getAppId() == appId; + final boolean sameState = (state == printJob.getState()) + || (state == PrintJobInfo.STATE_ANY) + || (state == PrintJobInfo.STATE_ANY_VISIBLE_TO_CLIENTS + && printJob.getState() > PrintJobInfo.STATE_CREATED); + if (sameComponent && sameAppId && sameState) { + if (foundPrintJobs == null) { + foundPrintJobs = new ArrayList<PrintJobInfo>(); + } + foundPrintJobs.add(printJob); + } + } + } + return foundPrintJobs; + } + + public PrintJobInfo getPrintJobInfo(int printJobId, int appId) { + synchronized (mLock) { + final int printJobCount = mPrintJobs.size(); + for (int i = 0; i < printJobCount; i++) { + PrintJobInfo printJob = mPrintJobs.get(i); + if (printJob.getId() == printJobId + && (appId == PrintManager.APP_ID_ANY + || appId == printJob.getAppId())) { + return printJob; + } + } + return null; + } + } + + public PrintJobInfo createPrintJob(String label, IPrintClient client, + PrintAttributes attributes, int appId) { + synchronized (mLock) { + final int printJobId = generatePrintJobIdLocked(); + PrintJobInfo printJob = new PrintJobInfo(); + printJob.setId(printJobId); + printJob.setAppId(appId); + printJob.setLabel(label); + printJob.setAttributes(attributes); + printJob.setState(PrintJobInfo.STATE_CREATED); + + addPrintJobLocked(printJob); + + return printJob; + } + } + + private void handleReadPrintJobsLocked() { + final int printJobCount = mPrintJobs.size(); + for (int i = 0; i < printJobCount; i++) { + PrintJobInfo printJob = mPrintJobs.get(i); + + // Update the notification. + mNotificationController.onPrintJobStateChanged(printJob); + + switch (printJob.getState()) { + case PrintJobInfo.STATE_QUEUED: + case PrintJobInfo.STATE_STARTED: { + // We have a print job that was queued or started in the + // past + // but the device battery died or a crash occurred. In this + // case + // we assume the print job failed and let the user decide + // whether + // to restart the job or just + setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED, + getString(R.string.no_connection_to_printer)); + } + break; + } + } + } + + public void checkAllPrintJobsHandled() { + synchronized (mLock) { + if (!hasActivePrintJobsLocked()) { + notifyOnAllPrintJobsHandled(); + } + } + } + + private void setPrinterDiscoverySessionClient(PrinterDiscoverySession session) { + synchronized (mLock) { + mDiscoverySession = session; + } + } + + private int generatePrintJobIdLocked() { + int printJobId = sPrintJobIdCounter++; + while (isDuplicatePrintJobId(printJobId)) { + printJobId = sPrintJobIdCounter++; + } + return printJobId; + } + + private boolean isDuplicatePrintJobId(int printJobId) { + final int printJobCount = mPrintJobs.size(); + for (int j = 0; j < printJobCount; j++) { + PrintJobInfo printJob = mPrintJobs.get(j); + if (printJob.getId() == printJobId) { + return true; + } + } + return false; + } + + public void writePrintJobData(final ParcelFileDescriptor fd, final int printJobId) { + final PrintJobInfo printJob; + synchronized (mLock) { + printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); + } + new AsyncTask<Void, Void, Void>() { + @Override + protected Void doInBackground(Void... params) { + FileInputStream in = null; + FileOutputStream out = null; + try { + if (printJob != null) { + File file = generateFileForPrintJob(printJobId); + in = new FileInputStream(file); + out = new FileOutputStream(fd.getFileDescriptor()); + } + final byte[] buffer = new byte[8192]; + while (true) { + final int readByteCount = in.read(buffer); + if (readByteCount < 0) { + return null; + } + out.write(buffer, 0, readByteCount); + } + } catch (FileNotFoundException fnfe) { + Log.e(LOG_TAG, "Error writing print job data!", fnfe); + } catch (IOException ioe) { + Log.e(LOG_TAG, "Error writing print job data!", ioe); + } finally { + IoUtils.closeQuietly(in); + IoUtils.closeQuietly(out); + IoUtils.closeQuietly(fd); + } + Log.i(LOG_TAG, "[END WRITE]"); + return null; + } + }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null); + } + + public File generateFileForPrintJob(int printJobId) { + return new File(getFilesDir(), "print_job_" + + printJobId + "." + PRINT_FILE_EXTENSION); + } + + private void addPrintJobLocked(PrintJobInfo printJob) { + mPrintJobs.add(printJob); + if (DEBUG_PRINT_JOB_LIFECYCLE) { + Slog.i(LOG_TAG, "[ADD] " + printJob); + } + } + + private void removePrintJobLocked(PrintJobInfo printJob) { + if (mPrintJobs.remove(printJob)) { + generateFileForPrintJob(printJob.getId()).delete(); + if (DEBUG_PRINT_JOB_LIFECYCLE) { + Slog.i(LOG_TAG, "[REMOVE] " + printJob); + } + } + } + + public boolean setPrintJobState(int printJobId, int state, String error) { + boolean success = false; + + synchronized (mLock) { + PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); + if (printJob != null) { + success = true; + + printJob.setState(state); + printJob.setFailureReason(error); + mNotificationController.onPrintJobStateChanged(printJob); + + if (DEBUG_PRINT_JOB_LIFECYCLE) { + Slog.i(LOG_TAG, "[STATE CHANGED] " + printJob); + } + + switch (state) { + case PrintJobInfo.STATE_COMPLETED: + case PrintJobInfo.STATE_CANCELED: + removePrintJobLocked(printJob); + // $fall-through$ + + case PrintJobInfo.STATE_FAILED: { + PrinterId printerId = printJob.getPrinterId(); + if (printerId != null) { + ComponentName service = printerId.getServiceName(); + if (!hasActivePrintJobsForServiceLocked(service)) { + sendOnAllPrintJobsForServiceHandled(service); + } + } + } break; + + case PrintJobInfo.STATE_QUEUED: { + sendOnPrintJobQueued(new PrintJobInfo(printJob)); + } break; + } + + if (shouldPersistPrintJob(printJob)) { + mPersistanceManager.writeStateLocked(); + } + + if (!hasActivePrintJobsLocked()) { + notifyOnAllPrintJobsHandled(); + } + } + } + + return success; + } + + public boolean hasActivePrintJobsLocked() { + final int printJobCount = mPrintJobs.size(); + for (int i = 0; i < printJobCount; i++) { + PrintJobInfo printJob = mPrintJobs.get(i); + if (isActiveState(printJob.getState())) { + return true; + } + } + return false; + } + + public boolean hasActivePrintJobsForServiceLocked(ComponentName service) { + final int printJobCount = mPrintJobs.size(); + for (int i = 0; i < printJobCount; i++) { + PrintJobInfo printJob = mPrintJobs.get(i); + if (isActiveState(printJob.getState()) + && printJob.getPrinterId().getServiceName().equals(service)) { + return true; + } + } + return false; + } + + private boolean isActiveState(int printJobState) { + return printJobState == PrintJobInfo.STATE_CREATED + || printJobState == PrintJobInfo.STATE_QUEUED + || printJobState == PrintJobInfo.STATE_STARTED; + } + + public boolean setPrintJobTag(int printJobId, String tag) { + synchronized (mLock) { + PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); + if (printJob != null) { + String printJobTag = printJob.getTag(); + if (printJobTag == null) { + if (tag == null) { + return false; + } + } else if (printJobTag.equals(tag)) { + return false; + } + printJob.setTag(tag); + if (shouldPersistPrintJob(printJob)) { + mPersistanceManager.writeStateLocked(); + } + return true; + } + } + return false; + } + + public void setPrintJobCopiesNoPersistence(int printJobId, int copies) { + synchronized (mLock) { + PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); + if (printJob != null) { + printJob.setCopies(copies); + } + } + } + + public void setPrintJobPrintDocumentInfoNoPersistence(int printJobId, PrintDocumentInfo info) { + synchronized (mLock) { + PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); + if (printJob != null) { + printJob.setDocumentInfo(info); + } + } + } + + public void setPrintJobAttributesNoPersistence(int printJobId, PrintAttributes attributes) { + synchronized (mLock) { + PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); + if (printJob != null) { + printJob.setAttributes(attributes); + } + } + } + + public void setPrintJobPrinterNoPersistence(int printJobId, PrinterInfo printer) { + synchronized (mLock) { + PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); + if (printJob != null) { + printJob.setPrinterId(printer.getId()); + printJob.setPrinterName(printer.getName()); + } + } + } + + public void setPrintJobPagesNoPersistence(int printJobId, PageRange[] pages) { + synchronized (mLock) { + PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY); + if (printJob != null) { + printJob.setPages(pages); + } + } + } + + private boolean shouldPersistPrintJob(PrintJobInfo printJob) { + return printJob.getState() >= PrintJobInfo.STATE_QUEUED; + } + + private void notifyOnAllPrintJobsHandled() { + // This has to run on the tread that is persisting the current state + // since this call may result in the system unbinding from the spooler + // and as a result the spooler process may get killed before the write + // completes. + new AsyncTask<Void, Void, Void>() { + @Override + protected Void doInBackground(Void... params) { + sendOnAllPrintJobsHandled(); + return null; + } + }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null); + } + + private final class PersistenceManager { + private static final String PERSIST_FILE_NAME = "print_spooler_state.xml"; + + private static final String TAG_SPOOLER = "spooler"; + private static final String TAG_JOB = "job"; + + private static final String TAG_PRINTER_ID = "printerId"; + private static final String TAG_PAGE_RANGE = "pageRange"; + private static final String TAG_ATTRIBUTES = "attributes"; + private static final String TAG_DOCUMENT_INFO = "documentInfo"; + + private static final String ATTR_ID = "id"; + private static final String ATTR_LABEL = "label"; + private static final String ATTR_STATE = "state"; + private static final String ATTR_APP_ID = "appId"; + private static final String ATTR_USER_ID = "userId"; + private static final String ATTR_TAG = "tag"; + private static final String ATTR_COPIES = "copies"; + + private static final String TAG_MEDIA_SIZE = "mediaSize"; + private static final String TAG_RESOLUTION = "resolution"; + private static final String TAG_MARGINS = "margins"; + private static final String TAG_INPUT_TRAY = "inputTray"; + private static final String TAG_OUTPUT_TRAY = "outputTray"; + + private static final String ATTR_DUPLEX_MODE = "duplexMode"; + private static final String ATTR_COLOR_MODE = "colorMode"; + private static final String ATTR_FITTING_MODE = "fittingMode"; + private static final String ATTR_ORIENTATION = "orientation"; + + private static final String ATTR_LOCAL_ID = "printerName"; + private static final String ATTR_SERVICE_NAME = "serviceName"; + + private static final String ATTR_WIDTH_MILS = "widthMils"; + private static final String ATTR_HEIGHT_MILS = "heightMils"; + + private static final String ATTR_HORIZONTAL_DPI = "horizontalDip"; + private static final String ATTR_VERTICAL_DPI = "verticalDpi"; + + private static final String ATTR_LEFT_MILS = "leftMils"; + private static final String ATTR_TOP_MILS = "topMils"; + private static final String ATTR_RIGHT_MILS = "rightMils"; + private static final String ATTR_BOTTOM_MILS = "bottomMils"; + + private static final String ATTR_START = "start"; + private static final String ATTR_END = "end"; + + private static final String ATTR_NAME = "name"; + private static final String ATTR_PAGE_COUNT = "pageCount"; + private static final String ATTR_CONTENT_TYPE = "contentType"; + + private final AtomicFile mStatePersistFile; + + private boolean mWriteStateScheduled; + + private PersistenceManager() { + mStatePersistFile = new AtomicFile(new File(getFilesDir(), + PERSIST_FILE_NAME)); + } + + public void writeStateLocked() { + if (!PERSISTNECE_MANAGER_ENABLED) { + return; + } + if (mWriteStateScheduled) { + return; + } + mWriteStateScheduled = true; + new AsyncTask<Void, Void, Void>() { + @Override + protected Void doInBackground(Void... params) { + synchronized (mLock) { + mWriteStateScheduled = false; + doWriteStateLocked(); + } + return null; + } + }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null); + } + + private void doWriteStateLocked() { + if (DEBUG_PERSISTENCE) { + Log.i(LOG_TAG, "[PERSIST START]"); + } + FileOutputStream out = null; + try { + out = mStatePersistFile.startWrite(); + + XmlSerializer serializer = new FastXmlSerializer(); + serializer.setOutput(out, "utf-8"); + serializer.startDocument(null, true); + serializer.startTag(null, TAG_SPOOLER); + + List<PrintJobInfo> printJobs = mPrintJobs; + + final int printJobCount = printJobs.size(); + for (int j = 0; j < printJobCount; j++) { + PrintJobInfo printJob = printJobs.get(j); + + final int state = printJob.getState(); + if (state < PrintJobInfo.STATE_QUEUED + || state > PrintJobInfo.STATE_CANCELED) { + continue; + } + + serializer.startTag(null, TAG_JOB); + + serializer.attribute(null, ATTR_ID, String.valueOf(printJob.getId())); + serializer.attribute(null, ATTR_LABEL, printJob.getLabel().toString()); + serializer.attribute(null, ATTR_STATE, String.valueOf(printJob.getState())); + serializer.attribute(null, ATTR_APP_ID, String.valueOf(printJob.getAppId())); + serializer.attribute(null, ATTR_USER_ID, String.valueOf(printJob.getUserId())); + String tag = printJob.getTag(); + if (tag != null) { + serializer.attribute(null, ATTR_TAG, tag); + } + serializer.attribute(null, ATTR_COPIES, String.valueOf(printJob.getCopies())); + + PrinterId printerId = printJob.getPrinterId(); + if (printerId != null) { + serializer.startTag(null, TAG_PRINTER_ID); + serializer.attribute(null, ATTR_LOCAL_ID, printerId.getLocalId()); + serializer.attribute(null, ATTR_SERVICE_NAME, printerId.getServiceName() + .flattenToString()); + serializer.endTag(null, TAG_PRINTER_ID); + } + + PageRange[] pages = printJob.getPages(); + if (pages != null) { + for (int i = 0; i < pages.length; i++) { + serializer.startTag(null, TAG_PAGE_RANGE); + serializer.attribute(null, ATTR_START, String.valueOf( + pages[i].getStart())); + serializer.attribute(null, ATTR_END, String.valueOf( + pages[i].getEnd())); + serializer.endTag(null, TAG_PAGE_RANGE); + } + } + + PrintAttributes attributes = printJob.getAttributes(); + if (attributes != null) { + serializer.startTag(null, TAG_ATTRIBUTES); + + final int duplexMode = attributes.getDuplexMode(); + serializer.attribute(null, ATTR_DUPLEX_MODE, + String.valueOf(duplexMode)); + + final int colorMode = attributes.getColorMode(); + serializer.attribute(null, ATTR_COLOR_MODE, + String.valueOf(colorMode)); + + final int fittingMode = attributes.getFittingMode(); + serializer.attribute(null, ATTR_FITTING_MODE, + String.valueOf(fittingMode)); + + final int orientation = attributes.getOrientation(); + serializer.attribute(null, ATTR_ORIENTATION, + String.valueOf(orientation)); + + MediaSize mediaSize = attributes.getMediaSize(); + if (mediaSize != null) { + serializer.startTag(null, TAG_MEDIA_SIZE); + serializer.attribute(null, ATTR_ID, mediaSize.getId()); + serializer.attribute(null, ATTR_LABEL, mediaSize.getLabel() + .toString()); + serializer.attribute(null, ATTR_WIDTH_MILS, String.valueOf( + mediaSize.getWidthMils())); + serializer.attribute(null, ATTR_HEIGHT_MILS, String.valueOf( + mediaSize.getHeightMils())); + serializer.endTag(null, TAG_MEDIA_SIZE); + } + + Resolution resolution = attributes.getResolution(); + if (resolution != null) { + serializer.startTag(null, TAG_RESOLUTION); + serializer.attribute(null, ATTR_ID, resolution.getId()); + serializer.attribute(null, ATTR_LABEL, resolution.getLabel() + .toString()); + serializer.attribute(null, ATTR_HORIZONTAL_DPI, String.valueOf( + resolution.getHorizontalDpi())); + serializer.attribute(null, ATTR_VERTICAL_DPI, String.valueOf( + resolution.getVerticalDpi())); + serializer.endTag(null, TAG_RESOLUTION); + } + + Margins margins = attributes.getMargins(); + if (margins != null) { + serializer.startTag(null, TAG_MARGINS); + serializer.attribute(null, ATTR_LEFT_MILS, String.valueOf( + margins.getLeftMils())); + serializer.attribute(null, ATTR_TOP_MILS, String.valueOf( + margins.getTopMils())); + serializer.attribute(null, ATTR_RIGHT_MILS, String.valueOf( + margins.getRightMils())); + serializer.attribute(null, ATTR_BOTTOM_MILS, String.valueOf( + margins.getBottomMils())); + serializer.endTag(null, TAG_MARGINS); + } + + Tray inputTray = attributes.getInputTray(); + if (inputTray != null) { + serializer.startTag(null, TAG_INPUT_TRAY); + serializer.attribute(null, ATTR_ID, inputTray.getId()); + serializer.attribute(null, ATTR_LABEL, inputTray.getLabel() + .toString()); + serializer.endTag(null, TAG_INPUT_TRAY); + } + + Tray outputTray = attributes.getOutputTray(); + if (outputTray != null) { + serializer.startTag(null, TAG_OUTPUT_TRAY); + serializer.attribute(null, ATTR_ID, outputTray.getId()); + serializer.attribute(null, ATTR_LABEL, outputTray.getLabel() + .toString()); + serializer.endTag(null, TAG_OUTPUT_TRAY); + } + + serializer.endTag(null, TAG_ATTRIBUTES); + } + + PrintDocumentInfo documentInfo = printJob.getDocumentInfo(); + if (documentInfo != null) { + serializer.startTag(null, TAG_DOCUMENT_INFO); + serializer.attribute(null, ATTR_NAME, documentInfo.getName()); + serializer.attribute(null, ATTR_CONTENT_TYPE, String.valueOf( + documentInfo.getContentType())); + serializer.attribute(null, ATTR_PAGE_COUNT, String.valueOf( + documentInfo.getPageCount())); + serializer.endTag(null, TAG_DOCUMENT_INFO); + } + + serializer.endTag(null, TAG_JOB); + + if (DEBUG_PERSISTENCE) { + Log.i(LOG_TAG, "[PERSISTED] " + printJob); + } + } + + serializer.endTag(null, TAG_SPOOLER); + serializer.endDocument(); + mStatePersistFile.finishWrite(out); + if (DEBUG_PERSISTENCE) { + Log.i(LOG_TAG, "[PERSIST END]"); + } + } catch (IOException e) { + Slog.w(LOG_TAG, "Failed to write state, restoring backup.", e); + mStatePersistFile.failWrite(out); + } finally { + IoUtils.closeQuietly(out); + } + } + + public void readStateLocked() { + if (!PERSISTNECE_MANAGER_ENABLED) { + return; + } + FileInputStream in = null; + try { + in = mStatePersistFile.openRead(); + } catch (FileNotFoundException e) { + Log.i(LOG_TAG, "No existing print spooler state."); + return; + } + try { + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(in, null); + parseState(parser); + } catch (IllegalStateException ise) { + Slog.w(LOG_TAG, "Failed parsing ", ise); + } catch (NullPointerException npe) { + Slog.w(LOG_TAG, "Failed parsing ", npe); + } catch (NumberFormatException nfe) { + Slog.w(LOG_TAG, "Failed parsing ", nfe); + } catch (XmlPullParserException xppe) { + Slog.w(LOG_TAG, "Failed parsing ", xppe); + } catch (IOException ioe) { + Slog.w(LOG_TAG, "Failed parsing ", ioe); + } catch (IndexOutOfBoundsException iobe) { + Slog.w(LOG_TAG, "Failed parsing ", iobe); + } finally { + IoUtils.closeQuietly(in); + } + } + + private void parseState(XmlPullParser parser) + throws IOException, XmlPullParserException { + parser.next(); + skipEmptyTextTags(parser); + expect(parser, XmlPullParser.START_TAG, TAG_SPOOLER); + parser.next(); + + while (parsePrintJob(parser)) { + parser.next(); + } + + skipEmptyTextTags(parser); + expect(parser, XmlPullParser.END_TAG, TAG_SPOOLER); + } + + private boolean parsePrintJob(XmlPullParser parser) + throws IOException, XmlPullParserException { + skipEmptyTextTags(parser); + if (!accept(parser, XmlPullParser.START_TAG, TAG_JOB)) { + return false; + } + + PrintJobInfo printJob = new PrintJobInfo(); + + final int printJobId = Integer.parseInt(parser.getAttributeValue(null, ATTR_ID)); + printJob.setId(printJobId); + String label = parser.getAttributeValue(null, ATTR_LABEL); + printJob.setLabel(label); + final int state = Integer.parseInt(parser.getAttributeValue(null, ATTR_STATE)); + printJob.setState(state); + final int appId = Integer.parseInt(parser.getAttributeValue(null, ATTR_APP_ID)); + printJob.setAppId(appId); + final int userId = Integer.parseInt(parser.getAttributeValue(null, ATTR_USER_ID)); + printJob.setUserId(userId); + String tag = parser.getAttributeValue(null, ATTR_TAG); + printJob.setTag(tag); + String copies = parser.getAttributeValue(null, ATTR_COPIES); + printJob.setCopies(Integer.parseInt(copies)); + + parser.next(); + + skipEmptyTextTags(parser); + if (accept(parser, XmlPullParser.START_TAG, TAG_PRINTER_ID)) { + String localId = parser.getAttributeValue(null, ATTR_LOCAL_ID); + ComponentName service = ComponentName.unflattenFromString(parser.getAttributeValue( + null, ATTR_SERVICE_NAME)); + printJob.setPrinterId(new PrinterId(service, localId)); + parser.next(); + skipEmptyTextTags(parser); + expect(parser, XmlPullParser.END_TAG, TAG_PRINTER_ID); + parser.next(); + } + + skipEmptyTextTags(parser); + List<PageRange> pageRanges = null; + while (accept(parser, XmlPullParser.START_TAG, TAG_PAGE_RANGE)) { + final int start = Integer.parseInt(parser.getAttributeValue(null, ATTR_START)); + final int end = Integer.parseInt(parser.getAttributeValue(null, ATTR_END)); + PageRange pageRange = new PageRange(start, end); + if (pageRanges == null) { + pageRanges = new ArrayList<PageRange>(); + } + pageRanges.add(pageRange); + parser.next(); + skipEmptyTextTags(parser); + expect(parser, XmlPullParser.END_TAG, TAG_PAGE_RANGE); + parser.next(); + } + if (pageRanges != null) { + PageRange[] pageRangesArray = new PageRange[pageRanges.size()]; + pageRanges.toArray(pageRangesArray); + printJob.setPages(pageRangesArray); + } + + skipEmptyTextTags(parser); + if (accept(parser, XmlPullParser.START_TAG, TAG_ATTRIBUTES)) { + + PrintAttributes.Builder builder = new PrintAttributes.Builder(); + + String duplexMode = parser.getAttributeValue(null, ATTR_DUPLEX_MODE); + builder.setDuplexMode(Integer.parseInt(duplexMode)); + + String colorMode = parser.getAttributeValue(null, ATTR_COLOR_MODE); + builder.setColorMode(Integer.parseInt(colorMode)); + + String fittingMode = parser.getAttributeValue(null, ATTR_FITTING_MODE); + builder.setFittingMode(Integer.parseInt(fittingMode)); + + String orientation = parser.getAttributeValue(null, ATTR_ORIENTATION); + builder.setOrientation(Integer.parseInt(orientation)); + + parser.next(); + + skipEmptyTextTags(parser); + if (accept(parser, XmlPullParser.START_TAG, TAG_MEDIA_SIZE)) { + String id = parser.getAttributeValue(null, ATTR_ID); + label = parser.getAttributeValue(null, ATTR_LABEL); + final int widthMils = Integer.parseInt(parser.getAttributeValue(null, + ATTR_WIDTH_MILS)); + final int heightMils = Integer.parseInt(parser.getAttributeValue(null, + ATTR_HEIGHT_MILS)); + MediaSize mediaSize = new MediaSize(id, label, widthMils, heightMils); + builder.setMediaSize(mediaSize); + parser.next(); + skipEmptyTextTags(parser); + expect(parser, XmlPullParser.END_TAG, TAG_MEDIA_SIZE); + parser.next(); + } + + skipEmptyTextTags(parser); + if (accept(parser, XmlPullParser.START_TAG, TAG_RESOLUTION)) { + String id = parser.getAttributeValue(null, ATTR_ID); + label = parser.getAttributeValue(null, ATTR_LABEL); + final int horizontalDpi = Integer.parseInt(parser.getAttributeValue(null, + ATTR_HORIZONTAL_DPI)); + final int verticalDpi = Integer.parseInt(parser.getAttributeValue(null, + ATTR_VERTICAL_DPI)); + Resolution resolution = new Resolution(id, label, horizontalDpi, verticalDpi); + builder.setResolution(resolution); + parser.next(); + skipEmptyTextTags(parser); + expect(parser, XmlPullParser.END_TAG, TAG_RESOLUTION); + parser.next(); + } + + skipEmptyTextTags(parser); + if (accept(parser, XmlPullParser.START_TAG, TAG_MARGINS)) { + final int leftMils = Integer.parseInt(parser.getAttributeValue(null, + ATTR_LEFT_MILS)); + final int topMils = Integer.parseInt(parser.getAttributeValue(null, + ATTR_TOP_MILS)); + final int rightMils = Integer.parseInt(parser.getAttributeValue(null, + ATTR_RIGHT_MILS)); + final int bottomMils = Integer.parseInt(parser.getAttributeValue(null, + ATTR_BOTTOM_MILS)); + Margins margins = new Margins(leftMils, topMils, rightMils, bottomMils); + builder.setMargins(margins); + parser.next(); + skipEmptyTextTags(parser); + expect(parser, XmlPullParser.END_TAG, TAG_MARGINS); + parser.next(); + } + + skipEmptyTextTags(parser); + if (accept(parser, XmlPullParser.START_TAG, TAG_INPUT_TRAY)) { + String id = parser.getAttributeValue(null, ATTR_ID); + label = parser.getAttributeValue(null, ATTR_LABEL); + Tray tray = new Tray(id, label); + builder.setInputTray(tray); + parser.next(); + skipEmptyTextTags(parser); + expect(parser, XmlPullParser.END_TAG, TAG_INPUT_TRAY); + parser.next(); + } + + skipEmptyTextTags(parser); + if (accept(parser, XmlPullParser.START_TAG, TAG_OUTPUT_TRAY)) { + String id = parser.getAttributeValue(null, ATTR_ID); + label = parser.getAttributeValue(null, ATTR_LABEL); + Tray tray = new Tray(id, label); + builder.setOutputTray(tray); + parser.next(); + skipEmptyTextTags(parser); + expect(parser, XmlPullParser.END_TAG, TAG_OUTPUT_TRAY); + parser.next(); + } + + printJob.setAttributes(builder.create()); + + skipEmptyTextTags(parser); + expect(parser, XmlPullParser.END_TAG, TAG_ATTRIBUTES); + parser.next(); + } + + skipEmptyTextTags(parser); + if (accept(parser, XmlPullParser.START_TAG, TAG_DOCUMENT_INFO)) { + String name = parser.getAttributeValue(null, ATTR_NAME); + final int pageCount = Integer.parseInt(parser.getAttributeValue(null, + ATTR_PAGE_COUNT)); + final int contentType = Integer.parseInt(parser.getAttributeValue(null, + ATTR_CONTENT_TYPE)); + PrintDocumentInfo info = new PrintDocumentInfo.Builder(name) + .setPageCount(pageCount) + .setContentType(contentType).create(); + printJob.setDocumentInfo(info); + parser.next(); + skipEmptyTextTags(parser); + expect(parser, XmlPullParser.END_TAG, TAG_DOCUMENT_INFO); + parser.next(); + } + + mPrintJobs.add(printJob); + + if (DEBUG_PERSISTENCE) { + Log.i(LOG_TAG, "[RESTORED] " + printJob); + } + + skipEmptyTextTags(parser); + expect(parser, XmlPullParser.END_TAG, TAG_JOB); + + return true; + } + + private void expect(XmlPullParser parser, int type, String tag) + throws IOException, XmlPullParserException { + if (!accept(parser, type, tag)) { + throw new XmlPullParserException("Exepected event: " + type + + " and tag: " + tag + " but got event: " + parser.getEventType() + + " and tag:" + parser.getName()); + } + } + + private void skipEmptyTextTags(XmlPullParser parser) + throws IOException, XmlPullParserException { + while (accept(parser, XmlPullParser.TEXT, null) + && "\n".equals(parser.getText())) { + parser.next(); + } + } + + private boolean accept(XmlPullParser parser, int type, String tag) + throws IOException, XmlPullParserException { + if (parser.getEventType() != type) { + return false; + } + if (tag != null) { + if (!tag.equals(parser.getName())) { + return false; + } + } else if (parser.getName() != null) { + return false; + } + return true; + } + } + + public static abstract class PrinterDiscoverySession { + + private PrintSpoolerService mService; + + private boolean mIsStarted; + + public PrinterDiscoverySession() { + mService = PrintSpoolerService.peekInstance(); + mService.createPrinterDiscoverySession(); + mService.setPrinterDiscoverySessionClient(this); + } + + public final void startPrinterDisovery(List<PrinterId> priorityList) { + mIsStarted = true; + mService.startPrinterDiscovery(priorityList); + } + + public final void stopPrinterDiscovery() { + mIsStarted = false; + mService.stopPrinterDiscovery(); + } + + public void requestPrinterUpdated(PrinterId printerId) { + mService.requestPrinterUpdate(printerId); + } + + public final void destroy() { + mService.setPrinterDiscoverySessionClient(null); + mService.destroyPrinterDiscoverySession(); + } + + public final boolean isStarted() { + return mIsStarted; + } + + public abstract void onPrintersAdded(List<PrinterInfo> printers); + + public abstract void onPrintersRemoved(List<PrinterId> printerIds); + + public abstract void onPrintersUpdated(List<PrinterInfo> printers); + } } diff --git a/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterActivity.java new file mode 100644 index 0000000..141dbd1 --- /dev/null +++ b/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterActivity.java @@ -0,0 +1,41 @@ +/* + * 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.printspooler; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.print.PrinterId; + +import com.android.printspooler.SelectPrinterFragment.OnPrinterSelectedListener; + +public class SelectPrinterActivity extends Activity implements OnPrinterSelectedListener { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.select_printer_activity); + } + + @Override + public void onPrinterSelected(PrinterId printer) { + Intent intent = new Intent(); + intent.putExtra(PrintJobConfigActivity.INTENT_EXTRA_PRINTER_ID, printer); + setResult(RESULT_OK, intent); + finish(); + } +} diff --git a/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java b/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java new file mode 100644 index 0000000..9ca3a86 --- /dev/null +++ b/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java @@ -0,0 +1,401 @@ +/* + * 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.printspooler; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.app.Fragment; +import android.app.FragmentTransaction; +import android.app.ListFragment; +import android.app.LoaderManager; +import android.content.ComponentName; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.Loader; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ResolveInfo; +import android.net.Uri; +import android.os.Bundle; +import android.print.PrinterId; +import android.print.PrinterInfo; +import android.printservice.PrintServiceInfo; +import android.text.TextUtils; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.BaseAdapter; +import android.widget.Filter; +import android.widget.Filterable; +import android.widget.ListView; +import android.widget.SearchView; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.List; + +/** + * This is a fragment for selecting a printer. + */ +public final class SelectPrinterFragment extends ListFragment { + + private static final int LOADER_ID_PRINTERS_LOADER = 1; + + private static final String FRAGMRNT_TAG_ADD_PRINTER_DIALOG = + "FRAGMRNT_TAG_ADD_PRINTER_DIALOG"; + + private static final String FRAGMRNT_ARGUMENT_PRINT_SERVICE_INFOS = + "FRAGMRNT_ARGUMENT_PRINT_SERVICE_INFOS"; + + private final ArrayList<PrintServiceInfo> mAddPrinterServices = + new ArrayList<PrintServiceInfo>(); + + public static interface OnPrinterSelectedListener { + public void onPrinterSelected(PrinterId printerId); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setHasOptionsMenu(true); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + setListAdapter(new DestinationAdapter()); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + inflater.inflate(R.menu.select_printer_activity, menu); + + MenuItem searchItem = menu.findItem(R.id.action_search); + SearchView searchView = (SearchView) searchItem.getActionView(); + searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + @Override + public boolean onQueryTextSubmit(String query) { + return true; + } + + @Override + public boolean onQueryTextChange(String searchString) { + ((DestinationAdapter) getListAdapter()).getFilter().filter(searchString); + return true; + } + }); + + if (mAddPrinterServices.isEmpty()) { + menu.removeItem(R.id.action_add_printer); + } + } + + @Override + public void onResume() { + updateAddPrintersAdapter(); + getActivity().invalidateOptionsMenu(); + super.onResume(); + } + + @Override + public void onListItemClick(ListView list, View view, int position, long id) { + PrinterInfo printer = (PrinterInfo) list.getAdapter().getItem(position); + Activity activity = getActivity(); + if (activity instanceof OnPrinterSelectedListener) { + ((OnPrinterSelectedListener) activity).onPrinterSelected(printer.getId()); + } else { + throw new IllegalStateException("the host activity must implement" + + " OnPrinterSelectedListener"); + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == R.id.action_add_printer) { + showAddPrinterSelectionDialog(); + return true; + } + return super.onOptionsItemSelected(item); + } + + private void updateAddPrintersAdapter() { + mAddPrinterServices.clear(); + + // Get all print services. + List<ResolveInfo> resolveInfos = getActivity().getPackageManager().queryIntentServices( + new Intent(android.printservice.PrintService.SERVICE_INTERFACE), + PackageManager.GET_SERVICES | PackageManager.GET_META_DATA); + + // No print services - done. + if (resolveInfos.isEmpty()) { + return; + } + + // Find the services with valid add printers activities. + final int resolveInfoCount = resolveInfos.size(); + for (int i = 0; i < resolveInfoCount; i++) { + ResolveInfo resolveInfo = resolveInfos.get(i); + + PrintServiceInfo printServiceInfo = PrintServiceInfo.create( + resolveInfo, getActivity()); + String addPrintersActivity = printServiceInfo.getAddPrintersActivityName(); + + // No add printers activity declared - done. + if (TextUtils.isEmpty(addPrintersActivity)) { + continue; + } + + ComponentName addPrintersComponentName = new ComponentName( + resolveInfo.serviceInfo.packageName, + addPrintersActivity); + Intent addPritnersIntent = new Intent(Intent.ACTION_MAIN) + .setComponent(addPrintersComponentName); + + // The add printers activity is valid - add it. + if (!getActivity().getPackageManager().queryIntentActivities( + addPritnersIntent, 0).isEmpty()) { + mAddPrinterServices.add(printServiceInfo); + } + } + } + + private void showAddPrinterSelectionDialog() { + FragmentTransaction transaction = getFragmentManager().beginTransaction(); + Fragment oldFragment = getFragmentManager().findFragmentByTag( + FRAGMRNT_TAG_ADD_PRINTER_DIALOG); + if (oldFragment != null) { + transaction.remove(oldFragment); + } + AddPrinterAlertDialogFragment newFragment = new AddPrinterAlertDialogFragment(); + Bundle arguments = new Bundle(); + arguments.putParcelableArrayList(FRAGMRNT_ARGUMENT_PRINT_SERVICE_INFOS, + mAddPrinterServices); + newFragment.setArguments(arguments); + transaction.add(newFragment, FRAGMRNT_TAG_ADD_PRINTER_DIALOG); + transaction.commit(); + } + + public static class AddPrinterAlertDialogFragment extends DialogFragment { + + private static final String DEFAULT_MARKET_QUERY_STRING = + "market://search?q=print"; + + @Override + @SuppressWarnings("unchecked") + public Dialog onCreateDialog(Bundle savedInstanceState) { + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()) + .setTitle(R.string.choose_print_service); + + final List<PrintServiceInfo> printServices = (List<PrintServiceInfo>) (List<?>) + getArguments().getParcelableArrayList(FRAGMRNT_ARGUMENT_PRINT_SERVICE_INFOS); + + ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), + android.R.layout.simple_list_item_1); + final int printServiceCount = printServices.size(); + for (int i = 0; i < printServiceCount; i++) { + PrintServiceInfo printService = printServices.get(i); + adapter.add(printService.getResolveInfo().loadLabel( + getActivity().getPackageManager()).toString()); + } + + builder.setAdapter(adapter, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + PrintServiceInfo printService = printServices.get(which); + ComponentName componentName = new ComponentName( + printService.getResolveInfo().serviceInfo.packageName, + printService.getAddPrintersActivityName()); + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.setComponent(componentName); + startActivity(intent); + } + }); + + Uri marketUri = Uri.parse(DEFAULT_MARKET_QUERY_STRING); + final Intent marketIntent = new Intent(Intent.ACTION_VIEW, marketUri); + if (getActivity().getPackageManager().resolveActivity(marketIntent, 0) != null) { + builder.setPositiveButton(R.string.search_play_store, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + startActivity(marketIntent); + } + }); + } + + return builder.create(); + } + } + + private final class DestinationAdapter extends BaseAdapter + implements LoaderManager.LoaderCallbacks<List<PrinterInfo>>, Filterable { + + private final Object mLock = new Object(); + + private final List<PrinterInfo> mPrinters = new ArrayList<PrinterInfo>(); + + private final List<PrinterInfo> mFilteredPrinters = new ArrayList<PrinterInfo>(); + + private CharSequence mLastSearchString; + + public DestinationAdapter() { + getLoaderManager().initLoader(LOADER_ID_PRINTERS_LOADER, null, this); + } + + @Override + public Filter getFilter() { + return new Filter() { + @Override + protected FilterResults performFiltering(CharSequence constraint) { + synchronized (mLock) { + if (TextUtils.isEmpty(constraint)) { + return null; + } + FilterResults results = new FilterResults(); + List<PrinterInfo> filteredPrinters = new ArrayList<PrinterInfo>(); + String constraintLowerCase = constraint.toString().toLowerCase(); + final int printerCount = mPrinters.size(); + for (int i = 0; i < printerCount; i++) { + PrinterInfo printer = mPrinters.get(i); + if (printer.getName().toLowerCase().contains(constraintLowerCase)) { + filteredPrinters.add(printer); + } + } + results.values = filteredPrinters; + results.count = filteredPrinters.size(); + return results; + } + } + + @Override + @SuppressWarnings("unchecked") + protected void publishResults(CharSequence constraint, FilterResults results) { + synchronized (mLock) { + mLastSearchString = constraint; + mFilteredPrinters.clear(); + if (results == null) { + mFilteredPrinters.addAll(mPrinters); + } else { + List<PrinterInfo> printers = (List<PrinterInfo>) results.values; + mFilteredPrinters.addAll(printers); + } + } + notifyDataSetChanged(); + } + }; + } + + @Override + public int getCount() { + synchronized (mLock) { + return mFilteredPrinters.size(); + } + } + + @Override + public Object getItem(int position) { + synchronized (mLock) { + return mFilteredPrinters.get(position); + } + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getDropDownView(int position, View convertView, + ViewGroup parent) { + return getView(position, convertView, parent); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + if (convertView == null) { + convertView = getActivity().getLayoutInflater().inflate( + R.layout.spinner_dropdown_item, parent, false); + } + + CharSequence title = null; + CharSequence subtitle = null; + + PrinterInfo printer = (PrinterInfo) getItem(position); + title = printer.getName(); + try { + PackageManager pm = getActivity().getPackageManager(); + PackageInfo packageInfo = pm.getPackageInfo(printer.getId() + .getServiceName().getPackageName(), 0); + subtitle = packageInfo.applicationInfo.loadLabel(pm); + } catch (NameNotFoundException nnfe) { + /* ignore */ + } + + TextView titleView = (TextView) convertView.findViewById(R.id.title); + titleView.setText(title); + + TextView subtitleView = (TextView) convertView.findViewById(R.id.subtitle); + if (!TextUtils.isEmpty(subtitle)) { + subtitleView.setText(subtitle); + subtitleView.setVisibility(View.VISIBLE); + } else { + subtitleView.setText(null); + subtitleView.setVisibility(View.GONE); + } + + return convertView; + } + + @Override + public Loader<List<PrinterInfo>> onCreateLoader(int id, Bundle args) { + if (id == LOADER_ID_PRINTERS_LOADER) { + return new FusedPrintersProvider(getActivity()); + } + return null; + } + + @Override + public void onLoadFinished(Loader<List<PrinterInfo>> loader, + List<PrinterInfo> printers) { + synchronized (mLock) { + mPrinters.clear(); + mPrinters.addAll(printers); + mFilteredPrinters.clear(); + mFilteredPrinters.addAll(printers); + if (!TextUtils.isEmpty(mLastSearchString)) { + getFilter().filter(mLastSearchString); + } + } + notifyDataSetChanged(); + } + + @Override + public void onLoaderReset(Loader<List<PrinterInfo>> loader) { + synchronized (mLock) { + mPrinters.clear(); + mFilteredPrinters.clear(); + } + notifyDataSetInvalidated(); + } + } +} diff --git a/packages/SystemUI/ic_sysbar_internal.psd b/packages/SystemUI/ic_sysbar_internal.psd Binary files differdeleted file mode 100644 index 929c872..0000000 --- a/packages/SystemUI/ic_sysbar_internal.psd +++ /dev/null diff --git a/packages/SystemUI/res/drawable-nodpi/lightning.png b/packages/SystemUI/res/drawable-nodpi/lightning.png Binary files differnew file mode 100644 index 0000000..29de308 --- /dev/null +++ b/packages/SystemUI/res/drawable-nodpi/lightning.png diff --git a/packages/SystemUI/res/layout/quick_settings_tile_battery.xml b/packages/SystemUI/res/layout/quick_settings_tile_battery.xml index c41e9b9..f3b894c 100644 --- a/packages/SystemUI/res/layout/quick_settings_tile_battery.xml +++ b/packages/SystemUI/res/layout/quick_settings_tile_battery.xml @@ -19,14 +19,14 @@ android:layout_height="match_parent" android:layout_gravity="top" android:orientation="vertical"> - <ImageView + <com.android.systemui.BatteryMeterView android:id="@+id/image" android:layout_marginTop="@dimen/qs_tile_margin_above_icon" android:layout_marginBottom="@dimen/qs_tile_margin_below_icon" - android:layout_width="@dimen/qs_tile_icon_size" - android:layout_height="@dimen/qs_tile_icon_size" + android:layout_width="22dp" + android:layout_height="32dp" + android:padding="3dp" android:layout_gravity="top|center_horizontal" - android:scaleType="centerInside" /> <TextView style="@style/TextAppearance.QuickSettings.TileView" @@ -36,4 +36,4 @@ android:layout_gravity="top|center_horizontal" android:gravity="top|center_horizontal" /> -</LinearLayout>
\ No newline at end of file +</LinearLayout> diff --git a/packages/SystemUI/res/layout/signal_cluster_view.xml b/packages/SystemUI/res/layout/signal_cluster_view.xml index aab5083..66b06ef 100644 --- a/packages/SystemUI/res/layout/signal_cluster_view.xml +++ b/packages/SystemUI/res/layout/signal_cluster_view.xml @@ -20,8 +20,9 @@ <com.android.systemui.statusbar.SignalClusterView xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_height="wrap_content" + android:layout_height="match_parent" android:layout_width="wrap_content" + android:gravity="center" android:orientation="horizontal" > <FrameLayout diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml index b27536d..4741cec 100644 --- a/packages/SystemUI/res/layout/status_bar.xml +++ b/packages/SystemUI/res/layout/status_bar.xml @@ -95,11 +95,13 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" /> - <ImageView + <!-- battery must be padded below by 1px to match assets --> + <com.android.systemui.BatteryMeterView android:id="@+id/battery" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:paddingStart="4dip" + android:layout_height="16dp" + android:layout_width="10dp" + android:paddingBottom="1px" + android:layout_marginStart="4dip" /> </LinearLayout> diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 9b2c127..2bed730 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -201,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OUTO"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Kennisgewings verskyn hier"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Verkry enige tyd toegang tot hulle deur af te sleep.\nSleep weer af vir stelselkontroles."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Sleep rand van skerm om balk te wys"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Sleep van rand van skerm af om stelselbalk te wys"</string> </resources> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 4aa452d..ebbad16 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -164,7 +164,7 @@ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ተያይዟል"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"ለGPS በመፈለግ ላይ"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"በ GPS የተዘጋጀ ሥፍራ"</string> - <string name="accessibility_location_active" msgid="2427290146138169014">"ገባሪ የአካባቢ ጥያቄዎች"</string> + <string name="accessibility_location_active" msgid="2427290146138169014">"የአካባቢ ጥያቄዎች ነቅተዋል"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"ሁሉንም ማሳወቂያዎች አጽዳ"</string> <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"የመተግበሪያ መረጃ"</string> <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"ማያ ገጽ በራስ ሰር ይዞራል።"</string> @@ -201,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ራስ-ሰር"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"ማሳወቂያዎች እዚህ ላይ ይታያሉ"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"ወደ ታች በማንሸራተት በማንኛውም ጊዜ ይድረሱባቸው።\nSwipe የስርዓት መቆጣጠሪያዎችን ለማምጣት እንደገና ወደ ታች ያንሸራትቱ።"</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"አሞሌውን ለማሳየት የማያ ገጹን ጠርዝ ላይ ያንሸራትቱ"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"አሞሌውን ለማሳየት ከማያ ገጹ ጠርዝ ጀምረው ያንሸራትቱ"</string> </resources> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index f7f5e37..7aac94e 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -201,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"تلقائي"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"تظهر الإشعارات هنا"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"يمكنك الدخول إليها في أي وقت بالتمرير السريع إلى أسفل.\nيمكنك التمرير السريع إلى أسفل مرة أخرى للوصول إلى عناصر تحكم النظام."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"مرر سريعًا لحافة الشاشة لإظهار الشريط"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"مرر سريعًا من حافة الشاشة لإظهار شريط النظام"</string> </resources> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml new file mode 100644 index 0000000..d22f3e6 --- /dev/null +++ b/packages/SystemUI/res/values-az/strings.xml @@ -0,0 +1,204 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, 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 xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_label" msgid="7164937344850004466">"Sistemin İstifadə İnterfeysi"</string> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Təmizlə"</string> + <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Siyahıdan sil"</string> + <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Tətbiq infosu"</string> + <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Yeni tətbiq yoxdur"</string> + <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Son tətbiqləri kənarlaşdır"</string> + <plurals name="status_bar_accessibility_recent_apps"> + <item quantity="one" msgid="5854176083865845541">"1 son tətbiq"</item> + <item quantity="other" msgid="1040784359794890744">"%d son tətbiq"</item> + </plurals> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Bildiriş yoxdu"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Davam edir"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Bildirişlər"</string> + <string name="battery_low_title" msgid="2783104807551211639">"Adapteri qoşun"</string> + <string name="battery_low_subtitle" msgid="1752040062087829196">"Batareya azalır."</string> + <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> qalıb"</string> + <string name="invalid_charger" msgid="4549105996740522523">"USB ilə elektrik doldurma dəstəklənmir.\nYalnız adapter istifadə edin."</string> + <string name="battery_low_why" msgid="7279169609518386372">"Batareya istifadəsi"</string> + <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Ayarlar"</string> + <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string> + <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Təyyarə rejimi"</string> + <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Ekranın avto-dönüşü"</string> + <string name="status_bar_settings_mute_label" msgid="554682549917429396">"SUSDUR"</string> + <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AVTO"</string> + <string name="status_bar_settings_notifications" msgid="397146176280905137">"Bildirişlər"</string> + <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth tezerinq"</string> + <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Daxiletmə metodlarını ayarlayın"</string> + <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fiziki klaviatura"</string> + <string name="usb_device_permission_prompt" msgid="834698001271562057">"<xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqinə USB cihazına daxil olmağa icazə verilsin?"</string> + <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"<xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqinə USB aksesuarına qoşulmağa icazə verirsiniz?"</string> + <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"USB cihaz qoşulu olan zaman <xliff:g id="ACTIVITY">%1$s</xliff:g> açılsın mı?"</string> + <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"USB aksesuar qoşulu olan zaman <xliff:g id="ACTIVITY">%1$s</xliff:g> açılsın mı?"</string> + <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Heç bir quraşdırılmış tətbiq bu USB aksesuar ilə işləmir. Bu aksesuar haqqında daha ətraflı məlumatı <xliff:g id="URL">%1$s</xliff:g> adresindən öyrənin"</string> + <string name="title_usb_accessory" msgid="4966265263465181372">"USB aksesuar"</string> + <string name="label_view" msgid="6304565553218192990">"Göstər"</string> + <string name="always_use_device" msgid="1450287437017315906">"Bu USB cihaz üçün defolt olaraq istifadə edin."</string> + <string name="always_use_accessory" msgid="1210954576979621596">"Bu USB aksesuar üçün defolt istifadə edin"</string> + <string name="usb_debugging_title" msgid="4513918393387141949">"USB sazlamaya icazə verilsin?"</string> + <string name="usb_debugging_message" msgid="2220143855912376496">"Kompüterin RSA barmaq izi: \n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string> + <string name="usb_debugging_always" msgid="303335496705863070">"Bu kompüterdən həmişə icazə verilsin"</string> + <string name="compat_mode_on" msgid="6623839244840638213">"Ekranı doldurmaq üçün yaxınlaşdır"</string> + <string name="compat_mode_off" msgid="4434467572461327898">"Ekranı doldurmaq üçün uzat"</string> + <string name="compat_mode_help_header" msgid="7969493989397529910">"Uyğunluq zoomu"</string> + <string name="compat_mode_help_body" msgid="4946726776359270040">"Tətbiq kiçik bir ekran üçün nəzərdə tutulduğu zaman, zoom kontrolu saatın yanında görünür."</string> + <string name="screenshot_saving_ticker" msgid="7403652894056693515">"Skrinşot yadda saxlanılır..."</string> + <string name="screenshot_saving_title" msgid="8242282144535555697">"Skrinşot yadda saxlanır..."</string> + <string name="screenshot_saving_text" msgid="2419718443411738818">"Skrinşot yadda saxlanır."</string> + <string name="screenshot_saved_title" msgid="6461865960961414961">"Skrinşot çəkildi."</string> + <string name="screenshot_saved_text" msgid="1152839647677558815">"Skrinşotunuza baxmaq üçün toxunun"</string> + <string name="screenshot_failed_title" msgid="705781116746922771">"Skrinşot götürülə bilinmədi."</string> + <string name="screenshot_failed_text" msgid="8134011269572415402">"Skrinşotu yadda saxlamaq alınmadı, yəqin yaddaş istifadə olunur."</string> + <string name="usb_preference_title" msgid="6551050377388882787">"USB fayl transferi seçimləri"</string> + <string name="use_mtp_button_title" msgid="4333504413563023626">"Media pleyer (MTP) kimi montaj edin"</string> + <string name="use_ptp_button_title" msgid="7517127540301625751">"Kamera kimi birləşdir (PTP)"</string> + <string name="installer_cd_button_title" msgid="2312667578562201583">"Mac üçün Android File Transfer tətbiqini quraşdırın"</string> + <string name="accessibility_back" msgid="567011538994429120">"Geri"</string> + <string name="accessibility_home" msgid="8217216074895377641">"Ana səhifə"</string> + <string name="accessibility_menu" msgid="316839303324695949">"Menyu"</string> + <string name="accessibility_recent" msgid="8571350598987952883">"Son tətbiqlər"</string> + <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Daxiletmə metodu düyməsinə keç"</string> + <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Uyğunluq zoom düyməsi."</string> + <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Daha böyük ekranda uzaqlaşdır."</string> + <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth qoşulub."</string> + <string name="accessibility_bluetooth_disconnected" msgid="7416648669976870175">"Bluetooth əlaqəsi kəsildi."</string> + <string name="accessibility_no_battery" msgid="358343022352820946">"Batareya yoxdur."</string> + <string name="accessibility_battery_one_bar" msgid="7774887721891057523">"Batareya bir xətdir."</string> + <string name="accessibility_battery_two_bars" msgid="8500650438735009973">"Batareya iki xətdir."</string> + <string name="accessibility_battery_three_bars" msgid="2302983330865040446">"Batareya üç xətdir."</string> + <string name="accessibility_battery_full" msgid="8909122401720158582">"Batareya doludur"</string> + <string name="accessibility_no_phone" msgid="4894708937052611281">"Telefon yoxdur."</string> + <string name="accessibility_phone_one_bar" msgid="687699278132664115">"Şəbəkə bir xətdir."</string> + <string name="accessibility_phone_two_bars" msgid="8384905382804815201">"Şəbəkə iki xətdir."</string> + <string name="accessibility_phone_three_bars" msgid="8521904843919971885">"Şəbəkə üç xətdir."</string> + <string name="accessibility_phone_signal_full" msgid="6471834868580757898">"Tam şəbəkə."</string> + <string name="accessibility_no_data" msgid="4791966295096867555">"Məlumat yoxdur."</string> + <string name="accessibility_data_one_bar" msgid="1415625833238273628">"Data bir xətdir."</string> + <string name="accessibility_data_two_bars" msgid="6166018492360432091">"Data iki xətdir."</string> + <string name="accessibility_data_three_bars" msgid="9167670452395038520">"Data üç xətdir."</string> + <string name="accessibility_data_signal_full" msgid="2708384608124519369">"Data siqnalı tamdır."</string> + <string name="accessibility_wifi_off" msgid="3177380296697933627">"Wifi sönülüdür."</string> + <string name="accessibility_no_wifi" msgid="1425476551827924474">"Wifi bağlantı kəsildi."</string> + <string name="accessibility_wifi_one_bar" msgid="7735893178010724377">"Wifi bir xətdir."</string> + <string name="accessibility_wifi_two_bars" msgid="4994274250497262434">"Wifi iki xətdir."</string> + <string name="accessibility_wifi_three_bars" msgid="3495755044276588384">"Wifi üç xətdir."</string> + <string name="accessibility_wifi_signal_full" msgid="6853561303586480376">"Wifi siqnalı tamdır."</string> + <string name="accessibility_no_wimax" msgid="4329180129727630368">"WiMAX yoxdur."</string> + <string name="accessibility_wimax_one_bar" msgid="4170994299011863648">"WiMAX bir xətt."</string> + <string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"WiMAX iki xətdir."</string> + <string name="accessibility_wimax_three_bars" msgid="6116551636752103927">"WiMAX üç xətdir."</string> + <string name="accessibility_wimax_signal_full" msgid="2768089986795579558">"WiMAX siqnalı tamdır."</string> + <string name="accessibility_no_signal" msgid="7064645320782585167">"Siqnal yoxdur."</string> + <string name="accessibility_not_connected" msgid="6395326276213402883">"Qoşulu deyil."</string> + <string name="accessibility_zero_bars" msgid="3806060224467027887">"Sıfır xətt."</string> + <string name="accessibility_one_bar" msgid="1685730113192081895">"Bir xətt."</string> + <string name="accessibility_two_bars" msgid="6437363648385206679">"İki xətt."</string> + <string name="accessibility_three_bars" msgid="2648241415119396648">"Üç xətdir."</string> + <string name="accessibility_signal_full" msgid="9122922886519676839">"Siqnal tamdır."</string> + <string name="accessibility_desc_on" msgid="2385254693624345265">"Aktiv."</string> + <string name="accessibility_desc_off" msgid="6475508157786853157">"Deaktiv"</string> + <string name="accessibility_desc_connected" msgid="8366256693719499665">"Qoşuludur."</string> + <string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string> + <string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string> + <string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string> + <string name="accessibility_data_connection_3g" msgid="8628562305003568260">"3G"</string> + <string name="accessibility_data_connection_3.5g" msgid="8664845609981692001">"3.5G"</string> + <string name="accessibility_data_connection_4g" msgid="7741000750630089612">"4G"</string> + <string name="accessibility_data_connection_lte" msgid="5413468808637540658">"LTE"</string> + <string name="accessibility_data_connection_cdma" msgid="6132648193978823023">"CDMA"</string> + <string name="accessibility_data_connection_roaming" msgid="5977362333466556094">"Rouminq"</string> + <string name="accessibility_data_connection_edge" msgid="4477457051631979278">"Edge"</string> + <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Wi-Fi"</string> + <string name="accessibility_no_sim" msgid="8274017118472455155">"SIM yoxdur"</string> + <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Bluetooth tezering."</string> + <string name="accessibility_airplane_mode" msgid="834748999790763092">"Uçuş rejimi"</string> + <string name="accessibility_battery_level" msgid="7451474187113371965">"Batareya <xliff:g id="NUMBER">%d</xliff:g> faizdir."</string> + <string name="accessibility_settings_button" msgid="799583911231893380">"Sistem parametrləri"</string> + <string name="accessibility_notifications_button" msgid="4498000369779421892">"Bildirişlər."</string> + <string name="accessibility_remove_notification" msgid="3603099514902182350">"Bildirişi təmizlə."</string> + <string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS aktivdir."</string> + <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"GPS əldə edilir."</string> + <string name="accessibility_tty_enabled" msgid="4613200365379426561">"TeleTypewriter aktivləşdirilib."</string> + <string name="accessibility_ringer_vibrate" msgid="666585363364155055">"Zəng vibrasiyası"</string> + <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Zəngvuran səssiz."</string> + <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> çıxarıldı."</string> + <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Bildiriş uzaqlaşdırıldı."</string> + <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Bildiriş kölgəsi."</string> + <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Tez ayarlar."</string> + <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"Axırıncı tətbiqlər."</string> + <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"İstifadəçi <xliff:g id="USER">%s</xliff:g>."</string> + <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string> + <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Mobil <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string> + <string name="accessibility_quick_settings_battery" msgid="1480931583381408972">"Batareya <xliff:g id="STATE">%s</xliff:g>."</string> + <string name="accessibility_quick_settings_airplane" msgid="4196876722090224753">"Təyyarə Rejimi <xliff:g id="STATE">%s</xliff:g>."</string> + <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>."</string> + <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Alarm <xliff:g id="TIME">%s</xliff:g> üçün qurulub."</string> + <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G-3G data qeyri-aktivdir"</string> + <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G data deaktiv edildi"</string> + <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobil data qeyri-aktivdir"</string> + <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Data qeyri-aktivdir"</string> + <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Göstərilmiş data istifadə limitinə çatdınız.\n\nƏgər datanı yenidən aktivləşdirsəniz, operator tərəfindən əlavə tariflər tətbiq oluna bilər."</string> + <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Datanı yenidən aktiv et"</string> + <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"İnternet bağlantısı yoxdur"</string> + <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi qoşulub"</string> + <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS Axtarışı"</string> + <string name="gps_notification_found_text" msgid="4619274244146446464">"Yer GPS tərəfindən müəyyən edildi"</string> + <string name="accessibility_location_active" msgid="2427290146138169014">"Məkan sorğuları arxivi"</string> + <string name="accessibility_clear_all" msgid="5235938559247164925">"Bütün bildirişləri sil."</string> + <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Tətbiq infosu"</string> + <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran avtomatik döndəriləcək."</string> + <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ekran landşaft orientasiyasında kilidlənib."</string> + <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ekran portret orientasiyasında kilidlənib."</string> + <string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string> + <string name="start_dreams" msgid="7219575858348719790">"Xəyal"</string> + <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string> + <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Uçuş rejimi"</string> + <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Dolur, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string> + <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Dolub"</string> + <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string> + <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Cihaz)"</string> + <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth bağlıdır"</string> + <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Parlaqlıq"</string> + <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Avtofırlanma"</string> + <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Fırlatma kilidlidir"</string> + <string name="quick_settings_ime_label" msgid="7073463064369468429">"Daxiletmə metodu"</string> + <string name="quick_settings_location_label" msgid="5011327048748762257">"Yer"</string> + <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Yer Deaktiv"</string> + <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Media cihazı"</string> + <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string> + <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Yalnız fövqəladə zənglər"</string> + <string name="quick_settings_settings_label" msgid="5326556592578065401">"Nizamlar"</string> + <string name="quick_settings_time_label" msgid="4635969182239736408">"Vaxt"</string> + <string name="quick_settings_user_label" msgid="5238995632130897840">"Mən"</string> + <string name="quick_settings_wifi_label" msgid="9135344704899546041">"Wi-Fi"</string> + <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Bağlantı yoxdur"</string> + <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Şəbəkə yoxdur"</string> + <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi sönülüdür"</string> + <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi Ekran"</string> + <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Simsiz Ekran"</string> + <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Parlaqlıq"</string> + <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AVTO"</string> + <string name="status_bar_help_title" msgid="1199237744086469217">"Bildirişlər burada görünür"</string> + <string name="status_bar_help_text" msgid="7874607155052076323">"Aşağı sürüşdürməklə istənilən vaxt onları əldə edin.\nSistemi nəzarəti üçün yenə də aşağı sürüşdürün."</string> +</resources> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index aaca584..76d0580 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -206,8 +206,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АЎТА"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Апавяшчэнні з\'яўляюцца тут"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Атрымлівайце доступ да іх у любы час, праводзячы пальцам уніз.\nПравядзіце пальцам уніз яшчэ раз, каб атрымаць доступ да сродкаў кіравання сістэмай."</string> - <!-- no translation found for hiding_navigation_confirmation_message (3227814171674734332) --> - <skip /> - <!-- no translation found for hiding_navigation_confirmation_message_long (7854368870786524950) --> - <skip /> </resources> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index b10f5ff..605dd97 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -164,8 +164,7 @@ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: Има връзка"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"Търси се GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Местоположението е зададено от GPS"</string> - <!-- no translation found for accessibility_location_active (2427290146138169014) --> - <skip /> + <string name="accessibility_location_active" msgid="2427290146138169014">"Активни заявки за местоположение"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Изчистване на всички известия."</string> <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Информация за приложението"</string> <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Екранът ще се завърта автоматично."</string> @@ -202,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТ."</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Известията се показват тук"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Осъществявайте достъп до тях по всяко време, като прекарате пръст надолу.\nНаправете го отново за системните контроли."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Прекарайте пръст по ръба на екрана, за да се покаже лентата"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Прекарайте пръст от ръба на екрана, за да се покаже системната лента"</string> </resources> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 0a95005..83e7020 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -166,8 +166,7 @@ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: connectada"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"S\'està cercant un GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"S\'ha establert la ubicació per GPS"</string> - <!-- no translation found for accessibility_location_active (2427290146138169014) --> - <skip /> + <string name="accessibility_location_active" msgid="2427290146138169014">"Sol·licituds d\'ubicació actives"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Esborra totes les notificacions."</string> <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informació de l\'aplicació"</string> <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"La pantalla girarà automàticament."</string> @@ -204,6 +203,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMÀTICA"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Les notificacions apareixen aquí"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Accedeix-hi en qualsevol moment: només has de fer lliscar el dit cap avall.\nTorna a fer lliscar el dit cap avall per fer que es mostrin els controls del sistema."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Fes lliscar el dit per la vora de la pantalla perquè es mostri la barra"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Fes lliscar el dit des de la vora de la pantalla perquè es mostri la barra del sistema"</string> </resources> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index 178238f..4497735 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -203,6 +203,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATICKY"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Zde se zobrazují oznámení"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Můžete je kdykoli zobrazit tím, že přejedete prstem dolů.\nPřejedete-li prstem dolů ještě jednou, zobrazí se ovládací prvky systému."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Panel zobrazíte přejetím přes okraj obrazovky"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Systémový panel zobrazíte přejetím přes okraj obrazovky"</string> </resources> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 1c772b5..be42612 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -164,8 +164,7 @@ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi er forbundet"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"Søger efter GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Placeringen er angivet ved hjælp af GPS"</string> - <!-- no translation found for accessibility_location_active (2427290146138169014) --> - <skip /> + <string name="accessibility_location_active" msgid="2427290146138169014">"Aktive placeringsanmodninger"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Ryd alle meddelelser."</string> <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Oplysninger om appen"</string> <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skærmen roterer automatisk."</string> @@ -202,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Underretninger vises her"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Få adgang til dem når som helst ved at stryge ned.\nStryg ned igen for at komme til systemindstillingerne."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Stryg fra skærmkanten for at se bjælken"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Stryg med fingeren fra skærmens kant for at få vist systembjælken"</string> </resources> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 86ea82d..052990c 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -166,8 +166,7 @@ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WLAN verbunden"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS wird gesucht"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Standort durch GPS festgelegt"</string> - <!-- no translation found for accessibility_location_active (2427290146138169014) --> - <skip /> + <string name="accessibility_location_active" msgid="2427290146138169014">"Standortanfragen aktiv"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Alle Benachrichtigungen löschen"</string> <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"App-Details"</string> <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Bildschirm wird automatisch gedreht."</string> @@ -204,6 +203,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Benachrichtigungen erscheinen hier"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Greifen Sie jederzeit auf sie zu, indem Sie nach unten wischen.\nWischen Sie für Systemeinstellungen erneut nach unten."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Zum Einblenden der Leiste vom Rand weg wischen"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Zum Einblenden der Systemleiste vom Display-Rand weg wischen"</string> </resources> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index f965773..d23b8d5 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -203,6 +203,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ΑΥΤΟΜΑΤΗ"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Οι ειδοποιήσεις εμφανίζονται εδώ"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Μεταβείτε σε αυτές ανά πάσα στιγμή σύροντας προς τα κάτω.\nΣύρετε ξανά προς τα κάτω για τα στοιχεία ελέγχου συστήματος."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Σύρετε από την άκρη της οθόνης για να εμφανίσετε τη γραμμή"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Σύρετε από την άκρη της οθόνης για να εμφανίσετε τη γραμμή συστήματος"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index a7d6213..2ac1040 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -201,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Notifications appear here"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Access them any time by swiping down.\nSwipe down again for system controls."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Swipe edge of screen to reveal bar"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Swipe from edge of screen to reveal system bar"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml new file mode 100644 index 0000000..2ac1040 --- /dev/null +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -0,0 +1,204 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, 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 xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_label" msgid="7164937344850004466">"System UI"</string> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Clear"</string> + <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Remove from list"</string> + <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"App info"</string> + <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"No recent apps"</string> + <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Dismiss recent apps"</string> + <plurals name="status_bar_accessibility_recent_apps"> + <item quantity="one" msgid="5854176083865845541">"1 recent app"</item> + <item quantity="other" msgid="1040784359794890744">"%d recent apps"</item> + </plurals> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"No notifications"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Ongoing"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string> + <string name="battery_low_title" msgid="2783104807551211639">"Connect charger"</string> + <string name="battery_low_subtitle" msgid="1752040062087829196">"The battery is getting low."</string> + <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> remaining"</string> + <string name="invalid_charger" msgid="4549105996740522523">"USB charging not supported.\nUse only the supplied charger."</string> + <string name="battery_low_why" msgid="7279169609518386372">"Battery use"</string> + <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Settings"</string> + <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string> + <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Aeroplane mode"</string> + <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Auto-rotate screen"</string> + <string name="status_bar_settings_mute_label" msgid="554682549917429396">"MUTE"</string> + <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string> + <string name="status_bar_settings_notifications" msgid="397146176280905137">"Notifications"</string> + <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth tethered"</string> + <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Set up input methods"</string> + <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Physical keyboard"</string> + <string name="usb_device_permission_prompt" msgid="834698001271562057">"Allow the app <xliff:g id="APPLICATION">%1$s</xliff:g> to access the USB device?"</string> + <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Allow the app <xliff:g id="APPLICATION">%1$s</xliff:g> to access the USB accessory?"</string> + <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Open <xliff:g id="ACTIVITY">%1$s</xliff:g> when this USB device is connected?"</string> + <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Open <xliff:g id="ACTIVITY">%1$s</xliff:g> when this USB accessory is connected?"</string> + <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"No installed apps work with this USB accessory. Learn more about this accessory at <xliff:g id="URL">%1$s</xliff:g>"</string> + <string name="title_usb_accessory" msgid="4966265263465181372">"USB accessory"</string> + <string name="label_view" msgid="6304565553218192990">"View"</string> + <string name="always_use_device" msgid="1450287437017315906">"Use by default for this USB device"</string> + <string name="always_use_accessory" msgid="1210954576979621596">"Use by default for this USB accessory"</string> + <string name="usb_debugging_title" msgid="4513918393387141949">"Allow USB debugging?"</string> + <string name="usb_debugging_message" msgid="2220143855912376496">"The computer\'s RSA key fingerprint is:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string> + <string name="usb_debugging_always" msgid="303335496705863070">"Always allow from this computer"</string> + <string name="compat_mode_on" msgid="6623839244840638213">"Zoom to fill screen"</string> + <string name="compat_mode_off" msgid="4434467572461327898">"Stretch to fill screen"</string> + <string name="compat_mode_help_header" msgid="7969493989397529910">"Compatibility zoom"</string> + <string name="compat_mode_help_body" msgid="4946726776359270040">"When an app was designed for a smaller screen, a zoom control will appear by the clock."</string> + <string name="screenshot_saving_ticker" msgid="7403652894056693515">"Saving screenshot…"</string> + <string name="screenshot_saving_title" msgid="8242282144535555697">"Saving screenshot…"</string> + <string name="screenshot_saving_text" msgid="2419718443411738818">"Screenshot is being saved."</string> + <string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshot captured."</string> + <string name="screenshot_saved_text" msgid="1152839647677558815">"Touch to view your screenshot."</string> + <string name="screenshot_failed_title" msgid="705781116746922771">"Couldn\'t capture screenshot."</string> + <string name="screenshot_failed_text" msgid="8134011269572415402">"Couldn\'t save screenshot. Storage may be in use."</string> + <string name="usb_preference_title" msgid="6551050377388882787">"USB file transfer options"</string> + <string name="use_mtp_button_title" msgid="4333504413563023626">"Mount as a media player (MTP)"</string> + <string name="use_ptp_button_title" msgid="7517127540301625751">"Mount as a camera (PTP)"</string> + <string name="installer_cd_button_title" msgid="2312667578562201583">"Install Android File Transfer application for Mac"</string> + <string name="accessibility_back" msgid="567011538994429120">"Back"</string> + <string name="accessibility_home" msgid="8217216074895377641">"Home"</string> + <string name="accessibility_menu" msgid="316839303324695949">"Menu"</string> + <string name="accessibility_recent" msgid="8571350598987952883">"Recent apps"</string> + <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Switch input method button."</string> + <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Compatibility zoom button."</string> + <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom smaller to larger screen."</string> + <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connected."</string> + <string name="accessibility_bluetooth_disconnected" msgid="7416648669976870175">"Bluetooth disconnected."</string> + <string name="accessibility_no_battery" msgid="358343022352820946">"No battery."</string> + <string name="accessibility_battery_one_bar" msgid="7774887721891057523">"Battery one bar."</string> + <string name="accessibility_battery_two_bars" msgid="8500650438735009973">"Battery two bars."</string> + <string name="accessibility_battery_three_bars" msgid="2302983330865040446">"Battery three bars."</string> + <string name="accessibility_battery_full" msgid="8909122401720158582">"Battery full."</string> + <string name="accessibility_no_phone" msgid="4894708937052611281">"No phone."</string> + <string name="accessibility_phone_one_bar" msgid="687699278132664115">"Phone one bar."</string> + <string name="accessibility_phone_two_bars" msgid="8384905382804815201">"Phone two bars."</string> + <string name="accessibility_phone_three_bars" msgid="8521904843919971885">"Phone three bars."</string> + <string name="accessibility_phone_signal_full" msgid="6471834868580757898">"Phone signal full."</string> + <string name="accessibility_no_data" msgid="4791966295096867555">"No data."</string> + <string name="accessibility_data_one_bar" msgid="1415625833238273628">"Data one bar."</string> + <string name="accessibility_data_two_bars" msgid="6166018492360432091">"Data two bars."</string> + <string name="accessibility_data_three_bars" msgid="9167670452395038520">"Data three bars."</string> + <string name="accessibility_data_signal_full" msgid="2708384608124519369">"Data signal full."</string> + <string name="accessibility_wifi_off" msgid="3177380296697933627">"Wi-Fi off."</string> + <string name="accessibility_no_wifi" msgid="1425476551827924474">"Wi-Fi disconnected."</string> + <string name="accessibility_wifi_one_bar" msgid="7735893178010724377">"Wi-Fi one bar."</string> + <string name="accessibility_wifi_two_bars" msgid="4994274250497262434">"Wi-Fi two bars."</string> + <string name="accessibility_wifi_three_bars" msgid="3495755044276588384">"Wi-Fi three bars."</string> + <string name="accessibility_wifi_signal_full" msgid="6853561303586480376">"Wi-Fi signal full."</string> + <string name="accessibility_no_wimax" msgid="4329180129727630368">"No WiMAX."</string> + <string name="accessibility_wimax_one_bar" msgid="4170994299011863648">"WiMAX one bar."</string> + <string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"WiMAX two bars."</string> + <string name="accessibility_wimax_three_bars" msgid="6116551636752103927">"WiMAX three bars."</string> + <string name="accessibility_wimax_signal_full" msgid="2768089986795579558">"WiMAX signal full."</string> + <string name="accessibility_no_signal" msgid="7064645320782585167">"No signal."</string> + <string name="accessibility_not_connected" msgid="6395326276213402883">"Not connected."</string> + <string name="accessibility_zero_bars" msgid="3806060224467027887">"Zero bars."</string> + <string name="accessibility_one_bar" msgid="1685730113192081895">"One bar."</string> + <string name="accessibility_two_bars" msgid="6437363648385206679">"Two bars."</string> + <string name="accessibility_three_bars" msgid="2648241415119396648">"Three bars."</string> + <string name="accessibility_signal_full" msgid="9122922886519676839">"Signal full."</string> + <string name="accessibility_desc_on" msgid="2385254693624345265">"On."</string> + <string name="accessibility_desc_off" msgid="6475508157786853157">"Off."</string> + <string name="accessibility_desc_connected" msgid="8366256693719499665">"Connected."</string> + <string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string> + <string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string> + <string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string> + <string name="accessibility_data_connection_3g" msgid="8628562305003568260">"3G"</string> + <string name="accessibility_data_connection_3.5g" msgid="8664845609981692001">"3.5G"</string> + <string name="accessibility_data_connection_4g" msgid="7741000750630089612">"4G"</string> + <string name="accessibility_data_connection_lte" msgid="5413468808637540658">"LTE"</string> + <string name="accessibility_data_connection_cdma" msgid="6132648193978823023">"CDMA"</string> + <string name="accessibility_data_connection_roaming" msgid="5977362333466556094">"Roaming"</string> + <string name="accessibility_data_connection_edge" msgid="4477457051631979278">"Edge"</string> + <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Wi-Fi"</string> + <string name="accessibility_no_sim" msgid="8274017118472455155">"No SIM."</string> + <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Bluetooth tethering"</string> + <string name="accessibility_airplane_mode" msgid="834748999790763092">"Aeroplane mode"</string> + <string name="accessibility_battery_level" msgid="7451474187113371965">"Battery <xliff:g id="NUMBER">%d</xliff:g> per cent."</string> + <string name="accessibility_settings_button" msgid="799583911231893380">"System settings"</string> + <string name="accessibility_notifications_button" msgid="4498000369779421892">"Notifications."</string> + <string name="accessibility_remove_notification" msgid="3603099514902182350">"Clear notification."</string> + <string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS enabled."</string> + <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"GPS acquiring."</string> + <string name="accessibility_tty_enabled" msgid="4613200365379426561">"TeleTypewriter enabled."</string> + <string name="accessibility_ringer_vibrate" msgid="666585363364155055">"Ringer vibrate."</string> + <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Ringer silent."</string> + <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> dismissed."</string> + <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notification dismissed."</string> + <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Notification shade."</string> + <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Quick settings."</string> + <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"Recent apps"</string> + <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"User <xliff:g id="USER">%s</xliff:g>."</string> + <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string> + <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Mobile <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string> + <string name="accessibility_quick_settings_battery" msgid="1480931583381408972">"Battery <xliff:g id="STATE">%s</xliff:g>."</string> + <string name="accessibility_quick_settings_airplane" msgid="4196876722090224753">"Aeroplane Mode <xliff:g id="STATE">%s</xliff:g>."</string> + <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>."</string> + <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Alarm set for <xliff:g id="TIME">%s</xliff:g>."</string> + <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G-3G data disabled"</string> + <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G data disabled"</string> + <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobile data disabled"</string> + <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Data disabled"</string> + <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"You\'ve reached the specified data usage limit.\n\nIf you re-enable data, you may be charged by the operator."</string> + <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Reenable data"</string> + <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No Internet connection"</string> + <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connected"</string> + <string name="gps_notification_searching_text" msgid="8574247005642736060">"Searching for GPS"</string> + <string name="gps_notification_found_text" msgid="4619274244146446464">"Location set by GPS"</string> + <string name="accessibility_location_active" msgid="2427290146138169014">"Location requests active"</string> + <string name="accessibility_clear_all" msgid="5235938559247164925">"Clear all notifications."</string> + <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"App info"</string> + <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Screen will rotate automatically."</string> + <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Screen is locked in landscape orientation."</string> + <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Screen is locked in portrait orientation."</string> + <string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string> + <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string> + <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string> + <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Aeroplane mode"</string> + <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Charging, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string> + <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Charged"</string> + <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string> + <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Devices)"</string> + <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth Off"</string> + <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Brightness"</string> + <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Auto Rotate"</string> + <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Rotation Locked"</string> + <string name="quick_settings_ime_label" msgid="7073463064369468429">"Input Method"</string> + <string name="quick_settings_location_label" msgid="5011327048748762257">"Location"</string> + <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Location Off"</string> + <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Media device"</string> + <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string> + <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Emergency Calls Only"</string> + <string name="quick_settings_settings_label" msgid="5326556592578065401">"Settings"</string> + <string name="quick_settings_time_label" msgid="4635969182239736408">"Time"</string> + <string name="quick_settings_user_label" msgid="5238995632130897840">"Me"</string> + <string name="quick_settings_wifi_label" msgid="9135344704899546041">"Wi-Fi"</string> + <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Not Connected"</string> + <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"No Network"</string> + <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Off"</string> + <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi Display"</string> + <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Wireless Display"</string> + <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brightness"</string> + <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string> + <string name="status_bar_help_title" msgid="1199237744086469217">"Notifications appear here"</string> + <string name="status_bar_help_text" msgid="7874607155052076323">"Access them any time by swiping down.\nSwipe down again for system controls."</string> +</resources> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index bdd0363..d11d413 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -166,8 +166,7 @@ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"Buscando GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"La ubicación se estableció por GPS"</string> - <!-- no translation found for accessibility_location_active (2427290146138169014) --> - <skip /> + <string name="accessibility_location_active" msgid="2427290146138169014">"Solicitudes de ubicación activas"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Eliminar todas las notificaciones"</string> <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Información de la aplicación"</string> <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"La pantalla girará automáticamente."</string> @@ -204,6 +203,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMÁTICO"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Las notificaciones aparecen aquí."</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Desliza el dedo hacia abajo para acceder al contenido.\nVuelve a deslizar el dedo hacia abajo para acceder a los controles del sistema."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Desliza el dedo desde el borde de la pantalla para mostrar la barra."</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Desliza el dedo desde el borde de la pantalla para mostrar la barra del sistema."</string> </resources> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index a81a2b4..068af45 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -201,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Las notificaciones aparecen aquí"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Desliza el dedo hacia abajo para acceder al contenido.\nVuelve a deslizar el dedo hacia abajo para acceder a los controles del sistema."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Desliza el borde de la pantalla para mostrar la barra"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Desliza el borde de la pantalla para mostrar la barra del sistema"</string> </resources> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index c4fda13..28ece65 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -201,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMAATNE"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Märguanded ilmuvad siia"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Juurdepääs igal ajal sõrmega alla pühkides.\nSüsteemi juhtnuppude jaoks pühkige uuesti alla."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Riba kuvamiseks pühkige ekraani serva"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Süsteemiriba kuvamiseks pühkige ekraani servast"</string> </resources> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index a84b9b4..2ba0427 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -201,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"خودکار"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"اعلانها در اینجا نمایش داده میشوند"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"با کشیدن انگشت به طرف پایین به آنها دسترسی پیدا کنید.\nبرای کنترلهای سیستم دوباره انگشت خود را به سمت پایین بکشید."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"برای نمایش نوار، انگشت خود را از لبه صفحه به داخل بکشید"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"برای نمایش نوار سیستم، انگشت خود را از لبه صفحه به داخل بکشید"</string> </resources> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index f2cce06..b652cb0 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -201,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Ilmoitukset näkyvät tässä"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Näet ilmoitukset liu\'uttamalla sormea alas ruudulla.\nVoit palauttaa järjestelmän ohjaimet näkyviin liu\'uttamalla sormea alas uudelleen."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Tuo palkki näkyviin liu\'uttamalla ruudun reunasta"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Tuo järjestelmäpalkki näkyviin liu\'uttamalla ruudun reunasta"</string> </resources> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml new file mode 100644 index 0000000..8fb7340 --- /dev/null +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -0,0 +1,206 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, 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 xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_label" msgid="7164937344850004466">"IU système"</string> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Effacer"</string> + <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Supprimer de la liste"</string> + <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Informations sur l\'application"</string> + <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Aucune application récente"</string> + <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Masquer les applications récentes"</string> + <plurals name="status_bar_accessibility_recent_apps"> + <item quantity="one" msgid="5854176083865845541">"1 application récente"</item> + <item quantity="other" msgid="1040784359794890744">"%d applications récentes"</item> + </plurals> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Aucune notification"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"En cours"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string> + <string name="battery_low_title" msgid="2783104807551211639">"Brancher le chargeur"</string> + <string name="battery_low_subtitle" msgid="1752040062087829196">"Le niveau de la batterie est faible."</string> + <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restant(s)"</string> + <string name="invalid_charger" msgid="4549105996740522523">"Chargement USB non compatible.\nVous devez utiliser le chargeur fourni."</string> + <string name="battery_low_why" msgid="7279169609518386372">"Utilisation de la batterie"</string> + <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Paramètres"</string> + <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string> + <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Mode Avion"</string> + <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Rotation auto de l\'écran"</string> + <string name="status_bar_settings_mute_label" msgid="554682549917429396">"MUET"</string> + <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTOMATIQUE"</string> + <string name="status_bar_settings_notifications" msgid="397146176280905137">"Notifications"</string> + <string name="bluetooth_tethered" msgid="7094101612161133267">"Connexion Bluetooth partagée"</string> + <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Configurer les modes de saisie"</string> + <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Clavier physique"</string> + <string name="usb_device_permission_prompt" msgid="834698001271562057">"Autoriser l\'application <xliff:g id="APPLICATION">%1$s</xliff:g> à accéder au périphérique USB?"</string> + <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Autoriser l\'application <xliff:g id="APPLICATION">%1$s</xliff:g> à accéder à l\'accessoire USB?"</string> + <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Ouvrir <xliff:g id="ACTIVITY">%1$s</xliff:g> lors de la connexion de ce périphérique USB?"</string> + <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Ouvrir <xliff:g id="ACTIVITY">%1$s</xliff:g> lors de la connexion de cet accessoire USB?"</string> + <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Aucune application installée compatible avec accessoire USB. En savoir plus sur <xliff:g id="URL">%1$s</xliff:g>"</string> + <string name="title_usb_accessory" msgid="4966265263465181372">"Accessoire USB"</string> + <string name="label_view" msgid="6304565553218192990">"Afficher"</string> + <string name="always_use_device" msgid="1450287437017315906">"Utiliser par défaut pour ce périphérique USB"</string> + <string name="always_use_accessory" msgid="1210954576979621596">"Utiliser par défaut pour cet accessoire USB"</string> + <string name="usb_debugging_title" msgid="4513918393387141949">"Autoriser le débogage USB?"</string> + <string name="usb_debugging_message" msgid="2220143855912376496">"Empreinte numérique de la clé RSA de l\'ordinateur : \n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string> + <string name="usb_debugging_always" msgid="303335496705863070">"Toujours autoriser sur cet ordinateur"</string> + <string name="compat_mode_on" msgid="6623839244840638213">"Zoomer pour remplir l\'écran"</string> + <string name="compat_mode_off" msgid="4434467572461327898">"Étirer pour remplir l\'écran"</string> + <string name="compat_mode_help_header" msgid="7969493989397529910">"Zoom de compatibilité"</string> + <string name="compat_mode_help_body" msgid="4946726776359270040">"Si une application a été conçue pour un écran plus petit, une commande de zoom s\'affiche à côté de l\'horloge."</string> + <string name="screenshot_saving_ticker" msgid="7403652894056693515">"Enregistrement capture écran…"</string> + <string name="screenshot_saving_title" msgid="8242282144535555697">"Enregistrement capture écran…"</string> + <string name="screenshot_saving_text" msgid="2419718443411738818">"Enregistrement de la capture d\'écran en cours…"</string> + <string name="screenshot_saved_title" msgid="6461865960961414961">"Capture d\'écran réussie"</string> + <string name="screenshot_saved_text" msgid="1152839647677558815">"Appuyez pour afficher votre capture d\'écran."</string> + <string name="screenshot_failed_title" msgid="705781116746922771">"Impossible de réaliser une capture d\'écran"</string> + <string name="screenshot_failed_text" msgid="8134011269572415402">"Impossible enregistrer capture d\'écran. Périphérique de stockage peut-être en cours d\'utilisation."</string> + <string name="usb_preference_title" msgid="6551050377388882787">"Options transfert fichiers USB"</string> + <string name="use_mtp_button_title" msgid="4333504413563023626">"Installer comme un lecteur multimédia (MTP)"</string> + <string name="use_ptp_button_title" msgid="7517127540301625751">"Installer comme un appareil photo (PTP)"</string> + <string name="installer_cd_button_title" msgid="2312667578562201583">"Installer application Android File Transfer (Mac)"</string> + <string name="accessibility_back" msgid="567011538994429120">"Précédent"</string> + <string name="accessibility_home" msgid="8217216074895377641">"Domicile"</string> + <string name="accessibility_menu" msgid="316839303324695949">"Menu"</string> + <string name="accessibility_recent" msgid="8571350598987952883">"Applications récentes"</string> + <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Bouton \"Changer le mode de saisie\""</string> + <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Bouton \"Zoom de compatibilité\""</string> + <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de compatibilité avec la taille de l\'écran"</string> + <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connecté"</string> + <string name="accessibility_bluetooth_disconnected" msgid="7416648669976870175">"Bluetooth déconnecté"</string> + <string name="accessibility_no_battery" msgid="358343022352820946">"Batterie vide"</string> + <string name="accessibility_battery_one_bar" msgid="7774887721891057523">"Niveau de batterie : faible"</string> + <string name="accessibility_battery_two_bars" msgid="8500650438735009973">"Niveau de batterie : moyen"</string> + <string name="accessibility_battery_three_bars" msgid="2302983330865040446">"Niveau de batterie : bon"</string> + <string name="accessibility_battery_full" msgid="8909122401720158582">"Batterie pleine"</string> + <string name="accessibility_no_phone" msgid="4894708937052611281">"Aucun signal"</string> + <string name="accessibility_phone_one_bar" msgid="687699278132664115">"Signal : faible"</string> + <string name="accessibility_phone_two_bars" msgid="8384905382804815201">"Signal : moyen"</string> + <string name="accessibility_phone_three_bars" msgid="8521904843919971885">"Signal : bon"</string> + <string name="accessibility_phone_signal_full" msgid="6471834868580757898">"Signal excellent"</string> + <string name="accessibility_no_data" msgid="4791966295096867555">"Aucun signal"</string> + <string name="accessibility_data_one_bar" msgid="1415625833238273628">"Signal faible"</string> + <string name="accessibility_data_two_bars" msgid="6166018492360432091">"Signal moyen"</string> + <string name="accessibility_data_three_bars" msgid="9167670452395038520">"Signal bon"</string> + <string name="accessibility_data_signal_full" msgid="2708384608124519369">"Signal excellent"</string> + <string name="accessibility_wifi_off" msgid="3177380296697933627">"Wi-Fi désactivé"</string> + <string name="accessibility_no_wifi" msgid="1425476551827924474">"Wi-Fi déconnecté"</string> + <string name="accessibility_wifi_one_bar" msgid="7735893178010724377">"Signal Wi-Fi faible"</string> + <string name="accessibility_wifi_two_bars" msgid="4994274250497262434">"Signal Wi-Fi moyen"</string> + <string name="accessibility_wifi_three_bars" msgid="3495755044276588384">"Signal Wi-Fi bon"</string> + <string name="accessibility_wifi_signal_full" msgid="6853561303586480376">"Signal Wi-Fi excellent"</string> + <string name="accessibility_no_wimax" msgid="4329180129727630368">"Aucun signal WiMAX"</string> + <string name="accessibility_wimax_one_bar" msgid="4170994299011863648">"Signal WiMAX : faible"</string> + <string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"Signal WiMAX : moyen"</string> + <string name="accessibility_wimax_three_bars" msgid="6116551636752103927">"Signal WiMAX : bon"</string> + <string name="accessibility_wimax_signal_full" msgid="2768089986795579558">"Signal WiMAX : excellent"</string> + <string name="accessibility_no_signal" msgid="7064645320782585167">"Aucun signal"</string> + <string name="accessibility_not_connected" msgid="6395326276213402883">"Non connecté"</string> + <string name="accessibility_zero_bars" msgid="3806060224467027887">"Aucun signal"</string> + <string name="accessibility_one_bar" msgid="1685730113192081895">"Signal faible"</string> + <string name="accessibility_two_bars" msgid="6437363648385206679">"Moyen"</string> + <string name="accessibility_three_bars" msgid="2648241415119396648">"Bon"</string> + <string name="accessibility_signal_full" msgid="9122922886519676839">"Signal excellent"</string> + <string name="accessibility_desc_on" msgid="2385254693624345265">"Activé"</string> + <string name="accessibility_desc_off" msgid="6475508157786853157">"Désactivé"</string> + <string name="accessibility_desc_connected" msgid="8366256693719499665">"Connecté"</string> + <string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string> + <string name="accessibility_data_connection_1x" msgid="994133468120244018">"1x"</string> + <string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"3G+"</string> + <string name="accessibility_data_connection_3g" msgid="8628562305003568260">"3G"</string> + <string name="accessibility_data_connection_3.5g" msgid="8664845609981692001">"3G+"</string> + <string name="accessibility_data_connection_4g" msgid="7741000750630089612">"4G"</string> + <string name="accessibility_data_connection_lte" msgid="5413468808637540658">"LTE"</string> + <string name="accessibility_data_connection_cdma" msgid="6132648193978823023">"CDMA"</string> + <string name="accessibility_data_connection_roaming" msgid="5977362333466556094">"Itinérance"</string> + <string name="accessibility_data_connection_edge" msgid="4477457051631979278">"EDGE"</string> + <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Wi-Fi"</string> + <string name="accessibility_no_sim" msgid="8274017118472455155">"Aucune carte SIM"</string> + <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Partage de connexion Bluetooth"</string> + <string name="accessibility_airplane_mode" msgid="834748999790763092">"Mode Avion"</string> + <!-- String.format failed for translation --> + <!-- no translation found for accessibility_battery_level (7451474187113371965) --> + <skip /> + <string name="accessibility_settings_button" msgid="799583911231893380">"Paramètres système"</string> + <string name="accessibility_notifications_button" msgid="4498000369779421892">"Notifications"</string> + <string name="accessibility_remove_notification" msgid="3603099514902182350">"Supprimer la notification"</string> + <string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS activé"</string> + <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"Acquisition de données GPS"</string> + <string name="accessibility_tty_enabled" msgid="4613200365379426561">"Téléscripteur activé"</string> + <string name="accessibility_ringer_vibrate" msgid="666585363364155055">"Sonnerie en mode vibreur"</string> + <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Sonnerie en mode silencieux"</string> + <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Application \"<xliff:g id="APP">%s</xliff:g>\" ignorée."</string> + <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notification masquée"</string> + <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Volet des notifications"</string> + <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Paramètres rapides"</string> + <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"Applications récentes"</string> + <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Utilisateur : <xliff:g id="USER">%s</xliff:g>"</string> + <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>, <xliff:g id="NETWORK">%2$s</xliff:g>"</string> + <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Signal mobile : <xliff:g id="SIGNAL">%1$s</xliff:g>, <xliff:g id="TYPE">%2$s</xliff:g>, <xliff:g id="NETWORK">%3$s</xliff:g>"</string> + <string name="accessibility_quick_settings_battery" msgid="1480931583381408972">"Batterie : <xliff:g id="STATE">%s</xliff:g>"</string> + <string name="accessibility_quick_settings_airplane" msgid="4196876722090224753">"Mode Avion : <xliff:g id="STATE">%s</xliff:g>"</string> + <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth : <xliff:g id="STATE">%s</xliff:g>"</string> + <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Alarme réglée sur <xliff:g id="TIME">%s</xliff:g>"</string> + <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Données 2G-3G désactivées"</string> + <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Données 4G désactivées"</string> + <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Données mobiles désactivées"</string> + <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Données désactivées"</string> + <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Vous avez atteint le plafond de consommation de données spécifié.\n\nSi vous utilisez des données supplémentaires, celles-ci pourront être facturées par l\'opérateur."</string> + <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Réactiver connexion données"</string> + <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Aucune connexion Internet"</string> + <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Connecté au Wi-Fi"</string> + <string name="gps_notification_searching_text" msgid="8574247005642736060">"Recherche de GPS..."</string> + <string name="gps_notification_found_text" msgid="4619274244146446464">"Position définie par GPS"</string> + <string name="accessibility_location_active" msgid="2427290146138169014">"Demandes de localisation actives"</string> + <string name="accessibility_clear_all" msgid="5235938559247164925">"Supprimer toutes les notifications"</string> + <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informations sur l\'application"</string> + <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"L\'écran pivote automatiquement."</string> + <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"L\'écran est verrouillé en mode paysage."</string> + <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"L\'écran est verrouillé en mode portrait."</string> + <string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string> + <string name="start_dreams" msgid="7219575858348719790">"Écran de veille"</string> + <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string> + <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Mode Avion"</string> + <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"En charge (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string> + <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Chargée"</string> + <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string> + <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> appareils)"</string> + <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"BLUETOOTH DÉSACTIVÉ"</string> + <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Luminosité"</string> + <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Rotation automatique"</string> + <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Rotation verrouillée"</string> + <string name="quick_settings_ime_label" msgid="7073463064369468429">"Mode de saisie"</string> + <string name="quick_settings_location_label" msgid="5011327048748762257">"Position"</string> + <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Localisation désactivée"</string> + <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Appareil multimédia"</string> + <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string> + <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Appels d\'urgence uniquement"</string> + <string name="quick_settings_settings_label" msgid="5326556592578065401">"Paramètres"</string> + <string name="quick_settings_time_label" msgid="4635969182239736408">"Heures"</string> + <string name="quick_settings_user_label" msgid="5238995632130897840">"Moi"</string> + <string name="quick_settings_wifi_label" msgid="9135344704899546041">"Wi-Fi"</string> + <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Non connecté"</string> + <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Aucun réseau"</string> + <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi désactivé"</string> + <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Affichage Wi-Fi"</string> + <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Affichage sans fil"</string> + <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminosité"</string> + <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATIQUE"</string> + <string name="status_bar_help_title" msgid="1199237744086469217">"Les notifications s’affichent ici"</string> + <string name="status_bar_help_text" msgid="7874607155052076323">"Accédez-y à tout moment en faisant glisser le doigt vers le bas.\nRépétez l\'opération pour accéder aux commandes du système."</string> +</resources> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 7fe1143..d00e4a3 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -166,8 +166,7 @@ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Connecté au Wi-Fi"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"Recherche de GPS..."</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Position définie par GPS"</string> - <!-- no translation found for accessibility_location_active (2427290146138169014) --> - <skip /> + <string name="accessibility_location_active" msgid="2427290146138169014">"Demandes de localisation actives"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Supprimer toutes les notifications"</string> <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informations sur l\'application"</string> <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"L\'écran pivote automatiquement."</string> @@ -204,6 +203,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATIQUE"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Les notifications s’affichent ici"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Accédez-y à tout moment en faisant glisser le doigt vers le bas.\nRépétez l\'opération pour accéder aux commandes du système."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Faites glisser le doigt sur le côté de l\'écran pour afficher la barre."</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Faites glisser le doigt à partir d\'un côté de l\'écran pour afficher la barre système."</string> </resources> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index a1de7a1..45b5813 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -201,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"स्वत:"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"सूचनाएं यहां दिखाई देती हैं"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"नीचे स्वाइप करके उन तक कभी भी पहुंचें.\nसिस्टम नियंत्रणों के लिए पुन: नीचे स्वाइप करें."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"बार को प्रदर्शित करने के लिए स्क्रीन के किनारे को स्वाइप करें"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"सिस्टम बार को प्रदर्शित करने के लिए स्क्रीन के किनारे से स्वाइप करें"</string> </resources> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index f8ff35d..9f8559c 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -201,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATSKI"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Obavijesti se prikazuju ovdje"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Pristupite im u bilo kojem trenutku tako da prstom trznete prema dolje. \nPonovo prstom trznite prema dolje za kontrole sustava."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Prijeđite prstom po rubu zaslona da bi se prikazala traka"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Prijeđite prstom od ruba zaslona da bi se prikazala traka sustava"</string> </resources> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 118baed..f2dcd93 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -201,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"automatikus"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Az értesítések itt jelennek meg."</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Bármikor elérheti őket, ha lefelé húzza az ujját.\nHúzza le az ujját még egyszer a rendszerbeállítások eléréséhez."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Csúsztassa ujját a képernyő szélén a sáv megjelenítéséhez"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Csúsztassa ujját a képernyő szélétől a rendszersáv megjelenítéséhez"</string> </resources> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml new file mode 100644 index 0000000..4241898 --- /dev/null +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -0,0 +1,204 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, 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 xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_label" msgid="7164937344850004466">"Համակարգային UI"</string> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Մաքրել"</string> + <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Հեռացնել ցանկից"</string> + <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Տեղեկություններ ծրագրի մասին"</string> + <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Թարմ հավելվածներ չկան"</string> + <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Անտեսել վերջին ծրագրերը"</string> + <plurals name="status_bar_accessibility_recent_apps"> + <item quantity="one" msgid="5854176083865845541">"1 նոր ծրագիր"</item> + <item quantity="other" msgid="1040784359794890744">"%d նոր ծրագիր"</item> + </plurals> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ծանուցումներ չկան"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Ընթացիկ"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Ծանուցումներ"</string> + <string name="battery_low_title" msgid="2783104807551211639">"Միացրեք լիցքավորիչը"</string> + <string name="battery_low_subtitle" msgid="1752040062087829196">"Մարտկոցը լիցքաթափվում է:"</string> + <string name="battery_low_percent_format" msgid="1077244949318261761">"մնում է <xliff:g id="NUMBER">%d%%</xliff:g>"</string> + <string name="invalid_charger" msgid="4549105996740522523">"USB լիցքավորումը չի աջակցվում:\nՕգտվեք միայն գործող լիցքավորիչից:"</string> + <string name="battery_low_why" msgid="7279169609518386372">"Մարտկոցի օգտագործումը"</string> + <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Կարգավորումներ"</string> + <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string> + <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Ինքնաթիռային ռեժիմ"</string> + <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Ինքնապտտվող էկրան"</string> + <string name="status_bar_settings_mute_label" msgid="554682549917429396">"Համրեցնել"</string> + <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"Ինքնաշխատ"</string> + <string name="status_bar_settings_notifications" msgid="397146176280905137">"Ծանուցումներ"</string> + <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth-ը կապված է"</string> + <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Կարգավորել մուտքագրման եղանակները"</string> + <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Ֆիզիկական ստեղնաշար"</string> + <string name="usb_device_permission_prompt" msgid="834698001271562057">"Թույլատրե՞լ <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածի մուտքը USB սարք:"</string> + <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Թույլատրե՞լ, որ <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածը մուտք գործի USB լրասարք:"</string> + <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Բացե՞լ <xliff:g id="ACTIVITY">%1$s</xliff:g>-ը, երբ այս USB կրիչը կապակցված է:"</string> + <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Բացե՞լ <xliff:g id="ACTIVITY">%1$s</xliff:g>-ը, երբ այս USB լրասարքը կապակցված է:"</string> + <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Այս USB լրասարքի հետ ոչ մի հավելված չի աշխատում: Իմացեք ավելին այս լրասարքի մասին <xliff:g id="URL">%1$s</xliff:g>-ում"</string> + <string name="title_usb_accessory" msgid="4966265263465181372">"USB լրասարք"</string> + <string name="label_view" msgid="6304565553218192990">"Դիտել"</string> + <string name="always_use_device" msgid="1450287437017315906">"Օգտագործել լռելյայն այս USB սարքի համար"</string> + <string name="always_use_accessory" msgid="1210954576979621596">"Օգտագործել լռելյայն այս USB լրասարքի համար"</string> + <string name="usb_debugging_title" msgid="4513918393387141949">"Թույլատրե՞լ USB-ի կարգաբերումը:"</string> + <string name="usb_debugging_message" msgid="2220143855912376496">"Համակարգչի RSA-ի բանալի մատնահետքն է`\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string> + <string name="usb_debugging_always" msgid="303335496705863070">"Միշտ թույլատրել այս համակարգչից"</string> + <string name="compat_mode_on" msgid="6623839244840638213">"Խոշորացնել` էկրանը լցնելու համար"</string> + <string name="compat_mode_off" msgid="4434467572461327898">"Ձգել` էկրանը լցնելու համար"</string> + <string name="compat_mode_help_header" msgid="7969493989397529910">"Համատեղելիության խոշորացում"</string> + <string name="compat_mode_help_body" msgid="4946726776359270040">"Երբ հավելվածը նախագծված է ավելի փոքր էկրանի համար, խոշորացման կարգավորիչը կհայտնվի ժամացույցի կողքին:"</string> + <string name="screenshot_saving_ticker" msgid="7403652894056693515">"Պահում է էկրանի հանույթը…"</string> + <string name="screenshot_saving_title" msgid="8242282144535555697">"Պահում է էկրանի հանույթը..."</string> + <string name="screenshot_saving_text" msgid="2419718443411738818">"Էկրանի հանույթը պահվում է:"</string> + <string name="screenshot_saved_title" msgid="6461865960961414961">"Էկրանի հանույթը լուսանկարվել է:"</string> + <string name="screenshot_saved_text" msgid="1152839647677558815">"Հպեք ձեր էկրանի հանույթը տեսնելու համար:"</string> + <string name="screenshot_failed_title" msgid="705781116746922771">"Չհաջողվեց լուսանկարել էկրանի հանույթը:"</string> + <string name="screenshot_failed_text" msgid="8134011269572415402">"Չհաջողվեց պահել էկրանի հանույթը: Հնարավոր է` պահոցն օգտագործման մեջ է:"</string> + <string name="usb_preference_title" msgid="6551050377388882787">"USB ֆայլերի փոխանցման ընտրանքներ"</string> + <string name="use_mtp_button_title" msgid="4333504413563023626">"Միացնել որպես մեդիա նվագարկիչ (MTP)"</string> + <string name="use_ptp_button_title" msgid="7517127540301625751">"Միացնել որպես ֆոտոխցիկ (PTP)"</string> + <string name="installer_cd_button_title" msgid="2312667578562201583">"Տեղադրել Android ֆայլերի փոխանցման հավելվածը Mac-ի համար"</string> + <string name="accessibility_back" msgid="567011538994429120">"Հետ"</string> + <string name="accessibility_home" msgid="8217216074895377641">"Տուն"</string> + <string name="accessibility_menu" msgid="316839303324695949">"Ցանկ"</string> + <string name="accessibility_recent" msgid="8571350598987952883">"Վերջին ծրագրերը"</string> + <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Միացնել մուտքագրման եղանակի կոճակը:"</string> + <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Համատեղելիության խոշորացման կոճակը:"</string> + <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Դիտափոխել փոքրից ավելի մեծ էկրան:"</string> + <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth-ը միացված է:"</string> + <string name="accessibility_bluetooth_disconnected" msgid="7416648669976870175">"Bluetooth-ն անջատված է:"</string> + <string name="accessibility_no_battery" msgid="358343022352820946">"Մարտկոց չկա:"</string> + <string name="accessibility_battery_one_bar" msgid="7774887721891057523">"Մարտկոցի մեկ գիծ:"</string> + <string name="accessibility_battery_two_bars" msgid="8500650438735009973">"Մարտկոցի երկու գիծ:"</string> + <string name="accessibility_battery_three_bars" msgid="2302983330865040446">"Մարտկոցի երեք գիծ:"</string> + <string name="accessibility_battery_full" msgid="8909122401720158582">"Մարտկոցը լիքն է:"</string> + <string name="accessibility_no_phone" msgid="4894708937052611281">"Հեռախոս չկա:"</string> + <string name="accessibility_phone_one_bar" msgid="687699278132664115">"Հեռախոսի մեկ գիծ:"</string> + <string name="accessibility_phone_two_bars" msgid="8384905382804815201">"Հեռախոսի երկու գիծ:"</string> + <string name="accessibility_phone_three_bars" msgid="8521904843919971885">"Հեռախոսի երեք գիծ:"</string> + <string name="accessibility_phone_signal_full" msgid="6471834868580757898">"Հեռախոսի ազդանշանը լիքն է:"</string> + <string name="accessibility_no_data" msgid="4791966295096867555">"Տվյալներ չկան:"</string> + <string name="accessibility_data_one_bar" msgid="1415625833238273628">"Տվյալների մեկ գիծ:"</string> + <string name="accessibility_data_two_bars" msgid="6166018492360432091">"Տվյալների երկու գիծ:"</string> + <string name="accessibility_data_three_bars" msgid="9167670452395038520">"Տվյալների երեք գիծ:"</string> + <string name="accessibility_data_signal_full" msgid="2708384608124519369">"Տվյալների ազդանշանը լրիվ է:"</string> + <string name="accessibility_wifi_off" msgid="3177380296697933627">"Wifi-ը անջատված է:"</string> + <string name="accessibility_no_wifi" msgid="1425476551827924474">"WiFi-ը անջատված է:"</string> + <string name="accessibility_wifi_one_bar" msgid="7735893178010724377">"Wifi-ի մեկ գիծ:"</string> + <string name="accessibility_wifi_two_bars" msgid="4994274250497262434">"Wifi-ի երկու գիծ:"</string> + <string name="accessibility_wifi_three_bars" msgid="3495755044276588384">"WiFi-ի երեք գիծ:"</string> + <string name="accessibility_wifi_signal_full" msgid="6853561303586480376">"Wifi-ի ազդանշանը լիքն է:"</string> + <string name="accessibility_no_wimax" msgid="4329180129727630368">"WiMAX չկա:"</string> + <string name="accessibility_wimax_one_bar" msgid="4170994299011863648">"WiMAX-ի մեկ գիծ:"</string> + <string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"WiMAX-ի երկու գիծ:"</string> + <string name="accessibility_wimax_three_bars" msgid="6116551636752103927">"WiMAX-ի երեք գիծ:"</string> + <string name="accessibility_wimax_signal_full" msgid="2768089986795579558">"WiMAX-ի ազդանշանը լիքն է:"</string> + <string name="accessibility_no_signal" msgid="7064645320782585167">"Ազդանշան չկա:"</string> + <string name="accessibility_not_connected" msgid="6395326276213402883">"Միացված չէ:"</string> + <string name="accessibility_zero_bars" msgid="3806060224467027887">"Զրո գիծ:"</string> + <string name="accessibility_one_bar" msgid="1685730113192081895">"Մեկ գիծ:"</string> + <string name="accessibility_two_bars" msgid="6437363648385206679">"Երկու գիծ:"</string> + <string name="accessibility_three_bars" msgid="2648241415119396648">"Երեք գիծ:"</string> + <string name="accessibility_signal_full" msgid="9122922886519676839">"Ազդանշանը լրիվ է:"</string> + <string name="accessibility_desc_on" msgid="2385254693624345265">"Միացված է:"</string> + <string name="accessibility_desc_off" msgid="6475508157786853157">"Անջատված է:"</string> + <string name="accessibility_desc_connected" msgid="8366256693719499665">"Միացված է:"</string> + <string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string> + <string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string> + <string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string> + <string name="accessibility_data_connection_3g" msgid="8628562305003568260">"3G"</string> + <string name="accessibility_data_connection_3.5g" msgid="8664845609981692001">"3.5G"</string> + <string name="accessibility_data_connection_4g" msgid="7741000750630089612">"4G"</string> + <string name="accessibility_data_connection_lte" msgid="5413468808637540658">"LTE"</string> + <string name="accessibility_data_connection_cdma" msgid="6132648193978823023">"CDMA"</string> + <string name="accessibility_data_connection_roaming" msgid="5977362333466556094">"Ռոումինգ"</string> + <string name="accessibility_data_connection_edge" msgid="4477457051631979278">"Edge"</string> + <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Wi-Fi"</string> + <string name="accessibility_no_sim" msgid="8274017118472455155">"SIM չկա:"</string> + <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Bluetooth-ը կապվում է:"</string> + <string name="accessibility_airplane_mode" msgid="834748999790763092">"Ինքնաթիռային ռեժիմ"</string> + <string name="accessibility_battery_level" msgid="7451474187113371965">"Մարտկոցը <xliff:g id="NUMBER">%d</xliff:g> տոկոս է:"</string> + <string name="accessibility_settings_button" msgid="799583911231893380">"Համակարգի կարգավորումներ:"</string> + <string name="accessibility_notifications_button" msgid="4498000369779421892">"Ծանուցումներ:"</string> + <string name="accessibility_remove_notification" msgid="3603099514902182350">"Մաքրել ծանուցումը:"</string> + <string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS-ը միացված է:"</string> + <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"GPS-ի ստացում:"</string> + <string name="accessibility_tty_enabled" msgid="4613200365379426561">"Հեռամուտքագրիչը միացված է:"</string> + <string name="accessibility_ringer_vibrate" msgid="666585363364155055">"Զանգի թրթռոց:"</string> + <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Զանգակը լռեցված է:"</string> + <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g>-ը անտեսված է:"</string> + <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Ծանուցումը անտեսվեց:"</string> + <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Ծանուցումների վահանակ:"</string> + <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Արագ կարգավորումներ:"</string> + <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"Վերջին հավելվածները:"</string> + <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Օգտվող <xliff:g id="USER">%s</xliff:g>:"</string> + <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>: <xliff:g id="NETWORK">%2$s</xliff:g>"</string> + <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Շարժական <xliff:g id="SIGNAL">%1$s</xliff:g>: <xliff:g id="TYPE">%2$s</xliff:g>: <xliff:g id="NETWORK">%3$s</xliff:g>:"</string> + <string name="accessibility_quick_settings_battery" msgid="1480931583381408972">"Մարտկոցը <xliff:g id="STATE">%s</xliff:g> է:"</string> + <string name="accessibility_quick_settings_airplane" msgid="4196876722090224753">"Ինքնաթիռային ռեժիմը <xliff:g id="STATE">%s</xliff:g> է:"</string> + <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth-ը <xliff:g id="STATE">%s</xliff:g> է:"</string> + <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Զարթուցիչը դրված է <xliff:g id="TIME">%s</xliff:g>-ին:"</string> + <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G-3G տվյալները անջատված են"</string> + <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G տվյալները անջատված են"</string> + <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Շարժական տվյալները անջատված են"</string> + <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Տվյալները անջատված են"</string> + <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Դուք հասել եք նշված տվյալների օգտագործման սահմանին:\n\n Եթե դուք կրկին ակտիվացնեք տվյալները, այն կարող է գանձվել օպերատորի կողմից:"</string> + <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Վերամիացնել տվյալները"</string> + <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ինտերնետ կապ չկա"</string> + <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi-ը միացված է"</string> + <string name="gps_notification_searching_text" msgid="8574247005642736060">"Որոնում է GPS"</string> + <string name="gps_notification_found_text" msgid="4619274244146446464">"Տեղադրությունը կարգավորվել է GPS-ի կողմից"</string> + <string name="accessibility_location_active" msgid="2427290146138169014">"Տեղադրության հարցումներն ակտիվ են"</string> + <string name="accessibility_clear_all" msgid="5235938559247164925">"Մաքրել բոլոր ծանուցումները:"</string> + <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Տեղեկություններ ծրագրի մասին"</string> + <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Էկրանը ինքնուրույն կպտտվի:"</string> + <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Էկրանը կողպված է հորիզոնական դիրքավորման մեջ:"</string> + <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Էկրանը կողպված է ուղղաձիգ դիրքավորմամբ:"</string> + <string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string> + <string name="start_dreams" msgid="7219575858348719790">"Ցերեկային ռեժիմ"</string> + <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string> + <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Ինքնաթիռային ռեժիմ"</string> + <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Լիցքավորում` <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string> + <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Լիցքավորված է"</string> + <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string> + <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> սարք)"</string> + <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth-ն անջատված է"</string> + <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Պայծառություն"</string> + <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Ինքնապտտում"</string> + <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Պտտումը կողպված է"</string> + <string name="quick_settings_ime_label" msgid="7073463064369468429">"Մուտքագրման եղանակը"</string> + <string name="quick_settings_location_label" msgid="5011327048748762257">"Տեղադրություն"</string> + <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Անջատել տեղադրությունը"</string> + <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Մեդիա սարք"</string> + <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string> + <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Միայն արտակարգ իրավիճակների զանգեր"</string> + <string name="quick_settings_settings_label" msgid="5326556592578065401">"Կարգավորումներ"</string> + <string name="quick_settings_time_label" msgid="4635969182239736408">"Ժամանակը"</string> + <string name="quick_settings_user_label" msgid="5238995632130897840">"Ես"</string> + <string name="quick_settings_wifi_label" msgid="9135344704899546041">"Wi-Fi"</string> + <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Միացված չէ"</string> + <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Ցանց չկա"</string> + <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi-ը անջատված է"</string> + <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi ցուցադրիչ"</string> + <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Անլար էկրան"</string> + <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Պայծառություն"</string> + <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"Ինքնաշխատ"</string> + <string name="status_bar_help_title" msgid="1199237744086469217">"Ծանուցումները հայտնվում են այստեղ"</string> + <string name="status_bar_help_text" msgid="7874607155052076323">"Դրանք մատչեք ցանկացած պահի` սահահարվածելով:\nԿրկին սահահարվածեք ներքև` համակարգային կառավարման համար:"</string> +</resources> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 013bd99..6846056 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -164,8 +164,7 @@ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tersambung"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"Menelusuri GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokasi yang disetel oleh GPS"</string> - <!-- no translation found for accessibility_location_active (2427290146138169014) --> - <skip /> + <string name="accessibility_location_active" msgid="2427290146138169014">"Permintaan lokasi aktif"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Menghapus semua pemberitahuan."</string> <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Info aplikasi"</string> <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Layar akan diputar secara otomatis."</string> @@ -202,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OTOMATIS"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Pemberitahuan muncul di sini"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Akses kapan saja dengan menggesek ke bawah.\nGesek ke bawah sekali lagi untuk kontrol sistem."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Gesek tepi layar untuk membuka bilah"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Gesek dari bagian tepi layar untuk membuka bilah sistem"</string> </resources> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index ff539be..a889342 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -203,6 +203,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Le notifiche vengono visualizzate qui"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Puoi accedervi in qualsiasi momento scorrendo verso il basso.\nFai scorrere di nuovo verso il basso per visualizzare i controlli del sistema."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Fai scorrere il bordo dello schermo per visualizzare la barra"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Fai scorrere il dito dal bordo dello schermo per visualizzare la barra di sistema"</string> </resources> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index c80ad7c..899f092 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -164,8 +164,7 @@ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi מחובר"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"מחפש GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"מיקום מוגדר על ידי GPS"</string> - <!-- no translation found for accessibility_location_active (2427290146138169014) --> - <skip /> + <string name="accessibility_location_active" msgid="2427290146138169014">"בקשות מיקום פעילות"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"נקה את כל ההתראות."</string> <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"פרטי יישום"</string> <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"המסך יסתובב באופן אוטומטי."</string> @@ -202,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"אוטומטי"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"הודעות מופיעות כאן"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"גש אליהם בכל עת על ידי החלקה למטה.\nהחלק למטה שוב למעבר למרכז הבקרה של המערכת."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"החלק מקצה המסך כדי להציג את הסרגל"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"החלק מקצה המסך כדי להציג את סרגל המערכת"</string> </resources> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 73aa558..e92e8be 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -166,8 +166,7 @@ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi接続済み"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPSで検索中"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"GPSにより現在地が設定されました"</string> - <!-- no translation found for accessibility_location_active (2427290146138169014) --> - <skip /> + <string name="accessibility_location_active" msgid="2427290146138169014">"現在地リクエストがアクティブ"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"通知をすべて消去。"</string> <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"アプリ情報"</string> <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"画面は自動的に回転します。"</string> @@ -204,6 +203,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自動"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"ここに通知が表示されます"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"下にスワイプすると、いつでも通知を表示できます。\nシステムを管理するにはもう一度下にスワイプしてください。"</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"バーを表示するには、画面の端からスワイプします"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"システムバーを表示するには、画面の端からスワイプします"</string> </resources> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml new file mode 100644 index 0000000..bcbe4de --- /dev/null +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -0,0 +1,204 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, 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 xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_label" msgid="7164937344850004466">"სისტემის UI"</string> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"გასუფთავება"</string> + <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"სიიდან ამოშლა"</string> + <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"აპის შესახებ"</string> + <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"ბოლოს გამოყენებული აპების სია ცარიელია"</string> + <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"ბოლო აპების გაუქმება"</string> + <plurals name="status_bar_accessibility_recent_apps"> + <item quantity="one" msgid="5854176083865845541">"1 ბოლო აპი"</item> + <item quantity="other" msgid="1040784359794890744">"%d ბოლო აპი"</item> + </plurals> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"შეტყობინებები არ არის."</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"მიმდინარე"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"შეტყობინებები"</string> + <string name="battery_low_title" msgid="2783104807551211639">"შეაერთეთ დამტენი."</string> + <string name="battery_low_subtitle" msgid="1752040062087829196">"ბატარეა ჯდება."</string> + <string name="battery_low_percent_format" msgid="1077244949318261761">"დარჩენილია <xliff:g id="NUMBER">%d%%</xliff:g>"</string> + <string name="invalid_charger" msgid="4549105996740522523">"USB-ით დატენვა არ არის მხარდაჭერილი.\nგამოიყენეთ მხოლოდ ელექტრო-დამტენი."</string> + <string name="battery_low_why" msgid="7279169609518386372">"ელემენტის გამოყენება"</string> + <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"პარამეტრები"</string> + <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string> + <string name="status_bar_settings_airplane" msgid="4879879698500955300">"თვითმფრინავის რეჟიმი"</string> + <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"ავტოროტაციის ეკრანი"</string> + <string name="status_bar_settings_mute_label" msgid="554682549917429396">"დადუმება"</string> + <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"ავტომატური"</string> + <string name="status_bar_settings_notifications" msgid="397146176280905137">"შეტყობინებები"</string> + <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth მიერთებულია."</string> + <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"შეყვანის მეთოდების დაყენება"</string> + <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"ფიზიკური კლავიატურა"</string> + <string name="usb_device_permission_prompt" msgid="834698001271562057">"გსურთ, მისცეთ აპლიკაციას „<xliff:g id="APPLICATION">%1$s</xliff:g>“ USB მეხსიერებასთან წვდომის უფლება?"</string> + <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"გსურთ, მისცეთ აპლიკაციას „<xliff:g id="APPLICATION">%1$s</xliff:g>“ USB აქსესუართან წვდომის უფლება?"</string> + <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"გსურთ <xliff:g id="ACTIVITY">%1$s</xliff:g> , როდესაც ეს USB მოწყობილობა შეერთებულია?"</string> + <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"გსურთ <xliff:g id="ACTIVITY">%1$s</xliff:g> , როდესაც ეს USB მოწყობილობა შეერთებულია?"</string> + <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"არცერთი დაყენებული აპი არ მუშაობს ამ USB აქსესუართან. შეიტყვეთ მეტი ამ აქსესუარის შესახებ <xliff:g id="URL">%1$s</xliff:g>"</string> + <string name="title_usb_accessory" msgid="4966265263465181372">"USB აქსესუარი"</string> + <string name="label_view" msgid="6304565553218192990">"ნახვა"</string> + <string name="always_use_device" msgid="1450287437017315906">"ამ USB მოწყობილობის ნაგულისხმევად გამოყენება"</string> + <string name="always_use_accessory" msgid="1210954576979621596">"ავტომატურად გამოიყენე ამ USB აქსესუარისთვის."</string> + <string name="usb_debugging_title" msgid="4513918393387141949">"გააქტიურდეს USB გამართვა?"</string> + <string name="usb_debugging_message" msgid="2220143855912376496">"კომპიუტერის RSA გასაღების თითის ანაბეჭდია:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string> + <string name="usb_debugging_always" msgid="303335496705863070">"ყოველთვის დართე ნება ამ კომპიუტერიდან."</string> + <string name="compat_mode_on" msgid="6623839244840638213">"მასშტაბი შეცვალეთ ეკრანის შესავსებად."</string> + <string name="compat_mode_off" msgid="4434467572461327898">"გაწიეთ ეკრანის შესავსებად."</string> + <string name="compat_mode_help_header" msgid="7969493989397529910">"თავსებადობის მასშტაბი"</string> + <string name="compat_mode_help_body" msgid="4946726776359270040">"თუ აპი გათვლილია მცირე ეკრანისთვის, საათის გვერდით გაჩნდება მასშტაბის მართვის ელემენტი."</string> + <string name="screenshot_saving_ticker" msgid="7403652894056693515">"სკრინშოტის შენახვა…"</string> + <string name="screenshot_saving_title" msgid="8242282144535555697">"ეკრანის სურათის შენახვა…"</string> + <string name="screenshot_saving_text" msgid="2419718443411738818">"ეკრანის სურათი შენახულია."</string> + <string name="screenshot_saved_title" msgid="6461865960961414961">"სკრინშოტი გადაღებულია."</string> + <string name="screenshot_saved_text" msgid="1152839647677558815">"შეეხეთ ეკრანის სურათის სანახავად."</string> + <string name="screenshot_failed_title" msgid="705781116746922771">"ვერ მოხერხდა ეკრანის ანაბეჭდის გადაღება."</string> + <string name="screenshot_failed_text" msgid="8134011269572415402">"ეკრანის სურათი ვერ შეინახა. შესაძლოა, მეხსიერება უკვე დაკავებულია."</string> + <string name="usb_preference_title" msgid="6551050377388882787">"USB ფაილის ტრანსფერის პარამეტრები"</string> + <string name="use_mtp_button_title" msgid="4333504413563023626">"მედია-საკრავად (MTP) ჩართვა"</string> + <string name="use_ptp_button_title" msgid="7517127540301625751">"მიუერთეთ როგორც კამერა (PTP)"</string> + <string name="installer_cd_button_title" msgid="2312667578562201583">"Android File Transfer აპის დაყენება Mac-თვის"</string> + <string name="accessibility_back" msgid="567011538994429120">"უკან"</string> + <string name="accessibility_home" msgid="8217216074895377641">"საწყისი"</string> + <string name="accessibility_menu" msgid="316839303324695949">"მენიუ"</string> + <string name="accessibility_recent" msgid="8571350598987952883">"ბოლოს გამოყენებული აპები"</string> + <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"შეყვანის მეთოდის გადართვის ღილაკი."</string> + <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"თავსებადი მასშტაბირების ღილაკი."</string> + <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"შეცვალეთ პატარა ეკრანი უფრო დიდით."</string> + <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth დაკავშირებულია."</string> + <string name="accessibility_bluetooth_disconnected" msgid="7416648669976870175">"Bluetooth კავშირი გაწყვეტილია."</string> + <string name="accessibility_no_battery" msgid="358343022352820946">"ბატარეა დამჯდარია."</string> + <string name="accessibility_battery_one_bar" msgid="7774887721891057523">"ბატარეია ერთ ზოლზეა."</string> + <string name="accessibility_battery_two_bars" msgid="8500650438735009973">"ელემენტი ორ ზოლზე."</string> + <string name="accessibility_battery_three_bars" msgid="2302983330865040446">"ელემენტი სამ ზოლზე."</string> + <string name="accessibility_battery_full" msgid="8909122401720158582">"ელემენტი სავსეა."</string> + <string name="accessibility_no_phone" msgid="4894708937052611281">"ტელეფონი არ არის."</string> + <string name="accessibility_phone_one_bar" msgid="687699278132664115">"ტელეფონის სიგნალი ერთ ზოლზეა."</string> + <string name="accessibility_phone_two_bars" msgid="8384905382804815201">"ტელეფონის სიგნალი ორ ზოლზეა."</string> + <string name="accessibility_phone_three_bars" msgid="8521904843919971885">"ტელეფონის სიგნალი სამ ზოლზეა."</string> + <string name="accessibility_phone_signal_full" msgid="6471834868580757898">"ტელეფონის სიგნალი სრულია."</string> + <string name="accessibility_no_data" msgid="4791966295096867555">"მონაცემები არ არის."</string> + <string name="accessibility_data_one_bar" msgid="1415625833238273628">"თარიღი ზოლზე."</string> + <string name="accessibility_data_two_bars" msgid="6166018492360432091">"მონაცემების გადაცემა: ორი ზოლი"</string> + <string name="accessibility_data_three_bars" msgid="9167670452395038520">"მონაცემების გადაცემა: სამი ზოლი"</string> + <string name="accessibility_data_signal_full" msgid="2708384608124519369">"მონაცემთა გადაცემის საიმედო სიგნალი."</string> + <string name="accessibility_wifi_off" msgid="3177380296697933627">"Wifi გამორთულია."</string> + <string name="accessibility_no_wifi" msgid="1425476551827924474">"Wifi არ არის დაკავშირებული."</string> + <string name="accessibility_wifi_one_bar" msgid="7735893178010724377">"Wifi სიგნალი ერთ ზოლზეა."</string> + <string name="accessibility_wifi_two_bars" msgid="4994274250497262434">"Wifi სიგნალი ორ ზოლზეა."</string> + <string name="accessibility_wifi_three_bars" msgid="3495755044276588384">"Wifi სამი ზოლი."</string> + <string name="accessibility_wifi_signal_full" msgid="6853561303586480376">"Wifi სიგნალი სრულია."</string> + <string name="accessibility_no_wimax" msgid="4329180129727630368">"WiMAX არ არის."</string> + <string name="accessibility_wimax_one_bar" msgid="4170994299011863648">"WiMAX ერთი სვეტი."</string> + <string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"WiMAX-ის ორი ზოლი."</string> + <string name="accessibility_wimax_three_bars" msgid="6116551636752103927">"WiMAX-ის სამი ზოლი."</string> + <string name="accessibility_wimax_signal_full" msgid="2768089986795579558">"WiMAX სიგნალი სრულია."</string> + <string name="accessibility_no_signal" msgid="7064645320782585167">"სიგნალი არ არის."</string> + <string name="accessibility_not_connected" msgid="6395326276213402883">"არ არის დაკავშირებული."</string> + <string name="accessibility_zero_bars" msgid="3806060224467027887">"სიგნალი ნულ ზოლზეა."</string> + <string name="accessibility_one_bar" msgid="1685730113192081895">"ერთი ზოლი."</string> + <string name="accessibility_two_bars" msgid="6437363648385206679">"ორი სვეტი."</string> + <string name="accessibility_three_bars" msgid="2648241415119396648">"სამი ზოლი."</string> + <string name="accessibility_signal_full" msgid="9122922886519676839">"სრული სიგნალი."</string> + <string name="accessibility_desc_on" msgid="2385254693624345265">"ჩართული"</string> + <string name="accessibility_desc_off" msgid="6475508157786853157">"გამორთულია."</string> + <string name="accessibility_desc_connected" msgid="8366256693719499665">"დაკავშირებულია."</string> + <string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string> + <string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string> + <string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string> + <string name="accessibility_data_connection_3g" msgid="8628562305003568260">"3G"</string> + <string name="accessibility_data_connection_3.5g" msgid="8664845609981692001">"3.5გბ"</string> + <string name="accessibility_data_connection_4g" msgid="7741000750630089612">"4G"</string> + <string name="accessibility_data_connection_lte" msgid="5413468808637540658">"LTE"</string> + <string name="accessibility_data_connection_cdma" msgid="6132648193978823023">"CDMA"</string> + <string name="accessibility_data_connection_roaming" msgid="5977362333466556094">"როუმინგი"</string> + <string name="accessibility_data_connection_edge" msgid="4477457051631979278">"Edge"</string> + <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Wi-Fi"</string> + <string name="accessibility_no_sim" msgid="8274017118472455155">"SIM არ არის."</string> + <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Bluetooth-ის ჩართვა"</string> + <string name="accessibility_airplane_mode" msgid="834748999790763092">"თვითმფრინავის რეჟიმი"</string> + <string name="accessibility_battery_level" msgid="7451474187113371965">"ბატარეა: <xliff:g id="NUMBER">%d</xliff:g> პროცენტი."</string> + <string name="accessibility_settings_button" msgid="799583911231893380">"სისტემის პარამეტრები."</string> + <string name="accessibility_notifications_button" msgid="4498000369779421892">"შეტყობინებები"</string> + <string name="accessibility_remove_notification" msgid="3603099514902182350">"შეტყობინებების გასუფთავება."</string> + <string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS გააქტიურდა."</string> + <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"GPS-ის დადგენა."</string> + <string name="accessibility_tty_enabled" msgid="4613200365379426561">"ტელეტაიპი ჩართულია."</string> + <string name="accessibility_ringer_vibrate" msgid="666585363364155055">"ვიბრაციის რეჟიმი."</string> + <string name="accessibility_ringer_silent" msgid="9061243307939135383">"უხმო რეჟიმი."</string> + <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ამოშლილია სიიდან."</string> + <string name="accessibility_notification_dismissed" msgid="854211387186306927">"შეტყობინება წაიშალა."</string> + <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"შეტყობინებების ფარდა"</string> + <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"სწრაფი პარამეტრები"</string> + <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"ბოლო აპები."</string> + <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"მომხმარებელი: <xliff:g id="USER">%s</xliff:g>."</string> + <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string> + <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"მობილურის <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string> + <string name="accessibility_quick_settings_battery" msgid="1480931583381408972">"ელემენტი: <xliff:g id="STATE">%s</xliff:g>."</string> + <string name="accessibility_quick_settings_airplane" msgid="4196876722090224753">"თვითმფრინავის რეჟიმი <xliff:g id="STATE">%s</xliff:g>."</string> + <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>."</string> + <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"მაღვიძარა დაყენებულია: <xliff:g id="TIME">%s</xliff:g>"</string> + <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G-3G ინტერნეტი გაითიშა."</string> + <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G მონაცემები გათიშულია"</string> + <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"მობილური ინტერნეტი გაითიშა."</string> + <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"ინტერნეტი გაითიშა."</string> + <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"თქვენ მიაღწიეთ ინტერნეტის გამოყენების განსაზღვრულ ლიმიტს.\n\nთუ გააქტიურებთ ინტერნეტს, შესაძლოა მობილური ოპერატორისთვის დამატებითი თანხის გადახდა მოგიწიოთ."</string> + <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"მონაცემების ხელახლა ჩართვა"</string> + <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ინტერნეტ კავშირი არ არის"</string> + <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi დაკავშირებულია"</string> + <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS-ის ძებნა"</string> + <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS-ით დადგენილი მდებარეობა"</string> + <string name="accessibility_location_active" msgid="2427290146138169014">"მდებარეობის მოთხოვნები აქტიურია"</string> + <string name="accessibility_clear_all" msgid="5235938559247164925">"ყველა შეტყობინების წაშლა"</string> + <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"აპის შესახებ"</string> + <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"ეკრანი შეტრიალდება ავტომატურად."</string> + <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"ეკრანი დაბლოკილია თარაზულ ორიენტაციაში"</string> + <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"ეკრანი დაბლოკილია პორტრეტის ორიენტაციაში."</string> + <string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string> + <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string> + <string name="ethernet_label" msgid="7967563676324087464">"ეთერნეტი"</string> + <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"თვითმფრინავის რეჟიმი"</string> + <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"დამუხტვა, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string> + <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"დამუხტულია"</string> + <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string> + <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> მოწყობილობა)"</string> + <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth გამორთულია"</string> + <string name="quick_settings_brightness_label" msgid="6968372297018755815">"სიკაშკაშე"</string> + <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"ავტოროტაცია"</string> + <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"როტაციის ჩაკეტვა"</string> + <string name="quick_settings_ime_label" msgid="7073463064369468429">"შეყვანის მეთოდი"</string> + <string name="quick_settings_location_label" msgid="5011327048748762257">"მდებარეობა"</string> + <string name="quick_settings_location_off_label" msgid="7464544086507331459">"მდებარეობა გამორთულია"</string> + <string name="quick_settings_media_device_label" msgid="1302906836372603762">"მედია მოწყობილობა"</string> + <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string> + <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"მხოლოდ გადაუდებელი დახმარების ზარებისთვის"</string> + <string name="quick_settings_settings_label" msgid="5326556592578065401">"პარამეტრები"</string> + <string name="quick_settings_time_label" msgid="4635969182239736408">"დრო"</string> + <string name="quick_settings_user_label" msgid="5238995632130897840">"მე"</string> + <string name="quick_settings_wifi_label" msgid="9135344704899546041">"Wi-Fi"</string> + <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"არ არის დაკავშირებული."</string> + <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"ქსელი არ არის"</string> + <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi გამორთულია"</string> + <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi ეკრანი"</string> + <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"უსადენო ეკრანი"</string> + <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"განათება"</string> + <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ავტომატურად"</string> + <string name="status_bar_help_title" msgid="1199237744086469217">"შეტყობინებები აქ გამოჩნდება"</string> + <string name="status_bar_help_text" msgid="7874607155052076323">"მათზე წვდომისათვის, ნებისმიერ დროს გადაფურცლეთ ქვემოთ.\nსისტემის კონტროლისთვისაც გადაფურცლეთ ქვემოთ."</string> +</resources> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml new file mode 100644 index 0000000..f972925 --- /dev/null +++ b/packages/SystemUI/res/values-km/strings.xml @@ -0,0 +1,204 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, 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 xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_label" msgid="7164937344850004466">"ចំណុចប្រទាក់ប្រព័ន្ធ"</string> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"សម្អាត"</string> + <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"យកចេញពីបញ្ជី"</string> + <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"ព័ត៌មានកម្មវិធី"</string> + <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"គ្មានកម្មវិធីថ្មីៗ"</string> + <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"បដិសេធកម្មវិធីថ្មីៗ"</string> + <plurals name="status_bar_accessibility_recent_apps"> + <item quantity="one" msgid="5854176083865845541">"កម្មវិធីថ្មី ១"</item> + <item quantity="other" msgid="1040784359794890744">"កម្មវិធីថ្មីៗ %d"</item> + </plurals> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"គ្មានការជូនដំណឹង"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"បន្ត"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"ការជូនដំណឹង"</string> + <string name="battery_low_title" msgid="2783104807551211639">"ភ្ជាប់ឧបករណ៍បញ្ចូលថ្ម"</string> + <string name="battery_low_subtitle" msgid="1752040062087829196">"ជិតអស់ថ្មហើយ។"</string> + <string name="battery_low_percent_format" msgid="1077244949318261761">"នៅសល់ <xliff:g id="NUMBER">%d%%</xliff:g>"</string> + <string name="invalid_charger" msgid="4549105996740522523">"មិនគាំទ្រការបញ្ចូលតាមយូអេសប៊ី។\nប្រើតែឧបករណ៍បញ្ចូលថ្មដែលបានផ្ដល់។"</string> + <string name="battery_low_why" msgid="7279169609518386372">"ការប្រើថ្ម"</string> + <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"ការកំណត់"</string> + <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"វ៉ាយហ្វាយ"</string> + <string name="status_bar_settings_airplane" msgid="4879879698500955300">"ពេលជិះយន្តហោះ"</string> + <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"បង្វិលអេក្រង់ស្វ័យប្រវត្តិ"</string> + <string name="status_bar_settings_mute_label" msgid="554682549917429396">"ស្ងាត់"</string> + <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"ស្វ័យប្រវត្តិ"</string> + <string name="status_bar_settings_notifications" msgid="397146176280905137">"ការជូនដំណឹង"</string> + <string name="bluetooth_tethered" msgid="7094101612161133267">"បានភ្ជាប់ប៊្លូធូស"</string> + <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"រៀបចំវិធីសាស្ត្របញ្ចូល"</string> + <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"ក្ដារចុចពិតប្រាកដ"</string> + <string name="usb_device_permission_prompt" msgid="834698001271562057">"ឲ្យកម្មវិធី <xliff:g id="APPLICATION">%1$s</xliff:g> ចូលដំណើរការឧបករណ៍យូអេសប៊ី?"</string> + <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"ឲ្យកម្មវិធី <xliff:g id="APPLICATION">%1$s</xliff:g> ចូលដំណើរការឧបករណ៍យូអេសប៊ី?"</string> + <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"បើក <xliff:g id="ACTIVITY">%1$s</xliff:g> ពេលបានភ្ជាប់ឧបករណ៍យូអេសប៊ីនេះ?"</string> + <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"បើក <xliff:g id="ACTIVITY">%1$s</xliff:g> ពេលបានភ្ជាប់ឧបករណ៍យូអេសប៊ី?"</string> + <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"គ្មានកម្មវិធីបានដំឡើងដំណើរការជាមួយឧបករណ៍យូអេសប៊ី។ ស្វែងយល់បន្ថែមអំពីឧបករណ៍នេះនៅ <xliff:g id="URL">%1$s</xliff:g>"</string> + <string name="title_usb_accessory" msgid="4966265263465181372">"ឧបករណ៍យូអេសប៊ី"</string> + <string name="label_view" msgid="6304565553218192990">"មើល"</string> + <string name="always_use_device" msgid="1450287437017315906">"ប្រើតាមលំនាំដើមសម្រាប់ឧបករណ៍យូអេសប៊ីនេះ"</string> + <string name="always_use_accessory" msgid="1210954576979621596">"ប្រើតាមលំនាំដើមសម្រាប់ខ្សែយូអេសប៊ីនេះ"</string> + <string name="usb_debugging_title" msgid="4513918393387141949">"អនុញ្ញាតការកែកំហុសយូអេសប៊ី?"</string> + <string name="usb_debugging_message" msgid="2220143855912376496">"ស្នាមម្រាមដៃ RSA របស់កុំព្យូទ័រគឺ៖ \n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string> + <string name="usb_debugging_always" msgid="303335496705863070">"អនុញ្ញាតជានិច្ចសម្រាប់កុំព្យូទ័រនេះ"</string> + <string name="compat_mode_on" msgid="6623839244840638213">"ពង្រីកដើម្បីឲ្យពេញអេក្រង់"</string> + <string name="compat_mode_off" msgid="4434467572461327898">"ទាញដើម្បីឲ្យពេញអេក្រង់"</string> + <string name="compat_mode_help_header" msgid="7969493989397529910">"ការពង្រីកត្រូវគ្នា"</string> + <string name="compat_mode_help_body" msgid="4946726776359270040">"ពេលកម្មវិធីត្រូវបានរៀបចំសម្រាប់អេក្រង់តូច ការគ្រប់គ្រងការពង្រីកនឹងបង្ហាញតាមនាឡិកា។"</string> + <string name="screenshot_saving_ticker" msgid="7403652894056693515">"កំពុងរក្សាទុករូបថតអេក្រង់…"</string> + <string name="screenshot_saving_title" msgid="8242282144535555697">"កំពុងរក្សាទុករូបថតអេក្រង់..."</string> + <string name="screenshot_saving_text" msgid="2419718443411738818">"រូបថតអេក្រង់កំពុងត្រូវបានរក្សាទុក។"</string> + <string name="screenshot_saved_title" msgid="6461865960961414961">"បានចាប់យករូបថតអេក្រង់។"</string> + <string name="screenshot_saved_text" msgid="1152839647677558815">"ប៉ះ ដើម្បីមើលរូបថតអេក្រង់របស់អ្នក។"</string> + <string name="screenshot_failed_title" msgid="705781116746922771">"មិនអាចចាប់យករូបថតអេក្រង់។"</string> + <string name="screenshot_failed_text" msgid="8134011269572415402">"មិនអាចរក្សាទុករូបថតអេក្រង់។ ឧបករណ៍ផ្ទុកអាចកំពុងប្រើ។"</string> + <string name="usb_preference_title" msgid="6551050377388882787">"ជម្រើសផ្ទេរឯកសារតាមយូអេសប៊ី"</string> + <string name="use_mtp_button_title" msgid="4333504413563023626">"ភ្ជាប់ជាកម្មវិធីចាក់មេឌៀ (MTP)"</string> + <string name="use_ptp_button_title" msgid="7517127540301625751">"ភ្ជាប់ជាម៉ាស៊ីនថត (PTP)"</string> + <string name="installer_cd_button_title" msgid="2312667578562201583">"ដំឡើងកម្មវិធីផ្ទេរឯកសារ Android សម្រាប់ Mac"</string> + <string name="accessibility_back" msgid="567011538994429120">"ថយក្រោយ"</string> + <string name="accessibility_home" msgid="8217216074895377641">"គេហទំព័រ"</string> + <string name="accessibility_menu" msgid="316839303324695949">"ម៉ឺនុយ"</string> + <string name="accessibility_recent" msgid="8571350598987952883">"កម្មវិធីថ្មីៗ"</string> + <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ប្ដូរប៊ូតុងវិធីសាស្ត្របញ្ចូល។"</string> + <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ប៊ូតុងពង្រីកត្រូវគ្នា។"</string> + <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ពង្រីក/បង្រួមអេក្រង់ពីទៅធំ"</string> + <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"បានតភ្ជាប់ប៊្លូធូស។"</string> + <string name="accessibility_bluetooth_disconnected" msgid="7416648669976870175">"បានផ្ដាច់ប៊្លូធូស។"</string> + <string name="accessibility_no_battery" msgid="358343022352820946">"គ្មានថ្ម។"</string> + <string name="accessibility_battery_one_bar" msgid="7774887721891057523">"ថ្មមួយកាំ។"</string> + <string name="accessibility_battery_two_bars" msgid="8500650438735009973">"ថ្មពីរកាំ។"</string> + <string name="accessibility_battery_three_bars" msgid="2302983330865040446">"ថ្មទាំងបីកាំ។"</string> + <string name="accessibility_battery_full" msgid="8909122401720158582">"ថ្មពេញហើយ។"</string> + <string name="accessibility_no_phone" msgid="4894708937052611281">"គ្មានទូរស័ព្ទ។"</string> + <string name="accessibility_phone_one_bar" msgid="687699278132664115">"សេវាទូរស័ព្ទមួយកាំ។"</string> + <string name="accessibility_phone_two_bars" msgid="8384905382804815201">"សេវាទូរស័ព្ទពីរកាំ។"</string> + <string name="accessibility_phone_three_bars" msgid="8521904843919971885">"សេវាទូរស័ព្ទបីកាំ។"</string> + <string name="accessibility_phone_signal_full" msgid="6471834868580757898">"សេវាទូរស័ព្ទពេញ។"</string> + <string name="accessibility_no_data" msgid="4791966295096867555">"គ្មានទិន្នន័យ។"</string> + <string name="accessibility_data_one_bar" msgid="1415625833238273628">"ទិន្នន័យមួយកាំ។"</string> + <string name="accessibility_data_two_bars" msgid="6166018492360432091">"ទិន្នន័យពីរកាំ។"</string> + <string name="accessibility_data_three_bars" msgid="9167670452395038520">"ទិន្នន័យបីកាំ។"</string> + <string name="accessibility_data_signal_full" msgid="2708384608124519369">"សញ្ញាទិន្នន័យពេញ។"</string> + <string name="accessibility_wifi_off" msgid="3177380296697933627">"បិទវ៉ាយហ្វាយ។"</string> + <string name="accessibility_no_wifi" msgid="1425476551827924474">"បានផ្ដាច់វ៉ាយហ្វាយ។"</string> + <string name="accessibility_wifi_one_bar" msgid="7735893178010724377">"សញ្ញាវ៉ាយហ្វាយមួយកាំ។"</string> + <string name="accessibility_wifi_two_bars" msgid="4994274250497262434">"សេវាវ៉ាយហ្វាយពីរកាំ។"</string> + <string name="accessibility_wifi_three_bars" msgid="3495755044276588384">"វ៉ាយហ្វាយបីកាំ។"</string> + <string name="accessibility_wifi_signal_full" msgid="6853561303586480376">"សញ្ញាវ៉ាយហ្វាយពេញ។"</string> + <string name="accessibility_no_wimax" msgid="4329180129727630368">"គ្មាន WiMAX ។"</string> + <string name="accessibility_wimax_one_bar" msgid="4170994299011863648">"WiMAX មួយកាំ។"</string> + <string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"WiMAX ពីរកាំ។"</string> + <string name="accessibility_wimax_three_bars" msgid="6116551636752103927">"WiMAX បីកាំ។"</string> + <string name="accessibility_wimax_signal_full" msgid="2768089986795579558">"សញ្ញា WiMAX ពេញ។"</string> + <string name="accessibility_no_signal" msgid="7064645320782585167">"គ្មានសញ្ញា។"</string> + <string name="accessibility_not_connected" msgid="6395326276213402883">"មិនបានតភ្ជាប់។"</string> + <string name="accessibility_zero_bars" msgid="3806060224467027887">"សូន្យកាំ។"</string> + <string name="accessibility_one_bar" msgid="1685730113192081895">"មួយកាំ។"</string> + <string name="accessibility_two_bars" msgid="6437363648385206679">"ពីរកាំ។"</string> + <string name="accessibility_three_bars" msgid="2648241415119396648">"បីកាំ។"</string> + <string name="accessibility_signal_full" msgid="9122922886519676839">"សញ្ញាពេញ។"</string> + <string name="accessibility_desc_on" msgid="2385254693624345265">"បើក។"</string> + <string name="accessibility_desc_off" msgid="6475508157786853157">"បិទ"</string> + <string name="accessibility_desc_connected" msgid="8366256693719499665">"បានតភ្ជាប់។"</string> + <string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string> + <string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string> + <string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string> + <string name="accessibility_data_connection_3g" msgid="8628562305003568260">"3G"</string> + <string name="accessibility_data_connection_3.5g" msgid="8664845609981692001">"3.5G"</string> + <string name="accessibility_data_connection_4g" msgid="7741000750630089612">"4G"</string> + <string name="accessibility_data_connection_lte" msgid="5413468808637540658">"LTE"</string> + <string name="accessibility_data_connection_cdma" msgid="6132648193978823023">"CDMA"</string> + <string name="accessibility_data_connection_roaming" msgid="5977362333466556094">"រ៉ូមីង"</string> + <string name="accessibility_data_connection_edge" msgid="4477457051631979278">"Edge"</string> + <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"វ៉ាយហ្វាយ"</string> + <string name="accessibility_no_sim" msgid="8274017118472455155">"គ្មានស៊ីមកាត។"</string> + <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"ការភ្ជាប់ប៊្លូធូស។"</string> + <string name="accessibility_airplane_mode" msgid="834748999790763092">"របៀបជិះយន្តហោះ"</string> + <string name="accessibility_battery_level" msgid="7451474187113371965">"ថ្ម <xliff:g id="NUMBER">%d</xliff:g> ភាគរយ។"</string> + <string name="accessibility_settings_button" msgid="799583911231893380">"ការកំណត់ប្រព័ន្ធ។"</string> + <string name="accessibility_notifications_button" msgid="4498000369779421892">"ការជូនដំណឹង។"</string> + <string name="accessibility_remove_notification" msgid="3603099514902182350">"សម្អាតការជូនដំណឹង។"</string> + <string name="accessibility_gps_enabled" msgid="3511469499240123019">"បានបើក GPS ។"</string> + <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"ទទួល GPS ។"</string> + <string name="accessibility_tty_enabled" msgid="4613200365379426561">"បានបើកម៉ាស៊ីនអង្គុលីលេខ"</string> + <string name="accessibility_ringer_vibrate" msgid="666585363364155055">"កម្មវិធីរោទ៍ញ័រ។"</string> + <string name="accessibility_ringer_silent" msgid="9061243307939135383">"កម្មវិធីរោទ៍ស្ងាត់។"</string> + <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> បដិសេធ។"</string> + <string name="accessibility_notification_dismissed" msgid="854211387186306927">"បានបដិសេធការជូនដំណឹង"</string> + <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"ពណ៌ការជូនដំណឹង"</string> + <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"ការកំណត់រហ័ស។"</string> + <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"កម្មវិធីថ្មីៗ។"</string> + <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"អ្នកប្រើ <xliff:g id="USER">%s</xliff:g> ។"</string> + <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string> + <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"ចល័ត <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string> + <string name="accessibility_quick_settings_battery" msgid="1480931583381408972">"ថ្ម <xliff:g id="STATE">%s</xliff:g> ។"</string> + <string name="accessibility_quick_settings_airplane" msgid="4196876722090224753">"របៀបជិះយន្តហោះ <xliff:g id="STATE">%s</xliff:g> ។"</string> + <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"ប៊្លូធូស <xliff:g id="STATE">%s</xliff:g> ។"</string> + <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"កំណត់សំឡេងរោទ៍សម្រាប់ <xliff:g id="TIME">%s</xliff:g> ។"</string> + <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"បានបិទទិន្នន័យ 2G-3G"</string> + <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"បានបិទទិន្នន័យ 4G"</string> + <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"បានបិទទិន្នន័យចល័ត"</string> + <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"បានបិទទិន្នន័យ"</string> + <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"អ្នកបានដល់ដែនកំណត់ប្រើទិន្នន័យបានបញ្ជាក់។\n\nបើអ្នកបើកទិន្នន័យឡើងវិញ អ្នកអាចត្រូវបានប្ដូរដោយប្រតិបត្តិករ។"</string> + <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"បើកទិន្នន័យឡើងវិញ"</string> + <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"គ្មានការតភ្ជាប់អ៊ីនធឺណិត"</string> + <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"បានភ្ជាប់វ៉ាយហ្វាយ"</string> + <string name="gps_notification_searching_text" msgid="8574247005642736060">"ស្វែងរក GPS"</string> + <string name="gps_notification_found_text" msgid="4619274244146446464">"ទីតាំងកំណត់ដោយ GPS"</string> + <string name="accessibility_location_active" msgid="2427290146138169014">"សំណើទីតាំងសកម្ម"</string> + <string name="accessibility_clear_all" msgid="5235938559247164925">"សម្អាតការជូនដំណឹងទាំងអស់។"</string> + <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"ព័ត៌មានកម្មវិធី"</string> + <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"នឹងបង្វិលអេក្រង់ស្វ័យប្រវត្តិ។"</string> + <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"អេក្រង់ជាប់សោក្នុងទិសផ្ដេក។"</string> + <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"បានចាក់សោអេក្រង់ក្នុងទិសបញ្ឈរ។"</string> + <string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string> + <string name="start_dreams" msgid="7219575858348719790">"ស្រមើស្រមៃ"</string> + <string name="ethernet_label" msgid="7967563676324087464">"អ៊ីសឺរណិត"</string> + <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"របៀបជិះយន្តហោះ"</string> + <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"បញ្ចូលថ្ម <xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string> + <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"បានបញ្ចូលពេញ"</string> + <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ប៊្លូធូស"</string> + <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ប៊្លូធូស (ឧបករណ៍ <xliff:g id="NUMBER">%d</xliff:g>)"</string> + <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"បិទប៊្លូធូស"</string> + <string name="quick_settings_brightness_label" msgid="6968372297018755815">"ពន្លឺ"</string> + <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"បង្វិលស្វ័យប្រវត្តិ"</string> + <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"បានចាក់សោការបង្វិល"</string> + <string name="quick_settings_ime_label" msgid="7073463064369468429">"វិធីសាស្ត្របញ្ចូល"</string> + <string name="quick_settings_location_label" msgid="5011327048748762257">"ទីតាំង"</string> + <string name="quick_settings_location_off_label" msgid="7464544086507331459">"ទីតាំងបិទ"</string> + <string name="quick_settings_media_device_label" msgid="1302906836372603762">"ឧបករណ៍មេឌៀ"</string> + <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string> + <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"សម្រាប់តែការហៅពេលអាសន្ន"</string> + <string name="quick_settings_settings_label" msgid="5326556592578065401">"ការកំណត់"</string> + <string name="quick_settings_time_label" msgid="4635969182239736408">"ពេលវេលា"</string> + <string name="quick_settings_user_label" msgid="5238995632130897840">"ខ្ញុំ"</string> + <string name="quick_settings_wifi_label" msgid="9135344704899546041">"វ៉ាយហ្វាយ"</string> + <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"មិនបានតភ្ជាប់"</string> + <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"គ្មានបណ្ដាញ"</string> + <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"បិទវ៉ាយហ្វាយ"</string> + <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"បង្ហាញវ៉ាយហ្វាយ"</string> + <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"បង្ហាញបណ្ដាញឥតខ្សែ"</string> + <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ពន្លឺ"</string> + <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ស្វ័យប្រវត្តិ"</string> + <string name="status_bar_help_title" msgid="1199237744086469217">"ការជូនដំណឹងបង្ហាញនៅទីនេះ"</string> + <string name="status_bar_help_text" msgid="7874607155052076323">"ចូលដំណើរការពួកវាពេលណាមួយដោយអូសចុះក្រោម។\nអូសចុះក្រោមម្ដងទៀត ដើម្បីពិនិត្យប្រព័ន្ធ។"</string> +</resources> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 403c94b..6319184 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -164,8 +164,7 @@ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 연결됨"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS 검색 중"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS에서 위치 설정"</string> - <!-- no translation found for accessibility_location_active (2427290146138169014) --> - <skip /> + <string name="accessibility_location_active" msgid="2427290146138169014">"위치 요청 있음"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"모든 알림 지우기"</string> <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"앱 정보"</string> <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"화면이 자동으로 회전됩니다."</string> @@ -202,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"자동"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"알림이 여기에 표시됨"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"아래로 스와이프하여 언제든 액세스하세요.\n한 번 더 아래로 스와이프하면 시스템 관리로 이동합니다."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"화면 가장자리에서 스와이프하여 표시줄 표시"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"화면 가장자리에서 스와이프하여 시스템 표시줄 표시"</string> </resources> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml new file mode 100644 index 0000000..85b10f7 --- /dev/null +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -0,0 +1,204 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, 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 xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_label" msgid="7164937344850004466">"ສ່ວນຕິດຕໍ່ຜູ່ໃຊ້ຂອງລະບົບ"</string> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"ລຶບ"</string> + <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"ເອົາອອກຈາກລາຍການ"</string> + <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"ຂໍ້ມູນແອັບຯ"</string> + <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"ບໍ່ມີແອັບຯທີ່ຫາກໍໃຊ້"</string> + <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"ປິດແອັບຯຫຼ້າສຸດທີ່ໃຊ້"</string> + <plurals name="status_bar_accessibility_recent_apps"> + <item quantity="one" msgid="5854176083865845541">"1 ແອັບຯຫຼ້າສຸດ"</item> + <item quantity="other" msgid="1040784359794890744">"%d ແອັບຯຫຼ້າສຸດ"</item> + </plurals> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"ບໍ່ມີການແຈ້ງເຕືອນ"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"ດຳເນີນຢູ່"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"ການແຈ້ງເຕືອນ"</string> + <string name="battery_low_title" msgid="2783104807551211639">"ເຊື່ອມຕໍ່ສາຍສາກ"</string> + <string name="battery_low_subtitle" msgid="1752040062087829196">"ແບັດເຕີຣີເຫຼືອໜ້ອຍແລ້ວ."</string> + <string name="battery_low_percent_format" msgid="1077244949318261761">"ຍັງເຫຼືອອີກ <xliff:g id="NUMBER">%d%%</xliff:g>"</string> + <string name="invalid_charger" msgid="4549105996740522523">"ບໍ່ຮອງຮັບການສາກໄຟດ້ວຍ USB.\nຕ້ອງໃຊ້ສະເພາະເຄື່ອງສາກທີ່ແຖມມານຳເທົ່ານັ້ນ."</string> + <string name="battery_low_why" msgid="7279169609518386372">"ການນຳໃຊ້ແບັດເຕີຣີ"</string> + <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"ການຕັ້ງຄ່າ"</string> + <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string> + <string name="status_bar_settings_airplane" msgid="4879879698500955300">"ໂໝດເທິງຍົນ"</string> + <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"ໝຸນໜ້າຈໍອັດຕະໂນມັດ"</string> + <string name="status_bar_settings_mute_label" msgid="554682549917429396">"ປິດສຽງ"</string> + <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"ອັດຕະໂນມັດ"</string> + <string name="status_bar_settings_notifications" msgid="397146176280905137">"ການແຈ້ງເຕືອນ"</string> + <string name="bluetooth_tethered" msgid="7094101612161133267">"ປ່ອຍສັນຍານຜ່ານ Bluetooth ແລ້ວ"</string> + <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"ຕັ້ງຄ່າວິທີການປ້ອນຂໍ້ມູນ"</string> + <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"ແປ້ນພິມແທ້"</string> + <string name="usb_device_permission_prompt" msgid="834698001271562057">"ອະນຸຍາດໃຫ້ແອັບຯ <xliff:g id="APPLICATION">%1$s</xliff:g> ເຂົ້າເຖິງອຸປະກອນ USB?"</string> + <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"ອະນຸຍາດໃຫ້ແອັບຯ <xliff:g id="APPLICATION">%1$s</xliff:g> ເຂົ້າເຖິງອຸປະກອນພ່ວງ USB?"</string> + <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"ເປີດ <xliff:g id="ACTIVITY">%1$s</xliff:g> ເມື່ອເຊື່ອມຕໍ່ກັບອຸປະກອນ USB ນີ້ຫຼືບໍ່?"</string> + <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"ເປີດ <xliff:g id="ACTIVITY">%1$s</xliff:g> ເມື່ອມີການເຊື່ອມຕໍ່ກັບອຸປະກອນເສີມ USB ນີ້ຫຼືບໍ່?"</string> + <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"ບໍ່ມີແອັບຯໃດທີ່ຕິດຕັ້ງໄປແລ້ວ ສາມາດເຮັດວຽກຮ່ວມກັບອຸປະກອນເສີມ USB ນີ້ໄດ້. ສຶກສາເພີ່ມເຕີມກ່ຽວກັບອຸປະກອນເສີມນີ້ທີ່ <xliff:g id="URL">%1$s</xliff:g>"</string> + <string name="title_usb_accessory" msgid="4966265263465181372">"ອຸປະກອນເສີມ USB"</string> + <string name="label_view" msgid="6304565553218192990">"ເບິ່ງ"</string> + <string name="always_use_device" msgid="1450287437017315906">"ໃຊ້ເປັນຄ່າເລີ່ມຕົ້ນສຳລັບອຸປະກອນ USB ນີ້"</string> + <string name="always_use_accessory" msgid="1210954576979621596">"ໃຊ້ຄ່າເລີ່ມຕົ້ນສຳລັບອຸປະກອນເສີມ USB ນີ້."</string> + <string name="usb_debugging_title" msgid="4513918393387141949">"ອະນຸຍາດການດີບັ໊ກຜ່ານ USB?"</string> + <string name="usb_debugging_message" msgid="2220143855912376496">"ລາຍນິ້ມື RSA ຂອງຄອມພິວເຕີແມ່ນ:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string> + <string name="usb_debugging_always" msgid="303335496705863070">"ອະນຸຍາດຈາກຄອມພິວເຕີນີ້ຕະຫຼອດ"</string> + <string name="compat_mode_on" msgid="6623839244840638213">"ຊູມໃຫ້ເຕັມໜ້າຈໍ"</string> + <string name="compat_mode_off" msgid="4434467572461327898">"ປັບໃຫ້ເຕັມໜ້າຈໍ"</string> + <string name="compat_mode_help_header" msgid="7969493989397529910">"ຄວາມເຂົ້າກັນໄດ້ຂອງການຊູມ"</string> + <string name="compat_mode_help_body" msgid="4946726776359270040">"ເມື່ອແອັບຯຖືກອອກແບບມາສຳລັບໜ້າຈໍນ້ອຍກວ່າ, ຕົວຄວບຄຸມການຊູມຈະປາກົດຢູ່ໃກ້ກັບໂມງ."</string> + <string name="screenshot_saving_ticker" msgid="7403652894056693515">"ກຳລັງບັນທຶກຮູບໜ້າຈໍ"</string> + <string name="screenshot_saving_title" msgid="8242282144535555697">"ກຳລັງບັນທຶກພາບໜ້າຈໍ..."</string> + <string name="screenshot_saving_text" msgid="2419718443411738818">"ກຳລັງບັນທຶກພາບໜ້າຈໍ."</string> + <string name="screenshot_saved_title" msgid="6461865960961414961">"ຖ່າຍຮູບໜ້າຈໍແລ້ວ"</string> + <string name="screenshot_saved_text" msgid="1152839647677558815">"ແຕະເພື່ອເບິ່ງພາບໜ້າຈໍຂອງທ່ານ."</string> + <string name="screenshot_failed_title" msgid="705781116746922771">"ບໍ່ສາມາດຖ່າຍຮູບໜ້າຈໍໄດ້"</string> + <string name="screenshot_failed_text" msgid="8134011269572415402">"ບໍ່ສາມາດບັນທຶກພາບໜ້າຈໍໄດ້. ບ່ອນຈັດເກັບອາດກຳລັງຖືກນຳໃຊ້ຢູ່."</string> + <string name="usb_preference_title" msgid="6551050377388882787">"USB ໂຕເລືອກການຍ້າຍໄຟລ໌"</string> + <string name="use_mtp_button_title" msgid="4333504413563023626">"ເຊື່ອມຕໍ່ເປັນ media player (MTP)"</string> + <string name="use_ptp_button_title" msgid="7517127540301625751">"ເຊື່ອມຕໍ່ເປັນກ້ອງຖ່າຍຮູບ (PTP)"</string> + <string name="installer_cd_button_title" msgid="2312667578562201583">"ຕິດຕັ້ງແອັບຯ Android File Transfer ສຳລັບ Mac"</string> + <string name="accessibility_back" msgid="567011538994429120">"ກັບຄືນ"</string> + <string name="accessibility_home" msgid="8217216074895377641">"ໜ້າທຳອິດ"</string> + <string name="accessibility_menu" msgid="316839303324695949">"ເມນູ"</string> + <string name="accessibility_recent" msgid="8571350598987952883">"ແອັບຯຫຼ້າສຸດ"</string> + <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ປຸ່ມສະລັບຮູບແບບການປ້ອນຂໍ້ມູນ."</string> + <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ປຸ່ມຊູມທີ່ໃຊ້ຮ່ວມກັນໄດ້."</string> + <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ຊູມຈໍນ້ອຍໄປເປັນຈໍຂະຫນາດໃຫຍ່."</string> + <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ເຊື່ອມຕໍ່ Bluetooth ແລ້ວ."</string> + <string name="accessibility_bluetooth_disconnected" msgid="7416648669976870175">"Bluetooth ຖືກຕັດການເຊື່ອມຕໍ່ແລ້ວ."</string> + <string name="accessibility_no_battery" msgid="358343022352820946">"ແບັດເຕີຣີໝົດ."</string> + <string name="accessibility_battery_one_bar" msgid="7774887721891057523">"ແບັດເຕີຣີນຶ່ງຂີດ."</string> + <string name="accessibility_battery_two_bars" msgid="8500650438735009973">"ແບັດເຕີຣີສອງຂີດ."</string> + <string name="accessibility_battery_three_bars" msgid="2302983330865040446">"ແບັດເຕີຣີສາມຂີດ."</string> + <string name="accessibility_battery_full" msgid="8909122401720158582">"ແບັດເຕີຣີເຕັມ."</string> + <string name="accessibility_no_phone" msgid="4894708937052611281">"ບໍ່ມີໂທລະສັບ."</string> + <string name="accessibility_phone_one_bar" msgid="687699278132664115">"ສັນຍານນຶ່ງຂີດ."</string> + <string name="accessibility_phone_two_bars" msgid="8384905382804815201">"ສັນຍານສອງຂີດ."</string> + <string name="accessibility_phone_three_bars" msgid="8521904843919971885">"ສັນຍານສາມຂີດ."</string> + <string name="accessibility_phone_signal_full" msgid="6471834868580757898">"ສັນຍານເຕັມ."</string> + <string name="accessibility_no_data" msgid="4791966295096867555">"ບໍ່ມີຂໍ້ມູນ."</string> + <string name="accessibility_data_one_bar" msgid="1415625833238273628">"ຂໍ້ມູນນຶ່ງຂີດ."</string> + <string name="accessibility_data_two_bars" msgid="6166018492360432091">"ຂໍ້ມູນສອງຂີດ."</string> + <string name="accessibility_data_three_bars" msgid="9167670452395038520">"ຂໍ້ມູນສາມຂີດ."</string> + <string name="accessibility_data_signal_full" msgid="2708384608124519369">"ສັນຍານຂໍ້ມູນເຕັມ."</string> + <string name="accessibility_wifi_off" msgid="3177380296697933627">"WiFi ປິດຢູ່."</string> + <string name="accessibility_no_wifi" msgid="1425476551827924474">"ຕັດການເຊື່ອມຕໍ່ Wi-Fi ແລ້ວ."</string> + <string name="accessibility_wifi_one_bar" msgid="7735893178010724377">"ສັນຍານ Wi-Fi ນຶ່ງຂີດ."</string> + <string name="accessibility_wifi_two_bars" msgid="4994274250497262434">"ສັນຍານ Wi-Fi ສອງຂີດ."</string> + <string name="accessibility_wifi_three_bars" msgid="3495755044276588384">"Wifi ສາມຂີດ."</string> + <string name="accessibility_wifi_signal_full" msgid="6853561303586480376">"ສັນຍານ Wi-Fi ເຕັມ"</string> + <string name="accessibility_no_wimax" msgid="4329180129727630368">"ບໍ່ມີ WiMAX."</string> + <string name="accessibility_wimax_one_bar" msgid="4170994299011863648">"WiMAX ນຶ່ງຂີດ."</string> + <string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"WiMAX ສອງຂີດ."</string> + <string name="accessibility_wimax_three_bars" msgid="6116551636752103927">"WiMAX ສາມຂີດ."</string> + <string name="accessibility_wimax_signal_full" msgid="2768089986795579558">"ສັນຍານ WiMAX ເຕັມ."</string> + <string name="accessibility_no_signal" msgid="7064645320782585167">"ບໍ່ມີສັນຍານ."</string> + <string name="accessibility_not_connected" msgid="6395326276213402883">"ບໍ່ໄດ້ເຊື່ອມຕໍ່."</string> + <string name="accessibility_zero_bars" msgid="3806060224467027887">"ບໍ່ມີຈັກຂີດ."</string> + <string name="accessibility_one_bar" msgid="1685730113192081895">"ນຶ່ງຂີດ."</string> + <string name="accessibility_two_bars" msgid="6437363648385206679">"ສອງຂີດ."</string> + <string name="accessibility_three_bars" msgid="2648241415119396648">"ສາມຂີດ."</string> + <string name="accessibility_signal_full" msgid="9122922886519676839">"ສັນຍານເຕັມ."</string> + <string name="accessibility_desc_on" msgid="2385254693624345265">"ເປີດ."</string> + <string name="accessibility_desc_off" msgid="6475508157786853157">"ປິດ."</string> + <string name="accessibility_desc_connected" msgid="8366256693719499665">"ເຊື່ອມຕໍ່ແລ້ວ."</string> + <string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string> + <string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string> + <string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string> + <string name="accessibility_data_connection_3g" msgid="8628562305003568260">"3G"</string> + <string name="accessibility_data_connection_3.5g" msgid="8664845609981692001">"3.5G"</string> + <string name="accessibility_data_connection_4g" msgid="7741000750630089612">"4G"</string> + <string name="accessibility_data_connection_lte" msgid="5413468808637540658">"LTE"</string> + <string name="accessibility_data_connection_cdma" msgid="6132648193978823023">"CDMA"</string> + <string name="accessibility_data_connection_roaming" msgid="5977362333466556094">"ໂຣມມິງ"</string> + <string name="accessibility_data_connection_edge" msgid="4477457051631979278">"Edge"</string> + <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Wi-Fi"</string> + <string name="accessibility_no_sim" msgid="8274017118472455155">"ບໍ່ມີຊິມ."</string> + <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"ການປ່ອຍສັນຍານ Bluetooth."</string> + <string name="accessibility_airplane_mode" msgid="834748999790763092">"ໂໝດໃນຍົນ."</string> + <string name="accessibility_battery_level" msgid="7451474187113371965">"ແບັດເຕີຣີ <xliff:g id="NUMBER">%d</xliff:g> ເປີເຊັນ."</string> + <string name="accessibility_settings_button" msgid="799583911231893380">"ການຕັ້ງຄ່າລະບົບ."</string> + <string name="accessibility_notifications_button" msgid="4498000369779421892">"ການແຈ້ງເຕືອນ."</string> + <string name="accessibility_remove_notification" msgid="3603099514902182350">"ລຶບລ້າງການແຈ້ງເຕືອນ."</string> + <string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS ເປີດແລ້ວ."</string> + <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"ກຳລັງຊອກຫາ GPS."</string> + <string name="accessibility_tty_enabled" msgid="4613200365379426561">"TeleTypewriter ຖືກເປີດຢູ່."</string> + <string name="accessibility_ringer_vibrate" msgid="666585363364155055">"ສັ່ນເຕືອນພ້ອມສຽງເອີ້ນເຂົ້າ."</string> + <string name="accessibility_ringer_silent" msgid="9061243307939135383">"ປິດສຽງ."</string> + <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"ປິດ <xliff:g id="APP">%s</xliff:g> ແລ້ວ."</string> + <string name="accessibility_notification_dismissed" msgid="854211387186306927">"ປິດການແຈ້ງເຕືອນແລ້ວ."</string> + <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"ໜ້າຈໍແຈ້ງເຕືອນ."</string> + <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"ການຕັ້ງຄ່າດ່ວນ."</string> + <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"ແອັບຯທີ່ຫາກໍໃຊ້."</string> + <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"ຜູ່ໃຊ້ <xliff:g id="USER">%s</xliff:g>."</string> + <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string> + <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"ມືຖື <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string> + <string name="accessibility_quick_settings_battery" msgid="1480931583381408972">"ແບັດເຕີຣີ <xliff:g id="STATE">%s</xliff:g>."</string> + <string name="accessibility_quick_settings_airplane" msgid="4196876722090224753">"ໂໝດໃນຍົນ <xliff:g id="STATE">%s</xliff:g>."</string> + <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>."</string> + <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"ຕັ້ງໂມງປຸກ <xliff:g id="TIME">%s</xliff:g> ແລ້ວ."</string> + <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"ອິນເຕີເນັດ 2G, 3G ຖືກປິດແລ້ວ"</string> + <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"ການນຳໃຊ້ຂໍ້ມູນ 4G ຖືກປິດແລ້ວ"</string> + <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"ອິນເຕີເນັດໃນມືຖືຖືກປິດການນຳໃຊ້ແລ້ວ"</string> + <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"ອິນເຕີເນັດຖືກປິດການນຳໃຊ້ແລ້ວ"</string> + <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"ທ່ານໄດ້ໃຊ້ຂໍ້ມູນຈົນຮອດຈຳນວນທີ່ຈຳກັດໄວ້ແລ້ວ.\n\nຫາກທ່ານເປີດນຳໃຊ້ຂໍ້ມູນຄືນອີກຄັ້ງ, ທ່ານອາດຖືກຮຽກເກັບເງິນໂດຍຜູ່ໃຫ້ບໍລິການໄດ້."</string> + <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"ເປີດນຳໃຊ້ຂໍ້ມູນຄືນໃໝ່"</string> + <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ"</string> + <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ເຊື່ອມຕໍ່ Wi--Fi ແລ້ວ"</string> + <string name="gps_notification_searching_text" msgid="8574247005642736060">"ກຳລັງຊອກຫາ GPS"</string> + <string name="gps_notification_found_text" msgid="4619274244146446464">"ສະຖານທີ່ກຳນົດໂດຍ GPS"</string> + <string name="accessibility_location_active" msgid="2427290146138169014">"ການຮ້ອງຂໍສະຖານທີ່ທີ່ເຮັດວຽກຢູ່"</string> + <string name="accessibility_clear_all" msgid="5235938559247164925">"ລຶບການແຈ້ງເຕືອນທັງໝົດ."</string> + <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"ຂໍ້ມູນແອັບຯ"</string> + <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"ໜ້າຈໍຈະໝຸນໂດຍອັດຕະໂນມັດ."</string> + <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"ໜ້າຈໍຖືກລັອກໃນລວງນອນ."</string> + <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"ໜ້າຈໍຖືກລັອກຢູ່ໃນໂໝດແນວຕັ້ງ."</string> + <string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string> + <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string> + <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string> + <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"ໂໝດຢູ່ໃນຍົນ"</string> + <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"ກຳລັງສາກ, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string> + <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"ສາກເຕັມແລ້ວ"</string> + <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string> + <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> ອຸປະກອນ)"</string> + <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth ປິດ"</string> + <string name="quick_settings_brightness_label" msgid="6968372297018755815">"ຄວາມສະຫວ່າງ"</string> + <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"ໝຸນໜ້າຈໍອັດຕະໂນມັດ"</string> + <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"ລັອກການປ່ຽນລວງ"</string> + <string name="quick_settings_ime_label" msgid="7073463064369468429">"ວິທີການປ້ອນຂໍ້ມູນ"</string> + <string name="quick_settings_location_label" msgid="5011327048748762257">"ສະຖານທີ່"</string> + <string name="quick_settings_location_off_label" msgid="7464544086507331459">"ຂໍ້ມູນສະຖານທີ່ປິດຢູ່"</string> + <string name="quick_settings_media_device_label" msgid="1302906836372603762">"ອຸປະກອນສື່"</string> + <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string> + <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"ໂທສຸກເສີນເທົ່ານັ້ນ"</string> + <string name="quick_settings_settings_label" msgid="5326556592578065401">"ການຕັ້ງຄ່າ"</string> + <string name="quick_settings_time_label" msgid="4635969182239736408">"ເວລາ"</string> + <string name="quick_settings_user_label" msgid="5238995632130897840">"ຂ້ອຍ"</string> + <string name="quick_settings_wifi_label" msgid="9135344704899546041">"Wi-Fi"</string> + <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"ບໍ່ໄດ້ເຊື່ອມຕໍ່"</string> + <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"ບໍ່ມີເຄືອຂ່າຍ"</string> + <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi ປິດ"</string> + <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"ຈໍສະແດງຜົນ Wi-Fi"</string> + <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"ການສະແດງຜົນໄຮ້ສາຍ"</string> + <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ຄວາມແຈ້ງ"</string> + <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ອັດຕະໂນມັດ"</string> + <string name="status_bar_help_title" msgid="1199237744086469217">"ການແຈ້ງເຕືອນຈະປາກົດບ່ອນນີ້"</string> + <string name="status_bar_help_text" msgid="7874607155052076323">"ເຂົ້າເຖິງໄດ້ທຸກເມື່ອໂດຍການປັດນິ້ວລົງ.\nປັດລົງອີກເທື່ອນຶ່ງສຳລັບການຄວບຄຸມລະບົບ."</string> +</resources> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 11b67ed..4400d37 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -164,8 +164,7 @@ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Prisij. prie „Wi-Fi“"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"Ieškoma GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS nustatyta vieta"</string> - <!-- no translation found for accessibility_location_active (2427290146138169014) --> - <skip /> + <string name="accessibility_location_active" msgid="2427290146138169014">"Vietovės užklausos aktyvios"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Išvalyti visus pranešimus."</string> <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Programos informacija"</string> <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekranas bus sukamas automatiškai."</string> @@ -202,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATINIS"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Pranešimai rodomi čia"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Perbraukę žemyn bet kuriuo metu pasieksite pranešimus.\nJei norite naudoti sistemos valdiklius, perbraukite žemyn dar kartą."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Jei norite, kad būtų rodoma juosta, perbraukite ekrano krašte"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Jei norite, kad būtų rodoma sistemos juosta, perbraukite iš ekrano krašto"</string> </resources> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 85ab3fd..b2bee8c 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -164,8 +164,7 @@ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Izv. sav. ar Wi-Fi"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"Notiek GPS meklēšana..."</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS iestatītā atrašanās vieta"</string> - <!-- no translation found for accessibility_location_active (2427290146138169014) --> - <skip /> + <string name="accessibility_location_active" msgid="2427290146138169014">"Aktīvi atrašanās vietu pieprasījumi"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Notīrīt visus paziņojumus"</string> <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informācija par lietotni"</string> <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekrāns tiks pagriezts automātiski."</string> @@ -202,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMĀTISKI"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Šeit tiek rādīti paziņojumi"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Piekļūstiet tiem jebkurā laikā, velkot uz leju.\nVēlreiz velciet, lai tiktu parādītas sistēmas vadīklas."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Velciet no ekrāna malas, lai piekļūtu joslai."</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Velciet no ekrāna malas, lai piekļūtu sistēmas joslai."</string> </resources> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml new file mode 100644 index 0000000..f5b45e1 --- /dev/null +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -0,0 +1,204 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, 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 xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_label" msgid="7164937344850004466">"Систем UI"</string> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Цэвэрлэх"</string> + <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Жагсаалтаас устгах"</string> + <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Апп мэдээлэл"</string> + <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Сүүлийн апп хоосон"</string> + <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Сүүлийн апп-уудыг хаах"</string> + <plurals name="status_bar_accessibility_recent_apps"> + <item quantity="one" msgid="5854176083865845541">"1 сүүлийн апп"</item> + <item quantity="other" msgid="1040784359794890744">"%d сүүлийн апп"</item> + </plurals> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Мэдэгдэл байхгүй"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Гарсан"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Мэдэгдэл"</string> + <string name="battery_low_title" msgid="2783104807551211639">"Цэнэглэгчийг холбоно уу"</string> + <string name="battery_low_subtitle" msgid="1752040062087829196">"Батерей дуусаж байна."</string> + <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> үлдсэн"</string> + <string name="invalid_charger" msgid="4549105996740522523">"USB цэнэглэлт дэмжигдэхгүй байна.\nЗөвхөн нийлүүлэгдсэн цэнэглэгчийг ашиглана уу."</string> + <string name="battery_low_why" msgid="7279169609518386372">"Батерей ашиглах"</string> + <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Тохиргоо"</string> + <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string> + <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Нислэгийн горим"</string> + <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Дэлгэцийг автоматаар эргүүлэх"</string> + <string name="status_bar_settings_mute_label" msgid="554682549917429396">"ХААХ"</string> + <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"АВТОМАТ"</string> + <string name="status_bar_settings_notifications" msgid="397146176280905137">"Мэдэгдэл"</string> + <string name="bluetooth_tethered" msgid="7094101612161133267">"Блютүүтыг модем болгож байна"</string> + <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Оруулах аргыг тохируулах"</string> + <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Бодит гар"</string> + <string name="usb_device_permission_prompt" msgid="834698001271562057">"<xliff:g id="APPLICATION">%1$s</xliff:g> апп-г USB төхөөрөмжид хандахыг зөвшөөрөх үү?"</string> + <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"<xliff:g id="APPLICATION">%1$s</xliff:g> апп-г USB төхөөрөмжид хандахыг зөвшөөрөх үү?"</string> + <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Энэ USB төхөөрөмж холбогдох үед <xliff:g id="ACTIVITY">%1$s</xliff:g>-г нээх үү?"</string> + <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Энэ USB төхөөрөмж холбогдох үед <xliff:g id="ACTIVITY">%1$s</xliff:g>-г нээх үү?"</string> + <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Энэ USB хэрэгсэл дээр суулгасан апп ажиллаагүй байна. Энэ хэрэгслийн талаар <xliff:g id="URL">%1$s</xliff:g>-с дэлгэрэнгүй үзнэ үү."</string> + <string name="title_usb_accessory" msgid="4966265263465181372">"USB төхөөрөмж"</string> + <string name="label_view" msgid="6304565553218192990">"Үзэх"</string> + <string name="always_use_device" msgid="1450287437017315906">"Энэ USB төхөөрөмжийг үндсэн болгон ашиглах"</string> + <string name="always_use_accessory" msgid="1210954576979621596">"Энэ USB төхөөрөмжийг үндсэн болгон ашиглах"</string> + <string name="usb_debugging_title" msgid="4513918393387141949">"USB дебаг хийхийг зөвшөөрөх үү?"</string> + <string name="usb_debugging_message" msgid="2220143855912376496">"Компьютерийн RSA түлхүүрийн хурууны хээ :\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string> + <string name="usb_debugging_always" msgid="303335496705863070">"Энэ компьютерээс орохыг байнга зөвшөөрөх"</string> + <string name="compat_mode_on" msgid="6623839244840638213">"Дэлгэц дүүргэх бол өсгөнө үү"</string> + <string name="compat_mode_off" msgid="4434467572461327898">"Дэлгэц дүүргэх бол татна уу"</string> + <string name="compat_mode_help_header" msgid="7969493989397529910">"Зохицсон өсгөлт"</string> + <string name="compat_mode_help_body" msgid="4946726776359270040">"Жижиг дэлгэцэнд зориулагдсан апп-н хувьд өсгөх контрол цагаар гарч ирнэ."</string> + <string name="screenshot_saving_ticker" msgid="7403652894056693515">"Дэлгэцийн агшинг хадгалж байна…"</string> + <string name="screenshot_saving_title" msgid="8242282144535555697">"Дэлгэцийн агшинг хадгалж байна…"</string> + <string name="screenshot_saving_text" msgid="2419718443411738818">"Дэлгэцийн агшин хадгалагдав."</string> + <string name="screenshot_saved_title" msgid="6461865960961414961">"Дэлгэцийн агшинг авсан."</string> + <string name="screenshot_saved_text" msgid="1152839647677558815">"Дэлгэцийн агшныг харах бол хүрнэ үү."</string> + <string name="screenshot_failed_title" msgid="705781116746922771">"Дэлгэцийн агшинг авч чадсангүй."</string> + <string name="screenshot_failed_text" msgid="8134011269572415402">"Дэлгэцийн агшинг хадгалж чадсангүй. Сан ашиглагдаж байгаа бололтой."</string> + <string name="usb_preference_title" msgid="6551050377388882787">"USB файл шилжүүлэх сонголт"</string> + <string name="use_mtp_button_title" msgid="4333504413563023626">"Медиа тоглуулагч(MTP) болгон залгах"</string> + <string name="use_ptp_button_title" msgid="7517127540301625751">"Камер болгон(PTP) залгах"</string> + <string name="installer_cd_button_title" msgid="2312667578562201583">"Мас-д зориулсан Андройд Файл Шилжүүлэх апп-г суулгана уу"</string> + <string name="accessibility_back" msgid="567011538994429120">"Буцах"</string> + <string name="accessibility_home" msgid="8217216074895377641">"Гэрийн"</string> + <string name="accessibility_menu" msgid="316839303324695949">"Цэс"</string> + <string name="accessibility_recent" msgid="8571350598987952883">"Сүүлийн апп"</string> + <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Оруулах аргыг сэлгэх товч."</string> + <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Тохиромжтой өсгөх товч."</string> + <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Жижгээс том дэлгэцрүү өсгөх."</string> + <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Блютүүт холбогдсон."</string> + <string name="accessibility_bluetooth_disconnected" msgid="7416648669976870175">"Блютүүт тасрав."</string> + <string name="accessibility_no_battery" msgid="358343022352820946">"Батерей байхгүй."</string> + <string name="accessibility_battery_one_bar" msgid="7774887721891057523">"Батерей нэг баганатай."</string> + <string name="accessibility_battery_two_bars" msgid="8500650438735009973">"Батерей хоёр баганатай."</string> + <string name="accessibility_battery_three_bars" msgid="2302983330865040446">"Батерей гурван баганатай."</string> + <string name="accessibility_battery_full" msgid="8909122401720158582">"Батерей дүүрэн."</string> + <string name="accessibility_no_phone" msgid="4894708937052611281">"Утас байхгүй."</string> + <string name="accessibility_phone_one_bar" msgid="687699278132664115">"Утас нэг баганатай."</string> + <string name="accessibility_phone_two_bars" msgid="8384905382804815201">"Утас хоёр баганатай."</string> + <string name="accessibility_phone_three_bars" msgid="8521904843919971885">"Утас гурван баганатай."</string> + <string name="accessibility_phone_signal_full" msgid="6471834868580757898">"Утасны дохио дүүрэн."</string> + <string name="accessibility_no_data" msgid="4791966295096867555">"Дата байхгүй."</string> + <string name="accessibility_data_one_bar" msgid="1415625833238273628">"Дата нэг баганатай."</string> + <string name="accessibility_data_two_bars" msgid="6166018492360432091">"Дата хоёр баганатай."</string> + <string name="accessibility_data_three_bars" msgid="9167670452395038520">"Дата гурван баганатай."</string> + <string name="accessibility_data_signal_full" msgid="2708384608124519369">"Дата дохио дүүрэн."</string> + <string name="accessibility_wifi_off" msgid="3177380296697933627">"Wifi унтарсан."</string> + <string name="accessibility_no_wifi" msgid="1425476551827924474">"Wifi салав."</string> + <string name="accessibility_wifi_one_bar" msgid="7735893178010724377">"Wifi нэг баганатай."</string> + <string name="accessibility_wifi_two_bars" msgid="4994274250497262434">"Wifi хоёр баганатай."</string> + <string name="accessibility_wifi_three_bars" msgid="3495755044276588384">"Wifi гурван баганатай."</string> + <string name="accessibility_wifi_signal_full" msgid="6853561303586480376">"Wifi дохио дүүрэн."</string> + <string name="accessibility_no_wimax" msgid="4329180129727630368">"WiMAX байхгүй."</string> + <string name="accessibility_wimax_one_bar" msgid="4170994299011863648">"WiMAX нэг багана."</string> + <string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"WiMAX хоёр баганатай."</string> + <string name="accessibility_wimax_three_bars" msgid="6116551636752103927">"WiMAX гурван баганатай."</string> + <string name="accessibility_wimax_signal_full" msgid="2768089986795579558">"WiMAX дохио дүүрэн."</string> + <string name="accessibility_no_signal" msgid="7064645320782585167">"Дохио байхгүй."</string> + <string name="accessibility_not_connected" msgid="6395326276213402883">"Холбогдоогүй."</string> + <string name="accessibility_zero_bars" msgid="3806060224467027887">"Тэг баганатай."</string> + <string name="accessibility_one_bar" msgid="1685730113192081895">"Нэг баганатай."</string> + <string name="accessibility_two_bars" msgid="6437363648385206679">"Хоёр багана."</string> + <string name="accessibility_three_bars" msgid="2648241415119396648">"Гурван баганатай."</string> + <string name="accessibility_signal_full" msgid="9122922886519676839">"Дохио дүүрэн."</string> + <string name="accessibility_desc_on" msgid="2385254693624345265">"Идэвхижсэн."</string> + <string name="accessibility_desc_off" msgid="6475508157786853157">"Унтраах"</string> + <string name="accessibility_desc_connected" msgid="8366256693719499665">"Холбогдсон."</string> + <string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string> + <string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string> + <string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string> + <string name="accessibility_data_connection_3g" msgid="8628562305003568260">"3G"</string> + <string name="accessibility_data_connection_3.5g" msgid="8664845609981692001">"3.5G"</string> + <string name="accessibility_data_connection_4g" msgid="7741000750630089612">"4G"</string> + <string name="accessibility_data_connection_lte" msgid="5413468808637540658">"LTE"</string> + <string name="accessibility_data_connection_cdma" msgid="6132648193978823023">"CDMA"</string> + <string name="accessibility_data_connection_roaming" msgid="5977362333466556094">"Рүүминг"</string> + <string name="accessibility_data_connection_edge" msgid="4477457051631979278">"Edge"</string> + <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Wi-Fi"</string> + <string name="accessibility_no_sim" msgid="8274017118472455155">"SIM байхгүй."</string> + <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Блютүүт модем болж байна."</string> + <string name="accessibility_airplane_mode" msgid="834748999790763092">"Нислэгийн горим"</string> + <string name="accessibility_battery_level" msgid="7451474187113371965">"Батерей <xliff:g id="NUMBER">%d</xliff:g> хувьтай."</string> + <string name="accessibility_settings_button" msgid="799583911231893380">"Системийн тохиргоо."</string> + <string name="accessibility_notifications_button" msgid="4498000369779421892">"Мэдэгдэл."</string> + <string name="accessibility_remove_notification" msgid="3603099514902182350">"Мэдэгдлийг цэвэрлэх."</string> + <string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS идэвхтэй."</string> + <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"GPS хайж байна."</string> + <string name="accessibility_tty_enabled" msgid="4613200365379426561">"TeleTypewriter идэвхтэй болов."</string> + <string name="accessibility_ringer_vibrate" msgid="666585363364155055">"Хонхны чичиргээ."</string> + <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Хонхыг хаах."</string> + <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> байхгүй."</string> + <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Мэдэгдэл хаагдсан."</string> + <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Мэдэгдлийн хураангуй самбар"</string> + <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Шуурхай тохиргоо."</string> + <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"Сүүлийн апп"</string> + <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Хэрэглэгч <xliff:g id="USER">%s</xliff:g>."</string> + <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string> + <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Мобайл <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string> + <string name="accessibility_quick_settings_battery" msgid="1480931583381408972">"Батерей <xliff:g id="STATE">%s</xliff:g>."</string> + <string name="accessibility_quick_settings_airplane" msgid="4196876722090224753">"Нислэгийн горим <xliff:g id="STATE">%s</xliff:g>."</string> + <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Блютүүт <xliff:g id="STATE">%s</xliff:g>."</string> + <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Сэрүүлгийг <xliff:g id="TIME">%s</xliff:g>-д тохируулсан."</string> + <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G-3G дата идэвхгүй болов"</string> + <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G дата идэвхгүй байна"</string> + <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Мобайл дата идэвхгүй болов"</string> + <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Дата идэвхгүй болов"</string> + <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Та заасан дата ашиглалтын хязгаарт хүрэв.\n\nХэрэв та датаг дахин идэвхжүүлбэл операторт төлбөр төлөх хэрэгтэй."</string> + <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Дата дахин идэвхжүүлэх"</string> + <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Интернет холболт байхгүй"</string> + <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi холбогдсон"</string> + <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS хайж байна"</string> + <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS байршил"</string> + <string name="accessibility_location_active" msgid="2427290146138169014">"Байршлын хүсэлтүүд идэвхтэй"</string> + <string name="accessibility_clear_all" msgid="5235938559247164925">"Бүх мэдэгдлийг цэвэрлэх."</string> + <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Апп мэдээлэл"</string> + <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Дэлгэц автоматаар эргэнэ."</string> + <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Дэлгэц хэвтээ чиглэлд түгжигдсэн."</string> + <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Дэлгэц босоо чиглэлээр түгжигдсэн."</string> + <string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string> + <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string> + <string name="ethernet_label" msgid="7967563676324087464">"Этернет"</string> + <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Нислэгийн горим"</string> + <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Цэнэглэж байна, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string> + <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Цэнэглэгдсэн"</string> + <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Блютүүт"</string> + <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Блютүүт (<xliff:g id="NUMBER">%d</xliff:g> төхөөрөмж)"</string> + <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Блютүүт унтраалттай"</string> + <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Тодрол"</string> + <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Автомат эргэх"</string> + <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Эргүүлэлт түгжигдсэн"</string> + <string name="quick_settings_ime_label" msgid="7073463064369468429">"Оруулах арга"</string> + <string name="quick_settings_location_label" msgid="5011327048748762257">"Байршил"</string> + <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Байршил идэвхгүй"</string> + <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Медиа төхөөрөмж"</string> + <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string> + <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Зөвхөн яаралтай дуудлага"</string> + <string name="quick_settings_settings_label" msgid="5326556592578065401">"Тохиргоо"</string> + <string name="quick_settings_time_label" msgid="4635969182239736408">"Цаг"</string> + <string name="quick_settings_user_label" msgid="5238995632130897840">"Би"</string> + <string name="quick_settings_wifi_label" msgid="9135344704899546041">"Wi-Fi"</string> + <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Холбогдоогүй"</string> + <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Сүлжээгүй"</string> + <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi унтарсан"</string> + <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi Дэлгэц"</string> + <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Утасгүй дэлгэц"</string> + <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Тодрол"</string> + <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТОМАТ"</string> + <string name="status_bar_help_title" msgid="1199237744086469217">"Мэдэгдэл энд харагдана"</string> + <string name="status_bar_help_text" msgid="7874607155052076323">"Доош татаад тэдгээрт хандана уу.\nДахин доош татаад систем контролд хандана уу."</string> +</resources> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index b6b3577..9c76eae 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -201,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Pemberitahuan dipaparkan di sini"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Akses panel pada bila-bila masa dengan meleret ke bawah.\nLeret ke bawah sekali lagi untuk mendapatkan kawalan sistem."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Leret ke bahagian tepi skrin untuk menampakkan bar"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Leret dari tepi skrin untuk menampakkan bar sistem"</string> </resources> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 6f7d727..d850cf3 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -164,8 +164,7 @@ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tilkoblet"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"Søker etter GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Posisjon angitt av GPS"</string> - <!-- no translation found for accessibility_location_active (2427290146138169014) --> - <skip /> + <string name="accessibility_location_active" msgid="2427290146138169014">"Aktive stedsforespørsler"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Fjern alle varslinger."</string> <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Info om app"</string> <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skjermen roterer automatisk."</string> @@ -202,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Varslene vises her"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Bruk dem når som helst ved å sveipe nedover.\nSveip nedover igjen for å gå til systemkontrollene."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Sveip på kanten av skjermen for å få frem feltet"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Sveip fra kanten på skjermen for å få frem systemfeltet"</string> </resources> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml new file mode 100644 index 0000000..c3eee01 --- /dev/null +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -0,0 +1,204 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, 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 xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_label" msgid="7164937344850004466">"प्रणाली UI"</string> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"हटाउनुहोस्"</string> + <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"सूचीबाट हटाउनुहोस्"</string> + <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"अनुप्रयोगको जानकारी"</string> + <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"कुनै नयाँ अनुप्रयोगहरू छैनन्"</string> + <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"नयाँ अनुप्रयोगहरू खारेज गर्नुहोस्"</string> + <plurals name="status_bar_accessibility_recent_apps"> + <item quantity="one" msgid="5854176083865845541">"१ भरखरै अनुप्रयोग"</item> + <item quantity="other" msgid="1040784359794890744">"%d भरखरैका अनुप्रयोगहरू"</item> + </plurals> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"कुनै सूचनाहरू छैन"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"चलिरहेको"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"सूचनाहरू"</string> + <string name="battery_low_title" msgid="2783104807551211639">"चार्जर जडान गर्नुहोस्"</string> + <string name="battery_low_subtitle" msgid="1752040062087829196">"ब्याट्रि न्यून हुँदै छ।"</string> + <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> बाँकी"</string> + <string name="invalid_charger" msgid="4549105996740522523">"USB चार्ज गर्न समर्थित छैन।\n आपूर्ति गरिएको चार्जर मात्र प्रयोग गर्नुहोस्।"</string> + <string name="battery_low_why" msgid="7279169609518386372">"ब्याट्रि प्रयोग"</string> + <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"सेटिङहरू"</string> + <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"वाइ-फाइ"</string> + <string name="status_bar_settings_airplane" msgid="4879879698500955300">"हवाइजहाज मोड"</string> + <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"स्वत:घुम्ने स्क्रिन"</string> + <string name="status_bar_settings_mute_label" msgid="554682549917429396">"म्युट गर्नुहोस्"</string> + <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"स्वतः"</string> + <string name="status_bar_settings_notifications" msgid="397146176280905137">"सूचनाहरू"</string> + <string name="bluetooth_tethered" msgid="7094101612161133267">"ब्लुटुथ टेथर भयो"</string> + <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"इनपुट विधिहरू सेटअप गर्नुहोस्"</string> + <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"फिजिकल किबोर्ड"</string> + <string name="usb_device_permission_prompt" msgid="834698001271562057">"<xliff:g id="APPLICATION">%1$s</xliff:g> USB उपकरणलाई पहुँच दिनको लागि अनुप्रयोगलाई अनुमति दिने हो?"</string> + <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"<xliff:g id="APPLICATION">%1$s</xliff:g> USB पाटपुर्जालाई पहुँच दिनको लागि अनुप्रयोगलाई अनुमति दिने हो?"</string> + <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"यो USB उपकरण जोडिएको बेला <xliff:g id="ACTIVITY">%1$s</xliff:g> खोल्ने हो?"</string> + <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"यो USB सहायक जडान हुँदा <xliff:g id="ACTIVITY">%1$s</xliff:g> खोल्ने हो?"</string> + <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"यस USB उपकरणसँग स्थापित अनुप्रयोग काम गर्दैन। यस उपकरणको बारेमा <xliff:g id="URL">%1$s</xliff:g> मा धेरै जान्नुहोस्"</string> + <string name="title_usb_accessory" msgid="4966265263465181372">"USB सहयोगी"</string> + <string name="label_view" msgid="6304565553218192990">"दृश्य"</string> + <string name="always_use_device" msgid="1450287437017315906">"यो USB उपकरणको लागि पूर्वनिर्धारितबाट प्रयोग गर्नुहोस्"</string> + <string name="always_use_accessory" msgid="1210954576979621596">"यस USB सहायक सामानको लागि पूर्वनिर्धारितद्वारा प्रयोग गर्नुहोस्"</string> + <string name="usb_debugging_title" msgid="4513918393387141949">"USB डिबग गर्नको लागि अनुमति दिने हो?"</string> + <string name="usb_debugging_message" msgid="2220143855912376496">"कम्प्युटरको RSA कुञ्जी औंलाछाप:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string> + <string name="usb_debugging_always" msgid="303335496705863070">"यो कम्प्युटरबाट सधैँ अनुमति दिनुहोस्"</string> + <string name="compat_mode_on" msgid="6623839244840638213">"स्क्रिन भर्न जुम गर्नुहोस्"</string> + <string name="compat_mode_off" msgid="4434467572461327898">"स्क्रिन भर्न तन्काउनुहोस्"</string> + <string name="compat_mode_help_header" msgid="7969493989397529910">"अनुकूलता जुम"</string> + <string name="compat_mode_help_body" msgid="4946726776359270040">"जब कुनै अनुप्रयोग सानो स्क्रिनको लागि बनाइएको हुन्छ, तब जुम नियन्त्रण घडीको नजिक देखिन्छ।"</string> + <string name="screenshot_saving_ticker" msgid="7403652894056693515">"स्क्रिनसट बचत गर्दै…"</string> + <string name="screenshot_saving_title" msgid="8242282144535555697">"स्क्रिनसट बचत गर्दै…"</string> + <string name="screenshot_saving_text" msgid="2419718443411738818">"स्क्रिनसट बचत हुँदै छ।"</string> + <string name="screenshot_saved_title" msgid="6461865960961414961">"स्क्रिनसट क्याप्चर गरियो।"</string> + <string name="screenshot_saved_text" msgid="1152839647677558815">"तपाईँको स्क्रिनसट हेर्न छुनुहोस्।"</string> + <string name="screenshot_failed_title" msgid="705781116746922771">"स्क्रिनसट क्याप्चर गर्न सकिएन।"</string> + <string name="screenshot_failed_text" msgid="8134011269572415402">"स्क्रिनसटलाई बचत गर्न सकेन। भण्डारण उपयोगमा हुन सक्छ।"</string> + <string name="usb_preference_title" msgid="6551050377388882787">"USB फाइल सार्ने विकल्पहरू"</string> + <string name="use_mtp_button_title" msgid="4333504413563023626">"मिडिया प्लेयर(MTP)को रूपमा माउन्ट गर्नुहोस्"</string> + <string name="use_ptp_button_title" msgid="7517127540301625751">"क्यामेराको रूपमा माउन्ट गर्नुहोस् (PTP)"</string> + <string name="installer_cd_button_title" msgid="2312667578562201583">"म्याकको लागि एन्ड्रोइड फाइल ट्रान्सफर अनुप्रयोग स्थापना गर्नुहोस्"</string> + <string name="accessibility_back" msgid="567011538994429120">"पछाडि"</string> + <string name="accessibility_home" msgid="8217216074895377641">"गृह"</string> + <string name="accessibility_menu" msgid="316839303324695949">"मेनु"</string> + <string name="accessibility_recent" msgid="8571350598987952883">"भर्खरका अनुप्रयोगहरू"</string> + <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"इनपुट विधि बटन स्विच गर्नुहोस्।"</string> + <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"मिलाउने जुम बटन।"</string> + <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"स्क्रिनलाई सानोबाट ठूलो पार्नुहोस्।"</string> + <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ब्लुटुथ जडान भयो।"</string> + <string name="accessibility_bluetooth_disconnected" msgid="7416648669976870175">"ब्लुटुथसँग विच्छेद गरियो।"</string> + <string name="accessibility_no_battery" msgid="358343022352820946">"कुनै ब्याट्रि छैन।"</string> + <string name="accessibility_battery_one_bar" msgid="7774887721891057523">"ब्याट्रि एउटा पट्टि।"</string> + <string name="accessibility_battery_two_bars" msgid="8500650438735009973">"ब्याट्रिका दुईवटा पट्टिहरू"</string> + <string name="accessibility_battery_three_bars" msgid="2302983330865040446">"ब्याट्रिका तिनवटा पट्टिहरू"</string> + <string name="accessibility_battery_full" msgid="8909122401720158582">"ब्याट्रि पूर्ण छ।"</string> + <string name="accessibility_no_phone" msgid="4894708937052611281">"फोन छैन्।"</string> + <string name="accessibility_phone_one_bar" msgid="687699278132664115">"फोन एउटा पट्टि।"</string> + <string name="accessibility_phone_two_bars" msgid="8384905382804815201">"फोन दुई पट्टि।"</string> + <string name="accessibility_phone_three_bars" msgid="8521904843919971885">"फोन तिन पट्टिहरू।"</string> + <string name="accessibility_phone_signal_full" msgid="6471834868580757898">"फोन सङ्केत भरिएको।"</string> + <string name="accessibility_no_data" msgid="4791966295096867555">"डेटा छैन।"</string> + <string name="accessibility_data_one_bar" msgid="1415625833238273628">"डेटाको एउटा पट्टि।"</string> + <string name="accessibility_data_two_bars" msgid="6166018492360432091">"डेटा दुई बाधाहरू।"</string> + <string name="accessibility_data_three_bars" msgid="9167670452395038520">"डेटा तिन बाधाहरू।"</string> + <string name="accessibility_data_signal_full" msgid="2708384608124519369">"डेटा संकेत पूर्ण।"</string> + <string name="accessibility_wifi_off" msgid="3177380296697933627">"वाइफाइ बन्द।"</string> + <string name="accessibility_no_wifi" msgid="1425476551827924474">"वाइफाइ विच्छेद भयो।"</string> + <string name="accessibility_wifi_one_bar" msgid="7735893178010724377">"वाइफाइ एक पट्टि।"</string> + <string name="accessibility_wifi_two_bars" msgid="4994274250497262434">"वाइफाइ दुई पट्टि।"</string> + <string name="accessibility_wifi_three_bars" msgid="3495755044276588384">"वाइफाइ तिन बारहरू।"</string> + <string name="accessibility_wifi_signal_full" msgid="6853561303586480376">"वाइफाइ सङ्केत भरिएको।"</string> + <string name="accessibility_no_wimax" msgid="4329180129727630368">"वाइम्यास छैन।"</string> + <string name="accessibility_wimax_one_bar" msgid="4170994299011863648">"WiMAX एउटा पट्टि।"</string> + <string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"वाइम्याक्स दुईवटा बारहरू।"</string> + <string name="accessibility_wimax_three_bars" msgid="6116551636752103927">"वाइम्याक्स तिनवटा बारहरू।"</string> + <string name="accessibility_wimax_signal_full" msgid="2768089986795579558">"वाइम्याक्स सङ्केत भरिएका।"</string> + <string name="accessibility_no_signal" msgid="7064645320782585167">"सङ्केत छैन।"</string> + <string name="accessibility_not_connected" msgid="6395326276213402883">"जडान नगरिएको।"</string> + <string name="accessibility_zero_bars" msgid="3806060224467027887">"शून्य पट्टि।"</string> + <string name="accessibility_one_bar" msgid="1685730113192081895">"एउटा बार।"</string> + <string name="accessibility_two_bars" msgid="6437363648385206679">"दुई पट्टिहरू।"</string> + <string name="accessibility_three_bars" msgid="2648241415119396648">"तिनवटा पट्टिहरू"</string> + <string name="accessibility_signal_full" msgid="9122922886519676839">"सङ्केत पूर्ण छ।"</string> + <string name="accessibility_desc_on" msgid="2385254693624345265">"चालु।"</string> + <string name="accessibility_desc_off" msgid="6475508157786853157">"बन्द गर्नुहोस्।"</string> + <string name="accessibility_desc_connected" msgid="8366256693719499665">"जडान गरिएको।"</string> + <string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string> + <string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string> + <string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string> + <string name="accessibility_data_connection_3g" msgid="8628562305003568260">"3G"</string> + <string name="accessibility_data_connection_3.5g" msgid="8664845609981692001">"3.5G"</string> + <string name="accessibility_data_connection_4g" msgid="7741000750630089612">"4G"</string> + <string name="accessibility_data_connection_lte" msgid="5413468808637540658">"LTE"</string> + <string name="accessibility_data_connection_cdma" msgid="6132648193978823023">"CDMA"</string> + <string name="accessibility_data_connection_roaming" msgid="5977362333466556094">"रोमिङ"</string> + <string name="accessibility_data_connection_edge" msgid="4477457051631979278">"Edge"</string> + <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"वाइ-फाइ"</string> + <string name="accessibility_no_sim" msgid="8274017118472455155">"SIM छैन।"</string> + <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"ब्लुटुथ टिथर गर्दै।"</string> + <string name="accessibility_airplane_mode" msgid="834748999790763092">"हवाइजहाज मोड।"</string> + <string name="accessibility_battery_level" msgid="7451474187113371965">"ब्याट्रि <xliff:g id="NUMBER">%d</xliff:g> प्रतिशत"</string> + <string name="accessibility_settings_button" msgid="799583911231893380">"प्रणाली सेटिङहरू"</string> + <string name="accessibility_notifications_button" msgid="4498000369779421892">"सूचनाहरू।"</string> + <string name="accessibility_remove_notification" msgid="3603099514902182350">"सूचना खाली गर्नुहोस्।"</string> + <string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS सक्षम गरिएको"</string> + <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"GPS प्राप्त हुँदैछ।"</string> + <string name="accessibility_tty_enabled" msgid="4613200365379426561">"टेलि टाइपराइटर सक्षम गरियो।"</string> + <string name="accessibility_ringer_vibrate" msgid="666585363364155055">"बज्ने कम्पन हुन्छ।"</string> + <string name="accessibility_ringer_silent" msgid="9061243307939135383">"घन्टी मौन।"</string> + <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> खारेज गरिएको छ।"</string> + <string name="accessibility_notification_dismissed" msgid="854211387186306927">"सूचना खारेज।"</string> + <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"सूचना कक्ष।"</string> + <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"द्रुत सेटिङहरू"</string> + <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"वर्तमान अनुप्रयोगहरू"</string> + <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"प्रयोगकर्ता <xliff:g id="USER">%s</xliff:g>।"</string> + <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>। <xliff:g id="NETWORK">%2$s</xliff:g>"</string> + <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"मोवाइल <xliff:g id="SIGNAL">%1$s</xliff:g>। <xliff:g id="TYPE">%2$s</xliff:g>। <xliff:g id="NETWORK">%3$s</xliff:g>।"</string> + <string name="accessibility_quick_settings_battery" msgid="1480931583381408972">"ब्याट्रि <xliff:g id="STATE">%s</xliff:g>।"</string> + <string name="accessibility_quick_settings_airplane" msgid="4196876722090224753">"हवाजहाज मोड <xliff:g id="STATE">%s</xliff:g>।"</string> + <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"ब्लुटुथ <xliff:g id="STATE">%s</xliff:g>।"</string> + <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"<xliff:g id="TIME">%s</xliff:g>को लागि सङ्केत घन्टी सेट गरिएको"</string> + <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G-3G डेटा अक्षम गरियो"</string> + <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G डेटा असक्षम गरियो"</string> + <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"मोबाइल डेटा अक्षम गरियो"</string> + <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"डेटा अक्षम गरियो"</string> + <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"तपाईँ निर्दिष्ट डेटा उपयोग सीमामा पुग्नु भएको छ।\n\nयदि तपाईँले डेटालाई पुनःसक्षम पार्नु भयो भने तपाईँलाई अर्को संचालकबाट शुल्क लगाउन सक्छ।"</string> + <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"डेटा पुनः सक्षम गर्नुहोस्"</string> + <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"इन्टरनेट जडान छैन"</string> + <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"वाइ-फाइ जडित"</string> + <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPSको लागि खोजी गर्दै"</string> + <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS द्वारा स्थान सेट गरिएको"</string> + <string name="accessibility_location_active" msgid="2427290146138169014">"स्थान अनुरोधहरू सक्रिय"</string> + <string name="accessibility_clear_all" msgid="5235938559247164925">"सबै सूचनाहरू हटाउनुहोस्।"</string> + <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"अनुप्रयोगको जानकारी"</string> + <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"स्क्रिन स्वतः घुम्ने छ।"</string> + <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"स्क्रिनलाई ल्यान्डस्केप अवस्थामा बन्द गरिएको छ।"</string> + <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"स्क्रिन पोर्टेट अभिमूखमा लक गरिएको छ।"</string> + <string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string> + <string name="start_dreams" msgid="7219575858348719790">"दिवासपना"</string> + <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string> + <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"उडान मोड"</string> + <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"चार्ज हुँदै, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string> + <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"चार्ज भयो"</string> + <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ब्लुटुथ"</string> + <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ब्लुटुथ (<xliff:g id="NUMBER">%d</xliff:g> उपकरणहरू)"</string> + <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"ब्लुटुथ बन्द"</string> + <string name="quick_settings_brightness_label" msgid="6968372297018755815">"चमक"</string> + <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"स्वतः घुमाइ"</string> + <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"घुम्ने लक गरेको"</string> + <string name="quick_settings_ime_label" msgid="7073463064369468429">"आगत विधि"</string> + <string name="quick_settings_location_label" msgid="5011327048748762257">"स्थान"</string> + <string name="quick_settings_location_off_label" msgid="7464544086507331459">"स्थान बन्द छ"</string> + <string name="quick_settings_media_device_label" msgid="1302906836372603762">"मिडिया उपकरण"</string> + <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string> + <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"आकस्मिक कल मात्र"</string> + <string name="quick_settings_settings_label" msgid="5326556592578065401">"सेटिङहरू"</string> + <string name="quick_settings_time_label" msgid="4635969182239736408">"समय"</string> + <string name="quick_settings_user_label" msgid="5238995632130897840">"मलाई"</string> + <string name="quick_settings_wifi_label" msgid="9135344704899546041">"वाइ-फाइ"</string> + <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"जोडिएको छैन"</string> + <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"नेटवर्क छैन"</string> + <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"वाइ-फाइ बन्द"</string> + <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"वाइ-फाइ प्रदर्शन"</string> + <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"ताररहित प्रदर्शन"</string> + <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"उज्यालपन"</string> + <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"स्वतः"</string> + <string name="status_bar_help_title" msgid="1199237744086469217">"यहाँ जानकारीहरू देखा पर्छन्"</string> + <string name="status_bar_help_text" msgid="7874607155052076323">"तल हुत्त्याएर तिनीहरूलाई सधैं पहुँच गर्नुहोस्\nप्रणाली नियन्त्रणको लागि पुनः तल हुत्त्याउनुहोस्"</string> +</resources> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 02a5b45..5b6ebab 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -201,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATISCH"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Meldingen worden hier weergegeven"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"U kunt de meldingen op elk gewenst moment openen door met uw vinger omlaag te vegen.\nVeeg nogmaals met uw vinger omlaag om de systeembesturingselementen weer te geven."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Veeg vanaf de rand om balk weer te geven"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Veeg vanaf de rand van het scherm om de systeembalk weer te geven"</string> </resources> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index d17c45e..6bff7af 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -164,8 +164,7 @@ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: połączono"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"Wyszukiwanie sygnału GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokalizacja z GPSa"</string> - <!-- no translation found for accessibility_location_active (2427290146138169014) --> - <skip /> + <string name="accessibility_location_active" msgid="2427290146138169014">"Prośby o lokalizację są aktywne"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Usuń wszystkie powiadomienia."</string> <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"O aplikacji"</string> <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran zostanie obrócony automatycznie."</string> @@ -202,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATYCZNA"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Tutaj pokazują się powiadomienia"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Możesz je otworzyć w dowolnej chwili, przesuwając w dół.\nPrzesuń jeszcze raz w dół, by otworzyć ustawienia systemowe."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Przesuń palcem od krawędzi ekranu, by odkryć pasek"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Przesuń palcem od krawędzi ekranu, by odkryć pasek systemu"</string> </resources> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index b520319..6aa94e0 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -164,8 +164,7 @@ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ligado"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"A procurar GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Localização definida por GPS"</string> - <!-- no translation found for accessibility_location_active (2427290146138169014) --> - <skip /> + <string name="accessibility_location_active" msgid="2427290146138169014">"Pedidos de localização ativos"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Limpar todas as notificações."</string> <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informações da aplicação"</string> <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"O ecrã será rodado automaticamente."</string> @@ -202,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMÁTICO"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"As notificações são apresentadas aqui"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Pode aceder em qualquer altura, deslizando rapidamente para baixo com o dedo.\nDeslize novamente para baixo para aceder aos controlos do sistema."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Deslize da extremidade do ecrã para revelar a barra"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Deslize da extremidade do ecrã para revelar a barra do sistema"</string> </resources> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index 2a2f336..aa972fb 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -166,8 +166,7 @@ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"Buscando GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Local definido por GPS"</string> - <!-- no translation found for accessibility_location_active (2427290146138169014) --> - <skip /> + <string name="accessibility_location_active" msgid="2427290146138169014">"Solicitações de localização ativas"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Limpar todas as notificações."</string> <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informações do aplicativo"</string> <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"A tela girará automaticamente."</string> @@ -204,6 +203,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"As notificações aparecem aqui"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Acesse a qualquer momento deslizando para baixo.\nDeslize para baixo novamente para acessar os controles do sistema."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Deslize a borda da tela para ver a barra"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Deslize a partir da borda da tela ver a barra do sistema"</string> </resources> diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml index 22a857e..05b7453 100644 --- a/packages/SystemUI/res/values-rm/strings.xml +++ b/packages/SystemUI/res/values-rm/strings.xml @@ -372,8 +372,4 @@ <skip /> <!-- no translation found for status_bar_help_text (7874607155052076323) --> <skip /> - <!-- no translation found for hiding_navigation_confirmation_message (3227814171674734332) --> - <skip /> - <!-- no translation found for hiding_navigation_confirmation_message_long (7854368870786524950) --> - <skip /> </resources> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index 375d12c..9c5ad00 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -164,8 +164,7 @@ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectat"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"Se caută GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Locaţie setată prin GPS"</string> - <!-- no translation found for accessibility_location_active (2427290146138169014) --> - <skip /> + <string name="accessibility_location_active" msgid="2427290146138169014">"Solicitări locație active"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Ștergeţi toate notificările."</string> <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informaţii despre aplicaţie"</string> <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ecranul se va roti în mod automat."</string> @@ -202,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMAT"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Notificările se afişează aici"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Accesaţi-le oricând glisând în jos.\nGlisaţi în jos din nou pentru comenzile sistemului."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Glisați dinspre marginea ecranului pentru a afișa bara"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Glisați dinspre marginea ecranului pentru a afișa bara de sistem"</string> </resources> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 15adf90..3020624 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -166,8 +166,7 @@ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi подключено"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"Поиск GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Координаты по GPS"</string> - <!-- no translation found for accessibility_location_active (2427290146138169014) --> - <skip /> + <string name="accessibility_location_active" msgid="2427290146138169014">"Есть активные запросы на определение местоположения"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Удалить все уведомления"</string> <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"О приложении"</string> <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Экран будет поворачиваться автоматически."</string> @@ -206,6 +205,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТОНАСТРОЙКА"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Это панель уведомлений"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Ее можно открыть, пролистнув экран вниз.\nЧтобы открыть настройки, проведите пальцем вниз ещё раз."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Чтобы открыть панель, проведите пальцем от края к центру экрана"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Чтобы открыть панель навигации, проведите пальцем от края к центру экрана"</string> </resources> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml new file mode 100644 index 0000000..f28cd16 --- /dev/null +++ b/packages/SystemUI/res/values-si/strings.xml @@ -0,0 +1,204 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, 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 xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_label" msgid="7164937344850004466">"පද්ධති UI"</string> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"හිස් කරන්න"</string> + <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"ලැයිස්තුවෙන් ඉවත් කරන්න"</string> + <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"යෙදුම් තොරතුරු"</string> + <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"මෑත උපාංග නැත"</string> + <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"මෑත යෙදුම් ඉවතලන්න"</string> + <plurals name="status_bar_accessibility_recent_apps"> + <item quantity="one" msgid="5854176083865845541">"මෑත යෙදුම් 1 ක්"</item> + <item quantity="other" msgid="1040784359794890744">"මෑත යෙදුම් %d ක්"</item> + </plurals> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"දැනුම්දීම් නැත"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"දැනට පවතින"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"දැනුම්දීම්"</string> + <string name="battery_low_title" msgid="2783104807551211639">"අරෝපකයට සම්බන්ධ කරන්න"</string> + <string name="battery_low_subtitle" msgid="1752040062087829196">"බැටරිය අඩු වෙමින් පවතී."</string> + <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> ක් ඉතිරියි"</string> + <string name="invalid_charger" msgid="4549105996740522523">"USB ආරෝපණය සහය නොදක්වයි.\nසපයන ලද ආරෝපකය පමණක් භාවිතා කරන්න."</string> + <string name="battery_low_why" msgid="7279169609518386372">"බැටරි භාවිතය"</string> + <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"සැකසීම්"</string> + <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string> + <string name="status_bar_settings_airplane" msgid="4879879698500955300">"අහස්යානා ආකාරය"</string> + <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"ස්වයංක්රීයව-භ්රමණය වන තිරය"</string> + <string name="status_bar_settings_mute_label" msgid="554682549917429396">"නිශ්ශබ්ද කරන්න"</string> + <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"ස්වයංක්රීය"</string> + <string name="status_bar_settings_notifications" msgid="397146176280905137">"දැනුම්දීම්"</string> + <string name="bluetooth_tethered" msgid="7094101612161133267">"බ්ලූටූත් ටෙදර් කරා"</string> + <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"ආදාන ක්රම සකසන්න"</string> + <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"භෞතික යතුරු පුවරුව"</string> + <string name="usb_device_permission_prompt" msgid="834698001271562057">"USB උපාංගය ප්රවේශ කිරීමට <xliff:g id="APPLICATION">%1$s</xliff:g> යෙදුමට අවසර දෙනවාද?"</string> + <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"USB මෙවලම ප්රවේශ කිරීමට <xliff:g id="APPLICATION">%1$s</xliff:g> යෙදුමට අවසර දෙනවාද?"</string> + <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"මෙම USB උපාංගය සම්බන්ධ විට <xliff:g id="ACTIVITY">%1$s</xliff:g> විවෘත කරන්නද?"</string> + <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"මෙම USB මෙවලමට සම්බන්ධ වී ඇති විට <xliff:g id="ACTIVITY">%1$s</xliff:g> විවෘත කරන්නද?"</string> + <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"මෙම USB මෙවලම සමග ක්රියා කරන ස්ථාපිත යෙදුම් නොමැත. <xliff:g id="URL">%1$s</xliff:g> වලින් මෙම මෙවලම ගැන තව දැනගන්න"</string> + <string name="title_usb_accessory" msgid="4966265263465181372">"USB මෙවලම"</string> + <string name="label_view" msgid="6304565553218192990">"පෙනුම"</string> + <string name="always_use_device" msgid="1450287437017315906">"මෙම USB උපාංගය සඳහා සුපුරුද්දෙන් භාවිතා කරන්න"</string> + <string name="always_use_accessory" msgid="1210954576979621596">"මේ USB මෙවලම සඳහා සුපුරුද්දෙන් භාවිතා කරන්න."</string> + <string name="usb_debugging_title" msgid="4513918393387141949">"USB නිදොස්කරණයට අවසර දෙනවද?"</string> + <string name="usb_debugging_message" msgid="2220143855912376496">"මෙම පරිගණකයේ RSA යතුරු ඇඟිලි සටහන වන්නේ:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string> + <string name="usb_debugging_always" msgid="303335496705863070">"සැම විටම මෙම පරිගණකයෙන් ඉඩ ලබා දෙන්න"</string> + <string name="compat_mode_on" msgid="6623839244840638213">"තිරය පිරවීමට විශාලනය කරන්න"</string> + <string name="compat_mode_off" msgid="4434467572461327898">"තිරය පිරවීමට අදින්න"</string> + <string name="compat_mode_help_header" msgid="7969493989397529910">"ගැළපෙන විශාලනය"</string> + <string name="compat_mode_help_body" msgid="4946726776359270040">"කුඩා තිරයක් සඳහා යෙදුමක් නිර්මාණය කළ විට, විශාලනය පාලකය ඔරලෝසුව ළඟින් පෙන්වයි."</string> + <string name="screenshot_saving_ticker" msgid="7403652894056693515">"තිර රුව සුරකිමින්…"</string> + <string name="screenshot_saving_title" msgid="8242282144535555697">"තිර රුව සුරැකෙමින් පවතී…"</string> + <string name="screenshot_saving_text" msgid="2419718443411738818">"තිර රුව සුරැකෙමින් පවතී."</string> + <string name="screenshot_saved_title" msgid="6461865960961414961">"තිර රුව ග්රහණය කරන ලදි."</string> + <string name="screenshot_saved_text" msgid="1152839647677558815">"ඔබගේ තිර රුව බැලීමට ස්පර්ශ කරන්න."</string> + <string name="screenshot_failed_title" msgid="705781116746922771">"තිර රුව ග්රහණය කිරීමට නොහැකි විය."</string> + <string name="screenshot_failed_text" msgid="8134011269572415402">"තිර රුව සුරැකීමට නොහැකි විය. ආචයනය භාවිතාවේ තිබෙනවා විය හැක."</string> + <string name="usb_preference_title" msgid="6551050377388882787">"USB ගොනු හුවමාරු විකල්ප"</string> + <string name="use_mtp_button_title" msgid="4333504413563023626">"මධ්ය ධාවකයක් (MTP) ලෙස සවි කරන්න"</string> + <string name="use_ptp_button_title" msgid="7517127540301625751">"කැමරාවක් (PTP) ලෙස සවි කරන්න"</string> + <string name="installer_cd_button_title" msgid="2312667578562201583">"Mac සඳහා Android ගොනු හුවමාරු යෙදුම ස්ථාපනය කරන්න"</string> + <string name="accessibility_back" msgid="567011538994429120">"ආපසු"</string> + <string name="accessibility_home" msgid="8217216074895377641">"මුල් පිටුව"</string> + <string name="accessibility_menu" msgid="316839303324695949">"මෙනුව"</string> + <string name="accessibility_recent" msgid="8571350598987952883">"මෑත යෙදුම්"</string> + <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ආදාන ක්රමය මාරු කිරීමේ බොත්තම."</string> + <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ගැළපෙන විශාලන බොත්තම."</string> + <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"විශාල තිරය වෙත කුඩාව විශාලනය කරන්න."</string> + <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"බ්ලූටූත් සම්බන්ධිතයි."</string> + <string name="accessibility_bluetooth_disconnected" msgid="7416648669976870175">"බ්ලූටූත් විසන්ධි කර ඇත."</string> + <string name="accessibility_no_battery" msgid="358343022352820946">"බැටරිය නැත."</string> + <string name="accessibility_battery_one_bar" msgid="7774887721891057523">"බැටරිය තීරු එකයි."</string> + <string name="accessibility_battery_two_bars" msgid="8500650438735009973">"බැටරිය තීරු දෙකයි."</string> + <string name="accessibility_battery_three_bars" msgid="2302983330865040446">"බැටරිය තීරු තුනයි."</string> + <string name="accessibility_battery_full" msgid="8909122401720158582">"බැටරිය පිරී ඇත."</string> + <string name="accessibility_no_phone" msgid="4894708937052611281">"දුරකථනයක් නැත."</string> + <string name="accessibility_phone_one_bar" msgid="687699278132664115">"දුරකථනය තීරු එකයි."</string> + <string name="accessibility_phone_two_bars" msgid="8384905382804815201">"දුරකථනය තීරු දෙකයි."</string> + <string name="accessibility_phone_three_bars" msgid="8521904843919971885">"දුරකථනය තීරු තුනයි."</string> + <string name="accessibility_phone_signal_full" msgid="6471834868580757898">"දුරකථනයේ සංඥාව පිරී ඇත."</string> + <string name="accessibility_no_data" msgid="4791966295096867555">"දත්ත නැත."</string> + <string name="accessibility_data_one_bar" msgid="1415625833238273628">"දත්ත තීරු එකයි."</string> + <string name="accessibility_data_two_bars" msgid="6166018492360432091">"දත්ත තීරු 2."</string> + <string name="accessibility_data_three_bars" msgid="9167670452395038520">"දත්ත තීරු 3."</string> + <string name="accessibility_data_signal_full" msgid="2708384608124519369">"දත්ත සංඥාව පිරී ඇත."</string> + <string name="accessibility_wifi_off" msgid="3177380296697933627">"Wifi අක්රියයි."</string> + <string name="accessibility_no_wifi" msgid="1425476551827924474">"Wifi සම්බන්ධ කර නොමැත."</string> + <string name="accessibility_wifi_one_bar" msgid="7735893178010724377">"Wifi තීරු එකයි."</string> + <string name="accessibility_wifi_two_bars" msgid="4994274250497262434">"Wifi තීරු දෙකයි."</string> + <string name="accessibility_wifi_three_bars" msgid="3495755044276588384">"WiFi තීරු තුනයි."</string> + <string name="accessibility_wifi_signal_full" msgid="6853561303586480376">"Wifi සංඥාව පිරී ඇත."</string> + <string name="accessibility_no_wimax" msgid="4329180129727630368">"WiMAX නැත."</string> + <string name="accessibility_wimax_one_bar" msgid="4170994299011863648">"WiMAX තීරු එකයි."</string> + <string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"WiMAX තීරු දෙකයි."</string> + <string name="accessibility_wimax_three_bars" msgid="6116551636752103927">"WiMAX තීරු තුනයි."</string> + <string name="accessibility_wimax_signal_full" msgid="2768089986795579558">"WiMAX සංඥාව පිරී ඇත."</string> + <string name="accessibility_no_signal" msgid="7064645320782585167">"සංඥා නැත."</string> + <string name="accessibility_not_connected" msgid="6395326276213402883">"සම්බන්ධ වී නැත."</string> + <string name="accessibility_zero_bars" msgid="3806060224467027887">"තීරු ශුන්යයි."</string> + <string name="accessibility_one_bar" msgid="1685730113192081895">"තීරු එක."</string> + <string name="accessibility_two_bars" msgid="6437363648385206679">"තීරු දෙකයි."</string> + <string name="accessibility_three_bars" msgid="2648241415119396648">"තීරු තුනයි."</string> + <string name="accessibility_signal_full" msgid="9122922886519676839">"සංඥාව පිරී ඇත."</string> + <string name="accessibility_desc_on" msgid="2385254693624345265">"සක්රීයයි."</string> + <string name="accessibility_desc_off" msgid="6475508157786853157">"අක්රිය කරන්න."</string> + <string name="accessibility_desc_connected" msgid="8366256693719499665">"සම්බන්ධිතයි."</string> + <string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string> + <string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string> + <string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string> + <string name="accessibility_data_connection_3g" msgid="8628562305003568260">"3G"</string> + <string name="accessibility_data_connection_3.5g" msgid="8664845609981692001">"3.5G"</string> + <string name="accessibility_data_connection_4g" msgid="7741000750630089612">"4G"</string> + <string name="accessibility_data_connection_lte" msgid="5413468808637540658">"LTE"</string> + <string name="accessibility_data_connection_cdma" msgid="6132648193978823023">"CDMA"</string> + <string name="accessibility_data_connection_roaming" msgid="5977362333466556094">"රෝමිං"</string> + <string name="accessibility_data_connection_edge" msgid="4477457051631979278">"Edge"</string> + <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Wi-Fi"</string> + <string name="accessibility_no_sim" msgid="8274017118472455155">"SIM නැත."</string> + <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"බ්ලූටූත් ටෙදරින්."</string> + <string name="accessibility_airplane_mode" msgid="834748999790763092">"අහස්යානා ආකාරය."</string> + <string name="accessibility_battery_level" msgid="7451474187113371965">"බැටරි ප්රතිශතය <xliff:g id="NUMBER">%d</xliff:g>"</string> + <string name="accessibility_settings_button" msgid="799583911231893380">"පද්ධති සැකසීම්."</string> + <string name="accessibility_notifications_button" msgid="4498000369779421892">"දැනුම්දීම්."</string> + <string name="accessibility_remove_notification" msgid="3603099514902182350">"දැනුම්දීම හිස් කරන්න."</string> + <string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS සබල කර ඇත."</string> + <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"GPS ලබා ගනිමින්."</string> + <string name="accessibility_tty_enabled" msgid="4613200365379426561">"TeleTypewriter ක්රියාත්මකයි."</string> + <string name="accessibility_ringer_vibrate" msgid="666585363364155055">"හඬ නඟනය කම්පනය වේ."</string> + <string name="accessibility_ringer_silent" msgid="9061243307939135383">"හඬ නඟනය නිශ්ශබ්දයි."</string> + <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> අස් කර ඇත."</string> + <string name="accessibility_notification_dismissed" msgid="854211387186306927">"දැනුම්දීම නිෂ්ප්රභා කරඇත."</string> + <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"දැනුම්දීම් ආවරණය."</string> + <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"ක්ෂණික සැකසීම්."</string> + <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"මෑත කාලීන යෙදුම්."</string> + <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"පරිශීලකයා <xliff:g id="USER">%s</xliff:g>."</string> + <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string> + <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"ජංගම <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string> + <string name="accessibility_quick_settings_battery" msgid="1480931583381408972">"බැටරිය <xliff:g id="STATE">%s</xliff:g>."</string> + <string name="accessibility_quick_settings_airplane" msgid="4196876722090224753">"අහස්යානා ආකාරය <xliff:g id="STATE">%s</xliff:g>."</string> + <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"බ්ලූටූත් <xliff:g id="STATE">%s</xliff:g>."</string> + <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"<xliff:g id="TIME">%s</xliff:g> සඳහා සීනුව සකස් කර ඇත."</string> + <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G-3G දත්ත අබල කර ඇත"</string> + <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G දත්ත අබල කරන ලදි"</string> + <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"ජංගම දත්ත අබල කර ඇත"</string> + <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"දත්ත අබල කර ඇත"</string> + <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"ඔබ නියමිත දත්ත භාවිත සීමාවට ළඟා වී ඇත.\n\nඔබ දත්ත නැවත සබල කළහොත් වාහකයා ඔබගෙන් ඇතැම් විට අය කරගත හැක."</string> + <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"නැවත දත්ත සබල කරන්න"</string> + <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"අන්තර්ජාල සම්බන්ධතාවයක් නැත"</string> + <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi සම්බන්ධිතයි"</string> + <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS සඳහා සොයමින්"</string> + <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS මඟින් ස්ථානය සකසා ඇත"</string> + <string name="accessibility_location_active" msgid="2427290146138169014">"පිහිටීම් ඉල්ලීම් සක්රියයි"</string> + <string name="accessibility_clear_all" msgid="5235938559247164925">"සියලු දැනුම්දීම් හිස් කරන්න."</string> + <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"යෙදුම් තොරතුරු"</string> + <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"තිරය ස්වයංක්රීයව කරකැවේ."</string> + <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"තිරය තිරස් දිශානතියෙහි අගුළු දමා ඇත."</string> + <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"තිරය සිරස් දිශානතිය තුළ අගුළු වැටී ඇත."</string> + <string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string> + <string name="start_dreams" msgid="7219575858348719790">"දවල් හීනය"</string> + <string name="ethernet_label" msgid="7967563676324087464">"ඊතර නෙට්"</string> + <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"අහස්යානා ආකාරය"</string> + <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"ආරෝපණය වෙමින්, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string> + <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"අරෝපිතයි"</string> + <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"බ්ලූටූත්"</string> + <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"බ්ලූටූත් (උපාංග <xliff:g id="NUMBER">%d</xliff:g>)"</string> + <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"බ්ලූටූත් අක්රියයි"</string> + <string name="quick_settings_brightness_label" msgid="6968372297018755815">"දීප්තිය"</string> + <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"ස්වයංක්රීය කරකැවීම"</string> + <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"භ්රමණය අගුළු දමා ඇත"</string> + <string name="quick_settings_ime_label" msgid="7073463064369468429">"ආදාන ක්රමය"</string> + <string name="quick_settings_location_label" msgid="5011327048748762257">"ස්ථානය"</string> + <string name="quick_settings_location_off_label" msgid="7464544086507331459">"ස්ථානය අක්රියයි"</string> + <string name="quick_settings_media_device_label" msgid="1302906836372603762">"මාධ්ය උපාංගය"</string> + <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string> + <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"හදිසි ඇමතුම් පමණි"</string> + <string name="quick_settings_settings_label" msgid="5326556592578065401">"සැකසීම්"</string> + <string name="quick_settings_time_label" msgid="4635969182239736408">"වේලාව"</string> + <string name="quick_settings_user_label" msgid="5238995632130897840">"මම"</string> + <string name="quick_settings_wifi_label" msgid="9135344704899546041">"Wi-Fi"</string> + <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"සම්බන්ධ වී නොමැත"</string> + <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"ජාලයක් නැත"</string> + <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi අක්රියයි"</string> + <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi සංදර්ශකය"</string> + <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"නොරැහැන් සංදර්ශකය"</string> + <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"දීප්තිමත් බව"</string> + <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ස්වයංක්රීය"</string> + <string name="status_bar_help_title" msgid="1199237744086469217">"දැනුම්දීම් මෙතන පෙන්නුම් කරයි"</string> + <string name="status_bar_help_text" msgid="7874607155052076323">"පහලට සර්පණය කිරීමෙන් ඕනෑම වෙලාවක ඒවා වෙත පිවිසෙන්න.\nපද්ධති පාලක සඳහා නැවත පහළට සර්පණය කරන්න."</string> +</resources> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index bb70f36..59af9ab 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -166,8 +166,7 @@ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: pripojené"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"Vyhľadávanie satelitov GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Poloha nastavená pomocou GPS"</string> - <!-- no translation found for accessibility_location_active (2427290146138169014) --> - <skip /> + <string name="accessibility_location_active" msgid="2427290146138169014">"Žiadosti o polohu sú aktívne"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Vymazať všetky upozornenia."</string> <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Informácie o aplikácii"</string> <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Obrazovka sa automaticky otočí."</string> @@ -204,6 +203,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATICKY"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Tu sa zobrazujú upozornenia"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Môžete ich kedykoľvek zobraziť tak, že posuniete prstom nadol.\nAk posuniete prstom nadol ešte raz, zobrazia sa ovládacie prvky systému."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Panel zobrazíte posunutím cez okraj obrazovky"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Systémový panel zobrazíte posunutím cez okraj obrazovky"</string> </resources> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 46a5826..338ff44 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -164,8 +164,7 @@ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi povezan"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"Iskanje GPS-a"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokacija nastavljena z GPS-om"</string> - <!-- no translation found for accessibility_location_active (2427290146138169014) --> - <skip /> + <string name="accessibility_location_active" msgid="2427290146138169014">"Aktivne zahteve za lokacijo"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Izbriši vsa obvestila."</string> <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Podatki o aplikaciji"</string> <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Zaslon se bo samodejno zasukal."</string> @@ -202,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"SAMODEJNO"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Obvestila so prikazana tukaj"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Do njih lahko kadar koli dostopate tako, da povlečete navzdol.\nZa prikaz sistemskih kontrolnikov znova povlecite navzdol."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Vrstico prikažete tako, da povlečete z roba zaslona"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Sistemsko vrstico prikažete tako, da povlečete z roba zaslona"</string> </resources> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 163bc06..b501d69 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -201,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АУТОМАТСКА"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Обавештења се појављују овде"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Приступите им у било ком тренутку листањем надоле.\nПоново листајте надоле да би се приказале системске контроле."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Превуците по ивици екрана да би се приказала трака"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Превуците од ивице екрана да би се приказала системска трака"</string> </resources> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index c5335f4..560a00e 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -164,8 +164,7 @@ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi-ansluten"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"Sökning efter GPS pågår"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Platsen har identifierats av GPS"</string> - <!-- no translation found for accessibility_location_active (2427290146138169014) --> - <skip /> + <string name="accessibility_location_active" msgid="2427290146138169014">"Det finns aktiva platsbegäranden"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Ta bort alla meddelanden."</string> <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Info om appen"</string> <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skärmen roteras automatiskt."</string> @@ -202,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Meddelanden visas här"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Du kommer åt dem när som helst genom att dra nedåt.\nDra nedåt igen om du vill visa systemkontroller."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Dra från kanten av skärmen om du vill visa fältet"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Dra från kanten av skärmen om du vill visa systemfältet"</string> </resources> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index a0fb0a8..e3338de 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -199,6 +199,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"KIOTOMATIKI"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Arifa zitaonekana hapa"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Zifikie wakati wowote kwa kutelezesha chini.\nTelezesha chini tena kupata vidhibiti vya mfumo."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Telezesha kidole kutoka ukingo wa skrini ili kuonyesha upau"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Telezesha kidole kutoka ukingo wa skrini ili kuonyesha upau wa mfumo"</string> </resources> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 2552e5c..3127eb3 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -201,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"อัตโนมัติ"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"การแจ้งเตือนจะแสดงขึ้นที่นี่"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"เข้าถึงได้ทุกเมื่อด้วยการกวาดนิ้วลง\nกวาดนิ้วลงอีกครั้งสำหรับการควบคุมระบบ"</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"กวาดขอบของหน้าจอเพื่อแสดงแถบ"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"กวาดจากขอบของหน้าจอเพื่อแสดงแถบระบบ"</string> </resources> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index dfc6c7d..9d4d9de 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -201,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Dito lumalabas ang mga notification"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"I-access ang mga ito anumang oras sa pamamagitan ng pag-swipe pababa.\nMuling mag-swipe pababa para sa mga kontrol ng system."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Mag-swipe sa gilid ng screen upang ipakita ang bar"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Mag-swipe mula sa gilid ng screen upang ipakita ang system bar"</string> </resources> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index f7b34de..b885344 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -164,8 +164,7 @@ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Kablosuz bağlandı"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS aranıyor"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Konum GPS ile belirlendi"</string> - <!-- no translation found for accessibility_location_active (2427290146138169014) --> - <skip /> + <string name="accessibility_location_active" msgid="2427290146138169014">"Konum bilgisi istekleri etkin"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Tüm bildirimleri temizle"</string> <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Uygulama bilgileri"</string> <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran otomatik olarak dönecektir."</string> @@ -202,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OTOMATİK"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Bildirimler burada görünür"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Aşağıya hızlıca kaydırarak bunlara istediğiniz zaman erişebilirsiniz.\nSistem denetimleri için tekrar hızlıca aşağı kaydırın."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Çubuğu görüntülemek için ekranın kenarından hızlıca kaydırın"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Sistem çubuğunu görüntülemek için ekranın kenarından hızlıca kaydırın"</string> </resources> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 23e276b..1f3c131 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -164,8 +164,7 @@ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi під’єднано"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"Виконується пошук GPS-сигналу"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Місцезнаходження встановлено за допомогою GPS"</string> - <!-- no translation found for accessibility_location_active (2427290146138169014) --> - <skip /> + <string name="accessibility_location_active" msgid="2427290146138169014">"Запити про місцезнаходження активні"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Очистити всі сповіщення."</string> <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Інформація про програму"</string> <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Екран обертатиметься автоматично."</string> @@ -202,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТО"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Сповіщення з’являються тут"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Отримуйте до них доступ будь-коли, провівши пальцем униз.\nЗнову проведіть униз, щоб відкрити елементи керування системи."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Гортайте від краю екрана, щоб з’явилась панель"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Проведіть пальцем від краю екрана, щоб з’явилась навігаційна панель"</string> </resources> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 31fc2c8..1bea172 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -164,8 +164,7 @@ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Đã kết nối Wi-Fi"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"Đang tìm kiếm GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"Vị trí đặt bởi GPS"</string> - <!-- no translation found for accessibility_location_active (2427290146138169014) --> - <skip /> + <string name="accessibility_location_active" msgid="2427290146138169014">"Yêu cầu về thông tin vị trí đang hoạt động"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"Xóa tất cả thông báo."</string> <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"Thông tin về ứng dụng"</string> <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Màn hình sẽ xoay tự động."</string> @@ -202,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"TỰ ĐỘNG"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Thông báo xuất hiện tại đây"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Truy cập vào chúng bất kỳ lúc nào bằng cách vuốt xuống.\nVuốt lại xuống để hiển thị các điều khiển hệ thống."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Vuốt cạnh màn hình để hiển thị thanh"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Vuốt từ cạnh màn hình để hiển thị thanh hệ thống"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index b8b56c9..867cb17 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -166,8 +166,7 @@ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WLAN 已连接"</string> <string name="gps_notification_searching_text" msgid="8574247005642736060">"正在搜索 GPS"</string> <string name="gps_notification_found_text" msgid="4619274244146446464">"已通过 GPS 确定位置"</string> - <!-- no translation found for accessibility_location_active (2427290146138169014) --> - <skip /> + <string name="accessibility_location_active" msgid="2427290146138169014">"应用发出了有效位置信息请求"</string> <string name="accessibility_clear_all" msgid="5235938559247164925">"清除所有通知。"</string> <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"应用信息"</string> <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"屏幕会自动旋转。"</string> @@ -204,6 +203,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自动"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"通知会显示在这里"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"向下滑动可随时查看通知。\n再次向下滑动可使用系统控制功能。"</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"从屏幕边缘向里滑可显示系统栏"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"从屏幕边缘向里滑动即可显示系统栏"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml new file mode 100644 index 0000000..ab38c59 --- /dev/null +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -0,0 +1,206 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, 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 xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_label" msgid="7164937344850004466">"系統用戶介面"</string> + <string name="status_bar_clear_all_button" msgid="7774721344716731603">"清除"</string> + <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"從清單中移除"</string> + <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"應用程式資訊"</string> + <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"沒有最近的應用程式"</string> + <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"關閉最近使用的應用程式"</string> + <plurals name="status_bar_accessibility_recent_apps"> + <item quantity="one" msgid="5854176083865845541">"1 個最近使用的應用程式"</item> + <item quantity="other" msgid="1040784359794890744">"%d 個最近使用的應用程式"</item> + </plurals> + <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"無通知"</string> + <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"持續進行"</string> + <string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string> + <string name="battery_low_title" msgid="2783104807551211639">"連接充電器"</string> + <string name="battery_low_subtitle" msgid="1752040062087829196">"電池即將用盡。"</string> + <string name="battery_low_percent_format" msgid="1077244949318261761">"剩餘 <xliff:g id="NUMBER">%d%%</xliff:g>"</string> + <string name="invalid_charger" msgid="4549105996740522523">"不支援 USB 充電。\n僅能使用隨附的充電器。"</string> + <string name="battery_low_why" msgid="7279169609518386372">"電池使用情況"</string> + <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"設定"</string> + <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string> + <string name="status_bar_settings_airplane" msgid="4879879698500955300">"飛行模式"</string> + <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"自動旋轉螢幕"</string> + <string name="status_bar_settings_mute_label" msgid="554682549917429396">"關閉"</string> + <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"自動"</string> + <string name="status_bar_settings_notifications" msgid="397146176280905137">"通知"</string> + <string name="bluetooth_tethered" msgid="7094101612161133267">"已經由藍牙進行網絡共享"</string> + <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"設定輸入方式"</string> + <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"實體鍵盤"</string> + <string name="usb_device_permission_prompt" msgid="834698001271562057">"允許「<xliff:g id="APPLICATION">%1$s</xliff:g>」應用程式存取 USB 裝置嗎?"</string> + <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"允許「<xliff:g id="APPLICATION">%1$s</xliff:g>」應用程式存取 USB 配件嗎?"</string> + <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"連接這個 USB 裝置時啟用 <xliff:g id="ACTIVITY">%1$s</xliff:g> 嗎?"</string> + <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"連接這個 USB 配件時啟用 <xliff:g id="ACTIVITY">%1$s</xliff:g> 嗎?"</string> + <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"已安裝的應用程式均無法存取這個 USB 配件,如要進一步瞭解這個配件,請瀏覽 <xliff:g id="URL">%1$s</xliff:g>"</string> + <string name="title_usb_accessory" msgid="4966265263465181372">"USB 配件"</string> + <string name="label_view" msgid="6304565553218192990">"觀看"</string> + <string name="always_use_device" msgid="1450287437017315906">"預設用於這個 USB 裝置"</string> + <string name="always_use_accessory" msgid="1210954576979621596">"預設用於這個 USB 配件"</string> + <string name="usb_debugging_title" msgid="4513918393387141949">"允許 USB 除錯嗎?"</string> + <string name="usb_debugging_message" msgid="2220143855912376496">"這部電腦的 RSA 密鑰指紋如下:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string> + <string name="usb_debugging_always" msgid="303335496705863070">"一律允許透過這部電腦進行"</string> + <string name="compat_mode_on" msgid="6623839244840638213">"放大為全螢幕"</string> + <string name="compat_mode_off" msgid="4434467572461327898">"放大為全螢幕"</string> + <string name="compat_mode_help_header" msgid="7969493989397529910">"兼容性縮放"</string> + <string name="compat_mode_help_body" msgid="4946726776359270040">"執行專為較小螢幕設計的應用程式時,系統會在時鐘旁顯示縮放控制項。"</string> + <string name="screenshot_saving_ticker" msgid="7403652894056693515">"正在儲存屏幕擷取畫面..."</string> + <string name="screenshot_saving_title" msgid="8242282144535555697">"正在儲存屏幕擷取畫面..."</string> + <string name="screenshot_saving_text" msgid="2419718443411738818">"正在儲存屏幕擷取畫面。"</string> + <string name="screenshot_saved_title" msgid="6461865960961414961">"已擷取屏幕畫面。"</string> + <string name="screenshot_saved_text" msgid="1152839647677558815">"輕觸即可查看屏幕擷取畫面。"</string> + <string name="screenshot_failed_title" msgid="705781116746922771">"無法擷取屏幕畫面。"</string> + <string name="screenshot_failed_text" msgid="8134011269572415402">"無法儲存屏幕擷取畫面,儲存裝置可能正在使用。"</string> + <string name="usb_preference_title" msgid="6551050377388882787">"USB 檔案傳輸選項"</string> + <string name="use_mtp_button_title" msgid="4333504413563023626">"掛接為媒體播放器 (MTP)"</string> + <string name="use_ptp_button_title" msgid="7517127540301625751">"掛接為相機 (PTP)"</string> + <string name="installer_cd_button_title" msgid="2312667578562201583">"安裝 Mac 專用的「Android 檔案傳輸」應用程式"</string> + <string name="accessibility_back" msgid="567011538994429120">"返回"</string> + <string name="accessibility_home" msgid="8217216074895377641">"首頁"</string> + <string name="accessibility_menu" msgid="316839303324695949">"選單"</string> + <string name="accessibility_recent" msgid="8571350598987952883">"最近使用的應用程式"</string> + <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"切換輸入法按鈕。"</string> + <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"相容性縮放按鈕。"</string> + <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"將較小螢幕的畫面放大在較大螢幕上顯示。"</string> + <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"藍牙連線已建立。"</string> + <string name="accessibility_bluetooth_disconnected" msgid="7416648669976870175">"藍牙連線已中斷。"</string> + <string name="accessibility_no_battery" msgid="358343022352820946">"未安裝電池。"</string> + <string name="accessibility_battery_one_bar" msgid="7774887721891057523">"電池電量為一格。"</string> + <string name="accessibility_battery_two_bars" msgid="8500650438735009973">"電池電量為兩格。"</string> + <string name="accessibility_battery_three_bars" msgid="2302983330865040446">"電池電量為三格。"</string> + <string name="accessibility_battery_full" msgid="8909122401720158582">"電池已滿。"</string> + <string name="accessibility_no_phone" msgid="4894708937052611281">"沒有電話訊號。"</string> + <string name="accessibility_phone_one_bar" msgid="687699278132664115">"電話訊號強度為一格。"</string> + <string name="accessibility_phone_two_bars" msgid="8384905382804815201">"電話訊號強度為兩格。"</string> + <string name="accessibility_phone_three_bars" msgid="8521904843919971885">"電話訊號強度為三格。"</string> + <string name="accessibility_phone_signal_full" msgid="6471834868580757898">"電話訊號滿格。"</string> + <string name="accessibility_no_data" msgid="4791966295096867555">"沒有數據網絡。"</string> + <string name="accessibility_data_one_bar" msgid="1415625833238273628">"數據網絡訊號強度為一格。"</string> + <string name="accessibility_data_two_bars" msgid="6166018492360432091">"數據網絡訊號強度為兩格。"</string> + <string name="accessibility_data_three_bars" msgid="9167670452395038520">"數據網絡訊號強度為三格。"</string> + <string name="accessibility_data_signal_full" msgid="2708384608124519369">"數據網絡訊號滿格。"</string> + <string name="accessibility_wifi_off" msgid="3177380296697933627">"WiFi 已關閉。"</string> + <string name="accessibility_no_wifi" msgid="1425476551827924474">"WiFi 連線已中斷。"</string> + <string name="accessibility_wifi_one_bar" msgid="7735893178010724377">"WiFi 訊號強度為一格。"</string> + <string name="accessibility_wifi_two_bars" msgid="4994274250497262434">"WiFi 訊號強度為兩格。"</string> + <string name="accessibility_wifi_three_bars" msgid="3495755044276588384">"WiFi 訊號強度為三格。"</string> + <string name="accessibility_wifi_signal_full" msgid="6853561303586480376">"WiFi 訊號已滿。"</string> + <string name="accessibility_no_wimax" msgid="4329180129727630368">"沒有 WiMAX 訊號。"</string> + <string name="accessibility_wimax_one_bar" msgid="4170994299011863648">"WiMAX 訊號強度一格。"</string> + <string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"WiMAX 訊號強度兩格。"</string> + <string name="accessibility_wimax_three_bars" msgid="6116551636752103927">"WiMAX 訊號強度三格。"</string> + <string name="accessibility_wimax_signal_full" msgid="2768089986795579558">"WiMAX 訊號滿格。"</string> + <string name="accessibility_no_signal" msgid="7064645320782585167">"沒有訊號。"</string> + <string name="accessibility_not_connected" msgid="6395326276213402883">"未連線。"</string> + <string name="accessibility_zero_bars" msgid="3806060224467027887">"訊號強度為零格。"</string> + <string name="accessibility_one_bar" msgid="1685730113192081895">"訊號強度為一格。"</string> + <string name="accessibility_two_bars" msgid="6437363648385206679">"訊號強度為兩格。"</string> + <string name="accessibility_three_bars" msgid="2648241415119396648">"訊號強度為三格。"</string> + <string name="accessibility_signal_full" msgid="9122922886519676839">"訊號已滿。"</string> + <string name="accessibility_desc_on" msgid="2385254693624345265">"開啟。"</string> + <string name="accessibility_desc_off" msgid="6475508157786853157">"關閉。"</string> + <string name="accessibility_desc_connected" msgid="8366256693719499665">"已連線。"</string> + <string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string> + <string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string> + <string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string> + <string name="accessibility_data_connection_3g" msgid="8628562305003568260">"3G"</string> + <string name="accessibility_data_connection_3.5g" msgid="8664845609981692001">"3.5G"</string> + <string name="accessibility_data_connection_4g" msgid="7741000750630089612">"4G"</string> + <string name="accessibility_data_connection_lte" msgid="5413468808637540658">"LTE"</string> + <string name="accessibility_data_connection_cdma" msgid="6132648193978823023">"CDMA"</string> + <string name="accessibility_data_connection_roaming" msgid="5977362333466556094">"漫遊"</string> + <string name="accessibility_data_connection_edge" msgid="4477457051631979278">"Edge"</string> + <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Wi-Fi"</string> + <string name="accessibility_no_sim" msgid="8274017118472455155">"無 SIM 卡。"</string> + <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"藍牙數據連線。"</string> + <string name="accessibility_airplane_mode" msgid="834748999790763092">"飛航模式。"</string> + <!-- String.format failed for translation --> + <!-- no translation found for accessibility_battery_level (7451474187113371965) --> + <skip /> + <string name="accessibility_settings_button" msgid="799583911231893380">"系統設定"</string> + <string name="accessibility_notifications_button" msgid="4498000369779421892">"通知。"</string> + <string name="accessibility_remove_notification" msgid="3603099514902182350">"清除通知。"</string> + <string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS 已啟用。"</string> + <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"正在取得 GPS 訊號。"</string> + <string name="accessibility_tty_enabled" msgid="4613200365379426561">"TeleTypewriter (TTY) 已啟用。"</string> + <string name="accessibility_ringer_vibrate" msgid="666585363364155055">"鈴聲震動。"</string> + <string name="accessibility_ringer_silent" msgid="9061243307939135383">"鈴聲靜音。"</string> + <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"「<xliff:g id="APP">%s</xliff:g>」已關閉。"</string> + <string name="accessibility_notification_dismissed" msgid="854211387186306927">"通知已關閉。"</string> + <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"通知欄。"</string> + <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"快速設定。"</string> + <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"最近使用的應用程式"</string> + <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"用戶:<xliff:g id="USER">%s</xliff:g>。"</string> + <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>、<xliff:g id="NETWORK">%2$s</xliff:g>"</string> + <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"流動數據連線:<xliff:g id="SIGNAL">%1$s</xliff:g>、<xliff:g id="TYPE">%2$s</xliff:g>、<xliff:g id="NETWORK">%3$s</xliff:g>。"</string> + <string name="accessibility_quick_settings_battery" msgid="1480931583381408972">"電池電量:<xliff:g id="STATE">%s</xliff:g>。"</string> + <string name="accessibility_quick_settings_airplane" msgid="4196876722090224753">"飛航模式:<xliff:g id="STATE">%s</xliff:g>。"</string> + <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"藍牙:<xliff:g id="STATE">%s</xliff:g>。"</string> + <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"鬧鐘已設定為:<xliff:g id="TIME">%s</xliff:g>。"</string> + <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"已停用 2G-3G 數據"</string> + <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"已停用 4G 數據"</string> + <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"已停用流動數據"</string> + <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"數據停用"</string> + <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"您已到達指定的數據用量上限。\n\n如果您重新啟用數據傳輸,流動網絡供應商可能會向您收費。"</string> + <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"重新啟用數據"</string> + <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"沒有互聯網連線"</string> + <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 已連線"</string> + <string name="gps_notification_searching_text" msgid="8574247005642736060">"正在搜尋 GPS"</string> + <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS 已定位"</string> + <string name="accessibility_location_active" msgid="2427290146138169014">"位置要求啟動中"</string> + <string name="accessibility_clear_all" msgid="5235938559247164925">"清除所有通知。"</string> + <string name="status_bar_notification_inspect_item_title" msgid="1163547729015390250">"應用程式資訊"</string> + <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"屏幕會自動旋轉。"</string> + <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"屏幕已鎖定為橫向模式。"</string> + <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"屏幕已鎖定為垂直模式。"</string> + <string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string> + <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string> + <string name="ethernet_label" msgid="7967563676324087464">"以太網"</string> + <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"飛行模式"</string> + <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"充電中 (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string> + <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"充電完成"</string> + <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"藍牙"</string> + <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"藍牙 (<xliff:g id="NUMBER">%d</xliff:g> 部裝置)"</string> + <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"藍牙關閉"</string> + <string name="quick_settings_brightness_label" msgid="6968372297018755815">"亮度"</string> + <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"自動旋轉"</string> + <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"已鎖定屏幕旋轉功能"</string> + <string name="quick_settings_ime_label" msgid="7073463064369468429">"輸入法"</string> + <string name="quick_settings_location_label" msgid="5011327048748762257">"位置"</string> + <string name="quick_settings_location_off_label" msgid="7464544086507331459">"位置關閉"</string> + <string name="quick_settings_media_device_label" msgid="1302906836372603762">"媒體裝置"</string> + <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string> + <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"只可撥打緊急電話"</string> + <string name="quick_settings_settings_label" msgid="5326556592578065401">"設定"</string> + <string name="quick_settings_time_label" msgid="4635969182239736408">"時間"</string> + <string name="quick_settings_user_label" msgid="5238995632130897840">"我"</string> + <string name="quick_settings_wifi_label" msgid="9135344704899546041">"Wi-Fi"</string> + <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"未連線"</string> + <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"沒有網絡"</string> + <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi 關閉"</string> + <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi Display"</string> + <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"無線顯示"</string> + <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"亮度"</string> + <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自動"</string> + <string name="status_bar_help_title" msgid="1199237744086469217">"通知會在這裡顯示"</string> + <string name="status_bar_help_text" msgid="7874607155052076323">"向下快速滑動可隨時存取通知。\n再次向下快速滑動則可使用系統控制介面。"</string> +</resources> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index a0bb92a..1d5b2ac 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -203,6 +203,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自動"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"系統會在這裡顯示通知"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"向下滑動即可隨時存取通知。\n再次向下滑動即可使用系統控制項。"</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"從螢幕邊緣向內滑動即可顯示導覽列"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"從螢幕邊緣向內滑動即可顯示導覽列"</string> </resources> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 53e7db0..662d3cb 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -201,6 +201,4 @@ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OKUZENZAKALELAYO"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Izaziso zivela lapha"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"Kufinyelele noma kunini ngokuswayiphela phansi.\nSwayiphela phansi futhi ngezilawuli zesistimu."</string> - <string name="hiding_navigation_confirmation_message" msgid="3227814171674734332">"Swayipha kunqenqema lwesikrini ukuze uveze ibha"</string> - <string name="hiding_navigation_confirmation_message_long" msgid="7854368870786524950">"Swayipha kusuka kunqenqema ukuze uveze ibha yesistimu"</string> </resources> diff --git a/packages/SystemUI/res/values/arrays.xml b/packages/SystemUI/res/values/arrays.xml index cd6aaf6..506722d 100644 --- a/packages/SystemUI/res/values/arrays.xml +++ b/packages/SystemUI/res/values/arrays.xml @@ -40,4 +40,16 @@ <item>@null</item> </array> + <!-- BatteryMeterView parameters --> + <array name="batterymeter_color_levels"> + <item>4</item> + <item>15</item> + <item>100</item> + </array> + <array name="batterymeter_color_values"> + <item>#FFFF0000</item> + <item>#FFFE6600</item> + <item>#FF3792B4</item> + </array> + </resources> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index 4a7d090..5718db2 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -20,6 +20,10 @@ <drawable name="notification_number_text_color">#ffffffff</drawable> <drawable name="ticker_background_color">#ff1d1d1d</drawable> <drawable name="status_bar_background">#ff000000</drawable> + <color name="status_bar_background_semi_transparent">#55000000</color> + <color name="status_bar_background_transparent">#00000000</color> + <color name="navigation_bar_background_transparent_start">#7f000000</color> + <color name="navigation_bar_background_transparent_end">#00000000</color> <color name="notification_panel_solid_background">#ff000000</color> <drawable name="status_bar_recents_app_thumbnail_background">#88000000</drawable> <color name="status_bar_recents_app_label_color">#ffffffff</color> @@ -30,4 +34,6 @@ <drawable name="heads_up_notification_bg_pressed">#ff33B5E5</drawable> <drawable name="notification_header_bg">#FF000000</drawable> <color name="notification_panel_scrim_color">#B0000000</color> + + <color name="batterymeter_frame_color">#FF404040</color> </resources> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 33a85c3..c849aa6 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -504,9 +504,6 @@ <!-- Body of help text shown when the notification panel is pulled down for the very first time. [CHAR LIMIT=NONE] --> <string name="status_bar_help_text">Access them anytime by swiping down.\nSwipe down again for system controls.</string> - <!-- Toast bar message when hiding the navigation bar --> - <string name="hiding_navigation_confirmation_message">Swipe edge of screen to reveal bar</string> - - <!-- Longer version of toast bar message when hiding the navigation bar (if room) --> - <string name="hiding_navigation_confirmation_message_long">Swipe from edge of screen to reveal system bar</string> + <!-- Glyph to be overlaid atop the battery when the level is extremely low. Do not translate. --> + <string name="battery_meter_very_low_overlay_symbol">!</string> </resources> diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java new file mode 100755 index 0000000..aa4362e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java @@ -0,0 +1,302 @@ +/* + * 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.systemui; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Typeface; +import android.graphics.drawable.Drawable; +import android.os.BatteryManager; +import android.provider.Settings; +import android.util.AttributeSet; +import android.view.View; + +public class BatteryMeterView extends View { + public static final String TAG = BatteryMeterView.class.getSimpleName(); + public static final String ACTION_LEVEL_TEST = "com.android.systemui.BATTERY_LEVEL_TEST"; + + public static final boolean ENABLE_PERCENT = true; + public static final boolean SINGLE_DIGIT_PERCENT = false; + public static final boolean SHOW_100_PERCENT = false; + + public static final int FULL = 96; + public static final int EMPTY = 4; + + int[] mColors; + + boolean mShowPercent = true; + Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint; + int mButtonHeight; + private float mTextHeight, mWarningTextHeight; + Drawable mLightning; + + private int mHeight; + private int mWidth; + private String mWarningString; + + private class BatteryTracker extends BroadcastReceiver { + // current battery status + int level; + String percentStr; + int plugType; + boolean plugged; + int health; + int status; + String technology; + int voltage; + int temperature; + boolean testmode = false; + + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { + if (testmode && ! intent.getBooleanExtra("testmode", false)) return; + + level = (int)(100f + * intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0) + / intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100)); + + plugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0); + plugged = plugType != 0; + health = intent.getIntExtra(BatteryManager.EXTRA_HEALTH, + BatteryManager.BATTERY_HEALTH_UNKNOWN); + status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, + BatteryManager.BATTERY_STATUS_UNKNOWN); + technology = intent.getStringExtra(BatteryManager.EXTRA_TECHNOLOGY); + voltage = intent.getIntExtra(BatteryManager.EXTRA_VOLTAGE, 0); + temperature = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0); + + setContentDescription( + context.getString(R.string.accessibility_battery_level, level)); + postInvalidate(); + } else if (action.equals(ACTION_LEVEL_TEST)) { + testmode = true; + post(new Runnable() { + int curLevel = 0; + int incr = 1; + int saveLevel = level; + int savePlugged = plugType; + Intent dummy = new Intent(Intent.ACTION_BATTERY_CHANGED); + @Override + public void run() { + if (curLevel < 0) { + testmode = false; + dummy.putExtra("level", saveLevel); + dummy.putExtra("plugged", savePlugged); + dummy.putExtra("testmode", false); + } else { + dummy.putExtra("level", curLevel); + dummy.putExtra("plugged", incr > 0 ? BatteryManager.BATTERY_PLUGGED_AC : 0); + dummy.putExtra("testmode", true); + } + getContext().sendBroadcast(dummy); + + if (!testmode) return; + + curLevel += incr; + if (curLevel == 100) { + incr *= -1; + } + postDelayed(this, 200); + } + }); + } + } + } + + BatteryTracker mTracker = new BatteryTracker(); + + @Override + public void onAttachedToWindow() { + super.onAttachedToWindow(); + + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_BATTERY_CHANGED); + filter.addAction(ACTION_LEVEL_TEST); + getContext().registerReceiver(mTracker, filter); + } + + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + + getContext().unregisterReceiver(mTracker); + } + + public BatteryMeterView(Context context) { + this(context, null, 0); + } + + public BatteryMeterView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public BatteryMeterView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + final Resources res = context.getResources(); + TypedArray levels = res.obtainTypedArray(R.array.batterymeter_color_levels); + TypedArray colors = res.obtainTypedArray(R.array.batterymeter_color_values); + + final int N = levels.length(); + mColors = new int[2*N]; + for (int i=0; i<N; i++) { + mColors[2*i] = levels.getInt(i, 0); + mColors[2*i+1] = colors.getColor(i, 0); + } + + mShowPercent = ENABLE_PERCENT && 0 != Settings.System.getInt( + context.getContentResolver(), "status_bar_show_battery_percent", 0); + + mWarningString = context.getString(R.string.battery_meter_very_low_overlay_symbol); + + mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mFramePaint.setColor(res.getColor(R.color.batterymeter_frame_color)); + mBatteryPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mBatteryPaint.setColor(0xFF00FF00); // will be replaced by something from mColors + + mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mTextPaint.setColor(0xFFFFFFFF); + Typeface font = Typeface.create("sans-serif-condensed", Typeface.NORMAL); + mTextPaint.setTypeface(font); + mTextPaint.setTextAlign(Paint.Align.CENTER); + + mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mWarningTextPaint.setColor(mColors[1]); + font = Typeface.create("sans-serif", Typeface.BOLD); + mWarningTextPaint.setTypeface(font); + mWarningTextPaint.setTextAlign(Paint.Align.CENTER); + + mLightning = getResources().getDrawable(R.drawable.lightning); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + mHeight = h; + mWidth = w; + mWarningTextPaint.setTextSize(h * 0.75f); + mWarningTextHeight = -mWarningTextPaint.getFontMetrics().ascent; + } + + private int getColorForLevel(int percent) { + int thresh, color = 0; + for (int i=0; i<mColors.length; i+=2) { + thresh = mColors[i]; + color = mColors[i+1]; + if (percent <= thresh) return color; + } + return color; + } + + @Override + public void draw(Canvas c) { + final int level = mTracker.level; + float drawFrac = (float) level / 100f; + final int pt = getPaddingTop(); + final int pl = getPaddingLeft(); + final int pr = getPaddingRight(); + final int pb = getPaddingBottom(); + int height = mHeight - pt - pb; + int width = mWidth - pl - pr; + + mButtonHeight = (int) (height * 0.12f); + + final RectF frame = new RectF(0, 0, width, height); + frame.offset(pl, pt); + + // Log.v("BatteryGauge", String.format("canvas: %dx%d frame: %s", + // c.getWidth(), c.getHeight(), frame.toString())); + + final RectF buttonframe = new RectF( + frame.left + width * 0.25f, + frame.top, + frame.right - width * 0.25f, + frame.top + mButtonHeight); + + frame.top += mButtonHeight; + + // first, draw the battery shape + c.drawRect(frame, mFramePaint); + + // fill 'er up + final int pct = mTracker.level; + final int color = getColorForLevel(pct); + mBatteryPaint.setColor(color); + + if (level >= FULL) { + drawFrac = 1f; + } else if (level <= EMPTY) { + drawFrac = 0f; + } + + c.drawRect(buttonframe, + drawFrac == 1f ? mBatteryPaint : mFramePaint); + + RectF clip = new RectF(frame); + clip.top += (frame.height() * (1f - drawFrac)); + + c.save(Canvas.CLIP_SAVE_FLAG); + c.clipRect(clip); + c.drawRect(frame, mBatteryPaint); + c.restore(); + + if (level <= EMPTY) { + final float x = mWidth * 0.5f; + final float y = (mHeight + mWarningTextHeight) * 0.48f; + c.drawText(mWarningString, x, y, mWarningTextPaint); + } else if (mTracker.plugged) { + final Rect r = new Rect( + (int)frame.left + width / 4, (int)frame.top + height / 5, + (int)frame.right - width / 4, (int)frame.bottom - height / 6); + mLightning.setBounds(r); + mLightning.draw(c); + } else if (mShowPercent && !(mTracker.level == 100 && !SHOW_100_PERCENT)) { + mTextPaint.setTextSize(height * + (SINGLE_DIGIT_PERCENT ? 0.75f + : (mTracker.level == 100 ? 0.38f : 0.5f))); + mTextHeight = -mTextPaint.getFontMetrics().ascent; + + final String str = String.valueOf(SINGLE_DIGIT_PERCENT ? (pct/10) : pct); + final float x = mWidth * 0.5f; + final float y = (mHeight + mTextHeight) * 0.47f; + c.drawText(str, + x, + y, + mTextPaint); + +// Paint pt = new Paint(); +// pt.setStrokeWidth(1f); +// pt.setStyle(Paint.Style.STROKE); +// pt.setColor(0xFFFF0000); +// c.drawRect(x, y-mTextHeight, x+tw, y, pt); +// +// Slog.v(TAG, "tw=" + tw + " th=" + mTextHeight); +// +// pt.setColor(0xFFFF00FF); +// c.drawRect(1, 1, mWidth, mHeight, pt); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java index f17b143..ff84243 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java @@ -135,9 +135,9 @@ public class SignalClusterView public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { // Standard group layout onPopulateAccessibilityEvent() implementations // ignore content description, so populate manually - if (mWifiVisible && mWifiGroup.getContentDescription() != null) + if (mWifiVisible && mWifiGroup != null && mWifiGroup.getContentDescription() != null) event.getText().add(mWifiGroup.getContentDescription()); - if (mMobileVisible && mMobileGroup.getContentDescription() != null) + if (mMobileVisible && mMobileGroup != null && mMobileGroup.getContentDescription() != null) event.getText().add(mMobileGroup.getContentDescription()); return super.dispatchPopulateAccessibilityEvent(event); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java new file mode 100644 index 0000000..e40c4e5 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java @@ -0,0 +1,108 @@ +/* + * 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.systemui.statusbar.phone; + +import android.animation.ArgbEvaluator; +import android.animation.ValueAnimator; +import android.animation.ValueAnimator.AnimatorUpdateListener; +import android.app.ActivityManager; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.util.Log; +import android.view.View; + +import com.android.systemui.R; + +public class BarTransitions { + private static final boolean DEBUG = false; + + public static final int MODE_OPAQUE = 0; + public static final int MODE_SEMI_TRANSPARENT = 1; + public static final int MODE_TRANSPARENT = 2; + + private final String mTag; + private final View mTarget; + private final int mOpaque; + private final int mSemiTransparent; + + protected Drawable mTransparent; + private int mMode; + + private final AnimatorUpdateListener mBackgroundColorListener = new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animator) { + mTarget.setBackgroundColor((Integer) animator.getAnimatedValue()); + } + }; + + public BarTransitions(Context context, View target) { + mTag = "BarTransitions." + target.getClass().getSimpleName(); + mTarget = target; + final Resources res = context.getResources(); + mOpaque = res.getColor(R.drawable.status_bar_background); + mSemiTransparent = res.getColor(R.color.status_bar_background_semi_transparent); + } + + public void setTransparent(Drawable transparent) { + mTransparent = transparent; + if (mMode == MODE_TRANSPARENT) { + transitionTo(MODE_TRANSPARENT); + } + } + + public void transitionTo(int mode) { + transitionTo(mode, false); + } + + public void transitionTo(int mode, boolean animate) { + if (mMode == mode) return; + int oldMode = mMode; + mMode = mode; + if (!ActivityManager.isHighEndGfx()) return; + if (DEBUG) Log.d(mTag, modeToString(oldMode) + " -> " + modeToString(mode)); + onTransition(oldMode, mMode, animate); + } + + protected void onTransition(int oldMode, int newMode, boolean animate) { + if (animate && oldMode == MODE_SEMI_TRANSPARENT && newMode == MODE_OPAQUE) { + startColorAnimation(mSemiTransparent, mOpaque); + } else if (animate && oldMode == MODE_OPAQUE && newMode == MODE_SEMI_TRANSPARENT) { + startColorAnimation(mOpaque, mSemiTransparent); + } else if (newMode == MODE_OPAQUE || newMode == MODE_SEMI_TRANSPARENT) { + mTarget.setBackgroundColor(newMode == MODE_OPAQUE ? mOpaque : mSemiTransparent); + } else { + mTarget.setBackground(newMode == MODE_TRANSPARENT? mTransparent + : newMode == MODE_SEMI_TRANSPARENT ? new ColorDrawable(mSemiTransparent) + : new ColorDrawable(mOpaque)); + } + } + + private void startColorAnimation(int from, int to) { + ValueAnimator anim = ValueAnimator.ofObject(new ArgbEvaluator(), from, to); + anim.addUpdateListener(mBackgroundColorListener); + anim.start(); + } + + public static String modeToString(int mode) { + if (mode == MODE_OPAQUE) return "MODE_OPAQUE"; + if (mode == MODE_SEMI_TRANSPARENT) return "MODE_SEMI_TRANSPARENT"; + if (mode == MODE_TRANSPARENT) return "MODE_TRANSPARENT"; + throw new IllegalArgumentException("Unknown mode " + mode); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index de33b87..62f8596 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -25,6 +25,8 @@ import android.content.res.Resources; import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; +import android.graphics.drawable.GradientDrawable.Orientation; import android.os.Handler; import android.os.Message; import android.os.ServiceManager; @@ -45,6 +47,7 @@ import com.android.systemui.R; import com.android.systemui.statusbar.BaseStatusBar; import com.android.systemui.statusbar.DelegateViewHelper; import com.android.systemui.statusbar.policy.DeadZone; +import com.android.systemui.statusbar.policy.KeyButtonView; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -79,6 +82,7 @@ public class NavigationBarView extends LinearLayout { private DelegateViewHelper mDelegateHelper; private DeadZone mDeadZone; + private final NavigationBarTransitions mBarTransitions; // workaround for LayoutTransitions leaving the nav buttons in a weird state (bug 5549288) final static boolean WORKAROUND_INVALID_LAYOUT = true; @@ -107,6 +111,68 @@ public class NavigationBarView extends LinearLayout { } } + private final class NavigationBarTransitions extends BarTransitions { + + private final Drawable mTransparentBottom; + private final Drawable mTransparentRight; + + public NavigationBarTransitions(Context context) { + super(context, NavigationBarView.this); + final Resources res = mContext.getResources(); + final int[] gradientColors = new int[] { + res.getColor(R.color.navigation_bar_background_transparent_start), + res.getColor(R.color.navigation_bar_background_transparent_end) + }; + mTransparentBottom = new GradientDrawable(Orientation.BOTTOM_TOP, gradientColors); + mTransparentRight = new GradientDrawable(Orientation.RIGHT_LEFT, gradientColors); + } + + public void setVertical(boolean isVertical) { + mTransparent = isVertical ? mTransparentRight : mTransparentBottom; + } + + @Override + protected void onTransition(int oldMode, int newMode, boolean animate) { + super.onTransition(oldMode, newMode, animate); + final float alpha = newMode == MODE_OPAQUE ? KeyButtonView.DEFAULT_QUIESCENT_ALPHA : 1f; + setKeyButtonViewQuiescentAlpha(getBackButton(), alpha); + setKeyButtonViewQuiescentAlpha(getHomeButton(), alpha); + setKeyButtonViewQuiescentAlpha(getRecentsButton(), alpha); + setKeyButtonViewQuiescentAlpha(getMenuButton(), alpha); + } + + private void setKeyButtonViewQuiescentAlpha(View button, float alpha) { + if (button instanceof KeyButtonView) { + ((KeyButtonView) button).setQuiescentAlpha(alpha); + } + } + } + + public NavigationBarView(Context context, AttributeSet attrs) { + super(context, attrs); + + mHidden = false; + + mDisplay = ((WindowManager)context.getSystemService( + Context.WINDOW_SERVICE)).getDefaultDisplay(); + mBarService = IStatusBarService.Stub.asInterface( + ServiceManager.getService(Context.STATUS_BAR_SERVICE)); + + final Resources res = mContext.getResources(); + mBarSize = res.getDimensionPixelSize(R.dimen.navigation_bar_size); + mVertical = false; + mShowMenu = false; + mDelegateHelper = new DelegateViewHelper(this); + + getIcons(res); + + mBarTransitions = new NavigationBarTransitions(context); + } + + public BarTransitions getBarTransitions() { + return mBarTransitions; + } + public void setDelegateView(View view) { mDelegateHelper.setDelegateView(view); } @@ -155,25 +221,6 @@ public class NavigationBarView extends LinearLayout { return mCurrentView.findViewById(R.id.search_light); } - public NavigationBarView(Context context, AttributeSet attrs) { - super(context, attrs); - - mHidden = false; - - mDisplay = ((WindowManager)context.getSystemService( - Context.WINDOW_SERVICE)).getDefaultDisplay(); - mBarService = IStatusBarService.Stub.asInterface( - ServiceManager.getService(Context.STATUS_BAR_SERVICE)); - - final Resources res = mContext.getResources(); - mBarSize = res.getDimensionPixelSize(R.dimen.navigation_bar_size); - mVertical = false; - mShowMenu = false; - mDelegateHelper = new DelegateViewHelper(this); - - getIcons(res); - } - private void getIcons(Resources res) { mBackIcon = res.getDrawable(R.drawable.ic_sysbar_back); mBackLandIcon = res.getDrawable(R.drawable.ic_sysbar_back_land); @@ -406,6 +453,7 @@ public class NavigationBarView extends LinearLayout { } setNavigationIconHints(mNavigationIconHints, true); + mBarTransitions.setVertical(mVertical); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index d0a6385..4b2c3e1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -76,6 +76,7 @@ public class PanelView extends FrameLayout { private boolean mClosing; private boolean mRubberbanding; private boolean mTracking; + private int mTrackingPointer; private TimeAnimator mTimeAnimator; private ObjectAnimator mPeekAnimator; @@ -118,7 +119,7 @@ public class PanelView extends FrameLayout { int i = 0; float totalweight = 0f; float weight = 10f; - for (final Iterator<MotionEventCopy> iter = mEventBuf.descendingIterator(); + for (final Iterator<MotionEventCopy> iter = mEventBuf.iterator(); iter.hasNext();) { final MotionEventCopy event = iter.next(); if (last != null) { @@ -126,13 +127,22 @@ public class PanelView extends FrameLayout { final float dx = (event.x - last.x); final float dy = (event.y - last.y); if (FlingTracker.DEBUG) { - Log.v("FlingTracker", String.format(" [%d] dx=%.1f dy=%.1f dt=%.0f vx=%.1f vy=%.1f", - i, + Log.v("FlingTracker", String.format( + " [%d] (t=%d %.1f,%.1f) dx=%.1f dy=%.1f dt=%f vx=%.1f vy=%.1f", + i, event.t, event.x, event.y, dx, dy, dt, (dx/dt), (dy/dt) )); } + if (event.t == last.t) { + // Really not sure what to do with events that happened at the same time, + // so we'll skip subsequent events. + if (DEBUG_NAN) { + Log.v("FlingTracker", "skipping simultaneous event at t=" + event.t); + } + continue; + } mVX += weight * dx / dt; mVY += weight * dy / dt; totalweight += weight; @@ -158,18 +168,18 @@ public class PanelView extends FrameLayout { } } public float getXVelocity() { - if (Float.isNaN(mVX)) { + if (Float.isNaN(mVX) || Float.isInfinite(mVX)) { if (DEBUG_NAN) { - Log.v("FlingTracker", "warning: vx=NaN"); + Log.v("FlingTracker", "warning: vx=" + mVX); } mVX = 0; } return mVX; } public float getYVelocity() { - if (Float.isNaN(mVY)) { + if (Float.isNaN(mVY) || Float.isInfinite(mVX)) { if (DEBUG_NAN) { - Log.v("FlingTracker", "warning: vx=NaN"); + Log.v("FlingTracker", "warning: vx=" + mVY); } mVY = 0; } @@ -371,14 +381,21 @@ public class PanelView extends FrameLayout { mHandleView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { - final float y = event.getY(); - final float rawY = event.getRawY(); - if (DEBUG) logf("handle.onTouch: a=%s y=%.1f rawY=%.1f off=%.1f", + int pointerIndex = event.findPointerIndex(mTrackingPointer); + if (pointerIndex < 0) { + pointerIndex = 0; + mTrackingPointer = event.getPointerId(pointerIndex); + } + final float y = event.getY(pointerIndex); + final float rawDelta = event.getRawY() - event.getY(); + final float rawY = y + rawDelta; + if (DEBUG) logf("handle.onTouch: a=%s p=[%d,%d] y=%.1f rawY=%.1f off=%.1f", MotionEvent.actionToString(event.getAction()), + mTrackingPointer, pointerIndex, y, rawY, mTouchOffset); PanelView.this.getLocationOnScreen(mAbsPos); - switch (event.getAction()) { + switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: mTracking = true; mHandleView.setPressed(true); @@ -388,13 +405,26 @@ public class PanelView extends FrameLayout { trackMovement(event); mTimeAnimator.cancel(); // end any outstanding animations mBar.onTrackingStarted(PanelView.this); - mTouchOffset = (rawY - mAbsPos[1]) - PanelView.this.getExpandedHeight(); + mTouchOffset = (rawY - mAbsPos[1]) - mExpandedHeight; if (mExpandedHeight == 0) { mJustPeeked = true; runPeekAnimation(); } break; + case MotionEvent.ACTION_POINTER_UP: + final int upPointer = event.getPointerId(event.getActionIndex()); + if (mTrackingPointer == upPointer) { + // gesture is ongoing, find a new pointer to track + final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1; + final float newY = event.getY(newIndex); + final float newRawY = newY + rawDelta; + mTrackingPointer = event.getPointerId(newIndex); + mTouchOffset = (newRawY - mAbsPos[1]) - mExpandedHeight; + mInitialTouchY = newY; + } + break; + case MotionEvent.ACTION_MOVE: final float h = rawY - mAbsPos[1] - mTouchOffset; if (h > mPeekHeight) { @@ -415,6 +445,7 @@ public class PanelView extends FrameLayout { case MotionEvent.ACTION_CANCEL: mFinalTouchY = y; mTracking = false; + mTrackingPointer = -1; mHandleView.setPressed(false); postInvalidate(); // catch the press state change mBar.onTrackingStopped(PanelView.this); @@ -613,6 +644,10 @@ public class PanelView extends FrameLayout { return mClosing; } + public boolean isTracking() { + return mTracking; + } + public void setBar(PanelBar panelBar) { mBar = panelBar; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index c914a34..ad53fea 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -16,6 +16,10 @@ package com.android.systemui.statusbar.phone; +import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE; +import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT; +import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; @@ -57,7 +61,6 @@ import android.view.Gravity; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; -import android.view.View.MeasureSpec; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.ViewPropertyAnimator; @@ -72,7 +75,7 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.TextView; -import android.widget.Toast; + import com.android.internal.statusbar.StatusBarIcon; import com.android.systemui.EventLogTags; import com.android.systemui.R; @@ -129,14 +132,7 @@ public class PhoneStatusBar extends BaseStatusBar { private static final int STATUS_OR_NAV_TRANSIENT = View.STATUS_BAR_TRANSIENT | View.NAVIGATION_BAR_TRANSIENT; - private static final int TRANSIENT_NAV_HIDING = - View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_ALLOW_TRANSIENT; private static final long AUTOHIDE_TIMEOUT_MS = 3000; - private static final float TRANSPARENT_ALPHA = 0.7f; - - private static final int BAR_MODE_NORMAL = 0; - private static final int BAR_MODE_TRANSIENT = 1; - private static final int BAR_MODE_TRANSPARENT = 2; // fling gesture tuning parameters, scaled to display density private float mSelfExpandVelocityPx; // classic value: 2000px/s @@ -314,37 +310,6 @@ public class PhoneStatusBar extends BaseStatusBar { } }; - private Toast mHidingNavigationConfirmation; - private boolean mHidingNavigationConfirmationDismissed; - - private final View.OnTouchListener mDismissHidingNavigationConfirmationOnTouchOutside = - new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - if (event.getActionMasked() == MotionEvent.ACTION_OUTSIDE) { - dismissHidingNavigationConfirmation(); - } - return false; - } - }; - - private final Runnable mHidingNavigationConfirmationAction = new Runnable() { - @Override - public void run() { - if (mHidingNavigationConfirmation != null) { - final boolean isGloballyConfirmed = Prefs.read(mContext) - .getBoolean(Prefs.HIDING_NAVIGATION_CONFIRMED, false); - if (!isGloballyConfirmed) { - // user pressed button, consider this a confirmation - Prefs.edit(mContext) - .putBoolean(Prefs.HIDING_NAVIGATION_CONFIRMED, true) - .apply(); - } - dismissHidingNavigationConfirmation(); - } - } - }; - private boolean mAutohideSuspended; private final Runnable mAutohide = new Runnable() { @@ -542,7 +507,6 @@ public class PhoneStatusBar extends BaseStatusBar { // Other icons mLocationController = new LocationController(mContext); // will post a notification mBatteryController = new BatteryController(mContext); - mBatteryController.addIconView((ImageView)mStatusBarView.findViewById(R.id.battery)); mNetworkController = new NetworkController(mContext); mBluetoothController = new BluetoothController(mContext); mRotationLockController = new RotationLockController(mContext); @@ -971,7 +935,7 @@ public class PhoneStatusBar extends BaseStatusBar { } if (CLOSE_PANEL_WHEN_EMPTIED && mNotificationData.size() == 0 - && !mStatusBarWindow.isPointerDown()) { + && !mNotificationPanel.isTracking()) { animateCollapsePanels(); } } @@ -1939,97 +1903,56 @@ public class PhoneStatusBar extends BaseStatusBar { } // update status bar mode - int sbMode = updateBarMode(oldVal, newVal, mStatusBarView, + int sbMode = updateBarMode(oldVal, newVal, mStatusBarView.getBarTransitions(), View.STATUS_BAR_TRANSIENT, View.SYSTEM_UI_FLAG_TRANSPARENT_STATUS); // update navigation bar mode - int nbMode = updateBarMode(oldVal, newVal, mNavigationBarView, + int nbMode = updateBarMode(oldVal, newVal, mNavigationBarView.getBarTransitions(), View.NAVIGATION_BAR_TRANSIENT, View.SYSTEM_UI_FLAG_TRANSPARENT_NAVIGATION); if (sbMode != -1 || nbMode != -1) { // update transient bar autohide - if (sbMode == BAR_MODE_TRANSIENT || nbMode == BAR_MODE_TRANSIENT) { + if (sbMode == MODE_SEMI_TRANSPARENT || nbMode == MODE_SEMI_TRANSPARENT) { scheduleAutohide(); } else { cancelAutohide(); } } - // update hiding navigation confirmation - if (mNavigationBarView != null) { - boolean oldShowConfirm = (oldVal & TRANSIENT_NAV_HIDING) == TRANSIENT_NAV_HIDING; - boolean newShowConfirm = (newVal & TRANSIENT_NAV_HIDING) == TRANSIENT_NAV_HIDING; - if (!oldShowConfirm && newShowConfirm) { - mHidingNavigationConfirmationDismissed = false; - } - setHidingNavigationConfirmationVisible(newShowConfirm); - } - // send updated sysui visibility to window manager notifyUiVisibilityChanged(mSystemUiVisibility); } } - private int updateBarMode(int oldVis, int newVis, View view, + private int updateBarMode(int oldVis, int newVis, BarTransitions transitions, int transientFlag, int transparentFlag) { final int oldMode = barMode(oldVis, transientFlag, transparentFlag); final int newMode = barMode(newVis, transientFlag, transparentFlag); if (oldMode == newMode) { return -1; // no mode change } - setTransparent(view, newMode != BAR_MODE_NORMAL); + transitions.transitionTo(newMode); return newMode; } private int barMode(int vis, int transientFlag, int transparentFlag) { - return (vis & transientFlag) != 0 ? BAR_MODE_TRANSIENT - : (vis & transparentFlag) != 0 ? BAR_MODE_TRANSPARENT - : BAR_MODE_NORMAL; - } - - private void dismissHidingNavigationConfirmation() { - if (mHidingNavigationConfirmation != null) { - mHidingNavigationConfirmationDismissed = true; - mHidingNavigationConfirmation.cancel(); - mHidingNavigationConfirmation = null; - } - } - - private void setHidingNavigationConfirmationVisible(boolean visible) { - if (DEBUG) Log.d(TAG, "setHidingNavigationConfirmationVisible " + visible); - if (visible && - mHidingNavigationConfirmation == null && !mHidingNavigationConfirmationDismissed) { - // create the confirmation toast bar - int msg = R.string.hiding_navigation_confirmation_message; - mHidingNavigationConfirmation = Toast.makeBar(mContext, msg, Toast.LENGTH_INFINITE) - .setAction(com.android.internal.R.string.ok, - mHidingNavigationConfirmationAction); - View v = mHidingNavigationConfirmation.getView(); - v.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); - boolean isGloballyConfirmed = Prefs.read(mContext) - .getBoolean(Prefs.HIDING_NAVIGATION_CONFIRMED, false); - if (isGloballyConfirmed) { - // dismiss on outside touch if globally confirmed - v.setOnTouchListener(mDismissHidingNavigationConfirmationOnTouchOutside); - } - // position at the bottom like normal toasts, but use top gravity - // to avoid jumping around when showing/hiding the nav bar - v.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); - int offsetY = mContext.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.toast_y_offset); - mHidingNavigationConfirmation.setGravity(Gravity.TOP, - 0, mCurrentDisplaySize.y - v.getMeasuredHeight() / 2 - offsetY); - // show the confirmation - mHidingNavigationConfirmation.show(); - } else if (!visible) { - dismissHidingNavigationConfirmation(); - } + return (vis & transientFlag) != 0 ? MODE_SEMI_TRANSPARENT + : (vis & transparentFlag) != 0 ? MODE_TRANSPARENT + : MODE_OPAQUE; } @Override public void resumeAutohide() { if (mAutohideSuspended) { scheduleAutohide(); + animateTransitionTo(BarTransitions.MODE_SEMI_TRANSPARENT); + } + } + + private void animateTransitionTo(int newMode) { + mStatusBarView.getBarTransitions().transitionTo(newMode, true /*animate*/); + if (mNavigationBarView != null) { + mNavigationBarView.getBarTransitions().transitionTo(newMode, true /*animate*/); } } @@ -2037,6 +1960,7 @@ public class PhoneStatusBar extends BaseStatusBar { public void suspendAutohide() { mHandler.removeCallbacks(mAutohide); mAutohideSuspended = 0 != (mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT); + animateTransitionTo(BarTransitions.MODE_OPAQUE); } private void cancelAutohide() { @@ -2063,13 +1987,6 @@ public class PhoneStatusBar extends BaseStatusBar { mHandler.postDelayed(mAutohide, 25); } - private void setTransparent(View view, boolean transparent) { - float alpha = transparent ? TRANSPARENT_ALPHA : 1; - if (DEBUG) Log.d(TAG, "Setting " + (view == mStatusBarView ? "status bar" : - view == mNavigationBarView ? "navigation bar" : "view") + " alpha to " + alpha); - view.setAlpha(alpha); - } - private void setStatusBarLowProfile(boolean lightsOut) { if (mLightsOutAnimation == null) { final View notifications = mStatusBarView.findViewById(R.id.notification_icon_area); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java index 1554e2c..910d4c4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java @@ -17,10 +17,10 @@ package com.android.systemui.statusbar.phone; import android.app.ActivityManager; -import android.app.StatusBarManager; import android.content.Context; import android.content.res.Resources; import android.content.res.Resources.NotFoundException; +import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.util.EventLog; import android.util.Log; @@ -46,6 +46,15 @@ public class PhoneStatusBarView extends PanelBar { PanelView mLastFullyOpenedPanel = null; PanelView mNotificationPanel, mSettingsPanel; private boolean mShouldFade; + private final StatusBarTransitions mBarTransitions; + + private final class StatusBarTransitions extends BarTransitions { + public StatusBarTransitions(Context context) { + super(context, PhoneStatusBarView.this); + final Resources res = context.getResources(); + mTransparent = res.getDrawable(R.color.status_bar_background_transparent); + } + } public PhoneStatusBarView(Context context, AttributeSet attrs) { super(context, attrs); @@ -59,6 +68,11 @@ public class PhoneStatusBarView extends PanelBar { mSettingsPanelDragzoneFrac = 0f; } mFullWidthNotifications = mSettingsPanelDragzoneFrac <= 0f; + mBarTransitions = new StatusBarTransitions(context); + } + + public BarTransitions getBarTransitions() { + return mBarTransitions; } public void setBar(PhoneStatusBar bar) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java index 5233f42..5f034a8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java @@ -494,7 +494,9 @@ class QuickSettings { } // Battery - final QuickSettingsBasicTile batteryTile = new QuickSettingsBasicTile(mContext); + final QuickSettingsTileView batteryTile = (QuickSettingsTileView) + inflater.inflate(R.layout.quick_settings_tile, parent, false); + batteryTile.setContent(R.layout.quick_settings_tile_battery, inflater); batteryTile.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -506,9 +508,6 @@ class QuickSettings { public void refreshView(QuickSettingsTileView unused, State state) { QuickSettingsModel.BatteryState batteryState = (QuickSettingsModel.BatteryState) state; - Drawable d = batteryState.pluggedIn - ? mChargingBatteryLevels - : mBatteryLevels; String t; if (batteryState.batteryLevel == 100) { t = mContext.getString(R.string.quick_settings_battery_charged_label); @@ -519,9 +518,7 @@ class QuickSettings { : mContext.getString(R.string.status_bar_settings_battery_meter_format, batteryState.batteryLevel); } - batteryTile.setImageDrawable(d); - batteryTile.getImageView().setImageLevel(batteryState.batteryLevel); - batteryTile.setText(t); + ((TextView)batteryTile.findViewById(R.id.text)).setText(t); batteryTile.setContentDescription( mContext.getString(R.string.accessibility_quick_settings_battery, t)); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java index 800bc02..a600aae 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java @@ -42,7 +42,6 @@ public class StatusBarWindowView extends FrameLayout private NotificationRowLayout latestItems; private NotificationPanelView mNotificationPanel; private ScrollView mScrollView; - private boolean mPointerDown; PhoneStatusBar mService; @@ -87,7 +86,6 @@ public class StatusBarWindowView extends FrameLayout @Override public boolean onInterceptTouchEvent(MotionEvent ev) { - registerPointer(ev); boolean intercept = false; if (mNotificationPanel.isFullyExpanded() && mScrollView.getVisibility() == View.VISIBLE) { intercept = mExpandHelper.onInterceptTouchEvent(ev); @@ -133,21 +131,5 @@ public class StatusBarWindowView extends FrameLayout mExpandHelper.cancel(); } } - - private void registerPointer(MotionEvent event) { - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - mPointerDown = true; - break; - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: - mPointerDown = false; - break; - } - } - - public boolean isPointerDown() { - return mPointerDown; - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java index f325957..924478c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java @@ -16,6 +16,9 @@ package com.android.systemui.statusbar.policy; +import android.animation.Animator; +import android.animation.Animator.AnimatorListener; +import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.content.Context; @@ -26,6 +29,7 @@ import android.graphics.drawable.Drawable; import android.hardware.input.InputManager; import android.os.SystemClock; import android.util.AttributeSet; +import android.util.Log; import android.view.HapticFeedbackConstants; import android.view.InputDevice; import android.view.KeyCharacterMap; @@ -41,9 +45,10 @@ import com.android.systemui.R; public class KeyButtonView extends ImageView { private static final String TAG = "StatusBar.KeyButtonView"; + private static final boolean DEBUG = false; final float GLOW_MAX_SCALE_FACTOR = 1.8f; - final float BUTTON_QUIESCENT_ALPHA = 0.70f; + public static final float DEFAULT_QUIESCENT_ALPHA = 0.70f; long mDownTime; int mCode; @@ -51,6 +56,7 @@ public class KeyButtonView extends ImageView { Drawable mGlowBG; int mGlowWidth, mGlowHeight; float mGlowAlpha = 0f, mGlowScale = 1f, mDrawingAlpha = 1f; + float mQuiescentAlpha = DEFAULT_QUIESCENT_ALPHA; boolean mSupportsLongpress = true; RectF mRect = new RectF(0f,0f,0f,0f); AnimatorSet mPressedAnim; @@ -70,6 +76,15 @@ public class KeyButtonView extends ImageView { } }; + private final AnimatorListener mRecoverToQuiescentListener = new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (mQuiescentAlpha != mDrawingAlpha) { + animateToQuiescent().setDuration(200).start(); + } + } + }; + public KeyButtonView(Context context, AttributeSet attrs) { this(context, attrs, 0); } @@ -86,7 +101,7 @@ public class KeyButtonView extends ImageView { mGlowBG = a.getDrawable(R.styleable.KeyButtonView_glowBackground); if (mGlowBG != null) { - setDrawingAlpha(BUTTON_QUIESCENT_ALPHA); + setDrawingAlpha(mQuiescentAlpha); mGlowWidth = mGlowBG.getIntrinsicWidth(); mGlowHeight = mGlowBG.getIntrinsicHeight(); } @@ -118,6 +133,16 @@ public class KeyButtonView extends ImageView { super.onDraw(canvas); } + public void setQuiescentAlpha(float alpha) { + alpha = Math.min(Math.max(alpha, 0), 1); + if (alpha == mQuiescentAlpha) return; + mQuiescentAlpha = alpha; + if (DEBUG) Log.d(TAG, "New quiescent alpha = " + mQuiescentAlpha); + if (mGlowBG != null) { + setDrawingAlpha(mQuiescentAlpha); + } + } + public float getDrawingAlpha() { if (mGlowBG == null) return 0; return mDrawingAlpha; @@ -172,6 +197,12 @@ public class KeyButtonView extends ImageView { } } + private ObjectAnimator animateToQuiescent() { + ObjectAnimator anim = ObjectAnimator.ofFloat(this, "drawingAlpha", mQuiescentAlpha); + anim.addListener(mRecoverToQuiescentListener); // mQuiescentAlpha may change mid-animation + return anim; + } + public void setPressed(boolean pressed) { if (mGlowBG != null) { if (pressed != isPressed()) { @@ -182,8 +213,8 @@ public class KeyButtonView extends ImageView { if (pressed) { if (mGlowScale < GLOW_MAX_SCALE_FACTOR) mGlowScale = GLOW_MAX_SCALE_FACTOR; - if (mGlowAlpha < BUTTON_QUIESCENT_ALPHA) - mGlowAlpha = BUTTON_QUIESCENT_ALPHA; + if (mGlowAlpha < mQuiescentAlpha) + mGlowAlpha = mQuiescentAlpha; setDrawingAlpha(1f); as.playTogether( ObjectAnimator.ofFloat(this, "glowAlpha", 1f), @@ -194,7 +225,7 @@ public class KeyButtonView extends ImageView { as.playTogether( ObjectAnimator.ofFloat(this, "glowAlpha", 0f), ObjectAnimator.ofFloat(this, "glowScale", 1f), - ObjectAnimator.ofFloat(this, "drawingAlpha", BUTTON_QUIESCENT_ALPHA) + animateToQuiescent() ); as.setDuration(500); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java index fcf04ac..c2ffff8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java @@ -53,7 +53,6 @@ public class LocationController extends BroadcastReceiver { private StatusBarManager mStatusBarManager; private boolean mAreActiveLocationRequests; - private boolean mIsAirplaneMode; private ArrayList<LocationSettingsChangeCallback> mSettingsChangeCallbacks = new ArrayList<LocationSettingsChangeCallback>(); @@ -76,9 +75,6 @@ public class LocationController extends BroadcastReceiver { IntentFilter filter = new IntentFilter(); filter.addAction(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION); - // Listen for a change in the airplane mode setting so we can defensively turn off the - // high power location icon when radios are disabled. - filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); context.registerReceiver(this, filter); mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); @@ -100,7 +96,6 @@ public class LocationController extends BroadcastReceiver { // Examine the current location state and initialize the status view. updateActiveLocationRequests(); - updateAirplaneMode(); refreshViews(); } @@ -170,11 +165,9 @@ public class LocationController extends BroadcastReceiver { return false; } - // Updates the status view based on the current state of location requests and airplane mode. + // Updates the status view based on the current state of location requests. private void refreshViews() { - // The airplane mode check is defensive - there shouldn't be any active high power - // location requests when airplane mode is on. - if (!mIsAirplaneMode && mAreActiveLocationRequests) { + if (mAreActiveLocationRequests) { mStatusBarManager.setIcon(LOCATION_STATUS_ICON_PLACEHOLDER, LOCATION_STATUS_ICON_ID, 0, mContext.getString(R.string.accessibility_location_active)); } else { @@ -191,25 +184,11 @@ public class LocationController extends BroadcastReceiver { } } - // Reads the airplane mode setting and updates the status view if necessary. - private void updateAirplaneMode() { - boolean wasAirplaneMode = mIsAirplaneMode; - // TODO This probably warrants a utility method in Settings.java. - mIsAirplaneMode = (Settings.Global.getInt( - mContext.getContentResolver(), - Settings.Global.AIRPLANE_MODE_ON, 0) == 1); - if (mIsAirplaneMode != wasAirplaneMode) { - refreshViews(); - } - } - @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if (LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)) { updateActiveLocationRequests(); - } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) { - updateAirplaneMode(); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java index fb2348e..34e3013 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java @@ -430,7 +430,8 @@ public class NetworkController extends BroadcastReceiver { @Override public void onServiceStateChanged(ServiceState state) { if (DEBUG) { - Log.d(TAG, "onServiceStateChanged state=" + state.getState()); + Log.d(TAG, "onServiceStateChanged voiceState=" + state.getVoiceRegState() + + " dataState=" + state.getDataRegState()); } mServiceState = state; updateTelephonySignalStrength(); @@ -506,10 +507,16 @@ public class NetworkController extends BroadcastReceiver { private boolean hasService() { if (mServiceState != null) { - switch (mServiceState.getState()) { - case ServiceState.STATE_OUT_OF_SERVICE: + // Consider the device to be in service if either voice or data service is available. + // Some SIM cards are marketed as data-only and do not support voice service, and on + // these SIM cards, we want to show signal bars for data service as well as the "no + // service" or "emergency calls only" text that indicates that voice is not available. + switch(mServiceState.getVoiceRegState()) { case ServiceState.STATE_POWER_OFF: return false; + case ServiceState.STATE_OUT_OF_SERVICE: + case ServiceState.STATE_EMERGENCY_ONLY: + return mServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE; default: return true; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java index 3d51f20..16a92ea 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java @@ -25,8 +25,6 @@ public class Prefs { public static final String SHOWN_COMPAT_MODE_HELP = "shown_compat_mode_help"; public static final String SHOWN_QUICK_SETTINGS_HELP = "shown_quick_settings_help"; - public static final String HIDING_NAVIGATION_CONFIRMED = "hiding_navigation_confirmed"; - public static SharedPreferences read(Context context) { return context.getSharedPreferences(Prefs.SHARED_PREFS_NAME, Context.MODE_PRIVATE); } diff --git a/packages/services/PacProcessor/Android.mk b/packages/services/PacProcessor/Android.mk index e4afde6..d9566d5 100644 --- a/packages/services/PacProcessor/Android.mk +++ b/packages/services/PacProcessor/Android.mk @@ -18,24 +18,15 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES := \ - main_pacserver.cpp \ - ProxyService.cpp \ - IProxyService.cpp - -LOCAL_C_INCLUDES += \ - external/chromium-libpac/src - -LOCAL_SHARED_LIBRARIES := \ - libutils \ - liblog \ - libpac \ - libbinder \ - libstlport - -LOCAL_MODULE := pacserver LOCAL_MODULE_TAGS := optional -include external/stlport/libstlport.mk +LOCAL_SRC_FILES := $(call all-java-files-under, src) -include $(BUILD_EXECUTABLE) +LOCAL_PACKAGE_NAME := PacProcessor +LOCAL_CERTIFICATE := platform + +LOCAL_REQUIRED_MODULES := libjni_pacprocessor + +include $(BUILD_PACKAGE) + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/packages/services/PacProcessor/AndroidManifest.xml b/packages/services/PacProcessor/AndroidManifest.xml new file mode 100644 index 0000000..6740c16 --- /dev/null +++ b/packages/services/PacProcessor/AndroidManifest.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.pacprocessor"> + + <uses-permission android:name="android.permission.INTERNET" /> + + <application + android:label="@string/app_name"> + + <service android:name=".PacService" + android:exported="true"> + </service> + + </application> + +</manifest> diff --git a/packages/services/PacProcessor/IProxyService.cpp b/packages/services/PacProcessor/IProxyService.cpp deleted file mode 100644 index 3707d85..0000000 --- a/packages/services/PacProcessor/IProxyService.cpp +++ /dev/null @@ -1,97 +0,0 @@ -#define LOG_TAG "ProxyTesting" - -#include <stdint.h> -#include <sys/types.h> -#include <binder/Parcel.h> -#include <binder/IPCThreadState.h> -#include <utils/Errors.h> -#include "IProxyService.h" - -#include <utils/Log.h> - -#include <private/android_filesystem_config.h> - -using namespace android; - -String16 BpProxyService::resolveProxies(String16 host, String16 url) { - String16 ret; - return ret; -} - -void BpProxyService::setPacFile(String16& scriptContents) { - -} - -void BpProxyService::startPacSystem() { - -} -void BpProxyService::stopPacSystem() { - -} - -IMPLEMENT_META_INTERFACE(ProxyService, "com.android.net.IProxyService"); - -status_t BnProxyService::onTransact( - uint32_t code, const Parcel& data, - Parcel* reply, uint32_t flags) { - int returnInt = 0; - switch (code) { - case RESOLVE_PROXIES: - { - CHECK_INTERFACE(IProxyService, data, reply); - String16 host = data.readString16(); - String16 url = data.readString16(); - String16 response = resolveProxies(host, url); - reply->writeNoException(); - reply->writeString16(response); - return NO_ERROR; - } break; - case SET_PAC: - { - CHECK_INTERFACE(IProxyService, data, reply); - if (notSystemUid()) { - returnInt = 1; - } else { - String16 pacFile = data.readString16(); - setPacFile(pacFile); - } - reply->writeNoException(); - reply->writeInt32(returnInt); - return NO_ERROR; - } break; - case START_PAC: - { - CHECK_INTERFACE(IProxyService, data, reply); - if (notSystemUid()) { - returnInt = 1; - } else { - startPacSystem(); - } - reply->writeNoException(); - reply->writeInt32(returnInt); - return NO_ERROR; - } break; - case STOP_PAC: - { - CHECK_INTERFACE(IProxyService, data, reply); - if (notSystemUid()) { - returnInt = 1; - } else { - stopPacSystem(); - } - reply->writeNoException(); - reply->writeInt32(returnInt); - return NO_ERROR; - } break; - default: - return BBinder::onTransact(code, data, reply, flags); - } -} - -int BnProxyService::getCallingUid() { - return IPCThreadState::self()->getCallingUid(); -} - -bool BnProxyService::notSystemUid() { - return getCallingUid() != AID_SYSTEM; -} diff --git a/packages/services/PacProcessor/IProxyService.h b/packages/services/PacProcessor/IProxyService.h deleted file mode 100644 index 57c527b..0000000 --- a/packages/services/PacProcessor/IProxyService.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef IPROXY_SERVICE_H -#define IPROXY_SERVICE_H - -#include <binder/IInterface.h> -#include <binder/IBinder.h> - -namespace android { -class IProxyService : public IInterface { -public: - /** - * Keep up-to-date with - * frameworks/base/packages/services/Proxy/com/android/net/IProxyService.aidl - */ - enum { - RESOLVE_PROXIES = IBinder::FIRST_CALL_TRANSACTION, - SET_PAC, - START_PAC, - STOP_PAC, - }; -public: - DECLARE_META_INTERFACE(ProxyService); - -public: - - virtual String16 resolveProxies(String16 host, String16 url) = 0; - - virtual void setPacFile(String16& scriptContents) = 0; - - virtual void startPacSystem() = 0; - virtual void stopPacSystem() = 0; -private: -}; - -class BpProxyService : public BpInterface<IProxyService> { -public: - BpProxyService(const sp<IBinder>& impl) : BpInterface<IProxyService>(impl) {} - - virtual String16 resolveProxies(String16 host, String16 url); - - virtual void setPacFile(String16& scriptContents); - - virtual void startPacSystem(); - virtual void stopPacSystem(); -}; - -class BnProxyService : public BnInterface<IProxyService> { -public: - virtual status_t onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); - -private: - int getCallingUid(); - - bool notSystemUid(); -}; -} - - -#endif //IPROXY_SERVICE_H diff --git a/packages/services/PacProcessor/ProxyService.cpp b/packages/services/PacProcessor/ProxyService.cpp deleted file mode 100644 index 7084a47..0000000 --- a/packages/services/PacProcessor/ProxyService.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#define LOG_TAG "ProxyService" -#include <utils/Log.h> - -#include <errno.h> -#include <utils/threads.h> -#include <binder/IServiceManager.h> -#include <binder/IPCThreadState.h> -#include <sys/stat.h> -#include <proxy_resolver_v8.h> -#include <sstream> - -#include "ProxyService.h" - -using namespace net; - -using namespace android; - -class ProxyErrorLogger : public ProxyErrorListener { -protected: - ~ProxyErrorLogger() { - - } -public: - void AlertMessage(String16 message) { - String8 str(message); - ALOGD("Alert: %s", str.string()); - } - void ErrorMessage(String16 message) { - String8 str(message); - ALOGE("Error: %s", str.string()); - } -}; - -void ProxyService::instantiate() { - ALOGV("instantiate"); - defaultServiceManager()->addService(String16("com.android.net.IProxyService"), - new ProxyService()); -} - -ProxyService::ProxyService() { - hasSetScript = false; -} - -ProxyService::~ProxyService() { - stopPacSystem(); -} - -String16 ProxyService::resolveProxies(String16 host, String16 url) { - ALOGV("resolve"); - String16 blankRet; - if (proxyResolver != NULL) { - if (hasSetScript) { - String16 ret; - if (proxyResolver->GetProxyForURL(url, host, &ret) != OK) { - return blankRet; - } - return ret; - } else { - ALOGD("Unable to resolve PAC when no script is set!"); - } - } else { - ALOGE("Cannot parse while resolver not initialized!"); - } - return blankRet; -} - -void ProxyService::setPacFile(String16& scriptContents) { - ALOGV("set"); - if (proxyResolver != NULL) { - if (proxyResolver->SetPacScript(scriptContents) != OK) { - ALOGD("Unable to initialize PAC - Resolving will not work"); - } else { - hasSetScript = true; - } - } else { - ALOGE("PAC script set while resolver not initialized!"); - } -} - -void ProxyService::startPacSystem() { - ALOGV("start"); - // Stop in case redundant start call - stopPacSystem(); - - proxyResolver = new ProxyResolverV8(ProxyResolverJSBindings::CreateDefault(), - new ProxyErrorLogger()); - hasSetScript = false; -} - -void ProxyService::stopPacSystem() { - ALOGV("stop"); - if (proxyResolver != NULL) { - delete proxyResolver; - proxyResolver = NULL; - } -} diff --git a/packages/services/PacProcessor/ProxyService.h b/packages/services/PacProcessor/ProxyService.h deleted file mode 100644 index a0861b2..0000000 --- a/packages/services/PacProcessor/ProxyService.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef PROXY_SERVICE_H -#define PROXY_SERVICE_H - -#include <binder/IInterface.h> -#include "IProxyService.h" -#include "proxy_resolver_v8.h" - -namespace android { - -class ProxyService : public BnProxyService { -public: - static void instantiate(); - -private: - ProxyService(); - virtual ~ProxyService(); - -public: - String16 resolveProxies(String16 host, String16 url); - - void setPacFile(String16& scriptContents); - - void startPacSystem(); - void stopPacSystem(); - -private: - net::ProxyResolverV8* proxyResolver; - bool hasSetScript; -}; - -} - -#endif //PROXY_SERVICE_H diff --git a/packages/SystemUI/res/values-land/refs.xml b/packages/services/PacProcessor/com/android/net/IProxyService.aidl index 62fb77d..4e54aba 100644 --- a/packages/SystemUI/res/values-land/refs.xml +++ b/packages/services/PacProcessor/com/android/net/IProxyService.aidl @@ -1,5 +1,4 @@ -<?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"); @@ -13,8 +12,16 @@ * 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> - <item type="string" name="hiding_navigation_confirmation_message">@string/hiding_navigation_confirmation_message_long</item> -</resources> + */ +package com.android.net; + +/** @hide */ +interface IProxyService +{ + String resolvePacFile(String host, String url); + + oneway void setPacFile(String scriptContents); + + oneway void startPacSystem(); + oneway void stopPacSystem(); +} diff --git a/packages/services/PacProcessor/jni/Android.mk b/packages/services/PacProcessor/jni/Android.mk new file mode 100644 index 0000000..f16c90b --- /dev/null +++ b/packages/services/PacProcessor/jni/Android.mk @@ -0,0 +1,41 @@ +# +# 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + jni_init.cpp \ + com_android_pacprocessor_PacNative.cpp + +LOCAL_C_INCLUDES += \ + external/chromium-libpac/src + +LOCAL_SHARED_LIBRARIES := \ + libandroidfw \ + libandroid_runtime \ + liblog \ + libutils \ + libnativehelper \ + libpac + +LOCAL_MODULE := libjni_pacprocessor +LOCAL_MODULE_TAGS := optional + +include external/stlport/libstlport.mk + +include $(BUILD_SHARED_LIBRARY) diff --git a/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp b/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp new file mode 100644 index 0000000..c5aa13b --- /dev/null +++ b/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp @@ -0,0 +1,148 @@ +/* + * 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. + */ + +#define LOG_TAG "PacProcessor" + +#include <utils/Log.h> +#include <utils/Mutex.h> +#include "android_runtime/AndroidRuntime.h" + +#include "jni.h" +#include "JNIHelp.h" + +#include "proxy_resolver_v8.h" + +namespace android { + +class ProxyErrorLogger : public net::ProxyErrorListener { +public: + ~ProxyErrorLogger() { + + } + void AlertMessage(String16 message) { + String8 str(message); + ALOGD("Alert: %s", str.string()); + } + void ErrorMessage(String16 message) { + String8 str(message); + ALOGE("Error: %s", str.string()); + } +}; + +net::ProxyResolverV8* proxyResolver = NULL; +ProxyErrorLogger* logger = NULL; +bool pacSet = false; + +String16 jstringToString16(JNIEnv* env, jstring jstr) { + const jchar* str = env->GetStringCritical(jstr, 0); + String16 str16(str, env->GetStringLength(jstr)); + env->ReleaseStringCritical(jstr, str); + return str16; +} + +jstring string16ToJstring(JNIEnv* env, String16 string) { + const char16_t* str = string.string(); + size_t len = string.size(); + + return env->NewString(str, len); +} + +static jboolean com_android_pacprocessor_PacNative_createV8ParserNativeLocked(JNIEnv* env, + jobject) { + if (proxyResolver == NULL) { + logger = new ProxyErrorLogger(); + proxyResolver = new net::ProxyResolverV8(net::ProxyResolverJSBindings::CreateDefault(), + logger); + pacSet = false; + return JNI_FALSE; + } + return JNI_TRUE; +} + +static jboolean com_android_pacprocessor_PacNative_destroyV8ParserNativeLocked(JNIEnv* env, + jobject) { + if (proxyResolver != NULL) { + delete logger; + delete proxyResolver; + logger = NULL; + proxyResolver = NULL; + return JNI_FALSE; + } + return JNI_TRUE; +} + +static jboolean com_android_pacprocessor_PacNative_setProxyScriptNativeLocked(JNIEnv* env, jobject, + jstring script) { + String16 script16 = jstringToString16(env, script); + + if (proxyResolver == NULL) { + ALOGE("V8 Parser not started when setting PAC script"); + return JNI_TRUE; + } + + if (proxyResolver->SetPacScript(script16) != OK) { + ALOGE("Unable to set PAC script"); + return JNI_TRUE; + } + pacSet = true; + + return JNI_FALSE; +} + +static jstring com_android_pacprocessor_PacNative_makeProxyRequestNativeLocked(JNIEnv* env, jobject, + jstring url, jstring host) { + String16 url16 = jstringToString16(env, url); + String16 host16 = jstringToString16(env, host); + String16 ret; + + if (proxyResolver == NULL) { + ALOGE("V8 Parser not initialized when running PAC script"); + return NULL; + } + + if (!pacSet) { + ALOGW("Attempting to run PAC with no script set"); + return NULL; + } + + if (proxyResolver->GetProxyForURL(url16, host16, &ret) != OK) { + String8 ret8(ret); + ALOGE("Error Running PAC: %s", ret8.string()); + return NULL; + } + + jstring jret = string16ToJstring(env, ret); + + return jret; +} + +static JNINativeMethod gMethods[] = { + { "createV8ParserNativeLocked", "()Z", + (void*)com_android_pacprocessor_PacNative_createV8ParserNativeLocked}, + { "destroyV8ParserNativeLocked", "()Z", + (void*)com_android_pacprocessor_PacNative_destroyV8ParserNativeLocked}, + { "setProxyScriptNativeLocked", "(Ljava/lang/String;)Z", + (void*)com_android_pacprocessor_PacNative_setProxyScriptNativeLocked}, + { "makeProxyRequestNativeLocked", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", + (void*)com_android_pacprocessor_PacNative_makeProxyRequestNativeLocked}, +}; + +int register_com_android_pacprocessor_PacNative(JNIEnv* env) { + return jniRegisterNativeMethods(env, "com/android/pacprocessor/PacNative", + gMethods, NELEM(gMethods)); +} + +} /* namespace android */ diff --git a/packages/services/PacProcessor/jni/jni_init.cpp b/packages/services/PacProcessor/jni/jni_init.cpp new file mode 100644 index 0000000..bda33fb --- /dev/null +++ b/packages/services/PacProcessor/jni/jni_init.cpp @@ -0,0 +1,38 @@ +/* + * 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. + */ + +#define LOG_TAG "PacProcessor" + +#include <utils/Log.h> +#include "jni.h" + +namespace android { + extern int register_com_android_pacprocessor_PacNative(JNIEnv *env); +} + +using namespace android; + +extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) { + JNIEnv *env; + if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { + ALOGE("ERROR: GetEnv failed"); + return -1; + } + + register_com_android_pacprocessor_PacNative(env); + + return JNI_VERSION_1_6; +} diff --git a/packages/services/PacProcessor/main_pacserver.cpp b/packages/services/PacProcessor/main_pacserver.cpp deleted file mode 100644 index 19588b5..0000000 --- a/packages/services/PacProcessor/main_pacserver.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#define LOG_TAG "pacserver" -//#define LOG_NDEBUG 0 - -#include <binder/IPCThreadState.h> -#include <binder/ProcessState.h> -#include <binder/IServiceManager.h> -#include <utils/Log.h> -#include "ProxyService.h" -#include "proxy_resolver_v8.h" -#include <stdio.h> - -using namespace android; - -int main(int argc, char** argv) -{ - sp<ProcessState> proc(ProcessState::self()); - sp<IServiceManager> sm = defaultServiceManager(); - - printf("1\n"); - ALOGV("ServiceManager: %p", sm.get()); - ProxyService::instantiate(); - printf("1\n"); - - ProcessState::self()->startThreadPool(); - printf("1\n"); - IPCThreadState::self()->joinThreadPool(); -} diff --git a/packages/services/PacProcessor/res/values/strings.xml b/packages/services/PacProcessor/res/values/strings.xml new file mode 100644 index 0000000..301a2b6 --- /dev/null +++ b/packages/services/PacProcessor/res/values/strings.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <string name="app_name">PacProcessor</string> + +</resources> diff --git a/packages/services/PacProcessor/src/com/android/pacprocessor/PacNative.java b/packages/services/PacProcessor/src/com/android/pacprocessor/PacNative.java new file mode 100644 index 0000000..c67fe9f --- /dev/null +++ b/packages/services/PacProcessor/src/com/android/pacprocessor/PacNative.java @@ -0,0 +1,86 @@ +/** + * 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.pacprocessor; + +import android.util.Log; + +/** + * @hide + */ +public class PacNative { + private static final String TAG = "PacProxy"; + + private String mCurrentPac; + + private boolean mIsActive; + + // Only make native calls from inside synchronized blocks. + private native boolean createV8ParserNativeLocked(); + private native boolean destroyV8ParserNativeLocked(); + + private native boolean setProxyScriptNativeLocked(String script); + + private native String makeProxyRequestNativeLocked(String url, String host); + + static { + System.loadLibrary("jni_pacprocessor"); + } + + PacNative() { + + } + + public synchronized boolean startPacSupport() { + if (createV8ParserNativeLocked()) { + Log.e(TAG, "Unable to Create v8 Proxy Parser."); + return true; + } + mIsActive = true; + return false; + } + + public synchronized boolean stopPacSupport() { + if (mIsActive) { + if (destroyV8ParserNativeLocked()) { + Log.e(TAG, "Unable to Destroy v8 Proxy Parser."); + return true; + } + mIsActive = false; + } + return false; + } + + public synchronized boolean setCurrentProxyScript(String script) { + if (setProxyScriptNativeLocked(script)) { + Log.e(TAG, "Unable to parse proxy script."); + return true; + } + return false; + } + + public synchronized String makeProxyRequest(String url, String host) { + String ret = makeProxyRequestNativeLocked(url, host); + if ((ret == null) || (ret.length() == 0)) { + Log.e(TAG, "v8 Proxy request failed."); + ret = null; + } + return ret; + } + + public synchronized boolean isActive() { + return mIsActive; + } +} diff --git a/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java b/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java new file mode 100644 index 0000000..7e76025 --- /dev/null +++ b/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java @@ -0,0 +1,101 @@ +/** + * 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.pacprocessor; + +import android.app.Service; +import android.content.Intent; +import android.os.Binder; +import android.os.IBinder; +import android.os.Process; +import android.os.RemoteException; +import android.util.Log; + +import com.android.net.IProxyService; + +public class PacService extends Service { + private static final String TAG = "PacService"; + + private PacNative mPacNative; + private ProxyServiceStub mStub; + + @Override + public void onCreate() { + super.onCreate(); + if (mPacNative == null) { + mPacNative = new PacNative(); + mStub = new ProxyServiceStub(mPacNative); + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (mPacNative != null) { + mPacNative.stopPacSupport(); + mPacNative = null; + mStub = null; + } + } + + @Override + public IBinder onBind(Intent intent) { + if (mPacNative == null) { + mPacNative = new PacNative(); + mStub = new ProxyServiceStub(mPacNative); + } + return mStub; + } + + private static class ProxyServiceStub extends IProxyService.Stub { + private final PacNative mPacNative; + + public ProxyServiceStub(PacNative pacNative) { + mPacNative = pacNative; + } + + @Override + public String resolvePacFile(String host, String url) throws RemoteException { + return mPacNative.makeProxyRequest(url, host); + } + + @Override + public void setPacFile(String script) throws RemoteException { + if (Binder.getCallingUid() != Process.SYSTEM_UID) { + Log.e(TAG, "Only system user is allowed to call setPacFile"); + throw new SecurityException(); + } + mPacNative.setCurrentProxyScript(script); + } + + @Override + public void startPacSystem() throws RemoteException { + if (Binder.getCallingUid() != Process.SYSTEM_UID) { + Log.e(TAG, "Only system user is allowed to call startPacSystem"); + throw new SecurityException(); + } + mPacNative.startPacSupport(); + } + + @Override + public void stopPacSystem() throws RemoteException { + if (Binder.getCallingUid() != Process.SYSTEM_UID) { + Log.e(TAG, "Only system user is allowed to call stopPacSystem"); + throw new SecurityException(); + } + mPacNative.stopPacSupport(); + } + } +} diff --git a/packages/services/Proxy/AndroidManifest.xml b/packages/services/Proxy/AndroidManifest.xml index 02475c0..09b8327 100644 --- a/packages/services/Proxy/AndroidManifest.xml +++ b/packages/services/Proxy/AndroidManifest.xml @@ -6,7 +6,6 @@ <uses-permission android:name="android.permission.INTERNET" /> <application - android:persistent="true" android:label="@string/app_label" android:process="com.android.proxyhandler"> diff --git a/packages/services/Proxy/com/android/net/IProxyService.aidl b/packages/services/Proxy/com/android/net/IProxyService.aidl deleted file mode 100644 index 7e9ed79..0000000 --- a/packages/services/Proxy/com/android/net/IProxyService.aidl +++ /dev/null @@ -1,16 +0,0 @@ -package com.android.net; - -/** @hide */ -interface IProxyService -{ - /** - * Keep up-to-date with - * frameworks/base/packages/services/PacProcessor/IProxyService.h - */ - String resolvePacFile(String host, String url); - - int setPacFile(String scriptContents); - - int startPacSystem(); - int stopPacSystem(); -} diff --git a/packages/services/Proxy/src/com/android/proxyhandler/ProxyService.java b/packages/services/Proxy/src/com/android/proxyhandler/ProxyService.java index 0aea5ee..18ed645 100644 --- a/packages/services/Proxy/src/com/android/proxyhandler/ProxyService.java +++ b/packages/services/Proxy/src/com/android/proxyhandler/ProxyService.java @@ -24,24 +24,28 @@ public class ProxyService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { if (intent != null) { - handleCommand(intent); + if (handleCommand(intent)) { + return START_REDELIVER_INTENT; + } } - return START_STICKY; + return START_NOT_STICKY; } - private void handleCommand(Intent intent) { + private boolean handleCommand(Intent intent) { Bundle bundle = intent.getExtras(); ProxyProperties proxy = null; if ((bundle != null) && bundle.containsKey(Proxy.EXTRA_PROXY_INFO)) { proxy = bundle.getParcelable(Proxy.EXTRA_PROXY_INFO); if ((proxy != null) && !TextUtils.isEmpty(proxy.getPacFileUrl())) { startProxy(proxy); + return true; } else { stopSelf(); } } else { stopSelf(); } + return false; } diff --git a/packages/services/Proxy/src/com/android/proxyhandler/ProxyServiceReceiver.java b/packages/services/Proxy/src/com/android/proxyhandler/ProxyServiceReceiver.java index f5c2ca5..4638def 100644 --- a/packages/services/Proxy/src/com/android/proxyhandler/ProxyServiceReceiver.java +++ b/packages/services/Proxy/src/com/android/proxyhandler/ProxyServiceReceiver.java @@ -4,7 +4,9 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.net.Proxy; +import android.net.ProxyProperties; import android.os.Bundle; +import android.text.TextUtils; public class ProxyServiceReceiver extends BroadcastReceiver { @@ -12,11 +14,16 @@ public class ProxyServiceReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { Intent service = new Intent(context, ProxyService.class); Bundle bundle = intent.getExtras(); + ProxyProperties proxy = null; if (bundle != null) { - service.putExtra(Proxy.EXTRA_PROXY_INFO, - bundle.getParcelable(Proxy.EXTRA_PROXY_INFO)); + proxy = bundle.getParcelable(Proxy.EXTRA_PROXY_INFO); + service.putExtra(Proxy.EXTRA_PROXY_INFO, proxy); + } + if ((proxy != null) && (!TextUtils.isEmpty(proxy.getPacFileUrl()))) { + context.startService(service); + } else { + context.stopService(service); } - context.startService(service); } } |