diff options
112 files changed, 3284 insertions, 1368 deletions
diff --git a/api/current.xml b/api/current.xml index 953c9f3..b0f0b14 100644 --- a/api/current.xml +++ b/api/current.xml @@ -20328,7 +20328,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="value" type="android.view.animation.Interpolator"> +<parameter name="value" type="android.animation.TimeInterpolator"> </parameter> </method> <method name="setStartDelay" @@ -20678,7 +20678,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="interpolator" type="android.view.animation.Interpolator"> +<parameter name="interpolator" type="android.animation.TimeInterpolator"> </parameter> </method> <method name="setStartDelay" @@ -20981,7 +20981,7 @@ > </method> <method name="getInterpolator" - return="android.view.animation.Interpolator" + return="android.animation.TimeInterpolator" abstract="false" native="false" synchronized="false" @@ -21036,7 +21036,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="interpolator" type="android.view.animation.Interpolator"> +<parameter name="interpolator" type="android.animation.TimeInterpolator"> </parameter> </method> <method name="setValue" @@ -21124,7 +21124,7 @@ </parameter> </method> <method name="getInterpolator" - return="android.view.animation.Interpolator" + return="android.animation.TimeInterpolator" abstract="false" native="false" synchronized="false" @@ -21271,7 +21271,7 @@ > <parameter name="transitionType" type="int"> </parameter> -<parameter name="interpolator" type="android.view.animation.Interpolator"> +<parameter name="interpolator" type="android.animation.TimeInterpolator"> </parameter> </method> <method name="setStagger" @@ -21670,6 +21670,27 @@ </parameter> </method> </class> +<interface name="TimeInterpolator" + abstract="true" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<method name="getInterpolation" + return="float" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="input" type="float"> +</parameter> +</method> +</interface> <interface name="TypeEvaluator" abstract="true" static="false" @@ -21794,7 +21815,7 @@ > </method> <method name="getInterpolator" - return="android.view.animation.Interpolator" + return="android.animation.TimeInterpolator" abstract="false" native="false" synchronized="false" @@ -21956,7 +21977,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="value" type="android.view.animation.Interpolator"> +<parameter name="value" type="android.animation.TimeInterpolator"> </parameter> </method> <method name="setRepeatCount" @@ -112283,6 +112304,348 @@ </method> </class> </package> +<package name="android.nfc" +> +<class name="NdefMessage" + extends="java.lang.Object" + abstract="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<implements name="android.os.Parcelable"> +</implements> +<constructor name="NdefMessage" + type="android.nfc.NdefMessage" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="records" type="android.nfc.NdefRecord[]"> +</parameter> +</constructor> +<method name="describeContents" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getRecords" + return="android.nfc.NdefRecord[]" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="writeToParcel" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="dest" type="android.os.Parcel"> +</parameter> +<parameter name="flags" type="int"> +</parameter> +</method> +<field name="CREATOR" + type="android.os.Parcelable.Creator" + transient="false" + volatile="false" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +</class> +<class name="NdefRecord" + extends="java.lang.Object" + abstract="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<implements name="android.os.Parcelable"> +</implements> +<constructor name="NdefRecord" + type="android.nfc.NdefRecord" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="tnf" type="short"> +</parameter> +<parameter name="type" type="byte[]"> +</parameter> +<parameter name="id" type="byte[]"> +</parameter> +<parameter name="payload" type="byte[]"> +</parameter> +</constructor> +<constructor name="NdefRecord" + type="android.nfc.NdefRecord" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="data" type="byte[]"> +</parameter> +</constructor> +<method name="describeContents" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getId" + return="byte[]" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getPayload" + return="byte[]" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getTnf" + return="short" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getType" + return="byte[]" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="writeToParcel" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="dest" type="android.os.Parcel"> +</parameter> +<parameter name="flags" type="int"> +</parameter> +</method> +<field name="CREATOR" + type="android.os.Parcelable.Creator" + transient="false" + volatile="false" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="RTD_ALTERNATIVE_CARRIER" + type="byte[]" + transient="false" + volatile="false" + value="null" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="RTD_HANDOVER_CARRIER" + type="byte[]" + transient="false" + volatile="false" + value="null" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="RTD_HANDOVER_REQUEST" + type="byte[]" + transient="false" + volatile="false" + value="null" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="RTD_HANDOVER_SELECT" + type="byte[]" + transient="false" + volatile="false" + value="null" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="RTD_SMART_POSTER" + type="byte[]" + transient="false" + volatile="false" + value="null" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="RTD_TEXT" + type="byte[]" + transient="false" + volatile="false" + value="null" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="RTD_URI" + type="byte[]" + transient="false" + volatile="false" + value="null" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TNF_ABSOLUTE_URI" + type="short" + transient="false" + volatile="false" + value="3" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TNF_EMPTY" + type="short" + transient="false" + volatile="false" + value="0" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TNF_EXTERNAL_TYPE" + type="short" + transient="false" + volatile="false" + value="4" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TNF_MIME_MEDIA" + type="short" + transient="false" + volatile="false" + value="2" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TNF_UNCHANGED" + type="short" + transient="false" + volatile="false" + value="6" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TNF_UNKNOWN" + type="short" + transient="false" + volatile="false" + value="5" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TNF_WELL_KNOWN" + type="short" + transient="false" + volatile="false" + value="1" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +</class> +</package> <package name="android.opengl" > <class name="ETC1" @@ -201101,7 +201464,7 @@ static="false" final="false" deprecated="not deprecated" - visibility="protected" + visibility="public" > <parameter name="event" type="android.view.DragEvent"> </parameter> @@ -202843,6 +203206,23 @@ <parameter name="animation" type="android.view.animation.Animation"> </parameter> </method> +<method name="startDrag" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +<parameter name="data" type="android.content.ClipData"> +</parameter> +<parameter name="thumbBuilder" type="android.view.View.DragThumbnailBuilder"> +</parameter> +<parameter name="myWindowOnly" type="boolean"> +</parameter> +</method> <method name="unscheduleDrawable" return="void" abstract="false" @@ -212058,19 +212438,8 @@ deprecated="not deprecated" visibility="public" > -<method name="getInterpolation" - return="float" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="input" type="float"> -</parameter> -</method> +<implements name="android.animation.TimeInterpolator"> +</implements> </interface> <class name="LayoutAnimationController" extends="java.lang.Object" @@ -215354,6 +215723,19 @@ <parameter name="id" type="java.lang.String"> </parameter> </method> +<method name="showInputMethodAndSubtypeEnabler" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="topId" type="java.lang.String"> +</parameter> +</method> <method name="showInputMethodPicker" return="void" abstract="false" diff --git a/cmds/stagefright/recordvideo.cpp b/cmds/stagefright/recordvideo.cpp index 330fbc2..f8eb514 100644 --- a/cmds/stagefright/recordvideo.cpp +++ b/cmds/stagefright/recordvideo.cpp @@ -18,12 +18,10 @@ #include <binder/ProcessState.h> #include <media/stagefright/AudioPlayer.h> -#include <media/stagefright/FileSource.h> #include <media/stagefright/MediaBufferGroup.h> #include <media/stagefright/MediaDebug.h> #include <media/stagefright/MediaDefs.h> #include <media/stagefright/MetaData.h> -#include <media/stagefright/MediaExtractor.h> #include <media/stagefright/MPEG4Writer.h> #include <media/stagefright/OMXClient.h> #include <media/stagefright/OMXCodec.h> @@ -31,18 +29,21 @@ using namespace android; -// print usage showing how to use this utility to record videos +// Print usage showing how to use this utility to record videos static void usage(const char *me) { fprintf(stderr, "usage: %s\n", me); fprintf(stderr, " -h(elp)\n"); - fprintf(stderr, " -b bit rate in bits per second (default 300000)\n"); - fprintf(stderr, " -c YUV420 color format: [0] semi planar or [1] planar (default 1)\n"); - fprintf(stderr, " -f frame rate in frames per second (default 30)\n"); - fprintf(stderr, " -i I frame interval in seconds (default 1)\n"); - fprintf(stderr, " -n number of frames to be recorded (default 300)\n"); - fprintf(stderr, " -w width in pixels (default 176)\n"); - fprintf(stderr, " -t height in pixels (default 144)\n"); - fprintf(stderr, " -v video codec: [0] AVC [1] M4V [2] H263 (default 0)\n"); + fprintf(stderr, " -b bit rate in bits per second (default: 300000)\n"); + fprintf(stderr, " -c YUV420 color format: [0] semi planar or [1] planar (default: 1)\n"); + fprintf(stderr, " -f frame rate in frames per second (default: 30)\n"); + fprintf(stderr, " -i I frame interval in seconds (default: 1)\n"); + fprintf(stderr, " -n number of frames to be recorded (default: 300)\n"); + fprintf(stderr, " -w width in pixels (default: 176)\n"); + fprintf(stderr, " -t height in pixels (default: 144)\n"); + fprintf(stderr, " -l encoder level. see omx il header (default: encoder specific)\n"); + fprintf(stderr, " -p encoder profile. see omx il header (default: encoder specific)\n"); + fprintf(stderr, " -v video codec: [0] AVC [1] M4V [2] H263 (default: 0)\n"); + fprintf(stderr, "The output file is /sdcard/output.mp4\n"); exit(1); } @@ -56,6 +57,7 @@ public: mFrameRate(fps), mColorFormat(colorFormat), mSize((width * height * 3) / 2) { + mGroup.add_buffer(new MediaBuffer(mSize)); // Check the color format to make sure @@ -98,8 +100,11 @@ public: return err; } - char x = (char)((double)rand() / RAND_MAX * 255); - memset((*buffer)->data(), x, mSize); + // We don't care about the contents. we just test video encoder + // Also, by skipping the content generation, we can return from + // read() much faster. + //char x = (char)((double)rand() / RAND_MAX * 255); + //memset((*buffer)->data(), x, mSize); (*buffer)->set_range(0, mSize); (*buffer)->meta_data()->clear(); (*buffer)->meta_data()->setInt64( @@ -125,38 +130,6 @@ private: DummySource &operator=(const DummySource &); }; -sp<MediaSource> createSource(const char *filename) { - sp<MediaSource> source; - - sp<MediaExtractor> extractor = - MediaExtractor::Create(new FileSource(filename)); - if (extractor == NULL) { - return NULL; - } - - size_t num_tracks = extractor->countTracks(); - - sp<MetaData> meta; - for (size_t i = 0; i < num_tracks; ++i) { - meta = extractor->getTrackMetaData(i); - CHECK(meta.get() != NULL); - - const char *mime; - if (!meta->findCString(kKeyMIMEType, &mime)) { - continue; - } - - if (strncasecmp(mime, "video/", 6)) { - continue; - } - - source = extractor->getTrack(i); - break; - } - - return source; -} - enum { kYUV420SP = 0, kYUV420P = 1, @@ -186,12 +159,14 @@ int main(int argc, char **argv) { int iFramesIntervalSeconds = 1; int colorFormat = OMX_COLOR_FormatYUV420Planar; int nFrames = 300; + int level = -1; // Encoder specific default + int profile = -1; // Encoder specific default int codec = 0; const char *fileName = "/sdcard/output.mp4"; android::ProcessState::self()->startThreadPool(); int res; - while ((res = getopt(argc, argv, "b:c:f:i:n:w:t:v:o:h")) >= 0) { + while ((res = getopt(argc, argv, "b:c:f:i:n:w:t:l:p:v:h")) >= 0) { switch (res) { case 'b': { @@ -238,6 +213,18 @@ int main(int argc, char **argv) { break; } + case 'l': + { + level = atoi(optarg); + break; + } + + case 'p': + { + profile = atoi(optarg); + break; + } + case 'v': { codec = atoi(optarg); @@ -260,7 +247,8 @@ int main(int argc, char **argv) { CHECK_EQ(client.connect(), OK); status_t err = OK; - sp<MediaSource> decoder = new DummySource(width, height, nFrames, frameRateFps, colorFormat); + sp<MediaSource> source = + new DummySource(width, height, nFrames, frameRateFps, colorFormat); sp<MetaData> enc_meta = new MetaData; switch (codec) { @@ -282,10 +270,16 @@ int main(int argc, char **argv) { enc_meta->setInt32(kKeySliceHeight, height); enc_meta->setInt32(kKeyIFramesInterval, iFramesIntervalSeconds); enc_meta->setInt32(kKeyColorFormat, colorFormat); + if (level != -1) { + enc_meta->setInt32(kKeyVideoLevel, level); + } + if (profile != -1) { + enc_meta->setInt32(kKeyVideoProfile, profile); + } sp<MediaSource> encoder = OMXCodec::Create( - client.interface(), enc_meta, true /* createEncoder */, decoder); + client.interface(), enc_meta, true /* createEncoder */, source); sp<MPEG4Writer> writer = new MPEG4Writer(fileName); writer->addSource(encoder); @@ -296,7 +290,7 @@ int main(int argc, char **argv) { err = writer->stop(); int64_t end = systemTime(); - printf("$\n"); + fprintf(stderr, "$\n"); client.disconnect(); if (err != OK && err != ERROR_END_OF_STREAM) { diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java index 2ada6d6..d3e0797 100644 --- a/core/java/android/animation/Animator.java +++ b/core/java/android/animation/Animator.java @@ -16,8 +16,6 @@ package android.animation; -import android.view.animation.Interpolator; - import java.util.ArrayList; /** @@ -97,7 +95,7 @@ public abstract class Animator implements Cloneable { * * @param value the interpolator to be used by this animation */ - public abstract void setInterpolator(Interpolator value); + public abstract void setInterpolator(TimeInterpolator value); /** * Returns whether this Animator is currently running (having been started and not yet ended). diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java index a8385e4..5de0293 100644 --- a/core/java/android/animation/AnimatorSet.java +++ b/core/java/android/animation/AnimatorSet.java @@ -16,8 +16,6 @@ package android.animation; -import android.view.animation.Interpolator; - import java.util.ArrayList; import java.util.HashMap; @@ -173,13 +171,13 @@ public final class AnimatorSet extends Animator { } /** - * Sets the Interpolator for all current {@link #getChildAnimations() child animations} + * Sets the TimeInterpolator for all current {@link #getChildAnimations() child animations} * of this AnimatorSet. * * @param interpolator the interpolator to be used by each child animation of this AnimatorSet */ @Override - public void setInterpolator(Interpolator interpolator) { + public void setInterpolator(TimeInterpolator interpolator) { for (Node node : mNodes) { node.animation.setInterpolator(interpolator); } diff --git a/core/java/android/animation/Keyframe.java b/core/java/android/animation/Keyframe.java index 192ba5c..f9a4f3c 100644 --- a/core/java/android/animation/Keyframe.java +++ b/core/java/android/animation/Keyframe.java @@ -16,14 +16,12 @@ package android.animation; -import android.view.animation.Interpolator; - /** * This class holds a time/value pair for an animation. The Keyframe class is used * by {@link ValueAnimator} to define the values that the animation target will have over the course * of the animation. As the time proceeds from one keyframe to the other, the value of the * target object will animate between the value at the previous keyframe and the value at the - * next keyframe. Each keyframe also holds an option {@link android.view.animation.Interpolator} + * next keyframe. Each keyframe also holds an optional {@link TimeInterpolator} * object, which defines the time interpolation over the intervalue preceding the keyframe. */ public class Keyframe implements Cloneable { @@ -47,7 +45,7 @@ public class Keyframe implements Cloneable { * The optional time interpolator for the interval preceding this keyframe. A null interpolator * (the default) results in linear interpolation over the interval. */ - private Interpolator mInterpolator = null; + private TimeInterpolator mInterpolator = null; /** * Private constructor, called from the public constructors with the additional @@ -224,7 +222,7 @@ public class Keyframe implements Cloneable { * * @return The optional interpolator for this Keyframe. */ - public Interpolator getInterpolator() { + public TimeInterpolator getInterpolator() { return mInterpolator; } @@ -234,7 +232,7 @@ public class Keyframe implements Cloneable { * * @return The optional interpolator for this Keyframe. */ - public void setInterpolator(Interpolator interpolator) { + public void setInterpolator(TimeInterpolator interpolator) { mInterpolator = interpolator; } diff --git a/core/java/android/animation/KeyframeSet.java b/core/java/android/animation/KeyframeSet.java index af47a15..a24b1fb 100644 --- a/core/java/android/animation/KeyframeSet.java +++ b/core/java/android/animation/KeyframeSet.java @@ -18,8 +18,6 @@ package android.animation; import java.util.ArrayList; -import android.view.animation.Interpolator; - /** * This class holds a collection of Keyframe objects and is called by ValueAnimator to calculate * values between those keyframes for a given animation. The class internal to the animation @@ -58,7 +56,7 @@ class KeyframeSet { if (fraction <= 0f) { final Keyframe prevKeyframe = mKeyframes.get(0); final Keyframe nextKeyframe = mKeyframes.get(1); - final Interpolator interpolator = nextKeyframe.getInterpolator(); + final TimeInterpolator interpolator = nextKeyframe.getInterpolator(); if (interpolator != null) { fraction = interpolator.getInterpolation(fraction); } @@ -69,7 +67,7 @@ class KeyframeSet { } else if (fraction >= 1f) { final Keyframe prevKeyframe = mKeyframes.get(mNumKeyframes - 2); final Keyframe nextKeyframe = mKeyframes.get(mNumKeyframes - 1); - final Interpolator interpolator = nextKeyframe.getInterpolator(); + final TimeInterpolator interpolator = nextKeyframe.getInterpolator(); if (interpolator != null) { fraction = interpolator.getInterpolation(fraction); } @@ -82,7 +80,7 @@ class KeyframeSet { for (int i = 1; i < mNumKeyframes; ++i) { Keyframe nextKeyframe = mKeyframes.get(i); if (fraction < nextKeyframe.getFraction()) { - final Interpolator interpolator = nextKeyframe.getInterpolator(); + final TimeInterpolator interpolator = nextKeyframe.getInterpolator(); if (interpolator != null) { fraction = interpolator.getInterpolation(fraction); } diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java index 52f0f16..56ad857 100644 --- a/core/java/android/animation/LayoutTransition.java +++ b/core/java/android/animation/LayoutTransition.java @@ -21,7 +21,6 @@ import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.DecelerateInterpolator; -import android.view.animation.Interpolator; import java.util.ArrayList; import java.util.HashMap; @@ -142,10 +141,10 @@ public class LayoutTransition { /** * The default interpolators used for the animations */ - private Interpolator mAppearingInterpolator = new AccelerateDecelerateInterpolator(); - private Interpolator mDisappearingInterpolator = new AccelerateDecelerateInterpolator(); - private Interpolator mChangingAppearingInterpolator = new DecelerateInterpolator(); - private Interpolator mChangingDisappearingInterpolator = new DecelerateInterpolator(); + private TimeInterpolator mAppearingInterpolator = new AccelerateDecelerateInterpolator(); + private TimeInterpolator mDisappearingInterpolator = new AccelerateDecelerateInterpolator(); + private TimeInterpolator mChangingAppearingInterpolator = new DecelerateInterpolator(); + private TimeInterpolator mChangingDisappearingInterpolator = new DecelerateInterpolator(); /** * This hashmap is used to store the animations that are currently running as part of @@ -387,9 +386,9 @@ public class LayoutTransition { * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose * duration is being set. * @param interpolator The interpolator that the specified animation should use. - * @see Animator#setInterpolator(android.view.animation.Interpolator) + * @see Animator#setInterpolator(TimeInterpolator) */ - public void setInterpolator(int transitionType, Interpolator interpolator) { + public void setInterpolator(int transitionType, TimeInterpolator interpolator) { switch (transitionType) { case CHANGE_APPEARING: mChangingAppearingInterpolator = interpolator; @@ -414,10 +413,10 @@ public class LayoutTransition { * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING}, * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose * duration is being set. - * @return Interpolator The interpolator that the specified animation uses. - * @see Animator#setInterpolator(android.view.animation.Interpolator) + * @return TimeInterpolator The interpolator that the specified animation uses. + * @see Animator#setInterpolator(TimeInterpolator) */ - public Interpolator getInterpolator(int transitionType) { + public TimeInterpolator getInterpolator(int transitionType) { switch (transitionType) { case CHANGE_APPEARING: return mChangingAppearingInterpolator; diff --git a/core/java/android/animation/TimeInterpolator.java b/core/java/android/animation/TimeInterpolator.java new file mode 100644 index 0000000..8d795a8 --- /dev/null +++ b/core/java/android/animation/TimeInterpolator.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.animation; + +/** + * A time interpolator defines the rate of change of an animation. This allows animations + * to have non-linear motion, such as acceleration and deceleration. + */ +public interface TimeInterpolator { + + /** + * Maps a value representing the elapsed fraciton of an animation to a value that represents + * the interpolated fraction. This interpolated value is then multiplied by the change in + * value of an animation to derive the animated value at the current elapsed animation time. + * + * @param input A value between 0 and 1.0 indicating our current point + * in the animation where 0 represents the start and 1.0 represents + * the end + * @return The interpolation value. This value can be more than 1.0 for + * interpolators which overshoot their targets, or less than 0 for + * interpolators that undershoot their targets. + */ + float getInterpolation(float input); +} diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java index f81b1ea..d2b17f0 100755 --- a/core/java/android/animation/ValueAnimator.java +++ b/core/java/android/animation/ValueAnimator.java @@ -21,7 +21,6 @@ import android.os.Looper; import android.os.Message; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.AnimationUtils; -import android.view.animation.Interpolator; import java.util.ArrayList; import java.util.HashMap; @@ -36,7 +35,7 @@ import java.util.HashMap; * <p>By default, ValueAnimator uses non-linear time interpolation, via the * {@link AccelerateDecelerateInterpolator} class, which accelerates into and decelerates * out of an animation. This behavior can be changed by calling - * {@link ValueAnimator#setInterpolator(Interpolator)}.</p> + * {@link ValueAnimator#setInterpolator(TimeInterpolator)}.</p> */ public class ValueAnimator<T> extends Animator { @@ -95,7 +94,8 @@ public class ValueAnimator<T> extends Animator { private static final ArrayList<ValueAnimator> sPendingAnimations = new ArrayList<ValueAnimator>(); // The time interpolator to be used if none is set on the animation - private static final Interpolator sDefaultInterpolator = new AccelerateDecelerateInterpolator(); + private static final TimeInterpolator sDefaultInterpolator = + new AccelerateDecelerateInterpolator(); // type evaluators for the three primitive types handled by this implementation private static final TypeEvaluator sIntEvaluator = new IntEvaluator(); @@ -178,7 +178,7 @@ public class ValueAnimator<T> extends Animator { * through this interpolator to calculate the interpolated fraction, which is then used to * calculate the animated values. */ - private Interpolator mInterpolator = sDefaultInterpolator; + private TimeInterpolator mInterpolator = sDefaultInterpolator; /** * The set of listeners to be sent events through the life of an animation. @@ -654,7 +654,7 @@ public class ValueAnimator<T> extends Animator { * @param value the interpolator to be used by this animation */ @Override - public void setInterpolator(Interpolator value) { + public void setInterpolator(TimeInterpolator value) { if (value != null) { mInterpolator = value; } @@ -665,7 +665,7 @@ public class ValueAnimator<T> extends Animator { * * @return The timing interpolator for this ValueAnimator. */ - public Interpolator getInterpolator() { + public TimeInterpolator getInterpolator() { return mInterpolator; } diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 38d897e..643e747 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -296,12 +296,12 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { * the normal application lifecycle. * * <p>Comes from the - * {@link android.R.styleable#AndroidManifestApplication_heavyWeight android:heavyWeight} + * {@link android.R.styleable#AndroidManifestApplication_cantSaveState android:cantSaveState} * attribute of the <application> tag. * * {@hide} */ - public static final int CANT_SAVE_STATE = 1<<27; + public static final int FLAG_CANT_SAVE_STATE = 1<<27; /** * Flags associated with the application. Any combination of @@ -380,6 +380,12 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { */ public boolean enabled = true; + /** + * For convenient access to package's install location. + * @hide + */ + public int installLocation = PackageInfo.INSTALL_LOCATION_UNSPECIFIED; + public void dump(Printer pw, String prefix) { super.dumpFront(pw, prefix); if (className != null) { @@ -393,7 +399,11 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { pw.println(prefix + "uid=" + uid + " flags=0x" + Integer.toHexString(flags) + " theme=0x" + Integer.toHexString(theme)); pw.println(prefix + "sourceDir=" + sourceDir); - if (!sourceDir.equals(publicSourceDir)) { + if (sourceDir == null) { + if (publicSourceDir != null) { + pw.println(prefix + "publicSourceDir=" + publicSourceDir); + } + } else if (!sourceDir.equals(publicSourceDir)) { pw.println(prefix + "publicSourceDir=" + publicSourceDir); } if (resourceDirs != null) { @@ -456,6 +466,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { uid = orig.uid; targetSdkVersion = orig.targetSdkVersion; enabled = orig.enabled; + installLocation = orig.installLocation; manageSpaceActivityName = orig.manageSpaceActivityName; descriptionRes = orig.descriptionRes; } @@ -488,6 +499,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { dest.writeInt(uid); dest.writeInt(targetSdkVersion); dest.writeInt(enabled ? 1 : 0); + dest.writeInt(installLocation); dest.writeString(manageSpaceActivityName); dest.writeString(backupAgentName); dest.writeInt(descriptionRes); @@ -520,6 +532,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { uid = source.readInt(); targetSdkVersion = source.readInt(); enabled = source.readInt() != 0; + installLocation = source.readInt(); manageSpaceActivityName = source.readString(); backupAgentName = source.readString(); descriptionRes = source.readInt(); diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index eaf1e33..6cbc9b5 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -783,7 +783,8 @@ public class PackageParser { pkg.installLocation = sa.getInteger( com.android.internal.R.styleable.AndroidManifest_installLocation, PARSE_DEFAULT_INSTALL_LOCATION); - + pkg.applicationInfo.installLocation = pkg.installLocation; + // Resource boolean are -1, so 1 means we don't know the value. int supportsSmallScreens = 1; int supportsNormalScreens = 1; @@ -1612,7 +1613,7 @@ public class PackageParser { if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_cantSaveState, false)) { - ai.flags |= ApplicationInfo.CANT_SAVE_STATE; + ai.flags |= ApplicationInfo.FLAG_CANT_SAVE_STATE; // A heavy-weight application can not be in a custom process. // We can do direct compare because we intern all strings. @@ -1929,7 +1930,7 @@ public class PackageParser { sa.recycle(); - if (receiver && (owner.applicationInfo.flags&ApplicationInfo.CANT_SAVE_STATE) != 0) { + if (receiver && (owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) { // A heavy-weight application can not have receives in its main process // We can do direct compare because we intern all strings. if (a.info.processName == owner.packageName) { @@ -2219,7 +2220,7 @@ public class PackageParser { sa.recycle(); - if ((owner.applicationInfo.flags&ApplicationInfo.CANT_SAVE_STATE) != 0) { + if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) { // A heavy-weight application can not have providers in its main process // We can do direct compare because we intern all strings. if (p.info.processName == owner.packageName) { @@ -2460,7 +2461,7 @@ public class PackageParser { sa.recycle(); - if ((owner.applicationInfo.flags&ApplicationInfo.CANT_SAVE_STATE) != 0) { + if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) { // A heavy-weight application can not have services in its main process // We can do direct compare because we intern all strings. if (s.info.processName == owner.packageName) { diff --git a/core/java/android/net/LinkAddress.aidl b/core/java/android/net/LinkAddress.aidl new file mode 100644 index 0000000..e7d8646 --- /dev/null +++ b/core/java/android/net/LinkAddress.aidl @@ -0,0 +1,21 @@ +/** + * + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +parcelable LinkAddress; + diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java new file mode 100644 index 0000000..cb302da --- /dev/null +++ b/core/java/android/net/LinkAddress.java @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.net.InetAddress; +import java.net.InterfaceAddress; +import java.net.UnknownHostException; + +/** + * Identifies an address of a network link + * @hide + */ +public class LinkAddress implements Parcelable { + /** + * IPv4 or IPv6 address. + */ + private final InetAddress address; + + /** + * Network prefix + */ + private final int prefix; + + public LinkAddress(InetAddress address, InetAddress mask) { + this.address = address; + this.prefix = computeprefix(mask); + } + + public LinkAddress(InetAddress address, int prefix) { + this.address = address; + this.prefix = prefix; + } + + public LinkAddress(InterfaceAddress interfaceAddress) { + this.address = interfaceAddress.getAddress(); + this.prefix = interfaceAddress.getNetworkPrefixLength(); + } + + private static int computeprefix(InetAddress mask) { + int count = 0; + for (byte b : mask.getAddress()) { + for (int i = 0; i < 8; ++i) { + if ((b & (1 << i)) != 0) { + ++count; + } + } + } + return count; + } + + @Override + public String toString() { + return (address == null ? "" : (address.getHostAddress() + "/" + prefix)); + } + + /** + * Compares this {@code LinkAddress} instance against the specified address + * in {@code obj}. Two addresses are equal if their InetAddress and prefix + * are equal + * + * @param obj the object to be tested for equality. + * @return {@code true} if both objects are equal, {@code false} otherwise. + */ + @Override + public boolean equals(Object obj) { + if (!(obj instanceof LinkAddress)) { + return false; + } + LinkAddress linkAddress = (LinkAddress) obj; + return this.address.equals(linkAddress.address) && + this.prefix == linkAddress.prefix; + } + + /** + * Returns the InetAddress for this address. + */ + public InetAddress getAddress() { + return address; + } + + /** + * Get network prefix length + */ + public int getNetworkPrefix() { + return prefix; + } + + /** + * Implement the Parcelable interface + * @hide + */ + public int describeContents() { + return 0; + } + + /** + * Implement the Parcelable interface. + * @hide + */ + public void writeToParcel(Parcel dest, int flags) { + if (address != null) { + dest.writeByte((byte)1); + dest.writeByteArray(address.getAddress()); + dest.writeInt(prefix); + } else { + dest.writeByte((byte)0); + } + } + + /** + * Implement the Parcelable interface. + * @hide + */ + public static final Creator<LinkAddress> CREATOR = + new Creator<LinkAddress>() { + public LinkAddress createFromParcel(Parcel in) { + InetAddress address = null; + int prefix = 0; + if (in.readByte() == 1) { + try { + address = InetAddress.getByAddress(in.createByteArray()); + prefix = in.readInt(); + } catch (UnknownHostException e) { } + } + return new LinkAddress(address, prefix); + } + + public LinkAddress[] newArray(int size) { + return new LinkAddress[size]; + } + }; +} diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index f411eac..f1545ea 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -36,8 +36,8 @@ import java.util.Collections; */ public class LinkProperties implements Parcelable { - private NetworkInterface mIface; - private Collection<InetAddress> mAddresses; + String mIfaceName; + private Collection<LinkAddress> mLinkAddresses; private Collection<InetAddress> mDnses; private InetAddress mGateway; private ProxyProperties mHttpProxy; @@ -49,34 +49,42 @@ public class LinkProperties implements Parcelable { // copy constructor instead of clone public LinkProperties(LinkProperties source) { if (source != null) { - mIface = source.getInterface(); - mAddresses = source.getAddresses(); + mIfaceName = source.getInterfaceName(); + mLinkAddresses = source.getLinkAddresses(); mDnses = source.getDnses(); mGateway = source.getGateway(); mHttpProxy = new ProxyProperties(source.getHttpProxy()); } } - public void setInterface(NetworkInterface iface) { - mIface = iface; - } - public NetworkInterface getInterface() { - return mIface; + public void setInterfaceName(String iface) { + mIfaceName = iface; } + public String getInterfaceName() { - return (mIface == null ? null : mIface.getName()); + return mIfaceName; } - public void addAddress(InetAddress address) { - mAddresses.add(address); - } public Collection<InetAddress> getAddresses() { - return Collections.unmodifiableCollection(mAddresses); + Collection<InetAddress> addresses = new ArrayList<InetAddress>(); + for (LinkAddress linkAddress : mLinkAddresses) { + addresses.add(linkAddress.getAddress()); + } + return Collections.unmodifiableCollection(addresses); + } + + public void addLinkAddress(LinkAddress address) { + mLinkAddresses.add(address); + } + + public Collection<LinkAddress> getLinkAddresses() { + return Collections.unmodifiableCollection(mLinkAddresses); } public void addDns(InetAddress dns) { mDnses.add(dns); } + public Collection<InetAddress> getDnses() { return Collections.unmodifiableCollection(mDnses); } @@ -96,8 +104,8 @@ public class LinkProperties implements Parcelable { } public void clear() { - mIface = null; - mAddresses = new ArrayList<InetAddress>(); + mIfaceName = null; + mLinkAddresses = new ArrayList<LinkAddress>(); mDnses = new ArrayList<InetAddress>(); mGateway = null; mHttpProxy = null; @@ -113,11 +121,11 @@ public class LinkProperties implements Parcelable { @Override public String toString() { - String ifaceName = (mIface == null ? "" : "InterfaceName: " + mIface.getName() + " "); + String ifaceName = (mIfaceName == null ? "" : "InterfaceName: " + mIfaceName + " "); - String ip = "IpAddresses: ["; - for (InetAddress addr : mAddresses) ip += addr.getHostAddress() + ","; - ip += "] "; + String linkAddresses = "LinkAddresses: ["; + for (LinkAddress addr : mLinkAddresses) linkAddresses += addr.toString(); + linkAddresses += "] "; String dns = "DnsAddresses: ["; for (InetAddress addr : mDnses) dns += addr.getHostAddress() + ","; @@ -126,7 +134,7 @@ public class LinkProperties implements Parcelable { String proxy = (mHttpProxy == null ? "" : "HttpProxy: " + mHttpProxy.toString() + " "); String gateway = (mGateway == null ? "" : "Gateway: " + mGateway.getHostAddress() + " "); - return ifaceName + ip + gateway + dns + proxy; + return ifaceName + linkAddresses + gateway + dns + proxy; } /** @@ -135,12 +143,11 @@ public class LinkProperties implements Parcelable { */ public void writeToParcel(Parcel dest, int flags) { dest.writeString(getInterfaceName()); - dest.writeInt(mAddresses.size()); - //TODO: explore an easy alternative to preserve hostname - // without doing a lookup - for(InetAddress a : mAddresses) { - dest.writeByteArray(a.getAddress()); + dest.writeInt(mLinkAddresses.size()); + for(LinkAddress linkAddress : mLinkAddresses) { + dest.writeParcelable(linkAddress, flags); } + dest.writeInt(mDnses.size()); for(InetAddress d : mDnses) { dest.writeByteArray(d.getAddress()); @@ -170,16 +177,14 @@ public class LinkProperties implements Parcelable { String iface = in.readString(); if (iface != null) { try { - netProp.setInterface(NetworkInterface.getByName(iface)); + netProp.setInterfaceName(iface); } catch (Exception e) { return null; } } int addressCount = in.readInt(); for (int i=0; i<addressCount; i++) { - try { - netProp.addAddress(InetAddress.getByAddress(in.createByteArray())); - } catch (UnknownHostException e) { } + netProp.addLinkAddress((LinkAddress)in.readParcelable(null)); } addressCount = in.readInt(); for (int i=0; i<addressCount; i++) { diff --git a/core/java/android/nfc/NdefMessage.java b/core/java/android/nfc/NdefMessage.java new file mode 100644 index 0000000..557f651 --- /dev/null +++ b/core/java/android/nfc/NdefMessage.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.nfc; + +import android.nfc.NdefRecord; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.UnsupportedOperationException; + +/** + * NDEF Message data. + * <p> + * Immutable data class. An NDEF message always contains zero or more NDEF + * records. + */ +public class NdefMessage implements Parcelable { + /** + * Create an NDEF message from raw bytes. + * <p> + * Validation is performed to make sure the Record format headers are valid, + * and the ID + TYPE + PAYLOAD fields are of the correct size. + * + * @hide + */ + public NdefMessage(byte[] data) { + throw new UnsupportedOperationException(); + } + + /** + * Create an NDEF message from NDEF records. + */ + public NdefMessage(NdefRecord[] records) { + throw new UnsupportedOperationException(); + } + + /** + * Get the NDEF records inside this NDEF message. + * + * @return array of zero or more NDEF records. + */ + public NdefRecord[] getRecords() { + throw new UnsupportedOperationException(); + } + + /** + * Get a byte array representation of this NDEF message. + * + * @return byte array + * @hide + */ + public byte[] toByteArray() { + throw new UnsupportedOperationException(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + throw new UnsupportedOperationException(); + } + + public static final Parcelable.Creator<NdefMessage> CREATOR = + new Parcelable.Creator<NdefMessage>() { + public NdefMessage createFromParcel(Parcel in) { + throw new UnsupportedOperationException(); + } + public NdefMessage[] newArray(int size) { + throw new UnsupportedOperationException(); + } + }; +}
\ No newline at end of file diff --git a/core/java/android/nfc/NdefRecord.java b/core/java/android/nfc/NdefRecord.java new file mode 100644 index 0000000..54cbbeb --- /dev/null +++ b/core/java/android/nfc/NdefRecord.java @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.nfc; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.UnsupportedOperationException; + +/** + * NDEF Record data. + * <p> + * Immutable data class. An NDEF record always contains + * <ul> + * <li>3-bit TNF field + * <li>Variable length type + * <li>Variable length ID + * <li>Variable length payload + * </ul> + * The TNF (Type Name Format) field indicates how to interpret the type field. + * <p> + * This class represents a logical (unchunked) NDEF record. The underlying + * representation may be chunked across several NDEF records when the payload is + * large. + */ +public class NdefRecord implements Parcelable { + /** + * Indicates no type, id, or payload is associated with this NDEF Record. + * <p> + * Type, id and payload fields must all be empty to be a valid TNF_EMPTY + * record. + */ + public static final short TNF_EMPTY = 0x00; + + /** + * Indicates the type field uses the RTD type name format. + * <p> + * Use this TNF with RTD types such as RTD_TEXT, RTD_URI. + */ + public static final short TNF_WELL_KNOWN = 0x01; + + /** + * Indicates the type field contains a value that follows the media-type BNF + * construct defined by RFC 2046. + */ + public static final short TNF_MIME_MEDIA = 0x02; + + /** + * Indicates the type field contains a value that follows the absolute-URI + * BNF construct defined by RFC 3986. + */ + public static final short TNF_ABSOLUTE_URI = 0x03; + + /** + * Indicates the type field contains a value that follows the RTD external + * name specification. + * <p> + * Note this TNF should not be used with RTD_TEXT or RTD_URI constants. + * Those are well known RTD constants, not external RTD constants. + */ + public static final short TNF_EXTERNAL_TYPE = 0x04; + + /** + * Indicates the payload type is unknown. + * <p> + * This is similar to the "application/octet-stream" MIME type. The payload + * type is not explicitly encoded within the NDEF Message. + * <p> + * The type field must be empty to be a valid TNF_UNKNOWN record. + */ + public static final short TNF_UNKNOWN = 0x05; + + /** + * Indicates the payload is an intermediate or final chunk of a chunked + * NDEF Record. + * <p> + * The payload type is specified in the first chunk, and subsequent chunks + * must use TNF_UNCHANGED with an empty type field. TNF_UNCHANGED must not + * be used in any other situation. + */ + public static final short TNF_UNCHANGED = 0x06; + + /** + * Reserved TNF type. + * <p> + * The NFC Forum NDEF Specification v1.0 suggests for NDEF parsers to treat this + * value like TNF_UNKNOWN. + * @hide + */ + public static final short TNF_RESERVED = 0x07; + + /** + * RTD Text type. For use with TNF_WELL_KNOWN. + */ + public static final byte[] RTD_TEXT = {0x54}; // "T" + + /** + * RTD URI type. For use with TNF_WELL_KNOWN. + */ + public static final byte[] RTD_URI = {0x55}; // "U" + + /** + * RTD Smart Poster type. For use with TNF_WELL_KNOWN. + */ + public static final byte[] RTD_SMART_POSTER = {0x53, 0x70}; // "Sp" + + /** + * RTD Alternative Carrier type. For use with TNF_WELL_KNOWN. + */ + public static final byte[] RTD_ALTERNATIVE_CARRIER = {0x61, 0x63}; // "ac" + + /** + * RTD Handover Carrier type. For use with TNF_WELL_KNOWN. + */ + public static final byte[] RTD_HANDOVER_CARRIER = {0x48, 0x63}; // "Hc" + + /** + * RTD Handover Request type. For use with TNF_WELL_KNOWN. + */ + public static final byte[] RTD_HANDOVER_REQUEST = {0x48, 0x72}; // "Hr" + + /** + * RTD Handover Select type. For use with TNF_WELL_KNOWN. + */ + public static final byte[] RTD_HANDOVER_SELECT = {0x48, 0x73}; // "Hs" + + /** + * Construct an NDEF Record. + * <p> + * Applications should not attempt to manually chunk NDEF Records - the + * implementation of android.nfc will automatically chunk an NDEF Record + * when necessary (and only present a single logical NDEF Record to the + * application). So applications should not use TNF_UNCHANGED. + * + * @param tnf a 3-bit TNF constant + * @param type byte array, containing zero to 255 bytes, must not be null + * @param id byte array, containing zero to 255 bytes, must not be null + * @param payload byte array, containing zero to (2 ** 32 - 1) bytes, + * must not be null + */ + public NdefRecord(short tnf, byte[] type, byte[] id, byte[] payload) { + throw new UnsupportedOperationException(); + } + + /** + * Construct an NDEF Record from raw bytes. + * <p> + * Validation is performed to make sure the header is valid, and that + * the id, type and payload sizes appear to be valid. + * + * @throws FormatException if the data is not a valid NDEF record + */ + public NdefRecord(byte[] data) { + throw new UnsupportedOperationException(); + } + + /** + * Returns the 3-bit TNF. + * <p> + * TNF is the top-level type. + */ + public short getTnf() { + throw new UnsupportedOperationException(); + } + + /** + * Returns the variable length Type field. + * <p> + * This should be used in conjunction with the TNF field to determine the + * payload format. + */ + public byte[] getType() { + throw new UnsupportedOperationException(); + } + + /** + * Returns the variable length ID. + */ + public byte[] getId() { + throw new UnsupportedOperationException(); + } + + /** + * Returns the variable length payload. + */ + public byte[] getPayload() { + throw new UnsupportedOperationException(); + } + + /** + * Return this NDEF Record as a byte array. + * @hide + */ + public byte[] toByteArray() { + throw new UnsupportedOperationException(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + throw new UnsupportedOperationException(); + } + + public static final Parcelable.Creator<NdefRecord> CREATOR = + new Parcelable.Creator<NdefRecord>() { + public NdefRecord createFromParcel(Parcel in) { + throw new UnsupportedOperationException(); + } + public NdefRecord[] newArray(int size) { + throw new UnsupportedOperationException(); + } + }; +}
\ No newline at end of file diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java index 44b73c5..5fd2246 100644 --- a/core/java/android/os/BatteryManager.java +++ b/core/java/android/os/BatteryManager.java @@ -84,7 +84,15 @@ public class BatteryManager { * String describing the technology of the current battery. */ public static final String EXTRA_TECHNOLOGY = "technology"; - + + /** + * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}: + * Boolean value set to true if an unsupported charger is attached + * to the device. + * {@hide} + */ + public static final String EXTRA_INVALID_CHARGER = "invalid_charger"; + // values for "status" field in the ACTION_BATTERY_CHANGED Intent public static final int BATTERY_STATUS_UNKNOWN = 1; public static final int BATTERY_STATUS_CHARGING = 2; diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index f0b00dd..2fadb82 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -135,10 +135,10 @@ class GLES20Canvas extends HardwareCanvas { @Override void onPreDraw() { - nPrepare(mRenderer); + nPrepare(mRenderer, mOpaque); } - private native void nPrepare(int renderer); + private native void nPrepare(int renderer, boolean opaque); @Override void onPostDraw() { diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index 2cc4052..b87dbc5 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -585,7 +585,7 @@ public abstract class HardwareRenderer { @Override GLES20Canvas createCanvas() { - return mGlCanvas = new GLES20Canvas(true); + return mGlCanvas = new GLES20Canvas(mTranslucent); } @Override diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 54cb4ca..b45aa99 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -287,10 +287,12 @@ public class SurfaceView extends View { setMeasuredDimension(width, height); } + /** @hide */ @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); + protected boolean setFrame(int left, int top, int right, int bottom) { + boolean result = super.setFrame(left, top, right, bottom); updateWindow(false, false); + return result; } @Override diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 2afbe81..472f7b4 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -8543,7 +8543,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility if ((privateFlags & PRESSED) != 0) viewStateIndex |= VIEW_STATE_PRESSED; if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= VIEW_STATE_ENABLED; if (isFocused()) viewStateIndex |= VIEW_STATE_FOCUSED; - if ((privateFlags & SELECTED) != 0) viewStateIndex |= VIEW_STATE_PRESSED; + if ((privateFlags & SELECTED) != 0) viewStateIndex |= VIEW_STATE_SELECTED; if (hasWindowFocus()) viewStateIndex |= VIEW_STATE_WINDOW_FOCUSED; if ((privateFlags & ACTIVATED) != 0) viewStateIndex |= VIEW_STATE_ACTIVATED; @@ -9898,11 +9898,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility } /** - * Drag and drop. App calls startDrag(), then callbacks to onMeasureDragThumbnail() - * and onDrawDragThumbnail() happen, then the drag operation is handed over to the - * OS. + * Drag and drop. App calls startDrag(), then callbacks to the thumbnail builder's + * onProvideThumbnailMetrics() and onDrawThumbnail() methods happen, then the drag + * operation is handed over to the OS. * !!! TODO: real docs - * @hide */ public final boolean startDrag(ClipData data, DragThumbnailBuilder thumbBuilder, boolean myWindowOnly) { @@ -10027,7 +10026,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility * For DRAG_ENDED_EVENT, the 'event' argument may be null. The view should return * to its normal visual state. */ - protected boolean onDragEvent(DragEvent event) { + public boolean onDragEvent(DragEvent event) { return false; } diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 5ebc981..5b3a091 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -938,11 +938,16 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, "Drop event: " + event); View target = findFrontmostDroppableChildAt(event.mX, event.mY, mLocalPoint); if (target != null) { + if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, " dispatch drop to " + target); event.mX = mLocalPoint.x; event.mY = mLocalPoint.y; retval = target.dispatchDragEvent(event); event.mX = tx; event.mY = ty; + } else { + if (ViewDebug.DEBUG_DRAG) { + Log.d(View.VIEW_LOG_TAG, " not dropped on an accepting view"); + } } } break; } diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index 155122f..79f1f5b 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -16,25 +16,41 @@ package android.view; -import com.android.internal.view.BaseSurfaceHolder; -import com.android.internal.view.IInputMethodCallback; -import com.android.internal.view.IInputMethodSession; -import com.android.internal.view.RootViewSurfaceTaker; - +import android.Manifest; +import android.app.ActivityManagerNative; +import android.content.ClipDescription; +import android.content.ComponentCallbacks; +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.res.CompatibilityInfo; +import android.content.res.Configuration; +import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.PixelFormat; -import android.graphics.PorterDuff; import android.graphics.Point; import android.graphics.PointF; +import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.Region; -import android.os.*; +import android.media.AudioManager; +import android.os.Binder; +import android.os.Bundle; +import android.os.Debug; +import android.os.Handler; +import android.os.LatencyTimer; +import android.os.Looper; +import android.os.Message; +import android.os.ParcelFileDescriptor; import android.os.Process; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.SystemClock; +import android.os.SystemProperties; import android.util.AndroidRuntimeException; import android.util.Config; import android.util.DisplayMetrics; -import android.util.Log; import android.util.EventLog; +import android.util.Log; import android.util.Slog; import android.util.SparseArray; import android.view.View.MeasureSpec; @@ -43,21 +59,14 @@ import android.view.accessibility.AccessibilityManager; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; import android.widget.Scroller; -import android.content.pm.PackageManager; -import android.content.res.CompatibilityInfo; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.content.ClipData; -import android.content.ClipDescription; -import android.content.ComponentCallbacks; -import android.content.Context; -import android.app.ActivityManagerNative; -import android.Manifest; -import android.media.AudioManager; +import com.android.internal.view.BaseSurfaceHolder; +import com.android.internal.view.IInputMethodCallback; +import com.android.internal.view.IInputMethodSession; +import com.android.internal.view.RootViewSurfaceTaker; -import java.lang.ref.WeakReference; import java.io.IOException; import java.io.OutputStream; +import java.lang.ref.WeakReference; import java.util.ArrayList; /** diff --git a/core/java/android/view/animation/Interpolator.java b/core/java/android/view/animation/Interpolator.java index d14c3e3..5d0fe7e 100644 --- a/core/java/android/view/animation/Interpolator.java +++ b/core/java/android/view/animation/Interpolator.java @@ -16,24 +16,16 @@ package android.view.animation; +import android.animation.TimeInterpolator; + /** * An interpolator defines the rate of change of an animation. This allows * the basic animation effects (alpha, scale, translate, rotate) to be * accelerated, decelerated, repeated, etc. */ -public interface Interpolator { - - /** - * Maps a point on the timeline to a multiplier to be applied to the - * transformations of an animation. - * - * @param input A value between 0 and 1.0 indicating our current point - * in the animation where 0 represents the start and 1.0 represents - * the end - * @return The interpolation value. This value can be more than 1.0 for - * Interpolators which overshoot their targets, or less than 0 for - * Interpolators that undershoot their targets. - */ - float getInterpolation(float input); - +public interface Interpolator extends TimeInterpolator { + // A new interface, TimeInterpolator, was introduced for the new android.animation + // package. This older Interpolator interface extends TimeInterpolator so that users of + // the new Animator-based animations can use either the old Interpolator implementations or + // new classes that implement TimeInterpolator directly. } diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 8bd3298..8e355d6 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -1401,6 +1401,16 @@ public final class InputMethodManager { } } + public void showInputMethodAndSubtypeEnabler(String topId) { + synchronized (mH) { + try { + mService.showInputMethodAndSubtypeEnablerFromClient(mClient, topId); + } catch (RemoteException e) { + Log.w(TAG, "IME died: " + mCurId, e); + } + } + } + void doDump(FileDescriptor fd, PrintWriter fout, String[] args) { final Printer p = new PrintWriterPrinter(fout); p.println("Input method client state for " + this + ":"); diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index 7462668..7c089d8 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -22,6 +22,7 @@ import android.database.Cursor; import android.graphics.Point; import android.graphics.Rect; import android.graphics.Region; +import android.media.MediaFile; import android.net.Uri; import android.os.Handler; import android.os.Looper; @@ -252,6 +253,13 @@ final class WebViewCore { return mSettings; } + /* + * Given mimeType, check whether it's supported in Android media framework. + * mimeType could be such as "audio/ogg" and "video/mp4". + */ + /* package */ static boolean supportsMimeType(String mimeType) { + return MediaFile.getFileTypeForMimeType(mimeType) > 0; + } /** * Add an error message to the client's console. * @param message The message to add diff --git a/core/java/android/widget/AdapterViewAnimator.java b/core/java/android/widget/AdapterViewAnimator.java index 1d1e601..b7b1a23 100644 --- a/core/java/android/widget/AdapterViewAnimator.java +++ b/core/java/android/widget/AdapterViewAnimator.java @@ -324,7 +324,11 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter> } private int modulo(int pos, int size) { - return (size + (pos % size)) % size; + if (size > 0) { + return (size + (pos % size)) % size; + } else { + return 0; + } } /** @@ -383,6 +387,8 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter> void showOnly(int childIndex, boolean animate, boolean onLayout) { if (mAdapter == null) return; + final int adapterCount = mAdapter.getCount(); + if (adapterCount == 0) return; for (int i = 0; i < mPreviousViews.size(); i++) { View viewToRemove = mViewsMap.get(mPreviousViews.get(i)).view; @@ -399,7 +405,6 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter> removeViewInLayout(viewToRemove); } mPreviousViews.clear(); - int adapterCount = mAdapter.getCount(); int newWindowStartUnbounded = childIndex - mActiveOffset; int newWindowEndUnbounded = newWindowStartUnbounded + mNumActiveViews - 1; int newWindowStart = Math.max(0, newWindowStartUnbounded); diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java index 839de7d..f0954e2 100644 --- a/core/java/android/widget/StackView.java +++ b/core/java/android/widget/StackView.java @@ -749,7 +749,9 @@ public class StackView extends AdapterViewAnimator { if (mAdapter != null && mWhichChild == -1) { mWhichChild = mAdapter.getCount() - 1; } - setDisplayedChild(mWhichChild); + if (mWhichChild >= 0) { + setDisplayedChild(mWhichChild); + } } LayoutParams createOrReuseLayoutParams(View v) { diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 70c6378..d63af4e 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -97,6 +97,7 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewDebug; import android.view.ViewGroup.LayoutParams; +import android.view.ViewParent; import android.view.ViewRoot; import android.view.ViewTreeObserver; import android.view.accessibility.AccessibilityEvent; @@ -198,7 +199,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private int mCurrentAlpha = 255; - private final int[] mTempCoords = new int[2]; + final int[] mTempCoords = new int[2]; + Rect mTempRect; private ColorStateList mTextColor; private int mCurTextColor; @@ -7792,6 +7794,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private float mOffsetY; private float mHotspotX; private float mHotspotY; + private int mLastParentX; + private int mLastParentY; public HandleView(CursorController controller, Drawable handle) { super(TextView.this.mContext); @@ -7801,8 +7805,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener com.android.internal.R.attr.textSelectHandleWindowStyle); mContainer.setSplitTouchEnabled(true); mContainer.setClippingEnabled(false); - mHotspotX = mDrawable.getIntrinsicWidth() * 0.5f; - mHotspotY = -mDrawable.getIntrinsicHeight() * 0.2f; + + final int handleWidth = mDrawable.getIntrinsicWidth(); + final int handleHeight = mDrawable.getIntrinsicHeight(); + mHotspotX = handleWidth * 0.5f; + mHotspotY = -handleHeight * 0.2f; } @Override @@ -7812,7 +7819,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } public void show() { - if (!isPositionInBounds()) { + if (!isPositionVisible()) { hide(); return; } @@ -7833,7 +7840,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return mContainer.isShowing(); } - private boolean isPositionInBounds() { + private boolean isPositionVisible() { + // Always show a dragging handle. + if (mIsDragging) { + return true; + } + final int extendedPaddingTop = getExtendedPaddingTop(); final int extendedPaddingBottom = getExtendedPaddingBottom(); final int compoundPaddingLeft = getCompoundPaddingLeft(); @@ -7845,28 +7857,55 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final int top = 0; final int bottom = hostView.getHeight(); - final int clipLeft = left + compoundPaddingLeft; - final int clipTop = top + extendedPaddingTop; - final int clipRight = right - compoundPaddingRight; - final int clipBottom = bottom - extendedPaddingBottom; + if (mTempRect == null) { + mTempRect = new Rect(); + } + final Rect clip = mTempRect; + clip.left = left + compoundPaddingLeft; + clip.top = top + extendedPaddingTop; + clip.right = right - compoundPaddingRight; + clip.bottom = bottom - extendedPaddingBottom; + + final ViewParent parent = hostView.getParent(); + if (parent == null || !parent.getChildVisibleRect(hostView, clip, null)) { + return false; + } + + final int[] coords = mTempCoords; + hostView.getLocationInWindow(coords); + final int posX = coords[0] + mPositionX + (int) mHotspotX; + final int posY = coords[1] + mPositionY; - return mPositionX + mHotspotX >= clipLeft && mPositionX + mHotspotX <= clipRight && - mPositionY + mHotspotY >= clipTop && mPositionY + mHotspotY <= clipBottom; + return posX >= clip.left && posX <= clip.right && + posY >= clip.top && posY + mHotspotY <= clip.bottom; } private void moveTo(int x, int y) { mPositionX = x - TextView.this.mScrollX; mPositionY = y - TextView.this.mScrollY; - if (isPositionInBounds()) { + if (isPositionVisible()) { + int[] coords = null; if (mContainer.isShowing()){ - final int[] coords = mTempCoords; + coords = mTempCoords; TextView.this.getLocationInWindow(coords); - coords[0] += mPositionX; - coords[1] += mPositionY; - mContainer.update(coords[0], coords[1], mRight - mLeft, mBottom - mTop); + mContainer.update(coords[0] + mPositionX, coords[1] + mPositionY, + mRight - mLeft, mBottom - mTop); } else { show(); } + + if (mIsDragging) { + if (coords == null) { + coords = mTempCoords; + TextView.this.getLocationInWindow(coords); + } + if (coords[0] != mLastParentX || coords[1] != mLastParentY) { + mOffsetX += coords[0] - mLastParentX; + mOffsetY += coords[1] - mLastParentY; + mLastParentX = coords[0]; + mLastParentY = coords[1]; + } + } } else { hide(); } @@ -7893,6 +7932,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final float rawY = ev.getRawY(); mOffsetX = rawX - mPositionX; mOffsetY = rawY - mPositionY; + final int[] coords = mTempCoords; + TextView.this.getLocationInWindow(coords); + mLastParentX = coords[0]; + mLastParentY = coords[1]; mIsDragging = true; break; } diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java index 2a8cd94..00c4dbe 100644 --- a/core/java/com/android/internal/content/NativeLibraryHelper.java +++ b/core/java/com/android/internal/content/NativeLibraryHelper.java @@ -294,33 +294,44 @@ public class NativeLibraryHelper { } } + // Convenience method to call removeNativeBinariesFromDirLI(File) + public static boolean removeNativeBinariesLI(String nativeLibraryPath) { + return removeNativeBinariesFromDirLI(new File(nativeLibraryPath)); + } + // Remove the native binaries of a given package. This simply // gets rid of the files in the 'lib' sub-directory. - public static void removeNativeBinariesLI(String nativeLibraryPath) { + public static boolean removeNativeBinariesFromDirLI(File nativeLibraryDir) { if (DEBUG_NATIVE) { - Slog.w(TAG, "Deleting native binaries from: " + nativeLibraryPath); + Slog.w(TAG, "Deleting native binaries from: " + nativeLibraryDir.getPath()); } + boolean deletedFiles = false; + /* * Just remove any file in the directory. Since the directory is owned * by the 'system' UID, the application is not supposed to have written * anything there. */ - File binaryDir = new File(nativeLibraryPath); - if (binaryDir.exists()) { - File[] binaries = binaryDir.listFiles(); + if (nativeLibraryDir.exists()) { + final File[] binaries = nativeLibraryDir.listFiles(); if (binaries != null) { for (int nn = 0; nn < binaries.length; nn++) { if (DEBUG_NATIVE) { Slog.d(TAG, " Deleting " + binaries[nn].getName()); } + if (!binaries[nn].delete()) { Slog.w(TAG, "Could not delete native binary: " + binaries[nn].getPath()); + } else { + deletedFiles = true; } } } // Do not delete 'lib' directory itself, or this will prevent // installation of future updates. } + + return deletedFiles; } } diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl index d012b0f..bffec1d 100644 --- a/core/java/com/android/internal/view/IInputMethodManager.aidl +++ b/core/java/com/android/internal/view/IInputMethodManager.aidl @@ -49,6 +49,7 @@ interface IInputMethodManager { void showInputMethodPickerFromClient(in IInputMethodClient client); void showInputMethodSubtypePickerFromClient(in IInputMethodClient client); + void showInputMethodAndSubtypeEnablerFromClient(in IInputMethodClient client, String topId); void setInputMethod(in IBinder token, String id); void hideMySoftInput(in IBinder token, int flags); void showMySoftInput(in IBinder token, int flags); diff --git a/core/java/com/android/internal/view/InputMethodAndSubtypeEnabler.java b/core/java/com/android/internal/view/InputMethodAndSubtypeEnabler.java new file mode 100644 index 0000000..200d49f --- /dev/null +++ b/core/java/com/android/internal/view/InputMethodAndSubtypeEnabler.java @@ -0,0 +1,319 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.view; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.res.Configuration; +import android.os.Bundle; +import android.preference.CheckBoxPreference; +import android.preference.Preference; +import android.preference.PreferenceActivity; +import android.preference.PreferenceCategory; +import android.preference.PreferenceScreen; +import android.provider.Settings; +import android.text.TextUtils; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodManager; +import android.view.inputmethod.InputMethodSubtype; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +public class InputMethodAndSubtypeEnabler extends PreferenceActivity { + + private boolean mHaveHardKeyboard; + + private List<InputMethodInfo> mInputMethodProperties; + + private final TextUtils.SimpleStringSplitter mStringColonSplitter + = new TextUtils.SimpleStringSplitter(':'); + + private String mLastInputMethodId; + private String mLastTickedInputMethodId; + + private AlertDialog mDialog = null; + + @Override + protected void onCreate(Bundle icicle) { + super.onCreate(icicle); + Configuration config = getResources().getConfiguration(); + mHaveHardKeyboard = (config.keyboard == Configuration.KEYBOARD_QWERTY); + onCreateIMM(); + setPreferenceScreen(createPreferenceHierarchy()); + } + + @Override + protected void onResume() { + super.onResume(); + loadInputMethodSubtypeList(); + } + + @Override + protected void onPause() { + super.onPause(); + saveInputMethodSubtypeList(); + } + + @Override + public boolean onPreferenceTreeClick( + PreferenceScreen preferenceScreen, Preference preference) { + + if (preference instanceof CheckBoxPreference) { + final CheckBoxPreference chkPref = (CheckBoxPreference) preference; + final String id = chkPref.getKey(); + // TODO: Check subtype or not here + if (chkPref.isChecked()) { + InputMethodInfo selImi = null; + final int N = mInputMethodProperties.size(); + for (int i = 0; i < N; i++) { + InputMethodInfo imi = mInputMethodProperties.get(i); + if (id.equals(imi.getId())) { + selImi = imi; + if (isSystemIme(imi)) { + setSubtypesPreferenceEnabled(id, true); + // This is a built-in IME, so no need to warn. + mLastTickedInputMethodId = id; + return super.onPreferenceTreeClick(preferenceScreen, preference); + } + break; + } + } + if (selImi == null) { + return super.onPreferenceTreeClick(preferenceScreen, preference); + } + chkPref.setChecked(false); + if (mDialog == null) { + mDialog = (new AlertDialog.Builder(this)) + .setTitle(android.R.string.dialog_alert_title) + .setIcon(android.R.drawable.ic_dialog_alert) + .setCancelable(true) + .setPositiveButton(android.R.string.ok, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + chkPref.setChecked(true); + setSubtypesPreferenceEnabled(id, true); + mLastTickedInputMethodId = id; + } + + }) + .setNegativeButton(android.R.string.cancel, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + } + + }) + .create(); + } else { + if (mDialog.isShowing()) { + mDialog.dismiss(); + } + } + mDialog.setMessage(getResources().getString( + com.android.internal.R.string.ime_enabler_security_warning, + selImi.getServiceInfo().applicationInfo.loadLabel(getPackageManager()))); + mDialog.show(); + } else { + if (id.equals(mLastTickedInputMethodId)) { + mLastTickedInputMethodId = null; + } + setSubtypesPreferenceEnabled(id, false); + } + } + return super.onPreferenceTreeClick(preferenceScreen, preference); + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (mDialog != null) { + mDialog.dismiss(); + mDialog = null; + } + } + + private void onCreateIMM() { + InputMethodManager imm = (InputMethodManager) getSystemService( + Context.INPUT_METHOD_SERVICE); + + // TODO: Change mInputMethodProperties to Map + mInputMethodProperties = imm.getInputMethodList(); + + mLastInputMethodId = Settings.Secure.getString(getContentResolver(), + Settings.Secure.DEFAULT_INPUT_METHOD); + } + + private PreferenceScreen createPreferenceHierarchy() { + // Root + PreferenceScreen root = getPreferenceManager().createPreferenceScreen(this); + + int N = (mInputMethodProperties == null ? 0 : mInputMethodProperties.size()); + // TODO: Use iterator. + for (int i = 0; i < N; ++i) { + PreferenceCategory keyboardSettingsCategory = new PreferenceCategory(this); + root.addPreference(keyboardSettingsCategory); + InputMethodInfo property = mInputMethodProperties.get(i); + String prefKey = property.getId(); + + PackageManager pm = getPackageManager(); + CharSequence label = property.loadLabel(pm); + boolean systemIME = isSystemIme(property); + + keyboardSettingsCategory.setTitle(label); + + // Add a check box. + // Don't show the toggle if it's the only keyboard in the system, or it's a system IME. + if (mHaveHardKeyboard || (N > 1 && !systemIME)) { + CheckBoxPreference chkbxPref = new CheckBoxPreference(this); + chkbxPref.setKey(prefKey); + chkbxPref.setTitle(label); + keyboardSettingsCategory.addPreference(chkbxPref); + } + + ArrayList<InputMethodSubtype> subtypes = property.getSubtypes(); + if (subtypes.size() > 0) { + PreferenceCategory subtypesCategory = new PreferenceCategory(this); + subtypesCategory.setTitle(getResources().getString( + com.android.internal.R.string.ime_enabler_subtype_title, label)); + root.addPreference(subtypesCategory); + for (InputMethodSubtype subtype: subtypes) { + CharSequence subtypeLabel; + int nameResId = subtype.getNameResId(); + if (nameResId != 0) { + subtypeLabel = pm.getText(property.getPackageName(), nameResId, + property.getServiceInfo().applicationInfo); + } else { + int modeResId = subtype.getModeResId(); + CharSequence language = subtype.getLocale(); + CharSequence mode = modeResId == 0 ? null + : pm.getText(property.getPackageName(), modeResId, + property.getServiceInfo().applicationInfo); + // TODO: Use more friendly Title and UI + subtypeLabel = (mode == null ? "" : mode) + "," + + (language == null ? "" : language); + } + CheckBoxPreference chkbxPref = new CheckBoxPreference(this); + chkbxPref.setKey(prefKey + subtype.hashCode()); + chkbxPref.setTitle(subtypeLabel); + chkbxPref.setSummary(label); + subtypesCategory.addPreference(chkbxPref); + } + } + } + return root; + } + + private void loadInputMethodSubtypeList() { + final HashSet<String> enabled = new HashSet<String>(); + String enabledStr = Settings.Secure.getString(getContentResolver(), + Settings.Secure.ENABLED_INPUT_METHODS); + if (enabledStr != null) { + final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter; + splitter.setString(enabledStr); + while (splitter.hasNext()) { + enabled.add(splitter.next()); + } + } + + // Update the statuses of the Check Boxes. + int N = mInputMethodProperties.size(); + // TODO: Use iterator. + for (int i = 0; i < N; ++i) { + final String id = mInputMethodProperties.get(i).getId(); + CheckBoxPreference pref = (CheckBoxPreference) findPreference( + mInputMethodProperties.get(i).getId()); + if (pref != null) { + boolean isEnabled = enabled.contains(id); + pref.setChecked(isEnabled); + setSubtypesPreferenceEnabled(id, isEnabled); + } + } + mLastTickedInputMethodId = null; + } + + private void saveInputMethodSubtypeList() { + StringBuilder builder = new StringBuilder(); + StringBuilder disabledSysImes = new StringBuilder(); + + int firstEnabled = -1; + int N = mInputMethodProperties.size(); + for (int i = 0; i < N; ++i) { + final InputMethodInfo property = mInputMethodProperties.get(i); + final String id = property.getId(); + CheckBoxPreference pref = (CheckBoxPreference) findPreference(id); + boolean currentInputMethod = id.equals(mLastInputMethodId); + boolean systemIme = isSystemIme(property); + // TODO: Append subtypes by using the separator ";" + if (((N == 1 || systemIme) && !mHaveHardKeyboard) + || (pref != null && pref.isChecked())) { + if (builder.length() > 0) builder.append(':'); + builder.append(id); + if (firstEnabled < 0) { + firstEnabled = i; + } + } else if (currentInputMethod) { + mLastInputMethodId = mLastTickedInputMethodId; + } + // If it's a disabled system ime, add it to the disabled list so that it + // doesn't get enabled automatically on any changes to the package list + if (pref != null && !pref.isChecked() && systemIme && mHaveHardKeyboard) { + if (disabledSysImes.length() > 0) disabledSysImes.append(":"); + disabledSysImes.append(id); + } + } + + // If the last input method is unset, set it as the first enabled one. + if (TextUtils.isEmpty(mLastInputMethodId)) { + if (firstEnabled >= 0) { + mLastInputMethodId = mInputMethodProperties.get(firstEnabled).getId(); + } else { + mLastInputMethodId = null; + } + } + + Settings.Secure.putString(getContentResolver(), + Settings.Secure.ENABLED_INPUT_METHODS, builder.toString()); + Settings.Secure.putString(getContentResolver(), + Settings.Secure.DISABLED_SYSTEM_INPUT_METHODS, disabledSysImes.toString()); + Settings.Secure.putString(getContentResolver(), + Settings.Secure.DEFAULT_INPUT_METHOD, + mLastInputMethodId != null ? mLastInputMethodId : ""); + } + + private void setSubtypesPreferenceEnabled(String id, boolean enabled) { + PreferenceScreen preferenceScreen = getPreferenceScreen(); + final int N = mInputMethodProperties.size(); + // TODO: Use iterator. + for (int i = 0; i < N; i++) { + InputMethodInfo imi = mInputMethodProperties.get(i); + if (id.equals(imi.getId())) { + for (InputMethodSubtype subtype: imi.getSubtypes()) { + preferenceScreen.findPreference(id + subtype.hashCode()).setEnabled(enabled); + } + } + } + } + + private boolean isSystemIme(InputMethodInfo property) { + return (property.getServiceInfo().applicationInfo.flags + & ApplicationInfo.FLAG_SYSTEM) != 0; + } +} diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index 7521af4..2001919 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -103,8 +103,8 @@ static void android_view_GLES20Canvas_setViewport(JNIEnv* env, jobject canvas, } static void android_view_GLES20Canvas_prepare(JNIEnv* env, jobject canvas, - OpenGLRenderer* renderer) { - renderer->prepare(); + OpenGLRenderer* renderer, jboolean opaque) { + renderer->prepare(opaque); } static void android_view_GLES20Canvas_finish(JNIEnv* env, jobject canvas, @@ -445,7 +445,7 @@ static JNINativeMethod gMethods[] = { { "nCreateRenderer", "()I", (void*) android_view_GLES20Canvas_createRenderer }, { "nDestroyRenderer", "(I)V", (void*) android_view_GLES20Canvas_destroyRenderer }, { "nSetViewport", "(III)V", (void*) android_view_GLES20Canvas_setViewport }, - { "nPrepare", "(I)V", (void*) android_view_GLES20Canvas_prepare }, + { "nPrepare", "(IZ)V", (void*) android_view_GLES20Canvas_prepare }, { "nFinish", "(I)V", (void*) android_view_GLES20Canvas_finish }, { "nAcquireContext", "(I)V", (void*) android_view_GLES20Canvas_acquireContext }, { "nReleaseContext", "(I)V", (void*) android_view_GLES20Canvas_releaseContext }, diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 3a1d76f..f15d0a4 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1373,6 +1373,11 @@ android:permission="android.permission.BIND_WALLPAPER"> </service> + <activity android:name="com.android.internal.view.InputMethodAndSubtypeEnabler" + android:excludeFromRecents="true" + android:exported="true"> + </activity> + <receiver android:name="com.android.server.BootReceiver" > <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> diff --git a/core/res/res/drawable-hdpi/ic_dialog_menu_generic.png b/core/res/res/drawable-hdpi/ic_dialog_menu_generic.png Binary files differdeleted file mode 100644 index ef8a877..0000000 --- a/core/res/res/drawable-hdpi/ic_dialog_menu_generic.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/status_bar_close_on.9.png b/core/res/res/drawable-hdpi/status_bar_close_on.9.png Binary files differdeleted file mode 100644 index f313ffb..0000000 --- a/core/res/res/drawable-hdpi/status_bar_close_on.9.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/ic_dialog_menu_generic.png b/core/res/res/drawable-mdpi/ic_dialog_menu_generic.png Binary files differdeleted file mode 100755 index de07bda..0000000 --- a/core/res/res/drawable-mdpi/ic_dialog_menu_generic.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/status_bar_close_on.9.png b/core/res/res/drawable-mdpi/status_bar_close_on.9.png Binary files differdeleted file mode 100644 index 9cbd9fe..0000000 --- a/core/res/res/drawable-mdpi/status_bar_close_on.9.png +++ /dev/null diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 8b4f91f..521a739 100755 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1639,7 +1639,7 @@ <!-- Do not translate. WebView User Agent string --> <string name="web_user_agent" translatable="false">Mozilla/5.0 (Linux; U; <xliff:g id="x">Android %s</xliff:g>) - AppleWebKit/534.9 (KHTML, like Gecko) Version/4.0 <xliff:g id="mobile">%s</xliff:g>Safari/534.9</string> + AppleWebKit/534.10 (KHTML, like Gecko) Version/4.0 <xliff:g id="mobile">%s</xliff:g>Safari/534.10</string> <!-- Do not translate. WebView User Agent targeted content --> <string name="web_user_agent_target_content" translatable="false">"Mobile "</string> @@ -2385,5 +2385,9 @@ <item quantity="other"><xliff:g id="index" example="2">%d</xliff:g> of <xliff:g id="total" example="137">%d</xliff:g></item> </plurals> + <!-- Warning message about security implications of enabling an input method, displayed as a dialog message when the user selects to enable an IME. --> + <string name="ime_enabler_security_warning">This input method may be able to collect all the text you type, including personal data like passwords and credit card numbers. It comes from the application <xliff:g id="ime_application_name">%1$s</xliff:g>. Use this input method?</string> + <!-- Label for selecting the input method to use --> + <string name="ime_enabler_subtype_title">Select inputmethods in <xliff:g id="ime_application_name">%1$s</xliff:g></string> </resources> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index 4b5047e..0f653f1 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -1139,13 +1139,13 @@ <item name="android:textColorLink">?textColorLinkInverse</item> </style> - <style name="TextAppearance.Holo.Light.Large"> + <style name="TextAppearance.Holo.Light.Large" parent="TextAppearance.Large"> </style> - <style name="TextAppearance.Holo.Light.Medium"> + <style name="TextAppearance.Holo.Light.Medium" parent="TextAppearance.Medium"> </style> - <style name="TextAppearance.Holo.Light.Small"> + <style name="TextAppearance.Holo.Light.Small" parent="TextAppearance.Small"> </style> <style name="TextAppearance.Holo.Light.Large.Inverse"> diff --git a/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java index ed42e64..37fc6c7 100644 --- a/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java +++ b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java @@ -66,6 +66,7 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { protected MockWebServer mServer = null; protected String mFileType = "text/plain"; protected Context mContext = null; + protected MultipleDownloadsCompletedReceiver mReceiver = null; protected static final int DEFAULT_FILE_SIZE = 130 * 1024; // 130kb protected static final int FILE_BLOCK_READ_SIZE = 1024 * 1024; @@ -131,12 +132,15 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { */ @Override public void onReceive(Context context, Intent intent) { + Log.i(LOG_TAG, "Received Notification:"); if (intent.getAction().equalsIgnoreCase(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) { - ++mNumDownloadsCompleted; - Log.i(LOG_TAG, "MultipleDownloadsCompletedReceiver got intent: " + - intent.getAction() + " --> total count: " + mNumDownloadsCompleted); - Bundle extras = intent.getExtras(); - downloadIds.add(new Long(extras.getLong(DownloadManager.EXTRA_DOWNLOAD_ID))); + synchronized(this) { + ++mNumDownloadsCompleted; + Log.i(LOG_TAG, "MultipleDownloadsCompletedReceiver got intent: " + + intent.getAction() + " --> total count: " + mNumDownloadsCompleted); + Bundle extras = intent.getExtras(); + downloadIds.add(new Long(extras.getLong(DownloadManager.EXTRA_DOWNLOAD_ID))); + } } } @@ -212,6 +216,7 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { mContext = getInstrumentation().getContext(); mDownloadManager = (DownloadManager)mContext.getSystemService(Context.DOWNLOAD_SERVICE); mServer = new MockWebServer(); + mReceiver = registerNewMultipleDownloadsReceiver(); // Note: callers overriding this should call mServer.play() with the desired port # } @@ -712,8 +717,9 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { Cursor cursor = mDownloadManager.query(query); try { - // If we've finished the downloads then we're done - if (cursor.getCount() == 0) { + // @TODO: there may be a little cleaner way to check for success, perhaps + // via STATUS_SUCCESSFUL and/or STATUS_FAILED + if (cursor.getCount() == 0 && mReceiver.numDownloadsCompleted() > 0) { break; } currentWaitTime = timeoutWait(currentWaitTime, poll, timeoutMillis, diff --git a/core/tests/coretests/src/android/app/DownloadManagerIntegrationTest.java b/core/tests/coretests/src/android/app/DownloadManagerIntegrationTest.java index 27eea4d..cb7c2d2 100644 --- a/core/tests/coretests/src/android/app/DownloadManagerIntegrationTest.java +++ b/core/tests/coretests/src/android/app/DownloadManagerIntegrationTest.java @@ -61,7 +61,6 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { Environment.getRootDirectory().getAbsolutePath(); private final static String CACHE_DIR = Environment.getDownloadCacheDirectory().getAbsolutePath(); - protected MultipleDownloadsCompletedReceiver mReceiver = null; /** * {@inheritDoc} @@ -72,7 +71,6 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { setWiFiStateOn(true); mServer.play(); removeAllCurrentDownloads(); - mReceiver = registerNewMultipleDownloadsReceiver(); } /** @@ -270,7 +268,7 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { try { verifyInt(cursor, DownloadManager.COLUMN_STATUS, DownloadManager.STATUS_FAILED); verifyInt(cursor, DownloadManager.COLUMN_REASON, - DownloadManager.ERROR_FILE_ERROR); + DownloadManager.ERROR_FILE_ALREADY_EXISTS); } finally { cursor.close(); } @@ -429,6 +427,7 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { } } + Log.i(LOG_TAG, "Done creating filler file."); assertTrue(DOWNLOAD_FILE_SIZE > (fs.getAvailableBlocks() * blockSize)); byte[] blobData = generateData(DOWNLOAD_FILE_SIZE, DataType.TEXT); long dlRequest = doBasicDownload(blobData); diff --git a/core/tests/coretests/src/android/content/SyncStorageEngineTest.java b/core/tests/coretests/src/android/content/SyncStorageEngineTest.java index 0b494a7..ae41409 100644 --- a/core/tests/coretests/src/android/content/SyncStorageEngineTest.java +++ b/core/tests/coretests/src/android/content/SyncStorageEngineTest.java @@ -39,7 +39,8 @@ public class SyncStorageEngineTest extends AndroidTestCase { * correcponding sync is finished. This can happen if the clock changes while we are syncing. * */ - @SmallTest + // TODO: this test causes AidlTest to fail. Omit for now + // @SmallTest public void testPurgeActiveSync() throws Exception { final Account account = new Account("a@example.com", "example.type"); final String authority = "testprovider"; diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java index 1289a9e..276e281 100755 --- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java +++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java @@ -579,7 +579,6 @@ public class PackageManagerTests extends AndroidTestCase { private InstallParams installFromRawResource(String outFileName, int rawResId, int flags, boolean cleanUp, boolean fail, int result, int expInstallLocation) { - PackageManager pm = mContext.getPackageManager(); InstallParams ip = new InstallParams(outFileName, rawResId); installFromRawResource(ip, flags, cleanUp, fail, result, expInstallLocation); return ip; diff --git a/core/tests/coretests/src/com/android/internal/os/LoggingPrintStreamTest.java b/core/tests/coretests/src/com/android/internal/os/LoggingPrintStreamTest.java index 4d016d1..fe62764 100644 --- a/core/tests/coretests/src/com/android/internal/os/LoggingPrintStreamTest.java +++ b/core/tests/coretests/src/com/android/internal/os/LoggingPrintStreamTest.java @@ -16,7 +16,7 @@ package com.android.internal.os; -import junit.framework.TestCase; +import android.test.suitebuilder.annotation.Suppress; import java.io.PrintWriter; import java.io.StringWriter; @@ -25,6 +25,10 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import junit.framework.TestCase; + +// this test causes a IllegalAccessError: superclass not accessible +@Suppress public class LoggingPrintStreamTest extends TestCase { TestPrintStream out = new TestPrintStream(); diff --git a/graphics/java/android/renderscript/ProgramFragment.java b/graphics/java/android/renderscript/ProgramFragment.java index c1d6428..8858b74 100644 --- a/graphics/java/android/renderscript/ProgramFragment.java +++ b/graphics/java/android/renderscript/ProgramFragment.java @@ -104,7 +104,7 @@ public class ProgramFragment extends Program { private void buildShaderString() { mShader = "//rs_shader_internal\n"; mShader += "varying lowp vec4 varColor;\n"; - mShader += "varying vec4 varTex0;\n"; + mShader += "varying vec2 varTex0;\n"; mShader += "void main() {\n"; if (mVaryingColorEnable) { diff --git a/graphics/java/android/renderscript/ProgramVertex.java b/graphics/java/android/renderscript/ProgramVertex.java index 63e2598..65a0af2 100644 --- a/graphics/java/android/renderscript/ProgramVertex.java +++ b/graphics/java/android/renderscript/ProgramVertex.java @@ -101,7 +101,7 @@ public class ProgramVertex extends Program { mShader = "//rs_shader_internal\n"; mShader += "varying vec4 varColor;\n"; - mShader += "varying vec4 varTex0;\n"; + mShader += "varying vec2 varTex0;\n"; mShader += "void main() {\n"; mShader += " gl_Position = UNI_MVP * ATTRIB_position;\n"; @@ -109,7 +109,7 @@ public class ProgramVertex extends Program { mShader += " varColor = ATTRIB_color;\n"; if (mTextureMatrixEnable) { - mShader += " varTex0 = UNI_TexMatrix * ATTRIB_texture0;\n"; + mShader += " varTex0 = (UNI_TexMatrix * vec4(ATTRIB_texture0, 0.0, 1.0)).xy;\n"; } else { mShader += " varTex0 = ATTRIB_texture0;\n"; } @@ -126,7 +126,7 @@ public class ProgramVertex extends Program { b.add(Element.F32_4(mRS), "position"); b.add(Element.F32_4(mRS), "color"); b.add(Element.F32_3(mRS), "normal"); - b.add(Element.F32_4(mRS), "texture0"); + b.add(Element.F32_2(mRS), "texture0"); addInput(b.create()); return super.create(); diff --git a/include/camera/CameraHardwareInterface.h b/include/camera/CameraHardwareInterface.h index 3a77dd1..561a46d 100644 --- a/include/camera/CameraHardwareInterface.h +++ b/include/camera/CameraHardwareInterface.h @@ -21,6 +21,8 @@ #include <ui/egl/android_natives.h> #include <utils/RefBase.h> #include <surfaceflinger/ISurface.h> +#include <ui/android_native_buffer.h> +#include <ui/GraphicBuffer.h> #include <camera/Camera.h> #include <camera/CameraParameters.h> @@ -47,6 +49,17 @@ typedef void (*data_callback)(int32_t msgType, const sp<IMemory>& dataPtr, void* user); +#ifdef USE_GRAPHIC_VIDEO_BUFFERS +/** + * Replace data_callback_timestamp. Once we are done, this + * should be renamed as data_callback_timestamp, and the existing + * data_callback_timestamp should be deleted. + */ +typedef void (*videobuffer_callback_timestamp)(nsecs_t timestamp, + int32_t msgType, + const sp<android_native_buffer_t>& buf, + void* user); +#endif typedef void (*data_callback_timestamp)(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr, @@ -87,6 +100,46 @@ class CameraHardwareInterface : public virtual RefBase { public: virtual ~CameraHardwareInterface() { } +#ifdef USE_GRAPHIC_VIDEO_BUFFERS + /** + * Replace existing setCallbacks() method. Once we are done, the + * videobuffer_callback_timestamp parameter will be renamed to + * data_callback_timestamp, but its signature will be the same + * as videobuffer_callback_timestamp, which will be renamed + * to data_callback_timestamp and the exiting data_callback_timestamp + * will be deleted. + */ + virtual void setCallbacks(notify_callback notify_cb, + data_callback data_cb, + videobuffer_callback_timestamp data_cb_timestamp, + void* user) = 0; + + /** + * Replace releaseRecordingFrame(). releaseRecordingFrame() should be + * changed so that it has the same signature of releaseVideoBuffer(), + * once we are done, and releaseVideoBuffer() will be deleted. + */ + virtual void releaseVideoBuffer(const sp<android_native_buffer_t>& buf) = 0; + + /** + * This method should be called after startRecording(). + * + * @param nBuffers the total number of video buffers allocated by the camera + * hal + * @param buffers an array allocated by the camera hal to hold the pointers + * to the individual video buffers. The video buffers and the buffers array + * should NOT be modified/released by camera hal until stopRecording() is + * called and all outstanding video buffers previously sent out via + * CAMERA_MSG_VIDEO_FRAME have been released via releaseVideoBuffer(). + * Camera hal client must not release the individual buffers and the buffers + * array. + * @return no error if OK. + */ + virtual status_t getVideoBufferInfo( + sp<android_native_buffer_t>** buffers, + size_t *nBuffers) = 0; +#endif + /** Set the ANativeWindow to which preview frames are sent */ virtual status_t setPreviewWindow(const sp<ANativeWindow>& buf) = 0; diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h index ed2f7d7..37af032 100644 --- a/include/media/stagefright/AudioPlayer.h +++ b/include/media/stagefright/AudioPlayer.h @@ -49,11 +49,9 @@ public: status_t start(bool sourceAlreadyStarted = false); - void pause(); + void pause(bool playPendingSamples = false); void resume(); - void stop(); - // Returns the timestamp of the last buffer played (in us). int64_t getMediaTimeUs(); @@ -107,6 +105,8 @@ private: int64_t getRealTimeUsLocked() const; + void reset(); + AudioPlayer(const AudioPlayer &); AudioPlayer &operator=(const AudioPlayer &); }; diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h index 70bd8e8..cff38b2 100644 --- a/include/media/stagefright/MPEG4Writer.h +++ b/include/media/stagefright/MPEG4Writer.h @@ -64,6 +64,7 @@ private: FILE *mFile; bool mUse4ByteNalLength; bool mUse32BitOffset; + bool mIsFileSizeLimitExplicitlyRequested; bool mPaused; bool mStarted; off_t mOffset; diff --git a/include/private/surfaceflinger/SharedBufferStack.h b/include/private/surfaceflinger/SharedBufferStack.h index d689667..d6ae5e9 100644 --- a/include/private/surfaceflinger/SharedBufferStack.h +++ b/include/private/surfaceflinger/SharedBufferStack.h @@ -114,8 +114,9 @@ public: int32_t identity; // surface's identity (const) int32_t token; // surface's token (for debugging) - int32_t reserved32[1]; Statistics stats; + int8_t headBuf; // last retired buffer + uint8_t reservedBytes[3]; int32_t reserved; BufferData buffers[NUM_BUFFER_MAX]; // 1024 bytes }; @@ -201,6 +202,7 @@ public: status_t undoDequeue(int buf); status_t lock(int buf); + status_t cancel(int buf); status_t queue(int buf); bool needNewBuffer(int buffer) const; status_t setDirtyRegion(int buffer, const Region& reg); @@ -230,8 +232,9 @@ private: inline ssize_t operator()(); }; - struct UndoDequeueUpdate : public UpdateBase { - inline UndoDequeueUpdate(SharedBufferBase* sbb); + struct CancelUpdate : public UpdateBase { + int tail, buf; + inline CancelUpdate(SharedBufferBase* sbb, int tail, int buf); inline ssize_t operator()(); }; @@ -256,7 +259,6 @@ private: int mNumBuffers; int32_t tail; - int32_t undoDequeueTail; int32_t queued_head; // statistics... nsecs_t mDequeueTime[SharedBufferStack::NUM_BUFFER_MAX]; diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h index a210880..cef439c 100644 --- a/include/surfaceflinger/Surface.h +++ b/include/surfaceflinger/Surface.h @@ -200,6 +200,7 @@ private: */ static int setSwapInterval(ANativeWindow* window, int interval); static int dequeueBuffer(ANativeWindow* window, android_native_buffer_t** buffer); + static int cancelBuffer(ANativeWindow* window, android_native_buffer_t* buffer); static int lockBuffer(ANativeWindow* window, android_native_buffer_t* buffer); static int queueBuffer(ANativeWindow* window, android_native_buffer_t* buffer); static int query(ANativeWindow* window, int what, int* value); @@ -208,6 +209,7 @@ private: int dequeueBuffer(android_native_buffer_t** buffer); int lockBuffer(android_native_buffer_t* buffer); int queueBuffer(android_native_buffer_t* buffer); + int cancelBuffer(android_native_buffer_t* buffer); int query(int what, int* value); int perform(int operation, va_list args); diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h index 8d4654f..246df8f 100644 --- a/include/ui/InputDispatcher.h +++ b/include/ui/InputDispatcher.h @@ -212,8 +212,15 @@ struct InputWindow { int32_t ownerPid; int32_t ownerUid; - bool visibleFrameIntersects(const InputWindow* other) const; bool touchableAreaContainsPoint(int32_t x, int32_t y) const; + bool frameContainsPoint(int32_t x, int32_t y) const; + + /* Returns true if the window is of a trusted type that is allowed to silently + * overlay other windows for the purpose of implementing the secure views feature. + * Trusted overlays, such as IME windows, can partly obscure other windows without causing + * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. + */ + bool isTrustedOverlay() const; }; @@ -973,7 +980,7 @@ private: bool shouldPokeUserActivityForCurrentInputTargetsLocked(); void pokeUserActivityLocked(nsecs_t eventTime, int32_t eventType); bool checkInjectionPermission(const InputWindow* window, const InjectionState* injectionState); - bool isWindowObscuredLocked(const InputWindow* window); + bool isWindowObscuredAtPointLocked(const InputWindow* window, int32_t x, int32_t y) const; bool isWindowFinishedWithPreviousInputLocked(const InputWindow* window); String8 getApplicationWindowLabelLocked(const InputApplication* application, const InputWindow* window); diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h index d59d72b..654d0f3 100644 --- a/include/ui/egl/android_natives.h +++ b/include/ui/egl/android_natives.h @@ -218,7 +218,17 @@ struct ANativeWindow int (*perform)(struct ANativeWindow* window, int operation, ... ); - void* reserved_proc[3]; + /* + * hook used to cancel a buffer that has been dequeued. + * No synchronization is performed between dequeue() and cancel(), so + * either external synchronization is needed, or these functions must be + * called from the same thread. + */ + int (*cancelBuffer)(struct ANativeWindow* window, + struct android_native_buffer_t* buffer); + + + void* reserved_proc[2]; }; // Backwards compatibility... please switch to ANativeWindow. diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index ce85d46..61e5408 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -342,7 +342,7 @@ void DisplayListRenderer::setViewport(int width, int height) { mHeight = height; } -void DisplayListRenderer::prepare() { +void DisplayListRenderer::prepare(bool opaque) { mSnapshot = new Snapshot(mFirstSnapshot, SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); mSaveCount = 1; diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h index 5d02bd7..0fbfce1 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -209,7 +209,7 @@ public: ~DisplayListRenderer(); void setViewport(int width, int height); - void prepare(); + void prepare(bool opaque); void acquireContext(); void releaseContext(); diff --git a/libs/hwui/OpenGLDebugRenderer.cpp b/libs/hwui/OpenGLDebugRenderer.cpp index 4e5123e..b9583e5 100644 --- a/libs/hwui/OpenGLDebugRenderer.cpp +++ b/libs/hwui/OpenGLDebugRenderer.cpp @@ -23,10 +23,10 @@ namespace android { namespace uirenderer { -void OpenGLDebugRenderer::prepare() { +void OpenGLDebugRenderer::prepare(bool opaque) { mPrimitivesCount = 0; LOGD("========= Frame start ========="); - OpenGLRenderer::prepare(); + OpenGLRenderer::prepare(opaque); } void OpenGLDebugRenderer::finish() { diff --git a/libs/hwui/OpenGLDebugRenderer.h b/libs/hwui/OpenGLDebugRenderer.h index ce15512..2ac19ae 100644 --- a/libs/hwui/OpenGLDebugRenderer.h +++ b/libs/hwui/OpenGLDebugRenderer.h @@ -34,7 +34,7 @@ public: ~OpenGLDebugRenderer() { } - void prepare(); + void prepare(bool opaque); void finish(); int saveLayer(float left, float top, float right, float bottom, diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index ee5fe22..5399668 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -150,7 +150,7 @@ void OpenGLRenderer::setViewport(int width, int height) { mFirstSnapshot->viewport.set(0, 0, width, height); } -void OpenGLRenderer::prepare() { +void OpenGLRenderer::prepare(bool opaque) { mSnapshot = new Snapshot(mFirstSnapshot, SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); mSaveCount = 1; @@ -160,8 +160,10 @@ void OpenGLRenderer::prepare() { glDisable(GL_DITHER); glDisable(GL_SCISSOR_TEST); - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT); + if (!opaque) { + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT); + } glEnable(GL_SCISSOR_TEST); glScissor(0, 0, mWidth, mHeight); @@ -325,7 +327,10 @@ int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bot * - Issue the drawing * * Switching rendering target n + 1 times per drawn primitive is extremely costly. - * To avoid this, layers are implemented in a different way here. + * To avoid this, layers are implemented in a different way here, at least in the + * general case. FBOs are used, as an optimization, when the "clip to layer" flag + * is set. When this flag is set we can redirect all drawing operations into a + * single FBO. * * This implementation relies on the frame buffer being at least RGBA 8888. When * a layer is created, only a texture is created, not an FBO. The content of the diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index e3d4653..4caa8fb 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -67,7 +67,7 @@ public: virtual void setViewport(int width, int height); - virtual void prepare(); + virtual void prepare(bool opaque); virtual void finish(); virtual void acquireContext(); diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index 3e9412c..439e6fb 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -35,17 +35,10 @@ const char* gVS_Header_Uniforms = "uniform mat4 transform;\n"; const char* gVS_Header_Uniforms_HasGradient[3] = { // Linear - "uniform float gradientLength;\n" - "uniform vec2 gradient;\n" - "uniform vec2 gradientStart;\n" "uniform mat4 screenSpace;\n", // Circular - "uniform vec2 gradientStart;\n" - "uniform mat4 gradientMatrix;\n" "uniform mat4 screenSpace;\n", // Sweep - "uniform vec2 gradientStart;\n" - "uniform mat4 gradientMatrix;\n" "uniform mat4 screenSpace;\n" }; const char* gVS_Header_Uniforms_HasBitmap = @@ -69,14 +62,11 @@ const char* gVS_Main_OutTexCoords = " outTexCoords = texCoords;\n"; const char* gVS_Main_OutGradient[3] = { // Linear - " vec4 location = screenSpace * position;\n" - " index = dot(location.xy - gradientStart, gradient) * gradientLength;\n", + " index = (screenSpace * position).x;\n", // Circular - " vec4 location = screenSpace * position;\n" - " circular = (gradientMatrix * vec4(location.xy - gradientStart, 0.0, 0.0)).xy;\n", + " circular = (screenSpace * position).xy;\n", // Sweep - " vec4 location = screenSpace * position;\n" - " sweep = (gradientMatrix * vec4(location.xy - gradientStart, 0.0, 0.0)).xy;\n" + " sweep = (screenSpace * position).xy;\n" }; const char* gVS_Main_OutBitmapTexCoords = " vec4 bitmapCoords = textureTransform * position;\n" @@ -102,7 +92,6 @@ const char* gFS_Uniforms_GradientSampler[3] = { // Linear "uniform sampler2D gradientSampler;\n", // Circular - "uniform float gradientRadius;\n" "uniform sampler2D gradientSampler;\n", // Sweep "uniform sampler2D gradientSampler;\n" @@ -134,7 +123,7 @@ const char* gFS_Main_FetchGradient[3] = { // Linear " vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n", // Circular - " float index = length(circular) * gradientRadius;\n" + " float index = length(circular);\n" " vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n", // Sweep " float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n" diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp index 165c0da..fa85d20 100644 --- a/libs/hwui/SkiaShader.cpp +++ b/libs/hwui/SkiaShader.cpp @@ -49,7 +49,8 @@ static const GLint gTileModes[] = { SkiaShader::SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX, SkShader::TileMode tileY, SkMatrix* matrix, bool blend): - mType(type), mKey(key), mTileX(tileX), mTileY(tileY), mMatrix(matrix), mBlend(blend) { + mType(type), mKey(key), mTileX(tileX), mTileY(tileY), mBlend(blend) { + setMatrix(matrix); } SkiaShader::~SkiaShader() { @@ -69,6 +70,11 @@ void SkiaShader::bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT, GLuint glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT); } +void SkiaShader::computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView) { + screenSpace.loadMultiply(mUnitMatrix, mShaderMatrix); + screenSpace.multiply(modelView); +} + /////////////////////////////////////////////////////////////////////////////// // Bitmap shader /////////////////////////////////////////////////////////////////////////////// @@ -76,6 +82,7 @@ void SkiaShader::bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT, GLuint SkiaBitmapShader::SkiaBitmapShader(SkBitmap* bitmap, SkShader* key, SkShader::TileMode tileX, SkShader::TileMode tileY, SkMatrix* matrix, bool blend): SkiaShader(kBitmap, key, tileX, tileY, matrix, blend), mBitmap(bitmap), mTexture(NULL) { + updateLocalMatrix(matrix); } void SkiaBitmapShader::describe(ProgramDescription& description, const Extensions& extensions) { @@ -116,14 +123,7 @@ void SkiaBitmapShader::setupProgram(Program* program, const mat4& modelView, const float height = texture->height; mat4 textureTransform; - if (mMatrix) { - SkMatrix inverse; - mMatrix->invert(&inverse); - textureTransform.load(inverse); - textureTransform.multiply(modelView); - } else { - textureTransform.load(modelView); - } + computeScreenSpaceMatrix(textureTransform, modelView); // Uniforms bindTexture(texture->id, mWrapS, mWrapT, textureSlot); @@ -136,15 +136,7 @@ void SkiaBitmapShader::setupProgram(Program* program, const mat4& modelView, void SkiaBitmapShader::updateTransforms(Program* program, const mat4& modelView, const Snapshot& snapshot) { mat4 textureTransform; - if (mMatrix) { - SkMatrix inverse; - mMatrix->invert(&inverse); - textureTransform.load(inverse); - textureTransform.multiply(modelView); - } else { - textureTransform.load(modelView); - } - + computeScreenSpaceMatrix(textureTransform, modelView); glUniformMatrix4fv(program->getUniform("textureTransform"), 1, GL_FALSE, &textureTransform.data[0]); } @@ -153,11 +145,31 @@ void SkiaBitmapShader::updateTransforms(Program* program, const mat4& modelView, // Linear gradient shader /////////////////////////////////////////////////////////////////////////////// +static void toUnitMatrix(const SkPoint pts[2], SkMatrix* matrix) { + SkVector vec = pts[1] - pts[0]; + const float mag = vec.length(); + const float inv = mag ? 1.0f / mag : 0; + + vec.scale(inv); + matrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY); + matrix->postTranslate(-pts[0].fX, -pts[0].fY); + matrix->postScale(inv, inv); +} + SkiaLinearGradientShader::SkiaLinearGradientShader(float* bounds, uint32_t* colors, float* positions, int count, SkShader* key, SkShader::TileMode tileMode, SkMatrix* matrix, bool blend): SkiaShader(kLinearGradient, key, tileMode, tileMode, matrix, blend), mBounds(bounds), mColors(colors), mPositions(positions), mCount(count) { + SkPoint points[2]; + points[0].set(bounds[0], bounds[1]); + points[1].set(bounds[2], bounds[3]); + + SkMatrix unitMatrix; + toUnitMatrix(points, &unitMatrix); + mUnitMatrix.load(unitMatrix); + + updateLocalMatrix(matrix); } SkiaLinearGradientShader::~SkiaLinearGradientShader() { @@ -182,34 +194,19 @@ void SkiaLinearGradientShader::setupProgram(Program* program, const mat4& modelV texture = mGradientCache->addLinearGradient(mKey, mColors, mPositions, mCount, mTileX); } - Rect start(mBounds[0], mBounds[1], mBounds[2], mBounds[3]); - if (mMatrix) { - mat4 shaderMatrix(*mMatrix); - shaderMatrix.mapPoint(start.left, start.top); - shaderMatrix.mapPoint(start.right, start.bottom); - } - snapshot.transform->mapRect(start); - - const float gradientX = start.right - start.left; - const float gradientY = start.bottom - start.top; - - mat4 screenSpace(*snapshot.transform); - screenSpace.multiply(modelView); + mat4 screenSpace; + computeScreenSpaceMatrix(screenSpace, modelView); // Uniforms bindTexture(texture->id, gTileModes[mTileX], gTileModes[mTileY], textureSlot); glUniform1i(program->getUniform("gradientSampler"), textureSlot); - glUniform2f(program->getUniform("gradientStart"), start.left, start.top); - glUniform2f(program->getUniform("gradient"), gradientX, gradientY); - glUniform1f(program->getUniform("gradientLength"), - 1.0f / (gradientX * gradientX + gradientY * gradientY)); glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); } void SkiaLinearGradientShader::updateTransforms(Program* program, const mat4& modelView, const Snapshot& snapshot) { - mat4 screenSpace(*snapshot.transform); - screenSpace.multiply(modelView); + mat4 screenSpace; + computeScreenSpaceMatrix(screenSpace, modelView); glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); } @@ -217,12 +214,23 @@ void SkiaLinearGradientShader::updateTransforms(Program* program, const mat4& mo // Circular gradient shader /////////////////////////////////////////////////////////////////////////////// +static void toCircularUnitMatrix(const float x, const float y, const float radius, + SkMatrix* matrix) { + const float inv = 1.0f / radius; + matrix->setTranslate(-x, -y); + matrix->postScale(inv, inv); +} + SkiaCircularGradientShader::SkiaCircularGradientShader(float x, float y, float radius, uint32_t* colors, float* positions, int count, SkShader* key, SkShader::TileMode tileMode, SkMatrix* matrix, bool blend): SkiaSweepGradientShader(kCircularGradient, x, y, colors, positions, count, key, - tileMode, matrix, blend), - mRadius(radius) { + tileMode, matrix, blend) { + SkMatrix unitMatrix; + toCircularUnitMatrix(x, y, radius, &unitMatrix); + mUnitMatrix.load(unitMatrix); + + updateLocalMatrix(matrix); } void SkiaCircularGradientShader::describe(ProgramDescription& description, @@ -231,28 +239,31 @@ void SkiaCircularGradientShader::describe(ProgramDescription& description, description.gradientType = ProgramDescription::kGradientCircular; } -void SkiaCircularGradientShader::setupProgram(Program* program, const mat4& modelView, - const Snapshot& snapshot, GLuint* textureUnit) { - SkiaSweepGradientShader::setupProgram(program, modelView, snapshot, textureUnit); - glUniform1f(program->getUniform("gradientRadius"), 1.0f / mRadius); -} - /////////////////////////////////////////////////////////////////////////////// // Sweep gradient shader /////////////////////////////////////////////////////////////////////////////// +static void toSweepUnitMatrix(const float x, const float y, SkMatrix* matrix) { + matrix->setTranslate(-x, -y); +} + SkiaSweepGradientShader::SkiaSweepGradientShader(float x, float y, uint32_t* colors, float* positions, int count, SkShader* key, SkMatrix* matrix, bool blend): SkiaShader(kSweepGradient, key, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, matrix, blend), - mX(x), mY(y), mColors(colors), mPositions(positions), mCount(count) { + mColors(colors), mPositions(positions), mCount(count) { + SkMatrix unitMatrix; + toSweepUnitMatrix(x, y, &unitMatrix); + mUnitMatrix.load(unitMatrix); + + updateLocalMatrix(matrix); } SkiaSweepGradientShader::SkiaSweepGradientShader(Type type, float x, float y, uint32_t* colors, float* positions, int count, SkShader* key, SkShader::TileMode tileMode, SkMatrix* matrix, bool blend): SkiaShader(type, key, tileMode, tileMode, matrix, blend), - mX(x), mY(y), mColors(colors), mPositions(positions), mCount(count) { + mColors(colors), mPositions(positions), mCount(count) { } SkiaSweepGradientShader::~SkiaSweepGradientShader() { @@ -276,35 +287,19 @@ void SkiaSweepGradientShader::setupProgram(Program* program, const mat4& modelVi texture = mGradientCache->addLinearGradient(mKey, mColors, mPositions, mCount); } - float left = mX; - float top = mY; - - mat4 shaderMatrix; - if (mMatrix) { - shaderMatrix.load(*mMatrix); - shaderMatrix.mapPoint(left, top); - } - - mat4 copy(shaderMatrix); - shaderMatrix.loadInverse(copy); - - snapshot.transform->mapPoint(left, top); - - mat4 screenSpace(*snapshot.transform); - screenSpace.multiply(modelView); + mat4 screenSpace; + computeScreenSpaceMatrix(screenSpace, modelView); // Uniforms bindTexture(texture->id, gTileModes[mTileX], gTileModes[mTileY], textureSlot); glUniform1i(program->getUniform("gradientSampler"), textureSlot); - glUniformMatrix4fv(program->getUniform("gradientMatrix"), 1, GL_FALSE, &shaderMatrix.data[0]); - glUniform2f(program->getUniform("gradientStart"), left, top); glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); } void SkiaSweepGradientShader::updateTransforms(Program* program, const mat4& modelView, const Snapshot& snapshot) { - mat4 screenSpace(*snapshot.transform); - screenSpace.multiply(modelView); + mat4 screenSpace; + computeScreenSpaceMatrix(screenSpace, modelView); glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); } diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h index 9f8778f..2565e65 100644 --- a/libs/hwui/SkiaShader.h +++ b/libs/hwui/SkiaShader.h @@ -78,9 +78,20 @@ struct SkiaShader { } void setMatrix(SkMatrix* matrix) { - mMatrix = matrix; + updateLocalMatrix(matrix); } + void updateLocalMatrix(const SkMatrix* matrix) { + if (matrix) { + mat4 localMatrix(*matrix); + mShaderMatrix.loadInverse(localMatrix); + } else { + mShaderMatrix.loadIdentity(); + } + } + + void computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView); + protected: inline void bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit); @@ -88,11 +99,13 @@ protected: SkShader* mKey; SkShader::TileMode mTileX; SkShader::TileMode mTileY; - SkMatrix* mMatrix; bool mBlend; TextureCache* mTextureCache; GradientCache* mGradientCache; + + mat4 mUnitMatrix; + mat4 mShaderMatrix; }; // struct SkiaShader @@ -155,7 +168,7 @@ struct SkiaSweepGradientShader: public SkiaShader { ~SkiaSweepGradientShader(); virtual void describe(ProgramDescription& description, const Extensions& extensions); - virtual void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot, + void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot, GLuint* textureUnit); void updateTransforms(Program* program, const mat4& modelView, const Snapshot& snapshot); @@ -163,7 +176,6 @@ protected: SkiaSweepGradientShader(Type type, float x, float y, uint32_t* colors, float* positions, int count, SkShader* key, SkShader::TileMode tileMode, SkMatrix* matrix, bool blend); - float mX, mY; uint32_t* mColors; float* mPositions; int mCount; @@ -177,11 +189,6 @@ struct SkiaCircularGradientShader: public SkiaSweepGradientShader { int count, SkShader* key,SkShader::TileMode tileMode, SkMatrix* matrix, bool blend); void describe(ProgramDescription& description, const Extensions& extensions); - void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot, - GLuint* textureUnit); - -private: - float mRadius; }; // struct SkiaCircularGradientShader /** diff --git a/libs/rs/java/Samples/res/raw/multitexf.glsl b/libs/rs/java/Samples/res/raw/multitexf.glsl index 91151ad..351ff9b 100644 --- a/libs/rs/java/Samples/res/raw/multitexf.glsl +++ b/libs/rs/java/Samples/res/raw/multitexf.glsl @@ -1,4 +1,4 @@ -varying vec4 varTex0; +varying vec2 varTex0; void main() { vec2 t0 = varTex0.xy; diff --git a/libs/rs/java/tests/src/com/android/rs/test/primitives.rs b/libs/rs/java/tests/src/com/android/rs/test/primitives.rs index 5312bcc..012af9c 100644 --- a/libs/rs/java/tests/src/com/android/rs/test/primitives.rs +++ b/libs/rs/java/tests/src/com/android/rs/test/primitives.rs @@ -2,15 +2,21 @@ #pragma rs export_func(primitives_test) +#pragma rs export_var(floatTest, doubleTest, charTest, shortTest, intTest, longTest, longlongTest) + // Testing primitive types static float floatTest = 1.99f; static double doubleTest = 2.05; static char charTest = -8; static short shortTest = -16; static int intTest = -32; +static long longTest = 17179869184l; // 1 << 34 +static long long longlongTest = 68719476736l; // 1 << 36 + static uchar ucharTest = 8; static ushort ushortTest = 16; static uint uintTest = 32; +static int64_t int64_tTest = -17179869184l; // - 1 << 34 static bool test_primitive_types(uint32_t index) { bool failed = false; @@ -21,9 +27,13 @@ static bool test_primitive_types(uint32_t index) { _RS_ASSERT(charTest == -8); _RS_ASSERT(shortTest == -16); _RS_ASSERT(intTest == -32); + _RS_ASSERT(longTest == 17179869184l); + _RS_ASSERT(longlongTest == 68719476736l); + _RS_ASSERT(ucharTest == 8); _RS_ASSERT(ushortTest == 16); _RS_ASSERT(uintTest == 32); + _RS_ASSERT(int64_tTest == -17179869184l); float time = end(index); diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp index b9de7e1..a951005 100644 --- a/libs/rs/rsFont.cpp +++ b/libs/rs/rsFont.cpp @@ -497,7 +497,7 @@ bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *r void FontState::initRenderState() { - String8 shaderString("varying vec4 varTex0;\n"); + String8 shaderString("varying vec2 varTex0;\n"); shaderString.append("void main() {\n"); shaderString.append(" lowp vec4 col = UNI_Color;\n"); shaderString.append(" col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n"); diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp index c94f294..81b4fa4 100644 --- a/libs/rs/rsProgramFragment.cpp +++ b/libs/rs/rsProgramFragment.cpp @@ -190,7 +190,7 @@ void ProgramFragmentState::init(Context *rsc) { String8 shaderString(RS_SHADER_INTERNAL); shaderString.append("varying lowp vec4 varColor;\n"); - shaderString.append("varying vec4 varTex0;\n"); + shaderString.append("varying vec2 varTex0;\n"); shaderString.append("void main() {\n"); shaderString.append(" lowp vec4 col = UNI_Color;\n"); shaderString.append(" gl_FragColor = col;\n"); diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp index d3dbfb2..a785262 100644 --- a/libs/rs/rsProgramVertex.cpp +++ b/libs/rs/rsProgramVertex.cpp @@ -242,6 +242,7 @@ ProgramVertexState::~ProgramVertexState() void ProgramVertexState::init(Context *rsc) { const Element *matrixElem = Element::create(rsc, RS_TYPE_MATRIX_4X4, RS_KIND_USER, false, 1); + const Element *f2Elem = Element::create(rsc, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2); const Element *f3Elem = Element::create(rsc, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3); const Element *f4Elem = Element::create(rsc, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4); @@ -256,7 +257,7 @@ void ProgramVertexState::init(Context *rsc) rsc->mStateElement.elementBuilderAdd(f4Elem, "position", 1); rsc->mStateElement.elementBuilderAdd(f4Elem, "color", 1); rsc->mStateElement.elementBuilderAdd(f3Elem, "normal", 1); - rsc->mStateElement.elementBuilderAdd(f4Elem, "texture0", 1); + rsc->mStateElement.elementBuilderAdd(f2Elem, "texture0", 1); const Element *attrElem = rsc->mStateElement.elementBuilderCreate(rsc); Type *inputType = new Type(rsc); @@ -266,7 +267,7 @@ void ProgramVertexState::init(Context *rsc) String8 shaderString(RS_SHADER_INTERNAL); shaderString.append("varying vec4 varColor;\n"); - shaderString.append("varying vec4 varTex0;\n"); + shaderString.append("varying vec2 varTex0;\n"); shaderString.append("void main() {\n"); shaderString.append(" gl_Position = UNI_MVP * ATTRIB_position;\n"); shaderString.append(" gl_PointSize = 1.0;\n"); diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/surfaceflinger_client/SharedBufferStack.cpp index a43b440..8f583f0 100644 --- a/libs/surfaceflinger_client/SharedBufferStack.cpp +++ b/libs/surfaceflinger_client/SharedBufferStack.cpp @@ -285,10 +285,12 @@ ssize_t SharedBufferClient::DequeueUpdate::operator()() { return NO_ERROR; } -SharedBufferClient::UndoDequeueUpdate::UndoDequeueUpdate(SharedBufferBase* sbb) - : UpdateBase(sbb) { +SharedBufferClient::CancelUpdate::CancelUpdate(SharedBufferBase* sbb, + int tail, int buf) + : UpdateBase(sbb), tail(tail), buf(buf) { } -ssize_t SharedBufferClient::UndoDequeueUpdate::operator()() { +ssize_t SharedBufferClient::CancelUpdate::operator()() { + stack.index[tail] = buf; android_atomic_inc(&stack.available); return NO_ERROR; } @@ -319,7 +321,7 @@ ssize_t SharedBufferServer::RetireUpdate::operator()() { return BAD_VALUE; // Preventively lock the current buffer before updating queued. - android_atomic_write(stack.index[head], &stack.inUse); + android_atomic_write(stack.headBuf, &stack.inUse); // Decrement the number of queued buffers int32_t queued; @@ -334,7 +336,9 @@ ssize_t SharedBufferServer::RetireUpdate::operator()() { // the buffer we preventively locked upon entering this function head = (head + 1) % numBuffers; - android_atomic_write(stack.index[head], &stack.inUse); + const int8_t headBuf = stack.index[head]; + stack.headBuf = headBuf; + android_atomic_write(headBuf, &stack.inUse); // head is only modified here, so we don't need to use cmpxchg android_atomic_write(head, &stack.head); @@ -359,7 +363,7 @@ ssize_t SharedBufferServer::StatusUpdate::operator()() { SharedBufferClient::SharedBufferClient(SharedClient* sharedClient, int surface, int num, int32_t identity) : SharedBufferBase(sharedClient, surface, identity), - mNumBuffers(num), tail(0), undoDequeueTail(0) + mNumBuffers(num), tail(0) { SharedBufferStack& stack( *mSharedStack ); tail = computeTail(); @@ -390,7 +394,6 @@ ssize_t SharedBufferClient::dequeue() DequeueUpdate update(this); updateCondition( update ); - undoDequeueTail = tail; int dequeued = stack.index[tail]; tail = ((tail+1 >= mNumBuffers) ? 0 : tail+1); LOGD_IF(DEBUG_ATOMICS, "dequeued=%d, tail++=%d, %s", @@ -403,14 +406,19 @@ ssize_t SharedBufferClient::dequeue() status_t SharedBufferClient::undoDequeue(int buf) { + return cancel(buf); +} + +status_t SharedBufferClient::cancel(int buf) +{ RWLock::AutoRLock _rd(mLock); - // TODO: we can only undo the previous dequeue, we should - // enforce that in the api - UndoDequeueUpdate update(this); + // calculate the new position of the tail index (essentially tail--) + int localTail = (tail + mNumBuffers - 1) % mNumBuffers; + CancelUpdate update(this, localTail, buf); status_t err = updateCondition( update ); if (err == NO_ERROR) { - tail = undoDequeueTail; + tail = localTail; } return err; } diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp index c77d48e..ebb0cc9 100644 --- a/libs/surfaceflinger_client/Surface.cpp +++ b/libs/surfaceflinger_client/Surface.cpp @@ -416,6 +416,7 @@ void Surface::init() { ANativeWindow::setSwapInterval = setSwapInterval; ANativeWindow::dequeueBuffer = dequeueBuffer; + ANativeWindow::cancelBuffer = cancelBuffer; ANativeWindow::lockBuffer = lockBuffer; ANativeWindow::queueBuffer = queueBuffer; ANativeWindow::query = query; @@ -527,6 +528,12 @@ int Surface::dequeueBuffer(ANativeWindow* window, return self->dequeueBuffer(buffer); } +int Surface::cancelBuffer(ANativeWindow* window, + android_native_buffer_t* buffer) { + Surface* self = getSelf(window); + return self->cancelBuffer(buffer); +} + int Surface::lockBuffer(ANativeWindow* window, android_native_buffer_t* buffer) { Surface* self = getSelf(window); @@ -627,6 +634,33 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer) return err; } +int Surface::cancelBuffer(android_native_buffer_t* buffer) +{ + status_t err = validate(); + switch (err) { + case NO_ERROR: + // no error, common case + break; + case INVALID_OPERATION: + // legitimate errors here + return err; + default: + // other errors happen because the surface is now invalid, + // for instance because it has been destroyed. In this case, + // we just fail silently (canceling a buffer is not technically + // an error at this point) + return NO_ERROR; + } + + int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer)); + + err = mSharedBufferClient->cancel(bufIdx); + + LOGE_IF(err, "error canceling buffer %d (%s)", bufIdx, strerror(-err)); + return err; +} + + int Surface::lockBuffer(android_native_buffer_t* buffer) { status_t err = validate(); diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp index a6f5a1b..75b2294 100644 --- a/libs/ui/InputDispatcher.cpp +++ b/libs/ui/InputDispatcher.cpp @@ -134,18 +134,21 @@ static bool validateMotionEvent(int32_t action, size_t pointerCount, // --- InputWindow --- -bool InputWindow::visibleFrameIntersects(const InputWindow* other) const { - return visibleFrameRight > other->visibleFrameLeft - && visibleFrameLeft < other->visibleFrameRight - && visibleFrameBottom > other->visibleFrameTop - && visibleFrameTop < other->visibleFrameBottom; -} - bool InputWindow::touchableAreaContainsPoint(int32_t x, int32_t y) const { return x >= touchableAreaLeft && x <= touchableAreaRight && y >= touchableAreaTop && y <= touchableAreaBottom; } +bool InputWindow::frameContainsPoint(int32_t x, int32_t y) const { + return x >= frameLeft && x <= frameRight + && y >= frameTop && y <= frameBottom; +} + +bool InputWindow::isTrustedOverlay() const { + return layoutParamsType == TYPE_INPUT_METHOD + || layoutParamsType == TYPE_INPUT_METHOD_DIALOG; +} + // --- InputDispatcher --- @@ -1053,8 +1056,12 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, if (maskedAction == AMOTION_EVENT_ACTION_DOWN && (flags & InputWindow::FLAG_WATCH_OUTSIDE_TOUCH)) { - mTempTouchState.addOrUpdateWindow(window, - InputTarget::FLAG_OUTSIDE, BitSet32(0)); + int32_t outsideTargetFlags = InputTarget::FLAG_OUTSIDE; + if (isWindowObscuredAtPointLocked(window, x, y)) { + outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; + } + + mTempTouchState.addOrUpdateWindow(window, outsideTargetFlags, BitSet32(0)); } } } @@ -1083,10 +1090,6 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, // (May be NULL which is why we put this code block before the next check.) newTouchedWindow = mTempTouchState.getFirstForegroundWindow(); } - int32_t targetFlags = InputTarget::FLAG_FOREGROUND; - if (isSplit) { - targetFlags |= InputTarget::FLAG_SPLIT; - } // If we did not find a touched window then fail. if (! newTouchedWindow) { @@ -1106,6 +1109,15 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, goto Failed; } + // Set target flags. + int32_t targetFlags = InputTarget::FLAG_FOREGROUND; + if (isSplit) { + targetFlags |= InputTarget::FLAG_SPLIT; + } + if (isWindowObscuredAtPointLocked(newTouchedWindow, x, y)) { + targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; + } + // Update the temporary touch state. BitSet32 pointerIds; if (isSplit) { @@ -1186,23 +1198,13 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, for (size_t i = 0; i < mWindows.size(); i++) { const InputWindow* window = & mWindows[i]; if (window->layoutParamsType == InputWindow::TYPE_WALLPAPER) { - mTempTouchState.addOrUpdateWindow(window, 0, BitSet32(0)); + mTempTouchState.addOrUpdateWindow(window, + InputTarget::FLAG_WINDOW_IS_OBSCURED, BitSet32(0)); } } } } - // If a touched window has been obscured at any point during the touch gesture, set - // the appropriate flag so we remember it for the entire gesture. - for (size_t i = 0; i < mTempTouchState.windows.size(); i++) { - TouchedWindow& touchedWindow = mTempTouchState.windows.editItemAt(i); - if ((touchedWindow.targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) == 0) { - if (isWindowObscuredLocked(touchedWindow.window)) { - touchedWindow.targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; - } - } - } - // Success! Output targets. injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED; @@ -1326,14 +1328,15 @@ bool InputDispatcher::checkInjectionPermission(const InputWindow* window, return true; } -bool InputDispatcher::isWindowObscuredLocked(const InputWindow* window) { +bool InputDispatcher::isWindowObscuredAtPointLocked( + const InputWindow* window, int32_t x, int32_t y) const { size_t numWindows = mWindows.size(); for (size_t i = 0; i < numWindows; i++) { const InputWindow* other = & mWindows.itemAt(i); if (other == window) { break; } - if (other->visible && window->visibleFrameIntersects(other)) { + if (other->visible && ! other->isTrustedOverlay() && other->frameContainsPoint(x, y)) { return true; } } diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java index bc5f9fa..e5fa0f8 100644 --- a/media/java/android/media/MediaScanner.java +++ b/media/java/android/media/MediaScanner.java @@ -117,6 +117,10 @@ public class MediaScanner Files.FileColumns.DATE_MODIFIED, // 3 }; + private static final String[] ID_PROJECTION = new String[] { + Files.FileColumns._ID, + }; + private static final int FILES_PRESCAN_ID_COLUMN_INDEX = 0; private static final int FILES_PRESCAN_PATH_COLUMN_INDEX = 1; private static final int FILES_PRESCAN_FORMAT_COLUMN_INDEX = 2; @@ -933,6 +937,14 @@ public class MediaScanner c.close(); } } + + // compute original size of images + mOriginalCount = 0; + c = mMediaProvider.query(mImagesUri, ID_PROJECTION, null, null, null); + if (c != null) { + mOriginalCount = c.getCount(); + c.close(); + } } private boolean inScanDirectory(String path, String[] directories) { diff --git a/media/java/android/media/videoeditor/AudioTrack.java b/media/java/android/media/videoeditor/AudioTrack.java index 8da7eaa..076cc31 100755 --- a/media/java/android/media/videoeditor/AudioTrack.java +++ b/media/java/android/media/videoeditor/AudioTrack.java @@ -18,17 +18,12 @@ package android.media.videoeditor; import java.io.IOException;
-import android.util.Log;
-
/**
* This class allows to handle an audio track. This audio file is mixed with the
* audio samples of the MediaItems.
* {@hide}
*/
public class AudioTrack {
- // Logging
- private static final String TAG = "AudioTrack";
-
// Instance variables
private final String mUniqueId;
private final String mFilename;
@@ -53,129 +48,6 @@ public class AudioTrack { // The audio waveform filename
private String mAudioWaveformFilename;
- private PlaybackThread mPlaybackThread;
-
- /**
- * This listener interface is used by the AudioTrack to emit playback
- * progress notifications.
- */
- public interface PlaybackProgressListener {
- /**
- * This method notifies the listener of the current time position while
- * playing an audio track
- *
- * @param audioTrack The audio track
- * @param timeMs The current playback position (expressed in milliseconds
- * since the beginning of the audio track).
- * @param end true if the end of the audio track was reached
- */
- public void onProgress(AudioTrack audioTrack, long timeMs, boolean end);
- }
-
- /**
- * The playback thread
- */
- private class PlaybackThread extends Thread {
- // Instance variables
- private final PlaybackProgressListener mListener;
- private final long mFromMs, mToMs;
- private boolean mRun;
- private final boolean mLoop;
- private long mPositionMs;
-
- /**
- * Constructor
- *
- * @param fromMs The time (relative to the beginning of the audio track)
- * at which the playback will start
- * @param toMs The time (relative to the beginning of the audio track) at
- * which the playback will stop. Use -1 to play to the end of
- * the audio track
- * @param loop true if the playback should be looped once it reaches the
- * end
- * @param listener The listener which will be notified of the playback
- * progress
- */
- public PlaybackThread(long fromMs, long toMs, boolean loop,
- PlaybackProgressListener listener) {
- mPositionMs = mFromMs = fromMs;
- if (toMs < 0) {
- mToMs = mDurationMs;
- } else {
- mToMs = toMs;
- }
- mLoop = loop;
- mListener = listener;
- mRun = true;
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public void run() {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "===> PlaybackThread.run enter");
- }
-
- while (mRun) {
- try {
- sleep(100);
- } catch (InterruptedException ex) {
- break;
- }
-
- mPositionMs += 100;
-
- if (mPositionMs >= mToMs) {
- if (!mLoop) {
- if (mListener != null) {
- mListener.onProgress(AudioTrack.this, mPositionMs, true);
- }
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "PlaybackThread.run playback complete");
- }
- break;
- } else {
- // Fire a notification for the end of the clip
- if (mListener != null) {
- mListener.onProgress(AudioTrack.this, mToMs, false);
- }
-
- // Rewind
- mPositionMs = mFromMs;
- if (mListener != null) {
- mListener.onProgress(AudioTrack.this, mPositionMs, false);
- }
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "PlaybackThread.run playback complete");
- }
- }
- } else {
- if (mListener != null) {
- mListener.onProgress(AudioTrack.this, mPositionMs, false);
- }
- }
- }
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "===> PlaybackThread.run exit");
- }
- }
-
- /**
- * Stop the playback
- *
- * @return The stop position
- */
- public long stopPlayback() {
- mRun = false;
- try {
- join();
- } catch (InterruptedException ex) {
- }
- return mPositionMs;
- }
- };
/**
* An object of this type cannot be instantiated by using the default
@@ -183,11 +55,13 @@ public class AudioTrack { */
@SuppressWarnings("unused")
private AudioTrack() throws IOException {
- this(null, null);
+ this(null, null, null);
}
/**
* Constructor
+ *
+ * @param editor The video editor reference
* @param audioTrackId The audio track id
* @param filename The absolute file name
*
@@ -195,7 +69,8 @@ public class AudioTrack { * @throws IllegalArgumentException if file format is not supported or if
* the codec is not supported
*/
- public AudioTrack(String audioTrackId, String filename) throws IOException {
+ public AudioTrack(VideoEditor editor, String audioTrackId, String filename)
+ throws IOException {
mUniqueId = audioTrackId;
mFilename = filename;
mStartTimeMs = 0;
@@ -233,6 +108,7 @@ public class AudioTrack { /**
* Constructor
*
+ * @param editor The video editor reference
* @param audioTrackId The audio track id
* @param filename The audio filename
* @param startTimeMs the start time in milliseconds (relative to the
@@ -248,8 +124,9 @@ public class AudioTrack { *
* @throws IOException if file is not found
*/
- AudioTrack(String audioTrackId, String filename, long startTimeMs, long beginMs, long endMs,
- boolean loop, int volume, boolean muted, String audioWaveformFilename) throws IOException {
+ AudioTrack(VideoEditor editor, String audioTrackId, String filename, long startTimeMs,
+ long beginMs, long endMs, boolean loop, int volume, boolean muted,
+ String audioWaveformFilename) throws IOException {
mUniqueId = audioTrackId;
mFilename = filename;
mStartTimeMs = startTimeMs;
@@ -504,50 +381,6 @@ public class AudioTrack { }
/**
- * Start the playback of this audio track. This method does not block (does
- * not wait for the playback to complete).
- *
- * @param fromMs The time (relative to the beginning of the audio track) at
- * which the playback will start
- * @param toMs The time (relative to the beginning of the audio track) at
- * which the playback will stop. Use -1 to play to the end of the
- * audio track
- * @param loop true if the playback should be looped once it reaches the end
- * @param listener The listener which will be notified of the playback
- * progress
- * @throws IllegalArgumentException if fromMs or toMs is beyond the playback
- * duration
- * @throws IllegalStateException if a playback, preview or an export is
- * already in progress
- */
- public void startPlayback(long fromMs, long toMs, boolean loop,
- PlaybackProgressListener listener) {
- if (fromMs >= mDurationMs) {
- return;
- }
- mPlaybackThread = new PlaybackThread(fromMs, toMs, loop, listener);
- mPlaybackThread.start();
- }
-
- /**
- * Stop the audio track playback. This method blocks until the ongoing
- * playback is stopped.
- *
- * @return The accurate current time when stop is effective expressed in
- * milliseconds
- */
- public long stopPlayback() {
- final long stopTimeMs;
- if (mPlaybackThread != null) {
- stopTimeMs = mPlaybackThread.stopPlayback();
- mPlaybackThread = null;
- } else {
- stopTimeMs = 0;
- }
- return stopTimeMs;
- }
-
- /**
* This API allows to generate a file containing the sample volume levels of
* this audio track object. This function may take significant time and is
* blocking. The filename can be retrieved using getAudioWaveformFilename().
diff --git a/media/java/android/media/videoeditor/MediaImageItem.java b/media/java/android/media/videoeditor/MediaImageItem.java index ae4d359..df3c5fb 100755 --- a/media/java/android/media/videoeditor/MediaImageItem.java +++ b/media/java/android/media/videoeditor/MediaImageItem.java @@ -53,12 +53,13 @@ public class MediaImageItem extends MediaItem { */
@SuppressWarnings("unused")
private MediaImageItem() throws IOException {
- this(null, null, 0, RENDERING_MODE_BLACK_BORDER);
+ this(null, null, null, 0, RENDERING_MODE_BLACK_BORDER);
}
/**
* Constructor
*
+ * @param editor The video editor reference
* @param mediaItemId The media item id
* @param filename The image file name
* @param durationMs The duration of the image on the storyboard
@@ -66,9 +67,10 @@ public class MediaImageItem extends MediaItem { *
* @throws IOException
*/
- public MediaImageItem(String mediaItemId, String filename, long durationMs, int renderingMode)
+ public MediaImageItem(VideoEditor editor, String mediaItemId, String filename, long durationMs,
+ int renderingMode)
throws IOException {
- super(mediaItemId, filename, renderingMode);
+ super(editor, mediaItemId, filename, renderingMode);
// Determine the dimensions of the image
final BitmapFactory.Options dbo = new BitmapFactory.Options();
diff --git a/media/java/android/media/videoeditor/MediaItem.java b/media/java/android/media/videoeditor/MediaItem.java index b5561e9..d9c38af 100755 --- a/media/java/android/media/videoeditor/MediaItem.java +++ b/media/java/android/media/videoeditor/MediaItem.java @@ -70,6 +70,7 @@ public abstract class MediaItem { /**
* Constructor
*
+ * @param editor The video editor reference
* @param mediaItemId The MediaItem id
* @param filename name of the media file.
* @param renderingMode The rendering mode
@@ -79,7 +80,8 @@ public abstract class MediaItem { * supported the exception object contains the unsupported
* capability
*/
- protected MediaItem(String mediaItemId, String filename, int renderingMode) throws IOException {
+ protected MediaItem(VideoEditor editor, String mediaItemId, String filename,
+ int renderingMode) throws IOException {
mUniqueId = mediaItemId;
mFilename = filename;
mRenderingMode = renderingMode;
diff --git a/media/java/android/media/videoeditor/MediaVideoItem.java b/media/java/android/media/videoeditor/MediaVideoItem.java index 8ac5bdd..f71f4f4 100755 --- a/media/java/android/media/videoeditor/MediaVideoItem.java +++ b/media/java/android/media/videoeditor/MediaVideoItem.java @@ -19,7 +19,6 @@ package android.media.videoeditor; import java.io.IOException;
import android.graphics.Bitmap;
-import android.util.Log;
import android.view.SurfaceHolder;
/**
@@ -27,9 +26,6 @@ import android.view.SurfaceHolder; * {@hide}
*/
public class MediaVideoItem extends MediaItem {
- // Logging
- private static final String TAG = "MediaVideoItem";
-
// Instance variables
private final int mWidth;
private final int mHeight;
@@ -50,168 +46,35 @@ public class MediaVideoItem extends MediaItem { private int mVolumePercentage;
private boolean mMuted;
private String mAudioWaveformFilename;
- private PlaybackThread mPlaybackThread;
-
- /**
- * This listener interface is used by the MediaVideoItem to emit playback
- * progress notifications. This callback should be invoked after the
- * number of frames specified by
- * {@link #startPlayback(SurfaceHolder surfaceHolder, long fromMs,
- * int callbackAfterFrameCount, PlaybackProgressListener listener)}
- */
- public interface PlaybackProgressListener {
- /**
- * This method notifies the listener of the current time position while
- * playing a media item
- *
- * @param mediaItem The media item
- * @param timeMs The current playback position (expressed in milliseconds
- * since the beginning of the media item).
- * @param end true if the end of the media item was reached
- */
- public void onProgress(MediaVideoItem mediaItem, long timeMs, boolean end);
- }
-
- /**
- * The playback thread
- */
- private class PlaybackThread extends Thread {
- // Instance variables
- private final static long FRAME_DURATION = 33;
- private final PlaybackProgressListener mListener;
- private final int mCallbackAfterFrameCount;
- private final long mFromMs, mToMs;
- private boolean mRun;
- private final boolean mLoop;
- private long mPositionMs;
-
- /**
- * Constructor
- *
- * @param fromMs The time (relative to the beginning of the media item)
- * at which the playback will start
- * @param toMs The time (relative to the beginning of the media item) at
- * which the playback will stop. Use -1 to play to the end of
- * the media item
- * @param loop true if the playback should be looped once it reaches the
- * end
- * @param callbackAfterFrameCount The listener interface should be
- * invoked after the number of frames specified by this
- * parameter.
- * @param listener The listener which will be notified of the playback
- * progress
- */
- public PlaybackThread(long fromMs, long toMs, boolean loop, int callbackAfterFrameCount,
- PlaybackProgressListener listener) {
- mPositionMs = mFromMs = fromMs;
- if (toMs < 0) {
- mToMs = mDurationMs;
- } else {
- mToMs = toMs;
- }
- mLoop = loop;
- mCallbackAfterFrameCount = callbackAfterFrameCount;
- mListener = listener;
- mRun = true;
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public void run() {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "===> PlaybackThread.run enter");
- }
- int frameCount = 0;
- while (mRun) {
- try {
- sleep(FRAME_DURATION);
- } catch (InterruptedException ex) {
- break;
- }
- frameCount++;
- mPositionMs += FRAME_DURATION;
-
- if (mPositionMs >= mToMs) {
- if (!mLoop) {
- if (mListener != null) {
- mListener.onProgress(MediaVideoItem.this, mPositionMs, true);
- }
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "PlaybackThread.run playback complete");
- }
- break;
- } else {
- // Fire a notification for the end of the clip
- if (mListener != null) {
- mListener.onProgress(MediaVideoItem.this, mToMs, false);
- }
-
- // Rewind
- mPositionMs = mFromMs;
- if (mListener != null) {
- mListener.onProgress(MediaVideoItem.this, mPositionMs, false);
- }
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "PlaybackThread.run playback complete");
- }
- frameCount = 0;
- }
- } else {
- if (frameCount == mCallbackAfterFrameCount) {
- if (mListener != null) {
- mListener.onProgress(MediaVideoItem.this, mPositionMs, false);
- }
- frameCount = 0;
- }
- }
- }
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "===> PlaybackThread.run exit");
- }
- }
-
- /**
- * Stop the playback
- *
- * @return The stop position
- */
- public long stopPlayback() {
- mRun = false;
- try {
- join();
- } catch (InterruptedException ex) {
- }
- return mPositionMs;
- }
- };
/**
* An object of this type cannot be instantiated with a default constructor
*/
@SuppressWarnings("unused")
private MediaVideoItem() throws IOException {
- this(null, null, RENDERING_MODE_BLACK_BORDER);
+ this(null, null, null, RENDERING_MODE_BLACK_BORDER);
}
/**
* Constructor
*
+ * @param editor The video editor reference
* @param mediaItemId The MediaItem id
* @param filename The image file name
* @param renderingMode The rendering mode
*
* @throws IOException if the file cannot be opened for reading
*/
- public MediaVideoItem(String mediaItemId, String filename, int renderingMode)
+ public MediaVideoItem(VideoEditor editor, String mediaItemId, String filename,
+ int renderingMode)
throws IOException {
- this(mediaItemId, filename, renderingMode, 0, END_OF_FILE, 100, false, null);
+ this(editor, mediaItemId, filename, renderingMode, 0, END_OF_FILE, 100, false, null);
}
/**
* Constructor
*
+ * @param editor The video editor reference
* @param mediaItemId The MediaItem id
* @param filename The image file name
* @param renderingMode The rendering mode
@@ -226,10 +89,10 @@ public class MediaVideoItem extends MediaItem { *
* @throws IOException if the file cannot be opened for reading
*/
- MediaVideoItem(String mediaItemId, String filename, int renderingMode,
+ MediaVideoItem(VideoEditor editor, String mediaItemId, String filename, int renderingMode,
long beginMs, long endMs, int volumePercent, boolean muted,
String audioWaveformFilename) throws IOException {
- super(mediaItemId, filename, renderingMode);
+ super(editor, mediaItemId, filename, renderingMode);
// TODO: Set these variables correctly
mWidth = 1080;
mHeight = 720;
@@ -405,57 +268,6 @@ public class MediaVideoItem extends MediaItem { }
/**
- * Start the playback of this media item. This method does not block (does
- * not wait for the playback to complete). The PlaybackProgressListener
- * allows to track the progress at the time interval determined by the
- * callbackAfterFrameCount parameter. The SurfaceHolder has to be created
- * and ready for use before calling this method.
- *
- * @param surfaceHolder SurfaceHolder where the frames are rendered.
- * @param fromMs The time (relative to the beginning of the media item) at
- * which the playback will start
- * @param toMs The time (relative to the beginning of the media item) at
- * which the playback will stop. Use -1 to play to the end of the
- * media item
- * @param loop true if the playback should be looped once it reaches the end
- * @param callbackAfterFrameCount The listener interface should be invoked
- * after the number of frames specified by this parameter.
- * @param listener The listener which will be notified of the playback
- * progress
- * @throws IllegalArgumentException if fromMs or toMs is beyond the playback
- * duration
- * @throws IllegalStateException if a playback, preview or an export is
- * already in progress
- */
- public void startPlayback(SurfaceHolder surfaceHolder, long fromMs, long toMs, boolean loop,
- int callbackAfterFrameCount, PlaybackProgressListener listener) {
- if (fromMs >= mDurationMs) {
- return;
- }
- mPlaybackThread = new PlaybackThread(fromMs, toMs, loop, callbackAfterFrameCount,
- listener);
- mPlaybackThread.start();
- }
-
- /**
- * Stop the media item playback. This method blocks until the ongoing
- * playback is stopped.
- *
- * @return The accurate current time when stop is effective expressed in
- * milliseconds
- */
- public long stopPlayback() {
- final long stopTimeMs;
- if (mPlaybackThread != null) {
- stopTimeMs = mPlaybackThread.stopPlayback();
- mPlaybackThread = null;
- } else {
- stopTimeMs = 0;
- }
- return stopTimeMs;
- }
-
- /**
* This API allows to generate a file containing the sample volume levels of
* the Audio track of this media item. This function may take significant
* time and is blocking. The file can be retrieved using
diff --git a/media/java/android/media/videoeditor/VideoEditorTestImpl.java b/media/java/android/media/videoeditor/VideoEditorTestImpl.java index b39d9d8..c3cb82a 100644 --- a/media/java/android/media/videoeditor/VideoEditorTestImpl.java +++ b/media/java/android/media/videoeditor/VideoEditorTestImpl.java @@ -765,7 +765,7 @@ public class VideoEditorTestImpl implements VideoEditor { if (MediaImageItem.class.getSimpleName().equals(type)) { final long durationMs = Long.parseLong(parser.getAttributeValue("", ATTR_DURATION)); - currentMediaItem = new MediaImageItem(mediaItemId, filename, + currentMediaItem = new MediaImageItem(this, mediaItemId, filename, durationMs, renderingMode); } else if (MediaVideoItem.class.getSimpleName().equals(type)) { final long beginMs = Long.parseLong(parser.getAttributeValue("", @@ -778,7 +778,7 @@ public class VideoEditorTestImpl implements VideoEditor { ATTR_MUTED)); final String audioWaveformFilename = parser.getAttributeValue("", ATTR_AUDIO_WAVEFORM_FILENAME); - currentMediaItem = new MediaVideoItem(mediaItemId, filename, + currentMediaItem = new MediaVideoItem(this, mediaItemId, filename, renderingMode, beginMs, endMs, volume, muted, audioWaveformFilename); @@ -1017,7 +1017,7 @@ public class VideoEditorTestImpl implements VideoEditor { final boolean loop = Boolean.parseBoolean(parser.getAttributeValue("", ATTR_LOOP)); final String waveformFilename = parser.getAttributeValue("", ATTR_AUDIO_WAVEFORM_FILENAME); try { - final AudioTrack audioTrack = new AudioTrack(audioTrackId, filename, startTimeMs, + final AudioTrack audioTrack = new AudioTrack(this, audioTrackId, filename, startTimeMs, beginMs, endMs, loop, volume, muted, waveformFilename); return audioTrack; diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp index b314114..5ff934d 100644 --- a/media/libstagefright/AudioPlayer.cpp +++ b/media/libstagefright/AudioPlayer.cpp @@ -55,7 +55,7 @@ AudioPlayer::AudioPlayer( AudioPlayer::~AudioPlayer() { if (mStarted) { - stop(); + reset(); } } @@ -165,13 +165,21 @@ status_t AudioPlayer::start(bool sourceAlreadyStarted) { return OK; } -void AudioPlayer::pause() { +void AudioPlayer::pause(bool playPendingSamples) { CHECK(mStarted); - if (mAudioSink.get() != NULL) { - mAudioSink->pause(); + if (playPendingSamples) { + if (mAudioSink.get() != NULL) { + mAudioSink->stop(); + } else { + mAudioTrack->stop(); + } } else { - mAudioTrack->stop(); + if (mAudioSink.get() != NULL) { + mAudioSink->pause(); + } else { + mAudioTrack->pause(); + } } } @@ -185,7 +193,7 @@ void AudioPlayer::resume() { } } -void AudioPlayer::stop() { +void AudioPlayer::reset() { CHECK(mStarted); if (mAudioSink.get() != NULL) { diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index 31c03ad..4f5ff75 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -579,7 +579,7 @@ void AwesomePlayer::onStreamDone() { notifyListener_l( MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus); - pause_l(); + pause_l(true /* at eos */); mFlags |= AT_EOS; return; @@ -603,7 +603,7 @@ void AwesomePlayer::onStreamDone() { LOGV("MEDIA_PLAYBACK_COMPLETE"); notifyListener_l(MEDIA_PLAYBACK_COMPLETE); - pause_l(); + pause_l(true /* at eos */); mFlags |= AT_EOS; } @@ -752,7 +752,7 @@ status_t AwesomePlayer::pause() { return pause_l(); } -status_t AwesomePlayer::pause_l() { +status_t AwesomePlayer::pause_l(bool at_eos) { if (!(mFlags & PLAYING)) { return OK; } @@ -760,7 +760,14 @@ status_t AwesomePlayer::pause_l() { cancelPlayerEvents(true /* keepBufferingGoing */); if (mAudioPlayer != NULL) { - mAudioPlayer->pause(); + if (at_eos) { + // If we played the audio stream to completion we + // want to make sure that all samples remaining in the audio + // track's queue are played out. + mAudioPlayer->pause(true /* playPendingSamples */); + } else { + mAudioPlayer->pause(); + } } mFlags &= ~PLAYING; diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index 90b1aab..6d00d7c 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -212,6 +212,7 @@ MPEG4Writer::MPEG4Writer(const char *filename) : mFile(fopen(filename, "wb")), mUse4ByteNalLength(true), mUse32BitOffset(true), + mIsFileSizeLimitExplicitlyRequested(false), mPaused(false), mStarted(false), mOffset(0), @@ -225,6 +226,7 @@ MPEG4Writer::MPEG4Writer(int fd) : mFile(fdopen(fd, "wb")), mUse4ByteNalLength(true), mUse32BitOffset(true), + mIsFileSizeLimitExplicitlyRequested(false), mPaused(false), mStarted(false), mOffset(0), @@ -322,7 +324,7 @@ int64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) { static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000); int64_t size = MIN_MOOV_BOX_SIZE; - if (mMaxFileSizeLimitBytes != 0) { + if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) { size = mMaxFileSizeLimitBytes * 4 / 1000; } else if (mMaxFileDurationLimitUs != 0) { if (bitRate <= 0) { @@ -342,7 +344,7 @@ int64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) { size = MAX_MOOV_BOX_SIZE; } - LOGV("limits: %lld/%lld bytes/us, bit rate: %d bps and the estimated" + LOGI("limits: %lld/%lld bytes/us, bit rate: %d bps and the estimated" " moov size %lld bytes", mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size); return factor * size; @@ -353,6 +355,16 @@ status_t MPEG4Writer::start(MetaData *param) { return UNKNOWN_ERROR; } + /* + * Check mMaxFileSizeLimitBytes at the beginning + * since mMaxFileSizeLimitBytes may be implicitly + * changed later for 32-bit file offset even if + * user does not ask to set it explicitly. + */ + if (mMaxFileSizeLimitBytes != 0) { + mIsFileSizeLimitExplicitlyRequested = true; + } + int32_t use64BitOffset; if (param && param->findInt32(kKey64BitFileOffset, &use64BitOffset) && diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 4d69dd3..a5341e3 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -1838,8 +1838,31 @@ void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) { case OMX_EventPortSettingsChanged: { + CODEC_LOGV("OMX_EventPortSettingsChanged(port=%ld, data2=0x%08lx)", + data1, data2); + if (data2 == 0 || data2 == OMX_IndexParamPortDefinition) { onPortSettingsChanged(data1); + } else if (data1 == kPortIndexOutput + && data2 == OMX_IndexConfigCommonOutputCrop) { + + OMX_CONFIG_RECTTYPE rect; + rect.nPortIndex = kPortIndexOutput; + InitOMXParams(&rect); + + status_t err = + mOMX->getConfig( + mNode, OMX_IndexConfigCommonOutputCrop, + &rect, sizeof(rect)); + + if (err == OK) { + CODEC_LOGV( + "output crop (%ld, %ld, %ld, %ld)", + rect.nLeft, rect.nTop, rect.nWidth, rect.nHeight); + } else { + CODEC_LOGE("getConfig(OMX_IndexConfigCommonOutputCrop) " + "returned error 0x%08x", err); + } } break; } diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp index c204a94..662a84a 100644 --- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp +++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp @@ -48,6 +48,9 @@ SoftwareRenderer::SoftwareRenderer( LOGI("display = %d x %d, decoded = %d x %d", mDisplayWidth, mDisplayHeight, mDecodedWidth, mDecodedHeight); + mDecodedWidth = mDisplayWidth; + mDecodedHeight = mDisplayHeight; + int halFormat; switch (mColorFormat) { #if HAS_YCBCR420_SP_ADRENO diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h index db98253..e04a24d 100644 --- a/media/libstagefright/include/AwesomePlayer.h +++ b/media/libstagefright/include/AwesomePlayer.h @@ -223,7 +223,7 @@ private: status_t setDataSource_l(const sp<MediaExtractor> &extractor); void reset_l(); status_t seekTo_l(int64_t timeUs); - status_t pause_l(); + status_t pause_l(bool at_eos = false); void initRenderer_l(); void notifyVideoSize_l(); void seekAudioIfNecessary_l(); diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java index e442c85..3908d71 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java @@ -23,10 +23,13 @@ import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.Writer; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; import android.hardware.Camera; import android.media.MediaPlayer; import android.media.MediaRecorder; +import android.os.Handler; import android.os.Looper; import android.test.ActivityInstrumentationTestCase2; import android.test.suitebuilder.annotation.LargeTest; @@ -51,105 +54,90 @@ public class MediaRecorderStressTest extends ActivityInstrumentationTestCase2<Me private static final int NUMBER_OF_SWTICHING_LOOPS_BW_CAMERA_AND_RECORDER = 200; private static final long WAIT_TIME_CAMERA_TEST = 3000; // 3 second private static final long WAIT_TIME_RECORDER_TEST = 6000; // 6 second - private static final long WAIT_TIME_RECORD = 10000; // 10 seconds - private static final long WAIT_TIME_PLAYBACK = 6000; // 6 second private static final String OUTPUT_FILE = "/sdcard/temp"; private static final String OUTPUT_FILE_EXT = ".3gp"; private static final String MEDIA_STRESS_OUTPUT = "/sdcard/mediaStressOutput.txt"; - private Looper mCameraLooper = null; - private Looper mRecorderLooper = null; - private final Object lock = new Object(); - private final Object recorderlock = new Object(); - private static int WAIT_FOR_COMMAND_TO_COMPLETE = 10000; // Milliseconds. private final CameraErrorCallback mCameraErrorCallback = new CameraErrorCallback(); private final RecorderErrorCallback mRecorderErrorCallback = new RecorderErrorCallback(); + private final static int WAIT_TIMEOUT = 10000; + private Thread mLooperThread; + private Handler mHandler; + public MediaRecorderStressTest() { super("com.android.mediaframeworktest", MediaFrameworkTest.class); } protected void setUp() throws Exception { + final Semaphore sem = new Semaphore(0); + mLooperThread = new Thread() { + @Override + public void run() { + Log.v(TAG, "starting looper"); + Looper.prepare(); + mHandler = new Handler(); + sem.release(); + Looper.loop(); + Log.v(TAG, "quit looper"); + } + }; + mLooperThread.start(); + if (! sem.tryAcquire(WAIT_TIMEOUT, TimeUnit.MILLISECONDS)) { + fail("Failed to start the looper."); + } + getActivity(); - super.setUp(); + super.setUp(); } - private final class CameraErrorCallback implements android.hardware.Camera.ErrorCallback { - public void onError(int error, android.hardware.Camera camera) { - if (error == android.hardware.Camera.CAMERA_ERROR_SERVER_DIED) { - assertTrue("Camera test mediaserver died", false); + @Override + protected void tearDown() throws Exception { + if (mHandler != null) { + mHandler.getLooper().quit(); + mHandler = null; + } + if (mLooperThread != null) { + mLooperThread.join(WAIT_TIMEOUT); + if (mLooperThread.isAlive()) { + fail("Failed to stop the looper."); } + mLooperThread = null; } - } - private final class RecorderErrorCallback implements MediaRecorder.OnErrorListener { - public void onError(MediaRecorder mr, int what, int extra) { - // fail the test case no matter what error come up - assertTrue("mediaRecorder error", false); - } + super.tearDown(); } - private void initializeCameraMessageLooper() { - Log.v(TAG, "start looper"); - new Thread() { + private void runOnLooper(final Runnable command) throws InterruptedException { + final Semaphore sem = new Semaphore(0); + mHandler.post(new Runnable() { @Override public void run() { - // Set up a looper to be used by camera. - Looper.prepare(); - Log.v(TAG, "start loopRun"); - mCameraLooper = Looper.myLooper(); - mCamera = Camera.open(); - synchronized (lock) { - lock.notify(); + try { + command.run(); + } finally { + sem.release(); } - Looper.loop(); - Log.v(TAG, "initializeMessageLooper: quit."); } - }.start(); + }); + if (! sem.tryAcquire(WAIT_TIMEOUT, TimeUnit.MILLISECONDS)) { + fail("Failed to run the command on the looper."); + } } - private void initializeRecorderMessageLooper() { - Log.v(TAG, "start looper"); - new Thread() { - @Override - public void run() { - Looper.prepare(); - Log.v(TAG, "start loopRun"); - mRecorderLooper = Looper.myLooper(); - mRecorder = new MediaRecorder(); - synchronized (recorderlock) { - recorderlock.notify(); - } - Looper.loop(); // Blocks forever until Looper.quit() is called. - Log.v(TAG, "initializeMessageLooper: quit."); + private final class CameraErrorCallback implements android.hardware.Camera.ErrorCallback { + public void onError(int error, android.hardware.Camera camera) { + if (error == android.hardware.Camera.CAMERA_ERROR_SERVER_DIED) { + assertTrue("Camera test mediaserver died", false); } - }.start(); - } - - /* - * Terminates the message looper thread. - */ - private void terminateCameraMessageLooper() { - mCameraLooper.quit(); - try { - Thread.sleep(1000); - } catch (Exception e){ - Log.v(TAG, e.toString()); } - mCamera.release(); } - /* - * Terminates the message looper thread. - */ - private void terminateRecorderMessageLooper() { - mRecorderLooper.quit(); - try { - Thread.sleep(1000); - } catch (Exception e){ - Log.v(TAG, e.toString()); + private final class RecorderErrorCallback implements MediaRecorder.OnErrorListener { + public void onError(MediaRecorder mr, int what, int extra) { + // fail the test case no matter what error come up + assertTrue("mediaRecorder error", false); } - mRecorder.release(); } //Test case for stressing the camera preview. @@ -166,21 +154,19 @@ public class MediaRecorderStressTest extends ActivityInstrumentationTestCase2<Me Log.v(TAG, "Start preview"); output.write("No of loop: "); - for (int i = 0; i< NUMBER_OF_CAMERA_STRESS_LOOPS; i++){ - synchronized (lock) { - initializeCameraMessageLooper(); - try { - lock.wait(WAIT_FOR_COMMAND_TO_COMPLETE); - } catch(Exception e) { - Log.v(TAG, "wait was interrupted."); + for (int i = 0; i< NUMBER_OF_CAMERA_STRESS_LOOPS; i++) { + runOnLooper(new Runnable() { + @Override + public void run() { + mCamera = Camera.open(); } - } + }); mCamera.setErrorCallback(mCameraErrorCallback); mCamera.setPreviewDisplay(mSurfaceHolder); mCamera.startPreview(); Thread.sleep(WAIT_TIME_CAMERA_TEST); mCamera.stopPreview(); - terminateCameraMessageLooper(); + mCamera.release(); output.write(" ," + i); } } catch (Exception e) { @@ -205,15 +191,13 @@ public class MediaRecorderStressTest extends ActivityInstrumentationTestCase2<Me try { output.write("No of loop: "); Log.v(TAG, "Start preview"); - for (int i = 0; i < NUMBER_OF_RECORDER_STRESS_LOOPS; i++){ - synchronized (recorderlock) { - initializeRecorderMessageLooper(); - try { - recorderlock.wait(WAIT_FOR_COMMAND_TO_COMPLETE); - } catch(Exception e) { - Log.v(TAG, "wait was interrupted."); + for (int i = 0; i < NUMBER_OF_RECORDER_STRESS_LOOPS; i++) { + runOnLooper(new Runnable() { + @Override + public void run() { + mRecorder = new MediaRecorder(); } - } + }); Log.v(TAG, "counter = " + i); filename = OUTPUT_FILE + i + OUTPUT_FILE_EXT; Log.v(TAG, filename); @@ -233,7 +217,7 @@ public class MediaRecorderStressTest extends ActivityInstrumentationTestCase2<Me Log.v(TAG, "before release"); Thread.sleep(WAIT_TIME_RECORDER_TEST); mRecorder.reset(); - terminateRecorderMessageLooper(); + mRecorder.release(); output.write(", " + i); } } catch (Exception e) { @@ -258,33 +242,29 @@ public class MediaRecorderStressTest extends ActivityInstrumentationTestCase2<Me try { Log.v(TAG, "Start preview"); output.write("No of loop: "); - for (int i = 0; i < NUMBER_OF_SWTICHING_LOOPS_BW_CAMERA_AND_RECORDER; i++){ - synchronized (lock) { - initializeCameraMessageLooper(); - try { - lock.wait(WAIT_FOR_COMMAND_TO_COMPLETE); - } catch(Exception e) { - Log.v(TAG, "wait was interrupted."); + for (int i = 0; i < NUMBER_OF_SWTICHING_LOOPS_BW_CAMERA_AND_RECORDER; i++) { + runOnLooper(new Runnable() { + @Override + public void run() { + mCamera = Camera.open(); } - } + }); mCamera.setErrorCallback(mCameraErrorCallback); mCamera.setPreviewDisplay(mSurfaceHolder); mCamera.startPreview(); Thread.sleep(WAIT_TIME_CAMERA_TEST); mCamera.stopPreview(); - terminateCameraMessageLooper(); + mCamera.release(); mCamera = null; Log.v(TAG, "release camera"); filename = OUTPUT_FILE + i + OUTPUT_FILE_EXT; Log.v(TAG, filename); - synchronized (recorderlock) { - initializeRecorderMessageLooper(); - try { - recorderlock.wait(WAIT_FOR_COMMAND_TO_COMPLETE); - } catch(Exception e) { - Log.v(TAG, "wait was interrupted."); + runOnLooper(new Runnable() { + @Override + public void run() { + mRecorder = new MediaRecorder(); } - } + }); mRecorder.setOnErrorListener(mRecorderErrorCallback); mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); @@ -299,7 +279,7 @@ public class MediaRecorderStressTest extends ActivityInstrumentationTestCase2<Me mRecorder.prepare(); Log.v(TAG, "before release"); Thread.sleep(WAIT_TIME_CAMERA_TEST); - terminateRecorderMessageLooper(); + mRecorder.release(); Log.v(TAG, "release video recorder"); output.write(", " + i); } @@ -358,14 +338,12 @@ public class MediaRecorderStressTest extends ActivityInstrumentationTestCase2<Me for (int i = 0; i < iterations; i++){ filename = OUTPUT_FILE + i + OUTPUT_FILE_EXT; Log.v(TAG, filename); - synchronized (recorderlock) { - initializeRecorderMessageLooper(); - try { - recorderlock.wait(WAIT_FOR_COMMAND_TO_COMPLETE); - } catch(Exception e) { - Log.v(TAG, "wait was interrupted."); + runOnLooper(new Runnable() { + @Override + public void run() { + mRecorder = new MediaRecorder(); } - } + }); Log.v(TAG, "iterations : " + iterations); Log.v(TAG, "video_encoder : " + video_encoder); Log.v(TAG, "audio_encoder : " + audio_encoder); @@ -391,7 +369,7 @@ public class MediaRecorderStressTest extends ActivityInstrumentationTestCase2<Me Thread.sleep(record_duration); Log.v(TAG, "Before stop"); mRecorder.stop(); - terminateRecorderMessageLooper(); + mRecorder.release(); //start the playback MediaPlayer mp = new MediaPlayer(); mp.setDataSource(filename); diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp index 460b74f..239dc05 100644 --- a/opengl/libagl/egl.cpp +++ b/opengl/libagl/egl.cpp @@ -1969,7 +1969,7 @@ EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) if (egl_display_t::is_valid(dpy) == EGL_FALSE) return setError(EGL_BAD_DISPLAY, EGL_FALSE); // TODO: eglSwapInterval() - return setError(EGL_BAD_PARAMETER, EGL_FALSE); + return EGL_TRUE; } // ---------------------------------------------------------------------------- diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index c25df1d..24c9443 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -1504,7 +1504,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { sendCloseSystemWindows(); Intent intent = new Intent(Intent.ACTION_CALL_BUTTON); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - getContext().startActivity(intent); + try { + getContext().startActivity(intent); + } catch (ActivityNotFoundException e) { + Log.w(TAG, "No activity found for android.intent.action.CALL_BUTTON."); + } } @Override diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 8527059..cd9b07e 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -1715,7 +1715,7 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track // The first time a track is added we wait // for all its buffers to be filled before processing it mAudioMixer->setActiveTrack(track->name()); - if (cblk->framesReady() && (track->isReady() || track->isStopped()) && + if (cblk->framesReady() && track->isReady() && !track->isPaused() && !track->isTerminated()) { //LOGV("track %d u=%08x, s=%08x [OK] on thread %p", track->name(), cblk->user, cblk->server, this); @@ -2231,7 +2231,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop() // The first time a track is added we wait // for all its buffers to be filled before processing it - if (cblk->framesReady() && (track->isReady() || track->isStopped()) && + if (cblk->framesReady() && track->isReady() && !track->isPaused() && !track->isTerminated()) { //LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server); @@ -3039,7 +3039,7 @@ getNextBuffer_exit: } bool AudioFlinger::PlaybackThread::Track::isReady() const { - if (mFillingUpStatus != FS_FILLING) return true; + if (mFillingUpStatus != FS_FILLING || isStopped() || isPausing()) return true; if (mCblk->framesReady() >= mCblk->frameCount || (mCblk->flags & CBLK_FORCEREADY_MSK)) { diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java index e6c32d9..a8ccfc0 100644 --- a/services/java/com/android/server/BatteryService.java +++ b/services/java/com/android/server/BatteryService.java @@ -99,6 +99,7 @@ class BatteryService extends Binder { private int mBatteryTemperature; private String mBatteryTechnology; private boolean mBatteryLevelCritical; + private boolean mInvalidCharger; private int mLastBatteryStatus; private int mLastBatteryHealth; @@ -107,6 +108,7 @@ class BatteryService extends Binder { private int mLastBatteryVoltage; private int mLastBatteryTemperature; private boolean mLastBatteryLevelCritical; + private boolean mLastInvalidCharger; private int mLowBatteryWarningLevel; private int mLowBatteryCloseWarningLevel; @@ -128,7 +130,12 @@ class BatteryService extends Binder { mLowBatteryCloseWarningLevel = mContext.getResources().getInteger( com.android.internal.R.integer.config_lowBatteryCloseWarningLevel); - mUEventObserver.startObserving("SUBSYSTEM=power_supply"); + mPowerSupplyObserver.startObserving("SUBSYSTEM=power_supply"); + + // watch for invalid charger messages if the invalid_charger switch exists + if (new File("/sys/devices/virtual/switch/invalid_charger/state").exists()) { + mInvalidChargerObserver.startObserving("DEVPATH=/devices/virtual/switch/invalid_charger"); + } // set initial status update(); @@ -162,13 +169,24 @@ class BatteryService extends Binder { return mPlugType; } - private UEventObserver mUEventObserver = new UEventObserver() { + private UEventObserver mPowerSupplyObserver = new UEventObserver() { @Override public void onUEvent(UEventObserver.UEvent event) { update(); } }; + private UEventObserver mInvalidChargerObserver = new UEventObserver() { + @Override + public void onUEvent(UEventObserver.UEvent event) { + boolean invalidCharger = "1".equals(event.get("SWITCH_STATE")); + if (mInvalidCharger != invalidCharger) { + mInvalidCharger = invalidCharger; + update(); + } + } + }; + // returns battery level as a percentage final int getBatteryLevel() { return mBatteryLevel; @@ -237,7 +255,8 @@ class BatteryService extends Binder { mBatteryLevel != mLastBatteryLevel || mPlugType != mLastPlugType || mBatteryVoltage != mLastBatteryVoltage || - mBatteryTemperature != mLastBatteryTemperature) { + mBatteryTemperature != mLastBatteryTemperature || + mInvalidCharger != mLastInvalidCharger) { if (mPlugType != mLastPlugType) { if (mLastPlugType == BATTERY_PLUGGED_NONE) { @@ -334,6 +353,7 @@ class BatteryService extends Binder { mLastBatteryVoltage = mBatteryVoltage; mLastBatteryTemperature = mBatteryTemperature; mLastBatteryLevelCritical = mBatteryLevelCritical; + mLastInvalidCharger = mInvalidCharger; } } @@ -355,6 +375,7 @@ class BatteryService extends Binder { intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mBatteryVoltage); intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mBatteryTemperature); intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mBatteryTechnology); + intent.putExtra(BatteryManager.EXTRA_INVALID_CHARGER, mInvalidCharger); if (false) { Slog.d(TAG, "updateBattery level:" + mBatteryLevel + @@ -364,7 +385,7 @@ class BatteryService extends Binder { " temperature: " + mBatteryTemperature + " technology: " + mBatteryTechnology + " AC powered:" + mAcOnline + " USB powered:" + mUsbOnline + - " icon:" + icon ); + " icon:" + icon + " invalid charger:" + mInvalidCharger); } ActivityManagerNative.broadcastStickyIntent(intent, null); diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index 9a5423c..dc4194c 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -25,6 +25,7 @@ import com.android.internal.view.IInputMethodClient; import com.android.internal.view.IInputMethodManager; import com.android.internal.view.IInputMethodSession; import com.android.internal.view.InputBindResult; +import com.android.internal.view.InputMethodAndSubtypeEnabler; import com.android.server.StatusBarManagerService; @@ -97,6 +98,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub static final int MSG_SHOW_IM_PICKER = 1; static final int MSG_SHOW_IM_SUBTYPE_PICKER = 2; + static final int MSG_SHOW_IM_SUBTYPE_ENABLER = 3; static final int MSG_UNBIND_INPUT = 1000; static final int MSG_BIND_INPUT = 1010; @@ -1225,7 +1227,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub synchronized (mMethodMap) { if (mCurClient == null || client == null || mCurClient.client.asBinder() != client.asBinder()) { - Slog.w(TAG, "Ignoring showInputMethodDialogFromClient of uid " + Slog.w(TAG, "Ignoring showInputMethodPickerFromClient of uid " + Binder.getCallingUid() + ": " + client); } @@ -1237,13 +1239,26 @@ public class InputMethodManagerService extends IInputMethodManager.Stub synchronized (mMethodMap) { if (mCurClient == null || client == null || mCurClient.client.asBinder() != client.asBinder()) { - Slog.w(TAG, "Ignoring showInputSubtypeMethodDialogFromClient of: " + client); + Slog.w(TAG, "Ignoring showInputMethodSubtypePickerFromClient of: " + client); } mHandler.sendEmptyMessage(MSG_SHOW_IM_SUBTYPE_PICKER); } } + public void showInputMethodAndSubtypeEnablerFromClient( + IInputMethodClient client, String topId) { + // TODO: Handle topId for setting the top position of the list activity + synchronized (mMethodMap) { + if (mCurClient == null || client == null + || mCurClient.client.asBinder() != client.asBinder()) { + Slog.w(TAG, "Ignoring showInputMethodAndSubtypeEnablerFromClient of: " + client); + } + + mHandler.sendEmptyMessage(MSG_SHOW_IM_SUBTYPE_ENABLER); + } + } + public void setInputMethod(IBinder token, String id) { setInputMethodWithSubtype(token, id, NOT_A_SUBTYPE_ID); } @@ -1336,6 +1351,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub showInputMethodSubtypeMenu(); return true; + case MSG_SHOW_IM_SUBTYPE_ENABLER: + showInputMethodAndSubtypeEnabler(); + return true; + // --------------------------------------------------------- case MSG_UNBIND_INPUT: @@ -1528,6 +1547,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub showInputMethodMenuInternal(true); } + private void showInputMethodAndSubtypeEnabler() { + Intent intent = new Intent(); + intent.setClassName("android", InputMethodAndSubtypeEnabler.class.getCanonicalName()); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + mContext.startActivity(intent); + } + private void showInputMethodMenuInternal(boolean showSubtypes) { if (DEBUG) Slog.v(TAG, "Show switching menu"); diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index c4d2d4d..bcf1b96 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -140,7 +140,6 @@ class PackageManagerService extends IPackageManager.Stub { private static final boolean DEBUG_PREFERRED = false; private static final boolean DEBUG_UPGRADE = false; private static final boolean DEBUG_INSTALL = false; - private static final boolean DEBUG_NATIVE = false; private static final boolean MULTIPLE_APPLICATION_UIDS = true; private static final int RADIO_UID = Process.PHONE_UID; @@ -3241,8 +3240,6 @@ class PackageManagerService extends IPackageManager.Stub { } } - pkg.applicationInfo.nativeLibraryDir = pkgSetting.nativeLibraryPathString; - /* * Set the data dir to the default "/data/data/<package name>/lib" * if we got here without anyone telling us different (e.g., apps @@ -3252,10 +3249,14 @@ class PackageManagerService extends IPackageManager.Stub { * This happens during an upgrade from a package settings file that * doesn't have a native library path attribute at all. */ - if (pkgSetting.nativeLibraryPathString == null && pkg.applicationInfo.dataDir != null) { - final String nativeLibraryPath = new File(dataPath, LIB_DIR_NAME).getPath(); - pkg.applicationInfo.nativeLibraryDir = nativeLibraryPath; - pkgSetting.nativeLibraryPathString = nativeLibraryPath; + if (pkg.applicationInfo.nativeLibraryDir == null && pkg.applicationInfo.dataDir != null) { + if (pkgSetting.nativeLibraryPathString == null) { + final String nativeLibraryPath = new File(dataPath, LIB_DIR_NAME).getPath(); + pkg.applicationInfo.nativeLibraryDir = nativeLibraryPath; + pkgSetting.nativeLibraryPathString = nativeLibraryPath; + } else { + pkg.applicationInfo.nativeLibraryDir = pkgSetting.nativeLibraryPathString; + } } pkgSetting.uidError = uidError; @@ -3274,10 +3275,23 @@ class PackageManagerService extends IPackageManager.Stub { * In other words, we're going to unpack the binaries * only for non-system apps and system app upgrades. */ - if ((!isSystemApp(pkg) || isUpdatedSystemApp(pkg)) && !isExternal(pkg)) { - Log.i(TAG, path + " changed; unpacking"); - File sharedLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir); - NativeLibraryHelper.copyNativeBinariesLI(scanFile, sharedLibraryDir); + if (pkg.applicationInfo.nativeLibraryDir != null) { + final File sharedLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir); + if (isSystemApp(pkg) && !isUpdatedSystemApp(pkg)) { + /* + * Upgrading from a previous version of the OS sometimes + * leaves native libraries in the /data/data/<app>/lib + * directory for system apps even when they shouldn't be. + * Recent changes in the JNI library search path + * necessitates we remove those to match previous behavior. + */ + if (NativeLibraryHelper.removeNativeBinariesFromDirLI(sharedLibraryDir)) { + Log.i(TAG, "removed obsolete native libraries for system package " + path); + } + } else if (!isExternal(pkg)) { + Log.i(TAG, path + " changed; unpacking"); + NativeLibraryHelper.copyNativeBinariesLI(scanFile, sharedLibraryDir); + } } pkg.mScanPath = path; @@ -8051,7 +8065,7 @@ class PackageManagerService extends IPackageManager.Stub { if (p != null) { if (!p.codePath.equals(codePath)) { // Check to see if its a disabled system app - if((p != null) && ((p.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0)) { + if ((p.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) { // This is an updated system app with versions in both system // and data partition. Just let the most recent version // take precedence. @@ -8062,6 +8076,13 @@ class PackageManagerService extends IPackageManager.Stub { // let's log a message about it. Slog.i(TAG, "Package " + name + " codePath changed from " + p.codePath + " to " + codePath + "; Retaining data and using new"); + /* + * Since we've changed paths, we need to prefer the new + * native library path over the one stored in the + * package settings since we might have moved from + * internal to external storage or vice versa. + */ + p.nativeLibraryPathString = nativeLibraryPathString; } } if (p.sharedUser != sharedUser) { diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index 29a9a7e..5386a1a 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -220,6 +220,7 @@ class PowerManagerService extends IPowerManager.Stub private Sensor mLightSensor; private boolean mLightSensorEnabled; private float mLightSensorValue = -1; + private boolean mProxIgnoredBecauseScreenTurnedOff = false; private int mHighestLightSensorValue = -1; private float mLightSensorPendingValue = -1; private int mLightSensorScreenBrightness = -1; @@ -252,7 +253,7 @@ class PowerManagerService extends IPowerManager.Stub // could be either static or controllable at runtime private static final boolean mSpew = false; - private static final boolean mDebugProximitySensor = (true || mSpew); + private static final boolean mDebugProximitySensor = (false || mSpew); private static final boolean mDebugLightSensor = (false || mSpew); private native void nativeInit(); @@ -638,7 +639,8 @@ class PowerManagerService extends IPowerManager.Stub int n = flags & LOCK_MASK; return n == PowerManager.FULL_WAKE_LOCK || n == PowerManager.SCREEN_BRIGHT_WAKE_LOCK - || n == PowerManager.SCREEN_DIM_WAKE_LOCK; + || n == PowerManager.SCREEN_DIM_WAKE_LOCK + || n == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK; } void enforceWakeSourcePermission(int uid, int pid) { @@ -778,25 +780,33 @@ class PowerManagerService extends IPowerManager.Stub // set it to whatever they want. otherwise, we modulate that // by the current state so we never turn it more on than // it already is. - if ((wl.flags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0) { - int oldWakeLockState = mWakeLockState; - mWakeLockState = mLocks.reactivateScreenLocksLocked(); - if (mSpew) { - Slog.d(TAG, "wakeup here mUserState=0x" + Integer.toHexString(mUserState) - + " mWakeLockState=0x" - + Integer.toHexString(mWakeLockState) - + " previous wakeLockState=0x" + Integer.toHexString(oldWakeLockState)); + if ((flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) { + mProximityWakeLockCount++; + if (mProximityWakeLockCount == 1) { + enableProximityLockLocked(); } } else { - if (mSpew) { - Slog.d(TAG, "here mUserState=0x" + Integer.toHexString(mUserState) - + " mLocks.gatherState()=0x" - + Integer.toHexString(mLocks.gatherState()) - + " mWakeLockState=0x" + Integer.toHexString(mWakeLockState)); + if ((wl.flags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0) { + int oldWakeLockState = mWakeLockState; + mWakeLockState = mLocks.reactivateScreenLocksLocked(); + if (mSpew) { + Slog.d(TAG, "wakeup here mUserState=0x" + Integer.toHexString(mUserState) + + " mWakeLockState=0x" + + Integer.toHexString(mWakeLockState) + + " previous wakeLockState=0x" + + Integer.toHexString(oldWakeLockState)); + } + } else { + if (mSpew) { + Slog.d(TAG, "here mUserState=0x" + Integer.toHexString(mUserState) + + " mLocks.gatherState()=0x" + + Integer.toHexString(mLocks.gatherState()) + + " mWakeLockState=0x" + Integer.toHexString(mWakeLockState)); + } + mWakeLockState = (mUserState | mWakeLockState) & mLocks.gatherState(); } - mWakeLockState = (mUserState | mWakeLockState) & mLocks.gatherState(); + setPowerState(mWakeLockState | mUserState); } - setPowerState(mWakeLockState | mUserState); } else if ((flags & LOCK_MASK) == PowerManager.PARTIAL_WAKE_LOCK) { if (newlock) { @@ -806,11 +816,6 @@ class PowerManagerService extends IPowerManager.Stub } } Power.acquireWakeLock(Power.PARTIAL_WAKE_LOCK,PARTIAL_NAME); - } else if ((flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) { - mProximityWakeLockCount++; - if (mProximityWakeLockCount == 1) { - enableProximityLockLocked(); - } } if (diffsource) { @@ -868,12 +873,27 @@ class PowerManagerService extends IPowerManager.Stub } if (isScreenLock(wl.flags)) { - mWakeLockState = mLocks.gatherState(); - // goes in the middle to reduce flicker - if ((wl.flags & PowerManager.ON_AFTER_RELEASE) != 0) { - userActivity(SystemClock.uptimeMillis(), -1, false, OTHER_EVENT, false); + if ((wl.flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) { + mProximityWakeLockCount--; + if (mProximityWakeLockCount == 0) { + if (mProximitySensorActive && + ((flags & PowerManager.WAIT_FOR_PROXIMITY_NEGATIVE) != 0)) { + // wait for proximity sensor to go negative before disabling sensor + if (mDebugProximitySensor) { + Slog.d(TAG, "waiting for proximity sensor to go negative"); + } + } else { + disableProximityLockLocked(); + } + } + } else { + mWakeLockState = mLocks.gatherState(); + // goes in the middle to reduce flicker + if ((wl.flags & PowerManager.ON_AFTER_RELEASE) != 0) { + userActivity(SystemClock.uptimeMillis(), -1, false, OTHER_EVENT, false); + } + setPowerState(mWakeLockState | mUserState); } - setPowerState(mWakeLockState | mUserState); } else if ((wl.flags & LOCK_MASK) == PowerManager.PARTIAL_WAKE_LOCK) { mPartialCount--; @@ -881,19 +901,6 @@ class PowerManagerService extends IPowerManager.Stub if (LOG_PARTIAL_WL) EventLog.writeEvent(EventLogTags.POWER_PARTIAL_WAKE_STATE, 0, wl.tag); Power.releaseWakeLock(PARTIAL_NAME); } - } else if ((wl.flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) { - mProximityWakeLockCount--; - if (mProximityWakeLockCount == 0) { - if (mProximitySensorActive && - ((flags & PowerManager.WAIT_FOR_PROXIMITY_NEGATIVE) != 0)) { - // wait for proximity sensor to go negative before disabling sensor - if (mDebugProximitySensor) { - Slog.d(TAG, "waiting for proximity sensor to go negative"); - } - } else { - disableProximityLockLocked(); - } - } } // Unlink the lock from the binder. wl.binder.unlinkToDeath(wl, 0); @@ -2433,11 +2440,23 @@ class PowerManagerService extends IPowerManager.Stub mWakeLockState = SCREEN_OFF; int N = mLocks.size(); int numCleared = 0; + boolean proxLock = false; for (int i=0; i<N; i++) { WakeLock wl = mLocks.get(i); if (isScreenLock(wl.flags)) { - mLocks.get(i).activated = false; - numCleared++; + if (((wl.flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) + && reason == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR) { + proxLock = true; + } else { + mLocks.get(i).activated = false; + numCleared++; + } + } + } + if (!proxLock) { + mProxIgnoredBecauseScreenTurnedOff = true; + if (mDebugProximitySensor) { + Slog.d(TAG, "setting mProxIgnoredBecauseScreenTurnedOff"); } } EventLog.writeEvent(EventLogTags.POWER_SLEEP_REQUESTED, numCleared); @@ -2629,6 +2648,11 @@ class PowerManagerService extends IPowerManager.Stub result |= wl.minState; } } + if (mDebugProximitySensor) { + Slog.d(TAG, "reactivateScreenLocksLocked mProxIgnoredBecauseScreenTurnedOff=" + + mProxIgnoredBecauseScreenTurnedOff); + } + mProxIgnoredBecauseScreenTurnedOff = false; return result; } } @@ -2788,7 +2812,13 @@ class PowerManagerService extends IPowerManager.Stub } if (mProximitySensorActive) { mProximitySensorActive = false; - forceUserActivityLocked(); + if (mDebugProximitySensor) { + Slog.d(TAG, "disableProximityLockLocked mProxIgnoredBecauseScreenTurnedOff=" + + mProxIgnoredBecauseScreenTurnedOff); + } + if (!mProxIgnoredBecauseScreenTurnedOff) { + forceUserActivityLocked(); + } } } } @@ -2802,15 +2832,27 @@ class PowerManagerService extends IPowerManager.Stub return; } if (active) { - goToSleepLocked(SystemClock.uptimeMillis(), - WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR); + if (mDebugProximitySensor) { + Slog.d(TAG, "b mProxIgnoredBecauseScreenTurnedOff=" + + mProxIgnoredBecauseScreenTurnedOff); + } + if (!mProxIgnoredBecauseScreenTurnedOff) { + goToSleepLocked(SystemClock.uptimeMillis(), + WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR); + } mProximitySensorActive = true; } else { // proximity sensor negative events trigger as user activity. // temporarily set mUserActivityAllowed to true so this will work // even when the keyguard is on. mProximitySensorActive = false; - forceUserActivityLocked(); + if (mDebugProximitySensor) { + Slog.d(TAG, "b mProxIgnoredBecauseScreenTurnedOff=" + + mProxIgnoredBecauseScreenTurnedOff); + } + if (!mProxIgnoredBecauseScreenTurnedOff) { + forceUserActivityLocked(); + } if (mProximityWakeLockCount == 0) { // disable sensor if we have no listeners left after proximity negative diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java index a33b7c2..2b4845b 100644 --- a/services/java/com/android/server/TelephonyRegistry.java +++ b/services/java/com/android/server/TelephonyRegistry.java @@ -584,9 +584,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (linkProperties != null) { intent.putExtra(Phone.DATA_LINK_PROPERTIES_KEY, linkProperties); - NetworkInterface iface = linkProperties.getInterface(); + String iface = linkProperties.getInterfaceName(); if (iface != null) { - intent.putExtra(Phone.DATA_IFACE_NAME_KEY, iface.getName()); + intent.putExtra(Phone.DATA_IFACE_NAME_KEY, iface); } } if (linkCapabilities != null) { diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index 30aed69..59f7434 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -505,7 +505,7 @@ public class WindowManagerService extends IWindowManager.Stub InputChannel mServerChannel, mClientChannel; WindowState mTargetWindow; ArrayList<WindowState> mNotifiedWindows; - boolean mDragEnded; + boolean mDragInProgress; private final Rect tmpRect = new Rect(); @@ -562,6 +562,7 @@ public class WindowManagerService extends IWindowManager.Stub // works correctly in calling out to the apps. mDataDescription = new ClipDescription(mData); mNotifiedWindows.clear(); + mDragInProgress = true; if (DEBUG_DRAG) { Slog.d(TAG, "broadcasting DRAG_STARTED of " + mDataDescription); @@ -586,7 +587,7 @@ public class WindowManagerService extends IWindowManager.Stub * process, so it's safe for the caller to call recycle() on the event afterwards. */ private void sendDragStartedLw(WindowState newWin, DragEvent event) { - if (!mDragEnded && newWin.isPotentialDragTarget()) { + if (mDragInProgress && newWin.isPotentialDragTarget()) { try { // clone for local callees since dispatch will recycle the event if (Process.myPid() == newWin.mSession.mPid) { @@ -606,20 +607,22 @@ public class WindowManagerService extends IWindowManager.Stub * was begun. This is a rare case. */ private void sendDragStartedIfNeededLw(WindowState newWin) { - // If we have sent the drag-started, we needn't do so again - for (WindowState ws : mNotifiedWindows) { - if (ws == newWin) { - return; + if (mDragInProgress) { + // If we have sent the drag-started, we needn't do so again + for (WindowState ws : mNotifiedWindows) { + if (ws == newWin) { + return; + } } + if (DEBUG_DRAG) { + Slog.d(TAG, "sending DRAG_STARTED to new window " + newWin); + } + DragEvent event = DragEvent.obtain(DragEvent.ACTION_DRAG_STARTED, 0, 0, + mDataDescription, null); + // sendDragStartedLw() clones 'event' if the window is process-local + sendDragStartedLw(newWin, event); + event.recycle(); } - if (DEBUG_DRAG) { - Slog.d(TAG, "sending DRAG_STARTED to new window " + newWin); - } - DragEvent event = DragEvent.obtain(DragEvent.ACTION_DRAG_STARTED, 0, 0, - mDataDescription, null); - // sendDragStartedLw() clones 'event' if the window is process-local - sendDragStartedLw(newWin, event); - event.recycle(); } void broadcastDragEnded() { @@ -636,7 +639,7 @@ public class WindowManagerService extends IWindowManager.Stub } } mNotifiedWindows.clear(); - mDragEnded = true; + mDragInProgress = false; } evt.recycle(); } diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index 30395c0..9ed1242 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -515,7 +515,7 @@ public class ActivityStack { r.info, r.icicle, results, newIntents, !andResume, mService.isNextTransitionForward()); - if ((app.info.flags&ApplicationInfo.CANT_SAVE_STATE) != 0) { + if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) { // This may be a heavy-weight process! Note that the package // manager will ensure that only activity can run in the main // process of the .apk, which is the only thing that will be @@ -2442,7 +2442,7 @@ public class ActivityStack { final long origId = Binder.clearCallingIdentity(); if (mMainStack && aInfo != null && - (aInfo.applicationInfo.flags&ApplicationInfo.CANT_SAVE_STATE) != 0) { + (aInfo.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) { // This may be a heavy-weight process! Check to see if we already // have another, different heavy-weight process running. if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) { diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java index 39ce0b6..e9eb4f0 100755 --- a/services/java/com/android/server/location/GpsLocationProvider.java +++ b/services/java/com/android/server/location/GpsLocationProvider.java @@ -46,6 +46,10 @@ import android.os.ServiceManager; import android.os.SystemClock; import android.os.WorkSource; import android.provider.Settings; +import android.provider.Telephony.Sms.Intents; +import android.telephony.TelephonyManager; +import android.telephony.gsm.GsmCellLocation; +import android.telephony.SmsMessage; import android.util.Log; import android.util.SparseIntArray; @@ -53,6 +57,9 @@ import com.android.internal.app.IBatteryStats; import com.android.internal.telephony.Phone; import com.android.internal.location.GpsNetInitiatedHandler; import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification; +import com.android.internal.telephony.GsmAlphabet; +import com.android.internal.telephony.SmsHeader; +import com.android.internal.util.HexDump; import java.io.File; import java.io.FileInputStream; @@ -153,6 +160,24 @@ public class GpsLocationProvider implements LocationProviderInterface { private static final int REMOVE_LISTENER = 9; private static final int REQUEST_SINGLE_SHOT = 10; + // Request setid + private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1; + private static final int AGPS_RIL_REQUEST_SETID_MSISDN = 2; + + // Request ref location + private static final int AGPS_RIL_REQUEST_REFLOC_CELLID = 1; + private static final int AGPS_RIL_REQUEST_REFLOC_MAC = 2; + + // ref. location info + private static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1; + private static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2; + private static final int AGPS_REG_LOCATION_TYPE_MAC = 3; + + // set id info + private static final int AGPS_SETID_TYPE_NONE = 0; + private static final int AGPS_SETID_TYPE_IMSI = 1; + private static final int AGPS_SETID_TYPE_MSISDN = 2; + private static final String PROPERTIES_FILE = "/etc/gps.conf"; private int mLocationFlags = LOCATION_INVALID; @@ -328,10 +353,27 @@ public class GpsLocationProvider implements LocationProviderInterface { } else if (action.equals(ALARM_TIMEOUT)) { if (DEBUG) Log.d(TAG, "ALARM_TIMEOUT"); hibernate(); - } + } else if (action.equals(Intents.DATA_SMS_RECEIVED_ACTION)) { + checkSmsSuplInit(intent); + } else if (action.equals(Intents.WAP_PUSH_RECEIVED_ACTION)) { + checkWapSuplInit(intent); + } } }; + private void checkSmsSuplInit(Intent intent) { + SmsMessage[] messages = Intents.getMessagesFromIntent(intent); + for (int i=0; i <messages.length; i++) { + byte[] supl_init = messages[i].getUserData(); + native_agps_ni_message(supl_init,supl_init.length); + } + } + + private void checkWapSuplInit(Intent intent) { + byte[] supl_init = (byte[]) intent.getExtra("data"); + native_agps_ni_message(supl_init,supl_init.length); + } + public static boolean isSupported() { return native_is_supported(); } @@ -352,6 +394,21 @@ public class GpsLocationProvider implements LocationProviderInterface { mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0); mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0); + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION); + intentFilter.addDataScheme("sms"); + intentFilter.addDataAuthority("localhost","7275"); + context.registerReceiver(mBroadcastReciever, intentFilter); + + intentFilter = new IntentFilter(); + intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION); + try { + intentFilter.addDataType("application/vnd.omaloc-supl-init"); + } catch (IntentFilter.MalformedMimeTypeException e) { + Log.w(TAG, "Malformed SUPL init mime type"); + } + context.registerReceiver(mBroadcastReciever, intentFilter); + mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); // Battery statistics service to be notified when GPS turns on or off @@ -1255,22 +1312,20 @@ public class GpsLocationProvider implements LocationProviderInterface { //============================================================= // NI Client support - //============================================================= + //============================================================= private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() { - // Sends a response for an NI reqeust to HAL. - public boolean sendNiResponse(int notificationId, int userResponse) - { - // TODO Add Permission check - - StringBuilder extrasBuf = new StringBuilder(); - - if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId + - ", response: " + userResponse); - - native_send_ni_response(notificationId, userResponse); - - return true; - } + // Sends a response for an NI reqeust to HAL. + public boolean sendNiResponse(int notificationId, int userResponse) + { + // TODO Add Permission check + + StringBuilder extrasBuf = new StringBuilder(); + + if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId + + ", response: " + userResponse); + native_send_ni_response(notificationId, userResponse); + return true; + } }; public INetInitiatedListener getNetInitiatedListener() { @@ -1278,70 +1333,132 @@ public class GpsLocationProvider implements LocationProviderInterface { } // Called by JNI function to report an NI request. - @SuppressWarnings("deprecation") - public void reportNiNotification( - int notificationId, - int niType, - int notifyFlags, - int timeout, - int defaultResponse, - String requestorId, - String text, - int requestorIdEncoding, - int textEncoding, - String extras // Encoded extra data + public void reportNiNotification( + int notificationId, + int niType, + int notifyFlags, + int timeout, + int defaultResponse, + String requestorId, + String text, + int requestorIdEncoding, + int textEncoding, + String extras // Encoded extra data ) - { - Log.i(TAG, "reportNiNotification: entered"); - Log.i(TAG, "notificationId: " + notificationId + - ", niType: " + niType + - ", notifyFlags: " + notifyFlags + - ", timeout: " + timeout + - ", defaultResponse: " + defaultResponse); - - Log.i(TAG, "requestorId: " + requestorId + - ", text: " + text + - ", requestorIdEncoding: " + requestorIdEncoding + - ", textEncoding: " + textEncoding); - - GpsNiNotification notification = new GpsNiNotification(); - - notification.notificationId = notificationId; - notification.niType = niType; - notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0; - notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0; - notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0; - notification.timeout = timeout; - notification.defaultResponse = defaultResponse; - notification.requestorId = requestorId; - notification.text = text; - notification.requestorIdEncoding = requestorIdEncoding; - notification.textEncoding = textEncoding; - - // Process extras, assuming the format is - // one of more lines of "key = value" - Bundle bundle = new Bundle(); - - if (extras == null) extras = ""; - Properties extraProp = new Properties(); - - try { - extraProp.load(new StringBufferInputStream(extras)); - } - catch (IOException e) - { - Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras); - } - - for (Entry<Object, Object> ent : extraProp.entrySet()) - { - bundle.putString((String) ent.getKey(), (String) ent.getValue()); - } - - notification.extras = bundle; - - mNIHandler.handleNiNotification(notification); - } + { + Log.i(TAG, "reportNiNotification: entered"); + Log.i(TAG, "notificationId: " + notificationId + + ", niType: " + niType + + ", notifyFlags: " + notifyFlags + + ", timeout: " + timeout + + ", defaultResponse: " + defaultResponse); + + Log.i(TAG, "requestorId: " + requestorId + + ", text: " + text + + ", requestorIdEncoding: " + requestorIdEncoding + + ", textEncoding: " + textEncoding); + + GpsNiNotification notification = new GpsNiNotification(); + + notification.notificationId = notificationId; + notification.niType = niType; + notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0; + notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0; + notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0; + notification.timeout = timeout; + notification.defaultResponse = defaultResponse; + notification.requestorId = requestorId; + notification.text = text; + notification.requestorIdEncoding = requestorIdEncoding; + notification.textEncoding = textEncoding; + + // Process extras, assuming the format is + // one of more lines of "key = value" + Bundle bundle = new Bundle(); + + if (extras == null) extras = ""; + Properties extraProp = new Properties(); + + try { + extraProp.load(new StringBufferInputStream(extras)); + } + catch (IOException e) + { + Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras); + } + + for (Entry<Object, Object> ent : extraProp.entrySet()) + { + bundle.putString((String) ent.getKey(), (String) ent.getValue()); + } + + notification.extras = bundle; + + mNIHandler.handleNiNotification(notification); + } + + /** + * Called from native code to request set id info. + * We should be careful about receiving null string from the TelephonyManager, + * because sending null String to JNI function would cause a crash. + */ + + private void requestSetID(int flags) { + TelephonyManager phone = (TelephonyManager) + mContext.getSystemService(Context.TELEPHONY_SERVICE); + int type = AGPS_SETID_TYPE_NONE; + String data = ""; + + if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) { + String data_temp = phone.getSubscriberId(); + if (data_temp == null) { + // This means the framework does not have the SIM card ready. + } else { + // This means the framework has the SIM card. + data = data_temp; + type = AGPS_SETID_TYPE_IMSI; + } + } + else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) { + String data_temp = phone.getLine1Number(); + if (data_temp == null) { + // This means the framework does not have the SIM card ready. + } else { + // This means the framework has the SIM card. + data = data_temp; + type = AGPS_SETID_TYPE_MSISDN; + } + } + native_agps_set_id(type, data); + } + + /** + * Called from native code to request reference location info + */ + + private void requestRefLocation(int flags) { + TelephonyManager phone = (TelephonyManager) + mContext.getSystemService(Context.TELEPHONY_SERVICE); + if (phone.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) { + GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation(); + if ((gsm_cell != null) && (phone.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) + && (phone.getNetworkOperator().length() > 3)) { + int type; + int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0,3)); + int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3)); + if (phone.getNetworkType() == TelephonyManager.NETWORK_TYPE_UMTS) + type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID; + else + type = AGPS_REF_LOCATION_TYPE_GSM_CELLID; + native_agps_set_ref_location_cellid(type, mcc, mnc, + gsm_cell.getLac(), gsm_cell.getCid()); + } + else + Log.e(TAG,"Error getting cell location info."); + } + else + Log.e(TAG,"CDMA not supported."); + } private void sendMessage(int message, int arg, Object obj) { // hold a wake lock while messages are pending @@ -1472,8 +1589,14 @@ public class GpsLocationProvider implements LocationProviderInterface { private native void native_agps_data_conn_open(String apn); private native void native_agps_data_conn_closed(); private native void native_agps_data_conn_failed(); + private native void native_agps_ni_message(byte [] msg, int length); private native void native_set_agps_server(int type, String hostname, int port); // Network-initiated (NI) Support private native void native_send_ni_response(int notificationId, int userResponse); + + // AGPS ril suport + private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc, + int lac, int cid); + private native void native_agps_set_id(int type, String setid); } diff --git a/services/jni/com_android_server_location_GpsLocationProvider.cpp b/services/jni/com_android_server_location_GpsLocationProvider.cpp index 93068e6..71c7aba 100755 --- a/services/jni/com_android_server_location_GpsLocationProvider.cpp +++ b/services/jni/com_android_server_location_GpsLocationProvider.cpp @@ -40,12 +40,15 @@ static jmethodID method_reportNmea; static jmethodID method_setEngineCapabilities; static jmethodID method_xtraDownloadRequest; static jmethodID method_reportNiNotification; +static jmethodID method_requestRefLocation; +static jmethodID method_requestSetID; static const GpsInterface* sGpsInterface = NULL; static const GpsXtraInterface* sGpsXtraInterface = NULL; static const AGpsInterface* sAGpsInterface = NULL; static const GpsNiInterface* sGpsNiInterface = NULL; static const GpsDebugInterface* sGpsDebugInterface = NULL; +static const AGpsRilInterface* sAGpsRilInterface = NULL; // temporary storage for GPS callbacks static GpsSvStatus sGpsSvStatus; @@ -193,17 +196,30 @@ GpsNiCallbacks sGpsNiCallbacks = { create_thread_callback, }; -static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) { - method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V"); - method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V"); - method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V"); - method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II)V"); - method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V"); - method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V"); - method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V"); - method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification", "(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V"); +static void agps_request_set_id(uint32_t flags) +{ + LOGD("agps_request_set_id: flags (%d)", flags); + + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->CallVoidMethod(mCallbacksObj, method_requestSetID, flags); + checkAndClearExceptionFromCallback(env, __FUNCTION__); +} + +static void agps_request_ref_location(uint32_t flags) +{ + LOGD("agps_ref_location: flags (%d)", flags); + + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->CallVoidMethod(mCallbacksObj, method_requestRefLocation, flags); + checkAndClearExceptionFromCallback(env, __FUNCTION__); } +AGpsRilCallbacks sAGpsRilCallbacks = { + agps_request_set_id, + agps_request_ref_location, + create_thread_callback, +}; + static const GpsInterface* get_gps_interface() { int err; hw_module_t* module; @@ -222,6 +238,64 @@ static const GpsInterface* get_gps_interface() { return interface; } +static const AGpsInterface* GetAGpsInterface() +{ + if (!sGpsInterface) + sGpsInterface = get_gps_interface(); + if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0) + return NULL; + + if (!sAGpsInterface) { + sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE); + if (sAGpsInterface) + sAGpsInterface->init(&sAGpsCallbacks); + } + return sAGpsInterface; +} + +static const GpsNiInterface* GetNiInterface() +{ + if (!sGpsInterface) + sGpsInterface = get_gps_interface(); + if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0) + return NULL; + + if (!sGpsNiInterface) { + sGpsNiInterface = (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE); + if (sGpsNiInterface) + sGpsNiInterface->init(&sGpsNiCallbacks); + } + return sGpsNiInterface; +} + +static const AGpsRilInterface* GetAGpsRilInterface() +{ + if (!sGpsInterface) + sGpsInterface = get_gps_interface(); + if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0) + return NULL; + + if (!sAGpsRilInterface) { + sAGpsRilInterface = (const AGpsRilInterface*)sGpsInterface->get_extension(AGPS_RIL_INTERFACE); + if (sAGpsRilInterface) + sAGpsRilInterface->init(&sAGpsRilCallbacks); + } + return sAGpsRilInterface; +} + +static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) { + method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V"); + method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V"); + method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V"); + method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II)V"); + method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V"); + method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V"); + method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V"); + method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification", "(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V"); + method_requestRefLocation = env->GetMethodID(clazz,"requestRefLocation","(I)V"); + method_requestSetID = env->GetMethodID(clazz,"requestSetID","(I)V"); +} + static jboolean android_location_GpsLocationProvider_is_supported(JNIEnv* env, jclass clazz) { if (!sGpsInterface) sGpsInterface = get_gps_interface(); @@ -239,16 +313,6 @@ static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject o if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0) return false; - if (!sAGpsInterface) - sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE); - if (sAGpsInterface) - sAGpsInterface->init(&sAGpsCallbacks); - - if (!sGpsNiInterface) - sGpsNiInterface = (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE); - if (sGpsNiInterface) - sGpsNiInterface->init(&sGpsNiCallbacks); - if (!sGpsDebugInterface) sGpsDebugInterface = (const GpsDebugInterface*)sGpsInterface->get_extension(GPS_DEBUG_INTERFACE); @@ -313,6 +377,64 @@ static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, job return num_svs; } +static void android_location_GpsLocationProvider_agps_set_reference_location_cellid(JNIEnv* env, + jobject obj, jint type, jint mcc, jint mnc, jint lac, jint cid) +{ + AGpsRefLocation location; + const AGpsRilInterface* interface = GetAGpsRilInterface(); + if (!interface) { + LOGE("no AGPS RIL interface in agps_set_reference_location_cellid"); + return; + } + + switch(type) { + case AGPS_REF_LOCATION_TYPE_GSM_CELLID: + case AGPS_REF_LOCATION_TYPE_UMTS_CELLID: + location.type = type; + location.u.cellID.mcc = mcc; + location.u.cellID.mnc = mnc; + location.u.cellID.lac = lac; + location.u.cellID.cid = cid; + break; + default: + LOGE("Neither a GSM nor a UMTS cellid (%s:%d).",__FUNCTION__,__LINE__); + return; + break; + } + interface->set_ref_location(&location, sizeof(location)); +} + +static void android_location_GpsLocationProvider_agps_send_ni_message(JNIEnv* env, + jobject obj, jbyteArray ni_msg, jint size) +{ + size_t sz; + const AGpsRilInterface* interface = GetAGpsRilInterface(); + if (!interface) { + LOGE("no AGPS RIL interface in send_ni_message"); + return; + } + if (size < 0) + return; + sz = (size_t)size; + jbyte* b = env->GetByteArrayElements(ni_msg, 0); + interface->ni_message((uint8_t *)b,sz); + env->ReleaseByteArrayElements(ni_msg,b,0); +} + +static void android_location_GpsLocationProvider_agps_set_id(JNIEnv *env, + jobject obj, jint type, jstring setid_string) +{ + const AGpsRilInterface* interface = GetAGpsRilInterface(); + if (!interface) { + LOGE("no AGPS RIL interface in agps_set_id"); + return; + } + + const char *setid = env->GetStringUTFChars(setid_string, NULL); + interface->set_set_id(type, setid); + env->ReleaseStringUTFChars(setid_string, setid); +} + static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject obj, jbyteArray nmeaArray, jint buffer_size) { @@ -363,60 +485,63 @@ static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, j static void android_location_GpsLocationProvider_agps_data_conn_open(JNIEnv* env, jobject obj, jstring apn) { - if (!sAGpsInterface) { - sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE); + const AGpsInterface* interface = GetAGpsInterface(); + if (!interface) { + LOGE("no AGPS interface in agps_data_conn_open"); + return; } - if (sAGpsInterface) { - if (apn == NULL) { - jniThrowException(env, "java/lang/IllegalArgumentException", NULL); - return; - } - const char *apnStr = env->GetStringUTFChars(apn, NULL); - sAGpsInterface->data_conn_open(apnStr); - env->ReleaseStringUTFChars(apn, apnStr); + if (apn == NULL) { + jniThrowException(env, "java/lang/IllegalArgumentException", NULL); + return; } + const char *apnStr = env->GetStringUTFChars(apn, NULL); + interface->data_conn_open(apnStr); + env->ReleaseStringUTFChars(apn, apnStr); } static void android_location_GpsLocationProvider_agps_data_conn_closed(JNIEnv* env, jobject obj) { - if (!sAGpsInterface) { - sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE); - } - if (sAGpsInterface) { - sAGpsInterface->data_conn_closed(); + const AGpsInterface* interface = GetAGpsInterface(); + if (!interface) { + LOGE("no AGPS interface in agps_data_conn_open"); + return; } + interface->data_conn_closed(); } static void android_location_GpsLocationProvider_agps_data_conn_failed(JNIEnv* env, jobject obj) { - if (!sAGpsInterface) { - sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE); - } - if (sAGpsInterface) { - sAGpsInterface->data_conn_failed(); + const AGpsInterface* interface = GetAGpsInterface(); + if (!interface) { + LOGE("no AGPS interface in agps_data_conn_open"); + return; } + interface->data_conn_failed(); } static void android_location_GpsLocationProvider_set_agps_server(JNIEnv* env, jobject obj, jint type, jstring hostname, jint port) { - if (!sAGpsInterface) { - sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE); - } - if (sAGpsInterface) { - const char *c_hostname = env->GetStringUTFChars(hostname, NULL); - sAGpsInterface->set_server(type, c_hostname, port); - env->ReleaseStringUTFChars(hostname, c_hostname); + const AGpsInterface* interface = GetAGpsInterface(); + if (!interface) { + LOGE("no AGPS interface in agps_data_conn_open"); + return; } + const char *c_hostname = env->GetStringUTFChars(hostname, NULL); + interface->set_server(type, c_hostname, port); + env->ReleaseStringUTFChars(hostname, c_hostname); } static void android_location_GpsLocationProvider_send_ni_response(JNIEnv* env, jobject obj, jint notifId, jint response) { - if (!sGpsNiInterface) - sGpsNiInterface = (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE); - if (sGpsNiInterface) - sGpsNiInterface->respond(notifId, response); + const GpsNiInterface* interface = GetNiInterface(); + if (!interface) { + LOGE("no NI interface in send_ni_response"); + return; + } + + interface->respond(notifId, response); } static jstring android_location_GpsLocationProvider_get_internal_state(JNIEnv* env, jobject obj) @@ -452,8 +577,11 @@ static JNINativeMethod sMethods[] = { {"native_agps_data_conn_open", "(Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_agps_data_conn_open}, {"native_agps_data_conn_closed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_closed}, {"native_agps_data_conn_failed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_failed}, + {"native_agps_set_id","(ILjava/lang/String;)V",(void*)android_location_GpsLocationProvider_agps_set_id}, + {"native_agps_set_ref_location_cellid","(IIIII)V",(void*)android_location_GpsLocationProvider_agps_set_reference_location_cellid}, {"native_set_agps_server", "(ILjava/lang/String;I)V", (void*)android_location_GpsLocationProvider_set_agps_server}, {"native_send_ni_response", "(II)V", (void*)android_location_GpsLocationProvider_send_ni_response}, + {"native_agps_ni_message", "([BI)V", (void *)android_location_GpsLocationProvider_agps_send_ni_message}, {"native_get_internal_state", "()Ljava/lang/String;", (void*)android_location_GpsLocationProvider_get_internal_state}, }; diff --git a/telephony/java/com/android/internal/telephony/Connection.java b/telephony/java/com/android/internal/telephony/Connection.java index 0d983b5..07f90cd 100644 --- a/telephony/java/com/android/internal/telephony/Connection.java +++ b/telephony/java/com/android/internal/telephony/Connection.java @@ -40,6 +40,7 @@ public abstract class Connection { MMI, /* not presently used; dial() returns null */ INVALID_NUMBER, /* invalid dial string */ NUMBER_UNREACHABLE, /* cannot reach the peer */ + SERVER_UNREACHABLE, /* cannot reach the server */ INVALID_CREDENTIALS, /* invalid credentials */ OUT_OF_NETWORK, /* calling from out of network is not allowed */ SERVER_ERROR, /* server error */ diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java index 3030481..185d413 100644 --- a/telephony/java/com/android/internal/telephony/DataConnection.java +++ b/telephony/java/com/android/internal/telephony/DataConnection.java @@ -21,6 +21,7 @@ import com.android.internal.telephony.gsm.ApnSetting; import com.android.internal.util.HierarchicalState; import com.android.internal.util.HierarchicalStateMachine; +import android.net.LinkAddress; import android.net.LinkCapabilities; import android.net.LinkProperties; import android.os.AsyncResult; @@ -29,10 +30,10 @@ import android.os.SystemProperties; import android.util.EventLog; import java.net.InetAddress; +import java.net.InterfaceAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.net.UnknownHostException; -import java.util.HashMap; /** * {@hide} @@ -68,7 +69,7 @@ import java.util.HashMap; * EVENT_GET_LAST_FAIL_DONE, * EVENT_DEACTIVATE_DONE. * } - * ++ # mInactiveState + * ++ # mInactiveState * e(doNotifications) * x(clearNotifications) { * EVENT_RESET { notifiyDisconnectCompleted }. @@ -428,26 +429,25 @@ public abstract class DataConnection extends HierarchicalStateMachine { try { String prefix = "net." + interfaceName + "."; - linkProperties.setInterface(NetworkInterface.getByName(interfaceName)); + NetworkInterface networkInterface = NetworkInterface.getByName(interfaceName); + linkProperties.setInterfaceName(interfaceName); // TODO: Get gateway and dns via RIL interface not property? String gatewayAddress = SystemProperties.get(prefix + "gw"); linkProperties.setGateway(InetAddress.getByName(gatewayAddress)); - if (response.length > 2) { - String ipAddress = response[2]; - linkProperties.addAddress(InetAddress.getByName(ipAddress)); - - // TODO: Get gateway and dns via RIL interface not property? - String dnsServers[] = new String[2]; - dnsServers[0] = SystemProperties.get(prefix + "dns1"); - dnsServers[1] = SystemProperties.get(prefix + "dns2"); - if (isDnsOk(dnsServers)) { - linkProperties.addDns(InetAddress.getByName(dnsServers[0])); - linkProperties.addDns(InetAddress.getByName(dnsServers[1])); - } else { - result = SetupResult.ERR_BadDns; - } + for (InterfaceAddress addr : networkInterface.getInterfaceAddresses()) { + linkProperties.addLinkAddress(new LinkAddress(addr)); + } + // TODO: Get gateway and dns via RIL interface not property? + String dnsServers[] = new String[2]; + dnsServers[0] = SystemProperties.get(prefix + "dns1"); + dnsServers[1] = SystemProperties.get(prefix + "dns2"); + if (isDnsOk(dnsServers)) { + linkProperties.addDns(InetAddress.getByName(dnsServers[0])); + linkProperties.addDns(InetAddress.getByName(dnsServers[1])); + } else { + result = SetupResult.ERR_BadDns; } } catch (UnknownHostException e1) { log("onSetupCompleted: UnknowHostException " + e1); diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java index 55e3002..6ed9295 100755 --- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java +++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java @@ -874,6 +874,9 @@ public class SipPhone extends SipPhoneBase { public void onError(SipAudioCall call, int errorCode, String errorMessage) { switch (errorCode) { + case SipErrorCode.SERVER_UNREACHABLE: + onError(Connection.DisconnectCause.SERVER_UNREACHABLE); + break; case SipErrorCode.PEER_NOT_REACHABLE: onError(Connection.DisconnectCause.NUMBER_UNREACHABLE); break; diff --git a/tests/CoreTests/android/core/MiscRegressionTest.java b/tests/CoreTests/android/core/MiscRegressionTest.java index 8281db0..7734397 100644 --- a/tests/CoreTests/android/core/MiscRegressionTest.java +++ b/tests/CoreTests/android/core/MiscRegressionTest.java @@ -66,37 +66,6 @@ public class MiscRegressionTest extends TestCase { } } - // Regression test for #1061945: negative Shorts do not - // serialize/deserialize correctly - @SmallTest - public void testShortSerialization() throws Exception { - // create an instance of ObjectInputStream - String x = new String("serialize_foobar"); - java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream(); - (new java.io.ObjectOutputStream(baos)).writeObject(x); - ObjectInputStream ois = new java.io.ObjectInputStream( - new java.io.ByteArrayInputStream(baos.toByteArray())); - - // get the setField(...,, short val) method in question - Class<ObjectInputStream> oClass = ObjectInputStream.class; - Method m = oClass.getDeclaredMethod("setField", new Class[] { Object.class, Class.class, String.class, short.class}); - // compose args - short start = 123; - short origval = -1; // 0xffff - Short obj = new Short(start); - Class<Short> declaringClass = Short.class; - String fieldDescName = "value"; - - // test the initial value - assertEquals(obj.shortValue(), start); - // invoke native method to set the field "value" of type short to the newval - m.setAccessible(true); // since the method is private - m.invoke(ois, new Object[]{ obj, declaringClass, fieldDescName, new Short(origval)} ); - // test the set value - short res = obj.shortValue(); - assertEquals("Read and written values must be equal", origval, res); - } - // Regression test for #951285: Suitable LogHandler should be chosen // depending on the environment. @MediumTest diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java index b70f3a9..8fa626b 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java @@ -18,13 +18,21 @@ package com.android.test.hwui; import android.app.Activity; import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.LinearGradient; +import android.graphics.RadialGradient; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Shader; +import android.graphics.SweepGradient; import android.os.Bundle; +import android.view.Gravity; import android.view.View; +import android.widget.FrameLayout; +import android.widget.SeekBar; @SuppressWarnings({"UnusedDeclaration"}) public class GradientsActivity extends Activity { @@ -32,9 +40,157 @@ public class GradientsActivity extends Activity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(new ShadersView(this)); + final FrameLayout layout = new FrameLayout(this); + + final ShadersView shadersView = new ShadersView(this); + final GradientView gradientView = new GradientView(this); + final RadialGradientView radialGradientView = new RadialGradientView(this); + final SweepGradientView sweepGradientView = new SweepGradientView(this); + final BitmapView bitmapView = new BitmapView(this); + + final SeekBar rotateView = new SeekBar(this); + rotateView.setMax(360); + rotateView.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + } + + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + gradientView.setRotationY((float) progress); + radialGradientView.setRotationX((float) progress); + sweepGradientView.setRotationY((float) progress); + bitmapView.setRotationX((float) progress); + } + }); + + layout.addView(shadersView); + layout.addView(gradientView, new FrameLayout.LayoutParams( + 200, 200, Gravity.CENTER)); + + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(200, 200, Gravity.CENTER); + lp.setMargins(220, 0, 0, 0); + layout.addView(radialGradientView, lp); + + lp = new FrameLayout.LayoutParams(200, 200, Gravity.CENTER); + lp.setMargins(440, 0, 0, 0); + layout.addView(sweepGradientView, lp); + + lp = new FrameLayout.LayoutParams(200, 200, Gravity.CENTER); + lp.setMargins(220, -220, 0, 0); + layout.addView(bitmapView, lp); + + layout.addView(rotateView, new FrameLayout.LayoutParams( + 300, FrameLayout.LayoutParams.WRAP_CONTENT, + Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM)); + + setContentView(layout); } + + static class BitmapView extends View { + private final Paint mPaint; + + BitmapView(Context c) { + super(c); + + Bitmap texture = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset1); + BitmapShader shader = new BitmapShader(texture, Shader.TileMode.REPEAT, + Shader.TileMode.REPEAT); + mPaint = new Paint(); + mPaint.setShader(shader); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + setMeasuredDimension(200, 200); + } + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + canvas.drawRect(0.0f, 0.0f, getWidth(), getHeight(), mPaint); + } + } + + static class GradientView extends View { + private final Paint mPaint; + + GradientView(Context c) { + super(c); + + LinearGradient gradient = new LinearGradient(0, 0, 200, 0, 0xFF000000, 0, + Shader.TileMode.CLAMP); + mPaint = new Paint(); + mPaint.setShader(gradient); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + setMeasuredDimension(200, 200); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + canvas.drawRect(0.0f, 0.0f, getWidth(), getHeight(), mPaint); + } + } + + static class RadialGradientView extends View { + private final Paint mPaint; + + RadialGradientView(Context c) { + super(c); + + RadialGradient gradient = new RadialGradient(0.0f, 0.0f, 100.0f, 0xff000000, 0xffffffff, + Shader.TileMode.MIRROR); + mPaint = new Paint(); + mPaint.setShader(gradient); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + setMeasuredDimension(200, 200); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + canvas.drawRect(0.0f, 0.0f, getWidth(), getHeight(), mPaint); + } + } + + static class SweepGradientView extends View { + private final Paint mPaint; + + SweepGradientView(Context c) { + super(c); + + SweepGradient gradient = new SweepGradient(100.0f, 100.0f, 0xff000000, 0xffffffff); + mPaint = new Paint(); + mPaint.setShader(gradient); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + setMeasuredDimension(200, 200); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + canvas.drawRect(0.0f, 0.0f, getWidth(), getHeight(), mPaint); + } + } + static class ShadersView extends View { private final Paint mPaint; private final float mDrawWidth; diff --git a/tests/StatusBar/src/com/android/statusbartest/PowerTest.java b/tests/StatusBar/src/com/android/statusbartest/PowerTest.java index f778cab..178fa92 100644 --- a/tests/StatusBar/src/com/android/statusbartest/PowerTest.java +++ b/tests/StatusBar/src/com/android/statusbartest/PowerTest.java @@ -49,6 +49,8 @@ public class PowerTest extends TestActivity int mPokeState = 0; IBinder mPokeToken = new Binder(); Handler mHandler = new Handler(); + PowerManager mPm; + PowerManager.WakeLock mProx; @Override protected String tag() { @@ -58,10 +60,27 @@ public class PowerTest extends TestActivity @Override protected Test[] tests() { mPowerManager = IPowerManager.Stub.asInterface(ServiceManager.getService("power")); + mPm = (PowerManager)getSystemService("power"); + mProx = mPm.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, "PowerTest-prox"); return mTests; } private Test[] mTests = new Test[] { + new Test("Enable proximity") { + public void run() { + mProx.acquire(); + } + }, + new Test("Disable proximity") { + public void run() { + mProx.release(); + } + }, + new Test("Disable proximity (WAIT_FOR_PROXIMITY_NEGATIVE)") { + public void run() { + mProx.release(PowerManager.WAIT_FOR_PROXIMITY_NEGATIVE); + } + }, new Test("Cheek events don't poke") { public void run() { mPokeState |= LocalPowerManager.POKE_LOCK_IGNORE_CHEEK_EVENTS; @@ -72,6 +91,7 @@ public class PowerTest extends TestActivity } } }, + new Test("Cheek events poke") { public void run() { mPokeState &= ~LocalPowerManager.POKE_LOCK_IGNORE_CHEEK_EVENTS; diff --git a/voip/java/android/net/sip/ISipService.aidl b/voip/java/android/net/sip/ISipService.aidl index 6c68213..3250bf9 100644 --- a/voip/java/android/net/sip/ISipService.aidl +++ b/voip/java/android/net/sip/ISipService.aidl @@ -16,6 +16,7 @@ package android.net.sip; +import android.app.PendingIntent; import android.net.sip.ISipSession; import android.net.sip.ISipSessionListener; import android.net.sip.SipProfile; @@ -26,7 +27,7 @@ import android.net.sip.SipProfile; interface ISipService { void open(in SipProfile localProfile); void open3(in SipProfile localProfile, - String incomingCallBroadcastAction, + in PendingIntent incomingCallPendingIntent, in ISipSessionListener listener); void close(in String localProfileUri); boolean isOpened(String localProfileUri); diff --git a/voip/java/android/net/sip/SipErrorCode.java b/voip/java/android/net/sip/SipErrorCode.java index eb7a1ae..a55ab25 100644 --- a/voip/java/android/net/sip/SipErrorCode.java +++ b/voip/java/android/net/sip/SipErrorCode.java @@ -61,6 +61,9 @@ public class SipErrorCode { /** Cross-domain authentication required. */ public static final int CROSS_DOMAIN_AUTHENTICATION = -11; + /** When the server is not reachable. */ + public static final int SERVER_UNREACHABLE = -12; + public static String toString(int errorCode) { switch (errorCode) { case NO_ERROR: @@ -87,6 +90,8 @@ public class SipErrorCode { return "DATA_CONNECTION_LOST"; case CROSS_DOMAIN_AUTHENTICATION: return "CROSS_DOMAIN_AUTHENTICATION"; + case SERVER_UNREACHABLE: + return "SERVER_UNREACHABLE"; default: return "UNKNOWN"; } diff --git a/voip/java/android/net/sip/SipManager.java b/voip/java/android/net/sip/SipManager.java index bd859e8..80c35fb 100644 --- a/voip/java/android/net/sip/SipManager.java +++ b/voip/java/android/net/sip/SipManager.java @@ -16,6 +16,7 @@ package android.net.sip; +import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; @@ -34,7 +35,7 @@ import java.text.ParseException; * <li>open a {@link SipProfile} to get ready for making outbound calls or have * the background SIP service listen to incoming calls and broadcast them * with registered command string. See - * {@link #open(SipProfile, String, SipRegistrationListener)}, + * {@link #open(SipProfile, PendingIntent, SipRegistrationListener)}, * {@link #open(SipProfile)}, {@link #close}, {@link #isOpened} and * {@link #isRegistered}. It also facilitates handling of the incoming call * broadcast intent. See @@ -51,6 +52,19 @@ import java.text.ParseException; */ public class SipManager { /** + * The result code to be sent back with the incoming call + * {@link PendingIntent}. + * @see #open(SipProfile, PendingIntent, SipRegistrationListener) + */ + public static final int INCOMING_CALL_RESULT_CODE = 101; + + /** Part of the incoming call intent. */ + public static final String EXTRA_CALL_ID = "android:sipCallID"; + + /** Part of the incoming call intent. */ + public static final String EXTRA_OFFER_SD = "android:sipOfferSD"; + + /** * Action string for the incoming call intent for the Phone app. * Internal use only. * @hide @@ -78,12 +92,6 @@ public class SipManager { */ public static final String EXTRA_LOCAL_URI = "android:localSipUri"; - /** Part of the incoming call intent. */ - public static final String EXTRA_CALL_ID = "android:sipCallID"; - - /** Part of the incoming call intent. */ - public static final String EXTRA_OFFER_SD = "android:sipOfferSD"; - private static final String TAG = "SipManager"; private ISipService mSipService; @@ -142,7 +150,8 @@ public class SipManager { /** * Opens the profile for making calls. The caller may make subsequent calls * through {@link #makeAudioCall}. If one also wants to receive calls on the - * profile, use {@link #open(SipProfile, String, SipRegistrationListener)} + * profile, use + * {@link #open(SipProfile, PendingIntent, SipRegistrationListener)} * instead. * * @param localProfile the SIP profile to make calls from @@ -165,17 +174,29 @@ public class SipManager { * in order to receive calls from the provider. * * @param localProfile the SIP profile to receive incoming calls for - * @param incomingCallBroadcastAction the action to be broadcast when an - * incoming call is received + * @param incomingCallPendingIntent When an incoming call is received, the + * SIP service will call + * {@link PendingIntent#send(Context, int, Intent)} to send back the + * intent to the caller with {@link #INCOMING_CALL_RESULT_CODE} as the + * result code and the intent to fill in the call ID and session + * description information. It cannot be null. * @param listener to listen to registration events; can be null + * @see #getCallId + * @see #getOfferSessionDescription + * @see #takeAudioCall + * @throws NullPointerException if {@code incomingCallPendingIntent} is null * @throws SipException if the profile contains incorrect settings or * calling the SIP service results in an error */ public void open(SipProfile localProfile, - String incomingCallBroadcastAction, + PendingIntent incomingCallPendingIntent, SipRegistrationListener listener) throws SipException { + if (incomingCallPendingIntent == null) { + throw new NullPointerException( + "incomingCallPendingIntent cannot be null"); + } try { - mSipService.open3(localProfile, incomingCallBroadcastAction, + mSipService.open3(localProfile, incomingCallPendingIntent, createRelay(listener, localProfile.getUriString())); } catch (RemoteException e) { throw new SipException("open()", e); @@ -184,7 +205,8 @@ public class SipManager { /** * Sets the listener to listen to registration events. No effect if the - * profile has not been opened to receive calls (see {@link #open}). + * profile has not been opened to receive calls (see + * {@link #open(SipProfile, PendingIntent, SipRegistrationListener)}). * * @param localProfileUri the URI of the profile * @param listener to listen to registration events; can be null @@ -282,9 +304,9 @@ public class SipManager { } /** - * Creates a {@link SipAudioCall} to make a call. To use this method, one - * must call {@link #open(SipProfile)} first. The attempt will be timed out - * if the call is not established within {@code timeout} seconds and + * Creates a {@link SipAudioCall} to make an audio call. The attempt will be + * timed out if the call is not established within {@code timeout} seconds + * and * {@code SipAudioCall.Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)} * will be called. * @@ -416,9 +438,11 @@ public class SipManager { /** * Manually registers the profile to the corresponding SIP provider for - * receiving calls. {@link #open(SipProfile, String, SipRegistrationListener)} - * is still needed to be called at least once in order for the SIP service - * to broadcast an intent when an incoming call is received. + * receiving calls. + * {@link #open(SipProfile, PendingIntent, SipRegistrationListener)} is + * still needed to be called at least once in order for the SIP service to + * notify the caller with the {@code PendingIntent} when an incoming call is + * received. * * @param localProfile the SIP profile to register with * @param expiryTime registration expiration time (in seconds) diff --git a/voip/java/com/android/server/sip/SipService.java b/voip/java/com/android/server/sip/SipService.java index 405dff8..a7c61e5 100644 --- a/voip/java/com/android/server/sip/SipService.java +++ b/voip/java/com/android/server/sip/SipService.java @@ -134,14 +134,6 @@ public final class SipService extends ISipService.Stub { public void open(SipProfile localProfile) { localProfile.setCallingUid(Binder.getCallingUid()); - if (localProfile.getAutoRegistration() && isCallerRadio()) { - openToReceiveCalls(localProfile); - } else { - openToMakeCalls(localProfile); - } - } - - private void openToMakeCalls(SipProfile localProfile) { try { createGroup(localProfile); } catch (SipException e) { @@ -150,28 +142,20 @@ public final class SipService extends ISipService.Stub { } } - private void openToReceiveCalls(SipProfile localProfile) { - open3(localProfile, SipManager.ACTION_SIP_INCOMING_CALL, null); - } - public synchronized void open3(SipProfile localProfile, - String incomingCallBroadcastAction, ISipSessionListener listener) { + PendingIntent incomingCallPendingIntent, + ISipSessionListener listener) { localProfile.setCallingUid(Binder.getCallingUid()); - if (TextUtils.isEmpty(incomingCallBroadcastAction)) { - Log.w(TAG, "empty broadcast action for incoming call"); - return; - } - if (incomingCallBroadcastAction.equals( - SipManager.ACTION_SIP_INCOMING_CALL) && !isCallerRadio()) { - Log.w(TAG, "failed to open the profile; " - + "the action string is reserved"); + if (incomingCallPendingIntent == null) { + Log.w(TAG, "incomingCallPendingIntent cannot be null; " + + "the profile is not opened"); return; } if (DEBUG) Log.d(TAG, "open3: " + localProfile.getUriString() + ": " - + incomingCallBroadcastAction + ": " + listener); + + incomingCallPendingIntent + ": " + listener); try { SipSessionGroupExt group = createGroup(localProfile, - incomingCallBroadcastAction, listener); + incomingCallPendingIntent, listener); if (localProfile.getAutoRegistration()) { group.openToReceiveCalls(); if (isWifiOn()) grabWifiLock(); @@ -287,20 +271,19 @@ public final class SipService extends ISipService.Stub { } private SipSessionGroupExt createGroup(SipProfile localProfile, - String incomingCallBroadcastAction, ISipSessionListener listener) - throws SipException { + PendingIntent incomingCallPendingIntent, + ISipSessionListener listener) throws SipException { String key = localProfile.getUriString(); SipSessionGroupExt group = mSipGroups.get(key); if (group != null) { if (!isCallerCreator(group)) { throw new SipException("only creator can access the profile"); } - group.setIncomingCallBroadcastAction( - incomingCallBroadcastAction); + group.setIncomingCallPendingIntent(incomingCallPendingIntent); group.setListener(listener); } else { group = new SipSessionGroupExt(localProfile, - incomingCallBroadcastAction, listener); + incomingCallPendingIntent, listener); mSipGroups.put(key, group); notifyProfileAdded(localProfile); } @@ -405,19 +388,19 @@ public final class SipService extends ISipService.Stub { private class SipSessionGroupExt extends SipSessionAdapter { private SipSessionGroup mSipGroup; - private String mIncomingCallBroadcastAction; + private PendingIntent mIncomingCallPendingIntent; private boolean mOpened; private AutoRegistrationProcess mAutoRegistration = new AutoRegistrationProcess(); public SipSessionGroupExt(SipProfile localProfile, - String incomingCallBroadcastAction, + PendingIntent incomingCallPendingIntent, ISipSessionListener listener) throws SipException { String password = localProfile.getPassword(); SipProfile p = duplicate(localProfile); mSipGroup = createSipSessionGroup(mLocalIp, p, password); - mIncomingCallBroadcastAction = incomingCallBroadcastAction; + mIncomingCallPendingIntent = incomingCallPendingIntent; mAutoRegistration.setListener(listener); } @@ -458,8 +441,8 @@ public final class SipService extends ISipService.Stub { mAutoRegistration.setListener(listener); } - public void setIncomingCallBroadcastAction(String action) { - mIncomingCallBroadcastAction = action; + public void setIncomingCallPendingIntent(PendingIntent pIntent) { + mIncomingCallPendingIntent = pIntent; } public void openToReceiveCalls() throws SipException { @@ -469,7 +452,7 @@ public final class SipService extends ISipService.Stub { mAutoRegistration.start(mSipGroup); } if (DEBUG) Log.d(TAG, " openToReceiveCalls: " + getUri() + ": " - + mIncomingCallBroadcastAction); + + mIncomingCallPendingIntent); } public void onConnectivityChanged(boolean connected) @@ -481,7 +464,7 @@ public final class SipService extends ISipService.Stub { } else { // close mSipGroup but remember mOpened if (DEBUG) Log.d(TAG, " close auto reg temporarily: " - + getUri() + ": " + mIncomingCallBroadcastAction); + + getUri() + ": " + mIncomingCallPendingIntent); mSipGroup.close(); mAutoRegistration.stop(); } @@ -508,7 +491,7 @@ public final class SipService extends ISipService.Stub { mSipGroup.close(); mAutoRegistration.stop(); if (DEBUG) Log.d(TAG, " close: " + getUri() + ": " - + mIncomingCallBroadcastAction); + + mIncomingCallPendingIntent); } public ISipSession createSession(ISipSessionListener listener) { @@ -516,8 +499,10 @@ public final class SipService extends ISipService.Stub { } @Override - public void onRinging(ISipSession session, SipProfile caller, + public void onRinging(ISipSession s, SipProfile caller, String sessionDescription) { + SipSessionGroup.SipSessionImpl session = + (SipSessionGroup.SipSessionImpl) s; synchronized (SipService.this) { try { if (!isRegistered()) { @@ -528,15 +513,15 @@ public final class SipService extends ISipService.Stub { // send out incoming call broadcast addPendingSession(session); Intent intent = SipManager.createIncomingCallBroadcast( - session.getCallId(), sessionDescription) - .setAction(mIncomingCallBroadcastAction); + session.getCallId(), sessionDescription); if (DEBUG) Log.d(TAG, " ringing~~ " + getUri() + ": " + caller.getUri() + ": " + session.getCallId() - + " " + mIncomingCallBroadcastAction); - mContext.sendBroadcast(intent); - } catch (RemoteException e) { - // should never happen with a local call - Log.e(TAG, "processCall()", e); + + " " + mIncomingCallPendingIntent); + mIncomingCallPendingIntent.send(mContext, + SipManager.INCOMING_CALL_RESULT_CODE, intent); + } catch (PendingIntent.CanceledException e) { + Log.w(TAG, "pendingIntent is canceled, drop incoming call"); + session.endCall(); } } } diff --git a/voip/java/com/android/server/sip/SipSessionGroup.java b/voip/java/com/android/server/sip/SipSessionGroup.java index bc377cf..37fffa8 100644 --- a/voip/java/com/android/server/sip/SipSessionGroup.java +++ b/voip/java/com/android/server/sip/SipSessionGroup.java @@ -480,7 +480,7 @@ class SipSessionGroup implements SipListener { public void run() { try { processCommand(command); - } catch (SipException e) { + } catch (Throwable e) { Log.w(TAG, "command error: " + command, e); onError(e); } @@ -1218,7 +1218,7 @@ class SipSessionGroup implements SipListener { private int getErrorCode(Throwable exception) { String message = exception.getMessage(); if (exception instanceof UnknownHostException) { - return SipErrorCode.INVALID_REMOTE_URI; + return SipErrorCode.SERVER_UNREACHABLE; } else if (exception instanceof IOException) { return SipErrorCode.SOCKET_ERROR; } else { diff --git a/voip/jni/rtp/AmrCodec.cpp b/voip/jni/rtp/AmrCodec.cpp index f3ecac2..84c7166 100644 --- a/voip/jni/rtp/AmrCodec.cpp +++ b/voip/jni/rtp/AmrCodec.cpp @@ -73,7 +73,7 @@ int AmrCodec::set(int sampleRate, const char *fmtp) } // Handle mode-set and octet-align. - char *modes = strcasestr(fmtp, "mode-set="); + const char *modes = strcasestr(fmtp, "mode-set="); if (modes) { mMode = 0; mModeSet = 0; diff --git a/voip/jni/rtp/EchoSuppressor.cpp b/voip/jni/rtp/EchoSuppressor.cpp index 92015a9..2ceebdc 100644 --- a/voip/jni/rtp/EchoSuppressor.cpp +++ b/voip/jni/rtp/EchoSuppressor.cpp @@ -16,6 +16,7 @@ #include <stdio.h> #include <stdint.h> +#include <string.h> #include <math.h> #define LOG_TAG "Echo" diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java index 7ea4872..9634157 100644 --- a/wifi/java/android/net/wifi/WifiConfigStore.java +++ b/wifi/java/android/net/wifi/WifiConfigStore.java @@ -20,19 +20,24 @@ import android.app.ActivityManagerNative; import android.content.Context; import android.content.Intent; import android.net.DhcpInfo; +import android.net.ProxyProperties; import android.net.wifi.WifiConfiguration.IpAssignment; import android.net.wifi.WifiConfiguration.KeyMgmt; +import android.net.wifi.WifiConfiguration.ProxySettings; import android.net.wifi.WifiConfiguration.Status; import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID; import android.os.Environment; import android.text.TextUtils; import android.util.Log; -import java.io.BufferedWriter; -import java.io.File; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; import java.io.FileInputStream; -import java.io.FileWriter; +import java.io.FileOutputStream; import java.io.IOException; +import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.BitSet; import java.util.HashMap; @@ -46,8 +51,31 @@ import java.util.List; * It deals with the following * - Add/update/remove a WifiConfiguration * The configuration contains two types of information. - * = IP configuration that is handled by WifiConfigStore and + * = IP and proxy configuration that is handled by WifiConfigStore and * is saved to disk on any change. + * + * The format of configuration file is as follows: + * <version> + * <netA_key1><netA_value1><netA_key2><netA_value2>...<EOS> + * <netB_key1><netB_value1><netB_key2><netB_value2>...<EOS> + * .. + * + * (key, value) pairs for a given network are grouped together and can + * be in any order. A "EOS" at the end of a set of (key, value) pairs + * indicates that the next set of (key, value) pairs are for a new + * network. A network is identified by a unique "id". If there is no + * "id" key in the (key, value) pairs, the data is discarded. An IP + * configuration includes the keys - "ipAssignment", "ipAddress", "gateway", + * "netmask", "dns1" and "dns2". A proxy configuration includes "proxySettings", + * "proxyHost", "proxyPort" and "exclusionList" + * + * An invalid version on read would result in discarding the contents of + * the file. On the next write, the latest version is written to file. + * + * Any failures during read or write to the configuration file are ignored + * without reporting to the user since the likelihood of these errors are + * low and the impact on connectivity is low. + * * = SSID & security details that is pushed to the supplicant. * supplicant saves these details to the disk on calling * saveConfigCommand(). @@ -59,10 +87,9 @@ import java.util.List; * to the disk. (TODO: deprecate these calls in WifiManager) * > The new API calls - selectNetwork(), saveNetwork() & forgetNetwork(). * These calls persist the supplicant config to disk. + * * - Maintain a list of configured networks for quick access * - * TODO: - * - handle proxy per configuration */ class WifiConfigStore { @@ -110,7 +137,7 @@ class WifiConfigStore { List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>(); synchronized (sConfiguredNetworks) { for(WifiConfiguration config : sConfiguredNetworks.values()) { - networks.add(config.clone()); + networks.add(new WifiConfiguration(config)); } } return networks; @@ -229,6 +256,7 @@ class WifiConfigStore { synchronized (sConfiguredNetworks) { sConfiguredNetworks.remove(netId); } + writeIpAndProxyConfigurations(); sendConfigChangeBroadcast(); } else { Log.e(TAG, "Failed to remove network " + netId); @@ -353,6 +381,19 @@ class WifiConfigStore { } /** + * Fetch the proxy properties for a given network id + */ + static ProxyProperties getProxyProperties(int netId) { + synchronized (sConfiguredNetworks) { + WifiConfiguration config = sConfiguredNetworks.get(netId); + if (config != null && config.proxySettings == ProxySettings.STATIC) { + return new ProxyProperties(config.proxyProperties); + } + } + return null; + } + + /** * Return if the specified network is using static IP */ static boolean isUsingStaticIp(int netId) { @@ -411,7 +452,7 @@ class WifiConfigStore { sNetworkIds.put(configKey(config), config.networkId); } } - readIpConfigurations(); + readIpAndProxyConfigurations(); sendConfigChangeBroadcast(); } @@ -430,38 +471,89 @@ class WifiConfigStore { markAllNetworksDisabledExcept(INVALID_NETWORK_ID); } - private static void writeIpConfigurations() { - StringBuilder builder = new StringBuilder(); - BufferedWriter out = null; + private static void writeIpAndProxyConfigurations() { - builder.append(IPCONFIG_FILE_VERSION); - builder.append("\n"); + DataOutputStream out = null; + try { + out = new DataOutputStream(new BufferedOutputStream( + new FileOutputStream(ipConfigFile))); - synchronized (sConfiguredNetworks) { - for(WifiConfiguration config : sConfiguredNetworks.values()) { - if (config.ipAssignment == WifiConfiguration.IpAssignment.STATIC) { - builder.append("id=" + configKey(config)); - builder.append(":"); - builder.append("ip=" + config.ipConfig.ipAddress); - builder.append(":"); - builder.append("gateway=" + config.ipConfig.gateway); - builder.append(":"); - builder.append("netmask=" + config.ipConfig.netmask); - builder.append(":"); - builder.append("dns1=" + config.ipConfig.dns1); - builder.append(":"); - builder.append("dns2=" + config.ipConfig.dns2); - builder.append("\n"); + out.writeInt(IPCONFIG_FILE_VERSION); + + synchronized (sConfiguredNetworks) { + for(WifiConfiguration config : sConfiguredNetworks.values()) { + boolean writeToFile = false; + + switch (config.ipAssignment) { + case STATIC: + out.writeUTF("ipAssignment"); + out.writeUTF(config.ipAssignment.toString()); + out.writeUTF("ipAddress"); + out.writeInt(config.ipConfig.ipAddress); + out.writeUTF("gateway"); + out.writeInt(config.ipConfig.gateway); + out.writeUTF("netmask"); + out.writeInt(config.ipConfig.netmask); + out.writeUTF("dns1"); + out.writeInt(config.ipConfig.dns1); + out.writeUTF("dns2"); + out.writeInt(config.ipConfig.dns2); + writeToFile = true; + break; + case DHCP: + out.writeUTF("ipAssignment"); + out.writeUTF(config.ipAssignment.toString()); + writeToFile = true; + break; + case UNASSIGNED: + /* Ignore */ + break; + default: + Log.e(TAG, "Ignore invalid ip assignment while writing"); + break; + } + + switch (config.proxySettings) { + case STATIC: + out.writeUTF("proxySettings"); + out.writeUTF(config.proxySettings.toString()); + InetSocketAddress proxy = config.proxyProperties.getSocketAddress(); + if (proxy != null) { + out.writeUTF("proxyHost"); + out.writeUTF(proxy.getHostName()); + out.writeUTF("proxyPort"); + out.writeInt(proxy.getPort()); + String exclusionList = config.proxyProperties.getExclusionList(); + if (exclusionList != null && exclusionList.length() > 0) { + out.writeUTF("exclusionList"); + out.writeUTF(exclusionList); + } + } + writeToFile = true; + break; + case NONE: + out.writeUTF("proxySettings"); + out.writeUTF(config.proxySettings.toString()); + writeToFile = true; + break; + case UNASSIGNED: + /* Ignore */ + break; + default: + Log.e(TAG, "Ignore invalid proxy settings while writing"); + break; + } + + if (writeToFile) { + out.writeUTF("id"); + out.writeInt(configKey(config)); + out.writeUTF("EOS"); + } } } - } - try { - out = new BufferedWriter(new FileWriter(ipConfigFile), builder.length()); - out.write(builder.toString()); } catch (IOException e) { Log.e(TAG, "Error writing data file"); - return; } finally { if (out != null) { try { @@ -471,80 +563,116 @@ class WifiConfigStore { } } - private static void readIpConfigurations() { - File f = new File(ipConfigFile); - byte[] buffer; - FileInputStream s = null; - try { - buffer = new byte[(int)f.length()]; - s = new FileInputStream(f); - s.read(buffer); - } catch (IOException e) { - Log.e(TAG, "Error reading data file"); - return; - } finally { - if (s != null) { - try { - s.close(); - } catch (Exception e) {} - } - } + private static void readIpAndProxyConfigurations() { - String data = new String(buffer); - if (data == null || data.length() == 0) { - Log.d(TAG, "IP configuration file empty"); - return; - } - - String[] parsed = data.split("\n"); + DataInputStream in = null; try { - if (Integer.parseInt(parsed[0]) != IPCONFIG_FILE_VERSION) { + in = new DataInputStream(new BufferedInputStream(new FileInputStream( + ipConfigFile))); + + if (in.readInt() != IPCONFIG_FILE_VERSION) { Log.e(TAG, "Bad version on IP configuration file, ignore read"); return; } - for (String line : parsed) { - int hashKey = -1; + while (true) { + int id = -1; + IpAssignment ipAssignment = IpAssignment.UNASSIGNED; DhcpInfo ipConfig = new DhcpInfo(); - String[] keyVals = line.split(":"); - - for (String keyVal : keyVals) { - String[] keyValPair = keyVal.split("="); - if (keyValPair[0].equals("id")) { - hashKey = Integer.parseInt(keyValPair[1]); - } else if (keyValPair[0].equals("ip")) { - ipConfig.ipAddress = Integer.parseInt(keyValPair[1]); - } else if (keyValPair[0].equals("gateway")) { - ipConfig.gateway = Integer.parseInt(keyValPair[1]); - } else if (keyValPair[0].equals("netmask")) { - ipConfig.netmask = Integer.parseInt(keyValPair[1]); - } else if (keyValPair[0].equals("dns1")) { - ipConfig.dns1 = Integer.parseInt(keyValPair[1]); - } else if (keyValPair[0].equals("dns2")) { - ipConfig.dns2 = Integer.parseInt(keyValPair[1]); + ProxySettings proxySettings = ProxySettings.UNASSIGNED; + String proxyHost = null; + int proxyPort = -1; + String exclusionList = null; + String key; + + do { + key = in.readUTF(); + if (key.equals("id")) { + id = in.readInt(); + } else if (key.equals("ipAssignment")) { + ipAssignment = IpAssignment.valueOf(in.readUTF()); + } else if (key.equals("ipAddress")) { + ipConfig.ipAddress = in.readInt(); + } else if (key.equals("gateway")) { + ipConfig.gateway = in.readInt(); + } else if (key.equals("netmask")) { + ipConfig.netmask = in.readInt(); + } else if (key.equals("dns1")) { + ipConfig.dns1 = in.readInt(); + } else if (key.equals("dns2")) { + ipConfig.dns2 = in.readInt(); + } else if (key.equals("proxySettings")) { + proxySettings = ProxySettings.valueOf(in.readUTF()); + } else if (key.equals("proxyHost")) { + proxyHost = in.readUTF(); + } else if (key.equals("proxyPort")) { + proxyPort = in.readInt(); + } else if (key.equals("exclusionList")) { + exclusionList = in.readUTF(); + } else if (key.equals("EOS")) { + break; } else { - Log.w(TAG, "Ignoring " + keyVal); + Log.e(TAG, "Ignore unknown key " + key + "while reading"); } - } + } while (true); - if (hashKey != -1) { + if (id != -1) { synchronized (sConfiguredNetworks) { WifiConfiguration config = sConfiguredNetworks.get( - sNetworkIds.get(hashKey)); + sNetworkIds.get(id)); if (config == null) { - Log.e(TAG, "IP configuration found for missing network, ignored"); + Log.e(TAG, "configuration found for missing network, ignored"); } else { - config.ipAssignment = WifiConfiguration.IpAssignment.STATIC; - config.ipConfig = ipConfig; + switch (ipAssignment) { + case STATIC: + config.ipAssignment = ipAssignment; + config.ipConfig = ipConfig; + break; + case DHCP: + config.ipAssignment = ipAssignment; + break; + case UNASSIGNED: + //Ignore + break; + default: + Log.e(TAG, "Ignore invalid ip assignment while reading"); + break; + } + + switch (proxySettings) { + case STATIC: + config.proxySettings = proxySettings; + ProxyProperties proxyProperties = new ProxyProperties(); + proxyProperties.setSocketAddress( + new InetSocketAddress(proxyHost, proxyPort)); + proxyProperties.setExclusionList(exclusionList); + config.proxyProperties = proxyProperties; + break; + case NONE: + config.proxySettings = proxySettings; + break; + case UNASSIGNED: + //Ignore + break; + default: + Log.e(TAG, "Ignore invalid proxy settings while reading"); + break; + } } } } else { - Log.e(TAG,"Missing id while parsing configuration" + line); + Log.e(TAG,"Missing id while parsing configuration"); } } - } catch (NumberFormatException e) { + } catch (IOException e) { Log.e(TAG, "Error parsing configuration"); + } finally { + if (in != null) { + try { + in.close(); + } catch (Exception e) {} + } } } @@ -759,21 +887,68 @@ class WifiConfigStore { } } readNetworkVariables(sConfig); + writeIpAndProxyConfigurationsOnChange(sConfig, config); + return netId; + } - if (config.ipAssignment != IpAssignment.UNASSIGNED) { + /* Compare current and new configuration and write to file on change */ + private static void writeIpAndProxyConfigurationsOnChange(WifiConfiguration currentConfig, + WifiConfiguration newConfig) { + boolean newNetwork = (newConfig.networkId == INVALID_NETWORK_ID); + boolean writeConfigToFile = false; + + if (newConfig.ipAssignment != IpAssignment.UNASSIGNED) { if (newNetwork || - (sConfig.ipAssignment != config.ipAssignment) || - (sConfig.ipConfig.ipAddress != config.ipConfig.ipAddress) || - (sConfig.ipConfig.gateway != config.ipConfig.gateway) || - (sConfig.ipConfig.netmask != config.ipConfig.netmask) || - (sConfig.ipConfig.dns1 != config.ipConfig.dns1) || - (sConfig.ipConfig.dns2 != config.ipConfig.dns2)) { - sConfig.ipAssignment = config.ipAssignment; - sConfig.ipConfig = config.ipConfig; - writeIpConfigurations(); + (currentConfig.ipAssignment != newConfig.ipAssignment) || + (currentConfig.ipConfig.ipAddress != newConfig.ipConfig.ipAddress) || + (currentConfig.ipConfig.gateway != newConfig.ipConfig.gateway) || + (currentConfig.ipConfig.netmask != newConfig.ipConfig.netmask) || + (currentConfig.ipConfig.dns1 != newConfig.ipConfig.dns1) || + (currentConfig.ipConfig.dns2 != newConfig.ipConfig.dns2)) { + currentConfig.ipAssignment = newConfig.ipAssignment; + currentConfig.ipConfig = newConfig.ipConfig; + writeConfigToFile = true; } } - return netId; + + if (newConfig.proxySettings != ProxySettings.UNASSIGNED) { + InetSocketAddress newSockAddr = newConfig.proxyProperties.getSocketAddress(); + String newExclusionList = newConfig.proxyProperties.getExclusionList(); + + InetSocketAddress currentSockAddr = currentConfig.proxyProperties.getSocketAddress(); + String currentExclusionList = currentConfig.proxyProperties.getExclusionList(); + + boolean socketAddressDiffers = false; + boolean exclusionListDiffers = false; + + if (newSockAddr != null && currentSockAddr != null ) { + socketAddressDiffers = !currentSockAddr.equals(newSockAddr); + } else if (newSockAddr != null || currentSockAddr != null) { + socketAddressDiffers = true; + } + + if (newExclusionList != null && currentExclusionList != null) { + exclusionListDiffers = currentExclusionList.equals(newExclusionList); + } else if (newExclusionList != null || currentExclusionList != null) { + exclusionListDiffers = true; + } + + if (newNetwork || + (currentConfig.proxySettings != newConfig.proxySettings) || + socketAddressDiffers || + exclusionListDiffers) { + currentConfig.proxySettings = newConfig.proxySettings; + currentConfig.proxyProperties = newConfig.proxyProperties; + Log.d(TAG, "proxy change SSID = " + currentConfig.SSID + " proxyProperties: " + + currentConfig.proxyProperties.toString()); + writeConfigToFile = true; + } + } + + if (writeConfigToFile) { + writeIpAndProxyConfigurations(); + sendConfigChangeBroadcast(); + } } /** diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index 57e9bad..c4a1310 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -17,6 +17,7 @@ package android.net.wifi; import android.net.DhcpInfo; +import android.net.ProxyProperties; import android.os.Parcelable; import android.os.Parcel; @@ -301,8 +302,13 @@ public class WifiConfiguration implements Parcelable { * @hide */ public enum IpAssignment { + /* Use statically configured IP settings. Configuration can be accessed + * with ipConfig */ STATIC, + /* Use dynamically configured IP settigns */ DHCP, + /* no IP details are assigned, this is used to indicate + * that any existing IP settings should be retained */ UNASSIGNED } /** @@ -314,6 +320,29 @@ public class WifiConfiguration implements Parcelable { */ public DhcpInfo ipConfig; + /** + * @hide + */ + public enum ProxySettings { + /* No proxy is to be used. Any existing proxy settings + * should be cleared. */ + NONE, + /* Use statically configured proxy. Configuration can be accessed + * with proxyProperties */ + STATIC, + /* no proxy details are assigned, this is used to indicate + * that any existing proxy settings should be retained */ + UNASSIGNED + } + /** + * @hide + */ + public ProxySettings proxySettings; + /** + * @hide + */ + public ProxyProperties proxyProperties; + public WifiConfiguration() { networkId = INVALID_NETWORK_ID; SSID = null; @@ -333,6 +362,8 @@ public class WifiConfiguration implements Parcelable { } ipAssignment = IpAssignment.UNASSIGNED; ipConfig = new DhcpInfo(); + proxySettings = ProxySettings.UNASSIGNED; + proxyProperties = new ProxyProperties(); } public String toString() { @@ -419,6 +450,12 @@ public class WifiConfiguration implements Parcelable { sbuf.append(" ").append(ipConfig); } sbuf.append('\n'); + + if (proxySettings == ProxySettings.STATIC) { + sbuf.append(" ").append("Proxy configuration:").append('\n'); + sbuf.append(" ").append(proxyProperties); + } + sbuf.append('\n'); return sbuf.toString(); } @@ -458,38 +495,36 @@ public class WifiConfiguration implements Parcelable { return 0; } - /** - * Returns a copy of this WifiConfiguration. - * - * @return a copy of this WifiConfiguration. - * @hide - */ - public WifiConfiguration clone() { - WifiConfiguration config = new WifiConfiguration(); - config.networkId = networkId; - config.status = status; - config.SSID = SSID; - config.BSSID = BSSID; - config.preSharedKey = preSharedKey; - - for (int i = 0; i < wepKeys.length; i++) - config.wepKeys[i] = wepKeys[i]; - - config.wepTxKeyIndex = wepTxKeyIndex; - config.priority = priority; - config.hiddenSSID = hiddenSSID; - config.allowedKeyManagement = (BitSet) allowedKeyManagement.clone(); - config.allowedProtocols = (BitSet) allowedProtocols.clone(); - config.allowedAuthAlgorithms = (BitSet) allowedAuthAlgorithms.clone(); - config.allowedPairwiseCiphers = (BitSet) allowedPairwiseCiphers.clone(); - config.allowedGroupCiphers = (BitSet) allowedGroupCiphers.clone(); - - for (int i = 0; i < enterpriseFields.length; i++) { - config.enterpriseFields[i].setValue(enterpriseFields[i].value()); + /** copy constructor {@hide} */ + public WifiConfiguration(WifiConfiguration source) { + if (source != null) { + networkId = source.networkId; + status = source.status; + SSID = source.SSID; + BSSID = source.BSSID; + preSharedKey = source.preSharedKey; + + wepKeys = new String[4]; + for (int i = 0; i < wepKeys.length; i++) + wepKeys[i] = source.wepKeys[i]; + + wepTxKeyIndex = source.wepTxKeyIndex; + priority = source.priority; + hiddenSSID = source.hiddenSSID; + allowedKeyManagement = (BitSet) source.allowedKeyManagement.clone(); + allowedProtocols = (BitSet) source.allowedProtocols.clone(); + allowedAuthAlgorithms = (BitSet) source.allowedAuthAlgorithms.clone(); + allowedPairwiseCiphers = (BitSet) source.allowedPairwiseCiphers.clone(); + allowedGroupCiphers = (BitSet) source.allowedGroupCiphers.clone(); + + for (int i = 0; i < source.enterpriseFields.length; i++) { + enterpriseFields[i].setValue(source.enterpriseFields[i].value()); + } + ipAssignment = source.ipAssignment; + ipConfig = new DhcpInfo(source.ipConfig); + proxySettings = source.proxySettings; + proxyProperties = new ProxyProperties(source.proxyProperties); } - config.ipAssignment = ipAssignment; - config.ipConfig = new DhcpInfo(ipConfig); - return config; } /** Implement the Parcelable interface {@hide} */ @@ -522,6 +557,8 @@ public class WifiConfiguration implements Parcelable { dest.writeInt(ipConfig.dns2); dest.writeInt(ipConfig.serverAddress); dest.writeInt(ipConfig.leaseDuration); + dest.writeString(proxySettings.name()); + dest.writeParcelable(proxyProperties, flags); } /** Implement the Parcelable interface {@hide} */ @@ -557,6 +594,8 @@ public class WifiConfiguration implements Parcelable { config.ipConfig.dns2 = in.readInt(); config.ipConfig.serverAddress = in.readInt(); config.ipConfig.leaseDuration = in.readInt(); + config.proxySettings = ProxySettings.valueOf(in.readString()); + config.proxyProperties = in.readParcelable(null); return config; } diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java index e82c003..572abc0 100644 --- a/wifi/java/android/net/wifi/WifiStateMachine.java +++ b/wifi/java/android/net/wifi/WifiStateMachine.java @@ -38,12 +38,14 @@ import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING; import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED; import android.app.ActivityManagerNative; +import android.net.LinkAddress; import android.net.NetworkInfo; import android.net.DhcpInfo; import android.net.NetworkUtils; import android.net.ConnectivityManager; import android.net.NetworkInfo.DetailedState; import android.net.LinkProperties; +import android.net.ProxyProperties; import android.net.wifi.WifiConfiguration.Status; import android.os.Binder; import android.os.Message; @@ -1251,24 +1253,25 @@ public class WifiStateMachine extends HierarchicalStateMachine { } private void configureLinkProperties() { - try { - mLinkProperties.setInterface(NetworkInterface.getByName(mInterfaceName)); - } catch (SocketException e) { - Log.e(TAG, "SocketException creating NetworkInterface from " + mInterfaceName + - ". e=" + e); - return; - } catch (NullPointerException e) { - Log.e(TAG, "NPE creating NetworkInterface. e=" + e); - return; - } + + mLinkProperties.setInterfaceName(mInterfaceName); + // TODO - fix this for v6 synchronized (mDhcpInfo) { - mLinkProperties.addAddress(NetworkUtils.intToInetAddress(mDhcpInfo.ipAddress)); + mLinkProperties.addLinkAddress(new LinkAddress( + NetworkUtils.intToInetAddress(mDhcpInfo.ipAddress), + NetworkUtils.intToInetAddress(mDhcpInfo.netmask))); mLinkProperties.setGateway(NetworkUtils.intToInetAddress(mDhcpInfo.gateway)); mLinkProperties.addDns(NetworkUtils.intToInetAddress(mDhcpInfo.dns1)); mLinkProperties.addDns(NetworkUtils.intToInetAddress(mDhcpInfo.dns2)); } - // TODO - add proxy info + + ProxyProperties proxyProperties = WifiConfigStore.getProxyProperties(mLastNetworkId); + if (proxyProperties != null) { + mLinkProperties.setHttpProxy(proxyProperties); + Log.d(TAG, "netId=" + mLastNetworkId + " proxy configured: " + + proxyProperties.toString()); + } } private int getMaxDhcpRetries() { |