Merge change 692 into donut
* changes:
location: Optimize use of mProviders ArrayList.
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 3bd76a6..dfa3fa8 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -161,7 +161,7 @@
return metrics;
}
- Resources getTopLevelResources(String appDir) {
+ Resources getTopLevelResources(String appDir, float applicationScale) {
synchronized (mPackages) {
//Log.w(TAG, "getTopLevelResources: " + appDir);
WeakReference<Resources> wr = mActiveResources.get(appDir);
@@ -181,7 +181,27 @@
return null;
}
DisplayMetrics metrics = getDisplayMetricsLocked(false);
- r = new Resources(assets, metrics, getConfiguration());
+ // density used to load resources
+ // scaledDensity is calculated in Resources constructor
+ //
+ boolean usePreloaded = true;
+
+ // TODO: use explicit flag to indicate the compatibility mode.
+ if (applicationScale != 1.0f) {
+ usePreloaded = false;
+ DisplayMetrics newMetrics = new DisplayMetrics();
+ newMetrics.setTo(metrics);
+ float invertedScale = 1.0f / applicationScale;
+ newMetrics.density *= invertedScale;
+ newMetrics.xdpi *= invertedScale;
+ newMetrics.ydpi *= invertedScale;
+ newMetrics.widthPixels *= invertedScale;
+ newMetrics.heightPixels *= invertedScale;
+ metrics = newMetrics;
+ }
+ //Log.i(TAG, "Resource:" + appDir + ", density " + newMetrics.density + ", orig density:" +
+ // metrics.density);
+ r = new Resources(assets, metrics, getConfiguration(), usePreloaded);
//Log.i(TAG, "Created app resources " + r + ": " + r.getConfiguration());
// XXX need to remove entries when weak references go away
mActiveResources.put(appDir, new WeakReference<Resources>(r));
@@ -209,6 +229,8 @@
private Resources mResources;
private ClassLoader mClassLoader;
private Application mApplication;
+ private float mApplicationScale;
+
private final HashMap<Context, HashMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers
= new HashMap<Context, HashMap<BroadcastReceiver, ReceiverDispatcher>>();
private final HashMap<Context, HashMap<BroadcastReceiver, ReceiverDispatcher>> mUnregisteredReceivers
@@ -241,8 +263,8 @@
mSystemContext =
ApplicationContext.createSystemContext(mainThread);
mSystemContext.getResources().updateConfiguration(
- mainThread.getConfiguration(),
- mainThread.getDisplayMetricsLocked(false));
+ mainThread.getConfiguration(),
+ mainThread.getDisplayMetricsLocked(false));
//Log.i(TAG, "Created system resources "
// + mSystemContext.getResources() + ": "
// + mSystemContext.getResources().getConfiguration());
@@ -250,6 +272,8 @@
mClassLoader = mSystemContext.getClassLoader();
mResources = mSystemContext.getResources();
}
+
+ mApplicationScale = -1.0f;
}
public PackageInfo(ActivityThread activityThread, String name,
@@ -268,6 +292,7 @@
mIncludeCode = true;
mClassLoader = systemContext.getClassLoader();
mResources = systemContext.getResources();
+ mApplicationScale = systemContext.getApplicationScale();
}
public String getPackageName() {
@@ -278,6 +303,47 @@
return mSecurityViolation;
}
+ public float getApplicationScale() {
+ if (mApplicationScale > 0.0f) {
+ return mApplicationScale;
+ }
+ DisplayMetrics metrics = mActivityThread.getDisplayMetricsLocked(false);
+ // Find out the density scale (relative to 160) of the supported density that
+ // is closest to the system's density.
+ try {
+ ApplicationInfo ai = getPackageManager().getApplicationInfo(
+ mPackageName, PackageManager.GET_SUPPORTS_DENSITIES);
+
+ float appScale = -1.0f;
+ if (ai.supportsDensities != null) {
+ // TODO: precompute this in DisplayMetrics
+ float systemDensityDpi = metrics.density * DisplayMetrics.DEFAULT_DENSITY;
+ int minDiff = Integer.MAX_VALUE;
+ for (int density : ai.supportsDensities) {
+ int tmpDiff = (int) Math.abs(systemDensityDpi - density);
+ if (tmpDiff == 0) {
+ appScale = 1.0f;
+ break;
+ }
+ // prefer higher density (appScale>1.0), unless that's only option.
+ if (tmpDiff < minDiff && appScale < 1.0f) {
+ appScale = systemDensityDpi / density;
+ minDiff = tmpDiff;
+ }
+ }
+ }
+ if (appScale < 0.0f) {
+ mApplicationScale = metrics.density;
+ } else {
+ mApplicationScale = appScale;
+ }
+ } catch (RemoteException e) {
+ throw new AssertionError(e);
+ }
+ if (localLOGV) Log.v(TAG, "appScale=" + mApplicationScale + ", pkg=" + mPackageName);
+ return mApplicationScale;
+ }
+
/**
* Gets the array of shared libraries that are listed as
* used by the given package.
@@ -435,7 +501,7 @@
public Resources getResources(ActivityThread mainThread) {
if (mResources == null) {
- mResources = mainThread.getTopLevelResources(mResDir);
+ mResources = mainThread.getTopLevelResources(mResDir, getApplicationScale());
}
return mResources;
}
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index 55fce49..a1f5a58 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -550,6 +550,19 @@
}
}
+ /**
+ * @hide
+ */
+ @Override
+ public float getApplicationScale() {
+ if (mPackageInfo != null) {
+ return mPackageInfo.getApplicationScale();
+ } else {
+ // same as system density
+ return 1.0f;
+ }
+ }
+
@Override
public void setWallpaper(Bitmap bitmap) throws IOException {
try {
@@ -2008,9 +2021,11 @@
if (app.packageName.equals("system")) {
return mContext.mMainThread.getSystemContext().getResources();
}
+ ActivityThread.PackageInfo pi = mContext.mMainThread.getPackageInfoNoCheck(app);
Resources r = mContext.mMainThread.getTopLevelResources(
app.uid == Process.myUid() ? app.sourceDir
- : app.publicSourceDir);
+ : app.publicSourceDir,
+ pi.getApplicationScale());
if (r != null) {
return r;
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 600dfa4..a301449 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -527,6 +527,16 @@
public abstract int getWallpaperDesiredMinimumHeight();
/**
+ * Returns the scale in which the application will be drawn on the
+ * screen. This is usually 1.0f if the application supports the device's
+ * resolution/density. This will be 1.5f, for example, if the application
+ * that supports only 160 density runs on 240 density screen.
+ *
+ * @hide
+ */
+ public abstract float getApplicationScale();
+
+ /**
* Change the current system wallpaper to a bitmap. The given bitmap is
* converted to a PNG and stored as the wallpaper. On success, the intent
* {@link Intent#ACTION_WALLPAPER_CHANGED} is broadcast.
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 36e1c34..25b2cae 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -419,4 +419,12 @@
throws PackageManager.NameNotFoundException {
return mBase.createPackageContext(packageName, flags);
}
+
+ /**
+ * @hide
+ */
+ @Override
+ public float getApplicationScale() {
+ return mBase.getApplicationScale();
+ }
}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index e020462..665e40c 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -24,6 +24,7 @@
import android.graphics.Movie;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.os.SystemProperties;
@@ -56,12 +57,14 @@
// Information about preloaded resources. Note that they are not
// protected by a lock, because while preloading in zygote we are all
// single-threaded, and after that these are immutable.
- private static final SparseArray<Drawable.ConstantState> mPreloadedDrawables
+ private static final SparseArray<Drawable.ConstantState> sPreloadedDrawables
= new SparseArray<Drawable.ConstantState>();
private static final SparseArray<ColorStateList> mPreloadedColorStateLists
= new SparseArray<ColorStateList>();
private static boolean mPreloaded;
+ private final SparseArray<Drawable.ConstantState> mPreloadedDrawables;
+
/*package*/ final TypedValue mTmpValue = new TypedValue();
// These are protected by the mTmpValue lock.
@@ -82,6 +85,22 @@
/*package*/ final DisplayMetrics mMetrics = new DisplayMetrics();
PluralRules mPluralRule;
+ private static final SparseArray<Object> EMPTY_ARRAY = new SparseArray<Object>() {
+ @Override
+ public void put(int k, Object o) {
+ throw new UnsupportedOperationException();
+ }
+ @Override
+ public void append(int k, Object o) {
+ throw new UnsupportedOperationException();
+ }
+ };
+
+ @SuppressWarnings("unchecked")
+ private static <T> SparseArray<T> emptySparseArray() {
+ return (SparseArray<T>) EMPTY_ARRAY;
+ }
+
/**
* This exception is thrown by the resource APIs when a requested resource
* can not be found.
@@ -107,11 +126,27 @@
*/
public Resources(AssetManager assets, DisplayMetrics metrics,
Configuration config) {
+ this(assets, metrics, config, true);
+ }
+
+ /**
+ * Create a resource with an additional flag for preloaded
+ * drawable cache. Used by {@link ActivityThread}.
+ *
+ * @hide
+ */
+ public Resources(AssetManager assets, DisplayMetrics metrics,
+ Configuration config, boolean usePreloadedCache) {
mAssets = assets;
mConfiguration.setToDefaults();
mMetrics.setToDefaults();
updateConfiguration(config, metrics);
assets.ensureStringBlocks();
+ if (usePreloadedCache) {
+ mPreloadedDrawables = sPreloadedDrawables;
+ } else {
+ mPreloadedDrawables = emptySparseArray();
+ }
}
/**
@@ -1218,6 +1253,7 @@
mMetrics.setTo(metrics);
}
mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;
+
String locale = null;
if (mConfiguration.locale != null) {
locale = mConfiguration.locale.getLanguage();
@@ -1653,7 +1689,7 @@
cs = dr.getConstantState();
if (cs != null) {
if (mPreloading) {
- mPreloadedDrawables.put(key, cs);
+ sPreloadedDrawables.put(key, cs);
} else {
synchronized (mTmpValue) {
//Log.i(TAG, "Saving cached drawable @ #" +
@@ -1883,6 +1919,6 @@
mMetrics.setToDefaults();
updateConfiguration(null, null);
mAssets.ensureStringBlocks();
+ mPreloadedDrawables = sPreloadedDrawables;
}
}
-
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 882a079..2402660 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -102,7 +102,7 @@
private float mYPrecision;
private int mDeviceId;
private int mEdgeFlags;
-
+
private MotionEvent mNext;
private RuntimeException mRecycledLocation;
private boolean mRecycled;
@@ -210,7 +210,29 @@
return ev;
}
-
+
+ /**
+ * Scales down the cood of this event by the given scale.
+ *
+ * @hide
+ */
+ public void scale(float scale) {
+ if (scale != 1.0f) {
+ mX *= scale;
+ mY *= scale;
+ mRawX *= scale;
+ mRawY *= scale;
+ mSize *= scale;
+ mXPrecision *= scale;
+ mYPrecision *= scale;
+ float[] history = mHistory;
+ int length = history.length;
+ for (int i = 0; i < length; i++) {
+ history[i] *= scale;
+ }
+ }
+ }
+
/**
* Create a new MotionEvent, copying from an existing one.
*/
@@ -682,4 +704,3 @@
}
}
-
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index e928998..61dca4c 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -135,20 +135,28 @@
int mFormat = -1;
int mType = -1;
final Rect mSurfaceFrame = new Rect();
+ private final float mAppScale;
+ private final float mAppScaleInverted;
public SurfaceView(Context context) {
super(context);
setWillNotDraw(true);
+ mAppScale = context.getApplicationScale();
+ mAppScaleInverted = 1.0f / mAppScale;
}
public SurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(true);
+ mAppScale = context.getApplicationScale();
+ mAppScaleInverted = 1.0f / mAppScale;
}
public SurfaceView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setWillNotDraw(true);
+ mAppScale = context.getApplicationScale();
+ mAppScaleInverted = 1.0f / mAppScale;
}
/**
@@ -297,8 +305,8 @@
mLayout.x = mLeft;
mLayout.y = mTop;
- mLayout.width = getWidth();
- mLayout.height = getHeight();
+ mLayout.width = (int) (getWidth() * mAppScale);
+ mLayout.height = (int) (getHeight() * mAppScale);
mLayout.format = mRequestedFormat;
mLayout.flags |=WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
| WindowManager.LayoutParams.FLAG_SCALED
@@ -325,9 +333,14 @@
mSurfaceLock.lock();
mDrawingStopped = !visible;
final int relayoutResult = mSession.relayout(
- mWindow, mLayout, mWidth, mHeight,
+ mWindow, mLayout, (int) (mWidth * mAppScale), (int) (mHeight * mAppScale),
visible ? VISIBLE : GONE, false, mWinFrame, mContentInsets,
mVisibleInsets, mSurface);
+
+ mContentInsets.scale(mAppScaleInverted);
+ mVisibleInsets.scale(mAppScaleInverted);
+ mWinFrame.scale(mAppScaleInverted);
+
if (localLOGV) Log.i(TAG, "New surface: " + mSurface
+ ", vis=" + visible + ", frame=" + mWinFrame);
mSurfaceFrame.left = 0;
@@ -395,15 +408,25 @@
}
private static class MyWindow extends IWindow.Stub {
- private WeakReference<SurfaceView> mSurfaceView;
+ private final WeakReference<SurfaceView> mSurfaceView;
+ private final float mAppScale;
+ private final float mAppScaleInverted;
public MyWindow(SurfaceView surfaceView) {
mSurfaceView = new WeakReference<SurfaceView>(surfaceView);
+ mAppScale = surfaceView.getContext().getApplicationScale();
+ mAppScaleInverted = 1.0f / mAppScale;
}
public void resized(int w, int h, Rect coveredInsets,
Rect visibleInsets, boolean reportDraw) {
SurfaceView surfaceView = mSurfaceView.get();
+ float scale = mAppScaleInverted;
+ w *= scale;
+ h *= scale;
+ coveredInsets.scale(scale);
+ visibleInsets.scale(scale);
+
if (surfaceView != null) {
if (localLOGV) Log.v(
"SurfaceView", surfaceView + " got resized: w=" +
@@ -566,6 +589,7 @@
Canvas c = null;
if (!mDrawingStopped && mWindow != null) {
Rect frame = dirty != null ? dirty : mSurfaceFrame;
+ frame.scale(mAppScale);
try {
c = mSurface.lockCanvas(frame);
} catch (Exception e) {
@@ -611,4 +635,3 @@
}
};
}
-
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 18ee9ae..0b03626 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -128,6 +128,9 @@
int mHeight;
Rect mDirty; // will be a graphics.Region soon
boolean mIsAnimating;
+ // TODO: change these to scaler class.
+ float mAppScale;
+ float mAppScaleInverted; // = 1.0f / mAppScale
final View.AttachInfo mAttachInfo;
@@ -384,10 +387,12 @@
View panelParentView) {
synchronized (this) {
if (mView == null) {
+ mView = view;
+ mAppScale = mView.getContext().getApplicationScale();
+ mAppScaleInverted = 1.0f / mAppScale;
mWindowAttributes.copyFrom(attrs);
mSoftInputMode = attrs.softInputMode;
mWindowAttributesChanged = true;
- mView = view;
mAttachInfo.mRootView = view;
if (panelParentView != null) {
mAttachInfo.mPanelParentWindowToken
@@ -400,7 +405,7 @@
// manager, to make sure we do the relayout before receiving
// any other events from the system.
requestLayout();
-
+
try {
res = sWindowSession.add(mWindow, attrs,
getHostVisibility(), mAttachInfo.mContentInsets);
@@ -411,6 +416,7 @@
unscheduleTraversals();
throw new RuntimeException("Adding window failed", e);
}
+ mAttachInfo.mContentInsets.scale(mAppScaleInverted);
mPendingContentInsets.set(mAttachInfo.mContentInsets);
mPendingVisibleInsets.set(0, 0, 0, 0);
if (Config.LOGV) Log.v("ViewRoot", "Added window " + mWindow);
@@ -472,6 +478,8 @@
synchronized (this) {
int oldSoftInputMode = mWindowAttributes.softInputMode;
mWindowAttributes.copyFrom(attrs);
+ mWindowAttributes.scale(mAppScale);
+
if (newView) {
mSoftInputMode = attrs.softInputMode;
requestLayout();
@@ -521,9 +529,14 @@
public void invalidateChild(View child, Rect dirty) {
checkThread();
if (LOCAL_LOGV) Log.v(TAG, "Invalidate child: " + dirty);
- if (mCurScrollY != 0) {
+ if (mCurScrollY != 0 || mAppScale != 1.0f) {
mTempRect.set(dirty);
- mTempRect.offset(0, -mCurScrollY);
+ if (mCurScrollY != 0) {
+ mTempRect.offset(0, -mCurScrollY);
+ }
+ if (mAppScale != 1.0f) {
+ mTempRect.scale(mAppScale);
+ }
dirty = mTempRect;
}
mDirty.union(dirty);
@@ -613,8 +626,8 @@
mLayoutRequested = true;
Display d = new Display(0);
- desiredWindowWidth = d.getWidth();
- desiredWindowHeight = d.getHeight();
+ desiredWindowWidth = (int) (d.getWidth() * mAppScaleInverted);
+ desiredWindowHeight = (int) (d.getHeight() * mAppScaleInverted);
// For the very first time, tell the view hierarchy that it
// is attached to the window. Note that at this point the surface
@@ -683,8 +696,8 @@
windowResizesToFitContent = true;
Display d = new Display(0);
- desiredWindowWidth = d.getWidth();
- desiredWindowHeight = d.getHeight();
+ desiredWindowWidth = (int) (d.getWidth() * mAppScaleInverted);
+ desiredWindowHeight = (int) (d.getHeight() * mAppScaleInverted);
}
}
@@ -792,10 +805,12 @@
params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
}
}
- relayoutResult = sWindowSession.relayout(
- mWindow, params, host.mMeasuredWidth, host.mMeasuredHeight,
- viewVisibility, insetsPending, frame,
- mPendingContentInsets, mPendingVisibleInsets, mSurface);
+ if (DEBUG_LAYOUT) {
+ Log.i(TAG, "host=w:" + host.mMeasuredWidth + ", h:" +
+ host.mMeasuredHeight + ", params=" + params);
+ }
+ relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
+
if (params != null) {
params.flags = fl;
}
@@ -862,7 +877,7 @@
mHeight = frame.height();
if (initialized) {
- mGlCanvas.setViewport(mWidth, mHeight);
+ mGlCanvas.setViewport((int) (mWidth * mAppScale), (int) (mHeight * mAppScale));
}
boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
@@ -944,6 +959,11 @@
mTmpLocation[1] + host.mBottom - host.mTop);
host.gatherTransparentRegion(mTransparentRegion);
+
+ // TODO: scale the region, like:
+ // Region uses native methods. We probabl should have ScalableRegion class.
+
+ // Region does not have equals method ?
if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
mPreviousTransparentRegion.set(mTransparentRegion);
// reconfigure window manager
@@ -974,6 +994,9 @@
givenContent.left = givenContent.top = givenContent.right
= givenContent.bottom = givenVisible.left = givenVisible.top
= givenVisible.right = givenVisible.bottom = 0;
+ insets.contentInsets.scale(mAppScale);
+ insets.visibleInsets.scale(mAppScale);
+
attachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
if (insetsPending || !mLastGivenInsets.equals(insets)) {
mLastGivenInsets.set(insets);
@@ -1113,7 +1136,7 @@
int yoff;
final boolean scrolling = mScroller != null
- && mScroller.computeScrollOffset();
+ && mScroller.computeScrollOffset();
if (scrolling) {
yoff = mScroller.getCurrY();
} else {
@@ -1135,10 +1158,19 @@
mGL.glEnable(GL_SCISSOR_TEST);
mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
- canvas.translate(0, -yoff);
mView.mPrivateFlags |= View.DRAWN;
- mView.draw(canvas);
- canvas.translate(0, yoff);
+
+ float scale = mAppScale;
+ int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
+ try {
+ canvas.translate(0, -yoff);
+ if (scale != 1.0f) {
+ canvas.scale(scale, scale);
+ }
+ mView.draw(canvas);
+ } finally {
+ canvas.restoreToCount(saveCount);
+ }
mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
checkEglErrors();
@@ -1160,7 +1192,7 @@
}
if (fullRedrawNeeded)
- dirty.union(0, 0, mWidth, mHeight);
+ dirty.union(0, 0, (int) (mWidth * mAppScale), (int) (mHeight * mAppScale));
if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Log.v("ViewRoot", "Draw " + mView + "/"
@@ -1212,10 +1244,24 @@
dirty.setEmpty();
mIsAnimating = false;
mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
- canvas.translate(0, -yoff);
- mView.mPrivateFlags |= View.DRAWN;
- mView.draw(canvas);
- canvas.translate(0, yoff);
+ mView.mPrivateFlags |= View.DRAWN;
+
+ float scale = mAppScale;
+ Context cxt = mView.getContext();
+ if (DEBUG_DRAW) {
+ Log.i(TAG, "Drawing: package:" + cxt.getPackageName() + ", appScale=" + mAppScale);
+ }
+ int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
+ try {
+ canvas.translate(0, -yoff);
+ if (scale != 1.0f) {
+ // re-scale this
+ canvas.scale(scale, scale);
+ }
+ mView.draw(canvas);
+ } finally {
+ canvas.restoreToCount(saveCount);
+ }
if (SHOW_FPS) {
int now = (int)SystemClock.elapsedRealtime();
@@ -1508,6 +1554,9 @@
} else {
didFinish = event.getAction() == MotionEvent.ACTION_OUTSIDE;
}
+ if (event != null) {
+ event.scale(mAppScaleInverted);
+ }
try {
boolean handled;
@@ -1628,7 +1677,8 @@
if (mGlWanted && !mUseGL) {
initializeGL();
if (mGlCanvas != null) {
- mGlCanvas.setViewport(mWidth, mHeight);
+ mGlCanvas.setViewport((int) (mWidth * mAppScale),
+ (int) (mHeight * mAppScale));
}
}
}
@@ -1828,6 +1878,9 @@
} else {
didFinish = false;
}
+ if (event != null) {
+ event.scale(mAppScaleInverted);
+ }
if (DEBUG_TRACKBALL) Log.v(TAG, "Motion event:" + event);
@@ -2254,6 +2307,20 @@
return mAudioManager;
}
+ private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
+ boolean insetsPending) throws RemoteException {
+ int relayoutResult = sWindowSession.relayout(
+ mWindow, params,
+ (int) (mView.mMeasuredWidth * mAppScale),
+ (int) (mView.mMeasuredHeight * mAppScale),
+ viewVisibility, insetsPending, mWinFrame,
+ mPendingContentInsets, mPendingVisibleInsets, mSurface);
+ mPendingContentInsets.scale(mAppScaleInverted);
+ mPendingVisibleInsets.scale(mAppScaleInverted);
+ mWinFrame.scale(mAppScaleInverted);
+ return relayoutResult;
+ }
+
/**
* {@inheritDoc}
*/
@@ -2322,12 +2389,8 @@
// to the window manager to make sure it has the correct
// animation info.
try {
- if ((sWindowSession.relayout(
- mWindow, mWindowAttributes,
- mView.mMeasuredWidth, mView.mMeasuredHeight,
- viewVisibility, false, mWinFrame, mPendingContentInsets,
- mPendingVisibleInsets, mSurface)
- &WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
+ if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
+ & WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
sWindowSession.finishDrawing(mWindow);
}
} catch (RemoteException e) {
@@ -2361,8 +2424,11 @@
+ " visibleInsets=" + visibleInsets.toShortString()
+ " reportDraw=" + reportDraw);
Message msg = obtainMessage(reportDraw ? RESIZED_REPORT :RESIZED);
- msg.arg1 = w;
- msg.arg2 = h;
+
+ coveredInsets.scale(mAppScaleInverted);
+ visibleInsets.scale(mAppScaleInverted);
+ msg.arg1 = (int) (w * mAppScaleInverted);
+ msg.arg2 = (int) (h * mAppScaleInverted);
msg.obj = new Rect[] { new Rect(coveredInsets), new Rect(visibleInsets) };
sendMessage(msg);
}
@@ -2493,7 +2559,7 @@
sWindowSession.finishKey(mWindow);
} catch (RemoteException e) {
}
- } else if (mIsPointer) {
+ } else if (mIsPointer) {
boolean didFinish;
MotionEvent event = mMotionEvent;
if (event == null) {
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 34e65ad..f6a171d 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -954,7 +954,7 @@
return sb.toString();
}
- void scaleUp(float scale) {
+ void scale(float scale) {
if (scale != 1.0f) {
x *= scale;
y *= scale;
diff --git a/graphics/java/android/graphics/Rect.java b/graphics/java/android/graphics/Rect.java
index 7022acf..50ab566 100644
--- a/graphics/java/android/graphics/Rect.java
+++ b/graphics/java/android/graphics/Rect.java
@@ -545,4 +545,17 @@
right = in.readInt();
bottom = in.readInt();
}
+
+ /**
+ * Scales up the rect by the given scale.
+ * @hide
+ */
+ public void scale(float scale) {
+ if (scale != 1.0f) {
+ left *= scale;
+ top *= scale;
+ right *= scale;
+ bottom*= scale;
+ }
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index 6428e90..677d609 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -40,10 +40,6 @@
import java.io.UnsupportedEncodingException;
import java.util.Random;
-import static android.telephony.SmsMessage.ENCODING_7BIT;
-import static android.telephony.SmsMessage.ENCODING_8BIT;
-import static android.telephony.SmsMessage.ENCODING_16BIT;
-import static android.telephony.SmsMessage.ENCODING_UNKNOWN;
import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES;
import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER;
import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS;
@@ -685,41 +681,22 @@
}
/**
- * Parses the User Data of an SMS.
+ * Copy parsed user data out from internal datastructures.
*/
private void parseUserData(UserData uData) {
- int encodingType;
-
- if (null == uData) {
+ if (uData == null) {
return;
}
- encodingType = uData.msgEncoding;
-
- // insert DCS-decoding here when type is supported by ril-library
-
userData = uData.payload;
userDataHeader = uData.userDataHeader;
-
- switch (encodingType) {
- case UserData.ENCODING_GSM_7BIT_ALPHABET:
- case UserData.ENCODING_7BIT_ASCII:
- case UserData.ENCODING_UNICODE_16:
- // user data was already decoded by wmsts-library
- messageBody = new String(userData);
- break;
-
- // data and unsupported encodings:
- case UserData.ENCODING_OCTET:
- default:
- messageBody = null;
- break;
- }
-
- if (Config.LOGV) Log.v(LOG_TAG, "SMS message body (raw): '" + messageBody + "'");
+ messageBody = uData.payloadStr;
if (messageBody != null) {
+ if (Config.LOGV) Log.v(LOG_TAG, "SMS message body: '" + messageBody + "'");
parseMessageBody();
+ } else if ((userData != null) && (Config.LOGV)) {
+ Log.v(LOG_TAG, "SMS payload: '" + IccUtils.bytesToHexString(userData) + "'");
}
}
@@ -727,7 +704,7 @@
* {@inheritDoc}
*/
public MessageClass getMessageClass() {
- if (BearerData.DISPLAY_IMMEDIATE == mBearerData.displayMode ) {
+ if (BearerData.DISPLAY_MODE_IMMEDIATE == mBearerData.displayMode ) {
return MessageClass.CLASS_0;
} else {
return MessageClass.UNKNOWN;
@@ -780,9 +757,6 @@
mBearerData.readAckReq = false;
mBearerData.reportReq = false;
- // Set the display mode (See C.S0015-B, v2.0, 4.5.16)
- mBearerData.displayMode = BearerData.DISPLAY_DEFAULT;
-
// number of messages: not needed for encoding!
// indicate whether a user data header is available
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
index 8e67387..b5952a1 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -46,14 +46,14 @@
//private final static byte SUBPARAM_VALIDITY_PERIOD_RELATIVE = 0x05;
//private final static byte SUBPARAM_DEFERRED_DELIVERY_TIME_ABSOLUTE = 0x06;
//private final static byte SUBPARAM_DEFERRED_DELIVERY_TIME_RELATIVE = 0x07;
- //private final static byte SUBPARAM_PRIORITY_INDICATOR = 0x08;
- //private final static byte SUBPARAM_PRIVACY_INDICATOR = 0x09;
+ private final static byte SUBPARAM_PRIORITY_INDICATOR = 0x08;
+ private final static byte SUBPARAM_PRIVACY_INDICATOR = 0x09;
private final static byte SUBPARAM_REPLY_OPTION = 0x0A;
private final static byte SUBPARAM_NUMBER_OF_MESSAGES = 0x0B;
- //private final static byte SUBPARAM_ALERT_ON_MESSAGE_DELIVERY = 0x0C;
- //private final static byte SUBPARAM_LANGUAGE_INDICATOR = 0x0D;
+ private final static byte SUBPARAM_ALERT_ON_MESSAGE_DELIVERY = 0x0C;
+ private final static byte SUBPARAM_LANGUAGE_INDICATOR = 0x0D;
private final static byte SUBPARAM_CALLBACK_NUMBER = 0x0E;
- //private final static byte SUBPARAM_MESSAGE_DISPLAY_MODE = 0x0F;
+ private final static byte SUBPARAM_MESSAGE_DISPLAY_MODE = 0x0F;
//private final static byte SUBPARAM_MULTIPLE_ENCODING_USER_DATA = 0x10;
//private final static byte SUBPARAM_MESSAGE_DEPOSIT_INDEX = 0x11;
//private final static byte SUBPARAM_SERVICE_CATEGORY_PROGRAM_DATA = 0x12;
@@ -63,42 +63,6 @@
//private final static byte SUBPARAM_ENHANCED_VMN = 0x16;
//private final static byte SUBPARAM_ENHANCED_VMN_ACK = 0x17;
- // For completeness the following fields are listed, though not used yet.
- /**
- * Supported priority modes for CDMA SMS messages
- * (See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1)
- */
- //public static final int PRIORITY_NORMAL = 0x0;
- //public static final int PRIORITY_INTERACTIVE = 0x1;
- //public static final int PRIORITY_URGENT = 0x2;
- //public static final int PRIORITY_EMERGENCY = 0x3;
-
- /**
- * Supported privacy modes for CDMA SMS messages
- * (See 3GPP2 C.S0015-B, v2.0, table 4.5.10-1)
- */
- //public static final int PRIVACY_NOT_RESTRICTED = 0x0;
- //public static final int PRIVACY_RESTRICTED = 0x1;
- //public static final int PRIVACY_CONFIDENTIAL = 0x2;
- //public static final int PRIVACY_SECRET = 0x3;
-
- /**
- * Supported alert modes for CDMA SMS messages
- * (See 3GPP2 C.S0015-B, v2.0, table 4.5.13-1)
- */
- //public static final int ALERT_DEFAULT = 0x0;
- //public static final int ALERT_LOW_PRIO = 0x1;
- //public static final int ALERT_MEDIUM_PRIO = 0x2;
- //public static final int ALERT_HIGH_PRIO = 0x3;
-
- /**
- * Supported display modes for CDMA SMS messages
- * (See 3GPP2 C.S0015-B, v2.0, table 4.5.16-1)
- */
- public static final int DISPLAY_IMMEDIATE = 0x0;
- public static final int DISPLAY_DEFAULT = 0x1;
- public static final int DISPLAY_USER = 0x2;
-
/**
* Supported message types for CDMA SMS messages
* (See 3GPP2 C.S0015-B, v2.0, table 4.5.1-1)
@@ -112,9 +76,89 @@
public static final int MESSAGE_TYPE_DELIVER_REPORT = 0x07;
public static final int MESSAGE_TYPE_SUBMIT_REPORT = 0x08;
+ public byte messageType;
+
/**
- * SMS Message Status Codes
- * (See 3GPP2 C.S0015-B, v2.0, table 4.5.21-1)
+ * 16-bit value indicating the message ID, which increments modulo 65536.
+ * (Special rules apply for WAP-messages.)
+ * (See 3GPP2 C.S0015-B, v2, 4.5.1)
+ */
+ public int messageId;
+
+ /**
+ * Supported priority modes for CDMA SMS messages
+ * (See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1)
+ */
+ public static final int PRIORITY_NORMAL = 0x0;
+ public static final int PRIORITY_INTERACTIVE = 0x1;
+ public static final int PRIORITY_URGENT = 0x2;
+ public static final int PRIORITY_EMERGENCY = 0x3;
+
+ public boolean priorityIndicatorSet = false;
+ public byte priority = PRIORITY_NORMAL;
+
+ /**
+ * Supported privacy modes for CDMA SMS messages
+ * (See 3GPP2 C.S0015-B, v2.0, table 4.5.10-1)
+ */
+ public static final int PRIVACY_NOT_RESTRICTED = 0x0;
+ public static final int PRIVACY_RESTRICTED = 0x1;
+ public static final int PRIVACY_CONFIDENTIAL = 0x2;
+ public static final int PRIVACY_SECRET = 0x3;
+
+ public boolean privacyIndicatorSet = false;
+ public byte privacy = PRIVACY_NOT_RESTRICTED;
+
+ /**
+ * Supported alert priority modes for CDMA SMS messages
+ * (See 3GPP2 C.S0015-B, v2.0, table 4.5.13-1)
+ */
+ public static final int ALERT_DEFAULT = 0x0;
+ public static final int ALERT_LOW_PRIO = 0x1;
+ public static final int ALERT_MEDIUM_PRIO = 0x2;
+ public static final int ALERT_HIGH_PRIO = 0x3;
+
+ public boolean alertIndicatorSet = false;
+ public int alert = ALERT_DEFAULT;
+
+ /**
+ * Supported display modes for CDMA SMS messages. Display mode is
+ * a 2-bit value used to indicate to the mobile station when to
+ * display the received message. (See 3GPP2 C.S0015-B, v2,
+ * 4.5.16)
+ */
+ public static final int DISPLAY_MODE_IMMEDIATE = 0x0;
+ public static final int DISPLAY_MODE_DEFAULT = 0x1;
+ public static final int DISPLAY_MODE_USER = 0x2;
+
+ public boolean displayModeSet = false;
+ public byte displayMode = DISPLAY_MODE_DEFAULT;
+
+ /**
+ * Language Indicator values. NOTE: the spec (3GPP2 C.S0015-B,
+ * v2, 4.5.14) is ambiguous as to the meaning of this field, as it
+ * refers to C.R1001-D but that reference has been crossed out.
+ * It would seem reasonable to assume the values from C.R1001-F
+ * (table 9.2-1) are to be used instead.
+ */
+ public static final int LANGUAGE_UNKNOWN = 0x00;
+ public static final int LANGUAGE_ENGLISH = 0x01;
+ public static final int LANGUAGE_FRENCH = 0x02;
+ public static final int LANGUAGE_SPANISH = 0x03;
+ public static final int LANGUAGE_JAPANESE = 0x04;
+ public static final int LANGUAGE_KOREAN = 0x05;
+ public static final int LANGUAGE_CHINESE = 0x06;
+ public static final int LANGUAGE_HEBREW = 0x07;
+
+ public boolean languageIndicatorSet = false;
+ public int language = LANGUAGE_UNKNOWN;
+
+ /**
+ * SMS Message Status Codes. The first component of the Message
+ * status indicates if an error has occurred and whether the error
+ * is considered permanent or temporary. The second component of
+ * the Message status indicates the cause of the error (if any).
+ * (See 3GPP2 C.S0015-B, v2.0, 4.5.21)
*/
/* no-error codes */
public static final int ERROR_NONE = 0x00;
@@ -139,19 +183,9 @@
public static final int ERROR_UNDEFINED = 0xFF;
public static final int STATUS_UNDEFINED = 0xFF;
- /**
- * 4-bit value indicating the message type in accordance to
- * table 4.5.1-1
- * (See 3GPP2 C.S0015-B, v2, 4.5.1)
- */
- public byte messageType;
-
- /**
- * 16-bit value indicating the message ID, which increments modulo 65536.
- * (Special rules apply for WAP-messages.)
- * (See 3GPP2 C.S0015-B, v2, 4.5.1)
- */
- public int messageId;
+ public boolean messageStatusSet = false;
+ public int errorClass = ERROR_UNDEFINED;
+ public int messageStatus = STATUS_UNDEFINED;
/**
* 1-bit value that indicates whether a User Data Header is present.
@@ -178,8 +212,6 @@
//public SmsRelTime validityPeriodRelative;
//public SmsTime deferredDeliveryTimeAbsolute;
//public SmsRelTime deferredDeliveryTimeRelative;
- //public byte priority;
- //public byte privacy;
/**
* Reply Option
@@ -199,9 +231,6 @@
*/
public int numberOfMessages;
- //public int alert;
- //public int language;
-
/**
* 4-bit or 8-bit value that indicates the number to be dialed in reply to a
* received SMS message.
@@ -209,27 +238,6 @@
*/
public CdmaSmsAddress callbackNumber;
- /**
- * 2-bit value that is used to indicate to the mobile station when to display
- * the received message.
- * (See 3GPP2 C.S0015-B, v2, 4.5.16)
- */
- public byte displayMode = DISPLAY_DEFAULT;
-
- /**
- * First component of the Message status, that indicates if an error has occurred
- * and whether the error is considered permanent or temporary.
- * (See 3GPP2 C.S0015-B, v2, 4.5.21)
- */
- public int errorClass = ERROR_UNDEFINED;
-
- /**
- * Second component of the Message status, that indicates if an error has occurred
- * and the cause of the error.
- * (See 3GPP2 C.S0015-B, v2, 4.5.21)
- */
- public int messageStatus = STATUS_UNDEFINED;
-
private static class CodingException extends Exception {
public CodingException(String s) {
super(s);
@@ -242,6 +250,13 @@
builder.append("BearerData:\n");
builder.append(" messageType: " + messageType + "\n");
builder.append(" messageId: " + (int)messageId + "\n");
+ builder.append(" priority: " + (priorityIndicatorSet ? priority : "not set") + "\n");
+ builder.append(" privacy: " + (privacyIndicatorSet ? privacy : "not set") + "\n");
+ builder.append(" alert: " + (alertIndicatorSet ? alert : "not set") + "\n");
+ builder.append(" displayMode: " + (displayModeSet ? displayMode : "not set") + "\n");
+ builder.append(" language: " + (languageIndicatorSet ? language : "not set") + "\n");
+ builder.append(" errorClass: " + (messageStatusSet ? errorClass : "not set") + "\n");
+ builder.append(" messageStatus: " + (messageStatusSet ? messageStatus : "not set") + "\n");
builder.append(" hasUserDataHeader: " + hasUserDataHeader + "\n");
builder.append(" timeStamp: " + timeStamp + "\n");
builder.append(" userAckReq: " + userAckReq + "\n");
@@ -250,9 +265,6 @@
builder.append(" reportReq: " + reportReq + "\n");
builder.append(" numberOfMessages: " + numberOfMessages + "\n");
builder.append(" callbackNumber: " + callbackNumber + "\n");
- builder.append(" displayMode: " + displayMode + "\n");
- builder.append(" errorClass: " + errorClass + "\n");
- builder.append(" messageStatus: " + messageStatus + "\n");
builder.append(" userData: " + userData + "\n");
return builder.toString();
}
@@ -387,6 +399,45 @@
outStream.writeByteArray(6 * 8, bData.timeStamp);
}
+ private static void encodePrivacyIndicator(BearerData bData, BitwiseOutputStream outStream)
+ throws BitwiseOutputStream.AccessException
+ {
+ outStream.write(8, 1);
+ outStream.write(2, bData.privacy);
+ outStream.skip(6);
+ }
+
+ private static void encodeLanguageIndicator(BearerData bData, BitwiseOutputStream outStream)
+ throws BitwiseOutputStream.AccessException
+ {
+ outStream.write(8, 1);
+ outStream.write(8, bData.language);
+ }
+
+ private static void encodeDisplayMode(BearerData bData, BitwiseOutputStream outStream)
+ throws BitwiseOutputStream.AccessException
+ {
+ outStream.write(8, 1);
+ outStream.write(2, bData.displayMode);
+ outStream.skip(6);
+ }
+
+ private static void encodePriorityIndicator(BearerData bData, BitwiseOutputStream outStream)
+ throws BitwiseOutputStream.AccessException
+ {
+ outStream.write(8, 1);
+ outStream.write(2, bData.priority);
+ outStream.skip(6);
+ }
+
+ private static void encodeMsgDeliveryAlert(BearerData bData, BitwiseOutputStream outStream)
+ throws BitwiseOutputStream.AccessException
+ {
+ outStream.write(8, 1);
+ outStream.write(2, bData.alert);
+ outStream.skip(6);
+ }
+
/**
* Create serialized representation for BearerData object.
* (See 3GPP2 C.R1001-F, v1.0, section 4.5 for layout details)
@@ -420,6 +471,30 @@
outStream.write(8, SUBPARAM_MESSAGE_CENTER_TIME_STAMP);
encodeMsgCenterTimeStamp(bData, outStream);
}
+ if (bData.privacyIndicatorSet) {
+ outStream.write(8, SUBPARAM_PRIVACY_INDICATOR);
+ encodePrivacyIndicator(bData, outStream);
+ }
+ if (bData.languageIndicatorSet) {
+ outStream.write(8, SUBPARAM_LANGUAGE_INDICATOR);
+ encodeLanguageIndicator(bData, outStream);
+ }
+ if (bData.displayModeSet) {
+ outStream.write(8, SUBPARAM_MESSAGE_DISPLAY_MODE);
+ encodeDisplayMode(bData, outStream);
+ }
+ if (bData.priorityIndicatorSet) {
+ outStream.write(8, SUBPARAM_PRIORITY_INDICATOR);
+ encodePriorityIndicator(bData, outStream);
+ }
+ if (bData.alertIndicatorSet) {
+ outStream.write(8, SUBPARAM_ALERT_ON_MESSAGE_DELIVERY);
+ encodeMsgDeliveryAlert(bData, outStream);
+ }
+ if (bData.messageStatusSet) {
+ outStream.write(8, SUBPARAM_MESSAGE_STATUS);
+ encodeMsgStatus(bData, outStream);
+ }
return outStream.toByteArray();
} catch (BitwiseOutputStream.AccessException ex) {
Log.e(LOG_TAG, "BearerData encode failed: " + ex);
@@ -471,6 +546,33 @@
}
}
+ private static String decodeIa5(byte[] data, int offset, int numFields) {
+ try {
+ StringBuffer strBuf = new StringBuffer(numFields);
+ BitwiseInputStream inStream = new BitwiseInputStream(data);
+ inStream.skip(offset);
+ int wantedBits = numFields * 7;
+ if (inStream.available() < wantedBits) {
+ throw new CodingException("insufficient data (wanted " + wantedBits +
+ " bits, but only have " + inStream.available() + ")");
+ }
+ for (int i = 0; i < numFields; i++) {
+ int charCode = inStream.read(7);
+ if ((charCode < UserData.IA5_MAP_BASE_INDEX) ||
+ (charCode > UserData.IA5_MAP_MAX_INDEX)) {
+ throw new CodingException("unsupported AI5 character code (" + charCode + ")");
+ }
+ strBuf.append(UserData.IA5_MAP[charCode - UserData.IA5_MAP_BASE_INDEX]);
+ }
+ return strBuf.toString();
+ } catch (BitwiseInputStream.AccessException ex) {
+ Log.e(LOG_TAG, "UserData AI5 decode failed: " + ex);
+ } catch (CodingException ex) {
+ Log.e(LOG_TAG, "UserData AI5 decode failed: " + ex);
+ }
+ return null;
+ }
+
private static void decodeUserDataPayload(UserData userData, boolean hasUserDataHeader)
throws CodingException
{
@@ -482,18 +584,23 @@
userData.userDataHeader = SmsHeader.parse(headerData);
}
switch (userData.msgEncoding) {
- case UserData.ENCODING_GSM_7BIT_ALPHABET:
- userData.payloadStr = GsmAlphabet.gsm7BitPackedToString(userData.payload,
- offset, userData.numFields);
+ case UserData.ENCODING_OCTET:
break;
case UserData.ENCODING_7BIT_ASCII:
userData.payloadStr = decodePayloadStr(userData.payload, offset,
userData.numFields, "US-ASCII");
break;
+ case UserData.ENCODING_IA5:
+ userData.payloadStr = decodeIa5(userData.payload, offset, userData.numFields);
+ break;
case UserData.ENCODING_UNICODE_16:
userData.payloadStr = decodePayloadStr(userData.payload, offset,
userData.numFields * 2, "UTF-16");
break;
+ case UserData.ENCODING_GSM_7BIT_ALPHABET:
+ userData.payloadStr = GsmAlphabet.gsm7BitPackedToString(userData.payload,
+ offset, userData.numFields);
+ break;
default:
throw new CodingException("unsupported user data encoding ("
+ userData.msgEncoding + ")");
@@ -592,6 +699,7 @@
}
bData.errorClass = inStream.read(2);
bData.messageStatus = inStream.read(6);
+ bData.messageStatusSet = true;
}
private static void decodeMsgCenterTimeStamp(BearerData bData,
@@ -604,6 +712,60 @@
bData.timeStamp = inStream.readByteArray(6 * 8);
}
+ private static void decodePrivacyIndicator(BearerData bData, BitwiseInputStream inStream)
+ throws BitwiseInputStream.AccessException, CodingException
+ {
+ if (inStream.read(8) != 1) {
+ throw new CodingException("PRIVACY_INDICATOR subparam size incorrect");
+ }
+ bData.privacy = inStream.read(2);
+ inStream.skip(6);
+ bData.privacyIndicatorSet = true;
+ }
+
+ private static void decodeLanguageIndicator(BearerData bData, BitwiseInputStream inStream)
+ throws BitwiseInputStream.AccessException, CodingException
+ {
+ if (inStream.read(8) != 1) {
+ throw new CodingException("LANGUAGE_INDICATOR subparam size incorrect");
+ }
+ bData.language = inStream.read(8);
+ bData.languageIndicatorSet = true;
+ }
+
+ private static void decodeDisplayMode(BearerData bData, BitwiseInputStream inStream)
+ throws BitwiseInputStream.AccessException, CodingException
+ {
+ if (inStream.read(8) != 1) {
+ throw new CodingException("DISPLAY_MODE subparam size incorrect");
+ }
+ bData.displayMode = inStream.read(2);
+ inStream.skip(6);
+ bData.displayModeSet = true;
+ }
+
+ private static void decodePriorityIndicator(BearerData bData, BitwiseInputStream inStream)
+ throws BitwiseInputStream.AccessException, CodingException
+ {
+ if (inStream.read(8) != 1) {
+ throw new CodingException("PRIORITY_INDICATOR subparam size incorrect");
+ }
+ bData.priority = inStream.read(2);
+ inStream.skip(6);
+ bData.priorityIndicatorSet = true;
+ }
+
+ private static void decodeMsgDeliveryAlert(BearerData bData, BitwiseInputStream inStream)
+ throws BitwiseInputStream.AccessException, CodingException
+ {
+ if (inStream.read(8) != 1) {
+ throw new CodingException("ALERT_ON_MESSAGE_DELIVERY subparam size incorrect");
+ }
+ bData.alert = inStream.read(2);
+ inStream.skip(6);
+ bData.alertIndicatorSet = true;
+ }
+
/**
* Create BearerData object from serialized representation.
* (See 3GPP2 C.R1001-F, v1.0, section 4.5 for layout details)
@@ -647,6 +809,21 @@
case SUBPARAM_MESSAGE_CENTER_TIME_STAMP:
decodeMsgCenterTimeStamp(bData, inStream);
break;
+ case SUBPARAM_PRIVACY_INDICATOR:
+ decodePrivacyIndicator(bData, inStream);
+ break;
+ case SUBPARAM_LANGUAGE_INDICATOR:
+ decodeLanguageIndicator(bData, inStream);
+ break;
+ case SUBPARAM_MESSAGE_DISPLAY_MODE:
+ decodeDisplayMode(bData, inStream);
+ break;
+ case SUBPARAM_PRIORITY_INDICATOR:
+ decodePriorityIndicator(bData, inStream);
+ break;
+ case SUBPARAM_ALERT_ON_MESSAGE_DELIVERY:
+ decodeMsgDeliveryAlert(bData, inStream);
+ break;
default:
throw new CodingException("unsupported bearer data subparameter ("
+ subparamId + ")");
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java
index bd6fbb4..f916089 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java
@@ -22,13 +22,13 @@
public class UserData{
/**
- * User data encoding types
+ * User data encoding types.
* (See 3GPP2 C.R1001-F, v1.0, table 9.1-1)
*/
public static final int ENCODING_OCTET = 0x00;
public static final int ENCODING_IS91_EXTENDED_PROTOCOL = 0x01;
public static final int ENCODING_7BIT_ASCII = 0x02;
- //public static final int ENCODING_IA5 = 0x03;
+ public static final int ENCODING_IA5 = 0x03;
public static final int ENCODING_UNICODE_16 = 0x04;
//public static final int ENCODING_SHIFT_JIS = 0x05;
//public static final int ENCODING_KOREAN = 0x06;
@@ -38,6 +38,25 @@
public static final int ENCODING_GSM_DCS = 0x0A;
/**
+ * IA5 data encoding character mappings.
+ * (See CCITT Rec. T.50 Tables 1 and 3)
+ */
+ public static final char[] IA5_MAP = {
+ ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~'};
+
+ /**
+ * Mapping for IA5 values less than 32 are flow control signals
+ * and not used here.
+ */
+ public static final int IA5_MAP_BASE_INDEX = 0x20;
+ public static final int IA5_MAP_MAX_INDEX = IA5_MAP_BASE_INDEX + IA5_MAP.length - 1;
+
+ /**
* Contains the data header of the user data
*/
public SmsHeader userDataHeader;
@@ -73,8 +92,8 @@
builder.append(" paddingBits: " + paddingBits + "\n");
builder.append(" numFields: " + (int)numFields + "\n");
builder.append(" userDataHeader: " + userDataHeader + "\n");
- builder.append(" payload: " + HexDump.toHexString(payload));
- builder.append(" payloadStr: " + payloadStr);
+ builder.append(" payload: '" + HexDump.toHexString(payload) + "'");
+ builder.append(", payloadStr: '" + payloadStr + "'");
return builder.toString();
}
diff --git a/test-runner/android/test/mock/MockContext.java b/test-runner/android/test/mock/MockContext.java
index e733dd1..bd39a14 100644
--- a/test-runner/android/test/mock/MockContext.java
+++ b/test-runner/android/test/mock/MockContext.java
@@ -386,4 +386,12 @@
throws PackageManager.NameNotFoundException {
throw new UnsupportedOperationException();
}
+
+ /**
+ * @hide
+ */
+ @Override
+ public float getApplicationScale() {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
index 723512c..9ff80c7 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
@@ -264,10 +264,152 @@
HexDump.toHexString(revBearerData.timeStamp));
}
- // XXX test messageId
+ @SmallTest
+ public void testPrivacyIndicator() throws Exception {
+ String pdu1 = "0003104090010c485f4194dfea34becf61b840090140";
+ BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1));
+ assertEquals(bd1.privacy, BearerData.PRIVACY_RESTRICTED);
+ String pdu2 = "0003104090010c485f4194dfea34becf61b840090180";
+ BearerData bd2 = BearerData.decode(HexDump.hexStringToByteArray(pdu2));
+ assertEquals(bd2.privacy, BearerData.PRIVACY_CONFIDENTIAL);
+ String pdu3 = "0003104090010c485f4194dfea34becf61b8400901c0";
+ BearerData bd3 = BearerData.decode(HexDump.hexStringToByteArray(pdu3));
+ assertEquals(bd3.privacy, BearerData.PRIVACY_SECRET);
+ }
- // String pdu1 = "0003104090010d4866a794e07055965b91d040300c0100"; sid 12
- // String pdu1 = "0003104090011748bea794e0731436ef3bd7c2e0352eef27a1c263fe58080d0101"; sid 13
- // Log.d(LOG_TAG, "revBearerData -- " + revBearerData);
+ @SmallTest
+ public void testPrivacyIndicatorFeedback() throws Exception {
+ BearerData bearerData = new BearerData();
+ bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER;
+ bearerData.messageId = 0;
+ bearerData.hasUserDataHeader = false;
+ String payloadStr = "test privacy indicator";
+ bearerData.userData = makeUserData(payloadStr);
+ bearerData.privacy = BearerData.PRIVACY_SECRET;
+ bearerData.privacyIndicatorSet = true;
+ byte []encodedSms = BearerData.encode(bearerData);
+ BearerData revBearerData = BearerData.decode(encodedSms);
+ assertEquals(revBearerData.userData.payloadStr, payloadStr);
+ assertEquals(revBearerData.privacyIndicatorSet, true);
+ assertEquals(revBearerData.privacy, BearerData.PRIVACY_SECRET);
+ bearerData.privacy = BearerData.PRIVACY_RESTRICTED;
+ encodedSms = BearerData.encode(bearerData);
+ revBearerData = BearerData.decode(encodedSms);
+ assertEquals(revBearerData.privacy, BearerData.PRIVACY_RESTRICTED);
+ }
+ @SmallTest
+ public void testMsgDeliveryAlert() throws Exception {
+ String pdu1 = "0003104090010d4866a794e07055965b91d040300c0100";
+ BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1));
+ assertEquals(bd1.alert, 0);
+ assertEquals(bd1.userData.payloadStr, "Test Alert 0");
+ String pdu2 = "0003104090010d4866a794e07055965b91d140300c0140";
+ BearerData bd2 = BearerData.decode(HexDump.hexStringToByteArray(pdu2));
+ assertEquals(bd2.alert, 1);
+ assertEquals(bd2.userData.payloadStr, "Test Alert 1");
+ String pdu3 = "0003104090010d4866a794e07055965b91d240300c0180";
+ BearerData bd3 = BearerData.decode(HexDump.hexStringToByteArray(pdu3));
+ assertEquals(bd3.alert, 2);
+ assertEquals(bd3.userData.payloadStr, "Test Alert 2");
+ String pdu4 = "0003104090010d4866a794e07055965b91d340300c01c0";
+ BearerData bd4 = BearerData.decode(HexDump.hexStringToByteArray(pdu4));
+ assertEquals(bd4.alert, 3);
+ assertEquals(bd4.userData.payloadStr, "Test Alert 3");
+ }
+
+ @SmallTest
+ public void testMsgDeliveryAlertFeedback() throws Exception {
+ BearerData bearerData = new BearerData();
+ bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER;
+ bearerData.messageId = 0;
+ bearerData.hasUserDataHeader = false;
+ String payloadStr = "test message delivery alert";
+ bearerData.userData = makeUserData(payloadStr);
+ bearerData.alert = BearerData.ALERT_MEDIUM_PRIO;
+ bearerData.alertIndicatorSet = true;
+ byte []encodedSms = BearerData.encode(bearerData);
+ BearerData revBearerData = BearerData.decode(encodedSms);
+ assertEquals(revBearerData.userData.payloadStr, payloadStr);
+ assertEquals(revBearerData.alertIndicatorSet, true);
+ assertEquals(revBearerData.alert, bearerData.alert);
+ bearerData.alert = BearerData.ALERT_HIGH_PRIO;
+ encodedSms = BearerData.encode(bearerData);
+ revBearerData = BearerData.decode(encodedSms);
+ assertEquals(revBearerData.userData.payloadStr, payloadStr);
+ assertEquals(revBearerData.alertIndicatorSet, true);
+ assertEquals(revBearerData.alert, bearerData.alert);
+ }
+
+ @SmallTest
+ public void testLanguageIndicator() throws Exception {
+ String pdu1 = "0003104090011748bea794e0731436ef3bd7c2e0352eef27a1c263fe58080d0101";
+ BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1));
+ assertEquals(bd1.userData.payloadStr, "Test Language indicator");
+ assertEquals(bd1.language, BearerData.LANGUAGE_ENGLISH);
+ String pdu2 = "0003104090011748bea794e0731436ef3bd7c2e0352eef27a1c263fe58080d0106";
+ BearerData bd2 = BearerData.decode(HexDump.hexStringToByteArray(pdu2));
+ assertEquals(bd2.userData.payloadStr, "Test Language indicator");
+ assertEquals(bd2.language, BearerData.LANGUAGE_CHINESE);
+ }
+
+ @SmallTest
+ public void testLanguageIndicatorFeedback() throws Exception {
+ BearerData bearerData = new BearerData();
+ bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER;
+ bearerData.messageId = 0;
+ bearerData.hasUserDataHeader = false;
+ String payloadStr = "test language indicator";
+ bearerData.userData = makeUserData(payloadStr);
+ bearerData.language = BearerData.LANGUAGE_ENGLISH;
+ bearerData.languageIndicatorSet = true;
+ byte []encodedSms = BearerData.encode(bearerData);
+ BearerData revBearerData = BearerData.decode(encodedSms);
+ assertEquals(revBearerData.userData.payloadStr, payloadStr);
+ assertEquals(revBearerData.languageIndicatorSet, true);
+ assertEquals(revBearerData.language, bearerData.language);
+ bearerData.language = BearerData.LANGUAGE_KOREAN;
+ encodedSms = BearerData.encode(bearerData);
+ revBearerData = BearerData.decode(encodedSms);
+ assertEquals(revBearerData.userData.payloadStr, payloadStr);
+ assertEquals(revBearerData.languageIndicatorSet, true);
+ assertEquals(revBearerData.language, bearerData.language);
+ }
+
+ @SmallTest
+ public void testDisplayMode() throws Exception {
+ String pdu1 = "0003104090010c485f4194dfea34becf61b8400f0100";
+ BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1));
+ //Log.d(LOG_TAG, "bd1 = " + bd1);
+ assertEquals(bd1.displayMode, BearerData.DISPLAY_MODE_IMMEDIATE);
+ String pdu2 = "0003104090010c485f4194dfea34becf61b8400f0140";
+ BearerData bd2 = BearerData.decode(HexDump.hexStringToByteArray(pdu2));
+ assertEquals(bd2.displayMode, BearerData.DISPLAY_MODE_DEFAULT);
+ String pdu3 = "0003104090010c485f4194dfea34becf61b8400f0180";
+ BearerData bd3 = BearerData.decode(HexDump.hexStringToByteArray(pdu3));
+ assertEquals(bd3.displayMode, BearerData.DISPLAY_MODE_USER);
+ }
+
+ @SmallTest
+ public void testDisplayModeFeedback() throws Exception {
+ BearerData bearerData = new BearerData();
+ bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER;
+ bearerData.messageId = 0;
+ bearerData.hasUserDataHeader = false;
+ String payloadStr = "test display mode";
+ bearerData.userData = makeUserData(payloadStr);
+ bearerData.displayMode = BearerData.DISPLAY_MODE_IMMEDIATE;
+ bearerData.displayModeSet = true;
+ byte []encodedSms = BearerData.encode(bearerData);
+ BearerData revBearerData = BearerData.decode(encodedSms);
+ assertEquals(revBearerData.userData.payloadStr, payloadStr);
+ assertEquals(revBearerData.displayModeSet, true);
+ assertEquals(revBearerData.displayMode, bearerData.displayMode);
+ bearerData.displayMode = BearerData.DISPLAY_MODE_USER;
+ encodedSms = BearerData.encode(bearerData);
+ revBearerData = BearerData.decode(encodedSms);
+ assertEquals(revBearerData.userData.payloadStr, payloadStr);
+ assertEquals(revBearerData.displayModeSet, true);
+ assertEquals(revBearerData.displayMode, bearerData.displayMode);
+ }
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
index baa3d53..f434e14 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
@@ -1145,4 +1145,12 @@
public Context getApplicationContext() {
throw new UnsupportedOperationException();
}
+
+ /**
+ * @hide
+ */
+ @Override
+ public float getApplicationScale() {
+ throw new UnsupportedOperationException();
+ }
}