diff options
-rw-r--r-- | core/java/android/provider/Contacts.java | 9 | ||||
-rw-r--r-- | core/java/android/provider/ContactsContract.java | 35 | ||||
-rw-r--r-- | core/java/com/android/internal/widget/ContactHeaderWidget.java | 349 | ||||
-rw-r--r-- | core/res/res/drawable/contact_header_bg.9.png | bin | 0 -> 231 bytes | |||
-rw-r--r-- | core/res/res/drawable/contact_picture_bg.9.png | bin | 0 -> 1699 bytes | |||
-rw-r--r-- | core/res/res/drawable/ic_contact_picture_2.png | bin | 0 -> 1894 bytes | |||
-rw-r--r-- | core/res/res/drawable/ic_contact_picture_3.png | bin | 0 -> 1364 bytes | |||
-rw-r--r-- | core/res/res/layout-ja/contact_header_name.xml | 39 | ||||
-rw-r--r-- | core/res/res/layout/contact_header.xml | 56 | ||||
-rw-r--r-- | core/res/res/layout/contact_header_name.xml | 26 | ||||
-rw-r--r-- | keystore/java/android/security/CertTool.java | 6 | ||||
-rw-r--r-- | packages/VpnServices/src/com/android/server/vpn/VpnService.java | 23 | ||||
-rw-r--r-- | telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java | 48 | ||||
-rw-r--r-- | telephony/java/com/android/internal/telephony/cdma/sms/UserData.java | 29 | ||||
-rw-r--r-- | vpn/java/android/net/vpn/VpnManager.java | 2 |
15 files changed, 539 insertions, 83 deletions
diff --git a/core/java/android/provider/Contacts.java b/core/java/android/provider/Contacts.java index 5f84e5778522..c0dbf4d69529 100644 --- a/core/java/android/provider/Contacts.java +++ b/core/java/android/provider/Contacts.java @@ -1523,6 +1523,15 @@ public class Contacts { ContactsContract.Intents.EXTRA_CREATE_DESCRIPTION; /** + * Optional extra used with {@link #SHOW_OR_CREATE_CONTACT} to specify a + * dialog location using screen coordinates. When not specified, the + * dialog will be centered. + * + * @hide pending API council review + */ + public static final String EXTRA_TARGET_RECT = ContactsContract.Intents.EXTRA_TARGET_RECT; + + /** * Intents related to the Contacts app UI. */ public static final class UI { diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index 01189fe8cf43..227c675530cc 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -1009,6 +1009,8 @@ public final class ContactsContract { public static final String PROTOCOL = "data5"; + public static final String CUSTOM_PROTOCOL = "data6"; + /** * The predefined IM protocol types. The protocol can either be non-present, one * of these types, or a free-form string. These cases are encoded in the PROTOCOL @@ -1019,6 +1021,7 @@ public final class ContactsContract { * <li>custom:<a string></li> * </ul> */ + public static final int PROTOCOL_CUSTOM = -1; public static final int PROTOCOL_AIM = 0; public static final int PROTOCOL_MSN = 1; public static final int PROTOCOL_YAHOO = 2; @@ -1027,31 +1030,6 @@ public final class ContactsContract { public static final int PROTOCOL_GOOGLE_TALK = 5; public static final int PROTOCOL_ICQ = 6; public static final int PROTOCOL_JABBER = 7; - - public static String encodePredefinedImProtocol(int protocol) { - return "pre:" + protocol; - } - - public static String encodeCustomImProtocol(String protocolString) { - return "custom:" + protocolString; - } - - public static Object decodeImProtocol(String encodedString) { - if (encodedString == null) { - return null; - } - - if (encodedString.startsWith("pre:")) { - return Integer.parseInt(encodedString.substring(4)); - } - - if (encodedString.startsWith("custom:")) { - return encodedString.substring(7); - } - - throw new IllegalArgumentException( - "the value is not a valid encoded protocol, " + encodedString); - } } /** @@ -1397,6 +1375,13 @@ public final class ContactsContract { "com.android.contacts.action.CREATE_DESCRIPTION"; /** + * Optional extra used with {@link #SHOW_OR_CREATE_CONTACT} to specify a + * dialog location using screen coordinates. When not specified, the + * dialog will be centered. + */ + public static final String EXTRA_TARGET_RECT = "target_rect"; + + /** * Intents related to the Contacts app UI. */ public static final class UI { diff --git a/core/java/com/android/internal/widget/ContactHeaderWidget.java b/core/java/com/android/internal/widget/ContactHeaderWidget.java new file mode 100644 index 000000000000..94d4edc9bd76 --- /dev/null +++ b/core/java/com/android/internal/widget/ContactHeaderWidget.java @@ -0,0 +1,349 @@ +/* + * 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. + */ + +package com.android.internal.widget; + +import android.content.AsyncQueryHandler; +import android.content.ContentResolver; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.os.Handler; +import android.os.Message; +import android.os.SystemClock; +import android.provider.SocialContract; +import android.provider.ContactsContract.Contacts; +import android.provider.ContactsContract.Data; +import android.provider.ContactsContract.PhoneLookup; +import android.provider.ContactsContract.RawContacts; +import android.provider.ContactsContract.CommonDataKinds.Photo; +import android.provider.SocialContract.Activities; +import android.util.AttributeSet; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.CheckBox; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.android.internal.R; + + +/* Widget that is used across system apps for displaying a header banner with contact info */ +public class ContactHeaderWidget extends FrameLayout implements View.OnClickListener { + + private static final String TAG = "ContactHeaderWidget"; + + private TextView mDisplayNameView; + private TextView mPhoneticNameView; + private CheckBox mStarredView; + private ImageView mPhotoView; + private TextView mStatusView; + private int mNoPhotoResource; + private QueryHandler mQueryHandler; + + protected long mContactId; + protected Uri mContactDataUri; + protected Uri mContactUri; + protected Uri mStatusUri; + + protected ContentResolver mContentResolver; + + //Projection used for the summary info in the header. + protected static final String[] HEADER_PROJECTION = new String[] { + Contacts.DISPLAY_NAME, + Contacts.STARRED, + Contacts.PHOTO_ID, + }; + protected static final int HEADER_DISPLAY_NAME_COLUMN_INDEX = 0; + //TODO: We need to figure out how we're going to get the phonetic name. + //static final int HEADER_PHONETIC_NAME_COLUMN_INDEX + protected static final int HEADER_STARRED_COLUMN_INDEX = 1; + protected static final int HEADER_PHOTO_ID_COLUMN_INDEX = 2; + + //Projection used for finding the most recent social status. + protected static final String[] SOCIAL_PROJECTION = new String[] { + Activities.TITLE, + Activities.PUBLISHED, + }; + protected static final int SOCIAL_TITLE_COLUMN_INDEX = 0; + protected static final int SOCIAL_PUBLISHED_COLUMN_INDEX = 1; + + //Projection used for looking up contact id from phone number + protected static final String[] PHONE_LOOKUP_PROJECTION = new String[] { + RawContacts.CONTACT_ID, + }; + protected static final int PHONE_LOOKUP_CONTACT_ID_COLUMN_INDEX = 0; + + //Projection used for looking up contact id from email address + protected static final String[] EMAIL_LOOKUP_PROJECTION = new String[] { + RawContacts.CONTACT_ID, + }; + protected static final int EMAIL_LOOKUP_CONTACT_ID_COLUMN_INDEX = 0; + + + private static final int TOKEN_CONTACT_INFO = 0; + private static final int TOKEN_SOCIAL = 1; + + public ContactHeaderWidget(Context context) { + this(context, null); + } + + public ContactHeaderWidget(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ContactHeaderWidget(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + mContentResolver = mContext.getContentResolver(); + + LayoutInflater inflater = + (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + inflater.inflate(R.layout.contact_header, this); + + mDisplayNameView = (TextView) findViewById(R.id.name); + mPhoneticNameView = (TextView) findViewById(R.id.phonetic_name); + mStarredView = (CheckBox) findViewById(R.id.star); + mStarredView.setOnClickListener(this); + // Don't show start by default. + mStarredView.setVisibility(View.GONE); + mPhotoView = (ImageView) findViewById(R.id.photo); + mStatusView = (TextView) findViewById(R.id.status); + + // Set the photo with a random "no contact" image + long now = SystemClock.elapsedRealtime(); + int num = (int) now & 0xf; + if (num < 9) { + // Leaning in from right, common + mNoPhotoResource = R.drawable.ic_contact_picture; + } else if (num < 14) { + // Leaning in from left uncommon + mNoPhotoResource = R.drawable.ic_contact_picture_2; + } else { + // Coming in from the top, rare + mNoPhotoResource = R.drawable.ic_contact_picture_3; + } + + mQueryHandler = new QueryHandler(mContentResolver); + } + + private class QueryHandler extends AsyncQueryHandler { + + public QueryHandler(ContentResolver cr) { + super(cr); + } + + @Override + protected void onQueryComplete(int token, Object cookie, Cursor cursor) { + try{ + if (token == TOKEN_CONTACT_INFO) { + bindContactInfo(cursor); + invalidate(); + } else if (token == TOKEN_SOCIAL) { + bindSocial(cursor); + invalidate(); + } + } finally { + if (cursor != null) { + cursor.close(); + } + } + } + } + + + /** {@inheritDoc} */ + public void onQueryComplete(int token, Object cookie, Cursor cursor) { + try{ + if (token == TOKEN_CONTACT_INFO) { + bindContactInfo(cursor); + invalidate(); + } else if (token == TOKEN_SOCIAL) { + bindSocial(cursor); + invalidate(); + } + } finally { + if (cursor != null) { + cursor.close(); + } + } + } + + /** + * Turn on/off showing of the star element. + */ + public void showStar(boolean showStar) { + mStarredView.setVisibility(showStar ? View.VISIBLE : View.GONE); + } + + /** + * Convenience method for binding all available data from an existing + * contact. + * + * @param contactId the contact id of the contact whose info should be displayed. + */ + public void bindFromContactId(long contactId) { + mContactId = contactId; + mContactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, mContactId); + mContactDataUri = Uri.withAppendedPath(mContactUri, Contacts.Data.CONTENT_DIRECTORY); + mStatusUri = ContentUris.withAppendedId( + SocialContract.Activities.CONTENT_CONTACT_STATUS_URI, mContactId); + redrawHeader(); + } + + /** + * Convenience method for binding all available data from an existing + * contact. + * + * @param emailAddress The email address used to do a reverse lookup in + * the contacts database. If more than one contact contains this email + * address, one of them will be chosen to bind to. + */ + public void bindFromEmail(String emailAddress) { + Cursor c = null; + try { + c = mContentResolver.query(Uri.withAppendedPath( + RawContacts.CONTENT_FILTER_EMAIL_URI, Uri.encode(emailAddress)), + EMAIL_LOOKUP_PROJECTION, null, null, null); + c.moveToFirst(); + long contactId = c.getLong(EMAIL_LOOKUP_CONTACT_ID_COLUMN_INDEX); + bindFromContactId(contactId); + } finally { + if (c != null) { + c.close(); + } + } + } + + /** + * Convenience method for binding all available data from an existing + * contact. + * + * @param number The phone number used to do a reverse lookup in + * the contacts database. If more than one contact contains this phone + * number, one of them will be chosen to bind to. + */ + public void bindFromPhoneNumber(String number) { + Cursor c = null; + try { + c = mContentResolver.query(Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number), + PHONE_LOOKUP_PROJECTION, null, null, null); + c.moveToFirst(); + long contactId = c.getLong(PHONE_LOOKUP_CONTACT_ID_COLUMN_INDEX); + bindFromContactId(contactId); + } finally { + if (c != null) { + c.close(); + } + } + } + + protected void redrawHeader() { + if (mContactDataUri != null) { + mQueryHandler.startQuery(TOKEN_CONTACT_INFO, null, mContactDataUri, HEADER_PROJECTION, + null, null, null); + } + + if (mStatusUri != null) { + mQueryHandler.startQuery(TOKEN_SOCIAL, null, mStatusUri, SOCIAL_PROJECTION, + null, null, null); + } + } + + protected void bindContactInfo(Cursor c) { + if (c == null) { + return; + } + if (c.moveToFirst()) { + //Set name + String displayName = c.getString(HEADER_DISPLAY_NAME_COLUMN_INDEX); + Log.i(TAG, displayName); + mDisplayNameView.setText(displayName); + //TODO: Bring back phonetic name + /*if (mPhoneticNameView != null) { + String phoneticName = c.getString(CONTACT_PHONETIC_NAME_COLUMN); + mPhoneticNameView.setText(phoneticName); + }*/ + + //Set starred + mStarredView.setChecked(c.getInt(HEADER_STARRED_COLUMN_INDEX) == 1); + + //Set the photo + Bitmap photoBitmap = loadContactPhoto(c.getLong(HEADER_PHOTO_ID_COLUMN_INDEX), null); + if (photoBitmap == null) { + photoBitmap = loadPlaceholderPhoto(null); + } + mPhotoView.setImageBitmap(photoBitmap); + } + } + + protected void bindSocial(Cursor c) { + if (c == null) { + return; + } + if (c.moveToFirst()) { + String status = c.getString(SOCIAL_TITLE_COLUMN_INDEX); + mStatusView.setText(status); + } + } + + public void onClick(View view) { + if (view.getId() == R.id.star) { + ContentValues values = new ContentValues(1); + values.put(Contacts.STARRED, mStarredView.isChecked()); + mContentResolver.update(mContactUri, values, null, null); + } + } + + private Bitmap loadContactPhoto(long photoId, BitmapFactory.Options options) { + Cursor photoCursor = null; + Bitmap photoBm = null; + + try { + photoCursor = mContentResolver.query( + ContentUris.withAppendedId(Data.CONTENT_URI, photoId), + new String[] { Photo.PHOTO }, + null, null, null); + + if (photoCursor.moveToFirst() && !photoCursor.isNull(0)) { + byte[] photoData = photoCursor.getBlob(0); + photoBm = BitmapFactory.decodeByteArray(photoData, 0, + photoData.length, options); + } + } finally { + if (photoCursor != null) { + photoCursor.close(); + } + } + + return photoBm; + } + + private Bitmap loadPlaceholderPhoto(BitmapFactory.Options options) { + if (mNoPhotoResource == 0) { + return null; + } + return BitmapFactory.decodeResource(mContext.getResources(), + mNoPhotoResource, options); + } +} diff --git a/core/res/res/drawable/contact_header_bg.9.png b/core/res/res/drawable/contact_header_bg.9.png Binary files differnew file mode 100644 index 000000000000..7f9a5a3e0d79 --- /dev/null +++ b/core/res/res/drawable/contact_header_bg.9.png diff --git a/core/res/res/drawable/contact_picture_bg.9.png b/core/res/res/drawable/contact_picture_bg.9.png Binary files differnew file mode 100644 index 000000000000..ae9c70920995 --- /dev/null +++ b/core/res/res/drawable/contact_picture_bg.9.png diff --git a/core/res/res/drawable/ic_contact_picture_2.png b/core/res/res/drawable/ic_contact_picture_2.png Binary files differnew file mode 100644 index 000000000000..8b184af7cfe4 --- /dev/null +++ b/core/res/res/drawable/ic_contact_picture_2.png diff --git a/core/res/res/drawable/ic_contact_picture_3.png b/core/res/res/drawable/ic_contact_picture_3.png Binary files differnew file mode 100644 index 000000000000..a2d08b55fe8e --- /dev/null +++ b/core/res/res/drawable/ic_contact_picture_3.png diff --git a/core/res/res/layout-ja/contact_header_name.xml b/core/res/res/layout-ja/contact_header_name.xml new file mode 100644 index 000000000000..03332b11d4b4 --- /dev/null +++ b/core/res/res/layout-ja/contact_header_name.xml @@ -0,0 +1,39 @@ +<?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. +--> + +<!-- In Japanese-language locales, the "Name" field contains two separate + TextViews: the name itself, and also the phonetic ("furigana") field. --> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="0dip" + android:layout_weight="1" + android:layout_height="wrap_content"> + + <TextView android:id="@+id/name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceLargeInverse" + android:textColor="@android:color/secondary_text_light" + /> + + <TextView android:id="@+id/phonetic_name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceSmallInverse" + android:textColor="@android:color/secondary_text_light" + /> + +</LinearLayout> diff --git a/core/res/res/layout/contact_header.xml b/core/res/res/layout/contact_header.xml new file mode 100644 index 000000000000..04b34b8fd62c --- /dev/null +++ b/core/res/res/layout/contact_header.xml @@ -0,0 +1,56 @@ +<?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. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/banner" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:background="@drawable/contact_header_bg" + android:paddingRight="5dip" + android:gravity="center_vertical"> + + <ImageView android:id="@+id/photo" + android:layout_width="64dip" + android:layout_height="64dip" + android:layout_marginRight="7dip" + android:layout_marginLeft="2dip" + android:scaleType="fitCenter" + android:background="@drawable/contact_picture_bg"/> + + <LinearLayout + android:layout_width="0dip" + android:layout_height="fill_parent" + android:layout_weight="1" + android:orientation="vertical"> + + <!-- "Name" field is locale-specific. --> + <include layout="@layout/contact_header_name"/> + + <TextView android:id="@+id/status" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceSmall" + android:maxLines="2"/> + + </LinearLayout> + + <CheckBox android:id="@+id/star" + style="?android:attr/starStyle" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + +</LinearLayout>
\ No newline at end of file diff --git a/core/res/res/layout/contact_header_name.xml b/core/res/res/layout/contact_header_name.xml new file mode 100644 index 000000000000..aec943e4cf6e --- /dev/null +++ b/core/res/res/layout/contact_header_name.xml @@ -0,0 +1,26 @@ +<?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. +--> + +<!-- In the default locale, the "Name" field is a single TextView --> +<TextView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/name" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceLargeInverse" + android:textColor="@android:color/secondary_text_light" + android:maxLines="2" + android:ellipsize="end" + /> diff --git a/keystore/java/android/security/CertTool.java b/keystore/java/android/security/CertTool.java index b1b78ea96362..989432a0d995 100644 --- a/keystore/java/android/security/CertTool.java +++ b/keystore/java/android/security/CertTool.java @@ -209,6 +209,10 @@ public class CertTool { } freeX509Certificate(handle); } - if (intent != null) context.startActivity(intent); + if (intent != null) { + context.startActivity(intent); + } else { + Log.w("CertTool", "incorrect data for addCertificate()"); + } } } diff --git a/packages/VpnServices/src/com/android/server/vpn/VpnService.java b/packages/VpnServices/src/com/android/server/vpn/VpnService.java index b107c7dcb191..f410c7b932a1 100644 --- a/packages/VpnServices/src/com/android/server/vpn/VpnService.java +++ b/packages/VpnServices/src/com/android/server/vpn/VpnService.java @@ -147,8 +147,7 @@ abstract class VpnService<E extends VpnProfile> implements Serializable { synchronized boolean onConnect(String username, String password) { try { - mState = VpnState.CONNECTING; - broadcastConnectivity(VpnState.CONNECTING); + setState(VpnState.CONNECTING); stopPreviouslyRunDaemons(); String serverIp = getIp(getProfile().getServerName()); @@ -166,8 +165,7 @@ abstract class VpnService<E extends VpnProfile> implements Serializable { synchronized void onDisconnect() { try { Log.i(TAG, "disconnecting VPN..."); - mState = VpnState.DISCONNECTING; - broadcastConnectivity(VpnState.DISCONNECTING); + setState(VpnState.DISCONNECTING); mNotification.showDisconnect(); mDaemonHelper.stopAll(); @@ -235,14 +233,13 @@ abstract class VpnService<E extends VpnProfile> implements Serializable { saveOriginalDns(); saveAndSetDomainSuffices(); - mState = VpnState.CONNECTED; mStartTime = System.currentTimeMillis(); // set DNS after saving the states in case the process gets killed // before states are saved saveSelf(); setVpnDns(); - broadcastConnectivity(VpnState.CONNECTED); + setState(VpnState.CONNECTED); enterConnectivityLoop(); } @@ -261,10 +258,10 @@ abstract class VpnService<E extends VpnProfile> implements Serializable { restoreOriginalDns(); restoreOriginalDomainSuffices(); - mState = VpnState.IDLE; - broadcastConnectivity(VpnState.IDLE); + setState(VpnState.IDLE); // stop the service itself + SystemProperties.set(VPN_STATUS, VPN_IS_DOWN); mContext.removeStates(); mContext.stopSelf(); } @@ -316,6 +313,11 @@ abstract class VpnService<E extends VpnProfile> implements Serializable { SystemProperties.set(DNS_DOMAIN_SUFFICES, mOriginalDomainSuffices); } + private void setState(VpnState newState) { + mState = newState; + broadcastConnectivity(newState); + } + private void broadcastConnectivity(VpnState s) { VpnManager m = new VpnManager(mContext); Throwable err = mError; @@ -326,6 +328,9 @@ abstract class VpnService<E extends VpnProfile> implements Serializable { } else if (err instanceof VpnConnectingError) { m.broadcastConnectivity(mProfile.getName(), s, ((VpnConnectingError) err).getErrorCode()); + } else if (VPN_IS_UP.equals(SystemProperties.get(VPN_STATUS))) { + m.broadcastConnectivity(mProfile.getName(), s, + VpnManager.VPN_ERROR_CONNECTION_LOST); } else { m.broadcastConnectivity(mProfile.getName(), s, VpnManager.VPN_ERROR_CONNECTION_FAILED); @@ -373,7 +378,7 @@ abstract class VpnService<E extends VpnProfile> implements Serializable { // returns false if vpn connectivity is broken private boolean checkConnectivity() { if (mDaemonHelper.anyDaemonStopped() || isLocalIpChanged()) { - onDisconnect(); + onError(new IOException("Connectivity lost")); return false; } else { return true; diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java index c71003bec5dc..d4ec85a7ebb0 100644 --- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java +++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java @@ -853,7 +853,7 @@ public final class BearerData { } } - private static String decodeIa5(byte[] data, int offset, int numFields) + private static String decode7bitAscii(byte[] data, int offset, int numFields) throws CodingException { try { @@ -868,38 +868,20 @@ public final class BearerData { inStream.skip(offset); for (int i = 0; i < numFields; i++) { int charCode = inStream.read(7); - if ((charCode < UserData.IA5_MAP_BASE_INDEX) || - (charCode > UserData.IA5_MAP_MAX_INDEX)) { - throw new CodingException("unsupported AI5 character code (" + charCode + ")"); + if ((charCode >= UserData.ASCII_MAP_BASE_INDEX) || + (charCode <= UserData.ASCII_MAP_MAX_INDEX)) { + strBuf.append(UserData.ASCII_MAP[charCode - UserData.ASCII_MAP_BASE_INDEX]); + } else if (charCode == UserData.ASCII_LF_INDEX) { + strBuf.append('\r'); + } else if (charCode == UserData.ASCII_CR_INDEX) { + strBuf.append('\n'); + } else { + /* For other charCodes, they are unprintable, and so simply use SPACE. */ + strBuf.append(' '); } - strBuf.append(UserData.IA5_MAP[charCode - UserData.IA5_MAP_BASE_INDEX]); } return strBuf.toString(); } catch (BitwiseInputStream.AccessException ex) { - throw new CodingException("AI5 decode failed: " + ex); - } - } - - private static String decode7bitAscii(byte[] data, int offset, int numFields) - throws CodingException - { - try { - offset *= 8; - BitwiseInputStream inStream = new BitwiseInputStream(data); - int wantedBits = offset + (numFields * 7); - if (inStream.available() < wantedBits) { - throw new CodingException("insufficient data (wanted " + wantedBits + - " bits, but only have " + inStream.available() + ")"); - } - inStream.skip(offset); - byte[] expandedData = new byte[numFields]; - for (int i = 0; i < numFields; i++) { - expandedData[i] = (byte)inStream.read(7); - } - return new String(expandedData, 0, numFields, "US-ASCII"); - } catch (java.io.UnsupportedEncodingException ex) { - throw new CodingException("7bit ASCII decode failed: " + ex); - } catch (BitwiseInputStream.AccessException ex) { throw new CodingException("7bit ASCII decode failed: " + ex); } } @@ -956,12 +938,10 @@ public final class BearerData { // octet encoded. userData.payloadStr = decodeLatin(userData.payload, offset, userData.numFields); break; + case UserData.ENCODING_IA5: case UserData.ENCODING_7BIT_ASCII: userData.payloadStr = decode7bitAscii(userData.payload, offset, userData.numFields); break; - case UserData.ENCODING_IA5: - userData.payloadStr = decodeIa5(userData.payload, offset, userData.numFields); - break; case UserData.ENCODING_UNICODE_16: userData.payloadStr = decodeUtf16(userData.payload, offset, userData.numFields); break; @@ -1003,7 +983,7 @@ public final class BearerData { try { StringBuffer strbuf = new StringBuffer(dataLen); while (inStream.available() >= 6) { - strbuf.append(UserData.IA5_MAP[inStream.read(6)]); + strbuf.append(UserData.ASCII_MAP[inStream.read(6)]); } String data = strbuf.toString(); bData.numberOfMessages = Integer.parseInt(data.substring(0, 2)); @@ -1045,7 +1025,7 @@ public final class BearerData { } StringBuffer strbuf = new StringBuffer(dataLen); for (int i = 0; i < numFields; i++) { - strbuf.append(UserData.IA5_MAP[inStream.read(6)]); + strbuf.append(UserData.ASCII_MAP[inStream.read(6)]); } bData.userData.payloadStr = strbuf.toString(); } diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java index 54c1f80340e2..15cb5e42e2b9 100644 --- a/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java +++ b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java @@ -49,19 +49,20 @@ public class UserData { public static final int IS91_MSG_TYPE_SHORT_MESSAGE = 0x85; /** - * IA5 data encoding character mappings. - * (See CCITT Rec. T.50 Tables 1 and 3) + * US ASCII character mapping table. * - * Note this mapping is the the same as for printable ASCII - * characters, with a 0x20 offset, meaning that the ASCII SPACE - * character occurs with code 0x20. + * This table contains only the printable ASCII characters, with a + * 0x20 offset, meaning that the ASCII SPACE character is at index + * 0, with the resulting code of 0x20. * - * Note this mapping is also equivalent to that used by the IS-91 - * protocol, except for the latter using only 6 bits, and hence - * mapping only entries up to the '_' character. + * Note this mapping is also equivalent to that used by both the + * IS5 and the IS-91 encodings. For the former this is defined + * using CCITT Rec. T.50 Tables 1 and 3. For the latter IS 637 B, + * Table 4.3.1.4.1-1 -- and note the encoding uses only 6 bits, + * and hence only maps entries up to the '_' character. * */ - public static final char[] IA5_MAP = { + public static final char[] ASCII_MAP = { ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', @@ -85,8 +86,8 @@ public class UserData { public static final int ASCII_CR_INDEX = 0x0D; public static final SparseIntArray charToAscii = new SparseIntArray(); static { - for (int i = 0; i < IA5_MAP.length; i++) { - charToAscii.put(IA5_MAP[i], PRINTABLE_ASCII_MIN_INDEX + i); + for (int i = 0; i < ASCII_MAP.length; i++) { + charToAscii.put(ASCII_MAP[i], PRINTABLE_ASCII_MIN_INDEX + i); } charToAscii.put('\r', ASCII_LF_INDEX); charToAscii.put('\n', ASCII_CR_INDEX); @@ -113,11 +114,11 @@ public class UserData { } /** - * Mapping for IA5 values less than 32 are flow control signals + * Mapping for ASCII values less than 32 are flow control signals * and not used here. */ - public static final int IA5_MAP_BASE_INDEX = 0x20; - public static final int IA5_MAP_MAX_INDEX = IA5_MAP_BASE_INDEX + IA5_MAP.length - 1; + public static final int ASCII_MAP_BASE_INDEX = 0x20; + public static final int ASCII_MAP_MAX_INDEX = ASCII_MAP_BASE_INDEX + ASCII_MAP.length - 1; /** * Contains the data header of the user data diff --git a/vpn/java/android/net/vpn/VpnManager.java b/vpn/java/android/net/vpn/VpnManager.java index e448e5a58bce..f71bbea0bf3a 100644 --- a/vpn/java/android/net/vpn/VpnManager.java +++ b/vpn/java/android/net/vpn/VpnManager.java @@ -54,6 +54,8 @@ public class VpnManager { public static final int VPN_ERROR_CHALLENGE = 4; /** Error code to indicate an error of remote server hanging up. */ public static final int VPN_ERROR_REMOTE_HUNG_UP = 5; + /** Error code to indicate an error of losing connectivity. */ + public static final int VPN_ERROR_CONNECTION_LOST = 6; private static final int VPN_ERROR_NO_ERROR = 0; public static final String PROFILES_PATH = "/data/misc/vpn/profiles"; |