diff options
Diffstat (limited to 'core/java')
83 files changed, 1011 insertions, 12256 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 7242029..b7e0683 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -4728,13 +4728,14 @@ public final class ActivityThread { Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper(); - if (sMainThreadHandler == null) { - sMainThreadHandler = new Handler(); - } ActivityThread thread = new ActivityThread(); thread.attach(false); + if (sMainThreadHandler == null) { + sMainThreadHandler = thread.getHandler(); + } + AsyncTask.init(); if (false) { diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java index dd9ea26..3a67cec 100644 --- a/core/java/android/app/Application.java +++ b/core/java/android/app/Application.java @@ -64,11 +64,12 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 { } /** - * Called when the application is starting, before any other application - * objects have been created. Implementations should be as quick as - * possible (for example using lazy initialization of state) since the time - * spent in this function directly impacts the performance of starting the - * first activity, service, or receiver in a process. + * Called when the application is starting, before any activity, service, + * or receiver objects (excluding content providers) have been created. + * Implementations should be as quick as possible (for example using + * lazy initialization of state) since the time spent in this function + * directly impacts the performance of starting the first activity, + * service, or receiver in a process. * If you override this method, be sure to call super.onCreate(). */ public void onCreate() { diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index 3e726e0..8e6278d 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -385,6 +385,7 @@ public abstract class ApplicationThreadNative extends Binder case SCHEDULE_LOW_MEMORY_TRANSACTION: { + data.enforceInterface(IApplicationThread.descriptor); scheduleLowMemory(); return true; } diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java index 17700f9..0b1c524 100644 --- a/core/java/android/app/DownloadManager.java +++ b/core/java/android/app/DownloadManager.java @@ -344,6 +344,13 @@ public class DownloadManager { */ public static final int NETWORK_WIFI = 1 << 1; + /** + * Bit flag for {@link #setAllowedNetworkTypes} corresponding to + * {@link ConnectivityManager#TYPE_BLUETOOTH}. + * @hide + */ + public static final int NETWORK_BLUETOOTH = 1 << 2; + private Uri mUri; private Uri mDestinationUri; private List<Pair<String, String>> mRequestHeaders = new ArrayList<Pair<String, String>>(); diff --git a/core/java/android/app/SharedPreferencesImpl.java b/core/java/android/app/SharedPreferencesImpl.java index 615e8ce..201d7b2 100644 --- a/core/java/android/app/SharedPreferencesImpl.java +++ b/core/java/android/app/SharedPreferencesImpl.java @@ -17,7 +17,6 @@ package android.app; import android.content.SharedPreferences; -import android.os.FileUtils.FileStatus; import android.os.FileUtils; import android.os.Looper; import android.util.Log; @@ -45,6 +44,11 @@ import java.util.WeakHashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; +import libcore.io.ErrnoException; +import libcore.io.IoUtils; +import libcore.io.Libcore; +import libcore.io.StructStat; + final class SharedPreferencesImpl implements SharedPreferences { private static final String TAG = "SharedPreferencesImpl"; private static final boolean DEBUG = false; @@ -105,26 +109,32 @@ final class SharedPreferencesImpl implements SharedPreferences { } Map map = null; - FileStatus stat = new FileStatus(); - if (FileUtils.getFileStatus(mFile.getPath(), stat) && mFile.canRead()) { - try { - BufferedInputStream str = new BufferedInputStream( - new FileInputStream(mFile), 16*1024); - map = XmlUtils.readMapXml(str); - str.close(); - } catch (XmlPullParserException e) { - Log.w(TAG, "getSharedPreferences", e); - } catch (FileNotFoundException e) { - Log.w(TAG, "getSharedPreferences", e); - } catch (IOException e) { - Log.w(TAG, "getSharedPreferences", e); + StructStat stat = null; + try { + stat = Libcore.os.stat(mFile.getPath()); + if (mFile.canRead()) { + BufferedInputStream str = null; + try { + str = new BufferedInputStream( + new FileInputStream(mFile), 16*1024); + map = XmlUtils.readMapXml(str); + } catch (XmlPullParserException e) { + Log.w(TAG, "getSharedPreferences", e); + } catch (FileNotFoundException e) { + Log.w(TAG, "getSharedPreferences", e); + } catch (IOException e) { + Log.w(TAG, "getSharedPreferences", e); + } finally { + IoUtils.closeQuietly(str); + } } + } catch (ErrnoException e) { } mLoaded = true; if (map != null) { mMap = map; - mStatTimestamp = stat.mtime; - mStatSize = stat.size; + mStatTimestamp = stat.st_mtime; + mStatSize = stat.st_size; } else { mMap = new HashMap<String, Object>(); } @@ -155,12 +165,21 @@ final class SharedPreferencesImpl implements SharedPreferences { return false; } } - FileStatus stat = new FileStatus(); - if (!FileUtils.getFileStatus(mFile.getPath(), stat)) { + + final StructStat stat; + try { + /* + * Metadata operations don't usually count as a block guard + * violation, but we explicitly want this one. + */ + BlockGuard.getThreadPolicy().onReadFromDisk(); + stat = Libcore.os.stat(mFile.getPath()); + } catch (ErrnoException e) { return true; } + synchronized (this) { - return mStatTimestamp != stat.mtime || mStatSize != stat.size; + return mStatTimestamp != stat.st_mtime || mStatSize != stat.st_size; } } @@ -577,12 +596,14 @@ final class SharedPreferencesImpl implements SharedPreferences { FileUtils.sync(str); str.close(); ContextImpl.setFilePermissionsFromMode(mFile.getPath(), mMode, 0); - FileStatus stat = new FileStatus(); - if (FileUtils.getFileStatus(mFile.getPath(), stat)) { + try { + final StructStat stat = Libcore.os.stat(mFile.getPath()); synchronized (this) { - mStatTimestamp = stat.mtime; - mStatSize = stat.size; + mStatTimestamp = stat.st_mtime; + mStatSize = stat.st_size; } + } catch (ErrnoException e) { + // Do nothing } // Writing was successful, delete the backup file if there is one. mBackupFile.delete(); diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 4ed0766..0b58396 100644..100755 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -1008,13 +1008,15 @@ public class DevicePolicyManager { /** * Ask the user date be wiped. This will cause the device to reboot, * erasing all user data while next booting up. External storage such - * as SD cards will not be erased. + * as SD cards will be also erased if the flag {@link #WIPE_EXTERNAL_STORAGE} + * is set. * * <p>The calling device admin must have requested * {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA} to be able to call * this method; if it has not, a security exception will be thrown. * - * @param flags Bit mask of additional options: currently must be 0. + * @param flags Bit mask of additional options: currently 0 and + * {@link #WIPE_EXTERNAL_STORAGE} are supported. */ public void wipeData(int flags) { if (mService != null) { diff --git a/core/java/android/bluetooth/BluetoothDeviceProfileState.java b/core/java/android/bluetooth/BluetoothDeviceProfileState.java index c9603bf..020f051 100644 --- a/core/java/android/bluetooth/BluetoothDeviceProfileState.java +++ b/core/java/android/bluetooth/BluetoothDeviceProfileState.java @@ -304,6 +304,25 @@ public final class BluetoothDeviceProfileState extends StateMachine { } } + @Override + protected void onQuitting() { + mContext.unregisterReceiver(mBroadcastReceiver); + mBroadcastReceiver = null; + mAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mHeadsetService); + mBluetoothProfileServiceListener = null; + mOutgoingHandsfree = null; + mPbap = null; + mPbapService.close(); + mPbapService = null; + mIncomingHid = null; + mOutgoingHid = null; + mIncomingHandsfree = null; + mOutgoingHandsfree = null; + mIncomingA2dp = null; + mOutgoingA2dp = null; + mBondedDevice = null; + } + private class BondedDevice extends State { @Override public void enter() { @@ -416,26 +435,6 @@ public final class BluetoothDeviceProfileState extends StateMachine { case TRANSITION_TO_STABLE: // ignore. break; - case SM_QUIT_CMD: - mContext.unregisterReceiver(mBroadcastReceiver); - mBroadcastReceiver = null; - mAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mHeadsetService); - mBluetoothProfileServiceListener = null; - mOutgoingHandsfree = null; - mPbap = null; - mPbapService.close(); - mPbapService = null; - mIncomingHid = null; - mOutgoingHid = null; - mIncomingHandsfree = null; - mOutgoingHandsfree = null; - mIncomingA2dp = null; - mOutgoingA2dp = null; - mBondedDevice = null; - // There is a problem in the State Machine code - // where things are not cleaned up properly, when quit message - // is handled so return NOT_HANDLED as a workaround. - return NOT_HANDLED; default: return NOT_HANDLED; } @@ -1341,6 +1340,15 @@ public final class BluetoothDeviceProfileState extends StateMachine { return mDevice; } + /** + * Quit the state machine, only to be called by BluetoothService. + * + * @hide + */ + public void doQuit() { + this.quit(); + } + private void log(String message) { if (DBG) { Log.i(TAG, "Device:" + mDevice + " Message:" + message); diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java index 226e107..7a9fc65 100644 --- a/core/java/android/content/SyncStorageEngine.java +++ b/core/java/android/content/SyncStorageEngine.java @@ -26,6 +26,7 @@ import org.xmlpull.v1.XmlSerializer; import android.accounts.Account; import android.accounts.AccountAndUser; +import android.content.res.Resources; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteException; @@ -337,6 +338,7 @@ public class SyncStorageEngine extends Handler { private int mNextHistoryId = 0; private SparseArray<Boolean> mMasterSyncAutomatically = new SparseArray<Boolean>(); + private boolean mDefaultMasterSyncAutomatically; private OnSyncRequestListener mSyncRequestListener; @@ -346,6 +348,9 @@ public class SyncStorageEngine extends Handler { mCal = Calendar.getInstance(TimeZone.getTimeZone("GMT+0")); + mDefaultMasterSyncAutomatically = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_syncstorageengine_masterSyncAutomatically); + File systemDir = new File(dataDir, "system"); File syncDir = new File(systemDir, "sync"); syncDir.mkdirs(); @@ -781,7 +786,7 @@ public class SyncStorageEngine extends Handler { public boolean getMasterSyncAutomatically(int userId) { synchronized (mAuthorities) { Boolean auto = mMasterSyncAutomatically.get(userId); - return auto == null ? true : auto; + return auto == null ? mDefaultMasterSyncAutomatically : auto; } } diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java index fb04817..e7ff92d 100644 --- a/core/java/android/database/AbstractCursor.java +++ b/core/java/android/database/AbstractCursor.java @@ -424,6 +424,9 @@ public abstract class AbstractCursor implements CrossProcessCursor { if (mSelfObserver != null && mSelfObserverRegistered == true) { mContentResolver.unregisterContentObserver(mSelfObserver); } + try { + if (!mClosed) close(); + } catch(Exception e) { } } /** diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index 4d9077f..829620b 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -26,6 +26,7 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; +import android.text.TextUtils; import android.view.Surface; import android.view.SurfaceHolder; @@ -34,7 +35,6 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import java.util.StringTokenizer; import java.util.concurrent.locks.ReentrantLock; /** @@ -1905,7 +1905,7 @@ public class Camera { private HashMap<String, String> mMap; private Parameters() { - mMap = new HashMap<String, String>(); + mMap = new HashMap<String, String>(64); } /** @@ -1929,7 +1929,7 @@ public class Camera { * semi-colon delimited key-value pairs */ public String flatten() { - StringBuilder flattened = new StringBuilder(); + StringBuilder flattened = new StringBuilder(128); for (String k : mMap.keySet()) { flattened.append(k); flattened.append("="); @@ -1952,9 +1952,9 @@ public class Camera { public void unflatten(String flattened) { mMap.clear(); - StringTokenizer tokenizer = new StringTokenizer(flattened, ";"); - while (tokenizer.hasMoreElements()) { - String kv = tokenizer.nextToken(); + TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(';'); + splitter.setString(flattened); + for (String kv : splitter) { int pos = kv.indexOf('='); if (pos == -1) { continue; @@ -3488,11 +3488,11 @@ public class Camera { private ArrayList<String> split(String str) { if (str == null) return null; - // Use StringTokenizer because it is faster than split. - StringTokenizer tokenizer = new StringTokenizer(str, ","); + TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(','); + splitter.setString(str); ArrayList<String> substrings = new ArrayList<String>(); - while (tokenizer.hasMoreElements()) { - substrings.add(tokenizer.nextToken()); + for (String s : splitter) { + substrings.add(s); } return substrings; } @@ -3502,11 +3502,11 @@ public class Camera { private ArrayList<Integer> splitInt(String str) { if (str == null) return null; - StringTokenizer tokenizer = new StringTokenizer(str, ","); + TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(','); + splitter.setString(str); ArrayList<Integer> substrings = new ArrayList<Integer>(); - while (tokenizer.hasMoreElements()) { - String token = tokenizer.nextToken(); - substrings.add(Integer.parseInt(token)); + for (String s : splitter) { + substrings.add(Integer.parseInt(s)); } if (substrings.size() == 0) return null; return substrings; @@ -3515,11 +3515,11 @@ public class Camera { private void splitInt(String str, int[] output) { if (str == null) return; - StringTokenizer tokenizer = new StringTokenizer(str, ","); + TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(','); + splitter.setString(str); int index = 0; - while (tokenizer.hasMoreElements()) { - String token = tokenizer.nextToken(); - output[index++] = Integer.parseInt(token); + for (String s : splitter) { + output[index++] = Integer.parseInt(s); } } @@ -3527,11 +3527,11 @@ public class Camera { private void splitFloat(String str, float[] output) { if (str == null) return; - StringTokenizer tokenizer = new StringTokenizer(str, ","); + TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(','); + splitter.setString(str); int index = 0; - while (tokenizer.hasMoreElements()) { - String token = tokenizer.nextToken(); - output[index++] = Float.parseFloat(token); + for (String s : splitter) { + output[index++] = Float.parseFloat(s); } } @@ -3558,10 +3558,11 @@ public class Camera { private ArrayList<Size> splitSize(String str) { if (str == null) return null; - StringTokenizer tokenizer = new StringTokenizer(str, ","); + TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(','); + splitter.setString(str); ArrayList<Size> sizeList = new ArrayList<Size>(); - while (tokenizer.hasMoreElements()) { - Size size = strToSize(tokenizer.nextToken()); + for (String s : splitter) { + Size size = strToSize(s); if (size != null) sizeList.add(size); } if (sizeList.size() == 0) return null; diff --git a/core/java/android/net/DhcpStateMachine.java b/core/java/android/net/DhcpStateMachine.java index 397a12a..cc3e34f 100644 --- a/core/java/android/net/DhcpStateMachine.java +++ b/core/java/android/net/DhcpStateMachine.java @@ -163,8 +163,21 @@ public class DhcpStateMachine extends StateMachine { mRegisteredForPreDhcpNotification = true; } + /** + * Quit the DhcpStateMachine. + * + * @hide + */ + public void doQuit() { + quit(); + } + class DefaultState extends State { @Override + public void exit() { + mContext.unregisterReceiver(mBroadcastReceiver); + } + @Override public boolean processMessage(Message message) { if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); switch (message.what) { @@ -172,10 +185,6 @@ public class DhcpStateMachine extends StateMachine { Log.e(TAG, "Error! Failed to handle a DHCP renewal on " + mInterfaceName); mDhcpRenewWakeLock.release(); break; - case SM_QUIT_CMD: - mContext.unregisterReceiver(mBroadcastReceiver); - //let parent kill the state machine - return NOT_HANDLED; default: Log.e(TAG, "Error! unhandled message " + message); break; diff --git a/core/java/android/net/EthernetDataTracker.java b/core/java/android/net/EthernetDataTracker.java index 28bd289..0cc78c9 100644 --- a/core/java/android/net/EthernetDataTracker.java +++ b/core/java/android/net/EthernetDataTracker.java @@ -223,7 +223,7 @@ public class EthernetDataTracker implements NetworkStateTracker { mIface = iface; mNMService.setInterfaceUp(iface); InterfaceConfiguration config = mNMService.getInterfaceConfig(iface); - mLinkUp = config.isActive(); + mLinkUp = config.hasFlag("up"); if (config != null && mHwAddr == null) { mHwAddr = config.getHardwareAddress(); if (mHwAddr != null) { diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java index 57f8d48..d59fa6a 100644 --- a/core/java/android/net/MobileDataStateTracker.java +++ b/core/java/android/net/MobileDataStateTracker.java @@ -16,11 +16,6 @@ package android.net; -import static com.android.internal.telephony.DataConnectionTracker.CMD_SET_POLICY_DATA_ENABLE; -import static com.android.internal.telephony.DataConnectionTracker.CMD_SET_USER_DATA_ENABLE; -import static com.android.internal.telephony.DataConnectionTracker.DISABLED; -import static com.android.internal.telephony.DataConnectionTracker.ENABLED; - import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -37,9 +32,9 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Slog; -import com.android.internal.telephony.DataConnectionTracker; +import com.android.internal.telephony.DctConstants; import com.android.internal.telephony.ITelephony; -import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.util.AsyncChannel; @@ -59,7 +54,7 @@ public class MobileDataStateTracker implements NetworkStateTracker { private static final boolean DBG = false; private static final boolean VDBG = false; - private Phone.DataState mMobileDataState; + private PhoneConstants.DataState mMobileDataState; private ITelephony mPhoneService; private String mApnType; @@ -108,10 +103,10 @@ public class MobileDataStateTracker implements NetworkStateTracker { IntentFilter filter = new IntentFilter(); filter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED); filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED); - filter.addAction(DataConnectionTracker.ACTION_DATA_CONNECTION_TRACKER_MESSENGER); + filter.addAction(DctConstants.ACTION_DATA_CONNECTION_TRACKER_MESSENGER); mContext.registerReceiver(new MobileDataStateReceiver(), filter); - mMobileDataState = Phone.DataState.DISCONNECTED; + mMobileDataState = PhoneConstants.DataState.DISCONNECTED; } static class MdstHandler extends Handler { @@ -180,7 +175,7 @@ public class MobileDataStateTracker implements NetworkStateTracker { public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(TelephonyIntents. ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) { - String apnType = intent.getStringExtra(Phone.DATA_APN_TYPE_KEY); + String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY); if (VDBG) { log(String.format("Broadcast received: ACTION_ANY_DATA_CONNECTION_STATE_CHANGED" + "mApnType=%s %s received apnType=%s", mApnType, @@ -189,20 +184,29 @@ public class MobileDataStateTracker implements NetworkStateTracker { if (!TextUtils.equals(apnType, mApnType)) { return; } - mNetworkInfo.setSubtype(TelephonyManager.getDefault().getNetworkType(), - TelephonyManager.getDefault().getNetworkTypeName()); - Phone.DataState state = Enum.valueOf(Phone.DataState.class, - intent.getStringExtra(Phone.STATE_KEY)); - String reason = intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY); - String apnName = intent.getStringExtra(Phone.DATA_APN_KEY); - mNetworkInfo.setRoaming(intent.getBooleanExtra(Phone.DATA_NETWORK_ROAMING_KEY, - false)); + + int oldSubtype = mNetworkInfo.getSubtype(); + int newSubType = TelephonyManager.getDefault().getNetworkType(); + String subTypeName = TelephonyManager.getDefault().getNetworkTypeName(); + mNetworkInfo.setSubtype(newSubType, subTypeName); + if (newSubType != oldSubtype && mNetworkInfo.isConnected()) { + Message msg = mTarget.obtainMessage(EVENT_NETWORK_SUBTYPE_CHANGED, + oldSubtype, 0, mNetworkInfo); + msg.sendToTarget(); + } + + PhoneConstants.DataState state = Enum.valueOf(PhoneConstants.DataState.class, + intent.getStringExtra(PhoneConstants.STATE_KEY)); + String reason = intent.getStringExtra(PhoneConstants.STATE_CHANGE_REASON_KEY); + String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY); + mNetworkInfo.setRoaming(intent.getBooleanExtra( + PhoneConstants.DATA_NETWORK_ROAMING_KEY, false)); if (VDBG) { log(mApnType + " setting isAvailable to " + - intent.getBooleanExtra(Phone.NETWORK_UNAVAILABLE_KEY,false)); + intent.getBooleanExtra(PhoneConstants.NETWORK_UNAVAILABLE_KEY,false)); } - mNetworkInfo.setIsAvailable(!intent.getBooleanExtra(Phone.NETWORK_UNAVAILABLE_KEY, - false)); + mNetworkInfo.setIsAvailable(!intent.getBooleanExtra( + PhoneConstants.NETWORK_UNAVAILABLE_KEY, false)); if (DBG) { log("Received state=" + state + ", old=" + mMobileDataState + @@ -232,13 +236,13 @@ public class MobileDataStateTracker implements NetworkStateTracker { break; case CONNECTED: mLinkProperties = intent.getParcelableExtra( - Phone.DATA_LINK_PROPERTIES_KEY); + PhoneConstants.DATA_LINK_PROPERTIES_KEY); if (mLinkProperties == null) { loge("CONNECTED event did not supply link properties."); mLinkProperties = new LinkProperties(); } mLinkCapabilities = intent.getParcelableExtra( - Phone.DATA_LINK_CAPABILITIES_KEY); + PhoneConstants.DATA_LINK_CAPABILITIES_KEY); if (mLinkCapabilities == null) { loge("CONNECTED event did not supply link capabilities."); mLinkCapabilities = new LinkCapabilities(); @@ -248,8 +252,9 @@ public class MobileDataStateTracker implements NetworkStateTracker { } } else { // There was no state change. Check if LinkProperties has been updated. - if (TextUtils.equals(reason, Phone.REASON_LINK_PROPERTIES_CHANGED)) { - mLinkProperties = intent.getParcelableExtra(Phone.DATA_LINK_PROPERTIES_KEY); + if (TextUtils.equals(reason, PhoneConstants.REASON_LINK_PROPERTIES_CHANGED)) { + mLinkProperties = intent.getParcelableExtra( + PhoneConstants.DATA_LINK_PROPERTIES_KEY); if (mLinkProperties == null) { loge("No link property in LINK_PROPERTIES change event."); mLinkProperties = new LinkProperties(); @@ -264,7 +269,7 @@ public class MobileDataStateTracker implements NetworkStateTracker { } } else if (intent.getAction(). equals(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED)) { - String apnType = intent.getStringExtra(Phone.DATA_APN_TYPE_KEY); + String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY); if (!TextUtils.equals(apnType, mApnType)) { if (DBG) { log(String.format( @@ -273,17 +278,18 @@ public class MobileDataStateTracker implements NetworkStateTracker { } return; } - String reason = intent.getStringExtra(Phone.FAILURE_REASON_KEY); - String apnName = intent.getStringExtra(Phone.DATA_APN_KEY); + String reason = intent.getStringExtra(PhoneConstants.FAILURE_REASON_KEY); + String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY); if (DBG) { log("Received " + intent.getAction() + " broadcast" + reason == null ? "" : "(" + reason + ")"); } setDetailedState(DetailedState.FAILED, reason, apnName); - } else if (intent.getAction(). - equals(DataConnectionTracker.ACTION_DATA_CONNECTION_TRACKER_MESSENGER)) { + } else if (intent.getAction().equals(DctConstants + .ACTION_DATA_CONNECTION_TRACKER_MESSENGER)) { if (VDBG) log(mApnType + " got ACTION_DATA_CONNECTION_TRACKER_MESSENGER"); - mMessenger = intent.getParcelableExtra(DataConnectionTracker.EXTRA_MESSENGER); + mMessenger = + intent.getParcelableExtra(DctConstants.EXTRA_MESSENGER); AsyncChannel ac = new AsyncChannel(); ac.connect(mContext, MobileDataStateTracker.this.mHandler, mMessenger); } else { @@ -332,6 +338,9 @@ public class MobileDataStateTracker implements NetworkStateTracker { case TelephonyManager.NETWORK_TYPE_HSPA: networkTypeStr = "hspa"; break; + case TelephonyManager.NETWORK_TYPE_HSPAP: + networkTypeStr = "hspap"; + break; case TelephonyManager.NETWORK_TYPE_CDMA: networkTypeStr = "cdma"; break; @@ -369,7 +378,7 @@ public class MobileDataStateTracker implements NetworkStateTracker { */ public boolean teardown() { setTeardownRequested(true); - return (setEnableApn(mApnType, false) != Phone.APN_REQUEST_FAILED); + return (setEnableApn(mApnType, false) != PhoneConstants.APN_REQUEST_FAILED); } /** @@ -418,17 +427,17 @@ public class MobileDataStateTracker implements NetworkStateTracker { boolean retValue = false; //connected or expect to be? setTeardownRequested(false); switch (setEnableApn(mApnType, true)) { - case Phone.APN_ALREADY_ACTIVE: + case PhoneConstants.APN_ALREADY_ACTIVE: // need to set self to CONNECTING so the below message is handled. retValue = true; break; - case Phone.APN_REQUEST_STARTED: + case PhoneConstants.APN_REQUEST_STARTED: // set IDLE here , avoid the following second FAILED not sent out mNetworkInfo.setDetailedState(DetailedState.IDLE, null, null); retValue = true; break; - case Phone.APN_REQUEST_FAILED: - case Phone.APN_TYPE_NOT_AVAILABLE: + case PhoneConstants.APN_REQUEST_FAILED: + case PhoneConstants.APN_TYPE_NOT_AVAILABLE: break; default: loge("Error in reconnect - unexpected response."); @@ -470,7 +479,8 @@ public class MobileDataStateTracker implements NetworkStateTracker { if (DBG) log("setUserDataEnable: E enabled=" + enabled); final AsyncChannel channel = mDataConnectionTrackerAc; if (channel != null) { - channel.sendMessage(CMD_SET_USER_DATA_ENABLE, enabled ? ENABLED : DISABLED); + channel.sendMessage(DctConstants.CMD_SET_USER_DATA_ENABLE, + enabled ? DctConstants.ENABLED : DctConstants.DISABLED); mUserDataEnabled = enabled; } if (VDBG) log("setUserDataEnable: X enabled=" + enabled); @@ -481,7 +491,8 @@ public class MobileDataStateTracker implements NetworkStateTracker { if (DBG) log("setPolicyDataEnable(enabled=" + enabled + ")"); final AsyncChannel channel = mDataConnectionTrackerAc; if (channel != null) { - channel.sendMessage(CMD_SET_POLICY_DATA_ENABLE, enabled ? ENABLED : DISABLED); + channel.sendMessage(DctConstants.CMD_SET_POLICY_DATA_ENABLE, + enabled ? DctConstants.ENABLED : DctConstants.DISABLED); mPolicyDataEnabled = enabled; } } @@ -491,12 +502,12 @@ public class MobileDataStateTracker implements NetworkStateTracker { * @param met */ public void setDependencyMet(boolean met) { - Bundle bundle = Bundle.forPair(DataConnectionTracker.APN_TYPE_KEY, mApnType); + Bundle bundle = Bundle.forPair(DctConstants.APN_TYPE_KEY, mApnType); try { if (DBG) log("setDependencyMet: E met=" + met); Message msg = Message.obtain(); - msg.what = DataConnectionTracker.CMD_SET_DEPENDENCY_MET; - msg.arg1 = (met ? DataConnectionTracker.ENABLED : DataConnectionTracker.DISABLED); + msg.what = DctConstants.CMD_SET_DEPENDENCY_MET; + msg.arg1 = (met ? DctConstants.ENABLED : DctConstants.DISABLED); msg.setData(bundle); mDataConnectionTrackerAc.sendMessage(msg); if (VDBG) log("setDependencyMet: X met=" + met); @@ -546,27 +557,27 @@ public class MobileDataStateTracker implements NetworkStateTracker { } loge("Could not " + (enable ? "enable" : "disable") + " APN type \"" + apnType + "\""); - return Phone.APN_REQUEST_FAILED; + return PhoneConstants.APN_REQUEST_FAILED; } public static String networkTypeToApnType(int netType) { switch(netType) { case ConnectivityManager.TYPE_MOBILE: - return Phone.APN_TYPE_DEFAULT; // TODO - use just one of these + return PhoneConstants.APN_TYPE_DEFAULT; // TODO - use just one of these case ConnectivityManager.TYPE_MOBILE_MMS: - return Phone.APN_TYPE_MMS; + return PhoneConstants.APN_TYPE_MMS; case ConnectivityManager.TYPE_MOBILE_SUPL: - return Phone.APN_TYPE_SUPL; + return PhoneConstants.APN_TYPE_SUPL; case ConnectivityManager.TYPE_MOBILE_DUN: - return Phone.APN_TYPE_DUN; + return PhoneConstants.APN_TYPE_DUN; case ConnectivityManager.TYPE_MOBILE_HIPRI: - return Phone.APN_TYPE_HIPRI; + return PhoneConstants.APN_TYPE_HIPRI; case ConnectivityManager.TYPE_MOBILE_FOTA: - return Phone.APN_TYPE_FOTA; + return PhoneConstants.APN_TYPE_FOTA; case ConnectivityManager.TYPE_MOBILE_IMS: - return Phone.APN_TYPE_IMS; + return PhoneConstants.APN_TYPE_IMS; case ConnectivityManager.TYPE_MOBILE_CBS: - return Phone.APN_TYPE_CBS; + return PhoneConstants.APN_TYPE_CBS; default: sloge("Error mapping networkType " + netType + " to apnType."); return null; diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java index 7df0193..0d6dcd6 100644 --- a/core/java/android/net/NetworkStateTracker.java +++ b/core/java/android/net/NetworkStateTracker.java @@ -69,6 +69,12 @@ public interface NetworkStateTracker { public static final int EVENT_RESTORE_DEFAULT_NETWORK = 6; /** + * msg.what = EVENT_NETWORK_SUBTYPE_CHANGED + * msg.obj = NetworkInfo object + */ + public static final int EVENT_NETWORK_SUBTYPE_CHANGED = 7; + + /** * ------------------------------------------------------------- * Control Interface * ------------------------------------------------------------- diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java index fb5263d..65d3f2b 100644 --- a/core/java/android/net/VpnService.java +++ b/core/java/android/net/VpnService.java @@ -329,7 +329,7 @@ public class VpnService extends Service { throw new IllegalArgumentException("Bad address"); } - mAddresses.append(String.format(" %s/%d", address.getHostAddress(), prefixLength)); + mAddresses.append(' ' + address.getHostAddress() + '/' + prefixLength); return this; } diff --git a/core/java/android/net/arp/ArpPeer.java b/core/java/android/net/arp/ArpPeer.java index 8e666bc..6ba1e7c 100644 --- a/core/java/android/net/arp/ArpPeer.java +++ b/core/java/android/net/arp/ArpPeer.java @@ -53,9 +53,11 @@ public class ArpPeer { mInterfaceName = interfaceName; mMyAddr = myAddr; - for (int i = 0; i < MAC_ADDR_LENGTH; i++) { - mMyMac[i] = (byte) Integer.parseInt(mac.substring( - i*3, (i*3) + 2), 16); + if (mac != null) { + for (int i = 0; i < MAC_ADDR_LENGTH; i++) { + mMyMac[i] = (byte) Integer.parseInt(mac.substring( + i*3, (i*3) + 2), 16); + } } if (myAddr instanceof Inet6Address || peer instanceof Inet6Address) { diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java index 6c1445d..0941d71 100644 --- a/core/java/android/os/FileUtils.java +++ b/core/java/android/os/FileUtils.java @@ -28,9 +28,6 @@ import java.util.regex.Pattern; import java.util.zip.CRC32; import java.util.zip.CheckedInputStream; -import libcore.io.Os; -import libcore.io.StructStat; - /** * Tools for managing files. Not for public consumption. * @hide @@ -50,60 +47,12 @@ public class FileUtils { public static final int S_IROTH = 00004; public static final int S_IWOTH = 00002; public static final int S_IXOTH = 00001; - - - /** - * File status information. This class maps directly to the POSIX stat structure. - * @deprecated use {@link StructStat} instead. - * @hide - */ - @Deprecated - public static final class FileStatus { - public int dev; - public int ino; - public int mode; - public int nlink; - public int uid; - public int gid; - public int rdev; - public long size; - public int blksize; - public long blocks; - public long atime; - public long mtime; - public long ctime; - } - - /** - * Get the status for the given path. This is equivalent to the POSIX stat(2) system call. - * @param path The path of the file to be stat'd. - * @param status Optional argument to fill in. It will only fill in the status if the file - * exists. - * @return true if the file exists and false if it does not exist. If you do not have - * permission to stat the file, then this method will return false. - * @deprecated use {@link Os#stat(String)} instead. - */ - @Deprecated - public static boolean getFileStatus(String path, FileStatus status) { - StrictMode.noteDiskRead(); - return getFileStatusNative(path, status); - } - - private static native boolean getFileStatusNative(String path, FileStatus status); /** Regular expression for safe filenames: no spaces or metacharacters */ private static final Pattern SAFE_FILENAME_PATTERN = Pattern.compile("[\\w%+,./=_-]+"); public static native int setPermissions(String file, int mode, int uid, int gid); - /** - * @deprecated use {@link Os#stat(String)} instead. - */ - @Deprecated - public static native int getPermissions(String file, int[] outPermissions); - - public static native int setUMask(int mask); - /** returns the FAT file system volume ID for the volume mounted * at the given mount point, or -1 for failure * @param mountPoint point for FAT volume diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 8eaeb1d..6ab4dc1 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -359,6 +359,7 @@ public class Process { * @param gids Additional group-ids associated with the process. * @param debugFlags Additional flags. * @param targetSdkVersion The target SDK version for the app. + * @param seInfo null-ok SE Android information for the new process. * @param zygoteArgs Additional arguments to supply to the zygote process. * * @return An object that describes the result of the attempt to start the process. @@ -370,10 +371,11 @@ public class Process { final String niceName, int uid, int gid, int[] gids, int debugFlags, int targetSdkVersion, + String seInfo, String[] zygoteArgs) { try { return startViaZygote(processClass, niceName, uid, gid, gids, - debugFlags, targetSdkVersion, zygoteArgs); + debugFlags, targetSdkVersion, seInfo, zygoteArgs); } catch (ZygoteStartFailedEx ex) { Log.e(LOG_TAG, "Starting VM process through Zygote failed"); @@ -536,6 +538,7 @@ public class Process { * new process should setgroup() to. * @param debugFlags Additional flags. * @param targetSdkVersion The target SDK version for the app. + * @param seInfo null-ok SE Android information for the new process. * @param extraArgs Additional arguments to supply to the zygote process. * @return An object that describes the result of the attempt to start the process. * @throws ZygoteStartFailedEx if process start failed for any reason @@ -545,6 +548,7 @@ public class Process { final int uid, final int gid, final int[] gids, int debugFlags, int targetSdkVersion, + String seInfo, String[] extraArgs) throws ZygoteStartFailedEx { synchronized(Process.class) { @@ -595,6 +599,10 @@ public class Process { argsForZygote.add("--nice-name=" + niceName); } + if (seInfo != null) { + argsForZygote.add("--seinfo=" + seInfo); + } + argsForZygote.add(processClass); if (extraArgs != null) { diff --git a/core/java/android/os/SELinux.java b/core/java/android/os/SELinux.java new file mode 100644 index 0000000..c05a974 --- /dev/null +++ b/core/java/android/os/SELinux.java @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2012 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 android.os; + +import android.util.Slog; + +import java.io.IOException; +import java.io.File; +import java.io.FileDescriptor; + +/** + * This class provides access to the centralized jni bindings for + * SELinux interaction. + * {@hide} + */ +public class SELinux { + + private static final String TAG = "SELinux"; + + /** + * Determine whether SELinux is disabled or enabled. + * @return a boolean indicating whether SELinux is enabled. + */ + public static final native boolean isSELinuxEnabled(); + + /** + * Determine whether SELinux is permissive or enforcing. + * @return a boolean indicating whether SELinux is enforcing. + */ + public static final native boolean isSELinuxEnforced(); + + /** + * Set whether SELinux is permissive or enforcing. + * @param boolean representing whether to set SELinux to enforcing + * @return a boolean representing whether the desired mode was set + */ + public static final native boolean setSELinuxEnforce(boolean value); + + /** + * Sets the security context for newly created file objects. + * @param context a security context given as a String. + * @return a boolean indicating whether the operation succeeded. + */ + public static final native boolean setFSCreateContext(String context); + + /** + * Change the security context of an existing file object. + * @param path representing the path of file object to relabel. + * @param con new security context given as a String. + * @return a boolean indicating whether the operation succeeded. + */ + public static final native boolean setFileContext(String path, String context); + + /** + * Get the security context of a file object. + * @param path the pathname of the file object. + * @return a security context given as a String. + */ + public static final native String getFileContext(String path); + + /** + * Get the security context of a peer socket. + * @param fd FileDescriptor class of the peer socket. + * @return a String representing the peer socket security context. + */ + public static final native String getPeerContext(FileDescriptor fd); + + /** + * Gets the security context of the current process. + * @return a String representing the security context of the current process. + */ + public static final native String getContext(); + + /** + * Gets the security context of a given process id. + * Use of this function is discouraged for Binder transactions. + * Use Binder.getCallingSecctx() instead. + * @param pid an int representing the process id to check. + * @return a String representing the security context of the given pid. + */ + public static final native String getPidContext(int pid); + + /** + * Gets a list of the SELinux boolean names. + * @return an array of strings containing the SELinux boolean names. + */ + public static final native String[] getBooleanNames(); + + /** + * Gets the value for the given SELinux boolean name. + * @param String The name of the SELinux boolean. + * @return a boolean indicating whether the SELinux boolean is set. + */ + public static final native boolean getBooleanValue(String name); + + /** + * Sets the value for the given SELinux boolean name. + * @param String The name of the SELinux boolean. + * @param Boolean The new value of the SELinux boolean. + * @return a boolean indicating whether or not the operation succeeded. + */ + public static final native boolean setBooleanValue(String name, boolean value); + + /** + * Check permissions between two security contexts. + * @param scon The source or subject security context. + * @param tcon The target or object security context. + * @param tclass The object security class name. + * @param perm The permission name. + * @return a boolean indicating whether permission was granted. + */ + public static final native boolean checkSELinuxAccess(String scon, String tcon, String tclass, String perm); + + /** + * Restores a file to its default SELinux security context. + * If the system is not compiled with SELinux, then {@code true} + * is automatically returned. + * If SELinux is compiled in, but disabled, then {@code true} is + * returned. + * + * @param pathname The pathname of the file to be relabeled. + * @return a boolean indicating whether the relabeling succeeded. + * @exception NullPointerException if the pathname is a null object. + */ + public static boolean restorecon(String pathname) throws NullPointerException { + if (pathname == null) { throw new NullPointerException(); } + return native_restorecon(pathname); + } + + /** + * Restores a file to its default SELinux security context. + * If the system is not compiled with SELinux, then {@code true} + * is automatically returned. + * If SELinux is compiled in, but disabled, then {@code true} is + * returned. + * + * @param pathname The pathname of the file to be relabeled. + * @return a boolean indicating whether the relabeling succeeded. + */ + private static native boolean native_restorecon(String pathname); + + /** + * Restores a file to its default SELinux security context. + * If the system is not compiled with SELinux, then {@code true} + * is automatically returned. + * If SELinux is compiled in, but disabled, then {@code true} is + * returned. + * + * @param file The File object representing the path to be relabeled. + * @return a boolean indicating whether the relabeling succeeded. + * @exception NullPointerException if the file is a null object. + */ + public static boolean restorecon(File file) throws NullPointerException { + try { + return native_restorecon(file.getCanonicalPath()); + } catch (IOException e) { + Slog.e(TAG, "Error getting canonical path. Restorecon failed for " + + file.getPath(), e); + return false; + } + } +} diff --git a/core/java/android/os/StatFs.java b/core/java/android/os/StatFs.java index 912bfdf..ca7fdba 100644 --- a/core/java/android/os/StatFs.java +++ b/core/java/android/os/StatFs.java @@ -16,59 +16,77 @@ package android.os; +import libcore.io.ErrnoException; +import libcore.io.Libcore; +import libcore.io.StructStatFs; + /** - * Retrieve overall information about the space on a filesystem. This is a - * Wrapper for Unix statfs(). + * Retrieve overall information about the space on a filesystem. This is a + * wrapper for Unix statfs(). */ public class StatFs { + private StructStatFs mStat; + /** - * Construct a new StatFs for looking at the stats of the - * filesystem at <var>path</var>. Upon construction, the stat of - * the file system will be performed, and the values retrieved available - * from the methods on this class. - * - * @param path A path in the desired file system to state. + * Construct a new StatFs for looking at the stats of the filesystem at + * {@code path}. Upon construction, the stat of the file system will be + * performed, and the values retrieved available from the methods on this + * class. + * + * @param path path in the desired file system to stat. */ - public StatFs(String path) { native_setup(path); } - + public StatFs(String path) { + mStat = doStat(path); + } + + private static StructStatFs doStat(String path) { + try { + return Libcore.os.statfs(path); + } catch (ErrnoException e) { + throw new IllegalArgumentException("Invalid path: " + path, e); + } + } + /** - * Perform a restat of the file system referenced by this object. This - * is the same as re-constructing the object with the same file system - * path, and the new stat values are available upon return. + * Perform a restat of the file system referenced by this object. This is + * the same as re-constructing the object with the same file system path, + * and the new stat values are available upon return. */ - public void restat(String path) { native_restat(path); } - - @Override - protected void finalize() { native_finalize(); } + public void restat(String path) { + mStat = doStat(path); + } /** - * The size, in bytes, of a block on the file system. This corresponds - * to the Unix statfs.f_bsize field. + * The size, in bytes, of a block on the file system. This corresponds to + * the Unix {@code statfs.f_bsize} field. */ - public native int getBlockSize(); + public int getBlockSize() { + return (int) mStat.f_bsize; + } /** - * The total number of blocks on the file system. This corresponds - * to the Unix statfs.f_blocks field. + * The total number of blocks on the file system. This corresponds to the + * Unix {@code statfs.f_blocks} field. */ - public native int getBlockCount(); + public int getBlockCount() { + return (int) mStat.f_blocks; + } /** * The total number of blocks that are free on the file system, including - * reserved blocks (that are not available to normal applications). This - * corresponds to the Unix statfs.f_bfree field. Most applications will - * want to use {@link #getAvailableBlocks()} instead. + * reserved blocks (that are not available to normal applications). This + * corresponds to the Unix {@code statfs.f_bfree} field. Most applications + * will want to use {@link #getAvailableBlocks()} instead. */ - public native int getFreeBlocks(); + public int getFreeBlocks() { + return (int) mStat.f_bfree; + } /** * The number of blocks that are free on the file system and available to - * applications. This corresponds to the Unix statfs.f_bavail field. + * applications. This corresponds to the Unix {@code statfs.f_bavail} field. */ - public native int getAvailableBlocks(); - - private int mNativeContext; - private native void native_restat(String path); - private native void native_setup(String path); - private native void native_finalize(); + public int getAvailableBlocks() { + return (int) mStat.f_bavail; + } } diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java index ce213fb..f682abe 100644 --- a/core/java/android/os/StrictMode.java +++ b/core/java/android/os/StrictMode.java @@ -407,17 +407,17 @@ public final class StrictMode { } /** - * Enable detection of disk reads. + * Enable detection of slow calls. */ public Builder detectCustomSlowCalls() { return enable(DETECT_CUSTOM); } /** - * Enable detection of disk reads. + * Disable detection of slow calls. */ public Builder permitCustomSlowCalls() { - return enable(DETECT_CUSTOM); + return disable(DETECT_CUSTOM); } /** diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index cb6c1dc..8a20a6e 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -56,7 +56,7 @@ public class StorageManager /* * Our internal MountService binder reference */ - private IMountService mMountService; + final private IMountService mMountService; /* * The looper target for callbacks @@ -304,8 +304,6 @@ public class StorageManager return; } mTgtLooper = tgtLooper; - mBinderListener = new MountServiceBinderListener(); - mMountService.registerListener(mBinderListener); } @@ -322,6 +320,15 @@ public class StorageManager } synchronized (mListeners) { + if (mBinderListener == null ) { + try { + mBinderListener = new MountServiceBinderListener(); + mMountService.registerListener(mBinderListener); + } catch (RemoteException rex) { + Log.e(TAG, "Register mBinderListener failed"); + return; + } + } mListeners.add(new ListenerDelegate(listener)); } } @@ -347,7 +354,15 @@ public class StorageManager break; } } - } + if (mListeners.size() == 0 && mBinderListener != null) { + try { + mMountService.unregisterListener(mBinderListener); + } catch (RemoteException rex) { + Log.e(TAG, "Unregister mBinderListener failed"); + return; + } + } + } } /** diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java index 7824724..22b68bc 100644 --- a/core/java/android/provider/CallLog.java +++ b/core/java/android/provider/CallLog.java @@ -18,7 +18,7 @@ package android.provider; import com.android.internal.telephony.CallerInfo; -import com.android.internal.telephony.Connection; +import com.android.internal.telephony.PhoneConstants; import android.content.ContentResolver; import android.content.ContentValues; @@ -267,14 +267,14 @@ public class CallLog { // If this is a private number then set the number to Private, otherwise check // if the number field is empty and set the number to Unavailable - if (presentation == Connection.PRESENTATION_RESTRICTED) { + if (presentation == PhoneConstants.PRESENTATION_RESTRICTED) { number = CallerInfo.PRIVATE_NUMBER; if (ci != null) ci.name = ""; - } else if (presentation == Connection.PRESENTATION_PAYPHONE) { + } else if (presentation == PhoneConstants.PRESENTATION_PAYPHONE) { number = CallerInfo.PAYPHONE_NUMBER; if (ci != null) ci.name = ""; } else if (TextUtils.isEmpty(number) - || presentation == Connection.PRESENTATION_UNKNOWN) { + || presentation == PhoneConstants.PRESENTATION_UNKNOWN) { number = CallerInfo.UNKNOWN_NUMBER; if (ci != null) ci.name = ""; } diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index 8e123ac..e7b0579 100644..100755 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -8362,7 +8362,7 @@ public final class ContactsContract { // Line contains the query string - now search for it at the start of tokens. List<String> lineTokens = new ArrayList<String>(); List<Integer> tokenOffsets = new ArrayList<Integer>(); - split(contentLine.trim(), lineTokens, tokenOffsets); + split(contentLine, lineTokens, tokenOffsets); // As we find matches against the query, we'll populate this list with the marked // (or unchanged) tokens. diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java deleted file mode 100755 index 19d8d5c..0000000 --- a/core/java/android/provider/Telephony.java +++ /dev/null @@ -1,2037 +0,0 @@ -/* - * Copyright (C) 2006 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 android.provider; - -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.content.Intent; -import android.database.Cursor; -import android.database.sqlite.SqliteWrapper; -import android.net.Uri; -import android.os.Environment; -import android.telephony.SmsMessage; -import android.text.TextUtils; -import android.util.Log; -import android.util.Patterns; - - -import java.util.HashSet; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * The Telephony provider contains data related to phone operation. - * - * @hide - */ -public final class Telephony { - private static final String TAG = "Telephony"; - private static final boolean DEBUG = true; - private static final boolean LOCAL_LOGV = false; - - // Constructor - public Telephony() { - } - - /** - * Base columns for tables that contain text based SMSs. - */ - public interface TextBasedSmsColumns { - /** - * The type of the message - * <P>Type: INTEGER</P> - */ - public static final String TYPE = "type"; - - public static final int MESSAGE_TYPE_ALL = 0; - public static final int MESSAGE_TYPE_INBOX = 1; - public static final int MESSAGE_TYPE_SENT = 2; - public static final int MESSAGE_TYPE_DRAFT = 3; - public static final int MESSAGE_TYPE_OUTBOX = 4; - public static final int MESSAGE_TYPE_FAILED = 5; // for failed outgoing messages - public static final int MESSAGE_TYPE_QUEUED = 6; // for messages to send later - - - /** - * The thread ID of the message - * <P>Type: INTEGER</P> - */ - public static final String THREAD_ID = "thread_id"; - - /** - * The address of the other party - * <P>Type: TEXT</P> - */ - public static final String ADDRESS = "address"; - - /** - * The person ID of the sender - * <P>Type: INTEGER (long)</P> - */ - public static final String PERSON_ID = "person"; - - /** - * The date the message was received - * <P>Type: INTEGER (long)</P> - */ - public static final String DATE = "date"; - - /** - * The date the message was sent - * <P>Type: INTEGER (long)</P> - */ - public static final String DATE_SENT = "date_sent"; - - /** - * Has the message been read - * <P>Type: INTEGER (boolean)</P> - */ - public static final String READ = "read"; - - /** - * Indicates whether this message has been seen by the user. The "seen" flag will be - * used to figure out whether we need to throw up a statusbar notification or not. - */ - public static final String SEEN = "seen"; - - /** - * The TP-Status value for the message, or -1 if no status has - * been received - */ - public static final String STATUS = "status"; - - public static final int STATUS_NONE = -1; - public static final int STATUS_COMPLETE = 0; - public static final int STATUS_PENDING = 32; - public static final int STATUS_FAILED = 64; - - /** - * The subject of the message, if present - * <P>Type: TEXT</P> - */ - public static final String SUBJECT = "subject"; - - /** - * The body of the message - * <P>Type: TEXT</P> - */ - public static final String BODY = "body"; - - /** - * The id of the sender of the conversation, if present - * <P>Type: INTEGER (reference to item in content://contacts/people)</P> - */ - public static final String PERSON = "person"; - - /** - * The protocol identifier code - * <P>Type: INTEGER</P> - */ - public static final String PROTOCOL = "protocol"; - - /** - * Whether the <code>TP-Reply-Path</code> bit was set on this message - * <P>Type: BOOLEAN</P> - */ - public static final String REPLY_PATH_PRESENT = "reply_path_present"; - - /** - * The service center (SC) through which to send the message, if present - * <P>Type: TEXT</P> - */ - public static final String SERVICE_CENTER = "service_center"; - - /** - * Has the message been locked? - * <P>Type: INTEGER (boolean)</P> - */ - public static final String LOCKED = "locked"; - - /** - * Error code associated with sending or receiving this message - * <P>Type: INTEGER</P> - */ - public static final String ERROR_CODE = "error_code"; - - /** - * Meta data used externally. - * <P>Type: TEXT</P> - */ - public static final String META_DATA = "meta_data"; -} - - /** - * Contains all text based SMS messages. - */ - public static final class Sms implements BaseColumns, TextBasedSmsColumns { - public static final Cursor query(ContentResolver cr, String[] projection) { - return cr.query(CONTENT_URI, projection, null, null, DEFAULT_SORT_ORDER); - } - - public static final Cursor query(ContentResolver cr, String[] projection, - String where, String orderBy) { - return cr.query(CONTENT_URI, projection, where, - null, orderBy == null ? DEFAULT_SORT_ORDER : orderBy); - } - - /** - * The content:// style URL for this table - */ - public static final Uri CONTENT_URI = - Uri.parse("content://sms"); - - /** - * The default sort order for this table - */ - public static final String DEFAULT_SORT_ORDER = "date DESC"; - - /** - * Add an SMS to the given URI. - * - * @param resolver the content resolver to use - * @param uri the URI to add the message to - * @param address the address of the sender - * @param body the body of the message - * @param subject the psuedo-subject of the message - * @param date the timestamp for the message - * @param read true if the message has been read, false if not - * @param deliveryReport true if a delivery report was requested, false if not - * @return the URI for the new message - */ - public static Uri addMessageToUri(ContentResolver resolver, - Uri uri, String address, String body, String subject, - Long date, boolean read, boolean deliveryReport) { - return addMessageToUri(resolver, uri, address, body, subject, - date, read, deliveryReport, -1L); - } - - /** - * Add an SMS to the given URI with thread_id specified. - * - * @param resolver the content resolver to use - * @param uri the URI to add the message to - * @param address the address of the sender - * @param body the body of the message - * @param subject the psuedo-subject of the message - * @param date the timestamp for the message - * @param read true if the message has been read, false if not - * @param deliveryReport true if a delivery report was requested, false if not - * @param threadId the thread_id of the message - * @return the URI for the new message - */ - public static Uri addMessageToUri(ContentResolver resolver, - Uri uri, String address, String body, String subject, - Long date, boolean read, boolean deliveryReport, long threadId) { - ContentValues values = new ContentValues(7); - - values.put(ADDRESS, address); - if (date != null) { - values.put(DATE, date); - } - values.put(READ, read ? Integer.valueOf(1) : Integer.valueOf(0)); - values.put(SUBJECT, subject); - values.put(BODY, body); - if (deliveryReport) { - values.put(STATUS, STATUS_PENDING); - } - if (threadId != -1L) { - values.put(THREAD_ID, threadId); - } - return resolver.insert(uri, values); - } - - /** - * Move a message to the given folder. - * - * @param context the context to use - * @param uri the message to move - * @param folder the folder to move to - * @return true if the operation succeeded - */ - public static boolean moveMessageToFolder(Context context, - Uri uri, int folder, int error) { - if (uri == null) { - return false; - } - - boolean markAsUnread = false; - boolean markAsRead = false; - switch(folder) { - case MESSAGE_TYPE_INBOX: - case MESSAGE_TYPE_DRAFT: - break; - case MESSAGE_TYPE_OUTBOX: - case MESSAGE_TYPE_SENT: - markAsRead = true; - break; - case MESSAGE_TYPE_FAILED: - case MESSAGE_TYPE_QUEUED: - markAsUnread = true; - break; - default: - return false; - } - - ContentValues values = new ContentValues(3); - - values.put(TYPE, folder); - if (markAsUnread) { - values.put(READ, Integer.valueOf(0)); - } else if (markAsRead) { - values.put(READ, Integer.valueOf(1)); - } - values.put(ERROR_CODE, error); - - return 1 == SqliteWrapper.update(context, context.getContentResolver(), - uri, values, null, null); - } - - /** - * Returns true iff the folder (message type) identifies an - * outgoing message. - */ - public static boolean isOutgoingFolder(int messageType) { - return (messageType == MESSAGE_TYPE_FAILED) - || (messageType == MESSAGE_TYPE_OUTBOX) - || (messageType == MESSAGE_TYPE_SENT) - || (messageType == MESSAGE_TYPE_QUEUED); - } - - /** - * Contains all text based SMS messages in the SMS app's inbox. - */ - public static final class Inbox implements BaseColumns, TextBasedSmsColumns { - /** - * The content:// style URL for this table - */ - public static final Uri CONTENT_URI = - Uri.parse("content://sms/inbox"); - - /** - * The default sort order for this table - */ - public static final String DEFAULT_SORT_ORDER = "date DESC"; - - /** - * Add an SMS to the Draft box. - * - * @param resolver the content resolver to use - * @param address the address of the sender - * @param body the body of the message - * @param subject the psuedo-subject of the message - * @param date the timestamp for the message - * @param read true if the message has been read, false if not - * @return the URI for the new message - */ - public static Uri addMessage(ContentResolver resolver, - String address, String body, String subject, Long date, - boolean read) { - return addMessageToUri(resolver, CONTENT_URI, address, body, - subject, date, read, false); - } - } - - /** - * Contains all sent text based SMS messages in the SMS app's. - */ - public static final class Sent implements BaseColumns, TextBasedSmsColumns { - /** - * The content:// style URL for this table - */ - public static final Uri CONTENT_URI = - Uri.parse("content://sms/sent"); - - /** - * The default sort order for this table - */ - public static final String DEFAULT_SORT_ORDER = "date DESC"; - - /** - * Add an SMS to the Draft box. - * - * @param resolver the content resolver to use - * @param address the address of the sender - * @param body the body of the message - * @param subject the psuedo-subject of the message - * @param date the timestamp for the message - * @return the URI for the new message - */ - public static Uri addMessage(ContentResolver resolver, - String address, String body, String subject, Long date) { - return addMessageToUri(resolver, CONTENT_URI, address, body, - subject, date, true, false); - } - } - - /** - * Contains all sent text based SMS messages in the SMS app's. - */ - public static final class Draft implements BaseColumns, TextBasedSmsColumns { - /** - * The content:// style URL for this table - */ - public static final Uri CONTENT_URI = - Uri.parse("content://sms/draft"); - - /** - * The default sort order for this table - */ - public static final String DEFAULT_SORT_ORDER = "date DESC"; - - /** - * Add an SMS to the Draft box. - * - * @param resolver the content resolver to use - * @param address the address of the sender - * @param body the body of the message - * @param subject the psuedo-subject of the message - * @param date the timestamp for the message - * @return the URI for the new message - */ - public static Uri addMessage(ContentResolver resolver, - String address, String body, String subject, Long date) { - return addMessageToUri(resolver, CONTENT_URI, address, body, - subject, date, true, false); - } - - /** - * Save over an existing draft message. - * - * @param resolver the content resolver to use - * @param uri of existing message - * @param body the new body for the draft message - * @return true is successful, false otherwise - */ - public static boolean saveMessage(ContentResolver resolver, - Uri uri, String body) { - ContentValues values = new ContentValues(2); - values.put(BODY, body); - values.put(DATE, System.currentTimeMillis()); - return resolver.update(uri, values, null, null) == 1; - } - } - - /** - * Contains all pending outgoing text based SMS messages. - */ - public static final class Outbox implements BaseColumns, TextBasedSmsColumns { - /** - * The content:// style URL for this table - */ - public static final Uri CONTENT_URI = - Uri.parse("content://sms/outbox"); - - /** - * The default sort order for this table - */ - public static final String DEFAULT_SORT_ORDER = "date DESC"; - - /** - * Add an SMS to the Out box. - * - * @param resolver the content resolver to use - * @param address the address of the sender - * @param body the body of the message - * @param subject the psuedo-subject of the message - * @param date the timestamp for the message - * @param deliveryReport whether a delivery report was requested for the message - * @return the URI for the new message - */ - public static Uri addMessage(ContentResolver resolver, - String address, String body, String subject, Long date, - boolean deliveryReport, long threadId) { - return addMessageToUri(resolver, CONTENT_URI, address, body, - subject, date, true, deliveryReport, threadId); - } - } - - /** - * Contains all sent text-based SMS messages in the SMS app's. - */ - public static final class Conversations - implements BaseColumns, TextBasedSmsColumns { - /** - * The content:// style URL for this table - */ - public static final Uri CONTENT_URI = - Uri.parse("content://sms/conversations"); - - /** - * The default sort order for this table - */ - public static final String DEFAULT_SORT_ORDER = "date DESC"; - - /** - * The first 45 characters of the body of the message - * <P>Type: TEXT</P> - */ - public static final String SNIPPET = "snippet"; - - /** - * The number of messages in the conversation - * <P>Type: INTEGER</P> - */ - public static final String MESSAGE_COUNT = "msg_count"; - } - - /** - * Contains info about SMS related Intents that are broadcast. - */ - public static final class Intents { - /** - * Set by BroadcastReceiver. Indicates the message was handled - * successfully. - */ - public static final int RESULT_SMS_HANDLED = 1; - - /** - * Set by BroadcastReceiver. Indicates a generic error while - * processing the message. - */ - public static final int RESULT_SMS_GENERIC_ERROR = 2; - - /** - * Set by BroadcastReceiver. Indicates insufficient memory to store - * the message. - */ - public static final int RESULT_SMS_OUT_OF_MEMORY = 3; - - /** - * Set by BroadcastReceiver. Indicates the message, while - * possibly valid, is of a format or encoding that is not - * supported. - */ - public static final int RESULT_SMS_UNSUPPORTED = 4; - - /** - * Broadcast Action: A new text based SMS message has been received - * by the device. The intent will have the following extra - * values:</p> - * - * <ul> - * <li><em>pdus</em> - An Object[] od byte[]s containing the PDUs - * that make up the message.</li> - * </ul> - * - * <p>The extra values can be extracted using - * {@link #getMessagesFromIntent(Intent)}.</p> - * - * <p>If a BroadcastReceiver encounters an error while processing - * this intent it should set the result code appropriately.</p> - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String SMS_RECEIVED_ACTION = - "android.provider.Telephony.SMS_RECEIVED"; - - /** - * Broadcast Action: A new data based SMS message has been received - * by the device. The intent will have the following extra - * values:</p> - * - * <ul> - * <li><em>pdus</em> - An Object[] of byte[]s containing the PDUs - * that make up the message.</li> - * </ul> - * - * <p>The extra values can be extracted using - * {@link #getMessagesFromIntent(Intent)}.</p> - * - * <p>If a BroadcastReceiver encounters an error while processing - * this intent it should set the result code appropriately.</p> - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String DATA_SMS_RECEIVED_ACTION = - "android.intent.action.DATA_SMS_RECEIVED"; - - /** - * Broadcast Action: A new WAP PUSH message has been received by the - * device. The intent will have the following extra - * values:</p> - * - * <ul> - * <li><em>transactionId (Integer)</em> - The WAP transaction ID</li> - * <li><em>pduType (Integer)</em> - The WAP PDU type</li> - * <li><em>header (byte[])</em> - The header of the message</li> - * <li><em>data (byte[])</em> - The data payload of the message</li> - * <li><em>contentTypeParameters (HashMap<String,String>)</em> - * - Any parameters associated with the content type - * (decoded from the WSP Content-Type header)</li> - * </ul> - * - * <p>If a BroadcastReceiver encounters an error while processing - * this intent it should set the result code appropriately.</p> - * - * <p>The contentTypeParameters extra value is map of content parameters keyed by - * their names.</p> - * - * <p>If any unassigned well-known parameters are encountered, the key of the map will - * be 'unassigned/0x...', where '...' is the hex value of the unassigned parameter. If - * a parameter has No-Value the value in the map will be null.</p> - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String WAP_PUSH_RECEIVED_ACTION = - "android.provider.Telephony.WAP_PUSH_RECEIVED"; - - /** - * Broadcast Action: A new Cell Broadcast message has been received - * by the device. The intent will have the following extra - * values:</p> - * - * <ul> - * <li><em>message</em> - An SmsCbMessage object containing the broadcast message - * data. This is not an emergency alert, so ETWS and CMAS data will be null.</li> - * </ul> - * - * <p>The extra values can be extracted using - * {@link #getMessagesFromIntent(Intent)}.</p> - * - * <p>If a BroadcastReceiver encounters an error while processing - * this intent it should set the result code appropriately.</p> - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String SMS_CB_RECEIVED_ACTION = - "android.provider.Telephony.SMS_CB_RECEIVED"; - - /** - * Broadcast Action: A new Emergency Broadcast message has been received - * by the device. The intent will have the following extra - * values:</p> - * - * <ul> - * <li><em>message</em> - An SmsCbMessage object containing the broadcast message - * data, including ETWS or CMAS warning notification info if present.</li> - * </ul> - * - * <p>The extra values can be extracted using - * {@link #getMessagesFromIntent(Intent)}.</p> - * - * <p>If a BroadcastReceiver encounters an error while processing - * this intent it should set the result code appropriately.</p> - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String SMS_EMERGENCY_CB_RECEIVED_ACTION = - "android.provider.Telephony.SMS_EMERGENCY_CB_RECEIVED"; - - /** - * Broadcast Action: A new CDMA SMS has been received containing Service Category - * Program Data (updates the list of enabled broadcast channels). The intent will - * have the following extra values:</p> - * - * <ul> - * <li><em>operations</em> - An array of CdmaSmsCbProgramData objects containing - * the service category operations (add/delete/clear) to perform.</li> - * </ul> - * - * <p>The extra values can be extracted using - * {@link #getMessagesFromIntent(Intent)}.</p> - * - * <p>If a BroadcastReceiver encounters an error while processing - * this intent it should set the result code appropriately.</p> - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION = - "android.provider.Telephony.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED"; - - /** - * Broadcast Action: The SIM storage for SMS messages is full. If - * space is not freed, messages targeted for the SIM (class 2) may - * not be saved. - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String SIM_FULL_ACTION = - "android.provider.Telephony.SIM_FULL"; - - /** - * Broadcast Action: An incoming SMS has been rejected by the - * telephony framework. This intent is sent in lieu of any - * of the RECEIVED_ACTION intents. The intent will have the - * following extra value:</p> - * - * <ul> - * <li><em>result</em> - An int result code, eg, - * <code>{@link #RESULT_SMS_OUT_OF_MEMORY}</code>, - * indicating the error returned to the network.</li> - * </ul> - - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String SMS_REJECTED_ACTION = - "android.provider.Telephony.SMS_REJECTED"; - - /** - * Read the PDUs out of an {@link #SMS_RECEIVED_ACTION} or a - * {@link #DATA_SMS_RECEIVED_ACTION} intent. - * - * @param intent the intent to read from - * @return an array of SmsMessages for the PDUs - */ - public static SmsMessage[] getMessagesFromIntent( - Intent intent) { - Object[] messages = (Object[]) intent.getSerializableExtra("pdus"); - String format = intent.getStringExtra("format"); - byte[][] pduObjs = new byte[messages.length][]; - - for (int i = 0; i < messages.length; i++) { - pduObjs[i] = (byte[]) messages[i]; - } - byte[][] pdus = new byte[pduObjs.length][]; - int pduCount = pdus.length; - SmsMessage[] msgs = new SmsMessage[pduCount]; - for (int i = 0; i < pduCount; i++) { - pdus[i] = pduObjs[i]; - msgs[i] = SmsMessage.createFromPdu(pdus[i], format); - } - return msgs; - } - } - } - - /** - * Base columns for tables that contain MMSs. - */ - public interface BaseMmsColumns extends BaseColumns { - - public static final int MESSAGE_BOX_ALL = 0; - public static final int MESSAGE_BOX_INBOX = 1; - public static final int MESSAGE_BOX_SENT = 2; - public static final int MESSAGE_BOX_DRAFTS = 3; - public static final int MESSAGE_BOX_OUTBOX = 4; - - /** - * The date the message was received. - * <P>Type: INTEGER (long)</P> - */ - public static final String DATE = "date"; - - /** - * The date the message was sent. - * <P>Type: INTEGER (long)</P> - */ - public static final String DATE_SENT = "date_sent"; - - /** - * The box which the message belong to, for example, MESSAGE_BOX_INBOX. - * <P>Type: INTEGER</P> - */ - public static final String MESSAGE_BOX = "msg_box"; - - /** - * Has the message been read. - * <P>Type: INTEGER (boolean)</P> - */ - public static final String READ = "read"; - - /** - * Indicates whether this message has been seen by the user. The "seen" flag will be - * used to figure out whether we need to throw up a statusbar notification or not. - */ - public static final String SEEN = "seen"; - - /** - * The Message-ID of the message. - * <P>Type: TEXT</P> - */ - public static final String MESSAGE_ID = "m_id"; - - /** - * The subject of the message, if present. - * <P>Type: TEXT</P> - */ - public static final String SUBJECT = "sub"; - - /** - * The character set of the subject, if present. - * <P>Type: INTEGER</P> - */ - public static final String SUBJECT_CHARSET = "sub_cs"; - - /** - * The Content-Type of the message. - * <P>Type: TEXT</P> - */ - public static final String CONTENT_TYPE = "ct_t"; - - /** - * The Content-Location of the message. - * <P>Type: TEXT</P> - */ - public static final String CONTENT_LOCATION = "ct_l"; - - /** - * The address of the sender. - * <P>Type: TEXT</P> - */ - public static final String FROM = "from"; - - /** - * The address of the recipients. - * <P>Type: TEXT</P> - */ - public static final String TO = "to"; - - /** - * The address of the cc. recipients. - * <P>Type: TEXT</P> - */ - public static final String CC = "cc"; - - /** - * The address of the bcc. recipients. - * <P>Type: TEXT</P> - */ - public static final String BCC = "bcc"; - - /** - * The expiry time of the message. - * <P>Type: INTEGER</P> - */ - public static final String EXPIRY = "exp"; - - /** - * The class of the message. - * <P>Type: TEXT</P> - */ - public static final String MESSAGE_CLASS = "m_cls"; - - /** - * The type of the message defined by MMS spec. - * <P>Type: INTEGER</P> - */ - public static final String MESSAGE_TYPE = "m_type"; - - /** - * The version of specification that this message conform. - * <P>Type: INTEGER</P> - */ - public static final String MMS_VERSION = "v"; - - /** - * The size of the message. - * <P>Type: INTEGER</P> - */ - public static final String MESSAGE_SIZE = "m_size"; - - /** - * The priority of the message. - * <P>Type: TEXT</P> - */ - public static final String PRIORITY = "pri"; - - /** - * The read-report of the message. - * <P>Type: TEXT</P> - */ - public static final String READ_REPORT = "rr"; - - /** - * Whether the report is allowed. - * <P>Type: TEXT</P> - */ - public static final String REPORT_ALLOWED = "rpt_a"; - - /** - * The response-status of the message. - * <P>Type: INTEGER</P> - */ - public static final String RESPONSE_STATUS = "resp_st"; - - /** - * The status of the message. - * <P>Type: INTEGER</P> - */ - public static final String STATUS = "st"; - - /** - * The transaction-id of the message. - * <P>Type: TEXT</P> - */ - public static final String TRANSACTION_ID = "tr_id"; - - /** - * The retrieve-status of the message. - * <P>Type: INTEGER</P> - */ - public static final String RETRIEVE_STATUS = "retr_st"; - - /** - * The retrieve-text of the message. - * <P>Type: TEXT</P> - */ - public static final String RETRIEVE_TEXT = "retr_txt"; - - /** - * The character set of the retrieve-text. - * <P>Type: TEXT</P> - */ - public static final String RETRIEVE_TEXT_CHARSET = "retr_txt_cs"; - - /** - * The read-status of the message. - * <P>Type: INTEGER</P> - */ - public static final String READ_STATUS = "read_status"; - - /** - * The content-class of the message. - * <P>Type: INTEGER</P> - */ - public static final String CONTENT_CLASS = "ct_cls"; - - /** - * The delivery-report of the message. - * <P>Type: INTEGER</P> - */ - public static final String DELIVERY_REPORT = "d_rpt"; - - /** - * The delivery-time-token of the message. - * <P>Type: INTEGER</P> - */ - public static final String DELIVERY_TIME_TOKEN = "d_tm_tok"; - - /** - * The delivery-time of the message. - * <P>Type: INTEGER</P> - */ - public static final String DELIVERY_TIME = "d_tm"; - - /** - * The response-text of the message. - * <P>Type: TEXT</P> - */ - public static final String RESPONSE_TEXT = "resp_txt"; - - /** - * The sender-visibility of the message. - * <P>Type: TEXT</P> - */ - public static final String SENDER_VISIBILITY = "s_vis"; - - /** - * The reply-charging of the message. - * <P>Type: INTEGER</P> - */ - public static final String REPLY_CHARGING = "r_chg"; - - /** - * The reply-charging-deadline-token of the message. - * <P>Type: INTEGER</P> - */ - public static final String REPLY_CHARGING_DEADLINE_TOKEN = "r_chg_dl_tok"; - - /** - * The reply-charging-deadline of the message. - * <P>Type: INTEGER</P> - */ - public static final String REPLY_CHARGING_DEADLINE = "r_chg_dl"; - - /** - * The reply-charging-id of the message. - * <P>Type: TEXT</P> - */ - public static final String REPLY_CHARGING_ID = "r_chg_id"; - - /** - * The reply-charging-size of the message. - * <P>Type: INTEGER</P> - */ - public static final String REPLY_CHARGING_SIZE = "r_chg_sz"; - - /** - * The previously-sent-by of the message. - * <P>Type: TEXT</P> - */ - public static final String PREVIOUSLY_SENT_BY = "p_s_by"; - - /** - * The previously-sent-date of the message. - * <P>Type: INTEGER</P> - */ - public static final String PREVIOUSLY_SENT_DATE = "p_s_d"; - - /** - * The store of the message. - * <P>Type: TEXT</P> - */ - public static final String STORE = "store"; - - /** - * The mm-state of the message. - * <P>Type: INTEGER</P> - */ - public static final String MM_STATE = "mm_st"; - - /** - * The mm-flags-token of the message. - * <P>Type: INTEGER</P> - */ - public static final String MM_FLAGS_TOKEN = "mm_flg_tok"; - - /** - * The mm-flags of the message. - * <P>Type: TEXT</P> - */ - public static final String MM_FLAGS = "mm_flg"; - - /** - * The store-status of the message. - * <P>Type: TEXT</P> - */ - public static final String STORE_STATUS = "store_st"; - - /** - * The store-status-text of the message. - * <P>Type: TEXT</P> - */ - public static final String STORE_STATUS_TEXT = "store_st_txt"; - - /** - * The stored of the message. - * <P>Type: TEXT</P> - */ - public static final String STORED = "stored"; - - /** - * The totals of the message. - * <P>Type: TEXT</P> - */ - public static final String TOTALS = "totals"; - - /** - * The mbox-totals of the message. - * <P>Type: TEXT</P> - */ - public static final String MBOX_TOTALS = "mb_t"; - - /** - * The mbox-totals-token of the message. - * <P>Type: INTEGER</P> - */ - public static final String MBOX_TOTALS_TOKEN = "mb_t_tok"; - - /** - * The quotas of the message. - * <P>Type: TEXT</P> - */ - public static final String QUOTAS = "qt"; - - /** - * The mbox-quotas of the message. - * <P>Type: TEXT</P> - */ - public static final String MBOX_QUOTAS = "mb_qt"; - - /** - * The mbox-quotas-token of the message. - * <P>Type: INTEGER</P> - */ - public static final String MBOX_QUOTAS_TOKEN = "mb_qt_tok"; - - /** - * The message-count of the message. - * <P>Type: INTEGER</P> - */ - public static final String MESSAGE_COUNT = "m_cnt"; - - /** - * The start of the message. - * <P>Type: INTEGER</P> - */ - public static final String START = "start"; - - /** - * The distribution-indicator of the message. - * <P>Type: TEXT</P> - */ - public static final String DISTRIBUTION_INDICATOR = "d_ind"; - - /** - * The element-descriptor of the message. - * <P>Type: TEXT</P> - */ - public static final String ELEMENT_DESCRIPTOR = "e_des"; - - /** - * The limit of the message. - * <P>Type: INTEGER</P> - */ - public static final String LIMIT = "limit"; - - /** - * The recommended-retrieval-mode of the message. - * <P>Type: INTEGER</P> - */ - public static final String RECOMMENDED_RETRIEVAL_MODE = "r_r_mod"; - - /** - * The recommended-retrieval-mode-text of the message. - * <P>Type: TEXT</P> - */ - public static final String RECOMMENDED_RETRIEVAL_MODE_TEXT = "r_r_mod_txt"; - - /** - * The status-text of the message. - * <P>Type: TEXT</P> - */ - public static final String STATUS_TEXT = "st_txt"; - - /** - * The applic-id of the message. - * <P>Type: TEXT</P> - */ - public static final String APPLIC_ID = "apl_id"; - - /** - * The reply-applic-id of the message. - * <P>Type: TEXT</P> - */ - public static final String REPLY_APPLIC_ID = "r_apl_id"; - - /** - * The aux-applic-id of the message. - * <P>Type: TEXT</P> - */ - public static final String AUX_APPLIC_ID = "aux_apl_id"; - - /** - * The drm-content of the message. - * <P>Type: TEXT</P> - */ - public static final String DRM_CONTENT = "drm_c"; - - /** - * The adaptation-allowed of the message. - * <P>Type: TEXT</P> - */ - public static final String ADAPTATION_ALLOWED = "adp_a"; - - /** - * The replace-id of the message. - * <P>Type: TEXT</P> - */ - public static final String REPLACE_ID = "repl_id"; - - /** - * The cancel-id of the message. - * <P>Type: TEXT</P> - */ - public static final String CANCEL_ID = "cl_id"; - - /** - * The cancel-status of the message. - * <P>Type: INTEGER</P> - */ - public static final String CANCEL_STATUS = "cl_st"; - - /** - * The thread ID of the message - * <P>Type: INTEGER</P> - */ - public static final String THREAD_ID = "thread_id"; - - /** - * Has the message been locked? - * <P>Type: INTEGER (boolean)</P> - */ - public static final String LOCKED = "locked"; - - /** - * Meta data used externally. - * <P>Type: TEXT</P> - */ - public static final String META_DATA = "meta_data"; - } - - /** - * Columns for the "canonical_addresses" table used by MMS and - * SMS." - */ - public interface CanonicalAddressesColumns extends BaseColumns { - /** - * An address used in MMS or SMS. Email addresses are - * converted to lower case and are compared by string - * equality. Other addresses are compared using - * PHONE_NUMBERS_EQUAL. - * <P>Type: TEXT</P> - */ - public static final String ADDRESS = "address"; - } - - /** - * Columns for the "threads" table used by MMS and SMS. - */ - public interface ThreadsColumns extends BaseColumns { - /** - * The date at which the thread was created. - * - * <P>Type: INTEGER (long)</P> - */ - public static final String DATE = "date"; - - /** - * A string encoding of the recipient IDs of the recipients of - * the message, in numerical order and separated by spaces. - * <P>Type: TEXT</P> - */ - public static final String RECIPIENT_IDS = "recipient_ids"; - - /** - * The message count of the thread. - * <P>Type: INTEGER</P> - */ - public static final String MESSAGE_COUNT = "message_count"; - /** - * Indicates whether all messages of the thread have been read. - * <P>Type: INTEGER</P> - */ - public static final String READ = "read"; - - /** - * The snippet of the latest message in the thread. - * <P>Type: TEXT</P> - */ - public static final String SNIPPET = "snippet"; - /** - * The charset of the snippet. - * <P>Type: INTEGER</P> - */ - public static final String SNIPPET_CHARSET = "snippet_cs"; - /** - * Type of the thread, either Threads.COMMON_THREAD or - * Threads.BROADCAST_THREAD. - * <P>Type: INTEGER</P> - */ - public static final String TYPE = "type"; - /** - * Indicates whether there is a transmission error in the thread. - * <P>Type: INTEGER</P> - */ - public static final String ERROR = "error"; - /** - * Indicates whether this thread contains any attachments. - * <P>Type: INTEGER</P> - */ - public static final String HAS_ATTACHMENT = "has_attachment"; - } - - /** - * Helper functions for the "threads" table used by MMS and SMS. - */ - public static final class Threads implements ThreadsColumns { - private static final String[] ID_PROJECTION = { BaseColumns._ID }; - private static final String STANDARD_ENCODING = "UTF-8"; - private static final Uri THREAD_ID_CONTENT_URI = Uri.parse( - "content://mms-sms/threadID"); - public static final Uri CONTENT_URI = Uri.withAppendedPath( - MmsSms.CONTENT_URI, "conversations"); - public static final Uri OBSOLETE_THREADS_URI = Uri.withAppendedPath( - CONTENT_URI, "obsolete"); - - public static final int COMMON_THREAD = 0; - public static final int BROADCAST_THREAD = 1; - - // No one should construct an instance of this class. - private Threads() { - } - - /** - * This is a single-recipient version of - * getOrCreateThreadId. It's convenient for use with SMS - * messages. - */ - public static long getOrCreateThreadId(Context context, String recipient) { - Set<String> recipients = new HashSet<String>(); - - recipients.add(recipient); - return getOrCreateThreadId(context, recipients); - } - - /** - * Given the recipients list and subject of an unsaved message, - * return its thread ID. If the message starts a new thread, - * allocate a new thread ID. Otherwise, use the appropriate - * existing thread ID. - * - * Find the thread ID of the same set of recipients (in - * any order, without any additions). If one - * is found, return it. Otherwise, return a unique thread ID. - */ - public static long getOrCreateThreadId( - Context context, Set<String> recipients) { - Uri.Builder uriBuilder = THREAD_ID_CONTENT_URI.buildUpon(); - - for (String recipient : recipients) { - if (Mms.isEmailAddress(recipient)) { - recipient = Mms.extractAddrSpec(recipient); - } - - uriBuilder.appendQueryParameter("recipient", recipient); - } - - Uri uri = uriBuilder.build(); - //if (DEBUG) Log.v(TAG, "getOrCreateThreadId uri: " + uri); - - Cursor cursor = SqliteWrapper.query(context, context.getContentResolver(), - uri, ID_PROJECTION, null, null, null); - if (cursor != null) { - try { - if (cursor.moveToFirst()) { - return cursor.getLong(0); - } else { - Log.e(TAG, "getOrCreateThreadId returned no rows!"); - } - } finally { - cursor.close(); - } - } - - Log.e(TAG, "getOrCreateThreadId failed with uri " + uri.toString()); - throw new IllegalArgumentException("Unable to find or allocate a thread ID."); - } - } - - /** - * Contains all MMS messages. - */ - public static final class Mms implements BaseMmsColumns { - /** - * The content:// style URL for this table - */ - public static final Uri CONTENT_URI = Uri.parse("content://mms"); - - public static final Uri REPORT_REQUEST_URI = Uri.withAppendedPath( - CONTENT_URI, "report-request"); - - public static final Uri REPORT_STATUS_URI = Uri.withAppendedPath( - CONTENT_URI, "report-status"); - - /** - * The default sort order for this table - */ - public static final String DEFAULT_SORT_ORDER = "date DESC"; - - /** - * mailbox = name-addr - * name-addr = [display-name] angle-addr - * angle-addr = [CFWS] "<" addr-spec ">" [CFWS] - */ - public static final Pattern NAME_ADDR_EMAIL_PATTERN = - Pattern.compile("\\s*(\"[^\"]*\"|[^<>\"]+)\\s*<([^<>]+)>\\s*"); - - /** - * quoted-string = [CFWS] - * DQUOTE *([FWS] qcontent) [FWS] DQUOTE - * [CFWS] - */ - public static final Pattern QUOTED_STRING_PATTERN = - Pattern.compile("\\s*\"([^\"]*)\"\\s*"); - - public static final Cursor query( - ContentResolver cr, String[] projection) { - return cr.query(CONTENT_URI, projection, null, null, DEFAULT_SORT_ORDER); - } - - public static final Cursor query( - ContentResolver cr, String[] projection, - String where, String orderBy) { - return cr.query(CONTENT_URI, projection, - where, null, orderBy == null ? DEFAULT_SORT_ORDER : orderBy); - } - - public static final String getMessageBoxName(int msgBox) { - switch (msgBox) { - case MESSAGE_BOX_ALL: - return "all"; - case MESSAGE_BOX_INBOX: - return "inbox"; - case MESSAGE_BOX_SENT: - return "sent"; - case MESSAGE_BOX_DRAFTS: - return "drafts"; - case MESSAGE_BOX_OUTBOX: - return "outbox"; - default: - throw new IllegalArgumentException("Invalid message box: " + msgBox); - } - } - - public static String extractAddrSpec(String address) { - Matcher match = NAME_ADDR_EMAIL_PATTERN.matcher(address); - - if (match.matches()) { - return match.group(2); - } - return address; - } - - /** - * Returns true if the address is an email address - * - * @param address the input address to be tested - * @return true if address is an email address - */ - public static boolean isEmailAddress(String address) { - if (TextUtils.isEmpty(address)) { - return false; - } - - String s = extractAddrSpec(address); - Matcher match = Patterns.EMAIL_ADDRESS.matcher(s); - return match.matches(); - } - - /** - * Returns true if the number is a Phone number - * - * @param number the input number to be tested - * @return true if number is a Phone number - */ - public static boolean isPhoneNumber(String number) { - if (TextUtils.isEmpty(number)) { - return false; - } - - Matcher match = Patterns.PHONE.matcher(number); - return match.matches(); - } - - /** - * Contains all MMS messages in the MMS app's inbox. - */ - public static final class Inbox implements BaseMmsColumns { - /** - * The content:// style URL for this table - */ - public static final Uri - CONTENT_URI = Uri.parse("content://mms/inbox"); - - /** - * The default sort order for this table - */ - public static final String DEFAULT_SORT_ORDER = "date DESC"; - } - - /** - * Contains all MMS messages in the MMS app's sent box. - */ - public static final class Sent implements BaseMmsColumns { - /** - * The content:// style URL for this table - */ - public static final Uri - CONTENT_URI = Uri.parse("content://mms/sent"); - - /** - * The default sort order for this table - */ - public static final String DEFAULT_SORT_ORDER = "date DESC"; - } - - /** - * Contains all MMS messages in the MMS app's drafts box. - */ - public static final class Draft implements BaseMmsColumns { - /** - * The content:// style URL for this table - */ - public static final Uri - CONTENT_URI = Uri.parse("content://mms/drafts"); - - /** - * The default sort order for this table - */ - public static final String DEFAULT_SORT_ORDER = "date DESC"; - } - - /** - * Contains all MMS messages in the MMS app's outbox. - */ - public static final class Outbox implements BaseMmsColumns { - /** - * The content:// style URL for this table - */ - public static final Uri - CONTENT_URI = Uri.parse("content://mms/outbox"); - - /** - * The default sort order for this table - */ - public static final String DEFAULT_SORT_ORDER = "date DESC"; - } - - public static final class Addr implements BaseColumns { - /** - * The ID of MM which this address entry belongs to. - */ - public static final String MSG_ID = "msg_id"; - - /** - * The ID of contact entry in Phone Book. - */ - public static final String CONTACT_ID = "contact_id"; - - /** - * The address text. - */ - public static final String ADDRESS = "address"; - - /** - * Type of address, must be one of PduHeaders.BCC, - * PduHeaders.CC, PduHeaders.FROM, PduHeaders.TO. - */ - public static final String TYPE = "type"; - - /** - * Character set of this entry. - */ - public static final String CHARSET = "charset"; - } - - public static final class Part implements BaseColumns { - /** - * The identifier of the message which this part belongs to. - * <P>Type: INTEGER</P> - */ - public static final String MSG_ID = "mid"; - - /** - * The order of the part. - * <P>Type: INTEGER</P> - */ - public static final String SEQ = "seq"; - - /** - * The content type of the part. - * <P>Type: TEXT</P> - */ - public static final String CONTENT_TYPE = "ct"; - - /** - * The name of the part. - * <P>Type: TEXT</P> - */ - public static final String NAME = "name"; - - /** - * The charset of the part. - * <P>Type: TEXT</P> - */ - public static final String CHARSET = "chset"; - - /** - * The file name of the part. - * <P>Type: TEXT</P> - */ - public static final String FILENAME = "fn"; - - /** - * The content disposition of the part. - * <P>Type: TEXT</P> - */ - public static final String CONTENT_DISPOSITION = "cd"; - - /** - * The content ID of the part. - * <P>Type: INTEGER</P> - */ - public static final String CONTENT_ID = "cid"; - - /** - * The content location of the part. - * <P>Type: INTEGER</P> - */ - public static final String CONTENT_LOCATION = "cl"; - - /** - * The start of content-type of the message. - * <P>Type: INTEGER</P> - */ - public static final String CT_START = "ctt_s"; - - /** - * The type of content-type of the message. - * <P>Type: TEXT</P> - */ - public static final String CT_TYPE = "ctt_t"; - - /** - * The location(on filesystem) of the binary data of the part. - * <P>Type: INTEGER</P> - */ - public static final String _DATA = "_data"; - - public static final String TEXT = "text"; - - } - - public static final class Rate { - public static final Uri CONTENT_URI = Uri.withAppendedPath( - Mms.CONTENT_URI, "rate"); - /** - * When a message was successfully sent. - * <P>Type: INTEGER</P> - */ - public static final String SENT_TIME = "sent_time"; - } - - public static final class Intents { - private Intents() { - // Non-instantiatable. - } - - /** - * The extra field to store the contents of the Intent, - * which should be an array of Uri. - */ - public static final String EXTRA_CONTENTS = "contents"; - /** - * The extra field to store the type of the contents, - * which should be an array of String. - */ - public static final String EXTRA_TYPES = "types"; - /** - * The extra field to store the 'Cc' addresses. - */ - public static final String EXTRA_CC = "cc"; - /** - * The extra field to store the 'Bcc' addresses; - */ - public static final String EXTRA_BCC = "bcc"; - /** - * The extra field to store the 'Subject'. - */ - public static final String EXTRA_SUBJECT = "subject"; - /** - * Indicates that the contents of specified URIs were changed. - * The application which is showing or caching these contents - * should be updated. - */ - public static final String - CONTENT_CHANGED_ACTION = "android.intent.action.CONTENT_CHANGED"; - /** - * An extra field which stores the URI of deleted contents. - */ - public static final String DELETED_CONTENTS = "deleted_contents"; - } - } - - /** - * Contains all MMS and SMS messages. - */ - public static final class MmsSms implements BaseColumns { - /** - * The column to distinguish SMS & MMS messages in query results. - */ - public static final String TYPE_DISCRIMINATOR_COLUMN = - "transport_type"; - - public static final Uri CONTENT_URI = Uri.parse("content://mms-sms/"); - - public static final Uri CONTENT_CONVERSATIONS_URI = Uri.parse( - "content://mms-sms/conversations"); - - public static final Uri CONTENT_FILTER_BYPHONE_URI = Uri.parse( - "content://mms-sms/messages/byphone"); - - public static final Uri CONTENT_UNDELIVERED_URI = Uri.parse( - "content://mms-sms/undelivered"); - - public static final Uri CONTENT_DRAFT_URI = Uri.parse( - "content://mms-sms/draft"); - - public static final Uri CONTENT_LOCKED_URI = Uri.parse( - "content://mms-sms/locked"); - - /*** - * Pass in a query parameter called "pattern" which is the text - * to search for. - * The sort order is fixed to be thread_id ASC,date DESC. - */ - public static final Uri SEARCH_URI = Uri.parse( - "content://mms-sms/search"); - - // Constants for message protocol types. - public static final int SMS_PROTO = 0; - public static final int MMS_PROTO = 1; - - // Constants for error types of pending messages. - public static final int NO_ERROR = 0; - public static final int ERR_TYPE_GENERIC = 1; - public static final int ERR_TYPE_SMS_PROTO_TRANSIENT = 2; - public static final int ERR_TYPE_MMS_PROTO_TRANSIENT = 3; - public static final int ERR_TYPE_TRANSPORT_FAILURE = 4; - public static final int ERR_TYPE_GENERIC_PERMANENT = 10; - public static final int ERR_TYPE_SMS_PROTO_PERMANENT = 11; - public static final int ERR_TYPE_MMS_PROTO_PERMANENT = 12; - - public static final class PendingMessages implements BaseColumns { - public static final Uri CONTENT_URI = Uri.withAppendedPath( - MmsSms.CONTENT_URI, "pending"); - /** - * The type of transport protocol(MMS or SMS). - * <P>Type: INTEGER</P> - */ - public static final String PROTO_TYPE = "proto_type"; - /** - * The ID of the message to be sent or downloaded. - * <P>Type: INTEGER</P> - */ - public static final String MSG_ID = "msg_id"; - /** - * The type of the message to be sent or downloaded. - * This field is only valid for MM. For SM, its value is always - * set to 0. - */ - public static final String MSG_TYPE = "msg_type"; - /** - * The type of the error code. - * <P>Type: INTEGER</P> - */ - public static final String ERROR_TYPE = "err_type"; - /** - * The error code of sending/retrieving process. - * <P>Type: INTEGER</P> - */ - public static final String ERROR_CODE = "err_code"; - /** - * How many times we tried to send or download the message. - * <P>Type: INTEGER</P> - */ - public static final String RETRY_INDEX = "retry_index"; - /** - * The time to do next retry. - */ - public static final String DUE_TIME = "due_time"; - /** - * The time we last tried to send or download the message. - */ - public static final String LAST_TRY = "last_try"; - } - - public static final class WordsTable { - public static final String ID = "_id"; - public static final String SOURCE_ROW_ID = "source_id"; - public static final String TABLE_ID = "table_to_use"; - public static final String INDEXED_TEXT = "index_text"; - } - } - - public static final class Carriers implements BaseColumns { - /** - * The content:// style URL for this table - */ - public static final Uri CONTENT_URI = - Uri.parse("content://telephony/carriers"); - - /** - * The default sort order for this table - */ - public static final String DEFAULT_SORT_ORDER = "name ASC"; - - public static final String NAME = "name"; - - public static final String APN = "apn"; - - public static final String PROXY = "proxy"; - - public static final String PORT = "port"; - - public static final String MMSPROXY = "mmsproxy"; - - public static final String MMSPORT = "mmsport"; - - public static final String SERVER = "server"; - - public static final String USER = "user"; - - public static final String PASSWORD = "password"; - - public static final String MMSC = "mmsc"; - - public static final String MCC = "mcc"; - - public static final String MNC = "mnc"; - - public static final String NUMERIC = "numeric"; - - public static final String AUTH_TYPE = "authtype"; - - public static final String TYPE = "type"; - - public static final String INACTIVE_TIMER = "inactivetimer"; - - // Only if enabled try Data Connection. - public static final String ENABLED = "enabled"; - - // Rules apply based on class. - public static final String CLASS = "class"; - - /** - * The protocol to be used to connect to this APN. - * - * One of the PDP_type values in TS 27.007 section 10.1.1. - * For example, "IP", "IPV6", "IPV4V6", or "PPP". - */ - public static final String PROTOCOL = "protocol"; - - /** - * The protocol to be used to connect to this APN when roaming. - * - * The syntax is the same as protocol. - */ - public static final String ROAMING_PROTOCOL = "roaming_protocol"; - - public static final String CURRENT = "current"; - - /** - * Current status of APN - * true : enabled APN, false : disabled APN. - */ - public static final String CARRIER_ENABLED = "carrier_enabled"; - - /** - * Radio Access Technology info - * To check what values can hold, refer to ServiceState.java. - * This should be spread to other technologies, - * but currently only used for LTE(14) and EHRPD(13). - */ - public static final String BEARER = "bearer"; - } - - /** - * Contains received SMS cell broadcast messages. - */ - public static final class CellBroadcasts implements BaseColumns { - - /** Not instantiable. */ - private CellBroadcasts() {} - - /** - * The content:// style URL for this table - */ - public static final Uri CONTENT_URI = - Uri.parse("content://cellbroadcasts"); - - /** - * Message geographical scope. - * <P>Type: INTEGER</P> - */ - public static final String GEOGRAPHICAL_SCOPE = "geo_scope"; - - /** - * Message serial number. - * <P>Type: INTEGER</P> - */ - public static final String SERIAL_NUMBER = "serial_number"; - - /** - * PLMN of broadcast sender. (SERIAL_NUMBER + PLMN + LAC + CID) uniquely identifies a - * broadcast for duplicate detection purposes. - * <P>Type: TEXT</P> - */ - public static final String PLMN = "plmn"; - - /** - * Location Area (GSM) or Service Area (UMTS) of broadcast sender. Unused for CDMA. - * Only included if Geographical Scope of message is not PLMN wide (01). - * <P>Type: INTEGER</P> - */ - public static final String LAC = "lac"; - - /** - * Cell ID of message sender (GSM/UMTS). Unused for CDMA. Only included when the - * Geographical Scope of message is cell wide (00 or 11). - * <P>Type: INTEGER</P> - */ - public static final String CID = "cid"; - - /** - * Message code (OBSOLETE: merged into SERIAL_NUMBER). - * <P>Type: INTEGER</P> - */ - public static final String V1_MESSAGE_CODE = "message_code"; - - /** - * Message identifier (OBSOLETE: renamed to SERVICE_CATEGORY). - * <P>Type: INTEGER</P> - */ - public static final String V1_MESSAGE_IDENTIFIER = "message_id"; - - /** - * Service category (GSM/UMTS message identifier, CDMA service category). - * <P>Type: INTEGER</P> - */ - public static final String SERVICE_CATEGORY = "service_category"; - - /** - * Message language code. - * <P>Type: TEXT</P> - */ - public static final String LANGUAGE_CODE = "language"; - - /** - * Message body. - * <P>Type: TEXT</P> - */ - public static final String MESSAGE_BODY = "body"; - - /** - * Message delivery time. - * <P>Type: INTEGER (long)</P> - */ - public static final String DELIVERY_TIME = "date"; - - /** - * Has the message been viewed? - * <P>Type: INTEGER (boolean)</P> - */ - public static final String MESSAGE_READ = "read"; - - /** - * Message format (3GPP or 3GPP2). - * <P>Type: INTEGER</P> - */ - public static final String MESSAGE_FORMAT = "format"; - - /** - * Message priority (including emergency). - * <P>Type: INTEGER</P> - */ - public static final String MESSAGE_PRIORITY = "priority"; - - /** - * ETWS warning type (ETWS alerts only). - * <P>Type: INTEGER</P> - */ - public static final String ETWS_WARNING_TYPE = "etws_warning_type"; - - /** - * CMAS message class (CMAS alerts only). - * <P>Type: INTEGER</P> - */ - public static final String CMAS_MESSAGE_CLASS = "cmas_message_class"; - - /** - * CMAS category (CMAS alerts only). - * <P>Type: INTEGER</P> - */ - public static final String CMAS_CATEGORY = "cmas_category"; - - /** - * CMAS response type (CMAS alerts only). - * <P>Type: INTEGER</P> - */ - public static final String CMAS_RESPONSE_TYPE = "cmas_response_type"; - - /** - * CMAS severity (CMAS alerts only). - * <P>Type: INTEGER</P> - */ - public static final String CMAS_SEVERITY = "cmas_severity"; - - /** - * CMAS urgency (CMAS alerts only). - * <P>Type: INTEGER</P> - */ - public static final String CMAS_URGENCY = "cmas_urgency"; - - /** - * CMAS certainty (CMAS alerts only). - * <P>Type: INTEGER</P> - */ - public static final String CMAS_CERTAINTY = "cmas_certainty"; - - /** - * The default sort order for this table - */ - public static final String DEFAULT_SORT_ORDER = DELIVERY_TIME + " DESC"; - - /** - * Query columns for instantiating {@link android.telephony.CellBroadcastMessage} objects. - */ - public static final String[] QUERY_COLUMNS = { - _ID, - GEOGRAPHICAL_SCOPE, - PLMN, - LAC, - CID, - SERIAL_NUMBER, - SERVICE_CATEGORY, - LANGUAGE_CODE, - MESSAGE_BODY, - DELIVERY_TIME, - MESSAGE_READ, - MESSAGE_FORMAT, - MESSAGE_PRIORITY, - ETWS_WARNING_TYPE, - CMAS_MESSAGE_CLASS, - CMAS_CATEGORY, - CMAS_RESPONSE_TYPE, - CMAS_SEVERITY, - CMAS_URGENCY, - CMAS_CERTAINTY - }; - } - - public static final class Intents { - private Intents() { - // Not instantiable - } - - /** - * Broadcast Action: A "secret code" has been entered in the dialer. Secret codes are - * of the form *#*#<code>#*#*. The intent will have the data URI:</p> - * - * <p><code>android_secret_code://<code></code></p> - */ - public static final String SECRET_CODE_ACTION = - "android.provider.Telephony.SECRET_CODE"; - - /** - * Broadcast Action: The Service Provider string(s) have been updated. Activities or - * services that use these strings should update their display. - * The intent will have the following extra values:</p> - * <ul> - * <li><em>showPlmn</em> - Boolean that indicates whether the PLMN should be shown.</li> - * <li><em>plmn</em> - The operator name of the registered network, as a string.</li> - * <li><em>showSpn</em> - Boolean that indicates whether the SPN should be shown.</li> - * <li><em>spn</em> - The service provider name, as a string.</li> - * </ul> - * Note that <em>showPlmn</em> may indicate that <em>plmn</em> should be displayed, even - * though the value for <em>plmn</em> is null. This can happen, for example, if the phone - * has not registered to a network yet. In this case the receiver may substitute an - * appropriate placeholder string (eg, "No service"). - * - * It is recommended to display <em>plmn</em> before / above <em>spn</em> if - * both are displayed. - * - * <p>Note this is a protected intent that can only be sent - * by the system. - */ - public static final String SPN_STRINGS_UPDATED_ACTION = - "android.provider.Telephony.SPN_STRINGS_UPDATED"; - - public static final String EXTRA_SHOW_PLMN = "showPlmn"; - public static final String EXTRA_PLMN = "plmn"; - public static final String EXTRA_SHOW_SPN = "showSpn"; - public static final String EXTRA_SPN = "spn"; - } -} diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java index 97c0209..6296b11 100755 --- a/core/java/android/server/BluetoothService.java +++ b/core/java/android/server/BluetoothService.java @@ -2448,7 +2448,7 @@ public class BluetoothService extends IBluetooth.Stub { BluetoothDeviceProfileState state = mDeviceProfileState.get(address); if (state == null) return; - state.quit(); + state.doQuit(); mDeviceProfileState.remove(address); } diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java index da10311..2e962a0 100644 --- a/core/java/android/text/format/DateUtils.java +++ b/core/java/android/text/format/DateUtils.java @@ -161,12 +161,17 @@ public class DateUtils public static final int FORMAT_NO_YEAR = 0x00008; public static final int FORMAT_SHOW_DATE = 0x00010; public static final int FORMAT_NO_MONTH_DAY = 0x00020; + @Deprecated public static final int FORMAT_12HOUR = 0x00040; + @Deprecated public static final int FORMAT_24HOUR = 0x00080; + @Deprecated public static final int FORMAT_CAP_AMPM = 0x00100; public static final int FORMAT_NO_NOON = 0x00200; + @Deprecated public static final int FORMAT_CAP_NOON = 0x00400; public static final int FORMAT_NO_MIDNIGHT = 0x00800; + @Deprecated public static final int FORMAT_CAP_MIDNIGHT = 0x01000; /** * @deprecated Use @@ -181,19 +186,25 @@ public class DateUtils public static final int FORMAT_NUMERIC_DATE = 0x20000; public static final int FORMAT_ABBREV_RELATIVE = 0x40000; public static final int FORMAT_ABBREV_ALL = 0x80000; + @Deprecated public static final int FORMAT_CAP_NOON_MIDNIGHT = (FORMAT_CAP_NOON | FORMAT_CAP_MIDNIGHT); + @Deprecated public static final int FORMAT_NO_NOON_MIDNIGHT = (FORMAT_NO_NOON | FORMAT_NO_MIDNIGHT); // Date and time format strings that are constant and don't need to be // translated. /** * This is not actually the preferred 24-hour date format in all locales. + * @deprecated use {@link java.text.SimpleDateFormat} instead. */ + @Deprecated public static final String HOUR_MINUTE_24 = "%H:%M"; public static final String MONTH_FORMAT = "%B"; /** * This is not actually a useful month name in all locales. + * @deprecated use {@link java.text.SimpleDateFormat} instead. */ + @Deprecated public static final String ABBREV_MONTH_FORMAT = "%b"; public static final String NUMERIC_MONTH_FORMAT = "%m"; public static final String MONTH_DAY_FORMAT = "%-d"; @@ -207,6 +218,7 @@ public class DateUtils // The index is constructed from a bit-wise OR of the boolean values: // {showTime, showYear, showWeekDay}. For example, if showYear and // showWeekDay are both true, then the index would be 3. + /** @deprecated do not use. */ public static final int sameYearTable[] = { com.android.internal.R.string.same_year_md1_md2, com.android.internal.R.string.same_year_wday1_md1_wday2_md2, @@ -233,6 +245,7 @@ public class DateUtils // The index is constructed from a bit-wise OR of the boolean values: // {showTime, showYear, showWeekDay}. For example, if showYear and // showWeekDay are both true, then the index would be 3. + /** @deprecated do not use. */ public static final int sameMonthTable[] = { com.android.internal.R.string.same_month_md1_md2, com.android.internal.R.string.same_month_wday1_md1_wday2_md2, @@ -259,7 +272,9 @@ public class DateUtils * * @more <p> * e.g. "Sunday" or "January" + * @deprecated use {@link java.text.SimpleDateFormat} instead. */ + @Deprecated public static final int LENGTH_LONG = 10; /** @@ -268,7 +283,9 @@ public class DateUtils * * @more <p> * e.g. "Sun" or "Jan" + * @deprecated use {@link java.text.SimpleDateFormat} instead. */ + @Deprecated public static final int LENGTH_MEDIUM = 20; /** @@ -278,14 +295,18 @@ public class DateUtils * <p>e.g. "Su" or "Jan" * <p>In most languages, the results returned for LENGTH_SHORT will be the same as * the results returned for {@link #LENGTH_MEDIUM}. + * @deprecated use {@link java.text.SimpleDateFormat} instead. */ + @Deprecated public static final int LENGTH_SHORT = 30; /** * Request an even shorter abbreviated version of the name. * Do not use this. Currently this will always return the same result * as {@link #LENGTH_SHORT}. + * @deprecated use {@link java.text.SimpleDateFormat} instead. */ + @Deprecated public static final int LENGTH_SHORTER = 40; /** @@ -295,7 +316,9 @@ public class DateUtils * <p>e.g. "S", "T", "T" or "J" * <p>In some languages, the results returned for LENGTH_SHORTEST will be the same as * the results returned for {@link #LENGTH_SHORT}. + * @deprecated use {@link java.text.SimpleDateFormat} instead. */ + @Deprecated public static final int LENGTH_SHORTEST = 50; /** @@ -309,7 +332,9 @@ public class DateUtils * Undefined lengths will return {@link #LENGTH_MEDIUM} * but may return something different in the future. * @throws IndexOutOfBoundsException if the dayOfWeek is out of bounds. + * @deprecated use {@link java.text.SimpleDateFormat} instead. */ + @Deprecated public static String getDayOfWeekString(int dayOfWeek, int abbrev) { int[] list; switch (abbrev) { @@ -330,7 +355,9 @@ public class DateUtils * @param ampm Either {@link Calendar#AM Calendar.AM} or {@link Calendar#PM Calendar.PM}. * @throws IndexOutOfBoundsException if the ampm is out of bounds. * @return Localized version of "AM" or "PM". + * @deprecated use {@link java.text.SimpleDateFormat} instead. */ + @Deprecated public static String getAMPMString(int ampm) { Resources r = Resources.getSystem(); return r.getString(sAmPm[ampm - Calendar.AM]); @@ -345,7 +372,9 @@ public class DateUtils * Undefined lengths will return {@link #LENGTH_MEDIUM} * but may return something different in the future. * @return Localized month of the year. + * @deprecated use {@link java.text.SimpleDateFormat} instead. */ + @Deprecated public static String getMonthString(int month, int abbrev) { // Note that here we use sMonthsMedium for MEDIUM, SHORT and SHORTER. // This is a shortcut to not spam the translators with too many variations @@ -378,7 +407,9 @@ public class DateUtils * but may return something different in the future. * @return Localized month of the year. * @hide Pending API council approval + * @deprecated use {@link java.text.SimpleDateFormat} instead. */ + @Deprecated public static String getStandaloneMonthString(int month, int abbrev) { // Note that here we use sMonthsMedium for MEDIUM, SHORT and SHORTER. // This is a shortcut to not spam the translators with too many variations @@ -1618,7 +1649,7 @@ public class DateUtils String result; long now = System.currentTimeMillis(); - long span = now - millis; + long span = Math.abs(now - millis); synchronized (DateUtils.class) { if (sNowTime == null) { diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java index 9063cea..31a9f05 100644 --- a/core/java/android/view/FocusFinder.java +++ b/core/java/android/view/FocusFinder.java @@ -250,8 +250,8 @@ public class FocusFinder { // only interested in other non-root views if (focusable == focused || focusable == root) continue; - // get visible bounds of other view in same coordinate system - focusable.getDrawingRect(mOtherRect); + // get focus bounds of other view in same coordinate system + focusable.getFocusRect(mOtherRect); root.offsetDescendantRectToMyCoords(focusable, mOtherRect); if (isBetterCandidate(direction, focusedRect, mOtherRect, mBestCandidateRect)) { diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index fd302dc..ed4c75c 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -531,7 +531,7 @@ public class SurfaceView extends View { mSurface.transferFrom(mNewSurface); - if (visible) { + if (visible && mSurface.isValid()) { if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) { mSurfaceCreated = true; mIsCreating = true; diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index f0ca302..f2a80d0 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -8737,6 +8737,18 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal } /** + * When searching for a view to focus this rectangle is used when considering if this view is + * a good candidate for receiving focus. + * + * By default, the rectangle is the {@link #getDrawingRect}) of the view. + * + * @param r The rectangle to fill in, in this view's coordinates. + */ + public void getFocusRect(Rect r) { + getDrawingRect(r); + } + + /** * Utility method to retrieve the inverse of the current mMatrix property. * We cache the matrix to avoid recalculating it when transform properties * have not changed. diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java index d1d867c..c624a87 100644 --- a/core/java/android/webkit/WebViewClassic.java +++ b/core/java/android/webkit/WebViewClassic.java @@ -686,6 +686,10 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc // It's used to dismiss the dialog in destroy if not done before. private AlertDialog mListBoxDialog = null; + // Reference to the save password dialog so it can be dimissed in + // destroy if not done before. + private AlertDialog mSavePasswordDialog = null; + static final String LOGTAG = "webview"; private ZoomManager mZoomManager; @@ -1826,7 +1830,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc neverRemember.getData().putString("password", password); neverRemember.obj = resumeMsg; - new AlertDialog.Builder(mContext) + mSavePasswordDialog = new AlertDialog.Builder(mContext) .setTitle(com.android.internal.R.string.save_password_label) .setMessage(com.android.internal.R.string.save_password_message) .setPositiveButton(com.android.internal.R.string.save_password_notnow, @@ -1837,6 +1841,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc resumeMsg.sendToTarget(); mResumeMsg = null; } + mSavePasswordDialog = null; } }) .setNeutralButton(com.android.internal.R.string.save_password_remember, @@ -1847,6 +1852,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc remember.sendToTarget(); mResumeMsg = null; } + mSavePasswordDialog = null; } }) .setNegativeButton(com.android.internal.R.string.save_password_never, @@ -1857,6 +1863,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc neverRemember.sendToTarget(); mResumeMsg = null; } + mSavePasswordDialog = null; } }) .setOnCancelListener(new OnCancelListener() { @@ -1866,6 +1873,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc resumeMsg.sendToTarget(); mResumeMsg = null; } + mSavePasswordDialog = null; } }).show(); // Return true so that WebViewCore will pause while the dialog is @@ -2105,6 +2113,10 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc mListBoxDialog.dismiss(); mListBoxDialog = null; } + if (mSavePasswordDialog != null) { + mSavePasswordDialog.dismiss(); + mSavePasswordDialog = null; + } if (mWebViewCore != null) { // Tell WebViewCore to destroy itself synchronized (this) { diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java index 323fcf0..b72b8cb 100644 --- a/core/java/android/widget/Gallery.java +++ b/core/java/android/widget/Gallery.java @@ -1192,15 +1192,15 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList case KeyEvent.KEYCODE_DPAD_LEFT: if (movePrevious()) { playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT); + return true; } - return true; - + break; case KeyEvent.KEYCODE_DPAD_RIGHT: if (moveNext()) { playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT); + return true; } - return true; - + break; case KeyEvent.KEYCODE_DPAD_CENTER: case KeyEvent.KEYCODE_ENTER: mReceivedInvokeKeyDown = true; diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java index ff8c0a1..37e0b90 100644 --- a/core/java/android/widget/GridView.java +++ b/core/java/android/widget/GridView.java @@ -2207,8 +2207,13 @@ public class GridView extends AbsListView { int height = view.getHeight(); if (height > 0) { final int numColumns = mNumColumns; - final int whichRow = mFirstPosition / numColumns; final int rowCount = (mItemCount + numColumns - 1) / numColumns; + // In case of stackFromBottom the calculation of whichRow needs + // to take into account that counting from the top the first row + // might not be entirely filled. + final int oddItemsOnFirstRow = isStackFromBottom() ? ((rowCount * numColumns) - + mItemCount) : 0; + final int whichRow = (mFirstPosition + oddItemsOnFirstRow) / numColumns; return Math.max(whichRow * 100 - (top * 100) / height + (int) ((float) mScrollY / getHeight() * rowCount * 100), 0); } diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java index 18c4fe6..ff0579c 100644 --- a/core/java/android/widget/HorizontalScrollView.java +++ b/core/java/android/widget/HorizontalScrollView.java @@ -22,6 +22,7 @@ import android.graphics.Canvas; import android.graphics.Rect; import android.os.Bundle; import android.util.AttributeSet; +import android.util.Log; import android.view.FocusFinder; import android.view.InputDevice; import android.view.KeyEvent; @@ -62,6 +63,7 @@ public class HorizontalScrollView extends FrameLayout { private static final float MAX_SCROLL_FACTOR = ScrollView.MAX_SCROLL_FACTOR; + private static final String TAG = "HorizontalScrollView"; private long mLastScroll; @@ -456,6 +458,12 @@ public class HorizontalScrollView extends FrameLayout { } final int pointerIndex = ev.findPointerIndex(activePointerId); + if (pointerIndex == -1) { + Log.e(TAG, "Invalid pointerId=" + activePointerId + + " in onInterceptTouchEvent"); + break; + } + final int x = (int) ev.getX(pointerIndex); final int xDiff = (int) Math.abs(x - mLastMotionX); if (xDiff > mTouchSlop) { @@ -557,6 +565,11 @@ public class HorizontalScrollView extends FrameLayout { } case MotionEvent.ACTION_MOVE: final int activePointerIndex = ev.findPointerIndex(mActivePointerId); + if (activePointerIndex == -1) { + Log.e(TAG, "Invalid pointerId=" + mActivePointerId + " in onTouchEvent"); + break; + } + final int x = (int) ev.getX(activePointerIndex); int deltaX = mLastMotionX - x; if (!mIsBeingDragged && Math.abs(deltaX) > mTouchSlop) { diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java index fc35f05..f76ab2b 100644 --- a/core/java/android/widget/MediaController.java +++ b/core/java/android/widget/MediaController.java @@ -477,7 +477,8 @@ public class MediaController extends FrameLayout { return true; } else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP - || keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) { + || keyCode == KeyEvent.KEYCODE_VOLUME_MUTE + || keyCode == KeyEvent.KEYCODE_CAMERA) { // don't show the controls for volume adjustment return super.dispatchKeyEvent(event); } else if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU) { diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java index ebc54f4..8747dc3 100644 --- a/core/java/android/widget/ScrollView.java +++ b/core/java/android/widget/ScrollView.java @@ -25,6 +25,7 @@ import android.graphics.Rect; import android.os.Bundle; import android.os.StrictMode; import android.util.AttributeSet; +import android.util.Log; import android.view.FocusFinder; import android.view.InputDevice; import android.view.KeyEvent; @@ -69,6 +70,8 @@ public class ScrollView extends FrameLayout { static final float MAX_SCROLL_FACTOR = 0.5f; + private static final String TAG = "ScrollView"; + private long mLastScroll; private final Rect mTempRect = new Rect(); @@ -478,6 +481,12 @@ public class ScrollView extends FrameLayout { } final int pointerIndex = ev.findPointerIndex(activePointerId); + if (pointerIndex == -1) { + Log.e(TAG, "Invalid pointerId=" + activePointerId + + " in onInterceptTouchEvent"); + break; + } + final int y = (int) ev.getY(pointerIndex); final int yDiff = Math.abs(y - mLastMotionY); if (yDiff > mTouchSlop) { @@ -585,6 +594,11 @@ public class ScrollView extends FrameLayout { } case MotionEvent.ACTION_MOVE: final int activePointerIndex = ev.findPointerIndex(mActivePointerId); + if (activePointerIndex == -1) { + Log.e(TAG, "Invalid pointerId=" + mActivePointerId + " in onTouchEvent"); + break; + } + final int y = (int) ev.getY(activePointerIndex); int deltaY = mLastMotionY - y; if (!mIsBeingDragged && Math.abs(deltaY) > mTouchSlop) { diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java index a0e961f..86433d4 100644 --- a/core/java/android/widget/SearchView.java +++ b/core/java/android/widget/SearchView.java @@ -1506,6 +1506,9 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { // because the voice search activity will always need to insert "QUERY" into // it anyway. Bundle queryExtras = new Bundle(); + if (mAppSearchData != null) { + queryExtras.putParcelable(SearchManager.APP_DATA, mAppSearchData); + } // Now build the intent to launch the voice search. Add all necessary // extras to launch the voice recognizer, and then all the necessary extras @@ -1595,8 +1598,8 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { } catch (RuntimeException e2 ) { rowNum = -1; } - Log.w(LOG_TAG, "Search Suggestions cursor at row " + rowNum + - " returned exception" + e.toString()); + Log.w(LOG_TAG, "Search suggestions cursor at row " + rowNum + + " returned exception.", e); return null; } } diff --git a/core/java/android/widget/SimpleExpandableListAdapter.java b/core/java/android/widget/SimpleExpandableListAdapter.java index 015c169..f514374 100644 --- a/core/java/android/widget/SimpleExpandableListAdapter.java +++ b/core/java/android/widget/SimpleExpandableListAdapter.java @@ -38,6 +38,8 @@ import java.util.Map; */ public class SimpleExpandableListAdapter extends BaseExpandableListAdapter { private List<? extends Map<String, ?>> mGroupData; + // Keeps track of if a group is currently expanded or not + private boolean[] mIsGroupExpanded; private int mExpandedGroupLayout; private int mCollapsedGroupLayout; private String[] mGroupFrom; @@ -196,6 +198,8 @@ public class SimpleExpandableListAdapter extends BaseExpandableListAdapter { int childLayout, int lastChildLayout, String[] childFrom, int[] childTo) { mGroupData = groupData; + // Initially all groups are not expanded + mIsGroupExpanded = new boolean[groupData.size()]; mExpandedGroupLayout = expandedGroupLayout; mCollapsedGroupLayout = collapsedGroupLayout; mGroupFrom = groupFrom; @@ -298,4 +302,52 @@ public class SimpleExpandableListAdapter extends BaseExpandableListAdapter { return true; } + /** + * {@inheritDoc} + * @return 1 for the last child in a group, 0 for the other children. + */ + @Override + public int getChildType(int groupPosition, int childPosition) { + final int childrenInGroup = getChildrenCount(groupPosition); + return childPosition == childrenInGroup - 1 ? 1 : 0; + } + + /** + * {@inheritDoc} + * @return 2, one type for the last child in a group, one for the other children. + */ + @Override + public int getChildTypeCount() { + return 2; + } + + /** + * {@inheritDoc} + * @return 1 for an expanded group view, 0 for a collapsed one. + */ + @Override + public int getGroupType(int groupPosition) { + return mIsGroupExpanded[groupPosition] ? 1 : 0; + } + + /** + * {@inheritDoc} + * @return 2, one for a collapsed group view, one for an expanded one. + */ + @Override + public int getGroupTypeCount() { + return 2; + } + + /** {@inheritDoc} */ + @Override + public void onGroupCollapsed(int groupPosition) { + mIsGroupExpanded[groupPosition] = false; + } + + /** {@inheritDoc} */ + @Override + public void onGroupExpanded(int groupPosition) { + mIsGroupExpanded[groupPosition] = true; + } } diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java index 56f6651..cea613f 100644 --- a/core/java/android/widget/Switch.java +++ b/core/java/android/widget/Switch.java @@ -686,7 +686,7 @@ public class Switch extends CompoundButton { @Override public void setChecked(boolean checked) { super.setChecked(checked); - mThumbPosition = checked ? getThumbScrollRange() : 0; + mThumbPosition = isChecked() ? getThumbScrollRange() : 0; invalidate(); } diff --git a/core/java/android/widget/TabHost.java b/core/java/android/widget/TabHost.java index 8bb9348..238dc55 100644 --- a/core/java/android/widget/TabHost.java +++ b/core/java/android/widget/TabHost.java @@ -48,6 +48,10 @@ import java.util.List; */ public class TabHost extends FrameLayout implements ViewTreeObserver.OnTouchModeChangeListener { + private static final int TABWIDGET_LOCATION_LEFT = 0; + private static final int TABWIDGET_LOCATION_TOP = 1; + private static final int TABWIDGET_LOCATION_RIGHT = 2; + private static final int TABWIDGET_LOCATION_BOTTOM = 3; private TabWidget mTabWidget; private FrameLayout mTabContent; private List<TabSpec> mTabSpecs = new ArrayList<TabSpec>(2); @@ -293,22 +297,73 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1"); return mTabContent; } + /** + * Get the location of the TabWidget. + * + * @return The TabWidget location. + */ + private int getTabWidgetLocation() { + int location = TABWIDGET_LOCATION_TOP; + + switch (mTabWidget.getOrientation()) { + case LinearLayout.VERTICAL: + location = (mTabContent.getLeft() < mTabWidget.getLeft()) ? TABWIDGET_LOCATION_RIGHT + : TABWIDGET_LOCATION_LEFT; + break; + case LinearLayout.HORIZONTAL: + default: + location = (mTabContent.getTop() < mTabWidget.getTop()) ? TABWIDGET_LOCATION_BOTTOM + : TABWIDGET_LOCATION_TOP; + break; + } + return location; + } + @Override public boolean dispatchKeyEvent(KeyEvent event) { final boolean handled = super.dispatchKeyEvent(event); - // unhandled key ups change focus to tab indicator for embedded activities - // when there is nothing that will take focus from default focus searching + // unhandled key events change focus to tab indicator for embedded + // activities when there is nothing that will take focus from default + // focus searching if (!handled && (event.getAction() == KeyEvent.ACTION_DOWN) - && (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_UP) && (mCurrentView != null) && (mCurrentView.isRootNamespace()) - && (mCurrentView.hasFocus()) - && (mCurrentView.findFocus().focusSearch(View.FOCUS_UP) == null)) { - mTabWidget.getChildTabViewAt(mCurrentTab).requestFocus(); - playSoundEffect(SoundEffectConstants.NAVIGATION_UP); - return true; + && (mCurrentView.hasFocus())) { + int keyCodeShouldChangeFocus = KeyEvent.KEYCODE_DPAD_UP; + int directionShouldChangeFocus = View.FOCUS_UP; + int soundEffect = SoundEffectConstants.NAVIGATION_UP; + + switch (getTabWidgetLocation()) { + case TABWIDGET_LOCATION_LEFT: + keyCodeShouldChangeFocus = KeyEvent.KEYCODE_DPAD_LEFT; + directionShouldChangeFocus = View.FOCUS_LEFT; + soundEffect = SoundEffectConstants.NAVIGATION_LEFT; + break; + case TABWIDGET_LOCATION_RIGHT: + keyCodeShouldChangeFocus = KeyEvent.KEYCODE_DPAD_RIGHT; + directionShouldChangeFocus = View.FOCUS_RIGHT; + soundEffect = SoundEffectConstants.NAVIGATION_RIGHT; + break; + case TABWIDGET_LOCATION_BOTTOM: + keyCodeShouldChangeFocus = KeyEvent.KEYCODE_DPAD_DOWN; + directionShouldChangeFocus = View.FOCUS_DOWN; + soundEffect = SoundEffectConstants.NAVIGATION_DOWN; + break; + case TABWIDGET_LOCATION_TOP: + default: + keyCodeShouldChangeFocus = KeyEvent.KEYCODE_DPAD_UP; + directionShouldChangeFocus = View.FOCUS_UP; + soundEffect = SoundEffectConstants.NAVIGATION_UP; + break; + } + if (event.getKeyCode() == keyCodeShouldChangeFocus + && mCurrentView.findFocus().focusSearch(directionShouldChangeFocus) == null) { + mTabWidget.getChildTabViewAt(mCurrentTab).requestFocus(); + playSoundEffect(soundEffect); + return true; + } } return handled; } diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java index 2061c90..56b5937 100644 --- a/core/java/com/android/internal/app/AlertController.java +++ b/core/java/com/android/internal/app/AlertController.java @@ -347,6 +347,18 @@ public class AlertController { } } + /** + * @param attrId the attributeId of the theme-specific drawable + * to resolve the resourceId for. + * + * @return resId the resourceId of the theme-specific drawable + */ + public int getIconAttributeResId(int attrId) { + TypedValue out = new TypedValue(); + mContext.getTheme().resolveAttribute(attrId, out, true); + return out.resourceId; + } + public void setInverseBackgroundForced(boolean forceInverseBackground) { mForceInverseBackground = forceInverseBackground; } @@ -740,6 +752,7 @@ public class AlertController { public int mIconId = 0; public Drawable mIcon; + public int mIconAttrId = 0; public CharSequence mTitle; public View mCustomTitleView; public CharSequence mMessage; @@ -806,6 +819,9 @@ public class AlertController { if (mIconId >= 0) { dialog.setIcon(mIconId); } + if (mIconAttrId > 0) { + dialog.setIcon(dialog.getIconAttributeResId(mIconAttrId)); + } } if (mMessage != null) { dialog.setMessage(mMessage); diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 5157385..db752e9 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -2302,8 +2302,8 @@ public final class BatteryStatsImpl extends BatteryStats { batteryRealtime, which); } - @Override public int getPhoneSignalStrengthCount(int dataType, int which) { - return mPhoneDataConnectionsTimer[dataType].getCountLocked(which); + @Override public int getPhoneSignalStrengthCount(int strengthBin, int which) { + return mPhoneSignalStrengthsTimer[strengthBin].getCountLocked(which); } @Override public long getPhoneDataConnectionTime(int dataType, diff --git a/core/java/com/android/internal/os/ProcessStats.java b/core/java/com/android/internal/os/ProcessStats.java index 1923b86..b1bb8c1 100644 --- a/core/java/com/android/internal/os/ProcessStats.java +++ b/core/java/com/android/internal/os/ProcessStats.java @@ -154,7 +154,7 @@ public class ProcessStats { private boolean mFirst = true; - private byte[] mBuffer = new byte[256]; + private byte[] mBuffer = new byte[4096]; /** * The time in microseconds that the CPU has been running at each speed. @@ -556,7 +556,7 @@ public class ProcessStats { private long[] getCpuSpeedTimes(long[] out) { long[] tempTimes = out; long[] tempSpeeds = mCpuSpeeds; - final int MAX_SPEEDS = 20; + final int MAX_SPEEDS = 60; if (out == null) { tempTimes = new long[MAX_SPEEDS]; // Hopefully no more than that tempSpeeds = new long[MAX_SPEEDS]; diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java index 9af7e96..b016e99 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -26,6 +26,8 @@ import android.util.Log; import dalvik.system.PathClassLoader; import dalvik.system.Zygote; +import android.os.SELinux; + import java.io.BufferedReader; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -73,6 +75,7 @@ class ZygoteConnection { private final DataOutputStream mSocketOutStream; private final BufferedReader mSocketReader; private final Credentials peer; + private final String peerSecurityContext; /** * A long-lived reference to the original command socket used to launch @@ -109,6 +112,8 @@ class ZygoteConnection { Log.e(TAG, "Cannot read peer credentials", ex); throw ex; } + + peerSecurityContext = SELinux.getPeerContext(mSocket.getFileDescriptor()); } /** @@ -207,10 +212,11 @@ class ZygoteConnection { try { parsedArgs = new Arguments(args); - applyUidSecurityPolicy(parsedArgs, peer); - applyRlimitSecurityPolicy(parsedArgs, peer); - applyCapabilitiesSecurityPolicy(parsedArgs, peer); - applyInvokeWithSecurityPolicy(parsedArgs, peer); + applyUidSecurityPolicy(parsedArgs, peer, peerSecurityContext); + applyRlimitSecurityPolicy(parsedArgs, peer, peerSecurityContext); + applyCapabilitiesSecurityPolicy(parsedArgs, peer, peerSecurityContext); + applyInvokeWithSecurityPolicy(parsedArgs, peer, peerSecurityContext); + applyseInfoSecurityPolicy(parsedArgs, peer, peerSecurityContext); applyDebuggerSystemProperty(parsedArgs); applyInvokeWithSystemProperty(parsedArgs); @@ -229,7 +235,8 @@ class ZygoteConnection { } pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, - parsedArgs.gids, parsedArgs.debugFlags, rlimits); + parsedArgs.gids, parsedArgs.debugFlags, rlimits, + parsedArgs.seInfo, parsedArgs.niceName); } catch (IOException ex) { logAndPrintError(newStderr, "Exception creating pipe", ex); } catch (ErrnoException ex) { @@ -352,6 +359,10 @@ class ZygoteConnection { long permittedCapabilities; long effectiveCapabilities; + /** from --seinfo */ + boolean seInfoSpecified; + String seInfo; + /** from all --rlimit=r,c,m */ ArrayList<int[]> rlimits; @@ -429,6 +440,13 @@ class ZygoteConnection { peerWait = true; } else if (arg.equals("--runtime-init")) { runtimeInit = true; + } else if (arg.startsWith("--seinfo=")) { + if (seInfoSpecified) { + throw new IllegalArgumentException( + "Duplicate arg specified"); + } + seInfoSpecified = true; + seInfo = arg.substring(arg.indexOf('=') + 1); } else if (arg.startsWith("--capabilities=")) { if (capabilitiesSpecified) { throw new IllegalArgumentException( @@ -591,7 +609,8 @@ class ZygoteConnection { * @param peer non-null; peer credentials * @throws ZygoteSecurityException */ - private static void applyUidSecurityPolicy(Arguments args, Credentials peer) + private static void applyUidSecurityPolicy(Arguments args, Credentials peer, + String peerSecurityContext) throws ZygoteSecurityException { int peerUid = peer.getUid(); @@ -624,6 +643,17 @@ class ZygoteConnection { } } + if (args.uidSpecified || args.gidSpecified || args.gids != null) { + boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext, + peerSecurityContext, + "zygote", + "specifyids"); + if (!allowed) { + throw new ZygoteSecurityException( + "Peer may not specify uid's or gid's"); + } + } + // If not otherwise specified, uid and gid are inherited from peer if (!args.uidSpecified) { args.uid = peer.getUid(); @@ -664,7 +694,7 @@ class ZygoteConnection { * @throws ZygoteSecurityException */ private static void applyRlimitSecurityPolicy( - Arguments args, Credentials peer) + Arguments args, Credentials peer, String peerSecurityContext) throws ZygoteSecurityException { int peerUid = peer.getUid(); @@ -676,6 +706,17 @@ class ZygoteConnection { "This UID may not specify rlimits."); } } + + if (args.rlimits != null) { + boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext, + peerSecurityContext, + "zygote", + "specifyrlimits"); + if (!allowed) { + throw new ZygoteSecurityException( + "Peer may not specify rlimits"); + } + } } /** @@ -689,7 +730,7 @@ class ZygoteConnection { * @throws ZygoteSecurityException */ private static void applyCapabilitiesSecurityPolicy( - Arguments args, Credentials peer) + Arguments args, Credentials peer, String peerSecurityContext) throws ZygoteSecurityException { if (args.permittedCapabilities == 0 @@ -698,6 +739,15 @@ class ZygoteConnection { return; } + boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext, + peerSecurityContext, + "zygote", + "specifycapabilities"); + if (!allowed) { + throw new ZygoteSecurityException( + "Peer may not specify capabilities"); + } + if (peer.getUid() == 0) { // root may specify anything return; @@ -747,7 +797,8 @@ class ZygoteConnection { * @param peer non-null; peer credentials * @throws ZygoteSecurityException */ - private static void applyInvokeWithSecurityPolicy(Arguments args, Credentials peer) + private static void applyInvokeWithSecurityPolicy(Arguments args, Credentials peer, + String peerSecurityContext) throws ZygoteSecurityException { int peerUid = peer.getUid(); @@ -755,6 +806,52 @@ class ZygoteConnection { throw new ZygoteSecurityException("Peer is not permitted to specify " + "an explicit invoke-with wrapper command"); } + + if (args.invokeWith != null) { + boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext, + peerSecurityContext, + "zygote", + "specifyinvokewith"); + if (!allowed) { + throw new ZygoteSecurityException("Peer is not permitted to specify " + + "an explicit invoke-with wrapper command"); + } + } + } + + /** + * Applies zygote security policy for SEAndroid information. + * + * @param args non-null; zygote spawner arguments + * @param peer non-null; peer credentials + * @throws ZygoteSecurityException + */ + private static void applyseInfoSecurityPolicy( + Arguments args, Credentials peer, String peerSecurityContext) + throws ZygoteSecurityException { + int peerUid = peer.getUid(); + + if (args.seInfo == null) { + // nothing to check + return; + } + + if (!(peerUid == 0 || peerUid == Process.SYSTEM_UID)) { + // All peers with UID other than root or SYSTEM_UID + throw new ZygoteSecurityException( + "This UID may not specify SEAndroid info."); + } + + boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext, + peerSecurityContext, + "zygote", + "specifyseinfo"); + if (!allowed) { + throw new ZygoteSecurityException( + "Peer may not specify SEAndroid info"); + } + + return; } /** diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index 998c037..4924326 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -16,16 +16,17 @@ package com.android.internal.os; +import static libcore.io.OsConstants.S_IRWXG; +import static libcore.io.OsConstants.S_IRWXO; + import android.content.pm.ActivityInfo; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.net.LocalServerSocket; import android.os.Debug; -import android.os.FileUtils; import android.os.Process; import android.os.SystemClock; -import android.os.SystemProperties; import android.util.EventLog; import android.util.Log; @@ -33,6 +34,7 @@ import dalvik.system.VMRuntime; import dalvik.system.Zygote; import libcore.io.IoUtils; +import libcore.io.Libcore; import java.io.BufferedReader; import java.io.FileDescriptor; @@ -447,7 +449,7 @@ public class ZygoteInit { closeServerSocket(); // set umask to 0077 so new files and directories will default to owner-only permissions. - FileUtils.setUMask(FileUtils.S_IRWXG | FileUtils.S_IRWXO); + Libcore.os.umask(S_IRWXG | S_IRWXO); if (parsedArgs.niceName != null) { Process.setArgV0(parsedArgs.niceName); diff --git a/core/java/com/android/internal/util/AsyncChannel.java b/core/java/com/android/internal/util/AsyncChannel.java index d1c2d2e..5093b4d 100644 --- a/core/java/com/android/internal/util/AsyncChannel.java +++ b/core/java/com/android/internal/util/AsyncChannel.java @@ -444,6 +444,16 @@ public class AsyncChannel { if ((mConnection != null) && (mSrcContext != null)) { mSrcContext.unbindService(mConnection); } + try { + // Send the DISCONNECTED, although it may not be received + // but its the best we can do. + Message msg = Message.obtain(); + msg.what = CMD_CHANNEL_DISCONNECTED; + msg.replyTo = mSrcMessenger; + mDstMessenger.send(msg); + } catch(Exception e) { + } + // Tell source we're disconnected. if (mSrcHandler != null) { replyDisconnected(STATUS_SUCCESSFUL); } diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java index 1391ac3..0ea7b83 100644 --- a/core/java/com/android/internal/util/StateMachine.java +++ b/core/java/com/android/internal/util/StateMachine.java @@ -80,9 +80,9 @@ import java.util.Vector; * and invoke <code>halting</code>. Any message subsequently received by the state * machine will cause <code>haltedProcessMessage</code> to be invoked.</p> * - * <p>If it is desirable to completely stop the state machine call <code>quit</code>. This - * will exit the current state and its parent and then exit from the controlling thread - * and no further messages will be processed.</p> + * <p>If it is desirable to completely stop the state machine call <code>quit</code> or + * <code>abort</code>. These will call <code>exit</code> of the current state and its parents, call + * <code>onQuiting</code> and then exit Thread/Loopers.</p> * * <p>In addition to <code>processMessage</code> each <code>State</code> has * an <code>enter</code> method and <code>exit</exit> method which may be overridden.</p> @@ -362,7 +362,7 @@ class Hsm1 extends StateMachine { } @Override - void halting() { + void onHalting() { Log.d(TAG, "halting"); synchronized (this) { this.notifyAll(); @@ -423,10 +423,10 @@ public class StateMachine { private String mName; /** Message.what value when quitting */ - public static final int SM_QUIT_CMD = -1; + private static final int SM_QUIT_CMD = -1; /** Message.what value when initializing */ - public static final int SM_INIT_CMD = -2; + private static final int SM_INIT_CMD = -2; /** * Convenience constant that maybe returned by processMessage @@ -443,11 +443,10 @@ public class StateMachine { public static final boolean NOT_HANDLED = false; /** + * StateMachine logging record. * {@hide} - * - * The information maintained for a processed message. */ - public static class ProcessedMessageInfo { + public static class LogRec { private long mTime; private int mWhat; private String mInfo; @@ -456,12 +455,13 @@ public class StateMachine { /** * Constructor - * @param message + * + * @param msg * @param state that handled the message * @param orgState is the first state the received the message but * did not processes the message. */ - ProcessedMessageInfo(Message msg, String info, State state, State orgState) { + LogRec(Message msg, String info, State state, State orgState) { update(msg, info, state, orgState); } @@ -473,7 +473,7 @@ public class StateMachine { */ public void update(Message msg, String info, State state, State orgState) { mTime = System.currentTimeMillis(); - mWhat = msg.what; + mWhat = (msg != null) ? msg.what : 0; mInfo = info; mState = state; mOrgState = orgState; @@ -517,8 +517,7 @@ public class StateMachine { /** * @return as string */ - @Override - public String toString() { + public String toString(StateMachine sm) { StringBuilder sb = new StringBuilder(); sb.append("time="); Calendar c = Calendar.getInstance(); @@ -529,10 +528,15 @@ public class StateMachine { sb.append(" orgState="); sb.append(mOrgState == null ? "<null>" : mOrgState.getName()); sb.append(" what="); - sb.append(mWhat); - sb.append("(0x"); - sb.append(Integer.toHexString(mWhat)); - sb.append(")"); + String what = sm.getWhatToString(mWhat); + if (TextUtils.isEmpty(what)) { + sb.append(mWhat); + sb.append("(0x"); + sb.append(Integer.toHexString(mWhat)); + sb.append(")"); + } else { + sb.append(what); + } if ( ! TextUtils.isEmpty(mInfo)) { sb.append(" "); sb.append(mInfo); @@ -542,21 +546,21 @@ public class StateMachine { } /** - * A list of messages recently processed by the state machine. + * A list of log records including messages recently processed by the state machine. * - * The class maintains a list of messages that have been most + * The class maintains a list of log records including messages * recently processed. The list is finite and may be set in the * constructor or by calling setSize. The public interface also - * includes size which returns the number of recent messages, - * count which is the number of message processed since the - * the last setSize, get which returns a processed message and - * add which adds a processed messaged. + * includes size which returns the number of recent records, + * count which is the number of records processed since the + * the last setSize, get which returns a record and + * add which adds a record. */ - private static class ProcessedMessages { + private static class LogRecords { private static final int DEFAULT_SIZE = 20; - private Vector<ProcessedMessageInfo> mMessages = new Vector<ProcessedMessageInfo>(); + private Vector<LogRec> mLogRecords = new Vector<LogRec>(); private int mMaxSize = DEFAULT_SIZE; private int mOldestIndex = 0; private int mCount = 0; @@ -564,39 +568,39 @@ public class StateMachine { /** * private constructor use add */ - private ProcessedMessages() { + private LogRecords() { } /** - * Set size of messages to maintain and clears all current messages. + * Set size of messages to maintain and clears all current records. * - * @param maxSize number of messages to maintain at anyone time. + * @param maxSize number of records to maintain at anyone time. */ - void setSize(int maxSize) { + synchronized void setSize(int maxSize) { mMaxSize = maxSize; mCount = 0; - mMessages.clear(); + mLogRecords.clear(); } /** - * @return the number of recent messages. + * @return the number of recent records. */ - int size() { - return mMessages.size(); + synchronized int size() { + return mLogRecords.size(); } /** - * @return the total number of messages processed since size was set. + * @return the total number of records processed since size was set. */ - int count() { + synchronized int count() { return mCount; } /** - * Clear the list of Processed Message Info. + * Clear the list of records. */ - void cleanup() { - mMessages.clear(); + synchronized void cleanup() { + mLogRecords.clear(); } /** @@ -604,7 +608,7 @@ public class StateMachine { * record and size()-1 is the newest record. If the index is to * large null is returned. */ - ProcessedMessageInfo get(int index) { + synchronized LogRec get(int index) { int nextIndex = mOldestIndex + index; if (nextIndex >= mMaxSize) { nextIndex -= mMaxSize; @@ -612,7 +616,7 @@ public class StateMachine { if (nextIndex >= size()) { return null; } else { - return mMessages.get(nextIndex); + return mLogRecords.get(nextIndex); } } @@ -625,12 +629,12 @@ public class StateMachine { * @param orgState is the first state the received the message but * did not processes the message. */ - void add(Message msg, String messageInfo, State state, State orgState) { + synchronized void add(Message msg, String messageInfo, State state, State orgState) { mCount += 1; - if (mMessages.size() < mMaxSize) { - mMessages.add(new ProcessedMessageInfo(msg, messageInfo, state, orgState)); + if (mLogRecords.size() < mMaxSize) { + mLogRecords.add(new LogRec(msg, messageInfo, state, orgState)); } else { - ProcessedMessageInfo pmi = mMessages.get(mOldestIndex); + LogRec pmi = mLogRecords.get(mOldestIndex); mOldestIndex += 1; if (mOldestIndex >= mMaxSize) { mOldestIndex = 0; @@ -652,8 +656,8 @@ public class StateMachine { /** The current message */ private Message mMsg; - /** A list of messages that this state machine has processed */ - private ProcessedMessages mProcessedMessages = new ProcessedMessages(); + /** A list of log records including messages this state machine has processed */ + private LogRecords mLogRecords = new LogRecords(); /** true if construction of the state machine has not been completed */ private boolean mIsConstructionCompleted; @@ -814,15 +818,18 @@ public class StateMachine { */ if (destState != null) { if (destState == mQuittingState) { + /** + * Call onQuitting to let subclasses cleanup. + */ + mSm.onQuitting(); cleanupAfterQuitting(); - } else if (destState == mHaltingState) { /** - * Call halting() if we've transitioned to the halting + * Call onHalting() if we've transitioned to the halting * state. All subsequent messages will be processed in * in the halting state which invokes haltedProcessMessage(msg); */ - mSm.halting(); + mSm.onHalting(); } } } @@ -831,7 +838,6 @@ public class StateMachine { * Cleanup all the static variables and the looper after the SM has been quit. */ private final void cleanupAfterQuitting() { - mSm.quitting(); if (mSm.mSmThread != null) { // If we made the thread then quit looper which stops the thread. getLooper().quit(); @@ -841,7 +847,7 @@ public class StateMachine { mSm.mSmHandler = null; mSm = null; mMsg = null; - mProcessedMessages.cleanup(); + mLogRecords.cleanup(); mStateStack = null; mTempStateStack = null; mStateInfo.clear(); @@ -892,36 +898,38 @@ public class StateMachine { if (mDbg) { Log.d(TAG, "processMsg: " + curStateInfo.state.getName()); } - while (!curStateInfo.state.processMessage(msg)) { - /** - * Not processed - */ - curStateInfo = curStateInfo.parentStateInfo; - if (curStateInfo == null) { + + if (isQuit(msg)) { + transitionTo(mQuittingState); + } else { + while (!curStateInfo.state.processMessage(msg)) { /** - * No parents left so it's not handled + * Not processed */ - mSm.unhandledMessage(msg); - if (isQuit(msg)) { - transitionTo(mQuittingState); + curStateInfo = curStateInfo.parentStateInfo; + if (curStateInfo == null) { + /** + * No parents left so it's not handled + */ + mSm.unhandledMessage(msg); + break; + } + if (mDbg) { + Log.d(TAG, "processMsg: " + curStateInfo.state.getName()); } - break; - } - if (mDbg) { - Log.d(TAG, "processMsg: " + curStateInfo.state.getName()); } - } - /** - * Record that we processed the message - */ - if (mSm.recordProcessedMessage(msg)) { - if (curStateInfo != null) { - State orgState = mStateStack[mStateStackTopIndex].state; - mProcessedMessages.add(msg, mSm.getMessageInfo(msg), curStateInfo.state, - orgState); - } else { - mProcessedMessages.add(msg, mSm.getMessageInfo(msg), null, null); + /** + * Record that we processed the message + */ + if (mSm.recordLogRec(msg)) { + if (curStateInfo != null) { + State orgState = mStateStack[mStateStackTopIndex].state; + mLogRecords.add(msg, mSm.getLogRecString(msg), curStateInfo.state, + orgState); + } else { + mLogRecords.add(msg, mSm.getLogRecString(msg), null, null); + } } } } @@ -1141,13 +1149,19 @@ public class StateMachine { mDeferredMessages.add(newMsg); } - /** @see StateMachine#deferMessage(Message) */ + /** @see StateMachine#quit() */ private final void quit() { if (mDbg) Log.d(TAG, "quit:"); sendMessage(obtainMessage(SM_QUIT_CMD, mSmHandlerObj)); } - /** @see StateMachine#isQuit(Message) */ + /** @see StateMachine#quitNow() */ + private final void quitNow() { + if (mDbg) Log.d(TAG, "abort:"); + sendMessageAtFrontOfQueue(obtainMessage(SM_QUIT_CMD, mSmHandlerObj)); + } + + /** Validate that the message was sent by quit or abort. */ private final boolean isQuit(Message msg) { return (msg.what == SM_QUIT_CMD) && (msg.obj == mSmHandlerObj); } @@ -1162,26 +1176,6 @@ public class StateMachine { mDbg = dbg; } - /** @see StateMachine#setProcessedMessagesSize(int) */ - private final void setProcessedMessagesSize(int maxSize) { - mProcessedMessages.setSize(maxSize); - } - - /** @see StateMachine#getProcessedMessagesSize() */ - private final int getProcessedMessagesSize() { - return mProcessedMessages.size(); - } - - /** @see StateMachine#getProcessedMessagesCount() */ - private final int getProcessedMessagesCount() { - return mProcessedMessages.count(); - } - - /** @see StateMachine#getProcessedMessageInfo(int) */ - private final ProcessedMessageInfo getProcessedMessageInfo(int index) { - return mProcessedMessages.get(index); - } - } private SmHandler mSmHandler; @@ -1282,8 +1276,8 @@ public class StateMachine { /** * transition to halt state. Upon returning * from processMessage we will exit all current - * states, execute the halting() method and then - * all subsequent messages haltedProcessMesage + * states, execute the onHalting() method and then + * for all subsequent messages haltedProcessMessage * will be called. */ protected final void transitionToHaltingState() { @@ -1303,7 +1297,6 @@ public class StateMachine { mSmHandler.deferMessage(msg); } - /** * Called when message wasn't handled * @@ -1325,7 +1318,7 @@ public class StateMachine { * transitionToHalting. All subsequent messages will invoke * {@link StateMachine#haltedProcessMessage(Message)} */ - protected void halting() { + protected void onHalting() { } /** @@ -1334,7 +1327,7 @@ public class StateMachine { * ignored. In addition, if this StateMachine created the thread, the thread will * be stopped after this method returns. */ - protected void quitting() { + protected void onQuitting() { } /** @@ -1345,33 +1338,77 @@ public class StateMachine { } /** - * Set size of messages to maintain and clears all current messages. + * Set number of log records to maintain and clears all current records. * * @param maxSize number of messages to maintain at anyone time. */ - public final void setProcessedMessagesSize(int maxSize) { - mSmHandler.setProcessedMessagesSize(maxSize); + public final void setLogRecSize(int maxSize) { + mSmHandler.mLogRecords.setSize(maxSize); + } + + /** + * @return number of log records + */ + public final int getLogRecSize() { + return mSmHandler.mLogRecords.size(); + } + + /** + * @return the total number of records processed + */ + public final int getLogRecCount() { + return mSmHandler.mLogRecords.count(); + } + + /** + * @return a log record + */ + public final LogRec getLogRec(int index) { + return mSmHandler.mLogRecords.get(index); + } + + /** + * Add the string to LogRecords. + * + * @param string + */ + protected void addLogRec(String string) { + mSmHandler.mLogRecords.add(null, string, null, null); } /** - * @return number of messages processed + * Add the string and state to LogRecords + * + * @param string + * @param state current state */ - public final int getProcessedMessagesSize() { - return mSmHandler.getProcessedMessagesSize(); + protected void addLogRec(String string, State state) { + mSmHandler.mLogRecords.add(null, string, state, null); } /** - * @return the total number of messages processed + * @return true if msg should be saved in the log, default is true. */ - public final int getProcessedMessagesCount() { - return mSmHandler.getProcessedMessagesCount(); + protected boolean recordLogRec(Message msg) { + return true; } /** - * @return a processed message information + * Return a string to be logged by LogRec, default + * is an empty string. Override if additional information is desired. + * + * @param msg that was processed + * @return information to be logged as a String */ - public final ProcessedMessageInfo getProcessedMessageInfo(int index) { - return mSmHandler.getProcessedMessageInfo(index); + protected String getLogRecString(Message msg) { + return ""; + } + + /** + * @return the string for msg.what + */ + protected String getWhatToString(int what) { + return null; } /** @@ -1548,43 +1585,23 @@ public class StateMachine { } /** - * Conditionally quit the looper and stop execution. - * - * This sends the SM_QUIT_MSG to the state machine and - * if not handled by any state's processMessage then the - * state machine will be stopped and no further messages - * will be processed. + * Quit the state machine after all currently queued up messages are processed. */ - public final void quit() { - // mSmHandler can be null if the state machine has quit. + protected final void quit() { + // mSmHandler can be null if the state machine is already stopped. if (mSmHandler == null) return; mSmHandler.quit(); } /** - * @return ture if msg is quit + * Quit the state machine immediately all currently queued messages will be discarded. */ - protected final boolean isQuit(Message msg) { - return mSmHandler.isQuit(msg); - } - - /** - * @return true if msg should be saved in ProcessedMessage, default is true. - */ - protected boolean recordProcessedMessage(Message msg) { - return true; - } + protected final void quitNow() { + // mSmHandler can be null if the state machine is already stopped. + if (mSmHandler == null) return; - /** - * Return message info to be logged by ProcessedMessageInfo, default - * is an empty string. Override if additional information is desired. - * - * @param msg that was processed - * @return information to be logged as a String - */ - protected String getMessageInfo(Message msg) { - return ""; + mSmHandler.quitNow(); } /** @@ -1629,9 +1646,9 @@ public class StateMachine { */ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println(getName() + ":"); - pw.println(" total messages=" + getProcessedMessagesCount()); - for (int i=0; i < getProcessedMessagesSize(); i++) { - pw.printf(" msg[%d]: %s\n", i, getProcessedMessageInfo(i)); + pw.println(" total records=" + getLogRecCount()); + for (int i=0; i < getLogRecSize(); i++) { + pw.printf(" rec[%d]: %s\n", i, getLogRec(i).toString(this)); pw.flush(); } pw.println("curState=" + getCurrentState().getName()); diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java index 73324c0..cf6029e 100644 --- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java +++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java @@ -278,7 +278,7 @@ public class ActionMenuPresenter extends BaseMenuPresenter */ public boolean showOverflowMenu() { if (mReserveOverflow && !isOverflowMenuShowing() && mMenu != null && mMenuView != null && - mPostedOpenRunnable == null) { + mPostedOpenRunnable == null && !mMenu.getNonActionItems().isEmpty()) { OverflowPopup popup = new OverflowPopup(mContext, mMenu, mOverflowButton, true); mPostedOpenRunnable = new OpenOverflowRunnable(popup); // Post this for later; we might still need a layout for the anchor to be right. diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java index f54575b..cef6a8f 100644 --- a/core/java/com/android/internal/view/menu/ActionMenuView.java +++ b/core/java/com/android/internal/view/menu/ActionMenuView.java @@ -524,6 +524,9 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo @Override protected boolean hasDividerBeforeChildAt(int childIndex) { + if (childIndex == 0) { + return false; + } final View childBefore = getChildAt(childIndex - 1); final View child = getChildAt(childIndex); boolean result = false; diff --git a/core/java/com/google/android/mms/ContentType.java b/core/java/com/google/android/mms/ContentType.java deleted file mode 100644 index 12a1343..0000000 --- a/core/java/com/google/android/mms/ContentType.java +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright (C) 2007-2008 Esmertec AG. - * Copyright (C) 2007-2008 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.mms; - -import java.util.ArrayList; - -public class ContentType { - public static final String MMS_MESSAGE = "application/vnd.wap.mms-message"; - // The phony content type for generic PDUs (e.g. ReadOrig.ind, - // Notification.ind, Delivery.ind). - public static final String MMS_GENERIC = "application/vnd.wap.mms-generic"; - public static final String MULTIPART_MIXED = "application/vnd.wap.multipart.mixed"; - public static final String MULTIPART_RELATED = "application/vnd.wap.multipart.related"; - public static final String MULTIPART_ALTERNATIVE = "application/vnd.wap.multipart.alternative"; - - public static final String TEXT_PLAIN = "text/plain"; - public static final String TEXT_HTML = "text/html"; - public static final String TEXT_VCALENDAR = "text/x-vCalendar"; - public static final String TEXT_VCARD = "text/x-vCard"; - - public static final String IMAGE_UNSPECIFIED = "image/*"; - public static final String IMAGE_JPEG = "image/jpeg"; - public static final String IMAGE_JPG = "image/jpg"; - public static final String IMAGE_GIF = "image/gif"; - public static final String IMAGE_WBMP = "image/vnd.wap.wbmp"; - public static final String IMAGE_PNG = "image/png"; - public static final String IMAGE_X_MS_BMP = "image/x-ms-bmp"; - - public static final String AUDIO_UNSPECIFIED = "audio/*"; - public static final String AUDIO_AAC = "audio/aac"; - public static final String AUDIO_AMR = "audio/amr"; - public static final String AUDIO_IMELODY = "audio/imelody"; - public static final String AUDIO_MID = "audio/mid"; - public static final String AUDIO_MIDI = "audio/midi"; - public static final String AUDIO_MP3 = "audio/mp3"; - public static final String AUDIO_MPEG3 = "audio/mpeg3"; - public static final String AUDIO_MPEG = "audio/mpeg"; - public static final String AUDIO_MPG = "audio/mpg"; - public static final String AUDIO_MP4 = "audio/mp4"; - public static final String AUDIO_X_MID = "audio/x-mid"; - public static final String AUDIO_X_MIDI = "audio/x-midi"; - public static final String AUDIO_X_MP3 = "audio/x-mp3"; - public static final String AUDIO_X_MPEG3 = "audio/x-mpeg3"; - public static final String AUDIO_X_MPEG = "audio/x-mpeg"; - public static final String AUDIO_X_MPG = "audio/x-mpg"; - public static final String AUDIO_3GPP = "audio/3gpp"; - public static final String AUDIO_X_WAV = "audio/x-wav"; - public static final String AUDIO_OGG = "application/ogg"; - - public static final String VIDEO_UNSPECIFIED = "video/*"; - public static final String VIDEO_3GPP = "video/3gpp"; - public static final String VIDEO_3G2 = "video/3gpp2"; - public static final String VIDEO_H263 = "video/h263"; - public static final String VIDEO_MP4 = "video/mp4"; - - public static final String APP_SMIL = "application/smil"; - public static final String APP_WAP_XHTML = "application/vnd.wap.xhtml+xml"; - public static final String APP_XHTML = "application/xhtml+xml"; - - public static final String APP_DRM_CONTENT = "application/vnd.oma.drm.content"; - public static final String APP_DRM_MESSAGE = "application/vnd.oma.drm.message"; - - private static final ArrayList<String> sSupportedContentTypes = new ArrayList<String>(); - private static final ArrayList<String> sSupportedImageTypes = new ArrayList<String>(); - private static final ArrayList<String> sSupportedAudioTypes = new ArrayList<String>(); - private static final ArrayList<String> sSupportedVideoTypes = new ArrayList<String>(); - - static { - sSupportedContentTypes.add(TEXT_PLAIN); - sSupportedContentTypes.add(TEXT_HTML); - sSupportedContentTypes.add(TEXT_VCALENDAR); - sSupportedContentTypes.add(TEXT_VCARD); - - sSupportedContentTypes.add(IMAGE_JPEG); - sSupportedContentTypes.add(IMAGE_GIF); - sSupportedContentTypes.add(IMAGE_WBMP); - sSupportedContentTypes.add(IMAGE_PNG); - sSupportedContentTypes.add(IMAGE_JPG); - sSupportedContentTypes.add(IMAGE_X_MS_BMP); - //supportedContentTypes.add(IMAGE_SVG); not yet supported. - - sSupportedContentTypes.add(AUDIO_AAC); - sSupportedContentTypes.add(AUDIO_AMR); - sSupportedContentTypes.add(AUDIO_IMELODY); - sSupportedContentTypes.add(AUDIO_MID); - sSupportedContentTypes.add(AUDIO_MIDI); - sSupportedContentTypes.add(AUDIO_MP3); - sSupportedContentTypes.add(AUDIO_MPEG3); - sSupportedContentTypes.add(AUDIO_MPEG); - sSupportedContentTypes.add(AUDIO_MPG); - sSupportedContentTypes.add(AUDIO_X_MID); - sSupportedContentTypes.add(AUDIO_X_MIDI); - sSupportedContentTypes.add(AUDIO_X_MP3); - sSupportedContentTypes.add(AUDIO_X_MPEG3); - sSupportedContentTypes.add(AUDIO_X_MPEG); - sSupportedContentTypes.add(AUDIO_X_MPG); - sSupportedContentTypes.add(AUDIO_X_WAV); - sSupportedContentTypes.add(AUDIO_3GPP); - sSupportedContentTypes.add(AUDIO_OGG); - - sSupportedContentTypes.add(VIDEO_3GPP); - sSupportedContentTypes.add(VIDEO_3G2); - sSupportedContentTypes.add(VIDEO_H263); - sSupportedContentTypes.add(VIDEO_MP4); - - sSupportedContentTypes.add(APP_SMIL); - sSupportedContentTypes.add(APP_WAP_XHTML); - sSupportedContentTypes.add(APP_XHTML); - - sSupportedContentTypes.add(APP_DRM_CONTENT); - sSupportedContentTypes.add(APP_DRM_MESSAGE); - - // add supported image types - sSupportedImageTypes.add(IMAGE_JPEG); - sSupportedImageTypes.add(IMAGE_GIF); - sSupportedImageTypes.add(IMAGE_WBMP); - sSupportedImageTypes.add(IMAGE_PNG); - sSupportedImageTypes.add(IMAGE_JPG); - sSupportedImageTypes.add(IMAGE_X_MS_BMP); - - // add supported audio types - sSupportedAudioTypes.add(AUDIO_AAC); - sSupportedAudioTypes.add(AUDIO_AMR); - sSupportedAudioTypes.add(AUDIO_IMELODY); - sSupportedAudioTypes.add(AUDIO_MID); - sSupportedAudioTypes.add(AUDIO_MIDI); - sSupportedAudioTypes.add(AUDIO_MP3); - sSupportedAudioTypes.add(AUDIO_MPEG3); - sSupportedAudioTypes.add(AUDIO_MPEG); - sSupportedAudioTypes.add(AUDIO_MPG); - sSupportedAudioTypes.add(AUDIO_MP4); - sSupportedAudioTypes.add(AUDIO_X_MID); - sSupportedAudioTypes.add(AUDIO_X_MIDI); - sSupportedAudioTypes.add(AUDIO_X_MP3); - sSupportedAudioTypes.add(AUDIO_X_MPEG3); - sSupportedAudioTypes.add(AUDIO_X_MPEG); - sSupportedAudioTypes.add(AUDIO_X_MPG); - sSupportedAudioTypes.add(AUDIO_X_WAV); - sSupportedAudioTypes.add(AUDIO_3GPP); - sSupportedAudioTypes.add(AUDIO_OGG); - - // add supported video types - sSupportedVideoTypes.add(VIDEO_3GPP); - sSupportedVideoTypes.add(VIDEO_3G2); - sSupportedVideoTypes.add(VIDEO_H263); - sSupportedVideoTypes.add(VIDEO_MP4); - } - - // This class should never be instantiated. - private ContentType() { - } - - public static boolean isSupportedType(String contentType) { - return (null != contentType) && sSupportedContentTypes.contains(contentType); - } - - public static boolean isSupportedImageType(String contentType) { - return isImageType(contentType) && isSupportedType(contentType); - } - - public static boolean isSupportedAudioType(String contentType) { - return isAudioType(contentType) && isSupportedType(contentType); - } - - public static boolean isSupportedVideoType(String contentType) { - return isVideoType(contentType) && isSupportedType(contentType); - } - - public static boolean isTextType(String contentType) { - return (null != contentType) && contentType.startsWith("text/"); - } - - public static boolean isImageType(String contentType) { - return (null != contentType) && contentType.startsWith("image/"); - } - - public static boolean isAudioType(String contentType) { - return (null != contentType) && contentType.startsWith("audio/"); - } - - public static boolean isVideoType(String contentType) { - return (null != contentType) && contentType.startsWith("video/"); - } - - public static boolean isDrmType(String contentType) { - return (null != contentType) - && (contentType.equals(APP_DRM_CONTENT) - || contentType.equals(APP_DRM_MESSAGE)); - } - - public static boolean isUnspecified(String contentType) { - return (null != contentType) && contentType.endsWith("*"); - } - - @SuppressWarnings("unchecked") - public static ArrayList<String> getImageTypes() { - return (ArrayList<String>) sSupportedImageTypes.clone(); - } - - @SuppressWarnings("unchecked") - public static ArrayList<String> getAudioTypes() { - return (ArrayList<String>) sSupportedAudioTypes.clone(); - } - - @SuppressWarnings("unchecked") - public static ArrayList<String> getVideoTypes() { - return (ArrayList<String>) sSupportedVideoTypes.clone(); - } - - @SuppressWarnings("unchecked") - public static ArrayList<String> getSupportedTypes() { - return (ArrayList<String>) sSupportedContentTypes.clone(); - } -} diff --git a/core/java/com/google/android/mms/InvalidHeaderValueException.java b/core/java/com/google/android/mms/InvalidHeaderValueException.java deleted file mode 100644 index 73d7832..0000000 --- a/core/java/com/google/android/mms/InvalidHeaderValueException.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2007 Esmertec AG. - * Copyright (C) 2007 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.mms; - -/** - * Thrown when an invalid header value was set. - */ -public class InvalidHeaderValueException extends MmsException { - private static final long serialVersionUID = -2053384496042052262L; - - /** - * Constructs an InvalidHeaderValueException with no detailed message. - */ - public InvalidHeaderValueException() { - super(); - } - - /** - * Constructs an InvalidHeaderValueException with the specified detailed message. - * - * @param message the detailed message. - */ - public InvalidHeaderValueException(String message) { - super(message); - } -} diff --git a/core/java/com/google/android/mms/MmsException.java b/core/java/com/google/android/mms/MmsException.java deleted file mode 100644 index 6ca0c7e..0000000 --- a/core/java/com/google/android/mms/MmsException.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2007 Esmertec AG. - * Copyright (C) 2007 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.mms; - -/** - * A generic exception that is thrown by the Mms client. - */ -public class MmsException extends Exception { - private static final long serialVersionUID = -7323249827281485390L; - - /** - * Creates a new MmsException. - */ - public MmsException() { - super(); - } - - /** - * Creates a new MmsException with the specified detail message. - * - * @param message the detail message. - */ - public MmsException(String message) { - super(message); - } - - /** - * Creates a new MmsException with the specified cause. - * - * @param cause the cause. - */ - public MmsException(Throwable cause) { - super(cause); - } - - /** - * Creates a new MmsException with the specified detail message and cause. - * - * @param message the detail message. - * @param cause the cause. - */ - public MmsException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/core/java/com/google/android/mms/package.html b/core/java/com/google/android/mms/package.html deleted file mode 100755 index c9f96a6..0000000 --- a/core/java/com/google/android/mms/package.html +++ /dev/null @@ -1,5 +0,0 @@ -<body> - -{@hide} - -</body> diff --git a/core/java/com/google/android/mms/pdu/AcknowledgeInd.java b/core/java/com/google/android/mms/pdu/AcknowledgeInd.java deleted file mode 100644 index 0e96c60..0000000 --- a/core/java/com/google/android/mms/pdu/AcknowledgeInd.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2007 Esmertec AG. - * Copyright (C) 2007 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.mms.pdu; - -import com.google.android.mms.InvalidHeaderValueException; - -/** - * M-Acknowledge.ind PDU. - */ -public class AcknowledgeInd extends GenericPdu { - /** - * Constructor, used when composing a M-Acknowledge.ind pdu. - * - * @param mmsVersion current viersion of mms - * @param transactionId the transaction-id value - * @throws InvalidHeaderValueException if parameters are invalid. - * NullPointerException if transactionId is null. - */ - public AcknowledgeInd(int mmsVersion, byte[] transactionId) - throws InvalidHeaderValueException { - super(); - - setMessageType(PduHeaders.MESSAGE_TYPE_ACKNOWLEDGE_IND); - setMmsVersion(mmsVersion); - setTransactionId(transactionId); - } - - /** - * Constructor with given headers. - * - * @param headers Headers for this PDU. - */ - AcknowledgeInd(PduHeaders headers) { - super(headers); - } - - /** - * Get X-Mms-Report-Allowed field value. - * - * @return the X-Mms-Report-Allowed value - */ - public int getReportAllowed() { - return mPduHeaders.getOctet(PduHeaders.REPORT_ALLOWED); - } - - /** - * Set X-Mms-Report-Allowed field value. - * - * @param value the value - * @throws InvalidHeaderValueException if the value is invalid. - */ - public void setReportAllowed(int value) throws InvalidHeaderValueException { - mPduHeaders.setOctet(value, PduHeaders.REPORT_ALLOWED); - } - - /** - * Get X-Mms-Transaction-Id field value. - * - * @return the X-Mms-Report-Allowed value - */ - public byte[] getTransactionId() { - return mPduHeaders.getTextString(PduHeaders.TRANSACTION_ID); - } - - /** - * Set X-Mms-Transaction-Id field value. - * - * @param value the value - * @throws NullPointerException if the value is null. - */ - public void setTransactionId(byte[] value) { - mPduHeaders.setTextString(value, PduHeaders.TRANSACTION_ID); - } -} diff --git a/core/java/com/google/android/mms/pdu/Base64.java b/core/java/com/google/android/mms/pdu/Base64.java deleted file mode 100644 index 604bee0..0000000 --- a/core/java/com/google/android/mms/pdu/Base64.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (C) 2007 Esmertec AG. - * Copyright (C) 2007 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.mms.pdu; - -public class Base64 { - /** - * Used to get the number of Quadruples. - */ - static final int FOURBYTE = 4; - - /** - * Byte used to pad output. - */ - static final byte PAD = (byte) '='; - - /** - * The base length. - */ - static final int BASELENGTH = 255; - - // Create arrays to hold the base64 characters - private static byte[] base64Alphabet = new byte[BASELENGTH]; - - // Populating the character arrays - static { - for (int i = 0; i < BASELENGTH; i++) { - base64Alphabet[i] = (byte) -1; - } - for (int i = 'Z'; i >= 'A'; i--) { - base64Alphabet[i] = (byte) (i - 'A'); - } - for (int i = 'z'; i >= 'a'; i--) { - base64Alphabet[i] = (byte) (i - 'a' + 26); - } - for (int i = '9'; i >= '0'; i--) { - base64Alphabet[i] = (byte) (i - '0' + 52); - } - - base64Alphabet['+'] = 62; - base64Alphabet['/'] = 63; - } - - /** - * Decodes Base64 data into octects - * - * @param base64Data Byte array containing Base64 data - * @return Array containing decoded data. - */ - public static byte[] decodeBase64(byte[] base64Data) { - // RFC 2045 requires that we discard ALL non-Base64 characters - base64Data = discardNonBase64(base64Data); - - // handle the edge case, so we don't have to worry about it later - if (base64Data.length == 0) { - return new byte[0]; - } - - int numberQuadruple = base64Data.length / FOURBYTE; - byte decodedData[] = null; - byte b1 = 0, b2 = 0, b3 = 0, b4 = 0, marker0 = 0, marker1 = 0; - - // Throw away anything not in base64Data - - int encodedIndex = 0; - int dataIndex = 0; - { - // this sizes the output array properly - rlw - int lastData = base64Data.length; - // ignore the '=' padding - while (base64Data[lastData - 1] == PAD) { - if (--lastData == 0) { - return new byte[0]; - } - } - decodedData = new byte[lastData - numberQuadruple]; - } - - for (int i = 0; i < numberQuadruple; i++) { - dataIndex = i * 4; - marker0 = base64Data[dataIndex + 2]; - marker1 = base64Data[dataIndex + 3]; - - b1 = base64Alphabet[base64Data[dataIndex]]; - b2 = base64Alphabet[base64Data[dataIndex + 1]]; - - if (marker0 != PAD && marker1 != PAD) { - //No PAD e.g 3cQl - b3 = base64Alphabet[marker0]; - b4 = base64Alphabet[marker1]; - - decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); - decodedData[encodedIndex + 1] = - (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); - decodedData[encodedIndex + 2] = (byte) (b3 << 6 | b4); - } else if (marker0 == PAD) { - //Two PAD e.g. 3c[Pad][Pad] - decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); - } else if (marker1 == PAD) { - //One PAD e.g. 3cQ[Pad] - b3 = base64Alphabet[marker0]; - - decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); - decodedData[encodedIndex + 1] = - (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); - } - encodedIndex += 3; - } - return decodedData; - } - - /** - * Check octect wheter it is a base64 encoding. - * - * @param octect to be checked byte - * @return ture if it is base64 encoding, false otherwise. - */ - private static boolean isBase64(byte octect) { - if (octect == PAD) { - return true; - } else if (base64Alphabet[octect] == -1) { - return false; - } else { - return true; - } - } - - /** - * Discards any characters outside of the base64 alphabet, per - * the requirements on page 25 of RFC 2045 - "Any characters - * outside of the base64 alphabet are to be ignored in base64 - * encoded data." - * - * @param data The base-64 encoded data to groom - * @return The data, less non-base64 characters (see RFC 2045). - */ - static byte[] discardNonBase64(byte[] data) { - byte groomedData[] = new byte[data.length]; - int bytesCopied = 0; - - for (int i = 0; i < data.length; i++) { - if (isBase64(data[i])) { - groomedData[bytesCopied++] = data[i]; - } - } - - byte packedData[] = new byte[bytesCopied]; - - System.arraycopy(groomedData, 0, packedData, 0, bytesCopied); - - return packedData; - } -} diff --git a/core/java/com/google/android/mms/pdu/CharacterSets.java b/core/java/com/google/android/mms/pdu/CharacterSets.java deleted file mode 100644 index 4e22ca5..0000000 --- a/core/java/com/google/android/mms/pdu/CharacterSets.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (C) 2007 Esmertec AG. - * Copyright (C) 2007 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.mms.pdu; - -import java.io.UnsupportedEncodingException; -import java.util.HashMap; - -public class CharacterSets { - /** - * IANA assigned MIB enum numbers. - * - * From wap-230-wsp-20010705-a.pdf - * Any-charset = <Octet 128> - * Equivalent to the special RFC2616 charset value "*" - */ - public static final int ANY_CHARSET = 0x00; - public static final int US_ASCII = 0x03; - public static final int ISO_8859_1 = 0x04; - public static final int ISO_8859_2 = 0x05; - public static final int ISO_8859_3 = 0x06; - public static final int ISO_8859_4 = 0x07; - public static final int ISO_8859_5 = 0x08; - public static final int ISO_8859_6 = 0x09; - public static final int ISO_8859_7 = 0x0A; - public static final int ISO_8859_8 = 0x0B; - public static final int ISO_8859_9 = 0x0C; - public static final int SHIFT_JIS = 0x11; - public static final int UTF_8 = 0x6A; - public static final int BIG5 = 0x07EA; - public static final int UCS2 = 0x03E8; - public static final int UTF_16 = 0x03F7; - - /** - * If the encoding of given data is unsupported, use UTF_8 to decode it. - */ - public static final int DEFAULT_CHARSET = UTF_8; - - /** - * Array of MIB enum numbers. - */ - private static final int[] MIBENUM_NUMBERS = { - ANY_CHARSET, - US_ASCII, - ISO_8859_1, - ISO_8859_2, - ISO_8859_3, - ISO_8859_4, - ISO_8859_5, - ISO_8859_6, - ISO_8859_7, - ISO_8859_8, - ISO_8859_9, - SHIFT_JIS, - UTF_8, - BIG5, - UCS2, - UTF_16, - }; - - /** - * The Well-known-charset Mime name. - */ - public static final String MIMENAME_ANY_CHARSET = "*"; - public static final String MIMENAME_US_ASCII = "us-ascii"; - public static final String MIMENAME_ISO_8859_1 = "iso-8859-1"; - public static final String MIMENAME_ISO_8859_2 = "iso-8859-2"; - public static final String MIMENAME_ISO_8859_3 = "iso-8859-3"; - public static final String MIMENAME_ISO_8859_4 = "iso-8859-4"; - public static final String MIMENAME_ISO_8859_5 = "iso-8859-5"; - public static final String MIMENAME_ISO_8859_6 = "iso-8859-6"; - public static final String MIMENAME_ISO_8859_7 = "iso-8859-7"; - public static final String MIMENAME_ISO_8859_8 = "iso-8859-8"; - public static final String MIMENAME_ISO_8859_9 = "iso-8859-9"; - public static final String MIMENAME_SHIFT_JIS = "shift_JIS"; - public static final String MIMENAME_UTF_8 = "utf-8"; - public static final String MIMENAME_BIG5 = "big5"; - public static final String MIMENAME_UCS2 = "iso-10646-ucs-2"; - public static final String MIMENAME_UTF_16 = "utf-16"; - - public static final String DEFAULT_CHARSET_NAME = MIMENAME_UTF_8; - - /** - * Array of the names of character sets. - */ - private static final String[] MIME_NAMES = { - MIMENAME_ANY_CHARSET, - MIMENAME_US_ASCII, - MIMENAME_ISO_8859_1, - MIMENAME_ISO_8859_2, - MIMENAME_ISO_8859_3, - MIMENAME_ISO_8859_4, - MIMENAME_ISO_8859_5, - MIMENAME_ISO_8859_6, - MIMENAME_ISO_8859_7, - MIMENAME_ISO_8859_8, - MIMENAME_ISO_8859_9, - MIMENAME_SHIFT_JIS, - MIMENAME_UTF_8, - MIMENAME_BIG5, - MIMENAME_UCS2, - MIMENAME_UTF_16, - }; - - private static final HashMap<Integer, String> MIBENUM_TO_NAME_MAP; - private static final HashMap<String, Integer> NAME_TO_MIBENUM_MAP; - - static { - // Create the HashMaps. - MIBENUM_TO_NAME_MAP = new HashMap<Integer, String>(); - NAME_TO_MIBENUM_MAP = new HashMap<String, Integer>(); - assert(MIBENUM_NUMBERS.length == MIME_NAMES.length); - int count = MIBENUM_NUMBERS.length - 1; - for(int i = 0; i <= count; i++) { - MIBENUM_TO_NAME_MAP.put(MIBENUM_NUMBERS[i], MIME_NAMES[i]); - NAME_TO_MIBENUM_MAP.put(MIME_NAMES[i], MIBENUM_NUMBERS[i]); - } - } - - private CharacterSets() {} // Non-instantiatable - - /** - * Map an MIBEnum number to the name of the charset which this number - * is assigned to by IANA. - * - * @param mibEnumValue An IANA assigned MIBEnum number. - * @return The name string of the charset. - * @throws UnsupportedEncodingException - */ - public static String getMimeName(int mibEnumValue) - throws UnsupportedEncodingException { - String name = MIBENUM_TO_NAME_MAP.get(mibEnumValue); - if (name == null) { - throw new UnsupportedEncodingException(); - } - return name; - } - - /** - * Map a well-known charset name to its assigned MIBEnum number. - * - * @param mimeName The charset name. - * @return The MIBEnum number assigned by IANA for this charset. - * @throws UnsupportedEncodingException - */ - public static int getMibEnumValue(String mimeName) - throws UnsupportedEncodingException { - if(null == mimeName) { - return -1; - } - - Integer mibEnumValue = NAME_TO_MIBENUM_MAP.get(mimeName); - if (mibEnumValue == null) { - throw new UnsupportedEncodingException(); - } - return mibEnumValue; - } -} diff --git a/core/java/com/google/android/mms/pdu/DeliveryInd.java b/core/java/com/google/android/mms/pdu/DeliveryInd.java deleted file mode 100644 index dafa8d1..0000000 --- a/core/java/com/google/android/mms/pdu/DeliveryInd.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (C) 2007 Esmertec AG. - * Copyright (C) 2007 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.mms.pdu; - -import com.google.android.mms.InvalidHeaderValueException; - -/** - * M-Delivery.Ind Pdu. - */ -public class DeliveryInd extends GenericPdu { - /** - * Empty constructor. - * Since the Pdu corresponding to this class is constructed - * by the Proxy-Relay server, this class is only instantiated - * by the Pdu Parser. - * - * @throws InvalidHeaderValueException if error occurs. - */ - public DeliveryInd() throws InvalidHeaderValueException { - super(); - setMessageType(PduHeaders.MESSAGE_TYPE_DELIVERY_IND); - } - - /** - * Constructor with given headers. - * - * @param headers Headers for this PDU. - */ - DeliveryInd(PduHeaders headers) { - super(headers); - } - - /** - * Get Date value. - * - * @return the value - */ - public long getDate() { - return mPduHeaders.getLongInteger(PduHeaders.DATE); - } - - /** - * Set Date value. - * - * @param value the value - */ - public void setDate(long value) { - mPduHeaders.setLongInteger(value, PduHeaders.DATE); - } - - /** - * Get Message-ID value. - * - * @return the value - */ - public byte[] getMessageId() { - return mPduHeaders.getTextString(PduHeaders.MESSAGE_ID); - } - - /** - * Set Message-ID value. - * - * @param value the value, should not be null - * @throws NullPointerException if the value is null. - */ - public void setMessageId(byte[] value) { - mPduHeaders.setTextString(value, PduHeaders.MESSAGE_ID); - } - - /** - * Get Status value. - * - * @return the value - */ - public int getStatus() { - return mPduHeaders.getOctet(PduHeaders.STATUS); - } - - /** - * Set Status value. - * - * @param value the value - * @throws InvalidHeaderValueException if the value is invalid. - */ - public void setStatus(int value) throws InvalidHeaderValueException { - mPduHeaders.setOctet(value, PduHeaders.STATUS); - } - - /** - * Get To value. - * - * @return the value - */ - public EncodedStringValue[] getTo() { - return mPduHeaders.getEncodedStringValues(PduHeaders.TO); - } - - /** - * set To value. - * - * @param value the value - * @throws NullPointerException if the value is null. - */ - public void setTo(EncodedStringValue[] value) { - mPduHeaders.setEncodedStringValues(value, PduHeaders.TO); - } - - /* - * Optional, not supported header fields: - * - * public byte[] getApplicId() {return null;} - * public void setApplicId(byte[] value) {} - * - * public byte[] getAuxApplicId() {return null;} - * public void getAuxApplicId(byte[] value) {} - * - * public byte[] getReplyApplicId() {return 0x00;} - * public void setReplyApplicId(byte[] value) {} - * - * public EncodedStringValue getStatusText() {return null;} - * public void setStatusText(EncodedStringValue value) {} - */ -} diff --git a/core/java/com/google/android/mms/pdu/EncodedStringValue.java b/core/java/com/google/android/mms/pdu/EncodedStringValue.java deleted file mode 100644 index 9495c1c..0000000 --- a/core/java/com/google/android/mms/pdu/EncodedStringValue.java +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright (C) 2007-2008 Esmertec AG. - * Copyright (C) 2007-2008 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.mms.pdu; - -import android.util.Log; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.util.ArrayList; - -/** - * Encoded-string-value = Text-string | Value-length Char-set Text-string - */ -public class EncodedStringValue implements Cloneable { - private static final String TAG = "EncodedStringValue"; - private static final boolean DEBUG = false; - private static final boolean LOCAL_LOGV = false; - - /** - * The Char-set value. - */ - private int mCharacterSet; - - /** - * The Text-string value. - */ - private byte[] mData; - - /** - * Constructor. - * - * @param charset the Char-set value - * @param data the Text-string value - * @throws NullPointerException if Text-string value is null. - */ - public EncodedStringValue(int charset, byte[] data) { - // TODO: CharSet needs to be validated against MIBEnum. - if(null == data) { - throw new NullPointerException("EncodedStringValue: Text-string is null."); - } - - mCharacterSet = charset; - mData = new byte[data.length]; - System.arraycopy(data, 0, mData, 0, data.length); - } - - /** - * Constructor. - * - * @param data the Text-string value - * @throws NullPointerException if Text-string value is null. - */ - public EncodedStringValue(byte[] data) { - this(CharacterSets.DEFAULT_CHARSET, data); - } - - public EncodedStringValue(String data) { - try { - mData = data.getBytes(CharacterSets.DEFAULT_CHARSET_NAME); - mCharacterSet = CharacterSets.DEFAULT_CHARSET; - } catch (UnsupportedEncodingException e) { - Log.e(TAG, "Default encoding must be supported.", e); - } - } - - /** - * Get Char-set value. - * - * @return the value - */ - public int getCharacterSet() { - return mCharacterSet; - } - - /** - * Set Char-set value. - * - * @param charset the Char-set value - */ - public void setCharacterSet(int charset) { - // TODO: CharSet needs to be validated against MIBEnum. - mCharacterSet = charset; - } - - /** - * Get Text-string value. - * - * @return the value - */ - public byte[] getTextString() { - byte[] byteArray = new byte[mData.length]; - - System.arraycopy(mData, 0, byteArray, 0, mData.length); - return byteArray; - } - - /** - * Set Text-string value. - * - * @param textString the Text-string value - * @throws NullPointerException if Text-string value is null. - */ - public void setTextString(byte[] textString) { - if(null == textString) { - throw new NullPointerException("EncodedStringValue: Text-string is null."); - } - - mData = new byte[textString.length]; - System.arraycopy(textString, 0, mData, 0, textString.length); - } - - /** - * Convert this object to a {@link java.lang.String}. If the encoding of - * the EncodedStringValue is null or unsupported, it will be - * treated as iso-8859-1 encoding. - * - * @return The decoded String. - */ - public String getString() { - if (CharacterSets.ANY_CHARSET == mCharacterSet) { - return new String(mData); // system default encoding. - } else { - try { - String name = CharacterSets.getMimeName(mCharacterSet); - return new String(mData, name); - } catch (UnsupportedEncodingException e) { - if (LOCAL_LOGV) { - Log.v(TAG, e.getMessage(), e); - } - try { - return new String(mData, CharacterSets.MIMENAME_ISO_8859_1); - } catch (UnsupportedEncodingException _) { - return new String(mData); // system default encoding. - } - } - } - } - - /** - * Append to Text-string. - * - * @param textString the textString to append - * @throws NullPointerException if the text String is null - * or an IOException occured. - */ - public void appendTextString(byte[] textString) { - if(null == textString) { - throw new NullPointerException("Text-string is null."); - } - - if(null == mData) { - mData = new byte[textString.length]; - System.arraycopy(textString, 0, mData, 0, textString.length); - } else { - ByteArrayOutputStream newTextString = new ByteArrayOutputStream(); - try { - newTextString.write(mData); - newTextString.write(textString); - } catch (IOException e) { - e.printStackTrace(); - throw new NullPointerException( - "appendTextString: failed when write a new Text-string"); - } - - mData = newTextString.toByteArray(); - } - } - - /* - * (non-Javadoc) - * @see java.lang.Object#clone() - */ - @Override - public Object clone() throws CloneNotSupportedException { - super.clone(); - int len = mData.length; - byte[] dstBytes = new byte[len]; - System.arraycopy(mData, 0, dstBytes, 0, len); - - try { - return new EncodedStringValue(mCharacterSet, dstBytes); - } catch (Exception e) { - Log.e(TAG, "failed to clone an EncodedStringValue: " + this); - e.printStackTrace(); - throw new CloneNotSupportedException(e.getMessage()); - } - } - - /** - * Split this encoded string around matches of the given pattern. - * - * @param pattern the delimiting pattern - * @return the array of encoded strings computed by splitting this encoded - * string around matches of the given pattern - */ - public EncodedStringValue[] split(String pattern) { - String[] temp = getString().split(pattern); - EncodedStringValue[] ret = new EncodedStringValue[temp.length]; - for (int i = 0; i < ret.length; ++i) { - try { - ret[i] = new EncodedStringValue(mCharacterSet, - temp[i].getBytes()); - } catch (NullPointerException _) { - // Can't arrive here - return null; - } - } - return ret; - } - - /** - * Extract an EncodedStringValue[] from a given String. - */ - public static EncodedStringValue[] extract(String src) { - String[] values = src.split(";"); - - ArrayList<EncodedStringValue> list = new ArrayList<EncodedStringValue>(); - for (int i = 0; i < values.length; i++) { - if (values[i].length() > 0) { - list.add(new EncodedStringValue(values[i])); - } - } - - int len = list.size(); - if (len > 0) { - return list.toArray(new EncodedStringValue[len]); - } else { - return null; - } - } - - /** - * Concatenate an EncodedStringValue[] into a single String. - */ - public static String concat(EncodedStringValue[] addr) { - StringBuilder sb = new StringBuilder(); - int maxIndex = addr.length - 1; - for (int i = 0; i <= maxIndex; i++) { - sb.append(addr[i].getString()); - if (i < maxIndex) { - sb.append(";"); - } - } - - return sb.toString(); - } - - public static EncodedStringValue copy(EncodedStringValue value) { - if (value == null) { - return null; - } - - return new EncodedStringValue(value.mCharacterSet, value.mData); - } - - public static EncodedStringValue[] encodeStrings(String[] array) { - int count = array.length; - if (count > 0) { - EncodedStringValue[] encodedArray = new EncodedStringValue[count]; - for (int i = 0; i < count; i++) { - encodedArray[i] = new EncodedStringValue(array[i]); - } - return encodedArray; - } - return null; - } -} diff --git a/core/java/com/google/android/mms/pdu/GenericPdu.java b/core/java/com/google/android/mms/pdu/GenericPdu.java deleted file mode 100644 index 705de6a..0000000 --- a/core/java/com/google/android/mms/pdu/GenericPdu.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2007 Esmertec AG. - * Copyright (C) 2007 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.mms.pdu; - -import com.google.android.mms.InvalidHeaderValueException; - -public class GenericPdu { - /** - * The headers of pdu. - */ - PduHeaders mPduHeaders = null; - - /** - * Constructor. - */ - public GenericPdu() { - mPduHeaders = new PduHeaders(); - } - - /** - * Constructor. - * - * @param headers Headers for this PDU. - */ - GenericPdu(PduHeaders headers) { - mPduHeaders = headers; - } - - /** - * Get the headers of this PDU. - * - * @return A PduHeaders of this PDU. - */ - PduHeaders getPduHeaders() { - return mPduHeaders; - } - - /** - * Get X-Mms-Message-Type field value. - * - * @return the X-Mms-Report-Allowed value - */ - public int getMessageType() { - return mPduHeaders.getOctet(PduHeaders.MESSAGE_TYPE); - } - - /** - * Set X-Mms-Message-Type field value. - * - * @param value the value - * @throws InvalidHeaderValueException if the value is invalid. - * RuntimeException if field's value is not Octet. - */ - public void setMessageType(int value) throws InvalidHeaderValueException { - mPduHeaders.setOctet(value, PduHeaders.MESSAGE_TYPE); - } - - /** - * Get X-Mms-MMS-Version field value. - * - * @return the X-Mms-MMS-Version value - */ - public int getMmsVersion() { - return mPduHeaders.getOctet(PduHeaders.MMS_VERSION); - } - - /** - * Set X-Mms-MMS-Version field value. - * - * @param value the value - * @throws InvalidHeaderValueException if the value is invalid. - * RuntimeException if field's value is not Octet. - */ - public void setMmsVersion(int value) throws InvalidHeaderValueException { - mPduHeaders.setOctet(value, PduHeaders.MMS_VERSION); - } - - /** - * Get From value. - * From-value = Value-length - * (Address-present-token Encoded-string-value | Insert-address-token) - * - * @return the value - */ - public EncodedStringValue getFrom() { - return mPduHeaders.getEncodedStringValue(PduHeaders.FROM); - } - - /** - * Set From value. - * - * @param value the value - * @throws NullPointerException if the value is null. - */ - public void setFrom(EncodedStringValue value) { - mPduHeaders.setEncodedStringValue(value, PduHeaders.FROM); - } -} diff --git a/core/java/com/google/android/mms/pdu/MultimediaMessagePdu.java b/core/java/com/google/android/mms/pdu/MultimediaMessagePdu.java deleted file mode 100644 index 5a85e0e..0000000 --- a/core/java/com/google/android/mms/pdu/MultimediaMessagePdu.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (C) 2007 Esmertec AG. - * Copyright (C) 2007 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.mms.pdu; - -import com.google.android.mms.InvalidHeaderValueException; - -/** - * Multimedia message PDU. - */ -public class MultimediaMessagePdu extends GenericPdu{ - /** - * The body. - */ - private PduBody mMessageBody; - - /** - * Constructor. - */ - public MultimediaMessagePdu() { - super(); - } - - /** - * Constructor. - * - * @param header the header of this PDU - * @param body the body of this PDU - */ - public MultimediaMessagePdu(PduHeaders header, PduBody body) { - super(header); - mMessageBody = body; - } - - /** - * Constructor with given headers. - * - * @param headers Headers for this PDU. - */ - MultimediaMessagePdu(PduHeaders headers) { - super(headers); - } - - /** - * Get body of the PDU. - * - * @return the body - */ - public PduBody getBody() { - return mMessageBody; - } - - /** - * Set body of the PDU. - * - * @param body the body - */ - public void setBody(PduBody body) { - mMessageBody = body; - } - - /** - * Get subject. - * - * @return the value - */ - public EncodedStringValue getSubject() { - return mPduHeaders.getEncodedStringValue(PduHeaders.SUBJECT); - } - - /** - * Set subject. - * - * @param value the value - * @throws NullPointerException if the value is null. - */ - public void setSubject(EncodedStringValue value) { - mPduHeaders.setEncodedStringValue(value, PduHeaders.SUBJECT); - } - - /** - * Get To value. - * - * @return the value - */ - public EncodedStringValue[] getTo() { - return mPduHeaders.getEncodedStringValues(PduHeaders.TO); - } - - /** - * Add a "To" value. - * - * @param value the value - * @throws NullPointerException if the value is null. - */ - public void addTo(EncodedStringValue value) { - mPduHeaders.appendEncodedStringValue(value, PduHeaders.TO); - } - - /** - * Get X-Mms-Priority value. - * - * @return the value - */ - public int getPriority() { - return mPduHeaders.getOctet(PduHeaders.PRIORITY); - } - - /** - * Set X-Mms-Priority value. - * - * @param value the value - * @throws InvalidHeaderValueException if the value is invalid. - */ - public void setPriority(int value) throws InvalidHeaderValueException { - mPduHeaders.setOctet(value, PduHeaders.PRIORITY); - } - - /** - * Get Date value. - * - * @return the value - */ - public long getDate() { - return mPduHeaders.getLongInteger(PduHeaders.DATE); - } - - /** - * Set Date value in seconds. - * - * @param value the value - */ - public void setDate(long value) { - mPduHeaders.setLongInteger(value, PduHeaders.DATE); - } -} diff --git a/core/java/com/google/android/mms/pdu/NotificationInd.java b/core/java/com/google/android/mms/pdu/NotificationInd.java deleted file mode 100644 index c56cba6..0000000 --- a/core/java/com/google/android/mms/pdu/NotificationInd.java +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Copyright (C) 2007 Esmertec AG. - * Copyright (C) 2007 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.mms.pdu; - -import com.google.android.mms.InvalidHeaderValueException; - -/** - * M-Notification.ind PDU. - */ -public class NotificationInd extends GenericPdu { - /** - * Empty constructor. - * Since the Pdu corresponding to this class is constructed - * by the Proxy-Relay server, this class is only instantiated - * by the Pdu Parser. - * - * @throws InvalidHeaderValueException if error occurs. - * RuntimeException if an undeclared error occurs. - */ - public NotificationInd() throws InvalidHeaderValueException { - super(); - setMessageType(PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND); - } - - /** - * Constructor with given headers. - * - * @param headers Headers for this PDU. - */ - NotificationInd(PduHeaders headers) { - super(headers); - } - - /** - * Get X-Mms-Content-Class Value. - * - * @return the value - */ - public int getContentClass() { - return mPduHeaders.getOctet(PduHeaders.CONTENT_CLASS); - } - - /** - * Set X-Mms-Content-Class Value. - * - * @param value the value - * @throws InvalidHeaderValueException if the value is invalid. - * RuntimeException if an undeclared error occurs. - */ - public void setContentClass(int value) throws InvalidHeaderValueException { - mPduHeaders.setOctet(value, PduHeaders.CONTENT_CLASS); - } - - /** - * Get X-Mms-Content-Location value. - * When used in a PDU other than M-Mbox-Delete.conf and M-Delete.conf: - * Content-location-value = Uri-value - * - * @return the value - */ - public byte[] getContentLocation() { - return mPduHeaders.getTextString(PduHeaders.CONTENT_LOCATION); - } - - /** - * Set X-Mms-Content-Location value. - * - * @param value the value - * @throws NullPointerException if the value is null. - * RuntimeException if an undeclared error occurs. - */ - public void setContentLocation(byte[] value) { - mPduHeaders.setTextString(value, PduHeaders.CONTENT_LOCATION); - } - - /** - * Get X-Mms-Expiry value. - * - * Expiry-value = Value-length - * (Absolute-token Date-value | Relative-token Delta-seconds-value) - * - * @return the value - */ - public long getExpiry() { - return mPduHeaders.getLongInteger(PduHeaders.EXPIRY); - } - - /** - * Set X-Mms-Expiry value. - * - * @param value the value - * @throws RuntimeException if an undeclared error occurs. - */ - public void setExpiry(long value) { - mPduHeaders.setLongInteger(value, PduHeaders.EXPIRY); - } - - /** - * Get From value. - * From-value = Value-length - * (Address-present-token Encoded-string-value | Insert-address-token) - * - * @return the value - */ - public EncodedStringValue getFrom() { - return mPduHeaders.getEncodedStringValue(PduHeaders.FROM); - } - - /** - * Set From value. - * - * @param value the value - * @throws NullPointerException if the value is null. - * RuntimeException if an undeclared error occurs. - */ - public void setFrom(EncodedStringValue value) { - mPduHeaders.setEncodedStringValue(value, PduHeaders.FROM); - } - - /** - * Get X-Mms-Message-Class value. - * Message-class-value = Class-identifier | Token-text - * Class-identifier = Personal | Advertisement | Informational | Auto - * - * @return the value - */ - public byte[] getMessageClass() { - return mPduHeaders.getTextString(PduHeaders.MESSAGE_CLASS); - } - - /** - * Set X-Mms-Message-Class value. - * - * @param value the value - * @throws NullPointerException if the value is null. - * RuntimeException if an undeclared error occurs. - */ - public void setMessageClass(byte[] value) { - mPduHeaders.setTextString(value, PduHeaders.MESSAGE_CLASS); - } - - /** - * Get X-Mms-Message-Size value. - * Message-size-value = Long-integer - * - * @return the value - */ - public long getMessageSize() { - return mPduHeaders.getLongInteger(PduHeaders.MESSAGE_SIZE); - } - - /** - * Set X-Mms-Message-Size value. - * - * @param value the value - * @throws RuntimeException if an undeclared error occurs. - */ - public void setMessageSize(long value) { - mPduHeaders.setLongInteger(value, PduHeaders.MESSAGE_SIZE); - } - - /** - * Get subject. - * - * @return the value - */ - public EncodedStringValue getSubject() { - return mPduHeaders.getEncodedStringValue(PduHeaders.SUBJECT); - } - - /** - * Set subject. - * - * @param value the value - * @throws NullPointerException if the value is null. - * RuntimeException if an undeclared error occurs. - */ - public void setSubject(EncodedStringValue value) { - mPduHeaders.setEncodedStringValue(value, PduHeaders.SUBJECT); - } - - /** - * Get X-Mms-Transaction-Id. - * - * @return the value - */ - public byte[] getTransactionId() { - return mPduHeaders.getTextString(PduHeaders.TRANSACTION_ID); - } - - /** - * Set X-Mms-Transaction-Id. - * - * @param value the value - * @throws NullPointerException if the value is null. - * RuntimeException if an undeclared error occurs. - */ - public void setTransactionId(byte[] value) { - mPduHeaders.setTextString(value, PduHeaders.TRANSACTION_ID); - } - - /** - * Get X-Mms-Delivery-Report Value. - * - * @return the value - */ - public int getDeliveryReport() { - return mPduHeaders.getOctet(PduHeaders.DELIVERY_REPORT); - } - - /** - * Set X-Mms-Delivery-Report Value. - * - * @param value the value - * @throws InvalidHeaderValueException if the value is invalid. - * RuntimeException if an undeclared error occurs. - */ - public void setDeliveryReport(int value) throws InvalidHeaderValueException { - mPduHeaders.setOctet(value, PduHeaders.DELIVERY_REPORT); - } - - /* - * Optional, not supported header fields: - * - * public byte[] getApplicId() {return null;} - * public void setApplicId(byte[] value) {} - * - * public byte[] getAuxApplicId() {return null;} - * public void getAuxApplicId(byte[] value) {} - * - * public byte getDrmContent() {return 0x00;} - * public void setDrmContent(byte value) {} - * - * public byte getDistributionIndicator() {return 0x00;} - * public void setDistributionIndicator(byte value) {} - * - * public ElementDescriptorValue getElementDescriptor() {return null;} - * public void getElementDescriptor(ElementDescriptorValue value) {} - * - * public byte getPriority() {return 0x00;} - * public void setPriority(byte value) {} - * - * public byte getRecommendedRetrievalMode() {return 0x00;} - * public void setRecommendedRetrievalMode(byte value) {} - * - * public byte getRecommendedRetrievalModeText() {return 0x00;} - * public void setRecommendedRetrievalModeText(byte value) {} - * - * public byte[] getReplaceId() {return 0x00;} - * public void setReplaceId(byte[] value) {} - * - * public byte[] getReplyApplicId() {return 0x00;} - * public void setReplyApplicId(byte[] value) {} - * - * public byte getReplyCharging() {return 0x00;} - * public void setReplyCharging(byte value) {} - * - * public byte getReplyChargingDeadline() {return 0x00;} - * public void setReplyChargingDeadline(byte value) {} - * - * public byte[] getReplyChargingId() {return 0x00;} - * public void setReplyChargingId(byte[] value) {} - * - * public long getReplyChargingSize() {return 0;} - * public void setReplyChargingSize(long value) {} - * - * public byte getStored() {return 0x00;} - * public void setStored(byte value) {} - */ -} diff --git a/core/java/com/google/android/mms/pdu/NotifyRespInd.java b/core/java/com/google/android/mms/pdu/NotifyRespInd.java deleted file mode 100644 index 2cc2fce..0000000 --- a/core/java/com/google/android/mms/pdu/NotifyRespInd.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2007 Esmertec AG. - * Copyright (C) 2007 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.mms.pdu; - -import com.google.android.mms.InvalidHeaderValueException; - -/** - * M-NofifyResp.ind PDU. - */ -public class NotifyRespInd extends GenericPdu { - /** - * Constructor, used when composing a M-NotifyResp.ind pdu. - * - * @param mmsVersion current version of mms - * @param transactionId the transaction-id value - * @param status the status value - * @throws InvalidHeaderValueException if parameters are invalid. - * NullPointerException if transactionId is null. - * RuntimeException if an undeclared error occurs. - */ - public NotifyRespInd(int mmsVersion, - byte[] transactionId, - int status) throws InvalidHeaderValueException { - super(); - setMessageType(PduHeaders.MESSAGE_TYPE_NOTIFYRESP_IND); - setMmsVersion(mmsVersion); - setTransactionId(transactionId); - setStatus(status); - } - - /** - * Constructor with given headers. - * - * @param headers Headers for this PDU. - */ - NotifyRespInd(PduHeaders headers) { - super(headers); - } - - /** - * Get X-Mms-Report-Allowed field value. - * - * @return the X-Mms-Report-Allowed value - */ - public int getReportAllowed() { - return mPduHeaders.getOctet(PduHeaders.REPORT_ALLOWED); - } - - /** - * Set X-Mms-Report-Allowed field value. - * - * @param value the value - * @throws InvalidHeaderValueException if the value is invalid. - * RuntimeException if an undeclared error occurs. - */ - public void setReportAllowed(int value) throws InvalidHeaderValueException { - mPduHeaders.setOctet(value, PduHeaders.REPORT_ALLOWED); - } - - /** - * Set X-Mms-Status field value. - * - * @param value the value - * @throws InvalidHeaderValueException if the value is invalid. - * RuntimeException if an undeclared error occurs. - */ - public void setStatus(int value) throws InvalidHeaderValueException { - mPduHeaders.setOctet(value, PduHeaders.STATUS); - } - - /** - * GetX-Mms-Status field value. - * - * @return the X-Mms-Status value - */ - public int getStatus() { - return mPduHeaders.getOctet(PduHeaders.STATUS); - } - - /** - * Get X-Mms-Transaction-Id field value. - * - * @return the X-Mms-Report-Allowed value - */ - public byte[] getTransactionId() { - return mPduHeaders.getTextString(PduHeaders.TRANSACTION_ID); - } - - /** - * Set X-Mms-Transaction-Id field value. - * - * @param value the value - * @throws NullPointerException if the value is null. - * RuntimeException if an undeclared error occurs. - */ - public void setTransactionId(byte[] value) { - mPduHeaders.setTextString(value, PduHeaders.TRANSACTION_ID); - } -} diff --git a/core/java/com/google/android/mms/pdu/PduBody.java b/core/java/com/google/android/mms/pdu/PduBody.java deleted file mode 100644 index fa0416c..0000000 --- a/core/java/com/google/android/mms/pdu/PduBody.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (C) 2007 Esmertec AG. - * Copyright (C) 2007 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.mms.pdu; - -import java.util.HashMap; -import java.util.Map; -import java.util.Vector; - -public class PduBody { - private Vector<PduPart> mParts = null; - - private Map<String, PduPart> mPartMapByContentId = null; - private Map<String, PduPart> mPartMapByContentLocation = null; - private Map<String, PduPart> mPartMapByName = null; - private Map<String, PduPart> mPartMapByFileName = null; - - /** - * Constructor. - */ - public PduBody() { - mParts = new Vector<PduPart>(); - - mPartMapByContentId = new HashMap<String, PduPart>(); - mPartMapByContentLocation = new HashMap<String, PduPart>(); - mPartMapByName = new HashMap<String, PduPart>(); - mPartMapByFileName = new HashMap<String, PduPart>(); - } - - private void putPartToMaps(PduPart part) { - // Put part to mPartMapByContentId. - byte[] contentId = part.getContentId(); - if(null != contentId) { - mPartMapByContentId.put(new String(contentId), part); - } - - // Put part to mPartMapByContentLocation. - byte[] contentLocation = part.getContentLocation(); - if(null != contentLocation) { - String clc = new String(contentLocation); - mPartMapByContentLocation.put(clc, part); - } - - // Put part to mPartMapByName. - byte[] name = part.getName(); - if(null != name) { - String clc = new String(name); - mPartMapByName.put(clc, part); - } - - // Put part to mPartMapByFileName. - byte[] fileName = part.getFilename(); - if(null != fileName) { - String clc = new String(fileName); - mPartMapByFileName.put(clc, part); - } - } - - /** - * Appends the specified part to the end of this body. - * - * @param part part to be appended - * @return true when success, false when fail - * @throws NullPointerException when part is null - */ - public boolean addPart(PduPart part) { - if(null == part) { - throw new NullPointerException(); - } - - putPartToMaps(part); - return mParts.add(part); - } - - /** - * Inserts the specified part at the specified position. - * - * @param index index at which the specified part is to be inserted - * @param part part to be inserted - * @throws NullPointerException when part is null - */ - public void addPart(int index, PduPart part) { - if(null == part) { - throw new NullPointerException(); - } - - putPartToMaps(part); - mParts.add(index, part); - } - - /** - * Removes the part at the specified position. - * - * @param index index of the part to return - * @return part at the specified index - */ - public PduPart removePart(int index) { - return mParts.remove(index); - } - - /** - * Remove all of the parts. - */ - public void removeAll() { - mParts.clear(); - } - - /** - * Get the part at the specified position. - * - * @param index index of the part to return - * @return part at the specified index - */ - public PduPart getPart(int index) { - return mParts.get(index); - } - - /** - * Get the index of the specified part. - * - * @param part the part object - * @return index the index of the first occurrence of the part in this body - */ - public int getPartIndex(PduPart part) { - return mParts.indexOf(part); - } - - /** - * Get the number of parts. - * - * @return the number of parts - */ - public int getPartsNum() { - return mParts.size(); - } - - /** - * Get pdu part by content id. - * - * @param cid the value of content id. - * @return the pdu part. - */ - public PduPart getPartByContentId(String cid) { - return mPartMapByContentId.get(cid); - } - - /** - * Get pdu part by Content-Location. Content-Location of part is - * the same as filename and name(param of content-type). - * - * @param fileName the value of filename. - * @return the pdu part. - */ - public PduPart getPartByContentLocation(String contentLocation) { - return mPartMapByContentLocation.get(contentLocation); - } - - /** - * Get pdu part by name. - * - * @param fileName the value of filename. - * @return the pdu part. - */ - public PduPart getPartByName(String name) { - return mPartMapByName.get(name); - } - - /** - * Get pdu part by filename. - * - * @param fileName the value of filename. - * @return the pdu part. - */ - public PduPart getPartByFileName(String filename) { - return mPartMapByFileName.get(filename); - } -} diff --git a/core/java/com/google/android/mms/pdu/PduComposer.java b/core/java/com/google/android/mms/pdu/PduComposer.java deleted file mode 100644 index d426f89..0000000 --- a/core/java/com/google/android/mms/pdu/PduComposer.java +++ /dev/null @@ -1,1179 +0,0 @@ -/* - * Copyright (C) 2007-2008 Esmertec AG. - * Copyright (C) 2007-2008 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.mms.pdu; - -import android.content.ContentResolver; -import android.content.Context; -import android.util.Log; -import android.text.TextUtils; - -import java.io.ByteArrayOutputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; -import java.util.HashMap; - -public class PduComposer { - /** - * Address type. - */ - static private final int PDU_PHONE_NUMBER_ADDRESS_TYPE = 1; - static private final int PDU_EMAIL_ADDRESS_TYPE = 2; - static private final int PDU_IPV4_ADDRESS_TYPE = 3; - static private final int PDU_IPV6_ADDRESS_TYPE = 4; - static private final int PDU_UNKNOWN_ADDRESS_TYPE = 5; - - /** - * Address regular expression string. - */ - static final String REGEXP_PHONE_NUMBER_ADDRESS_TYPE = "\\+?[0-9|\\.|\\-]+"; - static final String REGEXP_EMAIL_ADDRESS_TYPE = "[a-zA-Z| ]*\\<{0,1}[a-zA-Z| ]+@{1}" + - "[a-zA-Z| ]+\\.{1}[a-zA-Z| ]+\\>{0,1}"; - static final String REGEXP_IPV6_ADDRESS_TYPE = - "[a-fA-F]{4}\\:{1}[a-fA-F0-9]{4}\\:{1}[a-fA-F0-9]{4}\\:{1}" + - "[a-fA-F0-9]{4}\\:{1}[a-fA-F0-9]{4}\\:{1}[a-fA-F0-9]{4}\\:{1}" + - "[a-fA-F0-9]{4}\\:{1}[a-fA-F0-9]{4}"; - static final String REGEXP_IPV4_ADDRESS_TYPE = "[0-9]{1,3}\\.{1}[0-9]{1,3}\\.{1}" + - "[0-9]{1,3}\\.{1}[0-9]{1,3}"; - - /** - * The postfix strings of address. - */ - static final String STRING_PHONE_NUMBER_ADDRESS_TYPE = "/TYPE=PLMN"; - static final String STRING_IPV4_ADDRESS_TYPE = "/TYPE=IPV4"; - static final String STRING_IPV6_ADDRESS_TYPE = "/TYPE=IPV6"; - - /** - * Error values. - */ - static private final int PDU_COMPOSE_SUCCESS = 0; - static private final int PDU_COMPOSE_CONTENT_ERROR = 1; - static private final int PDU_COMPOSE_FIELD_NOT_SET = 2; - static private final int PDU_COMPOSE_FIELD_NOT_SUPPORTED = 3; - - /** - * WAP values defined in WSP spec. - */ - static private final int QUOTED_STRING_FLAG = 34; - static private final int END_STRING_FLAG = 0; - static private final int LENGTH_QUOTE = 31; - static private final int TEXT_MAX = 127; - static private final int SHORT_INTEGER_MAX = 127; - static private final int LONG_INTEGER_LENGTH_MAX = 8; - - /** - * Block size when read data from InputStream. - */ - static private final int PDU_COMPOSER_BLOCK_SIZE = 1024; - - /** - * The output message. - */ - protected ByteArrayOutputStream mMessage = null; - - /** - * The PDU. - */ - private GenericPdu mPdu = null; - - /** - * Current visiting position of the mMessage. - */ - protected int mPosition = 0; - - /** - * Message compose buffer stack. - */ - private BufferStack mStack = null; - - /** - * Content resolver. - */ - private final ContentResolver mResolver; - - /** - * Header of this pdu. - */ - private PduHeaders mPduHeader = null; - - /** - * Map of all content type - */ - private static HashMap<String, Integer> mContentTypeMap = null; - - static { - mContentTypeMap = new HashMap<String, Integer>(); - - int i; - for (i = 0; i < PduContentTypes.contentTypes.length; i++) { - mContentTypeMap.put(PduContentTypes.contentTypes[i], i); - } - } - - /** - * Constructor. - * - * @param context the context - * @param pdu the pdu to be composed - */ - public PduComposer(Context context, GenericPdu pdu) { - mPdu = pdu; - mResolver = context.getContentResolver(); - mPduHeader = pdu.getPduHeaders(); - mStack = new BufferStack(); - mMessage = new ByteArrayOutputStream(); - mPosition = 0; - } - - /** - * Make the message. No need to check whether mandatory fields are set, - * because the constructors of outgoing pdus are taking care of this. - * - * @return OutputStream of maked message. Return null if - * the PDU is invalid. - */ - public byte[] make() { - // Get Message-type. - int type = mPdu.getMessageType(); - - /* make the message */ - switch (type) { - case PduHeaders.MESSAGE_TYPE_SEND_REQ: - if (makeSendReqPdu() != PDU_COMPOSE_SUCCESS) { - return null; - } - break; - case PduHeaders.MESSAGE_TYPE_NOTIFYRESP_IND: - if (makeNotifyResp() != PDU_COMPOSE_SUCCESS) { - return null; - } - break; - case PduHeaders.MESSAGE_TYPE_ACKNOWLEDGE_IND: - if (makeAckInd() != PDU_COMPOSE_SUCCESS) { - return null; - } - break; - case PduHeaders.MESSAGE_TYPE_READ_REC_IND: - if (makeReadRecInd() != PDU_COMPOSE_SUCCESS) { - return null; - } - break; - default: - return null; - } - - return mMessage.toByteArray(); - } - - /** - * Copy buf to mMessage. - */ - protected void arraycopy(byte[] buf, int pos, int length) { - mMessage.write(buf, pos, length); - mPosition = mPosition + length; - } - - /** - * Append a byte to mMessage. - */ - protected void append(int value) { - mMessage.write(value); - mPosition ++; - } - - /** - * Append short integer value to mMessage. - * This implementation doesn't check the validity of parameter, since it - * assumes that the values are validated in the GenericPdu setter methods. - */ - protected void appendShortInteger(int value) { - /* - * From WAP-230-WSP-20010705-a: - * Short-integer = OCTET - * ; Integers in range 0-127 shall be encoded as a one octet value - * ; with the most significant bit set to one (1xxx xxxx) and with - * ; the value in the remaining least significant bits. - * In our implementation, only low 7 bits are stored and otherwise - * bits are ignored. - */ - append((value | 0x80) & 0xff); - } - - /** - * Append an octet number between 128 and 255 into mMessage. - * NOTE: - * A value between 0 and 127 should be appended by using appendShortInteger. - * This implementation doesn't check the validity of parameter, since it - * assumes that the values are validated in the GenericPdu setter methods. - */ - protected void appendOctet(int number) { - append(number); - } - - /** - * Append a short length into mMessage. - * This implementation doesn't check the validity of parameter, since it - * assumes that the values are validated in the GenericPdu setter methods. - */ - protected void appendShortLength(int value) { - /* - * From WAP-230-WSP-20010705-a: - * Short-length = <Any octet 0-30> - */ - append(value); - } - - /** - * Append long integer into mMessage. it's used for really long integers. - * This implementation doesn't check the validity of parameter, since it - * assumes that the values are validated in the GenericPdu setter methods. - */ - protected void appendLongInteger(long longInt) { - /* - * From WAP-230-WSP-20010705-a: - * Long-integer = Short-length Multi-octet-integer - * ; The Short-length indicates the length of the Multi-octet-integer - * Multi-octet-integer = 1*30 OCTET - * ; The content octets shall be an unsigned integer value with the - * ; most significant octet encoded first (big-endian representation). - * ; The minimum number of octets must be used to encode the value. - */ - int size; - long temp = longInt; - - // Count the length of the long integer. - for(size = 0; (temp != 0) && (size < LONG_INTEGER_LENGTH_MAX); size++) { - temp = (temp >>> 8); - } - - // Set Length. - appendShortLength(size); - - // Count and set the long integer. - int i; - int shift = (size -1) * 8; - - for (i = 0; i < size; i++) { - append((int)((longInt >>> shift) & 0xff)); - shift = shift - 8; - } - } - - /** - * Append text string into mMessage. - * This implementation doesn't check the validity of parameter, since it - * assumes that the values are validated in the GenericPdu setter methods. - */ - protected void appendTextString(byte[] text) { - /* - * From WAP-230-WSP-20010705-a: - * Text-string = [Quote] *TEXT End-of-string - * ; If the first character in the TEXT is in the range of 128-255, - * ; a Quote character must precede it. Otherwise the Quote character - * ;must be omitted. The Quote is not part of the contents. - */ - if (((text[0])&0xff) > TEXT_MAX) { // No need to check for <= 255 - append(TEXT_MAX); - } - - arraycopy(text, 0, text.length); - append(0); - } - - /** - * Append text string into mMessage. - * This implementation doesn't check the validity of parameter, since it - * assumes that the values are validated in the GenericPdu setter methods. - */ - protected void appendTextString(String str) { - /* - * From WAP-230-WSP-20010705-a: - * Text-string = [Quote] *TEXT End-of-string - * ; If the first character in the TEXT is in the range of 128-255, - * ; a Quote character must precede it. Otherwise the Quote character - * ;must be omitted. The Quote is not part of the contents. - */ - appendTextString(str.getBytes()); - } - - /** - * Append encoded string value to mMessage. - * This implementation doesn't check the validity of parameter, since it - * assumes that the values are validated in the GenericPdu setter methods. - */ - protected void appendEncodedString(EncodedStringValue enStr) { - /* - * From OMA-TS-MMS-ENC-V1_3-20050927-C: - * Encoded-string-value = Text-string | Value-length Char-set Text-string - */ - assert(enStr != null); - - int charset = enStr.getCharacterSet(); - byte[] textString = enStr.getTextString(); - if (null == textString) { - return; - } - - /* - * In the implementation of EncodedStringValue, the charset field will - * never be 0. It will always be composed as - * Encoded-string-value = Value-length Char-set Text-string - */ - mStack.newbuf(); - PositionMarker start = mStack.mark(); - - appendShortInteger(charset); - appendTextString(textString); - - int len = start.getLength(); - mStack.pop(); - appendValueLength(len); - mStack.copy(); - } - - /** - * Append uintvar integer into mMessage. - * This implementation doesn't check the validity of parameter, since it - * assumes that the values are validated in the GenericPdu setter methods. - */ - protected void appendUintvarInteger(long value) { - /* - * From WAP-230-WSP-20010705-a: - * To encode a large unsigned integer, split it into 7-bit fragments - * and place them in the payloads of multiple octets. The most significant - * bits are placed in the first octets with the least significant bits - * ending up in the last octet. All octets MUST set the Continue bit to 1 - * except the last octet, which MUST set the Continue bit to 0. - */ - int i; - long max = SHORT_INTEGER_MAX; - - for (i = 0; i < 5; i++) { - if (value < max) { - break; - } - - max = (max << 7) | 0x7fl; - } - - while(i > 0) { - long temp = value >>> (i * 7); - temp = temp & 0x7f; - - append((int)((temp | 0x80) & 0xff)); - - i--; - } - - append((int)(value & 0x7f)); - } - - /** - * Append date value into mMessage. - * This implementation doesn't check the validity of parameter, since it - * assumes that the values are validated in the GenericPdu setter methods. - */ - protected void appendDateValue(long date) { - /* - * From OMA-TS-MMS-ENC-V1_3-20050927-C: - * Date-value = Long-integer - */ - appendLongInteger(date); - } - - /** - * Append value length to mMessage. - * This implementation doesn't check the validity of parameter, since it - * assumes that the values are validated in the GenericPdu setter methods. - */ - protected void appendValueLength(long value) { - /* - * From WAP-230-WSP-20010705-a: - * Value-length = Short-length | (Length-quote Length) - * ; Value length is used to indicate the length of the value to follow - * Short-length = <Any octet 0-30> - * Length-quote = <Octet 31> - * Length = Uintvar-integer - */ - if (value < LENGTH_QUOTE) { - appendShortLength((int) value); - return; - } - - append(LENGTH_QUOTE); - appendUintvarInteger(value); - } - - /** - * Append quoted string to mMessage. - * This implementation doesn't check the validity of parameter, since it - * assumes that the values are validated in the GenericPdu setter methods. - */ - protected void appendQuotedString(byte[] text) { - /* - * From WAP-230-WSP-20010705-a: - * Quoted-string = <Octet 34> *TEXT End-of-string - * ;The TEXT encodes an RFC2616 Quoted-string with the enclosing - * ;quotation-marks <"> removed. - */ - append(QUOTED_STRING_FLAG); - arraycopy(text, 0, text.length); - append(END_STRING_FLAG); - } - - /** - * Append quoted string to mMessage. - * This implementation doesn't check the validity of parameter, since it - * assumes that the values are validated in the GenericPdu setter methods. - */ - protected void appendQuotedString(String str) { - /* - * From WAP-230-WSP-20010705-a: - * Quoted-string = <Octet 34> *TEXT End-of-string - * ;The TEXT encodes an RFC2616 Quoted-string with the enclosing - * ;quotation-marks <"> removed. - */ - appendQuotedString(str.getBytes()); - } - - private EncodedStringValue appendAddressType(EncodedStringValue address) { - EncodedStringValue temp = null; - - try { - int addressType = checkAddressType(address.getString()); - temp = EncodedStringValue.copy(address); - if (PDU_PHONE_NUMBER_ADDRESS_TYPE == addressType) { - // Phone number. - temp.appendTextString(STRING_PHONE_NUMBER_ADDRESS_TYPE.getBytes()); - } else if (PDU_IPV4_ADDRESS_TYPE == addressType) { - // Ipv4 address. - temp.appendTextString(STRING_IPV4_ADDRESS_TYPE.getBytes()); - } else if (PDU_IPV6_ADDRESS_TYPE == addressType) { - // Ipv6 address. - temp.appendTextString(STRING_IPV6_ADDRESS_TYPE.getBytes()); - } - } catch (NullPointerException e) { - return null; - } - - return temp; - } - - /** - * Append header to mMessage. - */ - private int appendHeader(int field) { - switch (field) { - case PduHeaders.MMS_VERSION: - appendOctet(field); - - int version = mPduHeader.getOctet(field); - if (0 == version) { - appendShortInteger(PduHeaders.CURRENT_MMS_VERSION); - } else { - appendShortInteger(version); - } - - break; - - case PduHeaders.MESSAGE_ID: - case PduHeaders.TRANSACTION_ID: - byte[] textString = mPduHeader.getTextString(field); - if (null == textString) { - return PDU_COMPOSE_FIELD_NOT_SET; - } - - appendOctet(field); - appendTextString(textString); - break; - - case PduHeaders.TO: - case PduHeaders.BCC: - case PduHeaders.CC: - EncodedStringValue[] addr = mPduHeader.getEncodedStringValues(field); - - if (null == addr) { - return PDU_COMPOSE_FIELD_NOT_SET; - } - - EncodedStringValue temp; - for (int i = 0; i < addr.length; i++) { - temp = appendAddressType(addr[i]); - if (temp == null) { - return PDU_COMPOSE_CONTENT_ERROR; - } - - appendOctet(field); - appendEncodedString(temp); - } - break; - - case PduHeaders.FROM: - // Value-length (Address-present-token Encoded-string-value | Insert-address-token) - appendOctet(field); - - EncodedStringValue from = mPduHeader.getEncodedStringValue(field); - if ((from == null) - || TextUtils.isEmpty(from.getString()) - || new String(from.getTextString()).equals( - PduHeaders.FROM_INSERT_ADDRESS_TOKEN_STR)) { - // Length of from = 1 - append(1); - // Insert-address-token = <Octet 129> - append(PduHeaders.FROM_INSERT_ADDRESS_TOKEN); - } else { - mStack.newbuf(); - PositionMarker fstart = mStack.mark(); - - // Address-present-token = <Octet 128> - append(PduHeaders.FROM_ADDRESS_PRESENT_TOKEN); - - temp = appendAddressType(from); - if (temp == null) { - return PDU_COMPOSE_CONTENT_ERROR; - } - - appendEncodedString(temp); - - int flen = fstart.getLength(); - mStack.pop(); - appendValueLength(flen); - mStack.copy(); - } - break; - - case PduHeaders.READ_STATUS: - case PduHeaders.STATUS: - case PduHeaders.REPORT_ALLOWED: - case PduHeaders.PRIORITY: - case PduHeaders.DELIVERY_REPORT: - case PduHeaders.READ_REPORT: - int octet = mPduHeader.getOctet(field); - if (0 == octet) { - return PDU_COMPOSE_FIELD_NOT_SET; - } - - appendOctet(field); - appendOctet(octet); - break; - - case PduHeaders.DATE: - long date = mPduHeader.getLongInteger(field); - if (-1 == date) { - return PDU_COMPOSE_FIELD_NOT_SET; - } - - appendOctet(field); - appendDateValue(date); - break; - - case PduHeaders.SUBJECT: - EncodedStringValue enString = - mPduHeader.getEncodedStringValue(field); - if (null == enString) { - return PDU_COMPOSE_FIELD_NOT_SET; - } - - appendOctet(field); - appendEncodedString(enString); - break; - - case PduHeaders.MESSAGE_CLASS: - byte[] messageClass = mPduHeader.getTextString(field); - if (null == messageClass) { - return PDU_COMPOSE_FIELD_NOT_SET; - } - - appendOctet(field); - if (Arrays.equals(messageClass, - PduHeaders.MESSAGE_CLASS_ADVERTISEMENT_STR.getBytes())) { - appendOctet(PduHeaders.MESSAGE_CLASS_ADVERTISEMENT); - } else if (Arrays.equals(messageClass, - PduHeaders.MESSAGE_CLASS_AUTO_STR.getBytes())) { - appendOctet(PduHeaders.MESSAGE_CLASS_AUTO); - } else if (Arrays.equals(messageClass, - PduHeaders.MESSAGE_CLASS_PERSONAL_STR.getBytes())) { - appendOctet(PduHeaders.MESSAGE_CLASS_PERSONAL); - } else if (Arrays.equals(messageClass, - PduHeaders.MESSAGE_CLASS_INFORMATIONAL_STR.getBytes())) { - appendOctet(PduHeaders.MESSAGE_CLASS_INFORMATIONAL); - } else { - appendTextString(messageClass); - } - break; - - case PduHeaders.EXPIRY: - long expiry = mPduHeader.getLongInteger(field); - if (-1 == expiry) { - return PDU_COMPOSE_FIELD_NOT_SET; - } - - appendOctet(field); - - mStack.newbuf(); - PositionMarker expiryStart = mStack.mark(); - - append(PduHeaders.VALUE_RELATIVE_TOKEN); - appendLongInteger(expiry); - - int expiryLength = expiryStart.getLength(); - mStack.pop(); - appendValueLength(expiryLength); - mStack.copy(); - break; - - default: - return PDU_COMPOSE_FIELD_NOT_SUPPORTED; - } - - return PDU_COMPOSE_SUCCESS; - } - - /** - * Make ReadRec.Ind. - */ - private int makeReadRecInd() { - if (mMessage == null) { - mMessage = new ByteArrayOutputStream(); - mPosition = 0; - } - - // X-Mms-Message-Type - appendOctet(PduHeaders.MESSAGE_TYPE); - appendOctet(PduHeaders.MESSAGE_TYPE_READ_REC_IND); - - // X-Mms-MMS-Version - if (appendHeader(PduHeaders.MMS_VERSION) != PDU_COMPOSE_SUCCESS) { - return PDU_COMPOSE_CONTENT_ERROR; - } - - // Message-ID - if (appendHeader(PduHeaders.MESSAGE_ID) != PDU_COMPOSE_SUCCESS) { - return PDU_COMPOSE_CONTENT_ERROR; - } - - // To - if (appendHeader(PduHeaders.TO) != PDU_COMPOSE_SUCCESS) { - return PDU_COMPOSE_CONTENT_ERROR; - } - - // From - if (appendHeader(PduHeaders.FROM) != PDU_COMPOSE_SUCCESS) { - return PDU_COMPOSE_CONTENT_ERROR; - } - - // Date Optional - appendHeader(PduHeaders.DATE); - - // X-Mms-Read-Status - if (appendHeader(PduHeaders.READ_STATUS) != PDU_COMPOSE_SUCCESS) { - return PDU_COMPOSE_CONTENT_ERROR; - } - - // X-Mms-Applic-ID Optional(not support) - // X-Mms-Reply-Applic-ID Optional(not support) - // X-Mms-Aux-Applic-Info Optional(not support) - - return PDU_COMPOSE_SUCCESS; - } - - /** - * Make NotifyResp.Ind. - */ - private int makeNotifyResp() { - if (mMessage == null) { - mMessage = new ByteArrayOutputStream(); - mPosition = 0; - } - - // X-Mms-Message-Type - appendOctet(PduHeaders.MESSAGE_TYPE); - appendOctet(PduHeaders.MESSAGE_TYPE_NOTIFYRESP_IND); - - // X-Mms-Transaction-ID - if (appendHeader(PduHeaders.TRANSACTION_ID) != PDU_COMPOSE_SUCCESS) { - return PDU_COMPOSE_CONTENT_ERROR; - } - - // X-Mms-MMS-Version - if (appendHeader(PduHeaders.MMS_VERSION) != PDU_COMPOSE_SUCCESS) { - return PDU_COMPOSE_CONTENT_ERROR; - } - - // X-Mms-Status - if (appendHeader(PduHeaders.STATUS) != PDU_COMPOSE_SUCCESS) { - return PDU_COMPOSE_CONTENT_ERROR; - } - - // X-Mms-Report-Allowed Optional (not support) - return PDU_COMPOSE_SUCCESS; - } - - /** - * Make Acknowledge.Ind. - */ - private int makeAckInd() { - if (mMessage == null) { - mMessage = new ByteArrayOutputStream(); - mPosition = 0; - } - - // X-Mms-Message-Type - appendOctet(PduHeaders.MESSAGE_TYPE); - appendOctet(PduHeaders.MESSAGE_TYPE_ACKNOWLEDGE_IND); - - // X-Mms-Transaction-ID - if (appendHeader(PduHeaders.TRANSACTION_ID) != PDU_COMPOSE_SUCCESS) { - return PDU_COMPOSE_CONTENT_ERROR; - } - - // X-Mms-MMS-Version - if (appendHeader(PduHeaders.MMS_VERSION) != PDU_COMPOSE_SUCCESS) { - return PDU_COMPOSE_CONTENT_ERROR; - } - - // X-Mms-Report-Allowed Optional - appendHeader(PduHeaders.REPORT_ALLOWED); - - return PDU_COMPOSE_SUCCESS; - } - - /** - * Make Send.req. - */ - private int makeSendReqPdu() { - if (mMessage == null) { - mMessage = new ByteArrayOutputStream(); - mPosition = 0; - } - - // X-Mms-Message-Type - appendOctet(PduHeaders.MESSAGE_TYPE); - appendOctet(PduHeaders.MESSAGE_TYPE_SEND_REQ); - - // X-Mms-Transaction-ID - appendOctet(PduHeaders.TRANSACTION_ID); - - byte[] trid = mPduHeader.getTextString(PduHeaders.TRANSACTION_ID); - if (trid == null) { - // Transaction-ID should be set(by Transaction) before make(). - throw new IllegalArgumentException("Transaction-ID is null."); - } - appendTextString(trid); - - // X-Mms-MMS-Version - if (appendHeader(PduHeaders.MMS_VERSION) != PDU_COMPOSE_SUCCESS) { - return PDU_COMPOSE_CONTENT_ERROR; - } - - // Date Date-value Optional. - appendHeader(PduHeaders.DATE); - - // From - if (appendHeader(PduHeaders.FROM) != PDU_COMPOSE_SUCCESS) { - return PDU_COMPOSE_CONTENT_ERROR; - } - - boolean recipient = false; - - // To - if (appendHeader(PduHeaders.TO) != PDU_COMPOSE_CONTENT_ERROR) { - recipient = true; - } - - // Cc - if (appendHeader(PduHeaders.CC) != PDU_COMPOSE_CONTENT_ERROR) { - recipient = true; - } - - // Bcc - if (appendHeader(PduHeaders.BCC) != PDU_COMPOSE_CONTENT_ERROR) { - recipient = true; - } - - // Need at least one of "cc", "bcc" and "to". - if (false == recipient) { - return PDU_COMPOSE_CONTENT_ERROR; - } - - // Subject Optional - appendHeader(PduHeaders.SUBJECT); - - // X-Mms-Message-Class Optional - // Message-class-value = Class-identifier | Token-text - appendHeader(PduHeaders.MESSAGE_CLASS); - - // X-Mms-Expiry Optional - appendHeader(PduHeaders.EXPIRY); - - // X-Mms-Priority Optional - appendHeader(PduHeaders.PRIORITY); - - // X-Mms-Delivery-Report Optional - appendHeader(PduHeaders.DELIVERY_REPORT); - - // X-Mms-Read-Report Optional - appendHeader(PduHeaders.READ_REPORT); - - // Content-Type - appendOctet(PduHeaders.CONTENT_TYPE); - - // Message body - return makeMessageBody(); - } - - /** - * Make message body. - */ - private int makeMessageBody() { - // 1. add body informations - mStack.newbuf(); // Switching buffer because we need to - - PositionMarker ctStart = mStack.mark(); - - // This contentTypeIdentifier should be used for type of attachment... - String contentType = new String(mPduHeader.getTextString(PduHeaders.CONTENT_TYPE)); - Integer contentTypeIdentifier = mContentTypeMap.get(contentType); - if (contentTypeIdentifier == null) { - // content type is mandatory - return PDU_COMPOSE_CONTENT_ERROR; - } - - appendShortInteger(contentTypeIdentifier.intValue()); - - // content-type parameter: start - PduBody body = ((SendReq) mPdu).getBody(); - if (null == body || body.getPartsNum() == 0) { - // empty message - appendUintvarInteger(0); - mStack.pop(); - mStack.copy(); - return PDU_COMPOSE_SUCCESS; - } - - PduPart part; - try { - part = body.getPart(0); - - byte[] start = part.getContentId(); - if (start != null) { - appendOctet(PduPart.P_DEP_START); - if (('<' == start[0]) && ('>' == start[start.length - 1])) { - appendTextString(start); - } else { - appendTextString("<" + new String(start) + ">"); - } - } - - // content-type parameter: type - appendOctet(PduPart.P_CT_MR_TYPE); - appendTextString(part.getContentType()); - } - catch (ArrayIndexOutOfBoundsException e){ - e.printStackTrace(); - } - - int ctLength = ctStart.getLength(); - mStack.pop(); - appendValueLength(ctLength); - mStack.copy(); - - // 3. add content - int partNum = body.getPartsNum(); - appendUintvarInteger(partNum); - for (int i = 0; i < partNum; i++) { - part = body.getPart(i); - mStack.newbuf(); // Leaving space for header lengh and data length - PositionMarker attachment = mStack.mark(); - - mStack.newbuf(); // Leaving space for Content-Type length - PositionMarker contentTypeBegin = mStack.mark(); - - byte[] partContentType = part.getContentType(); - - if (partContentType == null) { - // content type is mandatory - return PDU_COMPOSE_CONTENT_ERROR; - } - - // content-type value - Integer partContentTypeIdentifier = - mContentTypeMap.get(new String(partContentType)); - if (partContentTypeIdentifier == null) { - appendTextString(partContentType); - } else { - appendShortInteger(partContentTypeIdentifier.intValue()); - } - - /* Content-type parameter : name. - * The value of name, filename, content-location is the same. - * Just one of them is enough for this PDU. - */ - byte[] name = part.getName(); - - if (null == name) { - name = part.getFilename(); - - if (null == name) { - name = part.getContentLocation(); - - if (null == name) { - /* at lease one of name, filename, Content-location - * should be available. - */ - return PDU_COMPOSE_CONTENT_ERROR; - } - } - } - appendOctet(PduPart.P_DEP_NAME); - appendTextString(name); - - // content-type parameter : charset - int charset = part.getCharset(); - if (charset != 0) { - appendOctet(PduPart.P_CHARSET); - appendShortInteger(charset); - } - - int contentTypeLength = contentTypeBegin.getLength(); - mStack.pop(); - appendValueLength(contentTypeLength); - mStack.copy(); - - // content id - byte[] contentId = part.getContentId(); - - if (null != contentId) { - appendOctet(PduPart.P_CONTENT_ID); - if (('<' == contentId[0]) && ('>' == contentId[contentId.length - 1])) { - appendQuotedString(contentId); - } else { - appendQuotedString("<" + new String(contentId) + ">"); - } - } - - // content-location - byte[] contentLocation = part.getContentLocation(); - if (null != contentLocation) { - appendOctet(PduPart.P_CONTENT_LOCATION); - appendTextString(contentLocation); - } - - // content - int headerLength = attachment.getLength(); - - int dataLength = 0; // Just for safety... - byte[] partData = part.getData(); - - if (partData != null) { - arraycopy(partData, 0, partData.length); - dataLength = partData.length; - } else { - InputStream cr; - try { - byte[] buffer = new byte[PDU_COMPOSER_BLOCK_SIZE]; - cr = mResolver.openInputStream(part.getDataUri()); - int len = 0; - while ((len = cr.read(buffer)) != -1) { - mMessage.write(buffer, 0, len); - mPosition += len; - dataLength += len; - } - } catch (FileNotFoundException e) { - return PDU_COMPOSE_CONTENT_ERROR; - } catch (IOException e) { - return PDU_COMPOSE_CONTENT_ERROR; - } catch (RuntimeException e) { - return PDU_COMPOSE_CONTENT_ERROR; - } - } - - if (dataLength != (attachment.getLength() - headerLength)) { - throw new RuntimeException("BUG: Length sanity check failed"); - } - - mStack.pop(); - appendUintvarInteger(headerLength); - appendUintvarInteger(dataLength); - mStack.copy(); - } - - return PDU_COMPOSE_SUCCESS; - } - - /** - * Record current message informations. - */ - static private class LengthRecordNode { - ByteArrayOutputStream currentMessage = null; - public int currentPosition = 0; - - public LengthRecordNode next = null; - } - - /** - * Mark current message position and stact size. - */ - private class PositionMarker { - private int c_pos; // Current position - private int currentStackSize; // Current stack size - - int getLength() { - // If these assert fails, likely that you are finding the - // size of buffer that is deep in BufferStack you can only - // find the length of the buffer that is on top - if (currentStackSize != mStack.stackSize) { - throw new RuntimeException("BUG: Invalid call to getLength()"); - } - - return mPosition - c_pos; - } - } - - /** - * This implementation can be OPTIMIZED to use only - * 2 buffers. This optimization involves changing BufferStack - * only... Its usage (interface) will not change. - */ - private class BufferStack { - private LengthRecordNode stack = null; - private LengthRecordNode toCopy = null; - - int stackSize = 0; - - /** - * Create a new message buffer and push it into the stack. - */ - void newbuf() { - // You can't create a new buff when toCopy != null - // That is after calling pop() and before calling copy() - // If you do, it is a bug - if (toCopy != null) { - throw new RuntimeException("BUG: Invalid newbuf() before copy()"); - } - - LengthRecordNode temp = new LengthRecordNode(); - - temp.currentMessage = mMessage; - temp.currentPosition = mPosition; - - temp.next = stack; - stack = temp; - - stackSize = stackSize + 1; - - mMessage = new ByteArrayOutputStream(); - mPosition = 0; - } - - /** - * Pop the message before and record current message in the stack. - */ - void pop() { - ByteArrayOutputStream currentMessage = mMessage; - int currentPosition = mPosition; - - mMessage = stack.currentMessage; - mPosition = stack.currentPosition; - - toCopy = stack; - // Re using the top element of the stack to avoid memory allocation - - stack = stack.next; - stackSize = stackSize - 1; - - toCopy.currentMessage = currentMessage; - toCopy.currentPosition = currentPosition; - } - - /** - * Append current message to the message before. - */ - void copy() { - arraycopy(toCopy.currentMessage.toByteArray(), 0, - toCopy.currentPosition); - - toCopy = null; - } - - /** - * Mark current message position - */ - PositionMarker mark() { - PositionMarker m = new PositionMarker(); - - m.c_pos = mPosition; - m.currentStackSize = stackSize; - - return m; - } - } - - /** - * Check address type. - * - * @param address address string without the postfix stinng type, - * such as "/TYPE=PLMN", "/TYPE=IPv6" and "/TYPE=IPv4" - * @return PDU_PHONE_NUMBER_ADDRESS_TYPE if it is phone number, - * PDU_EMAIL_ADDRESS_TYPE if it is email address, - * PDU_IPV4_ADDRESS_TYPE if it is ipv4 address, - * PDU_IPV6_ADDRESS_TYPE if it is ipv6 address, - * PDU_UNKNOWN_ADDRESS_TYPE if it is unknown. - */ - protected static int checkAddressType(String address) { - /** - * From OMA-TS-MMS-ENC-V1_3-20050927-C.pdf, section 8. - * address = ( e-mail / device-address / alphanum-shortcode / num-shortcode) - * e-mail = mailbox; to the definition of mailbox as described in - * section 3.4 of [RFC2822], but excluding the - * obsolete definitions as indicated by the "obs-" prefix. - * device-address = ( global-phone-number "/TYPE=PLMN" ) - * / ( ipv4 "/TYPE=IPv4" ) / ( ipv6 "/TYPE=IPv6" ) - * / ( escaped-value "/TYPE=" address-type ) - * - * global-phone-number = ["+"] 1*( DIGIT / written-sep ) - * written-sep =("-"/".") - * - * ipv4 = 1*3DIGIT 3( "." 1*3DIGIT ) ; IPv4 address value - * - * ipv6 = 4HEXDIG 7( ":" 4HEXDIG ) ; IPv6 address per RFC 2373 - */ - - if (null == address) { - return PDU_UNKNOWN_ADDRESS_TYPE; - } - - if (address.matches(REGEXP_IPV4_ADDRESS_TYPE)) { - // Ipv4 address. - return PDU_IPV4_ADDRESS_TYPE; - }else if (address.matches(REGEXP_PHONE_NUMBER_ADDRESS_TYPE)) { - // Phone number. - return PDU_PHONE_NUMBER_ADDRESS_TYPE; - } else if (address.matches(REGEXP_EMAIL_ADDRESS_TYPE)) { - // Email address. - return PDU_EMAIL_ADDRESS_TYPE; - } else if (address.matches(REGEXP_IPV6_ADDRESS_TYPE)) { - // Ipv6 address. - return PDU_IPV6_ADDRESS_TYPE; - } else { - // Unknown address. - return PDU_UNKNOWN_ADDRESS_TYPE; - } - } -} diff --git a/core/java/com/google/android/mms/pdu/PduContentTypes.java b/core/java/com/google/android/mms/pdu/PduContentTypes.java deleted file mode 100644 index 7799e0e..0000000 --- a/core/java/com/google/android/mms/pdu/PduContentTypes.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2007 Esmertec AG. - * Copyright (C) 2007 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.mms.pdu; - -public class PduContentTypes { - /** - * All content types. From: - * http://www.openmobilealliance.org/tech/omna/omna-wsp-content-type.htm - */ - static final String[] contentTypes = { - "*/*", /* 0x00 */ - "text/*", /* 0x01 */ - "text/html", /* 0x02 */ - "text/plain", /* 0x03 */ - "text/x-hdml", /* 0x04 */ - "text/x-ttml", /* 0x05 */ - "text/x-vCalendar", /* 0x06 */ - "text/x-vCard", /* 0x07 */ - "text/vnd.wap.wml", /* 0x08 */ - "text/vnd.wap.wmlscript", /* 0x09 */ - "text/vnd.wap.wta-event", /* 0x0A */ - "multipart/*", /* 0x0B */ - "multipart/mixed", /* 0x0C */ - "multipart/form-data", /* 0x0D */ - "multipart/byterantes", /* 0x0E */ - "multipart/alternative", /* 0x0F */ - "application/*", /* 0x10 */ - "application/java-vm", /* 0x11 */ - "application/x-www-form-urlencoded", /* 0x12 */ - "application/x-hdmlc", /* 0x13 */ - "application/vnd.wap.wmlc", /* 0x14 */ - "application/vnd.wap.wmlscriptc", /* 0x15 */ - "application/vnd.wap.wta-eventc", /* 0x16 */ - "application/vnd.wap.uaprof", /* 0x17 */ - "application/vnd.wap.wtls-ca-certificate", /* 0x18 */ - "application/vnd.wap.wtls-user-certificate", /* 0x19 */ - "application/x-x509-ca-cert", /* 0x1A */ - "application/x-x509-user-cert", /* 0x1B */ - "image/*", /* 0x1C */ - "image/gif", /* 0x1D */ - "image/jpeg", /* 0x1E */ - "image/tiff", /* 0x1F */ - "image/png", /* 0x20 */ - "image/vnd.wap.wbmp", /* 0x21 */ - "application/vnd.wap.multipart.*", /* 0x22 */ - "application/vnd.wap.multipart.mixed", /* 0x23 */ - "application/vnd.wap.multipart.form-data", /* 0x24 */ - "application/vnd.wap.multipart.byteranges", /* 0x25 */ - "application/vnd.wap.multipart.alternative", /* 0x26 */ - "application/xml", /* 0x27 */ - "text/xml", /* 0x28 */ - "application/vnd.wap.wbxml", /* 0x29 */ - "application/x-x968-cross-cert", /* 0x2A */ - "application/x-x968-ca-cert", /* 0x2B */ - "application/x-x968-user-cert", /* 0x2C */ - "text/vnd.wap.si", /* 0x2D */ - "application/vnd.wap.sic", /* 0x2E */ - "text/vnd.wap.sl", /* 0x2F */ - "application/vnd.wap.slc", /* 0x30 */ - "text/vnd.wap.co", /* 0x31 */ - "application/vnd.wap.coc", /* 0x32 */ - "application/vnd.wap.multipart.related", /* 0x33 */ - "application/vnd.wap.sia", /* 0x34 */ - "text/vnd.wap.connectivity-xml", /* 0x35 */ - "application/vnd.wap.connectivity-wbxml", /* 0x36 */ - "application/pkcs7-mime", /* 0x37 */ - "application/vnd.wap.hashed-certificate", /* 0x38 */ - "application/vnd.wap.signed-certificate", /* 0x39 */ - "application/vnd.wap.cert-response", /* 0x3A */ - "application/xhtml+xml", /* 0x3B */ - "application/wml+xml", /* 0x3C */ - "text/css", /* 0x3D */ - "application/vnd.wap.mms-message", /* 0x3E */ - "application/vnd.wap.rollover-certificate", /* 0x3F */ - "application/vnd.wap.locc+wbxml", /* 0x40 */ - "application/vnd.wap.loc+xml", /* 0x41 */ - "application/vnd.syncml.dm+wbxml", /* 0x42 */ - "application/vnd.syncml.dm+xml", /* 0x43 */ - "application/vnd.syncml.notification", /* 0x44 */ - "application/vnd.wap.xhtml+xml", /* 0x45 */ - "application/vnd.wv.csp.cir", /* 0x46 */ - "application/vnd.oma.dd+xml", /* 0x47 */ - "application/vnd.oma.drm.message", /* 0x48 */ - "application/vnd.oma.drm.content", /* 0x49 */ - "application/vnd.oma.drm.rights+xml", /* 0x4A */ - "application/vnd.oma.drm.rights+wbxml", /* 0x4B */ - "application/vnd.wv.csp+xml", /* 0x4C */ - "application/vnd.wv.csp+wbxml", /* 0x4D */ - "application/vnd.syncml.ds.notification", /* 0x4E */ - "audio/*", /* 0x4F */ - "video/*", /* 0x50 */ - "application/vnd.oma.dd2+xml", /* 0x51 */ - "application/mikey" /* 0x52 */ - }; -} diff --git a/core/java/com/google/android/mms/pdu/PduHeaders.java b/core/java/com/google/android/mms/pdu/PduHeaders.java deleted file mode 100644 index 4313815..0000000 --- a/core/java/com/google/android/mms/pdu/PduHeaders.java +++ /dev/null @@ -1,721 +0,0 @@ -/* - * Copyright (C) 2007 Esmertec AG. - * Copyright (C) 2007 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.mms.pdu; - -import com.google.android.mms.InvalidHeaderValueException; - -import java.util.ArrayList; -import java.util.HashMap; - -public class PduHeaders { - /** - * All pdu header fields. - */ - public static final int BCC = 0x81; - public static final int CC = 0x82; - public static final int CONTENT_LOCATION = 0x83; - public static final int CONTENT_TYPE = 0x84; - public static final int DATE = 0x85; - public static final int DELIVERY_REPORT = 0x86; - public static final int DELIVERY_TIME = 0x87; - public static final int EXPIRY = 0x88; - public static final int FROM = 0x89; - public static final int MESSAGE_CLASS = 0x8A; - public static final int MESSAGE_ID = 0x8B; - public static final int MESSAGE_TYPE = 0x8C; - public static final int MMS_VERSION = 0x8D; - public static final int MESSAGE_SIZE = 0x8E; - public static final int PRIORITY = 0x8F; - - public static final int READ_REPLY = 0x90; - public static final int READ_REPORT = 0x90; - public static final int REPORT_ALLOWED = 0x91; - public static final int RESPONSE_STATUS = 0x92; - public static final int RESPONSE_TEXT = 0x93; - public static final int SENDER_VISIBILITY = 0x94; - public static final int STATUS = 0x95; - public static final int SUBJECT = 0x96; - public static final int TO = 0x97; - public static final int TRANSACTION_ID = 0x98; - public static final int RETRIEVE_STATUS = 0x99; - public static final int RETRIEVE_TEXT = 0x9A; - public static final int READ_STATUS = 0x9B; - public static final int REPLY_CHARGING = 0x9C; - public static final int REPLY_CHARGING_DEADLINE = 0x9D; - public static final int REPLY_CHARGING_ID = 0x9E; - public static final int REPLY_CHARGING_SIZE = 0x9F; - - public static final int PREVIOUSLY_SENT_BY = 0xA0; - public static final int PREVIOUSLY_SENT_DATE = 0xA1; - public static final int STORE = 0xA2; - public static final int MM_STATE = 0xA3; - public static final int MM_FLAGS = 0xA4; - public static final int STORE_STATUS = 0xA5; - public static final int STORE_STATUS_TEXT = 0xA6; - public static final int STORED = 0xA7; - public static final int ATTRIBUTES = 0xA8; - public static final int TOTALS = 0xA9; - public static final int MBOX_TOTALS = 0xAA; - public static final int QUOTAS = 0xAB; - public static final int MBOX_QUOTAS = 0xAC; - public static final int MESSAGE_COUNT = 0xAD; - public static final int CONTENT = 0xAE; - public static final int START = 0xAF; - - public static final int ADDITIONAL_HEADERS = 0xB0; - public static final int DISTRIBUTION_INDICATOR = 0xB1; - public static final int ELEMENT_DESCRIPTOR = 0xB2; - public static final int LIMIT = 0xB3; - public static final int RECOMMENDED_RETRIEVAL_MODE = 0xB4; - public static final int RECOMMENDED_RETRIEVAL_MODE_TEXT = 0xB5; - public static final int STATUS_TEXT = 0xB6; - public static final int APPLIC_ID = 0xB7; - public static final int REPLY_APPLIC_ID = 0xB8; - public static final int AUX_APPLIC_ID = 0xB9; - public static final int CONTENT_CLASS = 0xBA; - public static final int DRM_CONTENT = 0xBB; - public static final int ADAPTATION_ALLOWED = 0xBC; - public static final int REPLACE_ID = 0xBD; - public static final int CANCEL_ID = 0xBE; - public static final int CANCEL_STATUS = 0xBF; - - /** - * X-Mms-Message-Type field types. - */ - public static final int MESSAGE_TYPE_SEND_REQ = 0x80; - public static final int MESSAGE_TYPE_SEND_CONF = 0x81; - public static final int MESSAGE_TYPE_NOTIFICATION_IND = 0x82; - public static final int MESSAGE_TYPE_NOTIFYRESP_IND = 0x83; - public static final int MESSAGE_TYPE_RETRIEVE_CONF = 0x84; - public static final int MESSAGE_TYPE_ACKNOWLEDGE_IND = 0x85; - public static final int MESSAGE_TYPE_DELIVERY_IND = 0x86; - public static final int MESSAGE_TYPE_READ_REC_IND = 0x87; - public static final int MESSAGE_TYPE_READ_ORIG_IND = 0x88; - public static final int MESSAGE_TYPE_FORWARD_REQ = 0x89; - public static final int MESSAGE_TYPE_FORWARD_CONF = 0x8A; - public static final int MESSAGE_TYPE_MBOX_STORE_REQ = 0x8B; - public static final int MESSAGE_TYPE_MBOX_STORE_CONF = 0x8C; - public static final int MESSAGE_TYPE_MBOX_VIEW_REQ = 0x8D; - public static final int MESSAGE_TYPE_MBOX_VIEW_CONF = 0x8E; - public static final int MESSAGE_TYPE_MBOX_UPLOAD_REQ = 0x8F; - public static final int MESSAGE_TYPE_MBOX_UPLOAD_CONF = 0x90; - public static final int MESSAGE_TYPE_MBOX_DELETE_REQ = 0x91; - public static final int MESSAGE_TYPE_MBOX_DELETE_CONF = 0x92; - public static final int MESSAGE_TYPE_MBOX_DESCR = 0x93; - public static final int MESSAGE_TYPE_DELETE_REQ = 0x94; - public static final int MESSAGE_TYPE_DELETE_CONF = 0x95; - public static final int MESSAGE_TYPE_CANCEL_REQ = 0x96; - public static final int MESSAGE_TYPE_CANCEL_CONF = 0x97; - - /** - * X-Mms-Delivery-Report | - * X-Mms-Read-Report | - * X-Mms-Report-Allowed | - * X-Mms-Sender-Visibility | - * X-Mms-Store | - * X-Mms-Stored | - * X-Mms-Totals | - * X-Mms-Quotas | - * X-Mms-Distribution-Indicator | - * X-Mms-DRM-Content | - * X-Mms-Adaptation-Allowed | - * field types. - */ - public static final int VALUE_YES = 0x80; - public static final int VALUE_NO = 0x81; - - /** - * Delivery-Time | - * Expiry and Reply-Charging-Deadline | - * field type components. - */ - public static final int VALUE_ABSOLUTE_TOKEN = 0x80; - public static final int VALUE_RELATIVE_TOKEN = 0x81; - - /** - * X-Mms-MMS-Version field types. - */ - public static final int MMS_VERSION_1_3 = ((1 << 4) | 3); - public static final int MMS_VERSION_1_2 = ((1 << 4) | 2); - public static final int MMS_VERSION_1_1 = ((1 << 4) | 1); - public static final int MMS_VERSION_1_0 = ((1 << 4) | 0); - - // Current version is 1.2. - public static final int CURRENT_MMS_VERSION = MMS_VERSION_1_2; - - /** - * From field type components. - */ - public static final int FROM_ADDRESS_PRESENT_TOKEN = 0x80; - public static final int FROM_INSERT_ADDRESS_TOKEN = 0x81; - - public static final String FROM_ADDRESS_PRESENT_TOKEN_STR = "address-present-token"; - public static final String FROM_INSERT_ADDRESS_TOKEN_STR = "insert-address-token"; - - /** - * X-Mms-Status Field. - */ - public static final int STATUS_EXPIRED = 0x80; - public static final int STATUS_RETRIEVED = 0x81; - public static final int STATUS_REJECTED = 0x82; - public static final int STATUS_DEFERRED = 0x83; - public static final int STATUS_UNRECOGNIZED = 0x84; - public static final int STATUS_INDETERMINATE = 0x85; - public static final int STATUS_FORWARDED = 0x86; - public static final int STATUS_UNREACHABLE = 0x87; - - /** - * MM-Flags field type components. - */ - public static final int MM_FLAGS_ADD_TOKEN = 0x80; - public static final int MM_FLAGS_REMOVE_TOKEN = 0x81; - public static final int MM_FLAGS_FILTER_TOKEN = 0x82; - - /** - * X-Mms-Message-Class field types. - */ - public static final int MESSAGE_CLASS_PERSONAL = 0x80; - public static final int MESSAGE_CLASS_ADVERTISEMENT = 0x81; - public static final int MESSAGE_CLASS_INFORMATIONAL = 0x82; - public static final int MESSAGE_CLASS_AUTO = 0x83; - - public static final String MESSAGE_CLASS_PERSONAL_STR = "personal"; - public static final String MESSAGE_CLASS_ADVERTISEMENT_STR = "advertisement"; - public static final String MESSAGE_CLASS_INFORMATIONAL_STR = "informational"; - public static final String MESSAGE_CLASS_AUTO_STR = "auto"; - - /** - * X-Mms-Priority field types. - */ - public static final int PRIORITY_LOW = 0x80; - public static final int PRIORITY_NORMAL = 0x81; - public static final int PRIORITY_HIGH = 0x82; - - /** - * X-Mms-Response-Status field types. - */ - public static final int RESPONSE_STATUS_OK = 0x80; - public static final int RESPONSE_STATUS_ERROR_UNSPECIFIED = 0x81; - public static final int RESPONSE_STATUS_ERROR_SERVICE_DENIED = 0x82; - - public static final int RESPONSE_STATUS_ERROR_MESSAGE_FORMAT_CORRUPT = 0x83; - public static final int RESPONSE_STATUS_ERROR_SENDING_ADDRESS_UNRESOLVED = 0x84; - - public static final int RESPONSE_STATUS_ERROR_MESSAGE_NOT_FOUND = 0x85; - public static final int RESPONSE_STATUS_ERROR_NETWORK_PROBLEM = 0x86; - public static final int RESPONSE_STATUS_ERROR_CONTENT_NOT_ACCEPTED = 0x87; - public static final int RESPONSE_STATUS_ERROR_UNSUPPORTED_MESSAGE = 0x88; - public static final int RESPONSE_STATUS_ERROR_TRANSIENT_FAILURE = 0xC0; - - public static final int RESPONSE_STATUS_ERROR_TRANSIENT_SENDNG_ADDRESS_UNRESOLVED = 0xC1; - public static final int RESPONSE_STATUS_ERROR_TRANSIENT_MESSAGE_NOT_FOUND = 0xC2; - public static final int RESPONSE_STATUS_ERROR_TRANSIENT_NETWORK_PROBLEM = 0xC3; - public static final int RESPONSE_STATUS_ERROR_TRANSIENT_PARTIAL_SUCCESS = 0xC4; - - public static final int RESPONSE_STATUS_ERROR_PERMANENT_FAILURE = 0xE0; - public static final int RESPONSE_STATUS_ERROR_PERMANENT_SERVICE_DENIED = 0xE1; - public static final int RESPONSE_STATUS_ERROR_PERMANENT_MESSAGE_FORMAT_CORRUPT = 0xE2; - public static final int RESPONSE_STATUS_ERROR_PERMANENT_SENDING_ADDRESS_UNRESOLVED = 0xE3; - public static final int RESPONSE_STATUS_ERROR_PERMANENT_MESSAGE_NOT_FOUND = 0xE4; - public static final int RESPONSE_STATUS_ERROR_PERMANENT_CONTENT_NOT_ACCEPTED = 0xE5; - public static final int RESPONSE_STATUS_ERROR_PERMANENT_REPLY_CHARGING_LIMITATIONS_NOT_MET = 0xE6; - public static final int RESPONSE_STATUS_ERROR_PERMANENT_REPLY_CHARGING_REQUEST_NOT_ACCEPTED = 0xE6; - public static final int RESPONSE_STATUS_ERROR_PERMANENT_REPLY_CHARGING_FORWARDING_DENIED = 0xE8; - public static final int RESPONSE_STATUS_ERROR_PERMANENT_REPLY_CHARGING_NOT_SUPPORTED = 0xE9; - public static final int RESPONSE_STATUS_ERROR_PERMANENT_ADDRESS_HIDING_NOT_SUPPORTED = 0xEA; - public static final int RESPONSE_STATUS_ERROR_PERMANENT_LACK_OF_PREPAID = 0xEB; - public static final int RESPONSE_STATUS_ERROR_PERMANENT_END = 0xFF; - - /** - * X-Mms-Retrieve-Status field types. - */ - public static final int RETRIEVE_STATUS_OK = 0x80; - public static final int RETRIEVE_STATUS_ERROR_TRANSIENT_FAILURE = 0xC0; - public static final int RETRIEVE_STATUS_ERROR_TRANSIENT_MESSAGE_NOT_FOUND = 0xC1; - public static final int RETRIEVE_STATUS_ERROR_TRANSIENT_NETWORK_PROBLEM = 0xC2; - public static final int RETRIEVE_STATUS_ERROR_PERMANENT_FAILURE = 0xE0; - public static final int RETRIEVE_STATUS_ERROR_PERMANENT_SERVICE_DENIED = 0xE1; - public static final int RETRIEVE_STATUS_ERROR_PERMANENT_MESSAGE_NOT_FOUND = 0xE2; - public static final int RETRIEVE_STATUS_ERROR_PERMANENT_CONTENT_UNSUPPORTED = 0xE3; - public static final int RETRIEVE_STATUS_ERROR_END = 0xFF; - - /** - * X-Mms-Sender-Visibility field types. - */ - public static final int SENDER_VISIBILITY_HIDE = 0x80; - public static final int SENDER_VISIBILITY_SHOW = 0x81; - - /** - * X-Mms-Read-Status field types. - */ - public static final int READ_STATUS_READ = 0x80; - public static final int READ_STATUS__DELETED_WITHOUT_BEING_READ = 0x81; - - /** - * X-Mms-Cancel-Status field types. - */ - public static final int CANCEL_STATUS_REQUEST_SUCCESSFULLY_RECEIVED = 0x80; - public static final int CANCEL_STATUS_REQUEST_CORRUPTED = 0x81; - - /** - * X-Mms-Reply-Charging field types. - */ - public static final int REPLY_CHARGING_REQUESTED = 0x80; - public static final int REPLY_CHARGING_REQUESTED_TEXT_ONLY = 0x81; - public static final int REPLY_CHARGING_ACCEPTED = 0x82; - public static final int REPLY_CHARGING_ACCEPTED_TEXT_ONLY = 0x83; - - /** - * X-Mms-MM-State field types. - */ - public static final int MM_STATE_DRAFT = 0x80; - public static final int MM_STATE_SENT = 0x81; - public static final int MM_STATE_NEW = 0x82; - public static final int MM_STATE_RETRIEVED = 0x83; - public static final int MM_STATE_FORWARDED = 0x84; - - /** - * X-Mms-Recommended-Retrieval-Mode field types. - */ - public static final int RECOMMENDED_RETRIEVAL_MODE_MANUAL = 0x80; - - /** - * X-Mms-Content-Class field types. - */ - public static final int CONTENT_CLASS_TEXT = 0x80; - public static final int CONTENT_CLASS_IMAGE_BASIC = 0x81; - public static final int CONTENT_CLASS_IMAGE_RICH = 0x82; - public static final int CONTENT_CLASS_VIDEO_BASIC = 0x83; - public static final int CONTENT_CLASS_VIDEO_RICH = 0x84; - public static final int CONTENT_CLASS_MEGAPIXEL = 0x85; - public static final int CONTENT_CLASS_CONTENT_BASIC = 0x86; - public static final int CONTENT_CLASS_CONTENT_RICH = 0x87; - - /** - * X-Mms-Store-Status field types. - */ - public static final int STORE_STATUS_SUCCESS = 0x80; - public static final int STORE_STATUS_ERROR_TRANSIENT_FAILURE = 0xC0; - public static final int STORE_STATUS_ERROR_TRANSIENT_NETWORK_PROBLEM = 0xC1; - public static final int STORE_STATUS_ERROR_PERMANENT_FAILURE = 0xE0; - public static final int STORE_STATUS_ERROR_PERMANENT_SERVICE_DENIED = 0xE1; - public static final int STORE_STATUS_ERROR_PERMANENT_MESSAGE_FORMAT_CORRUPT = 0xE2; - public static final int STORE_STATUS_ERROR_PERMANENT_MESSAGE_NOT_FOUND = 0xE3; - public static final int STORE_STATUS_ERROR_PERMANENT_MMBOX_FULL = 0xE4; - public static final int STORE_STATUS_ERROR_END = 0xFF; - - /** - * The map contains the value of all headers. - */ - private HashMap<Integer, Object> mHeaderMap = null; - - /** - * Constructor of PduHeaders. - */ - public PduHeaders() { - mHeaderMap = new HashMap<Integer, Object>(); - } - - /** - * Get octet value by header field. - * - * @param field the field - * @return the octet value of the pdu header - * with specified header field. Return 0 if - * the value is not set. - */ - protected int getOctet(int field) { - Integer octet = (Integer) mHeaderMap.get(field); - if (null == octet) { - return 0; - } - - return octet; - } - - /** - * Set octet value to pdu header by header field. - * - * @param value the value - * @param field the field - * @throws InvalidHeaderValueException if the value is invalid. - */ - protected void setOctet(int value, int field) - throws InvalidHeaderValueException{ - /** - * Check whether this field can be set for specific - * header and check validity of the field. - */ - switch (field) { - case REPORT_ALLOWED: - case ADAPTATION_ALLOWED: - case DELIVERY_REPORT: - case DRM_CONTENT: - case DISTRIBUTION_INDICATOR: - case QUOTAS: - case READ_REPORT: - case STORE: - case STORED: - case TOTALS: - case SENDER_VISIBILITY: - if ((VALUE_YES != value) && (VALUE_NO != value)) { - // Invalid value. - throw new InvalidHeaderValueException("Invalid Octet value!"); - } - break; - case READ_STATUS: - if ((READ_STATUS_READ != value) && - (READ_STATUS__DELETED_WITHOUT_BEING_READ != value)) { - // Invalid value. - throw new InvalidHeaderValueException("Invalid Octet value!"); - } - break; - case CANCEL_STATUS: - if ((CANCEL_STATUS_REQUEST_SUCCESSFULLY_RECEIVED != value) && - (CANCEL_STATUS_REQUEST_CORRUPTED != value)) { - // Invalid value. - throw new InvalidHeaderValueException("Invalid Octet value!"); - } - break; - case PRIORITY: - if ((value < PRIORITY_LOW) || (value > PRIORITY_HIGH)) { - // Invalid value. - throw new InvalidHeaderValueException("Invalid Octet value!"); - } - break; - case STATUS: - if ((value < STATUS_EXPIRED) || (value > STATUS_UNREACHABLE)) { - // Invalid value. - throw new InvalidHeaderValueException("Invalid Octet value!"); - } - break; - case REPLY_CHARGING: - if ((value < REPLY_CHARGING_REQUESTED) - || (value > REPLY_CHARGING_ACCEPTED_TEXT_ONLY)) { - // Invalid value. - throw new InvalidHeaderValueException("Invalid Octet value!"); - } - break; - case MM_STATE: - if ((value < MM_STATE_DRAFT) || (value > MM_STATE_FORWARDED)) { - // Invalid value. - throw new InvalidHeaderValueException("Invalid Octet value!"); - } - break; - case RECOMMENDED_RETRIEVAL_MODE: - if (RECOMMENDED_RETRIEVAL_MODE_MANUAL != value) { - // Invalid value. - throw new InvalidHeaderValueException("Invalid Octet value!"); - } - break; - case CONTENT_CLASS: - if ((value < CONTENT_CLASS_TEXT) - || (value > CONTENT_CLASS_CONTENT_RICH)) { - // Invalid value. - throw new InvalidHeaderValueException("Invalid Octet value!"); - } - break; - case RETRIEVE_STATUS: - // According to oma-ts-mms-enc-v1_3, section 7.3.50, we modify the invalid value. - if ((value > RETRIEVE_STATUS_ERROR_TRANSIENT_NETWORK_PROBLEM) && - (value < RETRIEVE_STATUS_ERROR_PERMANENT_FAILURE)) { - value = RETRIEVE_STATUS_ERROR_TRANSIENT_FAILURE; - } else if ((value > RETRIEVE_STATUS_ERROR_PERMANENT_CONTENT_UNSUPPORTED) && - (value <= RETRIEVE_STATUS_ERROR_END)) { - value = RETRIEVE_STATUS_ERROR_PERMANENT_FAILURE; - } else if ((value < RETRIEVE_STATUS_OK) || - ((value > RETRIEVE_STATUS_OK) && - (value < RETRIEVE_STATUS_ERROR_TRANSIENT_FAILURE)) || - (value > RETRIEVE_STATUS_ERROR_END)) { - value = RETRIEVE_STATUS_ERROR_PERMANENT_FAILURE; - } - break; - case STORE_STATUS: - // According to oma-ts-mms-enc-v1_3, section 7.3.58, we modify the invalid value. - if ((value > STORE_STATUS_ERROR_TRANSIENT_NETWORK_PROBLEM) && - (value < STORE_STATUS_ERROR_PERMANENT_FAILURE)) { - value = STORE_STATUS_ERROR_TRANSIENT_FAILURE; - } else if ((value > STORE_STATUS_ERROR_PERMANENT_MMBOX_FULL) && - (value <= STORE_STATUS_ERROR_END)) { - value = STORE_STATUS_ERROR_PERMANENT_FAILURE; - } else if ((value < STORE_STATUS_SUCCESS) || - ((value > STORE_STATUS_SUCCESS) && - (value < STORE_STATUS_ERROR_TRANSIENT_FAILURE)) || - (value > STORE_STATUS_ERROR_END)) { - value = STORE_STATUS_ERROR_PERMANENT_FAILURE; - } - break; - case RESPONSE_STATUS: - // According to oma-ts-mms-enc-v1_3, section 7.3.48, we modify the invalid value. - if ((value > RESPONSE_STATUS_ERROR_TRANSIENT_PARTIAL_SUCCESS) && - (value < RESPONSE_STATUS_ERROR_PERMANENT_FAILURE)) { - value = RESPONSE_STATUS_ERROR_TRANSIENT_FAILURE; - } else if (((value > RESPONSE_STATUS_ERROR_PERMANENT_LACK_OF_PREPAID) && - (value <= RESPONSE_STATUS_ERROR_PERMANENT_END)) || - (value < RESPONSE_STATUS_OK) || - ((value > RESPONSE_STATUS_ERROR_UNSUPPORTED_MESSAGE) && - (value < RESPONSE_STATUS_ERROR_TRANSIENT_FAILURE)) || - (value > RESPONSE_STATUS_ERROR_PERMANENT_END)) { - value = RESPONSE_STATUS_ERROR_PERMANENT_FAILURE; - } - break; - case MMS_VERSION: - if ((value < MMS_VERSION_1_0)|| (value > MMS_VERSION_1_3)) { - value = CURRENT_MMS_VERSION; // Current version is the default value. - } - break; - case MESSAGE_TYPE: - if ((value < MESSAGE_TYPE_SEND_REQ) || (value > MESSAGE_TYPE_CANCEL_CONF)) { - // Invalid value. - throw new InvalidHeaderValueException("Invalid Octet value!"); - } - break; - default: - // This header value should not be Octect. - throw new RuntimeException("Invalid header field!"); - } - mHeaderMap.put(field, value); - } - - /** - * Get TextString value by header field. - * - * @param field the field - * @return the TextString value of the pdu header - * with specified header field - */ - protected byte[] getTextString(int field) { - return (byte[]) mHeaderMap.get(field); - } - - /** - * Set TextString value to pdu header by header field. - * - * @param value the value - * @param field the field - * @return the TextString value of the pdu header - * with specified header field - * @throws NullPointerException if the value is null. - */ - protected void setTextString(byte[] value, int field) { - /** - * Check whether this field can be set for specific - * header and check validity of the field. - */ - if (null == value) { - throw new NullPointerException(); - } - - switch (field) { - case TRANSACTION_ID: - case REPLY_CHARGING_ID: - case AUX_APPLIC_ID: - case APPLIC_ID: - case REPLY_APPLIC_ID: - case MESSAGE_ID: - case REPLACE_ID: - case CANCEL_ID: - case CONTENT_LOCATION: - case MESSAGE_CLASS: - case CONTENT_TYPE: - break; - default: - // This header value should not be Text-String. - throw new RuntimeException("Invalid header field!"); - } - mHeaderMap.put(field, value); - } - - /** - * Get EncodedStringValue value by header field. - * - * @param field the field - * @return the EncodedStringValue value of the pdu header - * with specified header field - */ - protected EncodedStringValue getEncodedStringValue(int field) { - return (EncodedStringValue) mHeaderMap.get(field); - } - - /** - * Get TO, CC or BCC header value. - * - * @param field the field - * @return the EncodeStringValue array of the pdu header - * with specified header field - */ - protected EncodedStringValue[] getEncodedStringValues(int field) { - ArrayList<EncodedStringValue> list = - (ArrayList<EncodedStringValue>) mHeaderMap.get(field); - if (null == list) { - return null; - } - EncodedStringValue[] values = new EncodedStringValue[list.size()]; - return list.toArray(values); - } - - /** - * Set EncodedStringValue value to pdu header by header field. - * - * @param value the value - * @param field the field - * @return the EncodedStringValue value of the pdu header - * with specified header field - * @throws NullPointerException if the value is null. - */ - protected void setEncodedStringValue(EncodedStringValue value, int field) { - /** - * Check whether this field can be set for specific - * header and check validity of the field. - */ - if (null == value) { - throw new NullPointerException(); - } - - switch (field) { - case SUBJECT: - case RECOMMENDED_RETRIEVAL_MODE_TEXT: - case RETRIEVE_TEXT: - case STATUS_TEXT: - case STORE_STATUS_TEXT: - case RESPONSE_TEXT: - case FROM: - case PREVIOUSLY_SENT_BY: - case MM_FLAGS: - break; - default: - // This header value should not be Encoded-String-Value. - throw new RuntimeException("Invalid header field!"); - } - - mHeaderMap.put(field, value); - } - - /** - * Set TO, CC or BCC header value. - * - * @param value the value - * @param field the field - * @return the EncodedStringValue value array of the pdu header - * with specified header field - * @throws NullPointerException if the value is null. - */ - protected void setEncodedStringValues(EncodedStringValue[] value, int field) { - /** - * Check whether this field can be set for specific - * header and check validity of the field. - */ - if (null == value) { - throw new NullPointerException(); - } - - switch (field) { - case BCC: - case CC: - case TO: - break; - default: - // This header value should not be Encoded-String-Value. - throw new RuntimeException("Invalid header field!"); - } - - ArrayList<EncodedStringValue> list = new ArrayList<EncodedStringValue>(); - for (int i = 0; i < value.length; i++) { - list.add(value[i]); - } - mHeaderMap.put(field, list); - } - - /** - * Append one EncodedStringValue to another. - * - * @param value the EncodedStringValue to append - * @param field the field - * @throws NullPointerException if the value is null. - */ - protected void appendEncodedStringValue(EncodedStringValue value, - int field) { - if (null == value) { - throw new NullPointerException(); - } - - switch (field) { - case BCC: - case CC: - case TO: - break; - default: - throw new RuntimeException("Invalid header field!"); - } - - ArrayList<EncodedStringValue> list = - (ArrayList<EncodedStringValue>) mHeaderMap.get(field); - if (null == list) { - list = new ArrayList<EncodedStringValue>(); - } - list.add(value); - mHeaderMap.put(field, list); - } - - /** - * Get LongInteger value by header field. - * - * @param field the field - * @return the LongInteger value of the pdu header - * with specified header field. if return -1, the - * field is not existed in pdu header. - */ - protected long getLongInteger(int field) { - Long longInteger = (Long) mHeaderMap.get(field); - if (null == longInteger) { - return -1; - } - - return longInteger.longValue(); - } - - /** - * Set LongInteger value to pdu header by header field. - * - * @param value the value - * @param field the field - */ - protected void setLongInteger(long value, int field) { - /** - * Check whether this field can be set for specific - * header and check validity of the field. - */ - switch (field) { - case DATE: - case REPLY_CHARGING_SIZE: - case MESSAGE_SIZE: - case MESSAGE_COUNT: - case START: - case LIMIT: - case DELIVERY_TIME: - case EXPIRY: - case REPLY_CHARGING_DEADLINE: - case PREVIOUSLY_SENT_DATE: - break; - default: - // This header value should not be LongInteger. - throw new RuntimeException("Invalid header field!"); - } - mHeaderMap.put(field, value); - } -} diff --git a/core/java/com/google/android/mms/pdu/PduParser.java b/core/java/com/google/android/mms/pdu/PduParser.java deleted file mode 100755 index 015d864..0000000 --- a/core/java/com/google/android/mms/pdu/PduParser.java +++ /dev/null @@ -1,1912 +0,0 @@ -/* - * Copyright (C) 2007-2008 Esmertec AG. - * Copyright (C) 2007-2008 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.mms.pdu; - -import com.google.android.mms.ContentType; -import com.google.android.mms.InvalidHeaderValueException; - -import android.util.Log; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.UnsupportedEncodingException; -import java.util.Arrays; -import java.util.HashMap; - -import android.content.res.Resources; - -public class PduParser { - /** - * The next are WAP values defined in WSP specification. - */ - private static final int QUOTE = 127; - private static final int LENGTH_QUOTE = 31; - private static final int TEXT_MIN = 32; - private static final int TEXT_MAX = 127; - private static final int SHORT_INTEGER_MAX = 127; - private static final int SHORT_LENGTH_MAX = 30; - private static final int LONG_INTEGER_LENGTH_MAX = 8; - private static final int QUOTED_STRING_FLAG = 34; - private static final int END_STRING_FLAG = 0x00; - //The next two are used by the interface "parseWapString" to - //distinguish Text-String and Quoted-String. - private static final int TYPE_TEXT_STRING = 0; - private static final int TYPE_QUOTED_STRING = 1; - private static final int TYPE_TOKEN_STRING = 2; - - /** - * Specify the part position. - */ - private static final int THE_FIRST_PART = 0; - private static final int THE_LAST_PART = 1; - - /** - * The pdu data. - */ - private ByteArrayInputStream mPduDataStream = null; - - /** - * Store pdu headers - */ - private PduHeaders mHeaders = null; - - /** - * Store pdu parts. - */ - private PduBody mBody = null; - - /** - * Store the "type" parameter in "Content-Type" header field. - */ - private static byte[] mTypeParam = null; - - /** - * Store the "start" parameter in "Content-Type" header field. - */ - private static byte[] mStartParam = null; - - /** - * The log tag. - */ - private static final String LOG_TAG = "PduParser"; - private static final boolean DEBUG = false; - private static final boolean LOCAL_LOGV = false; - - /** - * Constructor. - * - * @param pduDataStream pdu data to be parsed - */ - public PduParser(byte[] pduDataStream) { - mPduDataStream = new ByteArrayInputStream(pduDataStream); - } - - /** - * Parse the pdu. - * - * @return the pdu structure if parsing successfully. - * null if parsing error happened or mandatory fields are not set. - */ - public GenericPdu parse(){ - if (mPduDataStream == null) { - return null; - } - - /* parse headers */ - mHeaders = parseHeaders(mPduDataStream); - if (null == mHeaders) { - // Parse headers failed. - return null; - } - - /* get the message type */ - int messageType = mHeaders.getOctet(PduHeaders.MESSAGE_TYPE); - - /* check mandatory header fields */ - if (false == checkMandatoryHeader(mHeaders)) { - log("check mandatory headers failed!"); - return null; - } - - if ((PduHeaders.MESSAGE_TYPE_SEND_REQ == messageType) || - (PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF == messageType)) { - /* need to parse the parts */ - mBody = parseParts(mPduDataStream); - if (null == mBody) { - // Parse parts failed. - return null; - } - } - - switch (messageType) { - case PduHeaders.MESSAGE_TYPE_SEND_REQ: - SendReq sendReq = new SendReq(mHeaders, mBody); - return sendReq; - case PduHeaders.MESSAGE_TYPE_SEND_CONF: - SendConf sendConf = new SendConf(mHeaders); - return sendConf; - case PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND: - NotificationInd notificationInd = - new NotificationInd(mHeaders); - return notificationInd; - case PduHeaders.MESSAGE_TYPE_NOTIFYRESP_IND: - NotifyRespInd notifyRespInd = - new NotifyRespInd(mHeaders); - return notifyRespInd; - case PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF: - RetrieveConf retrieveConf = - new RetrieveConf(mHeaders, mBody); - - byte[] contentType = retrieveConf.getContentType(); - if (null == contentType) { - return null; - } - String ctTypeStr = new String(contentType); - if (ctTypeStr.equals(ContentType.MULTIPART_MIXED) - || ctTypeStr.equals(ContentType.MULTIPART_RELATED) - || ctTypeStr.equals(ContentType.MULTIPART_ALTERNATIVE)) { - // The MMS content type must be "application/vnd.wap.multipart.mixed" - // or "application/vnd.wap.multipart.related" - // or "application/vnd.wap.multipart.alternative" - return retrieveConf; - } else if (ctTypeStr.equals(ContentType.MULTIPART_ALTERNATIVE)) { - // "application/vnd.wap.multipart.alternative" - // should take only the first part. - PduPart firstPart = mBody.getPart(0); - mBody.removeAll(); - mBody.addPart(0, firstPart); - return retrieveConf; - } - return null; - case PduHeaders.MESSAGE_TYPE_DELIVERY_IND: - DeliveryInd deliveryInd = - new DeliveryInd(mHeaders); - return deliveryInd; - case PduHeaders.MESSAGE_TYPE_ACKNOWLEDGE_IND: - AcknowledgeInd acknowledgeInd = - new AcknowledgeInd(mHeaders); - return acknowledgeInd; - case PduHeaders.MESSAGE_TYPE_READ_ORIG_IND: - ReadOrigInd readOrigInd = - new ReadOrigInd(mHeaders); - return readOrigInd; - case PduHeaders.MESSAGE_TYPE_READ_REC_IND: - ReadRecInd readRecInd = - new ReadRecInd(mHeaders); - return readRecInd; - default: - log("Parser doesn't support this message type in this version!"); - return null; - } - } - - /** - * Parse pdu headers. - * - * @param pduDataStream pdu data input stream - * @return headers in PduHeaders structure, null when parse fail - */ - protected PduHeaders parseHeaders(ByteArrayInputStream pduDataStream){ - if (pduDataStream == null) { - return null; - } - - boolean keepParsing = true; - PduHeaders headers = new PduHeaders(); - - while (keepParsing && (pduDataStream.available() > 0)) { - pduDataStream.mark(1); - int headerField = extractByteValue(pduDataStream); - /* parse custom text header */ - if ((headerField >= TEXT_MIN) && (headerField <= TEXT_MAX)) { - pduDataStream.reset(); - byte [] bVal = parseWapString(pduDataStream, TYPE_TEXT_STRING); - if (LOCAL_LOGV) { - Log.v(LOG_TAG, "TextHeader: " + new String(bVal)); - } - /* we should ignore it at the moment */ - continue; - } - switch (headerField) { - case PduHeaders.MESSAGE_TYPE: - { - int messageType = extractByteValue(pduDataStream); - switch (messageType) { - // We don't support these kind of messages now. - case PduHeaders.MESSAGE_TYPE_FORWARD_REQ: - case PduHeaders.MESSAGE_TYPE_FORWARD_CONF: - case PduHeaders.MESSAGE_TYPE_MBOX_STORE_REQ: - case PduHeaders.MESSAGE_TYPE_MBOX_STORE_CONF: - case PduHeaders.MESSAGE_TYPE_MBOX_VIEW_REQ: - case PduHeaders.MESSAGE_TYPE_MBOX_VIEW_CONF: - case PduHeaders.MESSAGE_TYPE_MBOX_UPLOAD_REQ: - case PduHeaders.MESSAGE_TYPE_MBOX_UPLOAD_CONF: - case PduHeaders.MESSAGE_TYPE_MBOX_DELETE_REQ: - case PduHeaders.MESSAGE_TYPE_MBOX_DELETE_CONF: - case PduHeaders.MESSAGE_TYPE_MBOX_DESCR: - case PduHeaders.MESSAGE_TYPE_DELETE_REQ: - case PduHeaders.MESSAGE_TYPE_DELETE_CONF: - case PduHeaders.MESSAGE_TYPE_CANCEL_REQ: - case PduHeaders.MESSAGE_TYPE_CANCEL_CONF: - return null; - } - try { - headers.setOctet(messageType, headerField); - } catch(InvalidHeaderValueException e) { - log("Set invalid Octet value: " + messageType + - " into the header filed: " + headerField); - return null; - } catch(RuntimeException e) { - log(headerField + "is not Octet header field!"); - return null; - } - break; - } - /* Octect value */ - case PduHeaders.REPORT_ALLOWED: - case PduHeaders.ADAPTATION_ALLOWED: - case PduHeaders.DELIVERY_REPORT: - case PduHeaders.DRM_CONTENT: - case PduHeaders.DISTRIBUTION_INDICATOR: - case PduHeaders.QUOTAS: - case PduHeaders.READ_REPORT: - case PduHeaders.STORE: - case PduHeaders.STORED: - case PduHeaders.TOTALS: - case PduHeaders.SENDER_VISIBILITY: - case PduHeaders.READ_STATUS: - case PduHeaders.CANCEL_STATUS: - case PduHeaders.PRIORITY: - case PduHeaders.STATUS: - case PduHeaders.REPLY_CHARGING: - case PduHeaders.MM_STATE: - case PduHeaders.RECOMMENDED_RETRIEVAL_MODE: - case PduHeaders.CONTENT_CLASS: - case PduHeaders.RETRIEVE_STATUS: - case PduHeaders.STORE_STATUS: - /** - * The following field has a different value when - * used in the M-Mbox-Delete.conf and M-Delete.conf PDU. - * For now we ignore this fact, since we do not support these PDUs - */ - case PduHeaders.RESPONSE_STATUS: - { - int value = extractByteValue(pduDataStream); - - try { - headers.setOctet(value, headerField); - } catch(InvalidHeaderValueException e) { - log("Set invalid Octet value: " + value + - " into the header filed: " + headerField); - return null; - } catch(RuntimeException e) { - log(headerField + "is not Octet header field!"); - return null; - } - break; - } - - /* Long-Integer */ - case PduHeaders.DATE: - case PduHeaders.REPLY_CHARGING_SIZE: - case PduHeaders.MESSAGE_SIZE: - { - try { - long value = parseLongInteger(pduDataStream); - headers.setLongInteger(value, headerField); - } catch(RuntimeException e) { - log(headerField + "is not Long-Integer header field!"); - return null; - } - break; - } - - /* Integer-Value */ - case PduHeaders.MESSAGE_COUNT: - case PduHeaders.START: - case PduHeaders.LIMIT: - { - try { - long value = parseIntegerValue(pduDataStream); - headers.setLongInteger(value, headerField); - } catch(RuntimeException e) { - log(headerField + "is not Long-Integer header field!"); - return null; - } - break; - } - - /* Text-String */ - case PduHeaders.TRANSACTION_ID: - case PduHeaders.REPLY_CHARGING_ID: - case PduHeaders.AUX_APPLIC_ID: - case PduHeaders.APPLIC_ID: - case PduHeaders.REPLY_APPLIC_ID: - /** - * The next three header fields are email addresses - * as defined in RFC2822, - * not including the characters "<" and ">" - */ - case PduHeaders.MESSAGE_ID: - case PduHeaders.REPLACE_ID: - case PduHeaders.CANCEL_ID: - /** - * The following field has a different value when - * used in the M-Mbox-Delete.conf and M-Delete.conf PDU. - * For now we ignore this fact, since we do not support these PDUs - */ - case PduHeaders.CONTENT_LOCATION: - { - byte[] value = parseWapString(pduDataStream, TYPE_TEXT_STRING); - if (null != value) { - try { - headers.setTextString(value, headerField); - } catch(NullPointerException e) { - log("null pointer error!"); - } catch(RuntimeException e) { - log(headerField + "is not Text-String header field!"); - return null; - } - } - break; - } - - /* Encoded-string-value */ - case PduHeaders.SUBJECT: - case PduHeaders.RECOMMENDED_RETRIEVAL_MODE_TEXT: - case PduHeaders.RETRIEVE_TEXT: - case PduHeaders.STATUS_TEXT: - case PduHeaders.STORE_STATUS_TEXT: - /* the next one is not support - * M-Mbox-Delete.conf and M-Delete.conf now */ - case PduHeaders.RESPONSE_TEXT: - { - EncodedStringValue value = - parseEncodedStringValue(pduDataStream); - if (null != value) { - try { - headers.setEncodedStringValue(value, headerField); - } catch(NullPointerException e) { - log("null pointer error!"); - } catch (RuntimeException e) { - log(headerField + "is not Encoded-String-Value header field!"); - return null; - } - } - break; - } - - /* Addressing model */ - case PduHeaders.BCC: - case PduHeaders.CC: - case PduHeaders.TO: - { - EncodedStringValue value = - parseEncodedStringValue(pduDataStream); - if (null != value) { - byte[] address = value.getTextString(); - if (null != address) { - String str = new String(address); - int endIndex = str.indexOf("/"); - if (endIndex > 0) { - str = str.substring(0, endIndex); - } - try { - value.setTextString(str.getBytes()); - } catch(NullPointerException e) { - log("null pointer error!"); - return null; - } - } - - try { - headers.appendEncodedStringValue(value, headerField); - } catch(NullPointerException e) { - log("null pointer error!"); - } catch(RuntimeException e) { - log(headerField + "is not Encoded-String-Value header field!"); - return null; - } - } - break; - } - - /* Value-length - * (Absolute-token Date-value | Relative-token Delta-seconds-value) */ - case PduHeaders.DELIVERY_TIME: - case PduHeaders.EXPIRY: - case PduHeaders.REPLY_CHARGING_DEADLINE: - { - /* parse Value-length */ - parseValueLength(pduDataStream); - - /* Absolute-token or Relative-token */ - int token = extractByteValue(pduDataStream); - - /* Date-value or Delta-seconds-value */ - long timeValue; - try { - timeValue = parseLongInteger(pduDataStream); - } catch(RuntimeException e) { - log(headerField + "is not Long-Integer header field!"); - return null; - } - if (PduHeaders.VALUE_RELATIVE_TOKEN == token) { - /* need to convert the Delta-seconds-value - * into Date-value */ - timeValue = System.currentTimeMillis()/1000 + timeValue; - } - - try { - headers.setLongInteger(timeValue, headerField); - } catch(RuntimeException e) { - log(headerField + "is not Long-Integer header field!"); - return null; - } - break; - } - - case PduHeaders.FROM: { - /* From-value = - * Value-length - * (Address-present-token Encoded-string-value | Insert-address-token) - */ - EncodedStringValue from = null; - parseValueLength(pduDataStream); /* parse value-length */ - - /* Address-present-token or Insert-address-token */ - int fromToken = extractByteValue(pduDataStream); - - /* Address-present-token or Insert-address-token */ - if (PduHeaders.FROM_ADDRESS_PRESENT_TOKEN == fromToken) { - /* Encoded-string-value */ - from = parseEncodedStringValue(pduDataStream); - if (null != from) { - byte[] address = from.getTextString(); - if (null != address) { - String str = new String(address); - int endIndex = str.indexOf("/"); - if (endIndex > 0) { - str = str.substring(0, endIndex); - } - try { - from.setTextString(str.getBytes()); - } catch(NullPointerException e) { - log("null pointer error!"); - return null; - } - } - } - } else { - try { - from = new EncodedStringValue( - PduHeaders.FROM_INSERT_ADDRESS_TOKEN_STR.getBytes()); - } catch(NullPointerException e) { - log(headerField + "is not Encoded-String-Value header field!"); - return null; - } - } - - try { - headers.setEncodedStringValue(from, PduHeaders.FROM); - } catch(NullPointerException e) { - log("null pointer error!"); - } catch(RuntimeException e) { - log(headerField + "is not Encoded-String-Value header field!"); - return null; - } - break; - } - - case PduHeaders.MESSAGE_CLASS: { - /* Message-class-value = Class-identifier | Token-text */ - pduDataStream.mark(1); - int messageClass = extractByteValue(pduDataStream); - - if (messageClass >= PduHeaders.MESSAGE_CLASS_PERSONAL) { - /* Class-identifier */ - try { - if (PduHeaders.MESSAGE_CLASS_PERSONAL == messageClass) { - headers.setTextString( - PduHeaders.MESSAGE_CLASS_PERSONAL_STR.getBytes(), - PduHeaders.MESSAGE_CLASS); - } else if (PduHeaders.MESSAGE_CLASS_ADVERTISEMENT == messageClass) { - headers.setTextString( - PduHeaders.MESSAGE_CLASS_ADVERTISEMENT_STR.getBytes(), - PduHeaders.MESSAGE_CLASS); - } else if (PduHeaders.MESSAGE_CLASS_INFORMATIONAL == messageClass) { - headers.setTextString( - PduHeaders.MESSAGE_CLASS_INFORMATIONAL_STR.getBytes(), - PduHeaders.MESSAGE_CLASS); - } else if (PduHeaders.MESSAGE_CLASS_AUTO == messageClass) { - headers.setTextString( - PduHeaders.MESSAGE_CLASS_AUTO_STR.getBytes(), - PduHeaders.MESSAGE_CLASS); - } - } catch(NullPointerException e) { - log("null pointer error!"); - } catch(RuntimeException e) { - log(headerField + "is not Text-String header field!"); - return null; - } - } else { - /* Token-text */ - pduDataStream.reset(); - byte[] messageClassString = parseWapString(pduDataStream, TYPE_TEXT_STRING); - if (null != messageClassString) { - try { - headers.setTextString(messageClassString, PduHeaders.MESSAGE_CLASS); - } catch(NullPointerException e) { - log("null pointer error!"); - } catch(RuntimeException e) { - log(headerField + "is not Text-String header field!"); - return null; - } - } - } - break; - } - - case PduHeaders.MMS_VERSION: { - int version = parseShortInteger(pduDataStream); - - try { - headers.setOctet(version, PduHeaders.MMS_VERSION); - } catch(InvalidHeaderValueException e) { - log("Set invalid Octet value: " + version + - " into the header filed: " + headerField); - return null; - } catch(RuntimeException e) { - log(headerField + "is not Octet header field!"); - return null; - } - break; - } - - case PduHeaders.PREVIOUSLY_SENT_BY: { - /* Previously-sent-by-value = - * Value-length Forwarded-count-value Encoded-string-value */ - /* parse value-length */ - parseValueLength(pduDataStream); - - /* parse Forwarded-count-value */ - try { - parseIntegerValue(pduDataStream); - } catch(RuntimeException e) { - log(headerField + " is not Integer-Value"); - return null; - } - - /* parse Encoded-string-value */ - EncodedStringValue previouslySentBy = - parseEncodedStringValue(pduDataStream); - if (null != previouslySentBy) { - try { - headers.setEncodedStringValue(previouslySentBy, - PduHeaders.PREVIOUSLY_SENT_BY); - } catch(NullPointerException e) { - log("null pointer error!"); - } catch(RuntimeException e) { - log(headerField + "is not Encoded-String-Value header field!"); - return null; - } - } - break; - } - - case PduHeaders.PREVIOUSLY_SENT_DATE: { - /* Previously-sent-date-value = - * Value-length Forwarded-count-value Date-value */ - /* parse value-length */ - parseValueLength(pduDataStream); - - /* parse Forwarded-count-value */ - try { - parseIntegerValue(pduDataStream); - } catch(RuntimeException e) { - log(headerField + " is not Integer-Value"); - return null; - } - - /* Date-value */ - try { - long perviouslySentDate = parseLongInteger(pduDataStream); - headers.setLongInteger(perviouslySentDate, - PduHeaders.PREVIOUSLY_SENT_DATE); - } catch(RuntimeException e) { - log(headerField + "is not Long-Integer header field!"); - return null; - } - break; - } - - case PduHeaders.MM_FLAGS: { - /* MM-flags-value = - * Value-length - * ( Add-token | Remove-token | Filter-token ) - * Encoded-string-value - */ - - /* parse Value-length */ - parseValueLength(pduDataStream); - - /* Add-token | Remove-token | Filter-token */ - extractByteValue(pduDataStream); - - /* Encoded-string-value */ - parseEncodedStringValue(pduDataStream); - - /* not store this header filed in "headers", - * because now PduHeaders doesn't support it */ - break; - } - - /* Value-length - * (Message-total-token | Size-total-token) Integer-Value */ - case PduHeaders.MBOX_TOTALS: - case PduHeaders.MBOX_QUOTAS: - { - /* Value-length */ - parseValueLength(pduDataStream); - - /* Message-total-token | Size-total-token */ - extractByteValue(pduDataStream); - - /*Integer-Value*/ - try { - parseIntegerValue(pduDataStream); - } catch(RuntimeException e) { - log(headerField + " is not Integer-Value"); - return null; - } - - /* not store these headers filed in "headers", - because now PduHeaders doesn't support them */ - break; - } - - case PduHeaders.ELEMENT_DESCRIPTOR: { - parseContentType(pduDataStream, null); - - /* not store this header filed in "headers", - because now PduHeaders doesn't support it */ - break; - } - - case PduHeaders.CONTENT_TYPE: { - HashMap<Integer, Object> map = - new HashMap<Integer, Object>(); - byte[] contentType = - parseContentType(pduDataStream, map); - - if (null != contentType) { - try { - headers.setTextString(contentType, PduHeaders.CONTENT_TYPE); - } catch(NullPointerException e) { - log("null pointer error!"); - } catch(RuntimeException e) { - log(headerField + "is not Text-String header field!"); - return null; - } - } - - /* get start parameter */ - mStartParam = (byte[]) map.get(PduPart.P_START); - - /* get charset parameter */ - mTypeParam= (byte[]) map.get(PduPart.P_TYPE); - - keepParsing = false; - break; - } - - case PduHeaders.CONTENT: - case PduHeaders.ADDITIONAL_HEADERS: - case PduHeaders.ATTRIBUTES: - default: { - log("Unknown header"); - } - } - } - - return headers; - } - - /** - * Parse pdu parts. - * - * @param pduDataStream pdu data input stream - * @return parts in PduBody structure - */ - protected static PduBody parseParts(ByteArrayInputStream pduDataStream) { - if (pduDataStream == null) { - return null; - } - - int count = parseUnsignedInt(pduDataStream); // get the number of parts - PduBody body = new PduBody(); - - for (int i = 0 ; i < count ; i++) { - int headerLength = parseUnsignedInt(pduDataStream); - int dataLength = parseUnsignedInt(pduDataStream); - PduPart part = new PduPart(); - int startPos = pduDataStream.available(); - if (startPos <= 0) { - // Invalid part. - return null; - } - - /* parse part's content-type */ - HashMap<Integer, Object> map = new HashMap<Integer, Object>(); - byte[] contentType = parseContentType(pduDataStream, map); - if (null != contentType) { - part.setContentType(contentType); - } else { - part.setContentType((PduContentTypes.contentTypes[0]).getBytes()); //"*/*" - } - - /* get name parameter */ - byte[] name = (byte[]) map.get(PduPart.P_NAME); - if (null != name) { - part.setName(name); - } - - /* get charset parameter */ - Integer charset = (Integer) map.get(PduPart.P_CHARSET); - if (null != charset) { - part.setCharset(charset); - } - - /* parse part's headers */ - int endPos = pduDataStream.available(); - int partHeaderLen = headerLength - (startPos - endPos); - if (partHeaderLen > 0) { - if (false == parsePartHeaders(pduDataStream, part, partHeaderLen)) { - // Parse part header faild. - return null; - } - } else if (partHeaderLen < 0) { - // Invalid length of content-type. - return null; - } - - /* FIXME: check content-id, name, filename and content location, - * if not set anyone of them, generate a default content-location - */ - if ((null == part.getContentLocation()) - && (null == part.getName()) - && (null == part.getFilename()) - && (null == part.getContentId())) { - part.setContentLocation(Long.toOctalString( - System.currentTimeMillis()).getBytes()); - } - - /* get part's data */ - if (dataLength > 0) { - byte[] partData = new byte[dataLength]; - String partContentType = new String(part.getContentType()); - pduDataStream.read(partData, 0, dataLength); - if (partContentType.equalsIgnoreCase(ContentType.MULTIPART_ALTERNATIVE)) { - // parse "multipart/vnd.wap.multipart.alternative". - PduBody childBody = parseParts(new ByteArrayInputStream(partData)); - // take the first part of children. - part = childBody.getPart(0); - } else { - // Check Content-Transfer-Encoding. - byte[] partDataEncoding = part.getContentTransferEncoding(); - if (null != partDataEncoding) { - String encoding = new String(partDataEncoding); - if (encoding.equalsIgnoreCase(PduPart.P_BASE64)) { - // Decode "base64" into "binary". - partData = Base64.decodeBase64(partData); - } else if (encoding.equalsIgnoreCase(PduPart.P_QUOTED_PRINTABLE)) { - // Decode "quoted-printable" into "binary". - partData = QuotedPrintable.decodeQuotedPrintable(partData); - } else { - // "binary" is the default encoding. - } - } - if (null == partData) { - log("Decode part data error!"); - return null; - } - part.setData(partData); - } - } - - /* add this part to body */ - if (THE_FIRST_PART == checkPartPosition(part)) { - /* this is the first part */ - body.addPart(0, part); - } else { - /* add the part to the end */ - body.addPart(part); - } - } - - return body; - } - - /** - * Log status. - * - * @param text log information - */ - private static void log(String text) { - if (LOCAL_LOGV) { - Log.v(LOG_TAG, text); - } - } - - /** - * Parse unsigned integer. - * - * @param pduDataStream pdu data input stream - * @return the integer, -1 when failed - */ - protected static int parseUnsignedInt(ByteArrayInputStream pduDataStream) { - /** - * From wap-230-wsp-20010705-a.pdf - * The maximum size of a uintvar is 32 bits. - * So it will be encoded in no more than 5 octets. - */ - assert(null != pduDataStream); - int result = 0; - int temp = pduDataStream.read(); - if (temp == -1) { - return temp; - } - - while((temp & 0x80) != 0) { - result = result << 7; - result |= temp & 0x7F; - temp = pduDataStream.read(); - if (temp == -1) { - return temp; - } - } - - result = result << 7; - result |= temp & 0x7F; - - return result; - } - - /** - * Parse value length. - * - * @param pduDataStream pdu data input stream - * @return the integer - */ - protected static int parseValueLength(ByteArrayInputStream pduDataStream) { - /** - * From wap-230-wsp-20010705-a.pdf - * Value-length = Short-length | (Length-quote Length) - * Short-length = <Any octet 0-30> - * Length-quote = <Octet 31> - * Length = Uintvar-integer - * Uintvar-integer = 1*5 OCTET - */ - assert(null != pduDataStream); - int temp = pduDataStream.read(); - assert(-1 != temp); - int first = temp & 0xFF; - - if (first <= SHORT_LENGTH_MAX) { - return first; - } else if (first == LENGTH_QUOTE) { - return parseUnsignedInt(pduDataStream); - } - - throw new RuntimeException ("Value length > LENGTH_QUOTE!"); - } - - /** - * Parse encoded string value. - * - * @param pduDataStream pdu data input stream - * @return the EncodedStringValue - */ - protected static EncodedStringValue parseEncodedStringValue(ByteArrayInputStream pduDataStream){ - /** - * From OMA-TS-MMS-ENC-V1_3-20050927-C.pdf - * Encoded-string-value = Text-string | Value-length Char-set Text-string - */ - assert(null != pduDataStream); - pduDataStream.mark(1); - EncodedStringValue returnValue = null; - int charset = 0; - int temp = pduDataStream.read(); - assert(-1 != temp); - int first = temp & 0xFF; - if (first == 0) { - return null; // Blank subject, bail. - } - - pduDataStream.reset(); - if (first < TEXT_MIN) { - parseValueLength(pduDataStream); - - charset = parseShortInteger(pduDataStream); //get the "Charset" - } - - byte[] textString = parseWapString(pduDataStream, TYPE_TEXT_STRING); - - try { - if (0 != charset) { - returnValue = new EncodedStringValue(charset, textString); - } else { - returnValue = new EncodedStringValue(textString); - } - } catch(Exception e) { - return null; - } - - return returnValue; - } - - /** - * Parse Text-String or Quoted-String. - * - * @param pduDataStream pdu data input stream - * @param stringType TYPE_TEXT_STRING or TYPE_QUOTED_STRING - * @return the string without End-of-string in byte array - */ - protected static byte[] parseWapString(ByteArrayInputStream pduDataStream, - int stringType) { - assert(null != pduDataStream); - /** - * From wap-230-wsp-20010705-a.pdf - * Text-string = [Quote] *TEXT End-of-string - * If the first character in the TEXT is in the range of 128-255, - * a Quote character must precede it. - * Otherwise the Quote character must be omitted. - * The Quote is not part of the contents. - * Quote = <Octet 127> - * End-of-string = <Octet 0> - * - * Quoted-string = <Octet 34> *TEXT End-of-string - * - * Token-text = Token End-of-string - */ - - // Mark supposed beginning of Text-string - // We will have to mark again if first char is QUOTE or QUOTED_STRING_FLAG - pduDataStream.mark(1); - - // Check first char - int temp = pduDataStream.read(); - assert(-1 != temp); - if ((TYPE_QUOTED_STRING == stringType) && - (QUOTED_STRING_FLAG == temp)) { - // Mark again if QUOTED_STRING_FLAG and ignore it - pduDataStream.mark(1); - } else if ((TYPE_TEXT_STRING == stringType) && - (QUOTE == temp)) { - // Mark again if QUOTE and ignore it - pduDataStream.mark(1); - } else { - // Otherwise go back to origin - pduDataStream.reset(); - } - - // We are now definitely at the beginning of string - /** - * Return *TOKEN or *TEXT (Text-String without QUOTE, - * Quoted-String without QUOTED_STRING_FLAG and without End-of-string) - */ - return getWapString(pduDataStream, stringType); - } - - /** - * Check TOKEN data defined in RFC2616. - * @param ch checking data - * @return true when ch is TOKEN, false when ch is not TOKEN - */ - protected static boolean isTokenCharacter(int ch) { - /** - * Token = 1*<any CHAR except CTLs or separators> - * separators = "("(40) | ")"(41) | "<"(60) | ">"(62) | "@"(64) - * | ","(44) | ";"(59) | ":"(58) | "\"(92) | <">(34) - * | "/"(47) | "["(91) | "]"(93) | "?"(63) | "="(61) - * | "{"(123) | "}"(125) | SP(32) | HT(9) - * CHAR = <any US-ASCII character (octets 0 - 127)> - * CTL = <any US-ASCII control character - * (octets 0 - 31) and DEL (127)> - * SP = <US-ASCII SP, space (32)> - * HT = <US-ASCII HT, horizontal-tab (9)> - */ - if((ch < 33) || (ch > 126)) { - return false; - } - - switch(ch) { - case '"': /* '"' */ - case '(': /* '(' */ - case ')': /* ')' */ - case ',': /* ',' */ - case '/': /* '/' */ - case ':': /* ':' */ - case ';': /* ';' */ - case '<': /* '<' */ - case '=': /* '=' */ - case '>': /* '>' */ - case '?': /* '?' */ - case '@': /* '@' */ - case '[': /* '[' */ - case '\\': /* '\' */ - case ']': /* ']' */ - case '{': /* '{' */ - case '}': /* '}' */ - return false; - } - - return true; - } - - /** - * Check TEXT data defined in RFC2616. - * @param ch checking data - * @return true when ch is TEXT, false when ch is not TEXT - */ - protected static boolean isText(int ch) { - /** - * TEXT = <any OCTET except CTLs, - * but including LWS> - * CTL = <any US-ASCII control character - * (octets 0 - 31) and DEL (127)> - * LWS = [CRLF] 1*( SP | HT ) - * CRLF = CR LF - * CR = <US-ASCII CR, carriage return (13)> - * LF = <US-ASCII LF, linefeed (10)> - */ - if(((ch >= 32) && (ch <= 126)) || ((ch >= 128) && (ch <= 255))) { - return true; - } - - switch(ch) { - case '\t': /* '\t' */ - case '\n': /* '\n' */ - case '\r': /* '\r' */ - return true; - } - - return false; - } - - protected static byte[] getWapString(ByteArrayInputStream pduDataStream, - int stringType) { - assert(null != pduDataStream); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - int temp = pduDataStream.read(); - assert(-1 != temp); - while((-1 != temp) && ('\0' != temp)) { - // check each of the character - if (stringType == TYPE_TOKEN_STRING) { - if (isTokenCharacter(temp)) { - out.write(temp); - } - } else { - if (isText(temp)) { - out.write(temp); - } - } - - temp = pduDataStream.read(); - assert(-1 != temp); - } - - if (out.size() > 0) { - return out.toByteArray(); - } - - return null; - } - - /** - * Extract a byte value from the input stream. - * - * @param pduDataStream pdu data input stream - * @return the byte - */ - protected static int extractByteValue(ByteArrayInputStream pduDataStream) { - assert(null != pduDataStream); - int temp = pduDataStream.read(); - assert(-1 != temp); - return temp & 0xFF; - } - - /** - * Parse Short-Integer. - * - * @param pduDataStream pdu data input stream - * @return the byte - */ - protected static int parseShortInteger(ByteArrayInputStream pduDataStream) { - /** - * From wap-230-wsp-20010705-a.pdf - * Short-integer = OCTET - * Integers in range 0-127 shall be encoded as a one - * octet value with the most significant bit set to one (1xxx xxxx) - * and with the value in the remaining least significant bits. - */ - assert(null != pduDataStream); - int temp = pduDataStream.read(); - assert(-1 != temp); - return temp & 0x7F; - } - - /** - * Parse Long-Integer. - * - * @param pduDataStream pdu data input stream - * @return long integer - */ - protected static long parseLongInteger(ByteArrayInputStream pduDataStream) { - /** - * From wap-230-wsp-20010705-a.pdf - * Long-integer = Short-length Multi-octet-integer - * The Short-length indicates the length of the Multi-octet-integer - * Multi-octet-integer = 1*30 OCTET - * The content octets shall be an unsigned integer value - * with the most significant octet encoded first (big-endian representation). - * The minimum number of octets must be used to encode the value. - * Short-length = <Any octet 0-30> - */ - assert(null != pduDataStream); - int temp = pduDataStream.read(); - assert(-1 != temp); - int count = temp & 0xFF; - - if (count > LONG_INTEGER_LENGTH_MAX) { - throw new RuntimeException("Octet count greater than 8 and I can't represent that!"); - } - - long result = 0; - - for (int i = 0 ; i < count ; i++) { - temp = pduDataStream.read(); - assert(-1 != temp); - result <<= 8; - result += (temp & 0xFF); - } - - return result; - } - - /** - * Parse Integer-Value. - * - * @param pduDataStream pdu data input stream - * @return long integer - */ - protected static long parseIntegerValue(ByteArrayInputStream pduDataStream) { - /** - * From wap-230-wsp-20010705-a.pdf - * Integer-Value = Short-integer | Long-integer - */ - assert(null != pduDataStream); - pduDataStream.mark(1); - int temp = pduDataStream.read(); - assert(-1 != temp); - pduDataStream.reset(); - if (temp > SHORT_INTEGER_MAX) { - return parseShortInteger(pduDataStream); - } else { - return parseLongInteger(pduDataStream); - } - } - - /** - * To skip length of the wap value. - * - * @param pduDataStream pdu data input stream - * @param length area size - * @return the values in this area - */ - protected static int skipWapValue(ByteArrayInputStream pduDataStream, int length) { - assert(null != pduDataStream); - byte[] area = new byte[length]; - int readLen = pduDataStream.read(area, 0, length); - if (readLen < length) { //The actually read length is lower than the length - return -1; - } else { - return readLen; - } - } - - /** - * Parse content type parameters. For now we just support - * four parameters used in mms: "type", "start", "name", "charset". - * - * @param pduDataStream pdu data input stream - * @param map to store parameters of Content-Type field - * @param length length of all the parameters - */ - protected static void parseContentTypeParams(ByteArrayInputStream pduDataStream, - HashMap<Integer, Object> map, Integer length) { - /** - * From wap-230-wsp-20010705-a.pdf - * Parameter = Typed-parameter | Untyped-parameter - * Typed-parameter = Well-known-parameter-token Typed-value - * the actual expected type of the value is implied by the well-known parameter - * Well-known-parameter-token = Integer-value - * the code values used for parameters are specified in the Assigned Numbers appendix - * Typed-value = Compact-value | Text-value - * In addition to the expected type, there may be no value. - * If the value cannot be encoded using the expected type, it shall be encoded as text. - * Compact-value = Integer-value | - * Date-value | Delta-seconds-value | Q-value | Version-value | - * Uri-value - * Untyped-parameter = Token-text Untyped-value - * the type of the value is unknown, but it shall be encoded as an integer, - * if that is possible. - * Untyped-value = Integer-value | Text-value - */ - assert(null != pduDataStream); - assert(length > 0); - - int startPos = pduDataStream.available(); - int tempPos = 0; - int lastLen = length; - while(0 < lastLen) { - int param = pduDataStream.read(); - assert(-1 != param); - lastLen--; - - switch (param) { - /** - * From rfc2387, chapter 3.1 - * The type parameter must be specified and its value is the MIME media - * type of the "root" body part. It permits a MIME user agent to - * determine the content-type without reference to the enclosed body - * part. If the value of the type parameter and the root body part's - * content-type differ then the User Agent's behavior is undefined. - * - * From wap-230-wsp-20010705-a.pdf - * type = Constrained-encoding - * Constrained-encoding = Extension-Media | Short-integer - * Extension-media = *TEXT End-of-string - */ - case PduPart.P_TYPE: - case PduPart.P_CT_MR_TYPE: - pduDataStream.mark(1); - int first = extractByteValue(pduDataStream); - pduDataStream.reset(); - if (first > TEXT_MAX) { - // Short-integer (well-known type) - int index = parseShortInteger(pduDataStream); - - if (index < PduContentTypes.contentTypes.length) { - byte[] type = (PduContentTypes.contentTypes[index]).getBytes(); - map.put(PduPart.P_TYPE, type); - } else { - //not support this type, ignore it. - } - } else { - // Text-String (extension-media) - byte[] type = parseWapString(pduDataStream, TYPE_TEXT_STRING); - if ((null != type) && (null != map)) { - map.put(PduPart.P_TYPE, type); - } - } - - tempPos = pduDataStream.available(); - lastLen = length - (startPos - tempPos); - break; - - /** - * From oma-ts-mms-conf-v1_3.pdf, chapter 10.2.3. - * Start Parameter Referring to Presentation - * - * From rfc2387, chapter 3.2 - * The start parameter, if given, is the content-ID of the compound - * object's "root". If not present the "root" is the first body part in - * the Multipart/Related entity. The "root" is the element the - * applications processes first. - * - * From wap-230-wsp-20010705-a.pdf - * start = Text-String - */ - case PduPart.P_START: - case PduPart.P_DEP_START: - byte[] start = parseWapString(pduDataStream, TYPE_TEXT_STRING); - if ((null != start) && (null != map)) { - map.put(PduPart.P_START, start); - } - - tempPos = pduDataStream.available(); - lastLen = length - (startPos - tempPos); - break; - - /** - * From oma-ts-mms-conf-v1_3.pdf - * In creation, the character set SHALL be either us-ascii - * (IANA MIBenum 3) or utf-8 (IANA MIBenum 106)[Unicode]. - * In retrieval, both us-ascii and utf-8 SHALL be supported. - * - * From wap-230-wsp-20010705-a.pdf - * charset = Well-known-charset|Text-String - * Well-known-charset = Any-charset | Integer-value - * Both are encoded using values from Character Set - * Assignments table in Assigned Numbers - * Any-charset = <Octet 128> - * Equivalent to the special RFC2616 charset value "*" - */ - case PduPart.P_CHARSET: - pduDataStream.mark(1); - int firstValue = extractByteValue(pduDataStream); - pduDataStream.reset(); - //Check first char - if (((firstValue > TEXT_MIN) && (firstValue < TEXT_MAX)) || - (END_STRING_FLAG == firstValue)) { - //Text-String (extension-charset) - byte[] charsetStr = parseWapString(pduDataStream, TYPE_TEXT_STRING); - try { - int charsetInt = CharacterSets.getMibEnumValue( - new String(charsetStr)); - map.put(PduPart.P_CHARSET, charsetInt); - } catch (UnsupportedEncodingException e) { - // Not a well-known charset, use "*". - Log.e(LOG_TAG, Arrays.toString(charsetStr), e); - map.put(PduPart.P_CHARSET, CharacterSets.ANY_CHARSET); - } - } else { - //Well-known-charset - int charset = (int) parseIntegerValue(pduDataStream); - if (map != null) { - map.put(PduPart.P_CHARSET, charset); - } - } - - tempPos = pduDataStream.available(); - lastLen = length - (startPos - tempPos); - break; - - /** - * From oma-ts-mms-conf-v1_3.pdf - * A name for multipart object SHALL be encoded using name-parameter - * for Content-Type header in WSP multipart headers. - * - * From wap-230-wsp-20010705-a.pdf - * name = Text-String - */ - case PduPart.P_DEP_NAME: - case PduPart.P_NAME: - byte[] name = parseWapString(pduDataStream, TYPE_TEXT_STRING); - if ((null != name) && (null != map)) { - map.put(PduPart.P_NAME, name); - } - - tempPos = pduDataStream.available(); - lastLen = length - (startPos - tempPos); - break; - default: - if (LOCAL_LOGV) { - Log.v(LOG_TAG, "Not supported Content-Type parameter"); - } - if (-1 == skipWapValue(pduDataStream, lastLen)) { - Log.e(LOG_TAG, "Corrupt Content-Type"); - } else { - lastLen = 0; - } - break; - } - } - - if (0 != lastLen) { - Log.e(LOG_TAG, "Corrupt Content-Type"); - } - } - - /** - * Parse content type. - * - * @param pduDataStream pdu data input stream - * @param map to store parameters in Content-Type header field - * @return Content-Type value - */ - protected static byte[] parseContentType(ByteArrayInputStream pduDataStream, - HashMap<Integer, Object> map) { - /** - * From wap-230-wsp-20010705-a.pdf - * Content-type-value = Constrained-media | Content-general-form - * Content-general-form = Value-length Media-type - * Media-type = (Well-known-media | Extension-Media) *(Parameter) - */ - assert(null != pduDataStream); - - byte[] contentType = null; - pduDataStream.mark(1); - int temp = pduDataStream.read(); - assert(-1 != temp); - pduDataStream.reset(); - - int cur = (temp & 0xFF); - - if (cur < TEXT_MIN) { - int length = parseValueLength(pduDataStream); - int startPos = pduDataStream.available(); - pduDataStream.mark(1); - temp = pduDataStream.read(); - assert(-1 != temp); - pduDataStream.reset(); - int first = (temp & 0xFF); - - if ((first >= TEXT_MIN) && (first <= TEXT_MAX)) { - contentType = parseWapString(pduDataStream, TYPE_TEXT_STRING); - } else if (first > TEXT_MAX) { - int index = parseShortInteger(pduDataStream); - - if (index < PduContentTypes.contentTypes.length) { //well-known type - contentType = (PduContentTypes.contentTypes[index]).getBytes(); - } else { - pduDataStream.reset(); - contentType = parseWapString(pduDataStream, TYPE_TEXT_STRING); - } - } else { - Log.e(LOG_TAG, "Corrupt content-type"); - return (PduContentTypes.contentTypes[0]).getBytes(); //"*/*" - } - - int endPos = pduDataStream.available(); - int parameterLen = length - (startPos - endPos); - if (parameterLen > 0) {//have parameters - parseContentTypeParams(pduDataStream, map, parameterLen); - } - - if (parameterLen < 0) { - Log.e(LOG_TAG, "Corrupt MMS message"); - return (PduContentTypes.contentTypes[0]).getBytes(); //"*/*" - } - } else if (cur <= TEXT_MAX) { - contentType = parseWapString(pduDataStream, TYPE_TEXT_STRING); - } else { - contentType = - (PduContentTypes.contentTypes[parseShortInteger(pduDataStream)]).getBytes(); - } - - return contentType; - } - - /** - * Parse part's headers. - * - * @param pduDataStream pdu data input stream - * @param part to store the header informations of the part - * @param length length of the headers - * @return true if parse successfully, false otherwise - */ - protected static boolean parsePartHeaders(ByteArrayInputStream pduDataStream, - PduPart part, int length) { - assert(null != pduDataStream); - assert(null != part); - assert(length > 0); - - /** - * From oma-ts-mms-conf-v1_3.pdf, chapter 10.2. - * A name for multipart object SHALL be encoded using name-parameter - * for Content-Type header in WSP multipart headers. - * In decoding, name-parameter of Content-Type SHALL be used if available. - * If name-parameter of Content-Type is not available, - * filename parameter of Content-Disposition header SHALL be used if available. - * If neither name-parameter of Content-Type header nor filename parameter - * of Content-Disposition header is available, - * Content-Location header SHALL be used if available. - * - * Within SMIL part the reference to the media object parts SHALL use - * either Content-ID or Content-Location mechanism [RFC2557] - * and the corresponding WSP part headers in media object parts - * contain the corresponding definitions. - */ - int startPos = pduDataStream.available(); - int tempPos = 0; - int lastLen = length; - while(0 < lastLen) { - int header = pduDataStream.read(); - assert(-1 != header); - lastLen--; - - if (header > TEXT_MAX) { - // Number assigned headers. - switch (header) { - case PduPart.P_CONTENT_LOCATION: - /** - * From wap-230-wsp-20010705-a.pdf, chapter 8.4.2.21 - * Content-location-value = Uri-value - */ - byte[] contentLocation = parseWapString(pduDataStream, TYPE_TEXT_STRING); - if (null != contentLocation) { - part.setContentLocation(contentLocation); - } - - tempPos = pduDataStream.available(); - lastLen = length - (startPos - tempPos); - break; - case PduPart.P_CONTENT_ID: - /** - * From wap-230-wsp-20010705-a.pdf, chapter 8.4.2.21 - * Content-ID-value = Quoted-string - */ - byte[] contentId = parseWapString(pduDataStream, TYPE_QUOTED_STRING); - if (null != contentId) { - part.setContentId(contentId); - } - - tempPos = pduDataStream.available(); - lastLen = length - (startPos - tempPos); - break; - case PduPart.P_DEP_CONTENT_DISPOSITION: - case PduPart.P_CONTENT_DISPOSITION: - /** - * From wap-230-wsp-20010705-a.pdf, chapter 8.4.2.21 - * Content-disposition-value = Value-length Disposition *(Parameter) - * Disposition = Form-data | Attachment | Inline | Token-text - * Form-data = <Octet 128> - * Attachment = <Octet 129> - * Inline = <Octet 130> - */ - - /* - * some carrier mmsc servers do not support content_disposition - * field correctly - */ - boolean contentDisposition = Resources.getSystem().getBoolean(com - .android.internal.R.bool.config_mms_content_disposition_support); - - if (contentDisposition) { - int len = parseValueLength(pduDataStream); - pduDataStream.mark(1); - int thisStartPos = pduDataStream.available(); - int thisEndPos = 0; - int value = pduDataStream.read(); - - if (value == PduPart.P_DISPOSITION_FROM_DATA ) { - part.setContentDisposition(PduPart.DISPOSITION_FROM_DATA); - } else if (value == PduPart.P_DISPOSITION_ATTACHMENT) { - part.setContentDisposition(PduPart.DISPOSITION_ATTACHMENT); - } else if (value == PduPart.P_DISPOSITION_INLINE) { - part.setContentDisposition(PduPart.DISPOSITION_INLINE); - } else { - pduDataStream.reset(); - /* Token-text */ - part.setContentDisposition(parseWapString(pduDataStream - , TYPE_TEXT_STRING)); - } - - /* get filename parameter and skip other parameters */ - thisEndPos = pduDataStream.available(); - if (thisStartPos - thisEndPos < len) { - value = pduDataStream.read(); - if (value == PduPart.P_FILENAME) { //filename is text-string - part.setFilename(parseWapString(pduDataStream - , TYPE_TEXT_STRING)); - } - - /* skip other parameters */ - thisEndPos = pduDataStream.available(); - if (thisStartPos - thisEndPos < len) { - int last = len - (thisStartPos - thisEndPos); - byte[] temp = new byte[last]; - pduDataStream.read(temp, 0, last); - } - } - - tempPos = pduDataStream.available(); - lastLen = length - (startPos - tempPos); - } - break; - default: - if (LOCAL_LOGV) { - Log.v(LOG_TAG, "Not supported Part headers: " + header); - } - if (-1 == skipWapValue(pduDataStream, lastLen)) { - Log.e(LOG_TAG, "Corrupt Part headers"); - return false; - } - lastLen = 0; - break; - } - } else if ((header >= TEXT_MIN) && (header <= TEXT_MAX)) { - // Not assigned header. - byte[] tempHeader = parseWapString(pduDataStream, TYPE_TEXT_STRING); - byte[] tempValue = parseWapString(pduDataStream, TYPE_TEXT_STRING); - - // Check the header whether it is "Content-Transfer-Encoding". - if (true == - PduPart.CONTENT_TRANSFER_ENCODING.equalsIgnoreCase(new String(tempHeader))) { - part.setContentTransferEncoding(tempValue); - } - - tempPos = pduDataStream.available(); - lastLen = length - (startPos - tempPos); - } else { - if (LOCAL_LOGV) { - Log.v(LOG_TAG, "Not supported Part headers: " + header); - } - // Skip all headers of this part. - if (-1 == skipWapValue(pduDataStream, lastLen)) { - Log.e(LOG_TAG, "Corrupt Part headers"); - return false; - } - lastLen = 0; - } - } - - if (0 != lastLen) { - Log.e(LOG_TAG, "Corrupt Part headers"); - return false; - } - - return true; - } - - /** - * Check the position of a specified part. - * - * @param part the part to be checked - * @return part position, THE_FIRST_PART when it's the - * first one, THE_LAST_PART when it's the last one. - */ - private static int checkPartPosition(PduPart part) { - assert(null != part); - if ((null == mTypeParam) && - (null == mStartParam)) { - return THE_LAST_PART; - } - - /* check part's content-id */ - if (null != mStartParam) { - byte[] contentId = part.getContentId(); - if (null != contentId) { - if (true == Arrays.equals(mStartParam, contentId)) { - return THE_FIRST_PART; - } - } - } - - /* check part's content-type */ - if (null != mTypeParam) { - byte[] contentType = part.getContentType(); - if (null != contentType) { - if (true == Arrays.equals(mTypeParam, contentType)) { - return THE_FIRST_PART; - } - } - } - - return THE_LAST_PART; - } - - /** - * Check mandatory headers of a pdu. - * - * @param headers pdu headers - * @return true if the pdu has all of the mandatory headers, false otherwise. - */ - protected static boolean checkMandatoryHeader(PduHeaders headers) { - if (null == headers) { - return false; - } - - /* get message type */ - int messageType = headers.getOctet(PduHeaders.MESSAGE_TYPE); - - /* check Mms-Version field */ - int mmsVersion = headers.getOctet(PduHeaders.MMS_VERSION); - if (0 == mmsVersion) { - // Every message should have Mms-Version field. - return false; - } - - /* check mandatory header fields */ - switch (messageType) { - case PduHeaders.MESSAGE_TYPE_SEND_REQ: - // Content-Type field. - byte[] srContentType = headers.getTextString(PduHeaders.CONTENT_TYPE); - if (null == srContentType) { - return false; - } - - // From field. - EncodedStringValue srFrom = headers.getEncodedStringValue(PduHeaders.FROM); - if (null == srFrom) { - return false; - } - - // Transaction-Id field. - byte[] srTransactionId = headers.getTextString(PduHeaders.TRANSACTION_ID); - if (null == srTransactionId) { - return false; - } - - break; - case PduHeaders.MESSAGE_TYPE_SEND_CONF: - // Response-Status field. - int scResponseStatus = headers.getOctet(PduHeaders.RESPONSE_STATUS); - if (0 == scResponseStatus) { - return false; - } - - // Transaction-Id field. - byte[] scTransactionId = headers.getTextString(PduHeaders.TRANSACTION_ID); - if (null == scTransactionId) { - return false; - } - - break; - case PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND: - // Content-Location field. - byte[] niContentLocation = headers.getTextString(PduHeaders.CONTENT_LOCATION); - if (null == niContentLocation) { - return false; - } - - // Expiry field. - long niExpiry = headers.getLongInteger(PduHeaders.EXPIRY); - if (-1 == niExpiry) { - return false; - } - - // Message-Class field. - byte[] niMessageClass = headers.getTextString(PduHeaders.MESSAGE_CLASS); - if (null == niMessageClass) { - return false; - } - - // Message-Size field. - long niMessageSize = headers.getLongInteger(PduHeaders.MESSAGE_SIZE); - if (-1 == niMessageSize) { - return false; - } - - // Transaction-Id field. - byte[] niTransactionId = headers.getTextString(PduHeaders.TRANSACTION_ID); - if (null == niTransactionId) { - return false; - } - - break; - case PduHeaders.MESSAGE_TYPE_NOTIFYRESP_IND: - // Status field. - int nriStatus = headers.getOctet(PduHeaders.STATUS); - if (0 == nriStatus) { - return false; - } - - // Transaction-Id field. - byte[] nriTransactionId = headers.getTextString(PduHeaders.TRANSACTION_ID); - if (null == nriTransactionId) { - return false; - } - - break; - case PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF: - // Content-Type field. - byte[] rcContentType = headers.getTextString(PduHeaders.CONTENT_TYPE); - if (null == rcContentType) { - return false; - } - - // Date field. - long rcDate = headers.getLongInteger(PduHeaders.DATE); - if (-1 == rcDate) { - return false; - } - - break; - case PduHeaders.MESSAGE_TYPE_DELIVERY_IND: - // Date field. - long diDate = headers.getLongInteger(PduHeaders.DATE); - if (-1 == diDate) { - return false; - } - - // Message-Id field. - byte[] diMessageId = headers.getTextString(PduHeaders.MESSAGE_ID); - if (null == diMessageId) { - return false; - } - - // Status field. - int diStatus = headers.getOctet(PduHeaders.STATUS); - if (0 == diStatus) { - return false; - } - - // To field. - EncodedStringValue[] diTo = headers.getEncodedStringValues(PduHeaders.TO); - if (null == diTo) { - return false; - } - - break; - case PduHeaders.MESSAGE_TYPE_ACKNOWLEDGE_IND: - // Transaction-Id field. - byte[] aiTransactionId = headers.getTextString(PduHeaders.TRANSACTION_ID); - if (null == aiTransactionId) { - return false; - } - - break; - case PduHeaders.MESSAGE_TYPE_READ_ORIG_IND: - // Date field. - long roDate = headers.getLongInteger(PduHeaders.DATE); - if (-1 == roDate) { - return false; - } - - // From field. - EncodedStringValue roFrom = headers.getEncodedStringValue(PduHeaders.FROM); - if (null == roFrom) { - return false; - } - - // Message-Id field. - byte[] roMessageId = headers.getTextString(PduHeaders.MESSAGE_ID); - if (null == roMessageId) { - return false; - } - - // Read-Status field. - int roReadStatus = headers.getOctet(PduHeaders.READ_STATUS); - if (0 == roReadStatus) { - return false; - } - - // To field. - EncodedStringValue[] roTo = headers.getEncodedStringValues(PduHeaders.TO); - if (null == roTo) { - return false; - } - - break; - case PduHeaders.MESSAGE_TYPE_READ_REC_IND: - // From field. - EncodedStringValue rrFrom = headers.getEncodedStringValue(PduHeaders.FROM); - if (null == rrFrom) { - return false; - } - - // Message-Id field. - byte[] rrMessageId = headers.getTextString(PduHeaders.MESSAGE_ID); - if (null == rrMessageId) { - return false; - } - - // Read-Status field. - int rrReadStatus = headers.getOctet(PduHeaders.READ_STATUS); - if (0 == rrReadStatus) { - return false; - } - - // To field. - EncodedStringValue[] rrTo = headers.getEncodedStringValues(PduHeaders.TO); - if (null == rrTo) { - return false; - } - - break; - default: - // Parser doesn't support this message type in this version. - return false; - } - - return true; - } -} diff --git a/core/java/com/google/android/mms/pdu/PduPart.java b/core/java/com/google/android/mms/pdu/PduPart.java deleted file mode 100644 index b43e388..0000000 --- a/core/java/com/google/android/mms/pdu/PduPart.java +++ /dev/null @@ -1,402 +0,0 @@ -/* - * Copyright (C) 2007-2008 Esmertec AG. - * Copyright (C) 2007-2008 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.mms.pdu; - -import android.net.Uri; - -import java.util.HashMap; -import java.util.Map; - -/** - * The pdu part. - */ -public class PduPart { - /** - * Well-Known Parameters. - */ - public static final int P_Q = 0x80; - public static final int P_CHARSET = 0x81; - public static final int P_LEVEL = 0x82; - public static final int P_TYPE = 0x83; - public static final int P_DEP_NAME = 0x85; - public static final int P_DEP_FILENAME = 0x86; - public static final int P_DIFFERENCES = 0x87; - public static final int P_PADDING = 0x88; - // This value of "TYPE" s used with Content-Type: multipart/related - public static final int P_CT_MR_TYPE = 0x89; - public static final int P_DEP_START = 0x8A; - public static final int P_DEP_START_INFO = 0x8B; - public static final int P_DEP_COMMENT = 0x8C; - public static final int P_DEP_DOMAIN = 0x8D; - public static final int P_MAX_AGE = 0x8E; - public static final int P_DEP_PATH = 0x8F; - public static final int P_SECURE = 0x90; - public static final int P_SEC = 0x91; - public static final int P_MAC = 0x92; - public static final int P_CREATION_DATE = 0x93; - public static final int P_MODIFICATION_DATE = 0x94; - public static final int P_READ_DATE = 0x95; - public static final int P_SIZE = 0x96; - public static final int P_NAME = 0x97; - public static final int P_FILENAME = 0x98; - public static final int P_START = 0x99; - public static final int P_START_INFO = 0x9A; - public static final int P_COMMENT = 0x9B; - public static final int P_DOMAIN = 0x9C; - public static final int P_PATH = 0x9D; - - /** - * Header field names. - */ - public static final int P_CONTENT_TYPE = 0x91; - public static final int P_CONTENT_LOCATION = 0x8E; - public static final int P_CONTENT_ID = 0xC0; - public static final int P_DEP_CONTENT_DISPOSITION = 0xAE; - public static final int P_CONTENT_DISPOSITION = 0xC5; - // The next header is unassigned header, use reserved header(0x48) value. - public static final int P_CONTENT_TRANSFER_ENCODING = 0xC8; - - /** - * Content=Transfer-Encoding string. - */ - public static final String CONTENT_TRANSFER_ENCODING = - "Content-Transfer-Encoding"; - - /** - * Value of Content-Transfer-Encoding. - */ - public static final String P_BINARY = "binary"; - public static final String P_7BIT = "7bit"; - public static final String P_8BIT = "8bit"; - public static final String P_BASE64 = "base64"; - public static final String P_QUOTED_PRINTABLE = "quoted-printable"; - - /** - * Value of disposition can be set to PduPart when the value is octet in - * the PDU. - * "from-data" instead of Form-data<Octet 128>. - * "attachment" instead of Attachment<Octet 129>. - * "inline" instead of Inline<Octet 130>. - */ - static final byte[] DISPOSITION_FROM_DATA = "from-data".getBytes(); - static final byte[] DISPOSITION_ATTACHMENT = "attachment".getBytes(); - static final byte[] DISPOSITION_INLINE = "inline".getBytes(); - - /** - * Content-Disposition value. - */ - public static final int P_DISPOSITION_FROM_DATA = 0x80; - public static final int P_DISPOSITION_ATTACHMENT = 0x81; - public static final int P_DISPOSITION_INLINE = 0x82; - - /** - * Header of part. - */ - private Map<Integer, Object> mPartHeader = null; - - /** - * Data uri. - */ - private Uri mUri = null; - - /** - * Part data. - */ - private byte[] mPartData = null; - - private static final String TAG = "PduPart"; - - /** - * Empty Constructor. - */ - public PduPart() { - mPartHeader = new HashMap<Integer, Object>(); - } - - /** - * Set part data. The data are stored as byte array. - * - * @param data the data - */ - public void setData(byte[] data) { - if(data == null) { - return; - } - - mPartData = new byte[data.length]; - System.arraycopy(data, 0, mPartData, 0, data.length); - } - - /** - * @return A copy of the part data or null if the data wasn't set or - * the data is stored as Uri. - * @see #getDataUri - */ - public byte[] getData() { - if(mPartData == null) { - return null; - } - - byte[] byteArray = new byte[mPartData.length]; - System.arraycopy(mPartData, 0, byteArray, 0, mPartData.length); - return byteArray; - } - - /** - * Set data uri. The data are stored as Uri. - * - * @param uri the uri - */ - public void setDataUri(Uri uri) { - mUri = uri; - } - - /** - * @return The Uri of the part data or null if the data wasn't set or - * the data is stored as byte array. - * @see #getData - */ - public Uri getDataUri() { - return mUri; - } - - /** - * Set Content-id value - * - * @param contentId the content-id value - * @throws NullPointerException if the value is null. - */ - public void setContentId(byte[] contentId) { - if((contentId == null) || (contentId.length == 0)) { - throw new IllegalArgumentException( - "Content-Id may not be null or empty."); - } - - if ((contentId.length > 1) - && ((char) contentId[0] == '<') - && ((char) contentId[contentId.length - 1] == '>')) { - mPartHeader.put(P_CONTENT_ID, contentId); - return; - } - - // Insert beginning '<' and trailing '>' for Content-Id. - byte[] buffer = new byte[contentId.length + 2]; - buffer[0] = (byte) (0xff & '<'); - buffer[buffer.length - 1] = (byte) (0xff & '>'); - System.arraycopy(contentId, 0, buffer, 1, contentId.length); - mPartHeader.put(P_CONTENT_ID, buffer); - } - - /** - * Get Content-id value. - * - * @return the value - */ - public byte[] getContentId() { - return (byte[]) mPartHeader.get(P_CONTENT_ID); - } - - /** - * Set Char-set value. - * - * @param charset the value - */ - public void setCharset(int charset) { - mPartHeader.put(P_CHARSET, charset); - } - - /** - * Get Char-set value - * - * @return the charset value. Return 0 if charset was not set. - */ - public int getCharset() { - Integer charset = (Integer) mPartHeader.get(P_CHARSET); - if(charset == null) { - return 0; - } else { - return charset.intValue(); - } - } - - /** - * Set Content-Location value. - * - * @param contentLocation the value - * @throws NullPointerException if the value is null. - */ - public void setContentLocation(byte[] contentLocation) { - if(contentLocation == null) { - throw new NullPointerException("null content-location"); - } - - mPartHeader.put(P_CONTENT_LOCATION, contentLocation); - } - - /** - * Get Content-Location value. - * - * @return the value - * return PduPart.disposition[0] instead of <Octet 128> (Form-data). - * return PduPart.disposition[1] instead of <Octet 129> (Attachment). - * return PduPart.disposition[2] instead of <Octet 130> (Inline). - */ - public byte[] getContentLocation() { - return (byte[]) mPartHeader.get(P_CONTENT_LOCATION); - } - - /** - * Set Content-Disposition value. - * Use PduPart.disposition[0] instead of <Octet 128> (Form-data). - * Use PduPart.disposition[1] instead of <Octet 129> (Attachment). - * Use PduPart.disposition[2] instead of <Octet 130> (Inline). - * - * @param contentDisposition the value - * @throws NullPointerException if the value is null. - */ - public void setContentDisposition(byte[] contentDisposition) { - if(contentDisposition == null) { - throw new NullPointerException("null content-disposition"); - } - - mPartHeader.put(P_CONTENT_DISPOSITION, contentDisposition); - } - - /** - * Get Content-Disposition value. - * - * @return the value - */ - public byte[] getContentDisposition() { - return (byte[]) mPartHeader.get(P_CONTENT_DISPOSITION); - } - - /** - * Set Content-Type value. - * - * @param value the value - * @throws NullPointerException if the value is null. - */ - public void setContentType(byte[] contentType) { - if(contentType == null) { - throw new NullPointerException("null content-type"); - } - - mPartHeader.put(P_CONTENT_TYPE, contentType); - } - - /** - * Get Content-Type value of part. - * - * @return the value - */ - public byte[] getContentType() { - return (byte[]) mPartHeader.get(P_CONTENT_TYPE); - } - - /** - * Set Content-Transfer-Encoding value - * - * @param contentId the content-id value - * @throws NullPointerException if the value is null. - */ - public void setContentTransferEncoding(byte[] contentTransferEncoding) { - if(contentTransferEncoding == null) { - throw new NullPointerException("null content-transfer-encoding"); - } - - mPartHeader.put(P_CONTENT_TRANSFER_ENCODING, contentTransferEncoding); - } - - /** - * Get Content-Transfer-Encoding value. - * - * @return the value - */ - public byte[] getContentTransferEncoding() { - return (byte[]) mPartHeader.get(P_CONTENT_TRANSFER_ENCODING); - } - - /** - * Set Content-type parameter: name. - * - * @param name the name value - * @throws NullPointerException if the value is null. - */ - public void setName(byte[] name) { - if(null == name) { - throw new NullPointerException("null content-id"); - } - - mPartHeader.put(P_NAME, name); - } - - /** - * Get content-type parameter: name. - * - * @return the name - */ - public byte[] getName() { - return (byte[]) mPartHeader.get(P_NAME); - } - - /** - * Get Content-disposition parameter: filename - * - * @param fileName the filename value - * @throws NullPointerException if the value is null. - */ - public void setFilename(byte[] fileName) { - if(null == fileName) { - throw new NullPointerException("null content-id"); - } - - mPartHeader.put(P_FILENAME, fileName); - } - - /** - * Set Content-disposition parameter: filename - * - * @return the filename - */ - public byte[] getFilename() { - return (byte[]) mPartHeader.get(P_FILENAME); - } - - public String generateLocation() { - // Assumption: At least one of the content-location / name / filename - // or content-id should be set. This is guaranteed by the PduParser - // for incoming messages and by MM composer for outgoing messages. - byte[] location = (byte[]) mPartHeader.get(P_NAME); - if(null == location) { - location = (byte[]) mPartHeader.get(P_FILENAME); - - if (null == location) { - location = (byte[]) mPartHeader.get(P_CONTENT_LOCATION); - } - } - - if (null == location) { - byte[] contentId = (byte[]) mPartHeader.get(P_CONTENT_ID); - return "cid:" + new String(contentId); - } else { - return new String(location); - } - } -} - diff --git a/core/java/com/google/android/mms/pdu/PduPersister.java b/core/java/com/google/android/mms/pdu/PduPersister.java deleted file mode 100644 index ee285aa..0000000 --- a/core/java/com/google/android/mms/pdu/PduPersister.java +++ /dev/null @@ -1,1477 +0,0 @@ -/* - * Copyright (C) 2007-2008 Esmertec AG. - * Copyright (C) 2007-2008 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.mms.pdu; - -import com.google.android.mms.ContentType; -import com.google.android.mms.InvalidHeaderValueException; -import com.google.android.mms.MmsException; -import com.google.android.mms.util.DownloadDrmHelper; -import com.google.android.mms.util.DrmConvertSession; -import com.google.android.mms.util.PduCache; -import com.google.android.mms.util.PduCacheEntry; -import com.google.android.mms.util.SqliteWrapper; - -import android.content.ContentResolver; -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.database.DatabaseUtils; -import android.database.sqlite.SQLiteException; -import android.drm.DrmManagerClient; -import android.net.Uri; -import android.os.FileUtils; -import android.provider.MediaStore; -import android.provider.Telephony; -import android.provider.Telephony.Mms; -import android.provider.Telephony.MmsSms; -import android.provider.Telephony.Threads; -import android.provider.Telephony.Mms.Addr; -import android.provider.Telephony.Mms.Part; -import android.provider.Telephony.MmsSms.PendingMessages; -import android.text.TextUtils; -import android.util.Log; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.Map.Entry; - -import com.google.android.mms.pdu.EncodedStringValue; - -/** - * This class is the high-level manager of PDU storage. - */ -public class PduPersister { - private static final String TAG = "PduPersister"; - private static final boolean DEBUG = false; - private static final boolean LOCAL_LOGV = false; - - private static final long DUMMY_THREAD_ID = Long.MAX_VALUE; - - /** - * The uri of temporary drm objects. - */ - public static final String TEMPORARY_DRM_OBJECT_URI = - "content://mms/" + Long.MAX_VALUE + "/part"; - /** - * Indicate that we transiently failed to process a MM. - */ - public static final int PROC_STATUS_TRANSIENT_FAILURE = 1; - /** - * Indicate that we permanently failed to process a MM. - */ - public static final int PROC_STATUS_PERMANENTLY_FAILURE = 2; - /** - * Indicate that we have successfully processed a MM. - */ - public static final int PROC_STATUS_COMPLETED = 3; - - private static PduPersister sPersister; - private static final PduCache PDU_CACHE_INSTANCE; - - private static final int[] ADDRESS_FIELDS = new int[] { - PduHeaders.BCC, - PduHeaders.CC, - PduHeaders.FROM, - PduHeaders.TO - }; - - private static final String[] PDU_PROJECTION = new String[] { - Mms._ID, - Mms.MESSAGE_BOX, - Mms.THREAD_ID, - Mms.RETRIEVE_TEXT, - Mms.SUBJECT, - Mms.CONTENT_LOCATION, - Mms.CONTENT_TYPE, - Mms.MESSAGE_CLASS, - Mms.MESSAGE_ID, - Mms.RESPONSE_TEXT, - Mms.TRANSACTION_ID, - Mms.CONTENT_CLASS, - Mms.DELIVERY_REPORT, - Mms.MESSAGE_TYPE, - Mms.MMS_VERSION, - Mms.PRIORITY, - Mms.READ_REPORT, - Mms.READ_STATUS, - Mms.REPORT_ALLOWED, - Mms.RETRIEVE_STATUS, - Mms.STATUS, - Mms.DATE, - Mms.DELIVERY_TIME, - Mms.EXPIRY, - Mms.MESSAGE_SIZE, - Mms.SUBJECT_CHARSET, - Mms.RETRIEVE_TEXT_CHARSET, - }; - - private static final int PDU_COLUMN_ID = 0; - private static final int PDU_COLUMN_MESSAGE_BOX = 1; - private static final int PDU_COLUMN_THREAD_ID = 2; - private static final int PDU_COLUMN_RETRIEVE_TEXT = 3; - private static final int PDU_COLUMN_SUBJECT = 4; - private static final int PDU_COLUMN_CONTENT_LOCATION = 5; - private static final int PDU_COLUMN_CONTENT_TYPE = 6; - private static final int PDU_COLUMN_MESSAGE_CLASS = 7; - private static final int PDU_COLUMN_MESSAGE_ID = 8; - private static final int PDU_COLUMN_RESPONSE_TEXT = 9; - private static final int PDU_COLUMN_TRANSACTION_ID = 10; - private static final int PDU_COLUMN_CONTENT_CLASS = 11; - private static final int PDU_COLUMN_DELIVERY_REPORT = 12; - private static final int PDU_COLUMN_MESSAGE_TYPE = 13; - private static final int PDU_COLUMN_MMS_VERSION = 14; - private static final int PDU_COLUMN_PRIORITY = 15; - private static final int PDU_COLUMN_READ_REPORT = 16; - private static final int PDU_COLUMN_READ_STATUS = 17; - private static final int PDU_COLUMN_REPORT_ALLOWED = 18; - private static final int PDU_COLUMN_RETRIEVE_STATUS = 19; - private static final int PDU_COLUMN_STATUS = 20; - private static final int PDU_COLUMN_DATE = 21; - private static final int PDU_COLUMN_DELIVERY_TIME = 22; - private static final int PDU_COLUMN_EXPIRY = 23; - private static final int PDU_COLUMN_MESSAGE_SIZE = 24; - private static final int PDU_COLUMN_SUBJECT_CHARSET = 25; - private static final int PDU_COLUMN_RETRIEVE_TEXT_CHARSET = 26; - - private static final String[] PART_PROJECTION = new String[] { - Part._ID, - Part.CHARSET, - Part.CONTENT_DISPOSITION, - Part.CONTENT_ID, - Part.CONTENT_LOCATION, - Part.CONTENT_TYPE, - Part.FILENAME, - Part.NAME, - Part.TEXT - }; - - private static final int PART_COLUMN_ID = 0; - private static final int PART_COLUMN_CHARSET = 1; - private static final int PART_COLUMN_CONTENT_DISPOSITION = 2; - private static final int PART_COLUMN_CONTENT_ID = 3; - private static final int PART_COLUMN_CONTENT_LOCATION = 4; - private static final int PART_COLUMN_CONTENT_TYPE = 5; - private static final int PART_COLUMN_FILENAME = 6; - private static final int PART_COLUMN_NAME = 7; - private static final int PART_COLUMN_TEXT = 8; - - private static final HashMap<Uri, Integer> MESSAGE_BOX_MAP; - // These map are used for convenience in persist() and load(). - private static final HashMap<Integer, Integer> CHARSET_COLUMN_INDEX_MAP; - private static final HashMap<Integer, Integer> ENCODED_STRING_COLUMN_INDEX_MAP; - private static final HashMap<Integer, Integer> TEXT_STRING_COLUMN_INDEX_MAP; - private static final HashMap<Integer, Integer> OCTET_COLUMN_INDEX_MAP; - private static final HashMap<Integer, Integer> LONG_COLUMN_INDEX_MAP; - private static final HashMap<Integer, String> CHARSET_COLUMN_NAME_MAP; - private static final HashMap<Integer, String> ENCODED_STRING_COLUMN_NAME_MAP; - private static final HashMap<Integer, String> TEXT_STRING_COLUMN_NAME_MAP; - private static final HashMap<Integer, String> OCTET_COLUMN_NAME_MAP; - private static final HashMap<Integer, String> LONG_COLUMN_NAME_MAP; - - static { - MESSAGE_BOX_MAP = new HashMap<Uri, Integer>(); - MESSAGE_BOX_MAP.put(Mms.Inbox.CONTENT_URI, Mms.MESSAGE_BOX_INBOX); - MESSAGE_BOX_MAP.put(Mms.Sent.CONTENT_URI, Mms.MESSAGE_BOX_SENT); - MESSAGE_BOX_MAP.put(Mms.Draft.CONTENT_URI, Mms.MESSAGE_BOX_DRAFTS); - MESSAGE_BOX_MAP.put(Mms.Outbox.CONTENT_URI, Mms.MESSAGE_BOX_OUTBOX); - - CHARSET_COLUMN_INDEX_MAP = new HashMap<Integer, Integer>(); - CHARSET_COLUMN_INDEX_MAP.put(PduHeaders.SUBJECT, PDU_COLUMN_SUBJECT_CHARSET); - CHARSET_COLUMN_INDEX_MAP.put(PduHeaders.RETRIEVE_TEXT, PDU_COLUMN_RETRIEVE_TEXT_CHARSET); - - CHARSET_COLUMN_NAME_MAP = new HashMap<Integer, String>(); - CHARSET_COLUMN_NAME_MAP.put(PduHeaders.SUBJECT, Mms.SUBJECT_CHARSET); - CHARSET_COLUMN_NAME_MAP.put(PduHeaders.RETRIEVE_TEXT, Mms.RETRIEVE_TEXT_CHARSET); - - // Encoded string field code -> column index/name map. - ENCODED_STRING_COLUMN_INDEX_MAP = new HashMap<Integer, Integer>(); - ENCODED_STRING_COLUMN_INDEX_MAP.put(PduHeaders.RETRIEVE_TEXT, PDU_COLUMN_RETRIEVE_TEXT); - ENCODED_STRING_COLUMN_INDEX_MAP.put(PduHeaders.SUBJECT, PDU_COLUMN_SUBJECT); - - ENCODED_STRING_COLUMN_NAME_MAP = new HashMap<Integer, String>(); - ENCODED_STRING_COLUMN_NAME_MAP.put(PduHeaders.RETRIEVE_TEXT, Mms.RETRIEVE_TEXT); - ENCODED_STRING_COLUMN_NAME_MAP.put(PduHeaders.SUBJECT, Mms.SUBJECT); - - // Text string field code -> column index/name map. - TEXT_STRING_COLUMN_INDEX_MAP = new HashMap<Integer, Integer>(); - TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.CONTENT_LOCATION, PDU_COLUMN_CONTENT_LOCATION); - TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.CONTENT_TYPE, PDU_COLUMN_CONTENT_TYPE); - TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.MESSAGE_CLASS, PDU_COLUMN_MESSAGE_CLASS); - TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.MESSAGE_ID, PDU_COLUMN_MESSAGE_ID); - TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.RESPONSE_TEXT, PDU_COLUMN_RESPONSE_TEXT); - TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.TRANSACTION_ID, PDU_COLUMN_TRANSACTION_ID); - - TEXT_STRING_COLUMN_NAME_MAP = new HashMap<Integer, String>(); - TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.CONTENT_LOCATION, Mms.CONTENT_LOCATION); - TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.CONTENT_TYPE, Mms.CONTENT_TYPE); - TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.MESSAGE_CLASS, Mms.MESSAGE_CLASS); - TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.MESSAGE_ID, Mms.MESSAGE_ID); - TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.RESPONSE_TEXT, Mms.RESPONSE_TEXT); - TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.TRANSACTION_ID, Mms.TRANSACTION_ID); - - // Octet field code -> column index/name map. - OCTET_COLUMN_INDEX_MAP = new HashMap<Integer, Integer>(); - OCTET_COLUMN_INDEX_MAP.put(PduHeaders.CONTENT_CLASS, PDU_COLUMN_CONTENT_CLASS); - OCTET_COLUMN_INDEX_MAP.put(PduHeaders.DELIVERY_REPORT, PDU_COLUMN_DELIVERY_REPORT); - OCTET_COLUMN_INDEX_MAP.put(PduHeaders.MESSAGE_TYPE, PDU_COLUMN_MESSAGE_TYPE); - OCTET_COLUMN_INDEX_MAP.put(PduHeaders.MMS_VERSION, PDU_COLUMN_MMS_VERSION); - OCTET_COLUMN_INDEX_MAP.put(PduHeaders.PRIORITY, PDU_COLUMN_PRIORITY); - OCTET_COLUMN_INDEX_MAP.put(PduHeaders.READ_REPORT, PDU_COLUMN_READ_REPORT); - OCTET_COLUMN_INDEX_MAP.put(PduHeaders.READ_STATUS, PDU_COLUMN_READ_STATUS); - OCTET_COLUMN_INDEX_MAP.put(PduHeaders.REPORT_ALLOWED, PDU_COLUMN_REPORT_ALLOWED); - OCTET_COLUMN_INDEX_MAP.put(PduHeaders.RETRIEVE_STATUS, PDU_COLUMN_RETRIEVE_STATUS); - OCTET_COLUMN_INDEX_MAP.put(PduHeaders.STATUS, PDU_COLUMN_STATUS); - - OCTET_COLUMN_NAME_MAP = new HashMap<Integer, String>(); - OCTET_COLUMN_NAME_MAP.put(PduHeaders.CONTENT_CLASS, Mms.CONTENT_CLASS); - OCTET_COLUMN_NAME_MAP.put(PduHeaders.DELIVERY_REPORT, Mms.DELIVERY_REPORT); - OCTET_COLUMN_NAME_MAP.put(PduHeaders.MESSAGE_TYPE, Mms.MESSAGE_TYPE); - OCTET_COLUMN_NAME_MAP.put(PduHeaders.MMS_VERSION, Mms.MMS_VERSION); - OCTET_COLUMN_NAME_MAP.put(PduHeaders.PRIORITY, Mms.PRIORITY); - OCTET_COLUMN_NAME_MAP.put(PduHeaders.READ_REPORT, Mms.READ_REPORT); - OCTET_COLUMN_NAME_MAP.put(PduHeaders.READ_STATUS, Mms.READ_STATUS); - OCTET_COLUMN_NAME_MAP.put(PduHeaders.REPORT_ALLOWED, Mms.REPORT_ALLOWED); - OCTET_COLUMN_NAME_MAP.put(PduHeaders.RETRIEVE_STATUS, Mms.RETRIEVE_STATUS); - OCTET_COLUMN_NAME_MAP.put(PduHeaders.STATUS, Mms.STATUS); - - // Long field code -> column index/name map. - LONG_COLUMN_INDEX_MAP = new HashMap<Integer, Integer>(); - LONG_COLUMN_INDEX_MAP.put(PduHeaders.DATE, PDU_COLUMN_DATE); - LONG_COLUMN_INDEX_MAP.put(PduHeaders.DELIVERY_TIME, PDU_COLUMN_DELIVERY_TIME); - LONG_COLUMN_INDEX_MAP.put(PduHeaders.EXPIRY, PDU_COLUMN_EXPIRY); - LONG_COLUMN_INDEX_MAP.put(PduHeaders.MESSAGE_SIZE, PDU_COLUMN_MESSAGE_SIZE); - - LONG_COLUMN_NAME_MAP = new HashMap<Integer, String>(); - LONG_COLUMN_NAME_MAP.put(PduHeaders.DATE, Mms.DATE); - LONG_COLUMN_NAME_MAP.put(PduHeaders.DELIVERY_TIME, Mms.DELIVERY_TIME); - LONG_COLUMN_NAME_MAP.put(PduHeaders.EXPIRY, Mms.EXPIRY); - LONG_COLUMN_NAME_MAP.put(PduHeaders.MESSAGE_SIZE, Mms.MESSAGE_SIZE); - - PDU_CACHE_INSTANCE = PduCache.getInstance(); - } - - private final Context mContext; - private final ContentResolver mContentResolver; - private final DrmManagerClient mDrmManagerClient; - - private PduPersister(Context context) { - mContext = context; - mContentResolver = context.getContentResolver(); - mDrmManagerClient = new DrmManagerClient(context); - } - - /** Get(or create if not exist) an instance of PduPersister */ - public static PduPersister getPduPersister(Context context) { - if ((sPersister == null) || !context.equals(sPersister.mContext)) { - sPersister = new PduPersister(context); - } - - return sPersister; - } - - private void setEncodedStringValueToHeaders( - Cursor c, int columnIndex, - PduHeaders headers, int mapColumn) { - String s = c.getString(columnIndex); - if ((s != null) && (s.length() > 0)) { - int charsetColumnIndex = CHARSET_COLUMN_INDEX_MAP.get(mapColumn); - int charset = c.getInt(charsetColumnIndex); - EncodedStringValue value = new EncodedStringValue( - charset, getBytes(s)); - headers.setEncodedStringValue(value, mapColumn); - } - } - - private void setTextStringToHeaders( - Cursor c, int columnIndex, - PduHeaders headers, int mapColumn) { - String s = c.getString(columnIndex); - if (s != null) { - headers.setTextString(getBytes(s), mapColumn); - } - } - - private void setOctetToHeaders( - Cursor c, int columnIndex, - PduHeaders headers, int mapColumn) throws InvalidHeaderValueException { - if (!c.isNull(columnIndex)) { - int b = c.getInt(columnIndex); - headers.setOctet(b, mapColumn); - } - } - - private void setLongToHeaders( - Cursor c, int columnIndex, - PduHeaders headers, int mapColumn) { - if (!c.isNull(columnIndex)) { - long l = c.getLong(columnIndex); - headers.setLongInteger(l, mapColumn); - } - } - - private Integer getIntegerFromPartColumn(Cursor c, int columnIndex) { - if (!c.isNull(columnIndex)) { - return c.getInt(columnIndex); - } - return null; - } - - private byte[] getByteArrayFromPartColumn(Cursor c, int columnIndex) { - if (!c.isNull(columnIndex)) { - return getBytes(c.getString(columnIndex)); - } - return null; - } - - private PduPart[] loadParts(long msgId) throws MmsException { - Cursor c = SqliteWrapper.query(mContext, mContentResolver, - Uri.parse("content://mms/" + msgId + "/part"), - PART_PROJECTION, null, null, null); - - PduPart[] parts = null; - - try { - if ((c == null) || (c.getCount() == 0)) { - if (LOCAL_LOGV) { - Log.v(TAG, "loadParts(" + msgId + "): no part to load."); - } - return null; - } - - int partCount = c.getCount(); - int partIdx = 0; - parts = new PduPart[partCount]; - while (c.moveToNext()) { - PduPart part = new PduPart(); - Integer charset = getIntegerFromPartColumn( - c, PART_COLUMN_CHARSET); - if (charset != null) { - part.setCharset(charset); - } - - byte[] contentDisposition = getByteArrayFromPartColumn( - c, PART_COLUMN_CONTENT_DISPOSITION); - if (contentDisposition != null) { - part.setContentDisposition(contentDisposition); - } - - byte[] contentId = getByteArrayFromPartColumn( - c, PART_COLUMN_CONTENT_ID); - if (contentId != null) { - part.setContentId(contentId); - } - - byte[] contentLocation = getByteArrayFromPartColumn( - c, PART_COLUMN_CONTENT_LOCATION); - if (contentLocation != null) { - part.setContentLocation(contentLocation); - } - - byte[] contentType = getByteArrayFromPartColumn( - c, PART_COLUMN_CONTENT_TYPE); - if (contentType != null) { - part.setContentType(contentType); - } else { - throw new MmsException("Content-Type must be set."); - } - - byte[] fileName = getByteArrayFromPartColumn( - c, PART_COLUMN_FILENAME); - if (fileName != null) { - part.setFilename(fileName); - } - - byte[] name = getByteArrayFromPartColumn( - c, PART_COLUMN_NAME); - if (name != null) { - part.setName(name); - } - - // Construct a Uri for this part. - long partId = c.getLong(PART_COLUMN_ID); - Uri partURI = Uri.parse("content://mms/part/" + partId); - part.setDataUri(partURI); - - // For images/audio/video, we won't keep their data in Part - // because their renderer accept Uri as source. - String type = toIsoString(contentType); - if (!ContentType.isImageType(type) - && !ContentType.isAudioType(type) - && !ContentType.isVideoType(type)) { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - InputStream is = null; - - // Store simple string values directly in the database instead of an - // external file. This makes the text searchable and retrieval slightly - // faster. - if (ContentType.TEXT_PLAIN.equals(type) || ContentType.APP_SMIL.equals(type) - || ContentType.TEXT_HTML.equals(type)) { - String text = c.getString(PART_COLUMN_TEXT); - byte [] blob = new EncodedStringValue(text != null ? text : "") - .getTextString(); - baos.write(blob, 0, blob.length); - } else { - - try { - is = mContentResolver.openInputStream(partURI); - - byte[] buffer = new byte[256]; - int len = is.read(buffer); - while (len >= 0) { - baos.write(buffer, 0, len); - len = is.read(buffer); - } - } catch (IOException e) { - Log.e(TAG, "Failed to load part data", e); - c.close(); - throw new MmsException(e); - } finally { - if (is != null) { - try { - is.close(); - } catch (IOException e) { - Log.e(TAG, "Failed to close stream", e); - } // Ignore - } - } - } - part.setData(baos.toByteArray()); - } - parts[partIdx++] = part; - } - } finally { - if (c != null) { - c.close(); - } - } - - return parts; - } - - private void loadAddress(long msgId, PduHeaders headers) { - Cursor c = SqliteWrapper.query(mContext, mContentResolver, - Uri.parse("content://mms/" + msgId + "/addr"), - new String[] { Addr.ADDRESS, Addr.CHARSET, Addr.TYPE }, - null, null, null); - - if (c != null) { - try { - while (c.moveToNext()) { - String addr = c.getString(0); - if (!TextUtils.isEmpty(addr)) { - int addrType = c.getInt(2); - switch (addrType) { - case PduHeaders.FROM: - headers.setEncodedStringValue( - new EncodedStringValue(c.getInt(1), getBytes(addr)), - addrType); - break; - case PduHeaders.TO: - case PduHeaders.CC: - case PduHeaders.BCC: - headers.appendEncodedStringValue( - new EncodedStringValue(c.getInt(1), getBytes(addr)), - addrType); - break; - default: - Log.e(TAG, "Unknown address type: " + addrType); - break; - } - } - } - } finally { - c.close(); - } - } - } - - /** - * Load a PDU from storage by given Uri. - * - * @param uri The Uri of the PDU to be loaded. - * @return A generic PDU object, it may be cast to dedicated PDU. - * @throws MmsException Failed to load some fields of a PDU. - */ - public GenericPdu load(Uri uri) throws MmsException { - GenericPdu pdu = null; - PduCacheEntry cacheEntry = null; - int msgBox = 0; - long threadId = -1; - try { - synchronized(PDU_CACHE_INSTANCE) { - if (PDU_CACHE_INSTANCE.isUpdating(uri)) { - if (LOCAL_LOGV) { - Log.v(TAG, "load: " + uri + " blocked by isUpdating()"); - } - try { - PDU_CACHE_INSTANCE.wait(); - } catch (InterruptedException e) { - Log.e(TAG, "load: ", e); - } - cacheEntry = PDU_CACHE_INSTANCE.get(uri); - if (cacheEntry != null) { - return cacheEntry.getPdu(); - } - } - // Tell the cache to indicate to other callers that this item - // is currently being updated. - PDU_CACHE_INSTANCE.setUpdating(uri, true); - } - - Cursor c = SqliteWrapper.query(mContext, mContentResolver, uri, - PDU_PROJECTION, null, null, null); - PduHeaders headers = new PduHeaders(); - Set<Entry<Integer, Integer>> set; - long msgId = ContentUris.parseId(uri); - - try { - if ((c == null) || (c.getCount() != 1) || !c.moveToFirst()) { - throw new MmsException("Bad uri: " + uri); - } - - msgBox = c.getInt(PDU_COLUMN_MESSAGE_BOX); - threadId = c.getLong(PDU_COLUMN_THREAD_ID); - - set = ENCODED_STRING_COLUMN_INDEX_MAP.entrySet(); - for (Entry<Integer, Integer> e : set) { - setEncodedStringValueToHeaders( - c, e.getValue(), headers, e.getKey()); - } - - set = TEXT_STRING_COLUMN_INDEX_MAP.entrySet(); - for (Entry<Integer, Integer> e : set) { - setTextStringToHeaders( - c, e.getValue(), headers, e.getKey()); - } - - set = OCTET_COLUMN_INDEX_MAP.entrySet(); - for (Entry<Integer, Integer> e : set) { - setOctetToHeaders( - c, e.getValue(), headers, e.getKey()); - } - - set = LONG_COLUMN_INDEX_MAP.entrySet(); - for (Entry<Integer, Integer> e : set) { - setLongToHeaders( - c, e.getValue(), headers, e.getKey()); - } - } finally { - if (c != null) { - c.close(); - } - } - - // Check whether 'msgId' has been assigned a valid value. - if (msgId == -1L) { - throw new MmsException("Error! ID of the message: -1."); - } - - // Load address information of the MM. - loadAddress(msgId, headers); - - int msgType = headers.getOctet(PduHeaders.MESSAGE_TYPE); - PduBody body = new PduBody(); - - // For PDU which type is M_retrieve.conf or Send.req, we should - // load multiparts and put them into the body of the PDU. - if ((msgType == PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF) - || (msgType == PduHeaders.MESSAGE_TYPE_SEND_REQ)) { - PduPart[] parts = loadParts(msgId); - if (parts != null) { - int partsNum = parts.length; - for (int i = 0; i < partsNum; i++) { - body.addPart(parts[i]); - } - } - } - - switch (msgType) { - case PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND: - pdu = new NotificationInd(headers); - break; - case PduHeaders.MESSAGE_TYPE_DELIVERY_IND: - pdu = new DeliveryInd(headers); - break; - case PduHeaders.MESSAGE_TYPE_READ_ORIG_IND: - pdu = new ReadOrigInd(headers); - break; - case PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF: - pdu = new RetrieveConf(headers, body); - break; - case PduHeaders.MESSAGE_TYPE_SEND_REQ: - pdu = new SendReq(headers, body); - break; - case PduHeaders.MESSAGE_TYPE_ACKNOWLEDGE_IND: - pdu = new AcknowledgeInd(headers); - break; - case PduHeaders.MESSAGE_TYPE_NOTIFYRESP_IND: - pdu = new NotifyRespInd(headers); - break; - case PduHeaders.MESSAGE_TYPE_READ_REC_IND: - pdu = new ReadRecInd(headers); - break; - case PduHeaders.MESSAGE_TYPE_SEND_CONF: - case PduHeaders.MESSAGE_TYPE_FORWARD_REQ: - case PduHeaders.MESSAGE_TYPE_FORWARD_CONF: - case PduHeaders.MESSAGE_TYPE_MBOX_STORE_REQ: - case PduHeaders.MESSAGE_TYPE_MBOX_STORE_CONF: - case PduHeaders.MESSAGE_TYPE_MBOX_VIEW_REQ: - case PduHeaders.MESSAGE_TYPE_MBOX_VIEW_CONF: - case PduHeaders.MESSAGE_TYPE_MBOX_UPLOAD_REQ: - case PduHeaders.MESSAGE_TYPE_MBOX_UPLOAD_CONF: - case PduHeaders.MESSAGE_TYPE_MBOX_DELETE_REQ: - case PduHeaders.MESSAGE_TYPE_MBOX_DELETE_CONF: - case PduHeaders.MESSAGE_TYPE_MBOX_DESCR: - case PduHeaders.MESSAGE_TYPE_DELETE_REQ: - case PduHeaders.MESSAGE_TYPE_DELETE_CONF: - case PduHeaders.MESSAGE_TYPE_CANCEL_REQ: - case PduHeaders.MESSAGE_TYPE_CANCEL_CONF: - throw new MmsException( - "Unsupported PDU type: " + Integer.toHexString(msgType)); - - default: - throw new MmsException( - "Unrecognized PDU type: " + Integer.toHexString(msgType)); - } - } finally { - synchronized(PDU_CACHE_INSTANCE) { - if (pdu != null) { - assert(PDU_CACHE_INSTANCE.get(uri) == null); - // Update the cache entry with the real info - cacheEntry = new PduCacheEntry(pdu, msgBox, threadId); - PDU_CACHE_INSTANCE.put(uri, cacheEntry); - } - PDU_CACHE_INSTANCE.setUpdating(uri, false); - PDU_CACHE_INSTANCE.notifyAll(); // tell anybody waiting on this entry to go ahead - } - } - return pdu; - } - - private void persistAddress( - long msgId, int type, EncodedStringValue[] array) { - ContentValues values = new ContentValues(3); - - for (EncodedStringValue addr : array) { - values.clear(); // Clear all values first. - values.put(Addr.ADDRESS, toIsoString(addr.getTextString())); - values.put(Addr.CHARSET, addr.getCharacterSet()); - values.put(Addr.TYPE, type); - - Uri uri = Uri.parse("content://mms/" + msgId + "/addr"); - SqliteWrapper.insert(mContext, mContentResolver, uri, values); - } - } - - public Uri persistPart(PduPart part, long msgId) - throws MmsException { - Uri uri = Uri.parse("content://mms/" + msgId + "/part"); - ContentValues values = new ContentValues(8); - - int charset = part.getCharset(); - if (charset != 0 ) { - values.put(Part.CHARSET, charset); - } - - String contentType = null; - if (part.getContentType() != null) { - contentType = toIsoString(part.getContentType()); - - // There is no "image/jpg" in Android (and it's an invalid mimetype). - // Change it to "image/jpeg" - if (ContentType.IMAGE_JPG.equals(contentType)) { - contentType = ContentType.IMAGE_JPEG; - } - - values.put(Part.CONTENT_TYPE, contentType); - // To ensure the SMIL part is always the first part. - if (ContentType.APP_SMIL.equals(contentType)) { - values.put(Part.SEQ, -1); - } - } else { - throw new MmsException("MIME type of the part must be set."); - } - - if (part.getFilename() != null) { - String fileName = new String(part.getFilename()); - values.put(Part.FILENAME, fileName); - } - - if (part.getName() != null) { - String name = new String(part.getName()); - values.put(Part.NAME, name); - } - - Object value = null; - if (part.getContentDisposition() != null) { - value = toIsoString(part.getContentDisposition()); - values.put(Part.CONTENT_DISPOSITION, (String) value); - } - - if (part.getContentId() != null) { - value = toIsoString(part.getContentId()); - values.put(Part.CONTENT_ID, (String) value); - } - - if (part.getContentLocation() != null) { - value = toIsoString(part.getContentLocation()); - values.put(Part.CONTENT_LOCATION, (String) value); - } - - Uri res = SqliteWrapper.insert(mContext, mContentResolver, uri, values); - if (res == null) { - throw new MmsException("Failed to persist part, return null."); - } - - persistData(part, res, contentType); - // After successfully store the data, we should update - // the dataUri of the part. - part.setDataUri(res); - - return res; - } - - /** - * Save data of the part into storage. The source data may be given - * by a byte[] or a Uri. If it's a byte[], directly save it - * into storage, otherwise load source data from the dataUri and then - * save it. If the data is an image, we may scale down it according - * to user preference. - * - * @param part The PDU part which contains data to be saved. - * @param uri The URI of the part. - * @param contentType The MIME type of the part. - * @throws MmsException Cannot find source data or error occurred - * while saving the data. - */ - private void persistData(PduPart part, Uri uri, - String contentType) - throws MmsException { - OutputStream os = null; - InputStream is = null; - DrmConvertSession drmConvertSession = null; - Uri dataUri = null; - String path = null; - - try { - byte[] data = part.getData(); - if (ContentType.TEXT_PLAIN.equals(contentType) - || ContentType.APP_SMIL.equals(contentType) - || ContentType.TEXT_HTML.equals(contentType)) { - ContentValues cv = new ContentValues(); - cv.put(Telephony.Mms.Part.TEXT, new EncodedStringValue(data).getString()); - if (mContentResolver.update(uri, cv, null, null) != 1) { - throw new MmsException("unable to update " + uri.toString()); - } - } else { - boolean isDrm = DownloadDrmHelper.isDrmConvertNeeded(contentType); - if (isDrm) { - if (uri != null) { - try { - path = convertUriToPath(mContext, uri); - if (LOCAL_LOGV) { - Log.v(TAG, "drm uri: " + uri + " path: " + path); - } - File f = new File(path); - long len = f.length(); - if (LOCAL_LOGV) { - Log.v(TAG, "drm path: " + path + " len: " + len); - } - if (len > 0) { - // we're not going to re-persist and re-encrypt an already - // converted drm file - return; - } - } catch (Exception e) { - Log.e(TAG, "Can't get file info for: " + part.getDataUri(), e); - } - } - // We haven't converted the file yet, start the conversion - drmConvertSession = DrmConvertSession.open(mContext, contentType); - if (drmConvertSession == null) { - throw new MmsException("Mimetype " + contentType + - " can not be converted."); - } - } - os = mContentResolver.openOutputStream(uri); - if (data == null) { - dataUri = part.getDataUri(); - if ((dataUri == null) || (dataUri == uri)) { - Log.w(TAG, "Can't find data for this part."); - return; - } - is = mContentResolver.openInputStream(dataUri); - - if (LOCAL_LOGV) { - Log.v(TAG, "Saving data to: " + uri); - } - - byte[] buffer = new byte[8192]; - for (int len = 0; (len = is.read(buffer)) != -1; ) { - if (!isDrm) { - os.write(buffer, 0, len); - } else { - byte[] convertedData = drmConvertSession.convert(buffer, len); - if (convertedData != null) { - os.write(convertedData, 0, convertedData.length); - } else { - throw new MmsException("Error converting drm data."); - } - } - } - } else { - if (LOCAL_LOGV) { - Log.v(TAG, "Saving data to: " + uri); - } - if (!isDrm) { - os.write(data); - } else { - dataUri = uri; - byte[] convertedData = drmConvertSession.convert(data, data.length); - if (convertedData != null) { - os.write(convertedData, 0, convertedData.length); - } else { - throw new MmsException("Error converting drm data."); - } - } - } - } - } catch (FileNotFoundException e) { - Log.e(TAG, "Failed to open Input/Output stream.", e); - throw new MmsException(e); - } catch (IOException e) { - Log.e(TAG, "Failed to read/write data.", e); - throw new MmsException(e); - } finally { - if (os != null) { - try { - os.close(); - } catch (IOException e) { - Log.e(TAG, "IOException while closing: " + os, e); - } // Ignore - } - if (is != null) { - try { - is.close(); - } catch (IOException e) { - Log.e(TAG, "IOException while closing: " + is, e); - } // Ignore - } - if (drmConvertSession != null) { - drmConvertSession.close(path); - - // Reset the permissions on the encrypted part file so everyone has only read - // permission. - File f = new File(path); - ContentValues values = new ContentValues(0); - SqliteWrapper.update(mContext, mContentResolver, - Uri.parse("content://mms/resetFilePerm/" + f.getName()), - values, null, null); - } - } - } - - /** - * This method expects uri in the following format - * content://media/<table_name>/<row_index> (or) - * file://sdcard/test.mp4 - * http://test.com/test.mp4 - * - * Here <table_name> shall be "video" or "audio" or "images" - * <row_index> the index of the content in given table - */ - static public String convertUriToPath(Context context, Uri uri) { - String path = null; - if (null != uri) { - String scheme = uri.getScheme(); - if (null == scheme || scheme.equals("") || - scheme.equals(ContentResolver.SCHEME_FILE)) { - path = uri.getPath(); - - } else if (scheme.equals("http")) { - path = uri.toString(); - - } else if (scheme.equals(ContentResolver.SCHEME_CONTENT)) { - String[] projection = new String[] {MediaStore.MediaColumns.DATA}; - Cursor cursor = null; - try { - cursor = context.getContentResolver().query(uri, projection, null, - null, null); - if (null == cursor || 0 == cursor.getCount() || !cursor.moveToFirst()) { - throw new IllegalArgumentException("Given Uri could not be found" + - " in media store"); - } - int pathIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA); - path = cursor.getString(pathIndex); - } catch (SQLiteException e) { - throw new IllegalArgumentException("Given Uri is not formatted in a way " + - "so that it can be found in media store."); - } finally { - if (null != cursor) { - cursor.close(); - } - } - } else { - throw new IllegalArgumentException("Given Uri scheme is not supported"); - } - } - return path; - } - - private void updateAddress( - long msgId, int type, EncodedStringValue[] array) { - // Delete old address information and then insert new ones. - SqliteWrapper.delete(mContext, mContentResolver, - Uri.parse("content://mms/" + msgId + "/addr"), - Addr.TYPE + "=" + type, null); - - persistAddress(msgId, type, array); - } - - /** - * Update headers of a SendReq. - * - * @param uri The PDU which need to be updated. - * @param pdu New headers. - * @throws MmsException Bad URI or updating failed. - */ - public void updateHeaders(Uri uri, SendReq sendReq) { - synchronized(PDU_CACHE_INSTANCE) { - // If the cache item is getting updated, wait until it's done updating before - // purging it. - if (PDU_CACHE_INSTANCE.isUpdating(uri)) { - if (LOCAL_LOGV) { - Log.v(TAG, "updateHeaders: " + uri + " blocked by isUpdating()"); - } - try { - PDU_CACHE_INSTANCE.wait(); - } catch (InterruptedException e) { - Log.e(TAG, "updateHeaders: ", e); - } - } - } - PDU_CACHE_INSTANCE.purge(uri); - - ContentValues values = new ContentValues(10); - byte[] contentType = sendReq.getContentType(); - if (contentType != null) { - values.put(Mms.CONTENT_TYPE, toIsoString(contentType)); - } - - long date = sendReq.getDate(); - if (date != -1) { - values.put(Mms.DATE, date); - } - - int deliveryReport = sendReq.getDeliveryReport(); - if (deliveryReport != 0) { - values.put(Mms.DELIVERY_REPORT, deliveryReport); - } - - long expiry = sendReq.getExpiry(); - if (expiry != -1) { - values.put(Mms.EXPIRY, expiry); - } - - byte[] msgClass = sendReq.getMessageClass(); - if (msgClass != null) { - values.put(Mms.MESSAGE_CLASS, toIsoString(msgClass)); - } - - int priority = sendReq.getPriority(); - if (priority != 0) { - values.put(Mms.PRIORITY, priority); - } - - int readReport = sendReq.getReadReport(); - if (readReport != 0) { - values.put(Mms.READ_REPORT, readReport); - } - - byte[] transId = sendReq.getTransactionId(); - if (transId != null) { - values.put(Mms.TRANSACTION_ID, toIsoString(transId)); - } - - EncodedStringValue subject = sendReq.getSubject(); - if (subject != null) { - values.put(Mms.SUBJECT, toIsoString(subject.getTextString())); - values.put(Mms.SUBJECT_CHARSET, subject.getCharacterSet()); - } else { - values.put(Mms.SUBJECT, ""); - } - - long messageSize = sendReq.getMessageSize(); - if (messageSize > 0) { - values.put(Mms.MESSAGE_SIZE, messageSize); - } - - PduHeaders headers = sendReq.getPduHeaders(); - HashSet<String> recipients = new HashSet<String>(); - for (int addrType : ADDRESS_FIELDS) { - EncodedStringValue[] array = null; - if (addrType == PduHeaders.FROM) { - EncodedStringValue v = headers.getEncodedStringValue(addrType); - if (v != null) { - array = new EncodedStringValue[1]; - array[0] = v; - } - } else { - array = headers.getEncodedStringValues(addrType); - } - - if (array != null) { - long msgId = ContentUris.parseId(uri); - updateAddress(msgId, addrType, array); - if (addrType == PduHeaders.TO) { - for (EncodedStringValue v : array) { - if (v != null) { - recipients.add(v.getString()); - } - } - } - } - } - if (!recipients.isEmpty()) { - long threadId = Threads.getOrCreateThreadId(mContext, recipients); - values.put(Mms.THREAD_ID, threadId); - } - - SqliteWrapper.update(mContext, mContentResolver, uri, values, null, null); - } - - private void updatePart(Uri uri, PduPart part) throws MmsException { - ContentValues values = new ContentValues(7); - - int charset = part.getCharset(); - if (charset != 0 ) { - values.put(Part.CHARSET, charset); - } - - String contentType = null; - if (part.getContentType() != null) { - contentType = toIsoString(part.getContentType()); - values.put(Part.CONTENT_TYPE, contentType); - } else { - throw new MmsException("MIME type of the part must be set."); - } - - if (part.getFilename() != null) { - String fileName = new String(part.getFilename()); - values.put(Part.FILENAME, fileName); - } - - if (part.getName() != null) { - String name = new String(part.getName()); - values.put(Part.NAME, name); - } - - Object value = null; - if (part.getContentDisposition() != null) { - value = toIsoString(part.getContentDisposition()); - values.put(Part.CONTENT_DISPOSITION, (String) value); - } - - if (part.getContentId() != null) { - value = toIsoString(part.getContentId()); - values.put(Part.CONTENT_ID, (String) value); - } - - if (part.getContentLocation() != null) { - value = toIsoString(part.getContentLocation()); - values.put(Part.CONTENT_LOCATION, (String) value); - } - - SqliteWrapper.update(mContext, mContentResolver, uri, values, null, null); - - // Only update the data when: - // 1. New binary data supplied or - // 2. The Uri of the part is different from the current one. - if ((part.getData() != null) - || (uri != part.getDataUri())) { - persistData(part, uri, contentType); - } - } - - /** - * Update all parts of a PDU. - * - * @param uri The PDU which need to be updated. - * @param body New message body of the PDU. - * @throws MmsException Bad URI or updating failed. - */ - public void updateParts(Uri uri, PduBody body) - throws MmsException { - try { - PduCacheEntry cacheEntry; - synchronized(PDU_CACHE_INSTANCE) { - if (PDU_CACHE_INSTANCE.isUpdating(uri)) { - if (LOCAL_LOGV) { - Log.v(TAG, "updateParts: " + uri + " blocked by isUpdating()"); - } - try { - PDU_CACHE_INSTANCE.wait(); - } catch (InterruptedException e) { - Log.e(TAG, "updateParts: ", e); - } - cacheEntry = PDU_CACHE_INSTANCE.get(uri); - if (cacheEntry != null) { - ((MultimediaMessagePdu) cacheEntry.getPdu()).setBody(body); - } - } - // Tell the cache to indicate to other callers that this item - // is currently being updated. - PDU_CACHE_INSTANCE.setUpdating(uri, true); - } - - ArrayList<PduPart> toBeCreated = new ArrayList<PduPart>(); - HashMap<Uri, PduPart> toBeUpdated = new HashMap<Uri, PduPart>(); - - int partsNum = body.getPartsNum(); - StringBuilder filter = new StringBuilder().append('('); - for (int i = 0; i < partsNum; i++) { - PduPart part = body.getPart(i); - Uri partUri = part.getDataUri(); - if ((partUri == null) || !partUri.getAuthority().startsWith("mms")) { - toBeCreated.add(part); - } else { - toBeUpdated.put(partUri, part); - - // Don't use 'i > 0' to determine whether we should append - // 'AND' since 'i = 0' may be skipped in another branch. - if (filter.length() > 1) { - filter.append(" AND "); - } - - filter.append(Part._ID); - filter.append("!="); - DatabaseUtils.appendEscapedSQLString(filter, partUri.getLastPathSegment()); - } - } - filter.append(')'); - - long msgId = ContentUris.parseId(uri); - - // Remove the parts which doesn't exist anymore. - SqliteWrapper.delete(mContext, mContentResolver, - Uri.parse(Mms.CONTENT_URI + "/" + msgId + "/part"), - filter.length() > 2 ? filter.toString() : null, null); - - // Create new parts which didn't exist before. - for (PduPart part : toBeCreated) { - persistPart(part, msgId); - } - - // Update the modified parts. - for (Map.Entry<Uri, PduPart> e : toBeUpdated.entrySet()) { - updatePart(e.getKey(), e.getValue()); - } - } finally { - synchronized(PDU_CACHE_INSTANCE) { - PDU_CACHE_INSTANCE.setUpdating(uri, false); - PDU_CACHE_INSTANCE.notifyAll(); - } - } - } - - /** - * Persist a PDU object to specific location in the storage. - * - * @param pdu The PDU object to be stored. - * @param uri Where to store the given PDU object. - * @return A Uri which can be used to access the stored PDU. - */ - public Uri persist(GenericPdu pdu, Uri uri) throws MmsException { - if (uri == null) { - throw new MmsException("Uri may not be null."); - } - long msgId = -1; - try { - msgId = ContentUris.parseId(uri); - } catch (NumberFormatException e) { - // the uri ends with "inbox" or something else like that - } - boolean existingUri = msgId != -1; - - if (!existingUri && MESSAGE_BOX_MAP.get(uri) == null) { - throw new MmsException( - "Bad destination, must be one of " - + "content://mms/inbox, content://mms/sent, " - + "content://mms/drafts, content://mms/outbox, " - + "content://mms/temp."); - } - synchronized(PDU_CACHE_INSTANCE) { - // If the cache item is getting updated, wait until it's done updating before - // purging it. - if (PDU_CACHE_INSTANCE.isUpdating(uri)) { - if (LOCAL_LOGV) { - Log.v(TAG, "persist: " + uri + " blocked by isUpdating()"); - } - try { - PDU_CACHE_INSTANCE.wait(); - } catch (InterruptedException e) { - Log.e(TAG, "persist1: ", e); - } - } - } - PDU_CACHE_INSTANCE.purge(uri); - - PduHeaders header = pdu.getPduHeaders(); - PduBody body = null; - ContentValues values = new ContentValues(); - Set<Entry<Integer, String>> set; - - set = ENCODED_STRING_COLUMN_NAME_MAP.entrySet(); - for (Entry<Integer, String> e : set) { - int field = e.getKey(); - EncodedStringValue encodedString = header.getEncodedStringValue(field); - if (encodedString != null) { - String charsetColumn = CHARSET_COLUMN_NAME_MAP.get(field); - values.put(e.getValue(), toIsoString(encodedString.getTextString())); - values.put(charsetColumn, encodedString.getCharacterSet()); - } - } - - set = TEXT_STRING_COLUMN_NAME_MAP.entrySet(); - for (Entry<Integer, String> e : set){ - byte[] text = header.getTextString(e.getKey()); - if (text != null) { - values.put(e.getValue(), toIsoString(text)); - } - } - - set = OCTET_COLUMN_NAME_MAP.entrySet(); - for (Entry<Integer, String> e : set){ - int b = header.getOctet(e.getKey()); - if (b != 0) { - values.put(e.getValue(), b); - } - } - - set = LONG_COLUMN_NAME_MAP.entrySet(); - for (Entry<Integer, String> e : set){ - long l = header.getLongInteger(e.getKey()); - if (l != -1L) { - values.put(e.getValue(), l); - } - } - - HashMap<Integer, EncodedStringValue[]> addressMap = - new HashMap<Integer, EncodedStringValue[]>(ADDRESS_FIELDS.length); - // Save address information. - for (int addrType : ADDRESS_FIELDS) { - EncodedStringValue[] array = null; - if (addrType == PduHeaders.FROM) { - EncodedStringValue v = header.getEncodedStringValue(addrType); - if (v != null) { - array = new EncodedStringValue[1]; - array[0] = v; - } - } else { - array = header.getEncodedStringValues(addrType); - } - addressMap.put(addrType, array); - } - - HashSet<String> recipients = new HashSet<String>(); - int msgType = pdu.getMessageType(); - // Here we only allocate thread ID for M-Notification.ind, - // M-Retrieve.conf and M-Send.req. - // Some of other PDU types may be allocated a thread ID outside - // this scope. - if ((msgType == PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND) - || (msgType == PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF) - || (msgType == PduHeaders.MESSAGE_TYPE_SEND_REQ)) { - EncodedStringValue[] array = null; - switch (msgType) { - case PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND: - case PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF: - array = addressMap.get(PduHeaders.FROM); - break; - case PduHeaders.MESSAGE_TYPE_SEND_REQ: - array = addressMap.get(PduHeaders.TO); - break; - } - - if (array != null) { - for (EncodedStringValue v : array) { - if (v != null) { - recipients.add(v.getString()); - } - } - } - if (!recipients.isEmpty()) { - long threadId = Threads.getOrCreateThreadId(mContext, recipients); - values.put(Mms.THREAD_ID, threadId); - } - } - - // Save parts first to avoid inconsistent message is loaded - // while saving the parts. - long dummyId = System.currentTimeMillis(); // Dummy ID of the msg. - // Get body if the PDU is a RetrieveConf or SendReq. - if (pdu instanceof MultimediaMessagePdu) { - body = ((MultimediaMessagePdu) pdu).getBody(); - // Start saving parts if necessary. - if (body != null) { - int partsNum = body.getPartsNum(); - for (int i = 0; i < partsNum; i++) { - PduPart part = body.getPart(i); - persistPart(part, dummyId); - } - } - } - - Uri res = null; - if (existingUri) { - res = uri; - SqliteWrapper.update(mContext, mContentResolver, res, values, null, null); - } else { - res = SqliteWrapper.insert(mContext, mContentResolver, uri, values); - if (res == null) { - throw new MmsException("persist() failed: return null."); - } - // Get the real ID of the PDU and update all parts which were - // saved with the dummy ID. - msgId = ContentUris.parseId(res); - } - - values = new ContentValues(1); - values.put(Part.MSG_ID, msgId); - SqliteWrapper.update(mContext, mContentResolver, - Uri.parse("content://mms/" + dummyId + "/part"), - values, null, null); - // We should return the longest URI of the persisted PDU, for - // example, if input URI is "content://mms/inbox" and the _ID of - // persisted PDU is '8', we should return "content://mms/inbox/8" - // instead of "content://mms/8". - // FIXME: Should the MmsProvider be responsible for this??? - if (!existingUri) { - res = Uri.parse(uri + "/" + msgId); - } - - // Save address information. - for (int addrType : ADDRESS_FIELDS) { - EncodedStringValue[] array = addressMap.get(addrType); - if (array != null) { - persistAddress(msgId, addrType, array); - } - } - - return res; - } - - /** - * Move a PDU object from one location to another. - * - * @param from Specify the PDU object to be moved. - * @param to The destination location, should be one of the following: - * "content://mms/inbox", "content://mms/sent", - * "content://mms/drafts", "content://mms/outbox", - * "content://mms/trash". - * @return New Uri of the moved PDU. - * @throws MmsException Error occurred while moving the message. - */ - public Uri move(Uri from, Uri to) throws MmsException { - // Check whether the 'msgId' has been assigned a valid value. - long msgId = ContentUris.parseId(from); - if (msgId == -1L) { - throw new MmsException("Error! ID of the message: -1."); - } - - // Get corresponding int value of destination box. - Integer msgBox = MESSAGE_BOX_MAP.get(to); - if (msgBox == null) { - throw new MmsException( - "Bad destination, must be one of " - + "content://mms/inbox, content://mms/sent, " - + "content://mms/drafts, content://mms/outbox, " - + "content://mms/temp."); - } - - ContentValues values = new ContentValues(1); - values.put(Mms.MESSAGE_BOX, msgBox); - SqliteWrapper.update(mContext, mContentResolver, from, values, null, null); - return ContentUris.withAppendedId(to, msgId); - } - - /** - * Wrap a byte[] into a String. - */ - public static String toIsoString(byte[] bytes) { - try { - return new String(bytes, CharacterSets.MIMENAME_ISO_8859_1); - } catch (UnsupportedEncodingException e) { - // Impossible to reach here! - Log.e(TAG, "ISO_8859_1 must be supported!", e); - return ""; - } - } - - /** - * Unpack a given String into a byte[]. - */ - public static byte[] getBytes(String data) { - try { - return data.getBytes(CharacterSets.MIMENAME_ISO_8859_1); - } catch (UnsupportedEncodingException e) { - // Impossible to reach here! - Log.e(TAG, "ISO_8859_1 must be supported!", e); - return new byte[0]; - } - } - - /** - * Remove all objects in the temporary path. - */ - public void release() { - Uri uri = Uri.parse(TEMPORARY_DRM_OBJECT_URI); - SqliteWrapper.delete(mContext, mContentResolver, uri, null, null); - } - - /** - * Find all messages to be sent or downloaded before certain time. - */ - public Cursor getPendingMessages(long dueTime) { - Uri.Builder uriBuilder = PendingMessages.CONTENT_URI.buildUpon(); - uriBuilder.appendQueryParameter("protocol", "mms"); - - String selection = PendingMessages.ERROR_TYPE + " < ?" - + " AND " + PendingMessages.DUE_TIME + " <= ?"; - - String[] selectionArgs = new String[] { - String.valueOf(MmsSms.ERR_TYPE_GENERIC_PERMANENT), - String.valueOf(dueTime) - }; - - return SqliteWrapper.query(mContext, mContentResolver, - uriBuilder.build(), null, selection, selectionArgs, - PendingMessages.DUE_TIME); - } -} diff --git a/core/java/com/google/android/mms/pdu/QuotedPrintable.java b/core/java/com/google/android/mms/pdu/QuotedPrintable.java deleted file mode 100644 index a34ed12..0000000 --- a/core/java/com/google/android/mms/pdu/QuotedPrintable.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2007 Esmertec AG. - * Copyright (C) 2007 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.mms.pdu; - -import java.io.ByteArrayOutputStream; - -public class QuotedPrintable { - private static byte ESCAPE_CHAR = '='; - - /** - * Decodes an array quoted-printable characters into an array of original bytes. - * Escaped characters are converted back to their original representation. - * - * <p> - * This function implements a subset of - * quoted-printable encoding specification (rule #1 and rule #2) - * as defined in RFC 1521. - * </p> - * - * @param bytes array of quoted-printable characters - * @return array of original bytes, - * null if quoted-printable decoding is unsuccessful. - */ - public static final byte[] decodeQuotedPrintable(byte[] bytes) { - if (bytes == null) { - return null; - } - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - for (int i = 0; i < bytes.length; i++) { - int b = bytes[i]; - if (b == ESCAPE_CHAR) { - try { - if('\r' == (char)bytes[i + 1] && - '\n' == (char)bytes[i + 2]) { - i += 2; - continue; - } - int u = Character.digit((char) bytes[++i], 16); - int l = Character.digit((char) bytes[++i], 16); - if (u == -1 || l == -1) { - return null; - } - buffer.write((char) ((u << 4) + l)); - } catch (ArrayIndexOutOfBoundsException e) { - return null; - } - } else { - buffer.write(b); - } - } - return buffer.toByteArray(); - } -} diff --git a/core/java/com/google/android/mms/pdu/ReadOrigInd.java b/core/java/com/google/android/mms/pdu/ReadOrigInd.java deleted file mode 100644 index 1bfc0bb..0000000 --- a/core/java/com/google/android/mms/pdu/ReadOrigInd.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (C) 2007 Esmertec AG. - * Copyright (C) 2007 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.mms.pdu; - -import com.google.android.mms.InvalidHeaderValueException; - -public class ReadOrigInd extends GenericPdu { - /** - * Empty constructor. - * Since the Pdu corresponding to this class is constructed - * by the Proxy-Relay server, this class is only instantiated - * by the Pdu Parser. - * - * @throws InvalidHeaderValueException if error occurs. - */ - public ReadOrigInd() throws InvalidHeaderValueException { - super(); - setMessageType(PduHeaders.MESSAGE_TYPE_READ_ORIG_IND); - } - - /** - * Constructor with given headers. - * - * @param headers Headers for this PDU. - */ - ReadOrigInd(PduHeaders headers) { - super(headers); - } - - /** - * Get Date value. - * - * @return the value - */ - public long getDate() { - return mPduHeaders.getLongInteger(PduHeaders.DATE); - } - - /** - * Set Date value. - * - * @param value the value - */ - public void setDate(long value) { - mPduHeaders.setLongInteger(value, PduHeaders.DATE); - } - - /** - * Get From value. - * From-value = Value-length - * (Address-present-token Encoded-string-value | Insert-address-token) - * - * @return the value - */ - public EncodedStringValue getFrom() { - return mPduHeaders.getEncodedStringValue(PduHeaders.FROM); - } - - /** - * Set From value. - * - * @param value the value - * @throws NullPointerException if the value is null. - */ - public void setFrom(EncodedStringValue value) { - mPduHeaders.setEncodedStringValue(value, PduHeaders.FROM); - } - - /** - * Get Message-ID value. - * - * @return the value - */ - public byte[] getMessageId() { - return mPduHeaders.getTextString(PduHeaders.MESSAGE_ID); - } - - /** - * Set Message-ID value. - * - * @param value the value - * @throws NullPointerException if the value is null. - */ - public void setMessageId(byte[] value) { - mPduHeaders.setTextString(value, PduHeaders.MESSAGE_ID); - } - - /** - * Get X-MMS-Read-status value. - * - * @return the value - */ - public int getReadStatus() { - return mPduHeaders.getOctet(PduHeaders.READ_STATUS); - } - - /** - * Set X-MMS-Read-status value. - * - * @param value the value - * @throws InvalidHeaderValueException if the value is invalid. - */ - public void setReadStatus(int value) throws InvalidHeaderValueException { - mPduHeaders.setOctet(value, PduHeaders.READ_STATUS); - } - - /** - * Get To value. - * - * @return the value - */ - public EncodedStringValue[] getTo() { - return mPduHeaders.getEncodedStringValues(PduHeaders.TO); - } - - /** - * Set To value. - * - * @param value the value - * @throws NullPointerException if the value is null. - */ - public void setTo(EncodedStringValue[] value) { - mPduHeaders.setEncodedStringValues(value, PduHeaders.TO); - } - - /* - * Optional, not supported header fields: - * - * public byte[] getApplicId() {return null;} - * public void setApplicId(byte[] value) {} - * - * public byte[] getAuxApplicId() {return null;} - * public void getAuxApplicId(byte[] value) {} - * - * public byte[] getReplyApplicId() {return 0x00;} - * public void setReplyApplicId(byte[] value) {} - */ -} diff --git a/core/java/com/google/android/mms/pdu/ReadRecInd.java b/core/java/com/google/android/mms/pdu/ReadRecInd.java deleted file mode 100644 index 880e3ac..0000000 --- a/core/java/com/google/android/mms/pdu/ReadRecInd.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2007 Esmertec AG. - * Copyright (C) 2007 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.mms.pdu; - -import com.google.android.mms.InvalidHeaderValueException; - -public class ReadRecInd extends GenericPdu { - /** - * Constructor, used when composing a M-ReadRec.ind pdu. - * - * @param from the from value - * @param messageId the message ID value - * @param mmsVersion current viersion of mms - * @param readStatus the read status value - * @param to the to value - * @throws InvalidHeaderValueException if parameters are invalid. - * NullPointerException if messageId or to is null. - */ - public ReadRecInd(EncodedStringValue from, - byte[] messageId, - int mmsVersion, - int readStatus, - EncodedStringValue[] to) throws InvalidHeaderValueException { - super(); - setMessageType(PduHeaders.MESSAGE_TYPE_READ_REC_IND); - setFrom(from); - setMessageId(messageId); - setMmsVersion(mmsVersion); - setTo(to); - setReadStatus(readStatus); - } - - /** - * Constructor with given headers. - * - * @param headers Headers for this PDU. - */ - ReadRecInd(PduHeaders headers) { - super(headers); - } - - /** - * Get Date value. - * - * @return the value - */ - public long getDate() { - return mPduHeaders.getLongInteger(PduHeaders.DATE); - } - - /** - * Set Date value. - * - * @param value the value - */ - public void setDate(long value) { - mPduHeaders.setLongInteger(value, PduHeaders.DATE); - } - - /** - * Get Message-ID value. - * - * @return the value - */ - public byte[] getMessageId() { - return mPduHeaders.getTextString(PduHeaders.MESSAGE_ID); - } - - /** - * Set Message-ID value. - * - * @param value the value - * @throws NullPointerException if the value is null. - */ - public void setMessageId(byte[] value) { - mPduHeaders.setTextString(value, PduHeaders.MESSAGE_ID); - } - - /** - * Get To value. - * - * @return the value - */ - public EncodedStringValue[] getTo() { - return mPduHeaders.getEncodedStringValues(PduHeaders.TO); - } - - /** - * Set To value. - * - * @param value the value - * @throws NullPointerException if the value is null. - */ - public void setTo(EncodedStringValue[] value) { - mPduHeaders.setEncodedStringValues(value, PduHeaders.TO); - } - - /** - * Get X-MMS-Read-status value. - * - * @return the value - */ - public int getReadStatus() { - return mPduHeaders.getOctet(PduHeaders.READ_STATUS); - } - - /** - * Set X-MMS-Read-status value. - * - * @param value the value - * @throws InvalidHeaderValueException if the value is invalid. - */ - public void setReadStatus(int value) throws InvalidHeaderValueException { - mPduHeaders.setOctet(value, PduHeaders.READ_STATUS); - } - - /* - * Optional, not supported header fields: - * - * public byte[] getApplicId() {return null;} - * public void setApplicId(byte[] value) {} - * - * public byte[] getAuxApplicId() {return null;} - * public void getAuxApplicId(byte[] value) {} - * - * public byte[] getReplyApplicId() {return 0x00;} - * public void setReplyApplicId(byte[] value) {} - */ -} diff --git a/core/java/com/google/android/mms/pdu/RetrieveConf.java b/core/java/com/google/android/mms/pdu/RetrieveConf.java deleted file mode 100644 index 98e67c0..0000000 --- a/core/java/com/google/android/mms/pdu/RetrieveConf.java +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright (C) 2007 Esmertec AG. - * Copyright (C) 2007 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.mms.pdu; - -import com.google.android.mms.InvalidHeaderValueException; - -/** - * M-Retrive.conf Pdu. - */ -public class RetrieveConf extends MultimediaMessagePdu { - /** - * Empty constructor. - * Since the Pdu corresponding to this class is constructed - * by the Proxy-Relay server, this class is only instantiated - * by the Pdu Parser. - * - * @throws InvalidHeaderValueException if error occurs. - */ - public RetrieveConf() throws InvalidHeaderValueException { - super(); - setMessageType(PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF); - } - - /** - * Constructor with given headers. - * - * @param headers Headers for this PDU. - */ - RetrieveConf(PduHeaders headers) { - super(headers); - } - - /** - * Constructor with given headers and body - * - * @param headers Headers for this PDU. - * @param body Body of this PDu. - */ - RetrieveConf(PduHeaders headers, PduBody body) { - super(headers, body); - } - - /** - * Get CC value. - * - * @return the value - */ - public EncodedStringValue[] getCc() { - return mPduHeaders.getEncodedStringValues(PduHeaders.CC); - } - - /** - * Add a "CC" value. - * - * @param value the value - * @throws NullPointerException if the value is null. - */ - public void addCc(EncodedStringValue value) { - mPduHeaders.appendEncodedStringValue(value, PduHeaders.CC); - } - - /** - * Get Content-type value. - * - * @return the value - */ - public byte[] getContentType() { - return mPduHeaders.getTextString(PduHeaders.CONTENT_TYPE); - } - - /** - * Set Content-type value. - * - * @param value the value - * @throws NullPointerException if the value is null. - */ - public void setContentType(byte[] value) { - mPduHeaders.setTextString(value, PduHeaders.CONTENT_TYPE); - } - - /** - * Get X-Mms-Delivery-Report value. - * - * @return the value - */ - public int getDeliveryReport() { - return mPduHeaders.getOctet(PduHeaders.DELIVERY_REPORT); - } - - /** - * Set X-Mms-Delivery-Report value. - * - * @param value the value - * @throws InvalidHeaderValueException if the value is invalid. - */ - public void setDeliveryReport(int value) throws InvalidHeaderValueException { - mPduHeaders.setOctet(value, PduHeaders.DELIVERY_REPORT); - } - - /** - * Get From value. - * From-value = Value-length - * (Address-present-token Encoded-string-value | Insert-address-token) - * - * @return the value - */ - public EncodedStringValue getFrom() { - return mPduHeaders.getEncodedStringValue(PduHeaders.FROM); - } - - /** - * Set From value. - * - * @param value the value - * @throws NullPointerException if the value is null. - */ - public void setFrom(EncodedStringValue value) { - mPduHeaders.setEncodedStringValue(value, PduHeaders.FROM); - } - - /** - * Get X-Mms-Message-Class value. - * Message-class-value = Class-identifier | Token-text - * Class-identifier = Personal | Advertisement | Informational | Auto - * - * @return the value - */ - public byte[] getMessageClass() { - return mPduHeaders.getTextString(PduHeaders.MESSAGE_CLASS); - } - - /** - * Set X-Mms-Message-Class value. - * - * @param value the value - * @throws NullPointerException if the value is null. - */ - public void setMessageClass(byte[] value) { - mPduHeaders.setTextString(value, PduHeaders.MESSAGE_CLASS); - } - - /** - * Get Message-ID value. - * - * @return the value - */ - public byte[] getMessageId() { - return mPduHeaders.getTextString(PduHeaders.MESSAGE_ID); - } - - /** - * Set Message-ID value. - * - * @param value the value - * @throws NullPointerException if the value is null. - */ - public void setMessageId(byte[] value) { - mPduHeaders.setTextString(value, PduHeaders.MESSAGE_ID); - } - - /** - * Get X-Mms-Read-Report value. - * - * @return the value - */ - public int getReadReport() { - return mPduHeaders.getOctet(PduHeaders.READ_REPORT); - } - - /** - * Set X-Mms-Read-Report value. - * - * @param value the value - * @throws InvalidHeaderValueException if the value is invalid. - */ - public void setReadReport(int value) throws InvalidHeaderValueException { - mPduHeaders.setOctet(value, PduHeaders.READ_REPORT); - } - - /** - * Get X-Mms-Retrieve-Status value. - * - * @return the value - */ - public int getRetrieveStatus() { - return mPduHeaders.getOctet(PduHeaders.RETRIEVE_STATUS); - } - - /** - * Set X-Mms-Retrieve-Status value. - * - * @param value the value - * @throws InvalidHeaderValueException if the value is invalid. - */ - public void setRetrieveStatus(int value) throws InvalidHeaderValueException { - mPduHeaders.setOctet(value, PduHeaders.RETRIEVE_STATUS); - } - - /** - * Get X-Mms-Retrieve-Text value. - * - * @return the value - */ - public EncodedStringValue getRetrieveText() { - return mPduHeaders.getEncodedStringValue(PduHeaders.RETRIEVE_TEXT); - } - - /** - * Set X-Mms-Retrieve-Text value. - * - * @param value the value - * @throws NullPointerException if the value is null. - */ - public void setRetrieveText(EncodedStringValue value) { - mPduHeaders.setEncodedStringValue(value, PduHeaders.RETRIEVE_TEXT); - } - - /** - * Get X-Mms-Transaction-Id. - * - * @return the value - */ - public byte[] getTransactionId() { - return mPduHeaders.getTextString(PduHeaders.TRANSACTION_ID); - } - - /** - * Set X-Mms-Transaction-Id. - * - * @param value the value - * @throws NullPointerException if the value is null. - */ - public void setTransactionId(byte[] value) { - mPduHeaders.setTextString(value, PduHeaders.TRANSACTION_ID); - } - - /* - * Optional, not supported header fields: - * - * public byte[] getApplicId() {return null;} - * public void setApplicId(byte[] value) {} - * - * public byte[] getAuxApplicId() {return null;} - * public void getAuxApplicId(byte[] value) {} - * - * public byte getContentClass() {return 0x00;} - * public void setApplicId(byte value) {} - * - * public byte getDrmContent() {return 0x00;} - * public void setDrmContent(byte value) {} - * - * public byte getDistributionIndicator() {return 0x00;} - * public void setDistributionIndicator(byte value) {} - * - * public PreviouslySentByValue getPreviouslySentBy() {return null;} - * public void setPreviouslySentBy(PreviouslySentByValue value) {} - * - * public PreviouslySentDateValue getPreviouslySentDate() {} - * public void setPreviouslySentDate(PreviouslySentDateValue value) {} - * - * public MmFlagsValue getMmFlags() {return null;} - * public void setMmFlags(MmFlagsValue value) {} - * - * public MmStateValue getMmState() {return null;} - * public void getMmState(MmStateValue value) {} - * - * public byte[] getReplaceId() {return 0x00;} - * public void setReplaceId(byte[] value) {} - * - * public byte[] getReplyApplicId() {return 0x00;} - * public void setReplyApplicId(byte[] value) {} - * - * public byte getReplyCharging() {return 0x00;} - * public void setReplyCharging(byte value) {} - * - * public byte getReplyChargingDeadline() {return 0x00;} - * public void setReplyChargingDeadline(byte value) {} - * - * public byte[] getReplyChargingId() {return 0x00;} - * public void setReplyChargingId(byte[] value) {} - * - * public long getReplyChargingSize() {return 0;} - * public void setReplyChargingSize(long value) {} - */ -} diff --git a/core/java/com/google/android/mms/pdu/SendConf.java b/core/java/com/google/android/mms/pdu/SendConf.java deleted file mode 100644 index 0568fe7..0000000 --- a/core/java/com/google/android/mms/pdu/SendConf.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2007 Esmertec AG. - * Copyright (C) 2007 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.mms.pdu; - -import com.google.android.mms.InvalidHeaderValueException; - -public class SendConf extends GenericPdu { - /** - * Empty constructor. - * Since the Pdu corresponding to this class is constructed - * by the Proxy-Relay server, this class is only instantiated - * by the Pdu Parser. - * - * @throws InvalidHeaderValueException if error occurs. - */ - public SendConf() throws InvalidHeaderValueException { - super(); - setMessageType(PduHeaders.MESSAGE_TYPE_SEND_CONF); - } - - /** - * Constructor with given headers. - * - * @param headers Headers for this PDU. - */ - SendConf(PduHeaders headers) { - super(headers); - } - - /** - * Get Message-ID value. - * - * @return the value - */ - public byte[] getMessageId() { - return mPduHeaders.getTextString(PduHeaders.MESSAGE_ID); - } - - /** - * Set Message-ID value. - * - * @param value the value - * @throws NullPointerException if the value is null. - */ - public void setMessageId(byte[] value) { - mPduHeaders.setTextString(value, PduHeaders.MESSAGE_ID); - } - - /** - * Get X-Mms-Response-Status. - * - * @return the value - */ - public int getResponseStatus() { - return mPduHeaders.getOctet(PduHeaders.RESPONSE_STATUS); - } - - /** - * Set X-Mms-Response-Status. - * - * @param value the values - * @throws InvalidHeaderValueException if the value is invalid. - */ - public void setResponseStatus(int value) throws InvalidHeaderValueException { - mPduHeaders.setOctet(value, PduHeaders.RESPONSE_STATUS); - } - - /** - * Get X-Mms-Transaction-Id field value. - * - * @return the X-Mms-Report-Allowed value - */ - public byte[] getTransactionId() { - return mPduHeaders.getTextString(PduHeaders.TRANSACTION_ID); - } - - /** - * Set X-Mms-Transaction-Id field value. - * - * @param value the value - * @throws NullPointerException if the value is null. - */ - public void setTransactionId(byte[] value) { - mPduHeaders.setTextString(value, PduHeaders.TRANSACTION_ID); - } - - /* - * Optional, not supported header fields: - * - * public byte[] getContentLocation() {return null;} - * public void setContentLocation(byte[] value) {} - * - * public EncodedStringValue getResponseText() {return null;} - * public void setResponseText(EncodedStringValue value) {} - * - * public byte getStoreStatus() {return 0x00;} - * public void setStoreStatus(byte value) {} - * - * public byte[] getStoreStatusText() {return null;} - * public void setStoreStatusText(byte[] value) {} - */ -} diff --git a/core/java/com/google/android/mms/pdu/SendReq.java b/core/java/com/google/android/mms/pdu/SendReq.java deleted file mode 100644 index 597cd00..0000000 --- a/core/java/com/google/android/mms/pdu/SendReq.java +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Copyright (C) 2007-2008 Esmertec AG. - * Copyright (C) 2007-2008 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.mms.pdu; - -import android.util.Log; - -import com.google.android.mms.InvalidHeaderValueException; - -public class SendReq extends MultimediaMessagePdu { - private static final String TAG = "SendReq"; - - public SendReq() { - super(); - - try { - setMessageType(PduHeaders.MESSAGE_TYPE_SEND_REQ); - setMmsVersion(PduHeaders.CURRENT_MMS_VERSION); - // FIXME: Content-type must be decided according to whether - // SMIL part present. - setContentType("application/vnd.wap.multipart.related".getBytes()); - setFrom(new EncodedStringValue(PduHeaders.FROM_INSERT_ADDRESS_TOKEN_STR.getBytes())); - setTransactionId(generateTransactionId()); - } catch (InvalidHeaderValueException e) { - // Impossible to reach here since all headers we set above are valid. - Log.e(TAG, "Unexpected InvalidHeaderValueException.", e); - throw new RuntimeException(e); - } - } - - private byte[] generateTransactionId() { - String transactionId = "T" + Long.toHexString(System.currentTimeMillis()); - return transactionId.getBytes(); - } - - /** - * Constructor, used when composing a M-Send.req pdu. - * - * @param contentType the content type value - * @param from the from value - * @param mmsVersion current viersion of mms - * @param transactionId the transaction-id value - * @throws InvalidHeaderValueException if parameters are invalid. - * NullPointerException if contentType, form or transactionId is null. - */ - public SendReq(byte[] contentType, - EncodedStringValue from, - int mmsVersion, - byte[] transactionId) throws InvalidHeaderValueException { - super(); - setMessageType(PduHeaders.MESSAGE_TYPE_SEND_REQ); - setContentType(contentType); - setFrom(from); - setMmsVersion(mmsVersion); - setTransactionId(transactionId); - } - - /** - * Constructor with given headers. - * - * @param headers Headers for this PDU. - */ - SendReq(PduHeaders headers) { - super(headers); - } - - /** - * Constructor with given headers and body - * - * @param headers Headers for this PDU. - * @param body Body of this PDu. - */ - SendReq(PduHeaders headers, PduBody body) { - super(headers, body); - } - - /** - * Get Bcc value. - * - * @return the value - */ - public EncodedStringValue[] getBcc() { - return mPduHeaders.getEncodedStringValues(PduHeaders.BCC); - } - - /** - * Add a "BCC" value. - * - * @param value the value - * @throws NullPointerException if the value is null. - */ - public void addBcc(EncodedStringValue value) { - mPduHeaders.appendEncodedStringValue(value, PduHeaders.BCC); - } - - /** - * Set "BCC" value. - * - * @param value the value - * @throws NullPointerException if the value is null. - */ - public void setBcc(EncodedStringValue[] value) { - mPduHeaders.setEncodedStringValues(value, PduHeaders.BCC); - } - - /** - * Get CC value. - * - * @return the value - */ - public EncodedStringValue[] getCc() { - return mPduHeaders.getEncodedStringValues(PduHeaders.CC); - } - - /** - * Add a "CC" value. - * - * @param value the value - * @throws NullPointerException if the value is null. - */ - public void addCc(EncodedStringValue value) { - mPduHeaders.appendEncodedStringValue(value, PduHeaders.CC); - } - - /** - * Set "CC" value. - * - * @param value the value - * @throws NullPointerException if the value is null. - */ - public void setCc(EncodedStringValue[] value) { - mPduHeaders.setEncodedStringValues(value, PduHeaders.CC); - } - - /** - * Get Content-type value. - * - * @return the value - */ - public byte[] getContentType() { - return mPduHeaders.getTextString(PduHeaders.CONTENT_TYPE); - } - - /** - * Set Content-type value. - * - * @param value the value - * @throws NullPointerException if the value is null. - */ - public void setContentType(byte[] value) { - mPduHeaders.setTextString(value, PduHeaders.CONTENT_TYPE); - } - - /** - * Get X-Mms-Delivery-Report value. - * - * @return the value - */ - public int getDeliveryReport() { - return mPduHeaders.getOctet(PduHeaders.DELIVERY_REPORT); - } - - /** - * Set X-Mms-Delivery-Report value. - * - * @param value the value - * @throws InvalidHeaderValueException if the value is invalid. - */ - public void setDeliveryReport(int value) throws InvalidHeaderValueException { - mPduHeaders.setOctet(value, PduHeaders.DELIVERY_REPORT); - } - - /** - * Get X-Mms-Expiry value. - * - * Expiry-value = Value-length - * (Absolute-token Date-value | Relative-token Delta-seconds-value) - * - * @return the value - */ - public long getExpiry() { - return mPduHeaders.getLongInteger(PduHeaders.EXPIRY); - } - - /** - * Set X-Mms-Expiry value. - * - * @param value the value - */ - public void setExpiry(long value) { - mPduHeaders.setLongInteger(value, PduHeaders.EXPIRY); - } - - /** - * Get X-Mms-MessageSize value. - * - * Expiry-value = size of message - * - * @return the value - */ - public long getMessageSize() { - return mPduHeaders.getLongInteger(PduHeaders.MESSAGE_SIZE); - } - - /** - * Set X-Mms-MessageSize value. - * - * @param value the value - */ - public void setMessageSize(long value) { - mPduHeaders.setLongInteger(value, PduHeaders.MESSAGE_SIZE); - } - - /** - * Get X-Mms-Message-Class value. - * Message-class-value = Class-identifier | Token-text - * Class-identifier = Personal | Advertisement | Informational | Auto - * - * @return the value - */ - public byte[] getMessageClass() { - return mPduHeaders.getTextString(PduHeaders.MESSAGE_CLASS); - } - - /** - * Set X-Mms-Message-Class value. - * - * @param value the value - * @throws NullPointerException if the value is null. - */ - public void setMessageClass(byte[] value) { - mPduHeaders.setTextString(value, PduHeaders.MESSAGE_CLASS); - } - - /** - * Get X-Mms-Read-Report value. - * - * @return the value - */ - public int getReadReport() { - return mPduHeaders.getOctet(PduHeaders.READ_REPORT); - } - - /** - * Set X-Mms-Read-Report value. - * - * @param value the value - * @throws InvalidHeaderValueException if the value is invalid. - */ - public void setReadReport(int value) throws InvalidHeaderValueException { - mPduHeaders.setOctet(value, PduHeaders.READ_REPORT); - } - - /** - * Set "To" value. - * - * @param value the value - * @throws NullPointerException if the value is null. - */ - public void setTo(EncodedStringValue[] value) { - mPduHeaders.setEncodedStringValues(value, PduHeaders.TO); - } - - /** - * Get X-Mms-Transaction-Id field value. - * - * @return the X-Mms-Report-Allowed value - */ - public byte[] getTransactionId() { - return mPduHeaders.getTextString(PduHeaders.TRANSACTION_ID); - } - - /** - * Set X-Mms-Transaction-Id field value. - * - * @param value the value - * @throws NullPointerException if the value is null. - */ - public void setTransactionId(byte[] value) { - mPduHeaders.setTextString(value, PduHeaders.TRANSACTION_ID); - } - - /* - * Optional, not supported header fields: - * - * public byte getAdaptationAllowed() {return 0}; - * public void setAdaptationAllowed(btye value) {}; - * - * public byte[] getApplicId() {return null;} - * public void setApplicId(byte[] value) {} - * - * public byte[] getAuxApplicId() {return null;} - * public void getAuxApplicId(byte[] value) {} - * - * public byte getContentClass() {return 0x00;} - * public void setApplicId(byte value) {} - * - * public long getDeliveryTime() {return 0}; - * public void setDeliveryTime(long value) {}; - * - * public byte getDrmContent() {return 0x00;} - * public void setDrmContent(byte value) {} - * - * public MmFlagsValue getMmFlags() {return null;} - * public void setMmFlags(MmFlagsValue value) {} - * - * public MmStateValue getMmState() {return null;} - * public void getMmState(MmStateValue value) {} - * - * public byte[] getReplyApplicId() {return 0x00;} - * public void setReplyApplicId(byte[] value) {} - * - * public byte getReplyCharging() {return 0x00;} - * public void setReplyCharging(byte value) {} - * - * public byte getReplyChargingDeadline() {return 0x00;} - * public void setReplyChargingDeadline(byte value) {} - * - * public byte[] getReplyChargingId() {return 0x00;} - * public void setReplyChargingId(byte[] value) {} - * - * public long getReplyChargingSize() {return 0;} - * public void setReplyChargingSize(long value) {} - * - * public byte[] getReplyApplicId() {return 0x00;} - * public void setReplyApplicId(byte[] value) {} - * - * public byte getStore() {return 0x00;} - * public void setStore(byte value) {} - */ -} diff --git a/core/java/com/google/android/mms/pdu/package.html b/core/java/com/google/android/mms/pdu/package.html deleted file mode 100755 index c9f96a6..0000000 --- a/core/java/com/google/android/mms/pdu/package.html +++ /dev/null @@ -1,5 +0,0 @@ -<body> - -{@hide} - -</body> diff --git a/core/java/com/google/android/mms/util/AbstractCache.java b/core/java/com/google/android/mms/util/AbstractCache.java deleted file mode 100644 index 39b2abf..0000000 --- a/core/java/com/google/android/mms/util/AbstractCache.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2008 Esmertec AG. - * Copyright (C) 2008 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.mms.util; - -import android.util.Log; - -import java.util.HashMap; - -public abstract class AbstractCache<K, V> { - private static final String TAG = "AbstractCache"; - private static final boolean DEBUG = false; - private static final boolean LOCAL_LOGV = false; - - private static final int MAX_CACHED_ITEMS = 500; - - private final HashMap<K, CacheEntry<V>> mCacheMap; - - protected AbstractCache() { - mCacheMap = new HashMap<K, CacheEntry<V>>(); - } - - public boolean put(K key, V value) { - if (LOCAL_LOGV) { - Log.v(TAG, "Trying to put " + key + " into cache."); - } - - if (mCacheMap.size() >= MAX_CACHED_ITEMS) { - // TODO Should remove the oldest or least hit cached entry - // and then cache the new one. - if (LOCAL_LOGV) { - Log.v(TAG, "Failed! size limitation reached."); - } - return false; - } - - if (key != null) { - CacheEntry<V> cacheEntry = new CacheEntry<V>(); - cacheEntry.value = value; - mCacheMap.put(key, cacheEntry); - - if (LOCAL_LOGV) { - Log.v(TAG, key + " cached, " + mCacheMap.size() + " items total."); - } - return true; - } - return false; - } - - public V get(K key) { - if (LOCAL_LOGV) { - Log.v(TAG, "Trying to get " + key + " from cache."); - } - - if (key != null) { - CacheEntry<V> cacheEntry = mCacheMap.get(key); - if (cacheEntry != null) { - cacheEntry.hit++; - if (LOCAL_LOGV) { - Log.v(TAG, key + " hit " + cacheEntry.hit + " times."); - } - return cacheEntry.value; - } - } - return null; - } - - public V purge(K key) { - if (LOCAL_LOGV) { - Log.v(TAG, "Trying to purge " + key); - } - - CacheEntry<V> v = mCacheMap.remove(key); - - if (LOCAL_LOGV) { - Log.v(TAG, mCacheMap.size() + " items cached."); - } - - return v != null ? v.value : null; - } - - public void purgeAll() { - if (LOCAL_LOGV) { - Log.v(TAG, "Purging cache, " + mCacheMap.size() - + " items dropped."); - } - mCacheMap.clear(); - } - - public int size() { - return mCacheMap.size(); - } - - private static class CacheEntry<V> { - int hit; - V value; - } -} diff --git a/core/java/com/google/android/mms/util/DownloadDrmHelper.java b/core/java/com/google/android/mms/util/DownloadDrmHelper.java deleted file mode 100644 index 6852eca..0000000 --- a/core/java/com/google/android/mms/util/DownloadDrmHelper.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2012 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.mms.util; - -import android.content.Context; -import android.drm.DrmManagerClient; -import android.util.Log; - -public class DownloadDrmHelper { - private static final String TAG = "DownloadDrmHelper"; - - /** The MIME type of special DRM files */ - public static final String MIMETYPE_DRM_MESSAGE = "application/vnd.oma.drm.message"; - - /** The extensions of special DRM files */ - public static final String EXTENSION_DRM_MESSAGE = ".dm"; - - public static final String EXTENSION_INTERNAL_FWDL = ".fl"; - - /** - * Checks if the Media Type is a DRM Media Type - * - * @param drmManagerClient A DrmManagerClient - * @param mimetype Media Type to check - * @return True if the Media Type is DRM else false - */ - public static boolean isDrmMimeType(Context context, String mimetype) { - boolean result = false; - if (context != null) { - try { - DrmManagerClient drmClient = new DrmManagerClient(context); - if (drmClient != null && mimetype != null && mimetype.length() > 0) { - result = drmClient.canHandle("", mimetype); - } - } catch (IllegalArgumentException e) { - Log.w(TAG, - "DrmManagerClient instance could not be created, context is Illegal."); - } catch (IllegalStateException e) { - Log.w(TAG, "DrmManagerClient didn't initialize properly."); - } - } - return result; - } - - /** - * Checks if the Media Type needs to be DRM converted - * - * @param mimetype Media type of the content - * @return True if convert is needed else false - */ - public static boolean isDrmConvertNeeded(String mimetype) { - return MIMETYPE_DRM_MESSAGE.equals(mimetype); - } - - /** - * Modifies the file extension for a DRM Forward Lock file NOTE: This - * function shouldn't be called if the file shouldn't be DRM converted - */ - public static String modifyDrmFwLockFileExtension(String filename) { - if (filename != null) { - int extensionIndex; - extensionIndex = filename.lastIndexOf("."); - if (extensionIndex != -1) { - filename = filename.substring(0, extensionIndex); - } - filename = filename.concat(EXTENSION_INTERNAL_FWDL); - } - return filename; - } - - /** - * Gets the original mime type of DRM protected content. - * - * @param context The context - * @param path Path to the file - * @param containingMime The current mime type of of the file i.e. the - * containing mime type - * @return The original mime type of the file if DRM protected else the - * currentMime - */ - public static String getOriginalMimeType(Context context, String path, String containingMime) { - String result = containingMime; - DrmManagerClient drmClient = new DrmManagerClient(context); - try { - if (drmClient.canHandle(path, null)) { - result = drmClient.getOriginalMimeType(path); - } - } catch (IllegalArgumentException ex) { - Log.w(TAG, - "Can't get original mime type since path is null or empty string."); - } catch (IllegalStateException ex) { - Log.w(TAG, "DrmManagerClient didn't initialize properly."); - } - return result; - } -} diff --git a/core/java/com/google/android/mms/util/DrmConvertSession.java b/core/java/com/google/android/mms/util/DrmConvertSession.java deleted file mode 100644 index 2d8f274..0000000 --- a/core/java/com/google/android/mms/util/DrmConvertSession.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (C) 2012 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.mms.util; - -import android.content.Context; -import android.drm.DrmConvertedStatus; -import android.drm.DrmManagerClient; -import android.util.Log; -import android.provider.Downloads; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.RandomAccessFile; - - -public class DrmConvertSession { - private DrmManagerClient mDrmClient; - private int mConvertSessionId; - private static final String TAG = "DrmConvertSession"; - - private DrmConvertSession(DrmManagerClient drmClient, int convertSessionId) { - mDrmClient = drmClient; - mConvertSessionId = convertSessionId; - } - - /** - * Start of converting a file. - * - * @param context The context of the application running the convert session. - * @param mimeType Mimetype of content that shall be converted. - * @return A convert session or null in case an error occurs. - */ - public static DrmConvertSession open(Context context, String mimeType) { - DrmManagerClient drmClient = null; - int convertSessionId = -1; - if (context != null && mimeType != null && !mimeType.equals("")) { - try { - drmClient = new DrmManagerClient(context); - try { - convertSessionId = drmClient.openConvertSession(mimeType); - } catch (IllegalArgumentException e) { - Log.w(TAG, "Conversion of Mimetype: " + mimeType - + " is not supported.", e); - } catch (IllegalStateException e) { - Log.w(TAG, "Could not access Open DrmFramework.", e); - } - } catch (IllegalArgumentException e) { - Log.w(TAG, - "DrmManagerClient instance could not be created, context is Illegal."); - } catch (IllegalStateException e) { - Log.w(TAG, "DrmManagerClient didn't initialize properly."); - } - } - - if (drmClient == null || convertSessionId < 0) { - return null; - } else { - return new DrmConvertSession(drmClient, convertSessionId); - } - } - /** - * Convert a buffer of data to protected format. - * - * @param buffer Buffer filled with data to convert. - * @param size The number of bytes that shall be converted. - * @return A Buffer filled with converted data, if execution is ok, in all - * other case null. - */ - public byte [] convert(byte[] inBuffer, int size) { - byte[] result = null; - if (inBuffer != null) { - DrmConvertedStatus convertedStatus = null; - try { - if (size != inBuffer.length) { - byte[] buf = new byte[size]; - System.arraycopy(inBuffer, 0, buf, 0, size); - convertedStatus = mDrmClient.convertData(mConvertSessionId, buf); - } else { - convertedStatus = mDrmClient.convertData(mConvertSessionId, inBuffer); - } - - if (convertedStatus != null && - convertedStatus.statusCode == DrmConvertedStatus.STATUS_OK && - convertedStatus.convertedData != null) { - result = convertedStatus.convertedData; - } - } catch (IllegalArgumentException e) { - Log.w(TAG, "Buffer with data to convert is illegal. Convertsession: " - + mConvertSessionId, e); - } catch (IllegalStateException e) { - Log.w(TAG, "Could not convert data. Convertsession: " + - mConvertSessionId, e); - } - } else { - throw new IllegalArgumentException("Parameter inBuffer is null"); - } - return result; - } - - /** - * Ends a conversion session of a file. - * - * @param fileName The filename of the converted file. - * @return Downloads.Impl.STATUS_SUCCESS if execution is ok. - * Downloads.Impl.STATUS_FILE_ERROR in case converted file can not - * be accessed. Downloads.Impl.STATUS_NOT_ACCEPTABLE if a problem - * occurs when accessing drm framework. - * Downloads.Impl.STATUS_UNKNOWN_ERROR if a general error occurred. - */ - public int close(String filename) { - DrmConvertedStatus convertedStatus = null; - int result = Downloads.Impl.STATUS_UNKNOWN_ERROR; - if (mDrmClient != null && mConvertSessionId >= 0) { - try { - convertedStatus = mDrmClient.closeConvertSession(mConvertSessionId); - if (convertedStatus == null || - convertedStatus.statusCode != DrmConvertedStatus.STATUS_OK || - convertedStatus.convertedData == null) { - result = Downloads.Impl.STATUS_NOT_ACCEPTABLE; - } else { - RandomAccessFile rndAccessFile = null; - try { - rndAccessFile = new RandomAccessFile(filename, "rw"); - rndAccessFile.seek(convertedStatus.offset); - rndAccessFile.write(convertedStatus.convertedData); - result = Downloads.Impl.STATUS_SUCCESS; - } catch (FileNotFoundException e) { - result = Downloads.Impl.STATUS_FILE_ERROR; - Log.w(TAG, "File: " + filename + " could not be found.", e); - } catch (IOException e) { - result = Downloads.Impl.STATUS_FILE_ERROR; - Log.w(TAG, "Could not access File: " + filename + " .", e); - } catch (IllegalArgumentException e) { - result = Downloads.Impl.STATUS_FILE_ERROR; - Log.w(TAG, "Could not open file in mode: rw", e); - } catch (SecurityException e) { - Log.w(TAG, "Access to File: " + filename + - " was denied denied by SecurityManager.", e); - } finally { - if (rndAccessFile != null) { - try { - rndAccessFile.close(); - } catch (IOException e) { - result = Downloads.Impl.STATUS_FILE_ERROR; - Log.w(TAG, "Failed to close File:" + filename - + ".", e); - } - } - } - } - } catch (IllegalStateException e) { - Log.w(TAG, "Could not close convertsession. Convertsession: " + - mConvertSessionId, e); - } - } - return result; - } -} diff --git a/core/java/com/google/android/mms/util/PduCache.java b/core/java/com/google/android/mms/util/PduCache.java deleted file mode 100644 index de83124..0000000 --- a/core/java/com/google/android/mms/util/PduCache.java +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright (C) 2008 Esmertec AG. - * Copyright (C) 2008 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.mms.util; - -import android.content.ContentUris; -import android.content.UriMatcher; -import android.net.Uri; -import android.provider.Telephony.Mms; -import android.util.Log; - -import java.util.HashMap; -import java.util.HashSet; - -public final class PduCache extends AbstractCache<Uri, PduCacheEntry> { - private static final String TAG = "PduCache"; - private static final boolean DEBUG = false; - private static final boolean LOCAL_LOGV = false; - - private static final int MMS_ALL = 0; - private static final int MMS_ALL_ID = 1; - private static final int MMS_INBOX = 2; - private static final int MMS_INBOX_ID = 3; - private static final int MMS_SENT = 4; - private static final int MMS_SENT_ID = 5; - private static final int MMS_DRAFTS = 6; - private static final int MMS_DRAFTS_ID = 7; - private static final int MMS_OUTBOX = 8; - private static final int MMS_OUTBOX_ID = 9; - private static final int MMS_CONVERSATION = 10; - private static final int MMS_CONVERSATION_ID = 11; - - private static final UriMatcher URI_MATCHER; - private static final HashMap<Integer, Integer> MATCH_TO_MSGBOX_ID_MAP; - - private static PduCache sInstance; - - static { - URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH); - URI_MATCHER.addURI("mms", null, MMS_ALL); - URI_MATCHER.addURI("mms", "#", MMS_ALL_ID); - URI_MATCHER.addURI("mms", "inbox", MMS_INBOX); - URI_MATCHER.addURI("mms", "inbox/#", MMS_INBOX_ID); - URI_MATCHER.addURI("mms", "sent", MMS_SENT); - URI_MATCHER.addURI("mms", "sent/#", MMS_SENT_ID); - URI_MATCHER.addURI("mms", "drafts", MMS_DRAFTS); - URI_MATCHER.addURI("mms", "drafts/#", MMS_DRAFTS_ID); - URI_MATCHER.addURI("mms", "outbox", MMS_OUTBOX); - URI_MATCHER.addURI("mms", "outbox/#", MMS_OUTBOX_ID); - URI_MATCHER.addURI("mms-sms", "conversations", MMS_CONVERSATION); - URI_MATCHER.addURI("mms-sms", "conversations/#", MMS_CONVERSATION_ID); - - MATCH_TO_MSGBOX_ID_MAP = new HashMap<Integer, Integer>(); - MATCH_TO_MSGBOX_ID_MAP.put(MMS_INBOX, Mms.MESSAGE_BOX_INBOX); - MATCH_TO_MSGBOX_ID_MAP.put(MMS_SENT, Mms.MESSAGE_BOX_SENT); - MATCH_TO_MSGBOX_ID_MAP.put(MMS_DRAFTS, Mms.MESSAGE_BOX_DRAFTS); - MATCH_TO_MSGBOX_ID_MAP.put(MMS_OUTBOX, Mms.MESSAGE_BOX_OUTBOX); - } - - private final HashMap<Integer, HashSet<Uri>> mMessageBoxes; - private final HashMap<Long, HashSet<Uri>> mThreads; - private final HashSet<Uri> mUpdating; - - private PduCache() { - mMessageBoxes = new HashMap<Integer, HashSet<Uri>>(); - mThreads = new HashMap<Long, HashSet<Uri>>(); - mUpdating = new HashSet<Uri>(); - } - - synchronized public static final PduCache getInstance() { - if (sInstance == null) { - if (LOCAL_LOGV) { - Log.v(TAG, "Constructing new PduCache instance."); - } - sInstance = new PduCache(); - } - return sInstance; - } - - @Override - synchronized public boolean put(Uri uri, PduCacheEntry entry) { - int msgBoxId = entry.getMessageBox(); - HashSet<Uri> msgBox = mMessageBoxes.get(msgBoxId); - if (msgBox == null) { - msgBox = new HashSet<Uri>(); - mMessageBoxes.put(msgBoxId, msgBox); - } - - long threadId = entry.getThreadId(); - HashSet<Uri> thread = mThreads.get(threadId); - if (thread == null) { - thread = new HashSet<Uri>(); - mThreads.put(threadId, thread); - } - - Uri finalKey = normalizeKey(uri); - boolean result = super.put(finalKey, entry); - if (result) { - msgBox.add(finalKey); - thread.add(finalKey); - } - setUpdating(uri, false); - return result; - } - - synchronized public void setUpdating(Uri uri, boolean updating) { - if (updating) { - mUpdating.add(uri); - } else { - mUpdating.remove(uri); - } - } - - synchronized public boolean isUpdating(Uri uri) { - return mUpdating.contains(uri); - } - - @Override - synchronized public PduCacheEntry purge(Uri uri) { - int match = URI_MATCHER.match(uri); - switch (match) { - case MMS_ALL_ID: - return purgeSingleEntry(uri); - case MMS_INBOX_ID: - case MMS_SENT_ID: - case MMS_DRAFTS_ID: - case MMS_OUTBOX_ID: - String msgId = uri.getLastPathSegment(); - return purgeSingleEntry(Uri.withAppendedPath(Mms.CONTENT_URI, msgId)); - // Implicit batch of purge, return null. - case MMS_ALL: - case MMS_CONVERSATION: - purgeAll(); - return null; - case MMS_INBOX: - case MMS_SENT: - case MMS_DRAFTS: - case MMS_OUTBOX: - purgeByMessageBox(MATCH_TO_MSGBOX_ID_MAP.get(match)); - return null; - case MMS_CONVERSATION_ID: - purgeByThreadId(ContentUris.parseId(uri)); - return null; - default: - return null; - } - } - - private PduCacheEntry purgeSingleEntry(Uri key) { - mUpdating.remove(key); - PduCacheEntry entry = super.purge(key); - if (entry != null) { - removeFromThreads(key, entry); - removeFromMessageBoxes(key, entry); - return entry; - } - return null; - } - - @Override - synchronized public void purgeAll() { - super.purgeAll(); - - mMessageBoxes.clear(); - mThreads.clear(); - mUpdating.clear(); - } - - /** - * @param uri The Uri to be normalized. - * @return Uri The normalized key of cached entry. - */ - private Uri normalizeKey(Uri uri) { - int match = URI_MATCHER.match(uri); - Uri normalizedKey = null; - - switch (match) { - case MMS_ALL_ID: - normalizedKey = uri; - break; - case MMS_INBOX_ID: - case MMS_SENT_ID: - case MMS_DRAFTS_ID: - case MMS_OUTBOX_ID: - String msgId = uri.getLastPathSegment(); - normalizedKey = Uri.withAppendedPath(Mms.CONTENT_URI, msgId); - break; - default: - return null; - } - - if (LOCAL_LOGV) { - Log.v(TAG, uri + " -> " + normalizedKey); - } - return normalizedKey; - } - - private void purgeByMessageBox(Integer msgBoxId) { - if (LOCAL_LOGV) { - Log.v(TAG, "Purge cache in message box: " + msgBoxId); - } - - if (msgBoxId != null) { - HashSet<Uri> msgBox = mMessageBoxes.remove(msgBoxId); - if (msgBox != null) { - for (Uri key : msgBox) { - mUpdating.remove(key); - PduCacheEntry entry = super.purge(key); - if (entry != null) { - removeFromThreads(key, entry); - } - } - } - } - } - - private void removeFromThreads(Uri key, PduCacheEntry entry) { - HashSet<Uri> thread = mThreads.get(entry.getThreadId()); - if (thread != null) { - thread.remove(key); - } - } - - private void purgeByThreadId(long threadId) { - if (LOCAL_LOGV) { - Log.v(TAG, "Purge cache in thread: " + threadId); - } - - HashSet<Uri> thread = mThreads.remove(threadId); - if (thread != null) { - for (Uri key : thread) { - mUpdating.remove(key); - PduCacheEntry entry = super.purge(key); - if (entry != null) { - removeFromMessageBoxes(key, entry); - } - } - } - } - - private void removeFromMessageBoxes(Uri key, PduCacheEntry entry) { - HashSet<Uri> msgBox = mThreads.get(Long.valueOf(entry.getMessageBox())); - if (msgBox != null) { - msgBox.remove(key); - } - } -} diff --git a/core/java/com/google/android/mms/util/PduCacheEntry.java b/core/java/com/google/android/mms/util/PduCacheEntry.java deleted file mode 100644 index 8b41386..0000000 --- a/core/java/com/google/android/mms/util/PduCacheEntry.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2008 Esmertec AG. - * Copyright (C) 2008 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.mms.util; - -import com.google.android.mms.pdu.GenericPdu; - -public final class PduCacheEntry { - private final GenericPdu mPdu; - private final int mMessageBox; - private final long mThreadId; - - public PduCacheEntry(GenericPdu pdu, int msgBox, long threadId) { - mPdu = pdu; - mMessageBox = msgBox; - mThreadId = threadId; - } - - public GenericPdu getPdu() { - return mPdu; - } - - public int getMessageBox() { - return mMessageBox; - } - - public long getThreadId() { - return mThreadId; - } -} diff --git a/core/java/com/google/android/mms/util/SqliteWrapper.java b/core/java/com/google/android/mms/util/SqliteWrapper.java deleted file mode 100644 index bcdac22..0000000 --- a/core/java/com/google/android/mms/util/SqliteWrapper.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2008 Esmertec AG. - * Copyright (C) 2008 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.mms.util; - -import android.app.ActivityManager; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.database.sqlite.SQLiteException; -import android.net.Uri; -import android.util.Log; -import android.widget.Toast; - -public final class SqliteWrapper { - private static final String TAG = "SqliteWrapper"; - private static final String SQLITE_EXCEPTION_DETAIL_MESSAGE - = "unable to open database file"; - - private SqliteWrapper() { - // Forbidden being instantiated. - } - - // FIXME: It looks like outInfo.lowMemory does not work well as we expected. - // after run command: adb shell fillup -p 100, outInfo.lowMemory is still false. - private static boolean isLowMemory(Context context) { - if (null == context) { - return false; - } - - ActivityManager am = (ActivityManager) - context.getSystemService(Context.ACTIVITY_SERVICE); - ActivityManager.MemoryInfo outInfo = new ActivityManager.MemoryInfo(); - am.getMemoryInfo(outInfo); - - return outInfo.lowMemory; - } - - // FIXME: need to optimize this method. - private static boolean isLowMemory(SQLiteException e) { - return e.getMessage().equals(SQLITE_EXCEPTION_DETAIL_MESSAGE); - } - - public static void checkSQLiteException(Context context, SQLiteException e) { - if (isLowMemory(e)) { - Toast.makeText(context, com.android.internal.R.string.low_memory, - Toast.LENGTH_SHORT).show(); - } else { - throw e; - } - } - - public static Cursor query(Context context, ContentResolver resolver, Uri uri, - String[] projection, String selection, String[] selectionArgs, String sortOrder) { - try { - return resolver.query(uri, projection, selection, selectionArgs, sortOrder); - } catch (SQLiteException e) { - Log.e(TAG, "Catch a SQLiteException when query: ", e); - checkSQLiteException(context, e); - return null; - } - } - - public static boolean requery(Context context, Cursor cursor) { - try { - return cursor.requery(); - } catch (SQLiteException e) { - Log.e(TAG, "Catch a SQLiteException when requery: ", e); - checkSQLiteException(context, e); - return false; - } - } - public static int update(Context context, ContentResolver resolver, Uri uri, - ContentValues values, String where, String[] selectionArgs) { - try { - return resolver.update(uri, values, where, selectionArgs); - } catch (SQLiteException e) { - Log.e(TAG, "Catch a SQLiteException when update: ", e); - checkSQLiteException(context, e); - return -1; - } - } - - public static int delete(Context context, ContentResolver resolver, Uri uri, - String where, String[] selectionArgs) { - try { - return resolver.delete(uri, where, selectionArgs); - } catch (SQLiteException e) { - Log.e(TAG, "Catch a SQLiteException when delete: ", e); - checkSQLiteException(context, e); - return -1; - } - } - - public static Uri insert(Context context, ContentResolver resolver, - Uri uri, ContentValues values) { - try { - return resolver.insert(uri, values); - } catch (SQLiteException e) { - Log.e(TAG, "Catch a SQLiteException when insert: ", e); - checkSQLiteException(context, e); - return null; - } - } -} diff --git a/core/java/com/google/android/mms/util/package.html b/core/java/com/google/android/mms/util/package.html deleted file mode 100755 index c9f96a6..0000000 --- a/core/java/com/google/android/mms/util/package.html +++ /dev/null @@ -1,5 +0,0 @@ -<body> - -{@hide} - -</body> |
