Merge "Increase string lengths for localization." into klp-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 493d7f4..653290d 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1621,15 +1621,10 @@
android:resource="@id/nfc_payment_settings" />
</activity>
<activity android:name=".nfc.PaymentDefaultDialog"
- android:label="@string/nfc_payment_set_default"
+ android:label="@string/nfc_payment_set_default_label"
android:excludeFromRecents="true"
android:theme="@*android:style/Theme.Holo.Light.Dialog.Alert">
<intent-filter>
- <!-- TODO this filter can be removed -->
- <action android:name="android.nfc.cardemulation.ACTION_CHANGE_DEFAULT" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- <intent-filter>
<action android:name="android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
@@ -1691,5 +1686,14 @@
</intent-filter>
</receiver>
+ <provider
+ android:name="android.support.v4.content.FileProvider"
+ android:authorities="com.android.settings.files"
+ android:grantUriPermissions="true"
+ android:exported="false">
+ <meta-data
+ android:name="android.support.FILE_PROVIDER_PATHS"
+ android:resource="@xml/file_paths" />
+ </provider>
</application>
</manifest>
diff --git a/res/drawable-hdpi/nfc_payment_empty_state.png b/res/drawable-hdpi/nfc_payment_empty_state.png
new file mode 100644
index 0000000..69b22f2
--- /dev/null
+++ b/res/drawable-hdpi/nfc_payment_empty_state.png
Binary files differ
diff --git a/res/drawable-mdpi/nfc_payment_empty_state.png b/res/drawable-mdpi/nfc_payment_empty_state.png
new file mode 100644
index 0000000..1ab7187
--- /dev/null
+++ b/res/drawable-mdpi/nfc_payment_empty_state.png
Binary files differ
diff --git a/res/drawable-xhdpi/nfc_payment_empty_state.png b/res/drawable-xhdpi/nfc_payment_empty_state.png
new file mode 100644
index 0000000..3951c82
--- /dev/null
+++ b/res/drawable-xhdpi/nfc_payment_empty_state.png
Binary files differ
diff --git a/res/drawable-xxhdpi/nfc_payment_empty_state.png b/res/drawable-xxhdpi/nfc_payment_empty_state.png
new file mode 100644
index 0000000..914021a
--- /dev/null
+++ b/res/drawable-xxhdpi/nfc_payment_empty_state.png
Binary files differ
diff --git a/res/layout/nfc_payment.xml b/res/layout/nfc_payment.xml
new file mode 100644
index 0000000..92fe86f
--- /dev/null
+++ b/res/layout/nfc_payment.xml
@@ -0,0 +1,33 @@
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:orientation="vertical" >
+ <TextView
+ android:id="@+id/nfc_payment_empty_text"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:textSize="24sp"
+ android:visibility="gone"
+ android:paddingBottom="16dp"
+ android:text="@string/nfc_payment_no_apps"/>
+ <ImageView
+ android:id="@+id/nfc_payment_tap_image"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:visibility="gone"
+ android:src="@drawable/nfc_payment_empty_state"/>
+ </LinearLayout>
+ <ListView
+ android:id="@android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginTop="5dp" />
+
+</FrameLayout>
diff --git a/res/layout/nfc_payment_option.xml b/res/layout/nfc_payment_option.xml
index 122e041..04fdc07 100644
--- a/res/layout/nfc_payment_option.xml
+++ b/res/layout/nfc_payment_option.xml
@@ -13,7 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -21,53 +21,24 @@
android:focusable="true"
android:clickable="true"
android:gravity="center_vertical"
+ android:paddingTop="10dp"
+ android:paddingBottom="10dp"
android:minHeight="?android:attr/listPreferredItemHeight"
android:background="?android:attr/selectableItemBackground">
- <LinearLayout
+ <FrameLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:minWidth="@*android:dimen/preference_icon_minWidth"
android:orientation="horizontal">
<ImageView
- android:id="@+android:id/icon"
- android:layout_width="48dp"
- android:layout_height="48dp"
+ android:id="@+id/banner"
android:layout_gravity="center"
- android:minWidth="48dp"
+ android:layout_width="wrap_content"
+ android:layout_height="96dp"
android:scaleType="centerInside"
- android:layout_marginEnd="@*android:dimen/preference_item_padding_inner"
/>
- </LinearLayout>
- <RelativeLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginEnd="6dip"
- android:layout_marginTop="6dip"
- android:layout_marginBottom="6dip"
- android:layout_weight="1">
- <TextView
- android:id="@+android:id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal"/>
- <TextView
- android:id="@android:id/summary"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@android:id/title"
- android:layout_alignStart="@android:id/title"
- android:paddingBottom="3dip"
- android:visibility="gone"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textSize="13sp"
- android:textColor="?android:attr/textColorSecondary"
- android:focusable="false"
- android:maxLines="4" />
- </RelativeLayout>
+ </FrameLayout>
<RadioButton
android:id="@android:id/button1"
android:layout_width="wrap_content"
@@ -77,4 +48,4 @@
android:duplicateParentState="true"
android:clickable="false"
android:focusable="false" />
-</LinearLayout>
+</RelativeLayout>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 0e02af8..a4de070 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -658,15 +658,15 @@
<item>Post notification</item>
<item>Location</item>
<item>Call phone</item>
- <item>Receive SMS/MMS</item>
- <item>Send SMS/MMS</item>
+ <item>Read SMS/MMS</item>
+ <item>Write SMS/MMS</item>
<item>Receive SMS/MMS</item>
<item>Receive SMS/MMS</item>
<item>Receive SMS/MMS</item>
<item>Receive SMS/MMS</item>
<item>Send SMS/MMS</item>
- <item>Receive SMS/MMS</item>
- <item>Send SMS/MMS</item>
+ <item>Read SMS/MMS</item>
+ <item>Write SMS/MMS</item>
<item>Modify settings</item>
<item>Draw on top</item>
<item>Access notifications</item>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 8a0566a..8ffa17f 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -4678,13 +4678,13 @@
<!-- NFC payment settings --><skip/>
<string name="nfc_payment_settings_title">Payments</string>
- <!-- Option to tell Android to ask the user which payment app to use every time
- a payment terminal is tapped -->
- <string name="nfc_payment_ask">Ask every time</string>
+ <!-- String shown when there are no NFC payment applications installed -->
+ <string name="nfc_payment_no_apps">DO NOT TRANSLATE ME</string>
<!-- Label for the dialog that is shown when the user is asked to set a
preferred payment application -->
- <string name="nfc_payment_set_default">Set as your preference?</string>
-
+ <string name="nfc_payment_set_default_label">Set as your preference?</string>
+ <string name="nfc_payment_set_default">Always use <xliff:g id="app">%1$s</xliff:g> when you tap and pay?</string>
+ <string name="nfc_payment_set_default_instead_of">Always use <xliff:g id="app">%1$s</xliff:g> instead of <xliff:g id="app">%2$s</xliff:g> when you tap and pay?</string>
<!-- Restrictions settings --><skip/>
<!-- Restriction settings title [CHAR LIMIT=35] -->
diff --git a/res/xml/file_paths.xml b/res/xml/file_paths.xml
new file mode 100644
index 0000000..294c0cb
--- /dev/null
+++ b/res/xml/file_paths.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<paths xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- Offer access to files under Context.getCacheDir() -->
+ <cache-path name="my_cache" />
+</paths>
diff --git a/src/com/android/settings/nfc/PaymentBackend.java b/src/com/android/settings/nfc/PaymentBackend.java
index e2f110f..59f4ddf 100644
--- a/src/com/android/settings/nfc/PaymentBackend.java
+++ b/src/com/android/settings/nfc/PaymentBackend.java
@@ -33,7 +33,7 @@
public static class PaymentAppInfo {
CharSequence caption;
- Drawable icon;
+ Drawable banner;
boolean isDefault;
public ComponentName componentName;
}
@@ -62,7 +62,7 @@
for (ApduServiceInfo service : serviceInfos) {
PaymentAppInfo appInfo = new PaymentAppInfo();
appInfo.caption = service.loadLabel(pm);
- appInfo.icon = service.loadIcon(pm);
+ appInfo.banner = service.loadBanner(pm);
appInfo.isDefault = service.getComponent().equals(defaultApp);
appInfo.componentName = service.getComponent();
appInfos.add(appInfo);
diff --git a/src/com/android/settings/nfc/PaymentDefaultDialog.java b/src/com/android/settings/nfc/PaymentDefaultDialog.java
index ae2f4c1..538af2e 100644
--- a/src/com/android/settings/nfc/PaymentDefaultDialog.java
+++ b/src/com/android/settings/nfc/PaymentDefaultDialog.java
@@ -125,12 +125,15 @@
// Compose dialog; get
final AlertController.AlertParams p = mAlertParams;
- p.mTitle = getString(R.string.nfc_payment_set_default);
+ p.mTitle = getString(R.string.nfc_payment_set_default_label);
if (defaultAppInfo == null) {
- p.mMessage = "Always use " + newAppInfo.loadLabel(pm) + " when you tap and pay?";
+ String formatString = getString(R.string.nfc_payment_set_default);
+ String msg = String.format(formatString, newAppInfo.loadLabel(pm));
+ p.mMessage = msg;
} else {
- p.mMessage = "Always use " + newAppInfo.loadLabel(pm) + " instead of " +
- defaultAppInfo.loadLabel(pm) + " when you tap and pay?";
+ String formatString = getString(R.string.nfc_payment_set_default_instead_of);
+ String msg = String.format(formatString, newAppInfo.loadLabel(pm), defaultAppInfo.loadLabel(pm));
+ p.mMessage = msg;
}
p.mPositiveButtonText = getString(R.string.yes);
p.mNegativeButtonText = getString(R.string.no);
diff --git a/src/com/android/settings/nfc/PaymentSettings.java b/src/com/android/settings/nfc/PaymentSettings.java
index af569ac..d3ccbaf 100644
--- a/src/com/android/settings/nfc/PaymentSettings.java
+++ b/src/com/android/settings/nfc/PaymentSettings.java
@@ -21,9 +21,14 @@
import android.preference.Preference;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
+import android.util.Log;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.ImageView;
import android.widget.RadioButton;
+import android.widget.TextView;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
@@ -34,14 +39,17 @@
public class PaymentSettings extends SettingsPreferenceFragment implements
OnClickListener {
public static final String TAG = "PaymentSettings";
+ private LayoutInflater mInflater;
private PaymentBackend mPaymentBackend;
+
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setHasOptionsMenu(false);
mPaymentBackend = new PaymentBackend(getActivity());
+ mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public void refresh() {
@@ -55,12 +63,35 @@
for (PaymentAppInfo appInfo : appInfos) {
PaymentAppPreference preference =
new PaymentAppPreference(getActivity(), appInfo, this);
- preference.setIcon(appInfo.icon);
preference.setTitle(appInfo.caption);
- screen.addPreference(preference);
+ if (appInfo.banner != null) {
+ screen.addPreference(preference);
+ } else {
+ // Ignore, no banner
+ Log.e(TAG, "Couldn't load banner drawable of service " + appInfo.componentName);
+ }
}
}
- setPreferenceScreen(screen);
+ TextView emptyText = (TextView) getView().findViewById(R.id.nfc_payment_empty_text);
+ ImageView emptyImage = (ImageView) getView().findViewById(R.id.nfc_payment_tap_image);
+ if (screen.getPreferenceCount() == 0) {
+ emptyText.setVisibility(View.VISIBLE);
+ emptyImage.setVisibility(View.VISIBLE);
+ } else {
+ emptyText.setVisibility(View.GONE);
+ emptyImage.setVisibility(View.GONE);
+ setPreferenceScreen(screen);
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ super.onCreateView(inflater, container, savedInstanceState);
+
+ View v = mInflater.inflate(R.layout.nfc_payment, container, false);
+
+ return v;
}
@Override
@@ -101,6 +132,9 @@
RadioButton radioButton = (RadioButton) view.findViewById(android.R.id.button1);
radioButton.setChecked(appInfo.isDefault);
+
+ ImageView banner = (ImageView) view.findViewById(R.id.banner);
+ banner.setImageDrawable(appInfo.banner);
}
}
}
\ No newline at end of file
diff --git a/src/com/android/settings/users/RestrictedProfileSettings.java b/src/com/android/settings/users/RestrictedProfileSettings.java
index 99e55ab..73b49bf 100644
--- a/src/com/android/settings/users/RestrictedProfileSettings.java
+++ b/src/com/android/settings/users/RestrictedProfileSettings.java
@@ -20,6 +20,7 @@
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.Fragment;
+import android.content.ClipData;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@@ -27,14 +28,20 @@
import android.content.pm.UserInfo;
import android.database.Cursor;
import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.MediaStore;
import android.provider.ContactsContract.DisplayPhoto;
+import android.support.v4.content.FileProvider;
import android.text.TextUtils;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -51,6 +58,8 @@
import com.android.settings.R;
import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
@@ -58,6 +67,7 @@
private static final String KEY_SAVED_PHOTO = "pending_photo";
private static final int DIALOG_ID_EDIT_USER_INFO = 1;
+ public static final String FILE_PROVIDER_AUTHORITY = "com.android.settings.files";
private View mHeaderView;
private ImageView mUserIconView;
@@ -269,33 +279,20 @@
mNewUserPhotoDrawable = drawable;
}
- public boolean onActivityResult(int requestCode, int resultCode, final Intent data) {
+ public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != Activity.RESULT_OK) {
return false;
}
+ final Uri pictureUri = data != null && data.getData() != null
+ ? data.getData() : mTakePictureUri;
switch (requestCode) {
+ case REQUEST_CODE_CROP_PHOTO:
+ onPhotoCropped(pictureUri, true);
+ return true;
+ case REQUEST_CODE_TAKE_PHOTO:
case REQUEST_CODE_CHOOSE_PHOTO:
- case REQUEST_CODE_CROP_PHOTO: {
- new AsyncTask<Void, Void, Bitmap>() {
- @Override
- protected Bitmap doInBackground(Void... params) {
- return BitmapFactory.decodeFile(mCropPictureUri.getPath());
- }
- @Override
- protected void onPostExecute(Bitmap bitmap) {
- mNewUserPhotoBitmap = bitmap;
- mNewUserPhotoDrawable = CircleFramedDrawable
- .getInstance(mImageView.getContext(), mNewUserPhotoBitmap);
- mImageView.setImageDrawable(mNewUserPhotoDrawable);
- // Delete the files - not needed anymore.
- new File(mCropPictureUri.getPath()).delete();
- new File(mTakePictureUri.getPath()).delete();
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
- } return true;
- case REQUEST_CODE_TAKE_PHOTO: {
- cropPhoto();
- } break;
+ cropPhoto(pictureUri);
+ return true;
}
return false;
}
@@ -380,24 +377,35 @@
private void takePhoto() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
- intent.putExtra(MediaStore.EXTRA_OUTPUT, mTakePictureUri);
+ appendOutputExtra(intent, mTakePictureUri);
mFragment.startActivityForResult(intent, REQUEST_CODE_TAKE_PHOTO);
}
private void choosePhoto() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
intent.setType("image/*");
- intent.putExtra(MediaStore.EXTRA_OUTPUT, mCropPictureUri);
- appendCropExtras(intent);
+ appendOutputExtra(intent, mTakePictureUri);
mFragment.startActivityForResult(intent, REQUEST_CODE_CHOOSE_PHOTO);
}
- private void cropPhoto() {
+ private void cropPhoto(Uri pictureUri) {
+ // TODO: Use a public intent, when there is one.
Intent intent = new Intent("com.android.camera.action.CROP");
- intent.setDataAndType(mTakePictureUri, "image/*");
- intent.putExtra(MediaStore.EXTRA_OUTPUT, mCropPictureUri);
+ intent.setDataAndType(pictureUri, "image/*");
+ appendOutputExtra(intent, mCropPictureUri);
appendCropExtras(intent);
- mFragment.startActivityForResult(intent, REQUEST_CODE_CROP_PHOTO);
+ if (intent.resolveActivity(mContext.getPackageManager()) != null) {
+ mFragment.startActivityForResult(intent, REQUEST_CODE_CROP_PHOTO);
+ } else {
+ onPhotoCropped(pictureUri, false);
+ }
+ }
+
+ private void appendOutputExtra(Intent intent, Uri pictureUri) {
+ intent.putExtra(MediaStore.EXTRA_OUTPUT, pictureUri);
+ intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+ | Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ intent.setClipData(ClipData.newRawUri(MediaStore.EXTRA_OUTPUT, pictureUri));
}
private void appendCropExtras(Intent intent) {
@@ -410,6 +418,63 @@
intent.putExtra("outputY", mPhotoSize);
}
+ private void onPhotoCropped(final Uri data, final boolean cropped) {
+ new AsyncTask<Void, Void, Bitmap>() {
+ @Override
+ protected Bitmap doInBackground(Void... params) {
+ if (cropped) {
+ try {
+ InputStream imageStream = mContext.getContentResolver()
+ .openInputStream(data);
+ return BitmapFactory.decodeStream(imageStream);
+ } catch (FileNotFoundException fe) {
+ return null;
+ }
+ } else {
+ // Scale and crop to a square aspect ratio
+ Bitmap croppedImage = Bitmap.createBitmap(mPhotoSize, mPhotoSize,
+ Config.ARGB_8888);
+ Canvas canvas = new Canvas(croppedImage);
+ Bitmap fullImage = null;
+ try {
+ InputStream imageStream = mContext.getContentResolver()
+ .openInputStream(data);
+ fullImage = BitmapFactory.decodeStream(imageStream);
+ } catch (FileNotFoundException fe) {
+ return null;
+ }
+ if (fullImage != null) {
+ final int squareSize = Math.min(fullImage.getWidth(),
+ fullImage.getHeight());
+ final int left = (fullImage.getWidth() - squareSize) / 2;
+ final int top = (fullImage.getHeight() - squareSize) / 2;
+ Rect rectSource = new Rect(left, top,
+ left + squareSize, top + squareSize);
+ Rect rectDest = new Rect(0, 0, mPhotoSize, mPhotoSize);
+ Paint paint = new Paint();
+ canvas.drawBitmap(fullImage, rectSource, rectDest, paint);
+ return croppedImage;
+ } else {
+ // Bah! Got nothin.
+ return null;
+ }
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Bitmap bitmap) {
+ if (bitmap != null) {
+ mNewUserPhotoBitmap = bitmap;
+ mNewUserPhotoDrawable = CircleFramedDrawable
+ .getInstance(mImageView.getContext(), mNewUserPhotoBitmap);
+ mImageView.setImageDrawable(mNewUserPhotoDrawable);
+ }
+ new File(mContext.getCacheDir(), TAKE_PICTURE_FILE_NAME).delete();
+ new File(mContext.getCacheDir(), CROP_PICTURE_FILE_NAME).delete();
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
+ }
+
private static int getPhotoSize(Context context) {
Cursor cursor = context.getContentResolver().query(
DisplayPhoto.CONTENT_MAX_DIMENSIONS_URI,
@@ -423,11 +488,13 @@
}
private static Uri createTempImageUri(Context context, String fileName) {
- File folder = context.getExternalCacheDir();
+ final File folder = context.getCacheDir();
folder.mkdirs();
- File fullPath = new File(folder, fileName);
+ final File fullPath = new File(folder, fileName);
fullPath.delete();
- return Uri.fromFile(fullPath.getAbsoluteFile());
+ final Uri fileUri =
+ FileProvider.getUriForFile(context, FILE_PROVIDER_AUTHORITY, fullPath);
+ return fileUri;
}
private static final class AdapterItem {