Merge branch 'gingerbread' into gingerbread-release

This commit is contained in:
The Android Automerger
2010-10-18 08:27:25 -07:00
22 changed files with 409 additions and 125 deletions

View File

@@ -16,20 +16,12 @@
package com.android.apps.tag;
import com.android.apps.tag.record.ParsedNdefRecord;
import com.android.apps.tag.record.SmartPoster;
import com.android.apps.tag.record.TextRecord;
import com.android.apps.tag.record.UriRecord;
import com.google.common.collect.Iterables;
import com.google.common.primitives.Bytes;
import android.net.Uri;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import com.google.common.primitives.Bytes;
import java.nio.charset.Charsets;
import java.util.ArrayList;
import java.util.List;
/**
* Utilities for dealing with conversions to and from NdefRecords.
@@ -60,34 +52,4 @@ public class NdefUtil {
return new NdefRecord(NdefRecord.TNF_WELL_KNOWN,
NdefRecord.RTD_URI, EMPTY, payload);
}
public static Iterable<TextRecord> getTextFields(NdefMessage message) {
return Iterables.filter(getObjects(message), TextRecord.class);
}
public static Iterable<UriRecord> getUris(NdefMessage message) {
return Iterables.filter(getObjects(message), UriRecord.class);
}
/**
* Parse the provided {@code NdefMessage}, extracting all known
* objects from the message. Typically this list will consist of
* {@link String}s corresponding to NDEF text records, or {@link Uri}s
* corresponding to NDEF URI records.
* <p>
* TODO: Is this API too generic? Should we keep it?
*/
public static Iterable<ParsedNdefRecord> getObjects(NdefMessage message) {
List<ParsedNdefRecord> retval = new ArrayList<ParsedNdefRecord>();
for (NdefRecord record : message.getRecords()) {
if (UriRecord.isUri(record)) {
retval.add(UriRecord.parse(record));
} else if (TextRecord.isText(record)) {
retval.add(TextRecord.parse(record));
} else if (SmartPoster.isPoster(record)) {
retval.add(SmartPoster.parse(record));
}
}
return retval;
}
}

View File

@@ -16,14 +16,10 @@
package com.android.apps.tag;
import com.android.apps.tag.TagDBHelper.NdefMessagesTable;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.nfc.FormatException;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.LayoutInflater;
@@ -32,9 +28,12 @@ import android.view.ViewGroup;
import android.widget.Adapter;
import android.widget.CursorAdapter;
import android.widget.TextView;
import com.android.apps.tag.record.SmartPoster;
import com.android.apps.tag.record.TextRecord;
import com.android.apps.tag.record.UriRecord;
import com.android.apps.tag.TagDBHelper.NdefMessagesTable;
import com.android.apps.tag.message.NdefMessageParser;
import com.android.apps.tag.message.ParsedNdefMessage;
import java.util.Locale;
/**
* A custom {@link Adapter} that renders tag entries for a list.
@@ -63,23 +62,8 @@ public class TagAdapter extends CursorAdapter {
if (msg == null) {
mainLine.setText("Invalid tag");
} else {
try {
SmartPoster poster = SmartPoster.parse(msg.getRecords()[0]);
TextRecord title = poster.getTitle();
if (title != null) {
mainLine.setText(title.getText());
}
} catch (IllegalArgumentException e) {
// Not a smart poster
NdefRecord record = msg.getRecords()[0];
Uri uri = null;
try {
uri = UriRecord.parse(record).getUri();
mainLine.setText(uri.toString());
} catch (IllegalArgumentException e2) {
mainLine.setText("Not a smart poster or URL");
}
}
ParsedNdefMessage parsedMsg = NdefMessageParser.parse(msg);
mainLine.setText(parsedMsg.getSnippet(Locale.getDefault()));
}
dateLine.setText(DateUtils.getRelativeTimeSpanString(
context, cursor.getLong(cursor.getColumnIndex(NdefMessagesTable.DATE))));

View File

@@ -16,8 +16,6 @@
package com.android.apps.tag;
import com.google.common.annotations.VisibleForTesting;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
@@ -27,6 +25,8 @@ import android.nfc.FormatException;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import com.google.common.annotations.VisibleForTesting;
/**
* Database utilities for the saved tags.
*/

View File

@@ -16,8 +16,6 @@
package com.android.apps.tag;
import com.android.apps.tag.TagDBHelper.NdefMessagesTable;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -35,6 +33,8 @@ import android.view.Menu;
import android.view.View;
import android.widget.ListView;
import com.android.apps.tag.TagDBHelper.NdefMessagesTable;
/**
* An {@link Activity} that displays a flat list of tags that can be "opened".
*/

View File

@@ -30,10 +30,11 @@ import android.view.LayoutInflater;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.apps.tag.record.ParsedNdefRecord;
import com.android.apps.tag.record.SmartPoster;
import com.android.apps.tag.record.TextRecord;
import com.android.apps.tag.record.UriRecord;
import com.android.apps.tag.message.NdefMessageParser;
import com.android.apps.tag.message.ParsedNdefMessage;
import java.util.Locale;
/**
* An {@link Activity} which handles a broadcast of a new tag that the device just discovered.
@@ -93,35 +94,11 @@ public class TagViewer extends Activity {
// The body of the dialog should use the light theme
// Build the views from the logical records in the messages
boolean first = true;
for (NdefMessage msg : msgs) {
Iterable<ParsedNdefRecord> objects = NdefUtil.getObjects(msg);
for (ParsedNdefRecord object : objects) {
if (!first) {
list.addView(inflater.inflate(R.layout.tag_divider, list, false));
first = false;
}
if (object instanceof TextRecord) {
TextRecord textRecord = (TextRecord) object;
ParsedNdefMessage parsedMsg = NdefMessageParser.parse(msg);
TextView text = (TextView) inflater.inflate(R.layout.tag_text, list, false);
text.setText(textRecord.getText());
text.setText(parsedMsg.getSnippet(Locale.getDefault()));
list.addView(text);
} else if (object instanceof UriRecord) {
UriRecord uriRecord = (UriRecord) object;
TextView text = (TextView) inflater.inflate(R.layout.tag_text, list, false);
text.setText(uriRecord.getUri().toString());
list.addView(text);
} else if (object instanceof SmartPoster) {
TextView text = (TextView) inflater.inflate(R.layout.tag_text, list, false);
SmartPoster poster = (SmartPoster) object;
TextRecord title = poster.getTitle();
if (title != null) {
text.setText(title.getText());
}
list.addView(text);
}
}
}
}

View File

@@ -0,0 +1,37 @@
/*
* 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.
*/
package com.android.apps.tag.message;
import java.util.Locale;
/**
* A parsed message containing no elements.
*/
class EmptyMessage implements ParsedNdefMessage {
/* package private */ EmptyMessage() { }
@Override
public String getSnippet(Locale locale) {
return "Empty Tag"; // TODO: localize
}
@Override
public boolean isStarred() {
return false;
}
}

View File

@@ -0,0 +1,76 @@
/*
* 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.
*/
package com.android.apps.tag.message;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import com.android.apps.tag.record.ParsedNdefRecord;
import com.android.apps.tag.record.SmartPoster;
import com.android.apps.tag.record.TextRecord;
import com.android.apps.tag.record.UriRecord;
import java.util.ArrayList;
import java.util.List;
/**
* Utility class for creating {@link ParsedNdefMessage}s.
*/
public class NdefMessageParser {
// Utility class
private NdefMessageParser() { }
/** Parse an NdefMessage */
public static ParsedNdefMessage parse(NdefMessage message) {
List<ParsedNdefRecord> elements = getRecords(message);
if (elements.isEmpty()) {
return new EmptyMessage();
}
ParsedNdefRecord first = elements.get(0);
if (elements.size() == 1) {
if (first instanceof SmartPoster) {
return new SmartPosterMessage((SmartPoster) first);
}
if (first instanceof TextRecord) {
return new TextMessage((TextRecord) first);
}
if (first instanceof UriRecord) {
return new UriMessage((UriRecord) first);
}
}
return new UnknownMessage(elements);
}
public static List<ParsedNdefRecord> getRecords(NdefMessage message) {
List<ParsedNdefRecord> elements = new ArrayList<ParsedNdefRecord>();
for (NdefRecord record : message.getRecords()) {
if (UriRecord.isUri(record)) {
elements.add(UriRecord.parse(record));
} else if (TextRecord.isText(record)) {
elements.add(TextRecord.parse(record));
} else if (SmartPoster.isPoster(record)) {
elements.add(SmartPoster.parse(record));
}
}
return elements;
}
}

View File

@@ -0,0 +1,35 @@
/*
* 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.
*/
package com.android.apps.tag.message;
import java.util.Locale;
/**
* A parsed version of an {@link android.nfc.NdefMessage}
*/
public interface ParsedNdefMessage {
/**
* Returns the snippet information associated with the NdefMessage
* most appropriate for the given {@code locale}.
*/
public String getSnippet(Locale locale);
// TODO: Determine if this is the best place for holding whether
// the user has starred this parsed message.
public boolean isStarred();
}

View File

@@ -0,0 +1,48 @@
/*
* 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.
*/
package com.android.apps.tag.message;
import com.android.apps.tag.record.SmartPoster;
import com.android.apps.tag.record.TextRecord;
import com.google.common.base.Preconditions;
import java.util.Locale;
/**
* A message consisting of one {@link SmartPoster} object.
*/
class SmartPosterMessage implements ParsedNdefMessage {
private final SmartPoster mPoster;
SmartPosterMessage(SmartPoster poster) {
mPoster = Preconditions.checkNotNull(poster);
}
@Override
public String getSnippet(Locale locale) {
TextRecord title = mPoster.getTitle();
if (title == null) {
return mPoster.getUriRecord().getUri().toString();
}
return title.getText();
}
@Override
public boolean isStarred() {
return false;
}
}

View File

@@ -0,0 +1,43 @@
/*
* 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.
*/
package com.android.apps.tag.message;
import com.android.apps.tag.record.TextRecord;
import com.google.common.base.Preconditions;
import java.util.Locale;
/**
* A message containing one text element
*/
class TextMessage implements ParsedNdefMessage {
private final TextRecord mRecord;
TextMessage(TextRecord record) {
mRecord = Preconditions.checkNotNull(record);
}
@Override
public String getSnippet(Locale locale) {
return mRecord.getText();
}
@Override
public boolean isStarred() {
return false;
}
}

View File

@@ -0,0 +1,45 @@
/*
* 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.
*/
package com.android.apps.tag.message;
import com.android.apps.tag.record.ParsedNdefRecord;
import com.google.common.collect.ImmutableList;
import java.util.Locale;
/**
* The catchall parsed message format for when nothing else better applies.
*/
class UnknownMessage implements ParsedNdefMessage {
private final ImmutableList<ParsedNdefRecord> mRecords;
UnknownMessage(Iterable<ParsedNdefRecord> records) {
mRecords = ImmutableList.copyOf(records);
}
@Override
public String getSnippet(Locale locale) {
// TODO: localize
return "Unknown record type with " + mRecords.size() + " elements.";
}
@Override
public boolean isStarred() {
return false;
}
}

View File

@@ -0,0 +1,45 @@
/*
* 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.
*/
package com.android.apps.tag.message;
import com.android.apps.tag.record.UriRecord;
import com.google.common.base.Preconditions;
import java.util.Locale;
/**
* A {@link ParsedNdefMessage} consisting of one {@link UriRecord}.
*/
class UriMessage implements ParsedNdefMessage {
private final UriRecord mRecord;
UriMessage(UriRecord record) {
mRecord = Preconditions.checkNotNull(record);
}
@Override
public String getSnippet(Locale locale) {
// URIs cannot be localized
return mRecord.getUri().toString();
}
@Override
public boolean isStarred() {
return false;
}
}

View File

@@ -16,16 +16,16 @@
package com.android.apps.tag.record;
import com.android.apps.tag.NdefUtil;
import com.google.common.base.Preconditions;
import com.google.common.collect.Iterables;
import android.nfc.FormatException;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import java.util.Arrays;
import com.android.apps.tag.message.NdefMessageParser;
import com.google.common.base.Preconditions;
import com.google.common.collect.Iterables;
import java.util.Arrays;
import java.util.NoSuchElementException;
import javax.annotation.Nullable;
/**
@@ -73,8 +73,12 @@ public class SmartPoster implements ParsedNdefRecord {
Preconditions.checkArgument(Arrays.equals(record.getType(), NdefRecord.RTD_SMART_POSTER));
try {
NdefMessage subRecords = new NdefMessage(record.getPayload());
UriRecord uri = Iterables.getOnlyElement(NdefUtil.getUris(subRecords));
Iterable<TextRecord> textFields = NdefUtil.getTextFields(subRecords);
Iterable<ParsedNdefRecord> records = NdefMessageParser.getRecords(subRecords);
UriRecord uri = Iterables.getOnlyElement(Iterables.filter(records, UriRecord.class));
Iterable<TextRecord> textFields = Iterables.filter(records, TextRecord.class);
TextRecord title = null;
if (!Iterables.isEmpty(textFields)) {
title = Iterables.get(textFields, 0);
@@ -83,6 +87,8 @@ public class SmartPoster implements ParsedNdefRecord {
return new SmartPoster(uri, title);
} catch (FormatException e) {
throw new IllegalArgumentException(e);
} catch (NoSuchElementException e) {
throw new IllegalArgumentException(e);
}
}

View File

@@ -17,6 +17,7 @@
package com.android.apps.tag.record;
import android.nfc.NdefRecord;
import com.google.common.base.Preconditions;
import java.io.UnsupportedEncodingException;
@@ -27,6 +28,7 @@ import java.util.Arrays;
*/
public class TextRecord implements ParsedNdefRecord {
/** ISO/IANA language code */
private final String mLanguageCode;
private final String mText;
@@ -44,6 +46,11 @@ public class TextRecord implements ParsedNdefRecord {
return mText;
}
/**
* Returns the ISO/IANA language code associated with this text element.
*
* TODO: this should return a {@link java.util.Locale}
*/
public String getLanguageCode() {
return mLanguageCode;
}

View File

@@ -18,6 +18,7 @@ package com.android.apps.tag.record;
import android.net.Uri;
import android.nfc.NdefRecord;
import com.google.common.base.Preconditions;
import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableBiMap;

View File

@@ -16,10 +16,11 @@
package com.android.apps.tag;
import android.nfc.NdefRecord;
import android.test.AndroidTestCase;
import com.android.apps.tag.record.TextRecord;
import com.google.common.primitives.Bytes;
import android.nfc.NdefRecord;
import java.io.UnsupportedEncodingException;

View File

@@ -16,8 +16,9 @@
package com.android.apps.tag;
import android.test.AndroidTestCase;
import android.nfc.NdefMessage;
import android.test.AndroidTestCase;
import com.android.apps.tag.record.SmartPoster;
/**

View File

@@ -1,4 +0,0 @@
// Temporary until the NDK build system can deal with there being no Java source.
class Dummy {
}

View File

@@ -99,21 +99,27 @@
</LinearLayout>
<LinearLayout android:orientation="horizontal" android:gravity="center"
android:layout_width="match_parent" android:layout_height="wrap_content">
<Button android:id="@+id/force_lock"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_weight="0"
android:text="@string/force_lock">
</Button>
<LinearLayout android:orientation="horizontal" android:gravity="center"
android:layout_width="match_parent" android:layout_height="wrap_content">
<Button android:id="@+id/wipe_data"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_weight="0"
android:text="@string/wipe_data">
</Button>
<Button android:id="@+id/wipe_all_data"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_weight="0"
android:text="@string/wipe_all_data">
</Button>
</LinearLayout>
<LinearLayout android:orientation="horizontal" android:gravity="center"

View File

@@ -479,6 +479,7 @@
<string name="max_failed_pw_hint">Password Attempts Wipe Data</string>
<string name="force_lock">Force Lock</string>
<string name="wipe_data">Wipe Data</string>
<string name="wipe_all_data">Wipe All Data</string>
<string name="timeout_hint">Max screen timeout</string>
<string name="set_timeout_label">Set Timeout</string>

View File

@@ -128,6 +128,7 @@ public class DeviceAdminSample extends DeviceAdminReceiver {
Button mForceLockButton;
Button mWipeDataButton;
Button mWipeAllDataButton;
private Button mTimeoutButton;
@@ -208,6 +209,8 @@ public class DeviceAdminSample extends DeviceAdminReceiver {
mForceLockButton.setOnClickListener(mForceLockListener);
mWipeDataButton = (Button)findViewById(R.id.wipe_data);
mWipeDataButton.setOnClickListener(mWipeDataListener);
mWipeAllDataButton = (Button)findViewById(R.id.wipe_all_data);
mWipeAllDataButton.setOnClickListener(mWipeDataListener);
mTimeout = (EditText) findViewById(R.id.timeout);
mTimeoutButton = (Button) findViewById(R.id.set_timeout);
@@ -226,6 +229,7 @@ public class DeviceAdminSample extends DeviceAdminReceiver {
mResetPasswordButton.setEnabled(true);
mForceLockButton.setEnabled(true);
mWipeDataButton.setEnabled(true);
mWipeAllDataButton.setEnabled(true);
} else {
mEnableButton.setEnabled(true);
mDisableButton.setEnabled(false);
@@ -236,6 +240,7 @@ public class DeviceAdminSample extends DeviceAdminReceiver {
mResetPasswordButton.setEnabled(false);
mForceLockButton.setEnabled(false);
mWipeDataButton.setEnabled(false);
mWipeAllDataButton.setEnabled(false);
}
}
@@ -372,7 +377,7 @@ public class DeviceAdminSample extends DeviceAdminReceiver {
};
private OnClickListener mWipeDataListener = new OnClickListener() {
public void onClick(View v) {
public void onClick(final View v) {
if (mAM.isUserAMonkey()) {
// Don't trust monkeys to do the right thing!
AlertDialog.Builder builder = new AlertDialog.Builder(Controller.this);
@@ -386,14 +391,22 @@ public class DeviceAdminSample extends DeviceAdminReceiver {
builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
AlertDialog.Builder builder = new AlertDialog.Builder(Controller.this);
if (v == mWipeAllDataButton) {
builder.setMessage("This is not a test. "
+ "This WILL erase all of your data, "
+ "including external storage! "
+ "Are you really absolutely sure?");
} else {
builder.setMessage("This is not a test. "
+ "This WILL erase all of your data! "
+ "Are you really absolutely sure?");
}
builder.setPositiveButton("BOOM!", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
boolean active = mDPM.isAdminActive(mDeviceAdminSample);
if (active) {
mDPM.wipeData(0);
mDPM.wipeData(v == mWipeAllDataButton
? DevicePolicyManager.WIPE_EXTERNAL_STORAGE : 0);
}
}
});

View File

@@ -1,5 +1,5 @@
Pkg.UserSrc=false
Pkg.Revision=1
AndroidVersion.ApiLevel=8
#AndroidVersion.CodeName=
AndroidVersion.CodeName=gingerbread