diff options
145 files changed, 3847 insertions, 2539 deletions
diff --git a/api/current.xml b/api/current.xml index 956f2b8..98ced39 100644 --- a/api/current.xml +++ b/api/current.xml @@ -947,6 +947,17 @@ visibility="public" > </field> +<field name="SET_ALARM" + type="java.lang.String" + transient="false" + volatile="false" + value=""com.android.alarm.permission.SET_ALARM"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="SET_ALWAYS_FINISH" type="java.lang.String" transient="false" @@ -4695,17 +4706,6 @@ visibility="public" > </field> -<field name="immersive" - type="int" - transient="false" - volatile="false" - value="16843456" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> <field name="inAnimation" type="int" transient="false" @@ -6411,17 +6411,6 @@ visibility="public" > </field> -<field name="logo" - type="int" - transient="false" - volatile="false" - value="16843454" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> <field name="longClickable" type="int" transient="false" @@ -95431,6 +95420,17 @@ visibility="public" > </field> +<field name="ACTION_VIEW_DOWNLOADS" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.intent.action.VIEW_DOWNLOADS"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="COLUMN_BYTES_DOWNLOADED_SO_FAR" type="java.lang.String" transient="false" @@ -131718,6 +131718,67 @@ </package> <package name="android.provider" > +<class name="AlarmClock" + extends="java.lang.Object" + abstract="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +<constructor name="AlarmClock" + type="android.provider.AlarmClock" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</constructor> +<field name="ACTION_SET_ALARM" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.intent.action.SET_ALARM"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="EXTRA_HOUR" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.intent.extra.alarm.HOUR"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="EXTRA_MESSAGE" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.intent.extra.alarm.MESSAGE"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="EXTRA_MINUTES" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.intent.extra.alarm.MINUTES"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +</class> <interface name="BaseColumns" abstract="true" static="false" diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 301883f..f2aa91f 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -19,6 +19,7 @@ package com.android.commands.am; import android.app.ActivityManagerNative; +import android.app.IActivityController; import android.app.IActivityManager; import android.app.IInstrumentationWatcher; import android.app.Instrumentation; @@ -33,8 +34,11 @@ import android.os.ServiceManager; import android.util.AndroidException; import android.view.IWindowManager; +import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; import java.io.PrintStream; import java.net.URISyntaxException; import java.util.Iterator; @@ -98,6 +102,8 @@ public class Am { sendBroadcast(); } else if (op.equals("profile")) { runProfile(); + } else if (op.equals("monitor")) { + runMonitor(); } else { throw new IllegalArgumentException("Unknown command: " + op); } @@ -424,6 +430,303 @@ public class Am { } } + class MyActivityController extends IActivityController.Stub { + final String mGdbPort; + + static final int STATE_NORMAL = 0; + static final int STATE_CRASHED = 1; + static final int STATE_EARLY_ANR = 2; + static final int STATE_ANR = 3; + + int mState; + + static final int RESULT_DEFAULT = 0; + + static final int RESULT_CRASH_DIALOG = 0; + static final int RESULT_CRASH_KILL = 1; + + static final int RESULT_EARLY_ANR_CONTINUE = 0; + static final int RESULT_EARLY_ANR_KILL = 1; + + static final int RESULT_ANR_DIALOG = 0; + static final int RESULT_ANR_KILL = 1; + static final int RESULT_ANR_WAIT = 1; + + int mResult; + + Process mGdbProcess; + Thread mGdbThread; + boolean mGotGdbPrint; + + MyActivityController(String gdbPort) { + mGdbPort = gdbPort; + } + + @Override + public boolean activityResuming(String pkg) throws RemoteException { + synchronized (this) { + System.out.println("** Activity resuming: " + pkg); + } + return true; + } + + @Override + public boolean activityStarting(Intent intent, String pkg) throws RemoteException { + synchronized (this) { + System.out.println("** Activity starting: " + pkg); + } + return true; + } + + @Override + public boolean appCrashed(String processName, int pid, String shortMsg, String longMsg, + long timeMillis, String stackTrace) throws RemoteException { + synchronized (this) { + System.out.println("** ERROR: PROCESS CRASHED"); + System.out.println("processName: " + processName); + System.out.println("processPid: " + pid); + System.out.println("shortMsg: " + shortMsg); + System.out.println("longMsg: " + longMsg); + System.out.println("timeMillis: " + timeMillis); + System.out.println("stack:"); + System.out.print(stackTrace); + System.out.println("#"); + int result = waitControllerLocked(pid, STATE_CRASHED); + return result == RESULT_CRASH_KILL ? false : true; + } + } + + @Override + public int appEarlyNotResponding(String processName, int pid, String annotation) + throws RemoteException { + synchronized (this) { + System.out.println("** ERROR: EARLY PROCESS NOT RESPONDING"); + System.out.println("processName: " + processName); + System.out.println("processPid: " + pid); + System.out.println("annotation: " + annotation); + int result = waitControllerLocked(pid, STATE_EARLY_ANR); + if (result == RESULT_EARLY_ANR_KILL) return -1; + return 0; + } + } + + @Override + public int appNotResponding(String processName, int pid, String processStats) + throws RemoteException { + synchronized (this) { + System.out.println("** ERROR: PROCESS NOT RESPONDING"); + System.out.println("processName: " + processName); + System.out.println("processPid: " + pid); + System.out.println("processStats:"); + System.out.print(processStats); + System.out.println("#"); + int result = waitControllerLocked(pid, STATE_ANR); + if (result == RESULT_ANR_KILL) return -1; + if (result == RESULT_ANR_WAIT) return 1; + return 0; + } + } + + void killGdbLocked() { + mGotGdbPrint = false; + if (mGdbProcess != null) { + System.out.println("Stopping gdbserver"); + mGdbProcess.destroy(); + mGdbProcess = null; + } + if (mGdbThread != null) { + mGdbThread.interrupt(); + mGdbThread = null; + } + } + + int waitControllerLocked(int pid, int state) { + if (mGdbPort != null) { + killGdbLocked(); + + try { + System.out.println("Starting gdbserver on port " + mGdbPort); + System.out.println("Do the following:"); + System.out.println(" adb forward tcp:" + mGdbPort + " tcp:" + mGdbPort); + System.out.println(" gdbclient app_process :" + mGdbPort); + + mGdbProcess = Runtime.getRuntime().exec(new String[] { + "gdbserver", ":" + mGdbPort, "--attach", Integer.toString(pid) + }); + final InputStreamReader converter = new InputStreamReader( + mGdbProcess.getInputStream()); + mGdbThread = new Thread() { + @Override + public void run() { + BufferedReader in = new BufferedReader(converter); + String line; + int count = 0; + while (true) { + synchronized (MyActivityController.this) { + if (mGdbThread == null) { + return; + } + if (count == 2) { + mGotGdbPrint = true; + MyActivityController.this.notifyAll(); + } + } + try { + line = in.readLine(); + if (line == null) { + return; + } + System.out.println("GDB: " + line); + count++; + } catch (IOException e) { + return; + } + } + } + }; + mGdbThread.start(); + + // Stupid waiting for .5s. Doesn't matter if we end early. + try { + this.wait(500); + } catch (InterruptedException e) { + } + + } catch (IOException e) { + System.err.println("Failure starting gdbserver: " + e); + killGdbLocked(); + } + } + mState = state; + System.out.println(""); + printMessageForState(); + + while (mState != STATE_NORMAL) { + try { + wait(); + } catch (InterruptedException e) { + } + } + + killGdbLocked(); + + return mResult; + } + + void resumeController(int result) { + synchronized (this) { + mState = STATE_NORMAL; + mResult = result; + notifyAll(); + } + } + + void printMessageForState() { + switch (mState) { + case STATE_NORMAL: + System.out.println("Monitoring activity manager... available commands:"); + break; + case STATE_CRASHED: + System.out.println("Waiting after crash... available commands:"); + System.out.println("(c)ontinue: show crash dialog"); + System.out.println("(k)ill: immediately kill app"); + break; + case STATE_EARLY_ANR: + System.out.println("Waiting after early ANR... available commands:"); + System.out.println("(c)ontinue: standard ANR processing"); + System.out.println("(k)ill: immediately kill app"); + break; + case STATE_ANR: + System.out.println("Waiting after ANR... available commands:"); + System.out.println("(c)ontinue: show ANR dialog"); + System.out.println("(k)ill: immediately kill app"); + System.out.println("(w)ait: wait some more"); + break; + } + System.out.println("(q)uit: finish monitoring"); + } + + void run() throws RemoteException { + try { + printMessageForState(); + + mAm.setActivityController(this); + mState = STATE_NORMAL; + + InputStreamReader converter = new InputStreamReader(System.in); + BufferedReader in = new BufferedReader(converter); + String line; + + while ((line = in.readLine()) != null) { + boolean addNewline = true; + if (line.length() <= 0) { + addNewline = false; + } else if ("q".equals(line) || "quit".equals(line)) { + resumeController(RESULT_DEFAULT); + break; + } else if (mState == STATE_CRASHED) { + if ("c".equals(line) || "continue".equals(line)) { + resumeController(RESULT_CRASH_DIALOG); + } else if ("k".equals(line) || "kill".equals(line)) { + resumeController(RESULT_CRASH_KILL); + } else { + System.out.println("Invalid command: " + line); + } + } else if (mState == STATE_ANR) { + if ("c".equals(line) || "continue".equals(line)) { + resumeController(RESULT_ANR_DIALOG); + } else if ("k".equals(line) || "kill".equals(line)) { + resumeController(RESULT_ANR_KILL); + } else if ("w".equals(line) || "wait".equals(line)) { + resumeController(RESULT_ANR_WAIT); + } else { + System.out.println("Invalid command: " + line); + } + } else if (mState == STATE_EARLY_ANR) { + if ("c".equals(line) || "continue".equals(line)) { + resumeController(RESULT_EARLY_ANR_CONTINUE); + } else if ("k".equals(line) || "kill".equals(line)) { + resumeController(RESULT_EARLY_ANR_KILL); + } else { + System.out.println("Invalid command: " + line); + } + } else { + System.out.println("Invalid command: " + line); + } + + synchronized (this) { + if (addNewline) { + System.out.println(""); + } + printMessageForState(); + } + } + + } catch (IOException e) { + e.printStackTrace(); + } finally { + mAm.setActivityController(null); + } + } + } + + private void runMonitor() throws Exception { + String opt; + String gdbPort = null; + while ((opt=nextOption()) != null) { + if (opt.equals("--gdb")) { + gdbPort = nextArgRequired(); + } else { + System.err.println("Error: Unknown option: " + opt); + showUsage(); + return; + } + } + + MyActivityController controller = new MyActivityController(gdbPort); + controller.run(); + } + private class IntentReceiver extends IIntentReceiver.Stub { private boolean mFinished = false; @@ -594,6 +897,9 @@ public class Am { " start profiling: am profile <PROCESS> start <FILE>\n" + " stop profiling: am profile <PROCESS> stop\n" + "\n" + + " start monitoring: am monitor [--gdb <port>]\n" + + " --gdb: start gdbserv on the given port at crash/ANR\n" + + "\n" + " <INTENT> specifications include these flags:\n" + " [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" + " [-c <CATEGORY> [-c <CATEGORY>] ...]\n" + diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c index 6e9caaf..822f62d 100644 --- a/cmds/dumpstate/dumpstate.c +++ b/cmds/dumpstate/dumpstate.c @@ -122,11 +122,11 @@ static void dumpstate() { run_command("PROCESSES AND THREADS", 10, "ps", "-t", "-p", "-P", NULL); run_command("LIBRANK", 10, "librank", NULL); - dump_file("BINDER FAILED TRANSACTION LOG", "/proc/binder/failed_transaction_log"); - dump_file("BINDER TRANSACTION LOG", "/proc/binder/transaction_log"); - dump_file("BINDER TRANSACTIONS", "/proc/binder/transactions"); - dump_file("BINDER STATS", "/proc/binder/stats"); - run_command("BINDER PROCESS STATE", 10, "sh", "-c", "cat /proc/binder/proc/*"); + dump_file("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log"); + dump_file("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log"); + dump_file("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions"); + dump_file("BINDER STATS", "/sys/kernel/debug/binder/stats"); + dump_file("BINDER STATE", "/sys/kernel/debug/binder/state"); run_command("FILESYSTEMS & FREE SPACE", 10, "df", NULL); diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp index 8ab94ad..8b54871 100644 --- a/cmds/stagefright/stagefright.cpp +++ b/cmds/stagefright/stagefright.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 +#define LOG_TAG "stagefright" +#include <media/stagefright/foundation/ADebug.h> + #include <sys/time.h> #include <stdlib.h> @@ -27,10 +31,11 @@ #include <media/IMediaPlayerService.h> #include <media/stagefright/foundation/ALooper.h> #include "include/ARTSPController.h" +#include "include/LiveSource.h" +#include "include/NuCachedSource2.h" #include <media/stagefright/AudioPlayer.h> #include <media/stagefright/DataSource.h> #include <media/stagefright/JPEGSource.h> -#include <media/stagefright/MediaDebug.h> #include <media/stagefright/MediaDefs.h> #include <media/stagefright/MediaErrors.h> #include <media/stagefright/MediaExtractor.h> @@ -43,6 +48,8 @@ #include <media/stagefright/foundation/hexdump.h> #include <media/stagefright/MPEG4Writer.h> +#include <fcntl.h> + using namespace android; static long gNumRepetitions; @@ -120,7 +127,7 @@ static void playSource(OMXClient *client, sp<MediaSource> &source) { bool shouldSeek = false; if (err == INFO_FORMAT_CHANGED) { - CHECK_EQ(buffer, NULL); + CHECK(buffer == NULL); printf("format changed.\n"); continue; @@ -206,7 +213,7 @@ static void playSource(OMXClient *client, sp<MediaSource> &source) { options.clearSeekTo(); if (err != OK) { - CHECK_EQ(buffer, NULL); + CHECK(buffer == NULL); if (err == INFO_FORMAT_CHANGED) { printf("format changed.\n"); @@ -267,14 +274,115 @@ static void playSource(OMXClient *client, sp<MediaSource> &source) { } } -static void writeSourceToMP4(const sp<MediaSource> &source) { +//////////////////////////////////////////////////////////////////////////////// + +struct DetectSyncSource : public MediaSource { + DetectSyncSource(const sp<MediaSource> &source); + + virtual status_t start(MetaData *params = NULL); + virtual status_t stop(); + virtual sp<MetaData> getFormat(); + + virtual status_t read( + MediaBuffer **buffer, const ReadOptions *options); + +private: + enum StreamType { + AVC, + MPEG4, + H263, + OTHER, + }; + + sp<MediaSource> mSource; + StreamType mStreamType; + + DISALLOW_EVIL_CONSTRUCTORS(DetectSyncSource); +}; + +DetectSyncSource::DetectSyncSource(const sp<MediaSource> &source) + : mSource(source), + mStreamType(OTHER) { + const char *mime; + CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime)); + + if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { + mStreamType = AVC; + } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)) { + mStreamType = MPEG4; + CHECK(!"sync frame detection not implemented yet for MPEG4"); + } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_H263)) { + mStreamType = H263; + CHECK(!"sync frame detection not implemented yet for H.263"); + } +} + +status_t DetectSyncSource::start(MetaData *params) { + return mSource->start(params); +} + +status_t DetectSyncSource::stop() { + return mSource->stop(); +} + +sp<MetaData> DetectSyncSource::getFormat() { + return mSource->getFormat(); +} + +static bool isIDRFrame(MediaBuffer *buffer) { + const uint8_t *data = + (const uint8_t *)buffer->data() + buffer->range_offset(); + size_t size = buffer->range_length(); + for (size_t i = 0; i + 3 < size; ++i) { + if (!memcmp("\x00\x00\x01", &data[i], 3)) { + uint8_t nalType = data[i + 3] & 0x1f; + if (nalType == 5) { + return true; + } + } + } + + return false; +} + +status_t DetectSyncSource::read( + MediaBuffer **buffer, const ReadOptions *options) { + status_t err = mSource->read(buffer, options); + + if (err != OK) { + return err; + } + + if (mStreamType == AVC && isIDRFrame(*buffer)) { + (*buffer)->meta_data()->setInt32(kKeyIsSyncFrame, true); + } else { + (*buffer)->meta_data()->setInt32(kKeyIsSyncFrame, true); + } + + return OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +static void writeSourcesToMP4( + Vector<sp<MediaSource> > &sources, bool syncInfoPresent) { sp<MPEG4Writer> writer = new MPEG4Writer(gWriteMP4Filename.string()); - CHECK_EQ(writer->addSource(source), OK); + // at most one minute. + writer->setMaxFileDuration(60000000ll); + + for (size_t i = 0; i < sources.size(); ++i) { + sp<MediaSource> source = sources.editItemAt(i); + + CHECK_EQ(writer->addSource( + syncInfoPresent ? source : new DetectSyncSource(source)), + (status_t)OK); + } sp<MetaData> params = new MetaData; - CHECK_EQ(writer->start(), OK); + params->setInt32(kKeyNotRealTime, true); + CHECK_EQ(writer->start(params.get()), (status_t)OK); while (!writer->reachedEOS()) { usleep(100000); @@ -283,7 +391,7 @@ static void writeSourceToMP4(const sp<MediaSource> &source) { } static void performSeekTest(const sp<MediaSource> &source) { - CHECK_EQ(OK, source->start()); + CHECK_EQ((status_t)OK, source->start()); int64_t durationUs; CHECK(source->getFormat()->findInt64(kKeyDuration, &durationUs)); @@ -335,7 +443,7 @@ static void performSeekTest(const sp<MediaSource> &source) { } } - CHECK_EQ(OK, source->stop()); + CHECK_EQ((status_t)OK, source->stop()); } static void usage(const char *me) { @@ -481,10 +589,10 @@ int main(int argc, char **argv) { for (int k = 0; k < argc; ++k) { const char *filename = argv[k]; - CHECK_EQ(retriever->setDataSource(filename), OK); + CHECK_EQ(retriever->setDataSource(filename), (status_t)OK); CHECK_EQ(retriever->setMode( METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL), - OK); + (status_t)OK); sp<IMemory> mem = retriever->captureFrame(); @@ -530,7 +638,7 @@ int main(int argc, char **argv) { Vector<CodecCapabilities> results; CHECK_EQ(QueryCodecs(omx, kMimeTypes[k], true, // queryDecoders - &results), OK); + &results), (status_t)OK); for (size_t i = 0; i < results.size(); ++i) { printf(" decoder '%s' supports ", @@ -579,12 +687,16 @@ int main(int argc, char **argv) { status_t err = client.connect(); for (int k = 0; k < argc; ++k) { + bool syncInfoPresent = true; + const char *filename = argv[k]; sp<DataSource> dataSource = DataSource::CreateFromURI(filename); - if ((strncasecmp(filename, "sine:", 5) - && strncasecmp(filename, "rtsp://", 7)) && dataSource == NULL) { + if (strncasecmp(filename, "sine:", 5) + && strncasecmp(filename, "rtsp://", 7) + && strncasecmp(filename, "httplive://", 11) + && dataSource == NULL) { fprintf(stderr, "Unable to create data source.\n"); return 1; } @@ -596,10 +708,14 @@ int main(int argc, char **argv) { isJPEG = true; } + Vector<sp<MediaSource> > mediaSources; sp<MediaSource> mediaSource; if (isJPEG) { mediaSource = new JPEGSource(dataSource); + if (gWriteMP4) { + mediaSources.push(mediaSource); + } } else if (!strncasecmp("sine:", filename, 5)) { char *end; long sampleRate = strtol(filename + 5, &end, 10); @@ -608,6 +724,9 @@ int main(int argc, char **argv) { sampleRate = 44100; } mediaSource = new SineSource(sampleRate, 1); + if (gWriteMP4) { + mediaSources.push(mediaSource); + } } else { sp<MediaExtractor> extractor; @@ -625,6 +744,20 @@ int main(int argc, char **argv) { } extractor = rtspController.get(); + + syncInfoPresent = false; + } else if (!strncasecmp("httplive://", filename, 11)) { + String8 uri("http://"); + uri.append(filename + 11); + + dataSource = new LiveSource(uri.string()); + dataSource = new NuCachedSource2(dataSource); + + extractor = + MediaExtractor::Create( + dataSource, MEDIA_MIMETYPE_CONTAINER_MPEG2TS); + + syncInfoPresent = false; } else { extractor = MediaExtractor::Create(dataSource); if (extractor == NULL) { @@ -635,46 +768,75 @@ int main(int argc, char **argv) { size_t numTracks = extractor->countTracks(); - sp<MetaData> meta; - size_t i; - for (i = 0; i < numTracks; ++i) { - meta = extractor->getTrackMetaData( - i, MediaExtractor::kIncludeExtensiveMetaData); + if (gWriteMP4) { + bool haveAudio = false; + bool haveVideo = false; + for (size_t i = 0; i < numTracks; ++i) { + sp<MediaSource> source = extractor->getTrack(i); + + const char *mime; + CHECK(source->getFormat()->findCString( + kKeyMIMEType, &mime)); + + bool useTrack = false; + if (!haveAudio && !strncasecmp("audio/", mime, 6)) { + haveAudio = true; + useTrack = true; + } else if (!haveVideo && !strncasecmp("video/", mime, 6)) { + haveVideo = true; + useTrack = true; + } - const char *mime; - meta->findCString(kKeyMIMEType, &mime); + if (useTrack) { + mediaSources.push(source); - if (audioOnly && !strncasecmp(mime, "audio/", 6)) { - break; + if (haveAudio && haveVideo) { + break; + } + } } + } else { + sp<MetaData> meta; + size_t i; + for (i = 0; i < numTracks; ++i) { + meta = extractor->getTrackMetaData( + i, MediaExtractor::kIncludeExtensiveMetaData); - if (!audioOnly && !strncasecmp(mime, "video/", 6)) { - break; + const char *mime; + meta->findCString(kKeyMIMEType, &mime); + + if (audioOnly && !strncasecmp(mime, "audio/", 6)) { + break; + } + + if (!audioOnly && !strncasecmp(mime, "video/", 6)) { + break; + } + + meta = NULL; } - meta = NULL; - } + if (meta == NULL) { + fprintf(stderr, + "No suitable %s track found. The '-a' option will " + "target audio tracks only, the default is to target " + "video tracks only.\n", + audioOnly ? "audio" : "video"); + return -1; + } - if (meta == NULL) { - fprintf(stderr, - "No suitable %s track found. The '-a' option will " - "target audio tracks only, the default is to target " - "video tracks only.\n", - audioOnly ? "audio" : "video"); - return -1; - } + int64_t thumbTimeUs; + if (meta->findInt64(kKeyThumbnailTime, &thumbTimeUs)) { + printf("thumbnailTime: %lld us (%.2f secs)\n", + thumbTimeUs, thumbTimeUs / 1E6); + } - int64_t thumbTimeUs; - if (meta->findInt64(kKeyThumbnailTime, &thumbTimeUs)) { - printf("thumbnailTime: %lld us (%.2f secs)\n", - thumbTimeUs, thumbTimeUs / 1E6); + mediaSource = extractor->getTrack(i); } - - mediaSource = extractor->getTrack(i); } if (gWriteMP4) { - writeSourceToMP4(mediaSource); + writeSourcesToMP4(mediaSources, syncInfoPresent); } else if (seekTest) { performSeekTest(mediaSource); } else { diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 3c7bebf..6d1bf96 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -60,6 +60,7 @@ import android.util.Config; import android.util.DisplayMetrics; import android.util.EventLog; import android.util.Log; +import android.util.LogPrinter; import android.util.Slog; import android.view.Display; import android.view.View; @@ -118,6 +119,7 @@ public final class ActivityThread { private static final android.graphics.Bitmap.Config THUMBNAIL_FORMAT = Bitmap.Config.RGB_565; private static final boolean DEBUG = false; static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; + static final boolean DEBUG_MESSAGES = false; static final boolean DEBUG_BROADCAST = false; private static final boolean DEBUG_RESULTS = false; private static final boolean DEBUG_BACKUP = false; @@ -874,7 +876,7 @@ public final class ActivityThread { public static final int DISPATCH_PACKAGE_BROADCAST = 133; public static final int SCHEDULE_CRASH = 134; String codeToString(int code) { - if (localLOGV) { + if (DEBUG_MESSAGES) { switch (code) { case LAUNCH_ACTIVITY: return "LAUNCH_ACTIVITY"; case PAUSE_ACTIVITY: return "PAUSE_ACTIVITY"; @@ -916,6 +918,7 @@ public final class ActivityThread { return "(unknown)"; } public void handleMessage(Message msg) { + if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + msg.what); switch (msg.what) { case LAUNCH_ACTIVITY: { ActivityClientRecord r = (ActivityClientRecord)msg.obj; @@ -1037,6 +1040,7 @@ public final class ActivityThread { case SCHEDULE_CRASH: throw new RemoteServiceException((String)msg.obj); } + if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + msg.what); } void maybeSnapshot() { @@ -1484,7 +1488,7 @@ public final class ActivityThread { private final void queueOrSendMessage(int what, Object obj, int arg1, int arg2) { synchronized (this) { - if (localLOGV) Slog.v( + if (DEBUG_MESSAGES) Slog.v( TAG, "SCHEDULE " + what + " " + mH.codeToString(what) + ": " + arg1 + " / " + obj); Message msg = Message.obtain(); @@ -3608,6 +3612,11 @@ public final class ActivityThread { ActivityThread thread = new ActivityThread(); thread.attach(false); + if (false) { + Looper.myLooper().setMessageLogging(new + LogPrinter(Log.DEBUG, "ActivityThread")); + } + Looper.loop(); if (Process.supportsProcesses()) { diff --git a/core/java/android/app/IActivityController.aidl b/core/java/android/app/IActivityController.aidl index c76a517..aca8305 100644 --- a/core/java/android/app/IActivityController.aidl +++ b/core/java/android/app/IActivityController.aidl @@ -48,6 +48,11 @@ interface IActivityController long timeMillis, String stackTrace); /** + * Early call as soon as an ANR is detected. + */ + int appEarlyNotResponding(String processName, int pid, String annotation); + + /** * An application process is not responding. Return 0 to show the "app * not responding" dialog, 1 to continue waiting, or -1 to kill it * immediately. diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index e20cb5e..1f21672 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -1252,8 +1252,7 @@ public class PackageParser { "<permission-group>", sa, com.android.internal.R.styleable.AndroidManifestPermissionGroup_name, com.android.internal.R.styleable.AndroidManifestPermissionGroup_label, - com.android.internal.R.styleable.AndroidManifestPermissionGroup_icon, - com.android.internal.R.styleable.AndroidManifestPermissionGroup_logo)) { + com.android.internal.R.styleable.AndroidManifestPermissionGroup_icon, 0)) { sa.recycle(); mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return null; @@ -1288,8 +1287,7 @@ public class PackageParser { "<permission>", sa, com.android.internal.R.styleable.AndroidManifestPermission_name, com.android.internal.R.styleable.AndroidManifestPermission_label, - com.android.internal.R.styleable.AndroidManifestPermission_icon, - com.android.internal.R.styleable.AndroidManifestPermission_logo)) { + com.android.internal.R.styleable.AndroidManifestPermission_icon, 0)) { sa.recycle(); mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return null; @@ -1342,8 +1340,7 @@ public class PackageParser { "<permission-tree>", sa, com.android.internal.R.styleable.AndroidManifestPermissionTree_name, com.android.internal.R.styleable.AndroidManifestPermissionTree_label, - com.android.internal.R.styleable.AndroidManifestPermissionTree_icon, - com.android.internal.R.styleable.AndroidManifestPermissionTree_logo)) { + com.android.internal.R.styleable.AndroidManifestPermissionTree_icon, 0)) { sa.recycle(); mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return null; @@ -1387,8 +1384,7 @@ public class PackageParser { mParseInstrumentationArgs = new ParsePackageItemArgs(owner, outError, com.android.internal.R.styleable.AndroidManifestInstrumentation_name, com.android.internal.R.styleable.AndroidManifestInstrumentation_label, - com.android.internal.R.styleable.AndroidManifestInstrumentation_icon, - com.android.internal.R.styleable.AndroidManifestInstrumentation_logo); + com.android.internal.R.styleable.AndroidManifestInstrumentation_icon, 0); mParseInstrumentationArgs.tag = "<instrumentation>"; } @@ -1500,8 +1496,6 @@ public class PackageParser { ai.icon = sa.getResourceId( com.android.internal.R.styleable.AndroidManifestApplication_icon, 0); - ai.logo = sa.getResourceId( - com.android.internal.R.styleable.AndroidManifestApplication_logo, 0); ai.theme = sa.getResourceId( com.android.internal.R.styleable.AndroidManifestApplication_theme, 0); ai.descriptionRes = sa.getResourceId( @@ -1761,11 +1755,6 @@ public class PackageParser { outInfo.nonLocalizedLabel = null; } - int logoVal = sa.getResourceId(logoRes, 0); - if (logoVal != 0) { - outInfo.logo = logoVal; - } - TypedValue v = sa.peekValue(labelRes); if (v != null && (outInfo.labelRes=v.resourceId) == 0) { outInfo.nonLocalizedLabel = v.coerceToString(); @@ -1786,8 +1775,7 @@ public class PackageParser { mParseActivityArgs = new ParseComponentArgs(owner, outError, com.android.internal.R.styleable.AndroidManifestActivity_name, com.android.internal.R.styleable.AndroidManifestActivity_label, - com.android.internal.R.styleable.AndroidManifestActivity_icon, - com.android.internal.R.styleable.AndroidManifestActivity_logo, + com.android.internal.R.styleable.AndroidManifestActivity_icon, 0, mSeparateProcesses, com.android.internal.R.styleable.AndroidManifestActivity_process, com.android.internal.R.styleable.AndroidManifestActivity_description, @@ -1997,8 +1985,7 @@ public class PackageParser { mParseActivityAliasArgs = new ParseComponentArgs(owner, outError, com.android.internal.R.styleable.AndroidManifestActivityAlias_name, com.android.internal.R.styleable.AndroidManifestActivityAlias_label, - com.android.internal.R.styleable.AndroidManifestActivityAlias_icon, - com.android.internal.R.styleable.AndroidManifestActivityAlias_logo, + com.android.internal.R.styleable.AndroidManifestActivityAlias_icon, 0, mSeparateProcesses, 0, com.android.internal.R.styleable.AndroidManifestActivityAlias_description, @@ -2126,8 +2113,7 @@ public class PackageParser { mParseProviderArgs = new ParseComponentArgs(owner, outError, com.android.internal.R.styleable.AndroidManifestProvider_name, com.android.internal.R.styleable.AndroidManifestProvider_label, - com.android.internal.R.styleable.AndroidManifestProvider_icon, - com.android.internal.R.styleable.AndroidManifestProvider_logo, + com.android.internal.R.styleable.AndroidManifestProvider_icon, 0, mSeparateProcesses, com.android.internal.R.styleable.AndroidManifestProvider_process, com.android.internal.R.styleable.AndroidManifestProvider_description, @@ -2399,8 +2385,7 @@ public class PackageParser { mParseServiceArgs = new ParseComponentArgs(owner, outError, com.android.internal.R.styleable.AndroidManifestService_name, com.android.internal.R.styleable.AndroidManifestService_label, - com.android.internal.R.styleable.AndroidManifestService_icon, - com.android.internal.R.styleable.AndroidManifestService_logo, + com.android.internal.R.styleable.AndroidManifestService_icon, 0, mSeparateProcesses, com.android.internal.R.styleable.AndroidManifestService_process, com.android.internal.R.styleable.AndroidManifestService_description, @@ -2614,9 +2599,6 @@ public class PackageParser { outInfo.icon = sa.getResourceId( com.android.internal.R.styleable.AndroidManifestIntentFilter_icon, 0); - outInfo.logo = sa.getResourceId( - com.android.internal.R.styleable.AndroidManifestIntentFilter_logo, 0); - sa.recycle(); int outerDepth = parser.getDepth(); @@ -2884,11 +2866,6 @@ public class PackageParser { outInfo.nonLocalizedLabel = null; } - int logoVal = args.sa.getResourceId(args.logoRes, 0); - if (logoVal != 0) { - outInfo.logo = logoVal; - } - TypedValue v = args.sa.peekValue(args.labelRes); if (v != null && (outInfo.labelRes=v.resourceId) == 0) { outInfo.nonLocalizedLabel = v.coerceToString(); diff --git a/core/java/android/net/DownloadManager.java b/core/java/android/net/DownloadManager.java index 18e62b0..1f220d2 100644 --- a/core/java/android/net/DownloadManager.java +++ b/core/java/android/net/DownloadManager.java @@ -214,6 +214,11 @@ public class DownloadManager { "android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED"; /** + * Intent action to launch an activity to display all downloads. + */ + public final static String ACTION_VIEW_DOWNLOADS = "android.intent.action.VIEW_DOWNLOADS"; + + /** * Intent extra included with {@link #ACTION_DOWNLOAD_COMPLETE} intents, indicating the ID (as a * long) of the download that just completed. */ diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java index c5a3277..7803bf2 100644 --- a/core/java/android/net/NetworkStateTracker.java +++ b/core/java/android/net/NetworkStateTracker.java @@ -50,6 +50,12 @@ public abstract class NetworkStateTracker extends Handler { private static boolean DBG = true; private static final String TAG = "NetworkStateTracker"; + // Share the event space with ConnectivityService (which we can't see, but + // must send events to). If you change these, change ConnectivityService + // too. + private static final int MIN_NETWORK_STATE_TRACKER_EVENT = 1; + private static final int MAX_NETWORK_STATE_TRACKER_EVENT = 100; + public static final int EVENT_STATE_CHANGED = 1; public static final int EVENT_SCAN_RESULTS_AVAILABLE = 2; /** @@ -61,16 +67,6 @@ public abstract class NetworkStateTracker extends Handler { public static final int EVENT_CONFIGURATION_CHANGED = 4; public static final int EVENT_ROAMING_CHANGED = 5; public static final int EVENT_NETWORK_SUBTYPE_CHANGED = 6; - public static final int EVENT_RESTORE_DEFAULT_NETWORK = 7; - /** - * arg1: network type - * arg2: condition (0 bad, 100 good) - */ - public static final int EVENT_INET_CONDITION_CHANGE = 8; - /** - * arg1: network type - */ - public static final int EVENT_INET_CONDITION_HOLD_END = 9; public NetworkStateTracker(Context context, Handler target, diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index ba8014f..d49c8be 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -301,7 +301,11 @@ public abstract class BatteryStats implements Parcelable { */ public static abstract class Proc { - public static class ExcessiveWake { + public static class ExcessivePower { + public static final int TYPE_WAKE = 1; + public static final int TYPE_CPU = 2; + + public int type; public long overTime; public long usedTime; } @@ -343,9 +347,9 @@ public abstract class BatteryStats implements Parcelable { */ public abstract long getTimeAtCpuSpeedStep(int speedStep, int which); - public abstract int countExcessiveWakes(); + public abstract int countExcessivePowers(); - public abstract ExcessiveWake getExcessiveWake(int i); + public abstract ExcessivePower getExcessivePower(int i); } /** @@ -1593,7 +1597,7 @@ public abstract class BatteryStats implements Parcelable { systemTime = ps.getSystemTime(which); starts = ps.getStarts(which); numExcessive = which == STATS_SINCE_CHARGED - ? ps.countExcessiveWakes() : 0; + ? ps.countExcessivePowers() : 0; if (userTime != 0 || systemTime != 0 || starts != 0 || numExcessive != 0) { @@ -1609,9 +1613,17 @@ public abstract class BatteryStats implements Parcelable { } pw.println(sb.toString()); for (int e=0; e<numExcessive; e++) { - Uid.Proc.ExcessiveWake ew = ps.getExcessiveWake(e); + Uid.Proc.ExcessivePower ew = ps.getExcessivePower(e); if (ew != null) { - pw.print(prefix); pw.print(" * Killed for wake lock use: "); + pw.print(prefix); pw.print(" * Killed for "); + if (ew.type == Uid.Proc.ExcessivePower.TYPE_WAKE) { + pw.print("wake lock"); + } else if (ew.type == Uid.Proc.ExcessivePower.TYPE_CPU) { + pw.print("cpu"); + } else { + pw.print("unknown"); + } + pw.print(" use: "); TimeUtils.formatDuration(ew.usedTime, pw); pw.print(" over "); TimeUtils.formatDuration(ew.overTime, pw); diff --git a/core/java/android/provider/AlarmClock.java b/core/java/android/provider/AlarmClock.java new file mode 100644 index 0000000..b93dfd8 --- /dev/null +++ b/core/java/android/provider/AlarmClock.java @@ -0,0 +1,71 @@ +/* + * 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.provider; + +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; + +/** + * The AlarmClock provider contains an Intent action and extras that can be used + * to start an Activity to set a new alarm in an alarm clock application. + * + * Applications that wish to receive the ACTION_SET_ALARM Intent should create + * an activity to handle the Intent that requires the permission + * com.android.alarm.permission.SET_ALARM. Applications that wish to create a + * new alarm should use + * {@link android.content.Context#startActivity Context.startActivity()} so that + * the user has the option of choosing which alarm clock application to use. + */ +public final class AlarmClock { + /** + * Activity Action: Set an alarm. + * <p> + * Input: Nothing. + * <p> + * Output: Nothing. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_SET_ALARM = "android.intent.action.SET_ALARM"; + + /** + * Activity Extra: Provide a custom message for the alarm. + * <p> + * This can be passed as an extra field in the Intent created with + * ACTION_SET_ALARM. + */ + public static final String EXTRA_MESSAGE = "android.intent.extra.alarm.MESSAGE"; + + /** + * Activity Extra: The hour of the alarm being set. + * <p> + * This value can be passed as an extra field to the Intent created with + * ACTION_SET_ALARM. If it is not provided, the behavior is undefined and + * is up to the application. The value is an integer and ranges from 0 to + * 23. + */ + public static final String EXTRA_HOUR = "android.intent.extra.alarm.HOUR"; + + /** + * Activity Extra: The minutes of the alarm being set. + * <p> + * This value can be passed as an extra field to the Intent created with + * ACTION_SET_ALARM. If it is not provided, the behavior is undefined and + * is up to the application. The value is an integer and ranges from 0 to + * 59. + */ + public static final String EXTRA_MINUTES = "android.intent.extra.alarm.MINUTES"; +} diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index 59980ef..9c249ce 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -1876,6 +1876,9 @@ public final class ViewRoot extends Handler implements ViewParent, deliverPointerEvent(event); } finally { event.recycle(); + if (msg.arg1 != 0) { + finishInputEvent(); + } if (LOCAL_LOGV || WATCH_POINTER) Log.i(TAG, "Done dispatching!"); } } break; @@ -1885,6 +1888,9 @@ public final class ViewRoot extends Handler implements ViewParent, deliverTrackballEvent(event); } finally { event.recycle(); + if (msg.arg1 != 0) { + finishInputEvent(); + } } } break; case DISPATCH_APP_VISIBILITY: @@ -2019,15 +2025,24 @@ public final class ViewRoot extends Handler implements ViewParent, } } - private void finishKeyEvent(KeyEvent event) { - if (LOCAL_LOGV) Log.v(TAG, "Telling window manager key is finished"); + private void startInputEvent(Runnable finishedCallback) { + if (mFinishedCallback != null) { + Slog.w(TAG, "Received a new input event from the input queue but there is " + + "already an unfinished input event in progress."); + } + + mFinishedCallback = finishedCallback; + } + + private void finishInputEvent() { + if (LOCAL_LOGV) Log.v(TAG, "Telling window manager input event is finished"); if (mFinishedCallback != null) { mFinishedCallback.run(); mFinishedCallback = null; } else { - Slog.w(TAG, "Attempted to tell the input queue that the current key event " - + "is finished but there is no key event actually in progress."); + Slog.w(TAG, "Attempted to tell the input queue that the current input event " + + "is finished but there is no input event actually in progress."); } } @@ -2487,7 +2502,7 @@ public final class ViewRoot extends Handler implements ViewParent, ? mView.dispatchKeyEventPreIme(event) : true; if (handled) { if (sendDone) { - finishKeyEvent(event); + finishInputEvent(); } return; } @@ -2518,7 +2533,7 @@ public final class ViewRoot extends Handler implements ViewParent, deliverKeyEventToViewHierarchy(event, sendDone); return; } else if (sendDone) { - finishKeyEvent(event); + finishInputEvent(); } else { Log.w(TAG, "handleFinishedEvent(seq=" + seq + " handled=" + handled + " ev=" + event @@ -2591,7 +2606,7 @@ public final class ViewRoot extends Handler implements ViewParent, } finally { if (sendDone) { - finishKeyEvent(event); + finishInputEvent(); } // Let the exception fall through -- the looper will catch // it and take care of the bad app for us. @@ -2622,6 +2637,7 @@ public final class ViewRoot extends Handler implements ViewParent, if (DBG) Log.d(TAG, "WindowLayout in layoutWindow:" + params); } mPendingConfiguration.seq = 0; + //Log.d(TAG, ">>>>>> CALLING relayout"); int relayoutResult = sWindowSession.relayout( mWindow, params, (int) (mView.mMeasuredWidth * appScale + 0.5f), @@ -2629,6 +2645,7 @@ public final class ViewRoot extends Handler implements ViewParent, viewVisibility, insetsPending, mWinFrame, mPendingContentInsets, mPendingVisibleInsets, mPendingConfiguration, mSurface); + //Log.d(TAG, "<<<<<< BACK FROM relayout"); if (restore) { params.restore(); } @@ -2774,20 +2791,13 @@ public final class ViewRoot extends Handler implements ViewParent, private final InputHandler mInputHandler = new InputHandler() { public void handleKey(KeyEvent event, Runnable finishedCallback) { - if (mFinishedCallback != null) { - Slog.w(TAG, "Received a new key event from the input queue but there is " - + "already an unfinished key event in progress."); - } - - mFinishedCallback = finishedCallback; - + startInputEvent(finishedCallback); dispatchKey(event, true); } public void handleMotion(MotionEvent event, Runnable finishedCallback) { - finishedCallback.run(); - - dispatchMotion(event); + startInputEvent(finishedCallback); + dispatchMotion(event, true); } }; @@ -2820,26 +2830,43 @@ public final class ViewRoot extends Handler implements ViewParent, } public void dispatchMotion(MotionEvent event) { + dispatchMotion(event, false); + } + + private void dispatchMotion(MotionEvent event, boolean sendDone) { int source = event.getSource(); if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { - dispatchPointer(event); + dispatchPointer(event, sendDone); } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) { - dispatchTrackball(event); + dispatchTrackball(event, sendDone); } else { // TODO Log.v(TAG, "Dropping unsupported motion event (unimplemented): " + event); + if (sendDone) { + finishInputEvent(); + } } } public void dispatchPointer(MotionEvent event) { + dispatchPointer(event, false); + } + + private void dispatchPointer(MotionEvent event, boolean sendDone) { Message msg = obtainMessage(DISPATCH_POINTER); msg.obj = event; + msg.arg1 = sendDone ? 1 : 0; sendMessageAtTime(msg, event.getEventTime()); } public void dispatchTrackball(MotionEvent event) { + dispatchTrackball(event, false); + } + + private void dispatchTrackball(MotionEvent event, boolean sendDone) { Message msg = obtainMessage(DISPATCH_TRACKBALL); msg.obj = event; + msg.arg1 = sendDone ? 1 : 0; sendMessageAtTime(msg, event.getEventTime()); } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 6e5c47f..b033fad 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -67,7 +67,7 @@ public final class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version - private static final int VERSION = 51; + private static final int VERSION = 52; // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; @@ -85,7 +85,7 @@ public final class BatteryStatsImpl extends BatteryStats { static final int MSG_UPDATE_WAKELOCKS = 1; static final int MSG_REPORT_POWER_CHANGE = 2; - static final long DELAY_UPDATE_WAKELOCKS = 15*1000; + static final long DELAY_UPDATE_WAKELOCKS = 5*1000; public interface BatteryCallback { public void batteryNeedsCpuUpdate(); @@ -1474,6 +1474,13 @@ public final class BatteryStatsImpl extends BatteryStats { } } + public void reportExcessiveCpuLocked(int uid, String proc, long overTime, long usedTime) { + Uid u = mUidStats.get(uid); + if (u != null) { + u.reportExcessiveCpuLocked(proc, overTime, usedTime); + } + } + int mSensorNesting; public void noteStartSensorLocked(int uid, int sensor) { @@ -2975,7 +2982,7 @@ public final class BatteryStatsImpl extends BatteryStats { SamplingCounter[] mSpeedBins; - ArrayList<ExcessiveWake> mExcessiveWake; + ArrayList<ExcessivePower> mExcessivePower; Proc() { mUnpluggables.add(this); @@ -3003,55 +3010,69 @@ public final class BatteryStatsImpl extends BatteryStats { } } - public int countExcessiveWakes() { - return mExcessiveWake != null ? mExcessiveWake.size() : 0; + public int countExcessivePowers() { + return mExcessivePower != null ? mExcessivePower.size() : 0; } - public ExcessiveWake getExcessiveWake(int i) { - if (mExcessiveWake != null) { - return mExcessiveWake.get(i); + public ExcessivePower getExcessivePower(int i) { + if (mExcessivePower != null) { + return mExcessivePower.get(i); } return null; } public void addExcessiveWake(long overTime, long usedTime) { - if (mExcessiveWake == null) { - mExcessiveWake = new ArrayList<ExcessiveWake>(); + if (mExcessivePower == null) { + mExcessivePower = new ArrayList<ExcessivePower>(); } - ExcessiveWake ew = new ExcessiveWake(); + ExcessivePower ew = new ExcessivePower(); + ew.type = ExcessivePower.TYPE_WAKE; ew.overTime = overTime; ew.usedTime = usedTime; - mExcessiveWake.add(ew); + mExcessivePower.add(ew); } - void writeExcessiveWakeToParcelLocked(Parcel out) { - if (mExcessiveWake == null) { + public void addExcessiveCpu(long overTime, long usedTime) { + if (mExcessivePower == null) { + mExcessivePower = new ArrayList<ExcessivePower>(); + } + ExcessivePower ew = new ExcessivePower(); + ew.type = ExcessivePower.TYPE_CPU; + ew.overTime = overTime; + ew.usedTime = usedTime; + mExcessivePower.add(ew); + } + + void writeExcessivePowerToParcelLocked(Parcel out) { + if (mExcessivePower == null) { out.writeInt(0); return; } - final int N = mExcessiveWake.size(); + final int N = mExcessivePower.size(); out.writeInt(N); for (int i=0; i<N; i++) { - ExcessiveWake ew = mExcessiveWake.get(i); + ExcessivePower ew = mExcessivePower.get(i); + out.writeInt(ew.type); out.writeLong(ew.overTime); out.writeLong(ew.usedTime); } } - void readExcessiveWakeFromParcelLocked(Parcel in) { + void readExcessivePowerFromParcelLocked(Parcel in) { final int N = in.readInt(); if (N == 0) { - mExcessiveWake = null; + mExcessivePower = null; return; } - mExcessiveWake = new ArrayList<ExcessiveWake>(); + mExcessivePower = new ArrayList<ExcessivePower>(); for (int i=0; i<N; i++) { - ExcessiveWake ew = new ExcessiveWake(); + ExcessivePower ew = new ExcessivePower(); + ew.type = in.readInt(); ew.overTime = in.readLong(); ew.usedTime = in.readLong(); - mExcessiveWake.add(ew); + mExcessivePower.add(ew); } } @@ -3080,7 +3101,7 @@ public final class BatteryStatsImpl extends BatteryStats { } } - writeExcessiveWakeToParcelLocked(out); + writeExcessivePowerToParcelLocked(out); } void readFromParcelLocked(Parcel in) { @@ -3110,7 +3131,7 @@ public final class BatteryStatsImpl extends BatteryStats { } } - readExcessiveWakeFromParcelLocked(in); + readExcessivePowerFromParcelLocked(in); } public BatteryStatsImpl getBatteryStats() { @@ -3744,6 +3765,13 @@ public final class BatteryStatsImpl extends BatteryStats { } } + public void reportExcessiveCpuLocked(String proc, long overTime, long usedTime) { + Proc p = getProcessStatsLocked(proc); + if (p != null) { + p.addExcessiveCpu(overTime, usedTime); + } + } + public void noteStartSensor(int sensor) { StopwatchTimer t = getSensorTimerLocked(sensor, true); if (t != null) { @@ -4686,7 +4714,7 @@ public final class BatteryStatsImpl extends BatteryStats { p.mSpeedBins[i].readSummaryFromParcelLocked(in); } } - p.readExcessiveWakeFromParcelLocked(in); + p.readExcessivePowerFromParcelLocked(in); } NP = in.readInt(); @@ -4885,7 +4913,7 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeInt(0); } } - ps.writeExcessiveWakeToParcelLocked(out); + ps.writeExcessivePowerToParcelLocked(out); } } diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp index 9d215b7..8409adc 100644 --- a/core/jni/android_media_AudioTrack.cpp +++ b/core/jni/android_media_AudioTrack.cpp @@ -252,21 +252,23 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this); lpJniStorage->mStreamType = atStreamType; - - jint* nSession = NULL; - if (jSession) { - nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL); - if (nSession == NULL) { - LOGE("Error creating AudioTrack: Error retrieving session id pointer"); - delete lpJniStorage; - return AUDIOTRACK_ERROR; - } - } else { + + if (jSession == NULL) { LOGE("Error creating AudioTrack: invalid session ID pointer"); delete lpJniStorage; return AUDIOTRACK_ERROR; } + jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL); + if (nSession == NULL) { + LOGE("Error creating AudioTrack: Error retrieving session id pointer"); + delete lpJniStorage; + return AUDIOTRACK_ERROR; + } + int sessionId = nSession[0]; + env->ReleasePrimitiveArrayCritical(jSession, nSession, 0); + nSession = NULL; + // create the native AudioTrack object AudioTrack* lpTrack = new AudioTrack(); if (lpTrack == NULL) { @@ -288,7 +290,7 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack 0,// shared mem true,// thread can call Java - nSession[0]);// audio session ID + sessionId);// audio session ID } else if (memoryMode == javaAudioTrackFields.MODE_STATIC) { // AudioTrack is using shared memory @@ -309,7 +311,7 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack lpJniStorage->mMemBase,// shared mem true,// thread can call Java - nSession[0]);// audio session ID + sessionId);// audio session ID } if (lpTrack->initCheck() != NO_ERROR) { @@ -317,9 +319,13 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th goto native_init_failure; } + nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL); + if (nSession == NULL) { + LOGE("Error creating AudioTrack: Error retrieving session id pointer"); + goto native_init_failure; + } // read the audio session ID back from AudioTrack in case we create a new session nSession[0] = lpTrack->getSessionId(); - env->ReleasePrimitiveArrayCritical(jSession, nSession, 0); nSession = NULL; diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index ab0ff3f..68a5a14 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -242,6 +242,14 @@ android:description="@string/permdesc_writeHistoryBookmarks" android:protectionLevel="dangerous" /> + <!-- Allows an application to broadcast an Intent to set an alarm for the + user. --> + <permission android:name="com.android.alarm.permission.SET_ALARM" + android:permissionGroup="android.permission-group.PERSONAL_INFO" + android:label="@string/permlab_setAlarm" + android:description="@string/permdesc_setAlarm" + android:protectionLevel="normal" /> + <!-- ======================================= --> <!-- Permissions for accessing location info --> <!-- ======================================= --> diff --git a/core/res/res/drawable-hdpi/btn_dropdown_disable.9.png b/core/res/res/drawable-hdpi/btn_dropdown_disable.9.png Binary files differindex 606a68e..0d25b6e 100755 --- a/core/res/res/drawable-hdpi/btn_dropdown_disable.9.png +++ b/core/res/res/drawable-hdpi/btn_dropdown_disable.9.png diff --git a/core/res/res/drawable-hdpi/btn_dropdown_disable_focused.9.png b/core/res/res/drawable-hdpi/btn_dropdown_disable_focused.9.png Binary files differindex d5d99cf..e21fd75 100755 --- a/core/res/res/drawable-hdpi/btn_dropdown_disable_focused.9.png +++ b/core/res/res/drawable-hdpi/btn_dropdown_disable_focused.9.png diff --git a/core/res/res/drawable-hdpi/btn_dropdown_normal.9.png b/core/res/res/drawable-hdpi/btn_dropdown_normal.9.png Binary files differindex a4488b0..f10402f 100755 --- a/core/res/res/drawable-hdpi/btn_dropdown_normal.9.png +++ b/core/res/res/drawable-hdpi/btn_dropdown_normal.9.png diff --git a/core/res/res/drawable-hdpi/btn_dropdown_pressed.9.png b/core/res/res/drawable-hdpi/btn_dropdown_pressed.9.png Binary files differindex bdb0077..366c6e0 100755 --- a/core/res/res/drawable-hdpi/btn_dropdown_pressed.9.png +++ b/core/res/res/drawable-hdpi/btn_dropdown_pressed.9.png diff --git a/core/res/res/drawable-hdpi/btn_dropdown_selected.9.png b/core/res/res/drawable-hdpi/btn_dropdown_selected.9.png Binary files differindex 0033fdd..f063c8d 100755 --- a/core/res/res/drawable-hdpi/btn_dropdown_selected.9.png +++ b/core/res/res/drawable-hdpi/btn_dropdown_selected.9.png diff --git a/core/res/res/drawable-hdpi/indicator_code_lock_point_area_default.png b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_default.png Binary files differindex 0102a61..467a013 100644 --- a/core/res/res/drawable-hdpi/indicator_code_lock_point_area_default.png +++ b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_default.png diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_gray.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_gray.9.png Binary files differindex 53ed136..bae80bb 100644 --- a/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_gray.9.png +++ b/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_gray.9.png diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_green.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_green.9.png Binary files differindex 6455790..0d34a6c 100644 --- a/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_green.9.png +++ b/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_green.9.png diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_red.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_red.9.png Binary files differindex 49bb9c1..792168a 100644 --- a/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_red.9.png +++ b/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_red.9.png diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_yellow.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_yellow.9.png Binary files differindex b3c4c4c..cc34ab2 100644 --- a/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_yellow.9.png +++ b/core/res/res/drawable-hdpi/jog_tab_bar_left_end_confirm_yellow.9.png diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_left_end_normal.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_left_end_normal.9.png Binary files differindex 00dea6ec..fe5eb93 100644 --- a/core/res/res/drawable-hdpi/jog_tab_bar_left_end_normal.9.png +++ b/core/res/res/drawable-hdpi/jog_tab_bar_left_end_normal.9.png diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_left_end_pressed.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_left_end_pressed.9.png Binary files differindex 45b1850..93bf1d6 100644 --- a/core/res/res/drawable-hdpi/jog_tab_bar_left_end_pressed.9.png +++ b/core/res/res/drawable-hdpi/jog_tab_bar_left_end_pressed.9.png diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_gray.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_gray.9.png Binary files differindex 35b3529..34e80ee 100644 --- a/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_gray.9.png +++ b/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_gray.9.png diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_green.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_green.9.png Binary files differindex 720de7f..227b07c 100644 --- a/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_green.9.png +++ b/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_green.9.png diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_red.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_red.9.png Binary files differindex b3387be..ef03424 100644 --- a/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_red.9.png +++ b/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_red.9.png diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_yellow.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_yellow.9.png Binary files differindex 7ddfbcc..a6a4e6d 100644 --- a/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_yellow.9.png +++ b/core/res/res/drawable-hdpi/jog_tab_bar_right_end_confirm_yellow.9.png diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_right_end_normal.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_right_end_normal.9.png Binary files differindex 1855e5f..60d65c2 100644 --- a/core/res/res/drawable-hdpi/jog_tab_bar_right_end_normal.9.png +++ b/core/res/res/drawable-hdpi/jog_tab_bar_right_end_normal.9.png diff --git a/core/res/res/drawable-hdpi/jog_tab_bar_right_end_pressed.9.png b/core/res/res/drawable-hdpi/jog_tab_bar_right_end_pressed.9.png Binary files differindex 844f304..d00cc85 100644 --- a/core/res/res/drawable-hdpi/jog_tab_bar_right_end_pressed.9.png +++ b/core/res/res/drawable-hdpi/jog_tab_bar_right_end_pressed.9.png diff --git a/core/res/res/drawable-hdpi/jog_tab_left_confirm_gray.png b/core/res/res/drawable-hdpi/jog_tab_left_confirm_gray.png Binary files differindex f8dc42a..9599fb5 100644..100755 --- a/core/res/res/drawable-hdpi/jog_tab_left_confirm_gray.png +++ b/core/res/res/drawable-hdpi/jog_tab_left_confirm_gray.png diff --git a/core/res/res/drawable-hdpi/jog_tab_left_confirm_green.png b/core/res/res/drawable-hdpi/jog_tab_left_confirm_green.png Binary files differindex 92b24b0..46d9ab3 100644..100755 --- a/core/res/res/drawable-hdpi/jog_tab_left_confirm_green.png +++ b/core/res/res/drawable-hdpi/jog_tab_left_confirm_green.png diff --git a/core/res/res/drawable-hdpi/jog_tab_left_confirm_red.png b/core/res/res/drawable-hdpi/jog_tab_left_confirm_red.png Binary files differindex 8818b9e..6c0dc0a 100644 --- a/core/res/res/drawable-hdpi/jog_tab_left_confirm_red.png +++ b/core/res/res/drawable-hdpi/jog_tab_left_confirm_red.png diff --git a/core/res/res/drawable-hdpi/jog_tab_left_confirm_yellow.png b/core/res/res/drawable-hdpi/jog_tab_left_confirm_yellow.png Binary files differindex 8208b20..3f9fb8f 100644..100755 --- a/core/res/res/drawable-hdpi/jog_tab_left_confirm_yellow.png +++ b/core/res/res/drawable-hdpi/jog_tab_left_confirm_yellow.png diff --git a/core/res/res/drawable-hdpi/jog_tab_left_normal.png b/core/res/res/drawable-hdpi/jog_tab_left_normal.png Binary files differindex 4c87743..8b89538 100644..100755 --- a/core/res/res/drawable-hdpi/jog_tab_left_normal.png +++ b/core/res/res/drawable-hdpi/jog_tab_left_normal.png diff --git a/core/res/res/drawable-hdpi/jog_tab_left_pressed.png b/core/res/res/drawable-hdpi/jog_tab_left_pressed.png Binary files differindex 150c735..ec98790 100644..100755 --- a/core/res/res/drawable-hdpi/jog_tab_left_pressed.png +++ b/core/res/res/drawable-hdpi/jog_tab_left_pressed.png diff --git a/core/res/res/drawable-hdpi/jog_tab_right_confirm_gray.png b/core/res/res/drawable-hdpi/jog_tab_right_confirm_gray.png Binary files differindex 11ab30c..2861e8d 100644..100755 --- a/core/res/res/drawable-hdpi/jog_tab_right_confirm_gray.png +++ b/core/res/res/drawable-hdpi/jog_tab_right_confirm_gray.png diff --git a/core/res/res/drawable-hdpi/jog_tab_right_confirm_green.png b/core/res/res/drawable-hdpi/jog_tab_right_confirm_green.png Binary files differindex a912285..e974bbc 100644..100755 --- a/core/res/res/drawable-hdpi/jog_tab_right_confirm_green.png +++ b/core/res/res/drawable-hdpi/jog_tab_right_confirm_green.png diff --git a/core/res/res/drawable-hdpi/jog_tab_right_confirm_red.png b/core/res/res/drawable-hdpi/jog_tab_right_confirm_red.png Binary files differindex d772fb6..9647fa6 100644 --- a/core/res/res/drawable-hdpi/jog_tab_right_confirm_red.png +++ b/core/res/res/drawable-hdpi/jog_tab_right_confirm_red.png diff --git a/core/res/res/drawable-hdpi/jog_tab_right_confirm_yellow.png b/core/res/res/drawable-hdpi/jog_tab_right_confirm_yellow.png Binary files differindex 0dd84fa..ad878e1 100644..100755 --- a/core/res/res/drawable-hdpi/jog_tab_right_confirm_yellow.png +++ b/core/res/res/drawable-hdpi/jog_tab_right_confirm_yellow.png diff --git a/core/res/res/drawable-hdpi/jog_tab_right_normal.png b/core/res/res/drawable-hdpi/jog_tab_right_normal.png Binary files differindex e0f1a0a..01bba0b 100644..100755 --- a/core/res/res/drawable-hdpi/jog_tab_right_normal.png +++ b/core/res/res/drawable-hdpi/jog_tab_right_normal.png diff --git a/core/res/res/drawable-hdpi/jog_tab_right_pressed.png b/core/res/res/drawable-hdpi/jog_tab_right_pressed.png Binary files differindex f41d6f5..647e802 100644..100755 --- a/core/res/res/drawable-hdpi/jog_tab_right_pressed.png +++ b/core/res/res/drawable-hdpi/jog_tab_right_pressed.png diff --git a/core/res/res/drawable-hdpi/overscroll_edge.png b/core/res/res/drawable-hdpi/overscroll_edge.png Binary files differindex 5969093..f8e40ec 100644 --- a/core/res/res/drawable-hdpi/overscroll_edge.png +++ b/core/res/res/drawable-hdpi/overscroll_edge.png diff --git a/core/res/res/drawable-hdpi/stat_notify_email_generic.png b/core/res/res/drawable-hdpi/stat_notify_email_generic.png Binary files differindex 78003fa..87f0cd4 100755..100644 --- a/core/res/res/drawable-hdpi/stat_notify_email_generic.png +++ b/core/res/res/drawable-hdpi/stat_notify_email_generic.png diff --git a/core/res/res/drawable-hdpi/stat_notify_gmail.png b/core/res/res/drawable-hdpi/stat_notify_gmail.png Binary files differindex 7356309..8a9140c 100755..100644 --- a/core/res/res/drawable-hdpi/stat_notify_gmail.png +++ b/core/res/res/drawable-hdpi/stat_notify_gmail.png diff --git a/core/res/res/drawable-hdpi/status_bar_item_app_background_normal.9.png b/core/res/res/drawable-hdpi/status_bar_item_app_background_normal.9.png Binary files differindex 4fbfa4f..bdcb378 100644 --- a/core/res/res/drawable-hdpi/status_bar_item_app_background_normal.9.png +++ b/core/res/res/drawable-hdpi/status_bar_item_app_background_normal.9.png diff --git a/core/res/res/drawable-hdpi/status_bar_item_background_focus.9.png b/core/res/res/drawable-hdpi/status_bar_item_background_focus.9.png Binary files differindex b07c7bc..0876bc6 100644 --- a/core/res/res/drawable-hdpi/status_bar_item_background_focus.9.png +++ b/core/res/res/drawable-hdpi/status_bar_item_background_focus.9.png diff --git a/core/res/res/drawable-hdpi/status_bar_item_background_normal.9.png b/core/res/res/drawable-hdpi/status_bar_item_background_normal.9.png Binary files differindex de2f3c3..fa27ee4 100644 --- a/core/res/res/drawable-hdpi/status_bar_item_background_normal.9.png +++ b/core/res/res/drawable-hdpi/status_bar_item_background_normal.9.png diff --git a/core/res/res/drawable-hdpi/status_bar_item_background_pressed.9.png b/core/res/res/drawable-hdpi/status_bar_item_background_pressed.9.png Binary files differindex b5eab83..343e4ca 100644 --- a/core/res/res/drawable-hdpi/status_bar_item_background_pressed.9.png +++ b/core/res/res/drawable-hdpi/status_bar_item_background_pressed.9.png diff --git a/core/res/res/drawable-mdpi/btn_dropdown_normal.9.png b/core/res/res/drawable-mdpi/btn_dropdown_normal.9.png Binary files differindex f6e9a19..8540501 100644 --- a/core/res/res/drawable-mdpi/btn_dropdown_normal.9.png +++ b/core/res/res/drawable-mdpi/btn_dropdown_normal.9.png diff --git a/core/res/res/drawable-mdpi/btn_dropdown_pressed.9.png b/core/res/res/drawable-mdpi/btn_dropdown_pressed.9.png Binary files differindex 3bdf52d..9a50396 100644 --- a/core/res/res/drawable-mdpi/btn_dropdown_pressed.9.png +++ b/core/res/res/drawable-mdpi/btn_dropdown_pressed.9.png diff --git a/core/res/res/drawable-mdpi/btn_dropdown_selected.9.png b/core/res/res/drawable-mdpi/btn_dropdown_selected.9.png Binary files differindex 087956e..a0a3fef 100644 --- a/core/res/res/drawable-mdpi/btn_dropdown_selected.9.png +++ b/core/res/res/drawable-mdpi/btn_dropdown_selected.9.png diff --git a/core/res/res/drawable-mdpi/indicator_code_lock_point_area_default.png b/core/res/res/drawable-mdpi/indicator_code_lock_point_area_default.png Binary files differindex 4e88b37..8546c5f 100755 --- a/core/res/res/drawable-mdpi/indicator_code_lock_point_area_default.png +++ b/core/res/res/drawable-mdpi/indicator_code_lock_point_area_default.png diff --git a/core/res/res/drawable-mdpi/jog_tab_bar_left_end_confirm_gray.9.png b/core/res/res/drawable-mdpi/jog_tab_bar_left_end_confirm_gray.9.png Binary files differindex adbb146..4440abc 100644 --- a/core/res/res/drawable-mdpi/jog_tab_bar_left_end_confirm_gray.9.png +++ b/core/res/res/drawable-mdpi/jog_tab_bar_left_end_confirm_gray.9.png diff --git a/core/res/res/drawable-mdpi/jog_tab_bar_left_end_confirm_green.9.png b/core/res/res/drawable-mdpi/jog_tab_bar_left_end_confirm_green.9.png Binary files differindex e8be7bf..26c07e6 100644 --- a/core/res/res/drawable-mdpi/jog_tab_bar_left_end_confirm_green.9.png +++ b/core/res/res/drawable-mdpi/jog_tab_bar_left_end_confirm_green.9.png diff --git a/core/res/res/drawable-mdpi/jog_tab_bar_left_end_confirm_red.9.png b/core/res/res/drawable-mdpi/jog_tab_bar_left_end_confirm_red.9.png Binary files differindex 120a9d8..684f8ac 100644 --- a/core/res/res/drawable-mdpi/jog_tab_bar_left_end_confirm_red.9.png +++ b/core/res/res/drawable-mdpi/jog_tab_bar_left_end_confirm_red.9.png diff --git a/core/res/res/drawable-mdpi/jog_tab_bar_left_end_confirm_yellow.9.png b/core/res/res/drawable-mdpi/jog_tab_bar_left_end_confirm_yellow.9.png Binary files differindex 60ec146..56cfce33a 100644 --- a/core/res/res/drawable-mdpi/jog_tab_bar_left_end_confirm_yellow.9.png +++ b/core/res/res/drawable-mdpi/jog_tab_bar_left_end_confirm_yellow.9.png diff --git a/core/res/res/drawable-mdpi/jog_tab_bar_left_end_normal.9.png b/core/res/res/drawable-mdpi/jog_tab_bar_left_end_normal.9.png Binary files differindex 7477453..d4e1929 100644 --- a/core/res/res/drawable-mdpi/jog_tab_bar_left_end_normal.9.png +++ b/core/res/res/drawable-mdpi/jog_tab_bar_left_end_normal.9.png diff --git a/core/res/res/drawable-mdpi/jog_tab_bar_left_end_pressed.9.png b/core/res/res/drawable-mdpi/jog_tab_bar_left_end_pressed.9.png Binary files differindex c79a35c..39cd1e5 100644 --- a/core/res/res/drawable-mdpi/jog_tab_bar_left_end_pressed.9.png +++ b/core/res/res/drawable-mdpi/jog_tab_bar_left_end_pressed.9.png diff --git a/core/res/res/drawable-mdpi/jog_tab_bar_right_end_confirm_gray.9.png b/core/res/res/drawable-mdpi/jog_tab_bar_right_end_confirm_gray.9.png Binary files differindex 4ce09fa..a6ee329 100644 --- a/core/res/res/drawable-mdpi/jog_tab_bar_right_end_confirm_gray.9.png +++ b/core/res/res/drawable-mdpi/jog_tab_bar_right_end_confirm_gray.9.png diff --git a/core/res/res/drawable-mdpi/jog_tab_bar_right_end_confirm_green.9.png b/core/res/res/drawable-mdpi/jog_tab_bar_right_end_confirm_green.9.png Binary files differindex 9d7565f..386ed9d 100644 --- a/core/res/res/drawable-mdpi/jog_tab_bar_right_end_confirm_green.9.png +++ b/core/res/res/drawable-mdpi/jog_tab_bar_right_end_confirm_green.9.png diff --git a/core/res/res/drawable-mdpi/jog_tab_bar_right_end_confirm_red.9.png b/core/res/res/drawable-mdpi/jog_tab_bar_right_end_confirm_red.9.png Binary files differindex d5f9bd8..0242a42 100644 --- a/core/res/res/drawable-mdpi/jog_tab_bar_right_end_confirm_red.9.png +++ b/core/res/res/drawable-mdpi/jog_tab_bar_right_end_confirm_red.9.png diff --git a/core/res/res/drawable-mdpi/jog_tab_bar_right_end_confirm_yellow.9.png b/core/res/res/drawable-mdpi/jog_tab_bar_right_end_confirm_yellow.9.png Binary files differindex 5b9c5b4..b8c2e18 100644 --- a/core/res/res/drawable-mdpi/jog_tab_bar_right_end_confirm_yellow.9.png +++ b/core/res/res/drawable-mdpi/jog_tab_bar_right_end_confirm_yellow.9.png diff --git a/core/res/res/drawable-mdpi/jog_tab_bar_right_end_normal.9.png b/core/res/res/drawable-mdpi/jog_tab_bar_right_end_normal.9.png Binary files differindex 2e6ca2e..4c608ee 100644 --- a/core/res/res/drawable-mdpi/jog_tab_bar_right_end_normal.9.png +++ b/core/res/res/drawable-mdpi/jog_tab_bar_right_end_normal.9.png diff --git a/core/res/res/drawable-mdpi/jog_tab_bar_right_end_pressed.9.png b/core/res/res/drawable-mdpi/jog_tab_bar_right_end_pressed.9.png Binary files differindex f41750d..8bdfd84 100644 --- a/core/res/res/drawable-mdpi/jog_tab_bar_right_end_pressed.9.png +++ b/core/res/res/drawable-mdpi/jog_tab_bar_right_end_pressed.9.png diff --git a/core/res/res/drawable-mdpi/jog_tab_left_confirm_gray.png b/core/res/res/drawable-mdpi/jog_tab_left_confirm_gray.png Binary files differindex b5d3290..3dce451 100644..100755 --- a/core/res/res/drawable-mdpi/jog_tab_left_confirm_gray.png +++ b/core/res/res/drawable-mdpi/jog_tab_left_confirm_gray.png diff --git a/core/res/res/drawable-mdpi/jog_tab_left_confirm_green.png b/core/res/res/drawable-mdpi/jog_tab_left_confirm_green.png Binary files differindex e4cff64..829b146 100644..100755 --- a/core/res/res/drawable-mdpi/jog_tab_left_confirm_green.png +++ b/core/res/res/drawable-mdpi/jog_tab_left_confirm_green.png diff --git a/core/res/res/drawable-mdpi/jog_tab_left_confirm_red.png b/core/res/res/drawable-mdpi/jog_tab_left_confirm_red.png Binary files differindex 5188c86..f2ceb2e 100644 --- a/core/res/res/drawable-mdpi/jog_tab_left_confirm_red.png +++ b/core/res/res/drawable-mdpi/jog_tab_left_confirm_red.png diff --git a/core/res/res/drawable-mdpi/jog_tab_left_confirm_yellow.png b/core/res/res/drawable-mdpi/jog_tab_left_confirm_yellow.png Binary files differindex d501814..5a29262 100644..100755 --- a/core/res/res/drawable-mdpi/jog_tab_left_confirm_yellow.png +++ b/core/res/res/drawable-mdpi/jog_tab_left_confirm_yellow.png diff --git a/core/res/res/drawable-mdpi/jog_tab_left_normal.png b/core/res/res/drawable-mdpi/jog_tab_left_normal.png Binary files differindex 42f7e39..eb91e97 100644..100755 --- a/core/res/res/drawable-mdpi/jog_tab_left_normal.png +++ b/core/res/res/drawable-mdpi/jog_tab_left_normal.png diff --git a/core/res/res/drawable-mdpi/jog_tab_left_pressed.png b/core/res/res/drawable-mdpi/jog_tab_left_pressed.png Binary files differindex 888f19b..9951992 100644..100755 --- a/core/res/res/drawable-mdpi/jog_tab_left_pressed.png +++ b/core/res/res/drawable-mdpi/jog_tab_left_pressed.png diff --git a/core/res/res/drawable-mdpi/jog_tab_right_confirm_gray.png b/core/res/res/drawable-mdpi/jog_tab_right_confirm_gray.png Binary files differindex 7fc930e..d446480 100644..100755 --- a/core/res/res/drawable-mdpi/jog_tab_right_confirm_gray.png +++ b/core/res/res/drawable-mdpi/jog_tab_right_confirm_gray.png diff --git a/core/res/res/drawable-mdpi/jog_tab_right_confirm_green.png b/core/res/res/drawable-mdpi/jog_tab_right_confirm_green.png Binary files differindex 1a08be8..96d7acb 100644..100755 --- a/core/res/res/drawable-mdpi/jog_tab_right_confirm_green.png +++ b/core/res/res/drawable-mdpi/jog_tab_right_confirm_green.png diff --git a/core/res/res/drawable-mdpi/jog_tab_right_confirm_red.png b/core/res/res/drawable-mdpi/jog_tab_right_confirm_red.png Binary files differindex 74f2935..2e1e105 100644 --- a/core/res/res/drawable-mdpi/jog_tab_right_confirm_red.png +++ b/core/res/res/drawable-mdpi/jog_tab_right_confirm_red.png diff --git a/core/res/res/drawable-mdpi/jog_tab_right_confirm_yellow.png b/core/res/res/drawable-mdpi/jog_tab_right_confirm_yellow.png Binary files differindex 2aa4036..8224c38 100644..100755 --- a/core/res/res/drawable-mdpi/jog_tab_right_confirm_yellow.png +++ b/core/res/res/drawable-mdpi/jog_tab_right_confirm_yellow.png diff --git a/core/res/res/drawable-mdpi/jog_tab_right_normal.png b/core/res/res/drawable-mdpi/jog_tab_right_normal.png Binary files differindex 10710fb..f2113f2 100644..100755 --- a/core/res/res/drawable-mdpi/jog_tab_right_normal.png +++ b/core/res/res/drawable-mdpi/jog_tab_right_normal.png diff --git a/core/res/res/drawable-mdpi/jog_tab_right_pressed.png b/core/res/res/drawable-mdpi/jog_tab_right_pressed.png Binary files differindex 021e96b..65cd51e 100644..100755 --- a/core/res/res/drawable-mdpi/jog_tab_right_pressed.png +++ b/core/res/res/drawable-mdpi/jog_tab_right_pressed.png diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index dda1fc5..d58dedc 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -266,8 +266,8 @@ <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Umožňuje aplikaci uvolnit paměť telefonu smazáním souborů v adresáři mezipaměti aplikace. Přístup je velmi omezený, většinou pouze pro systémové procesy."</string> <string name="permlab_movePackage" msgid="728454979946503926">"Přesun zdrojů aplikace"</string> <string name="permdesc_movePackage" msgid="6323049291923925277">"Umožňuje aplikaci přesunout své zdroje z interní paměti na externí médium a opačně."</string> - <string name="permlab_readLogs" msgid="4811921703882532070">"čtení systémových souborů protokolu"</string> - <string name="permdesc_readLogs" msgid="2257937955580475902">"Umožňuje aplikaci číst různé systémové soubory protokolů. Toto nastavení aplikaci umožní získat obecné informace o činnostech s telefonem, ale neměly by obsahovat žádné osobní či soukromé informace."</string> + <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"čtení systémových souborů protokolu"</string> + <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Umožňuje aplikaci číst různé systémové soubory protokolů. Toto nastavení aplikaci umožní získat obecné informace o činnostech s telefonem, ale neměly by obsahovat žádné osobní či soukromé informace."</string> <string name="permlab_diagnostic" msgid="8076743953908000342">"čtení nebo zápis do prostředků funkce diag"</string> <string name="permdesc_diagnostic" msgid="3121238373951637049">"Umožňuje aplikaci číst libovolné prostředky ve skupině diag, např. soubory ve složce /dev, a zapisovat do nich. Může dojít k ovlivnění stability a bezpečnosti systému. Toto nastavení by měl používat pouze výrobce či operátor pro diagnostiku hardwaru."</string> <string name="permlab_changeComponentState" msgid="79425198834329406">"povolení či zakázání komponent aplikací"</string> @@ -525,6 +525,14 @@ <string name="orgTypeWork" msgid="29268870505363872">"Práce"</string> <string name="orgTypeOther" msgid="3951781131570124082">"Jiné"</string> <string name="orgTypeCustom" msgid="225523415372088322">"Vlastní"</string> + <!-- no translation found for sipAddressTypeCustom (2473580593111590945) --> + <skip /> + <!-- no translation found for sipAddressTypeHome (6093598181069359295) --> + <skip /> + <!-- no translation found for sipAddressTypeWork (6920725730797099047) --> + <skip /> + <!-- no translation found for sipAddressTypeOther (4408436162950119849) --> + <skip /> <string name="contact_status_update_attribution" msgid="5112589886094402795">"pomocí <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> pomocí <xliff:g id="SOURCE">%2$s</xliff:g>"</string> <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Zadejte kód PIN"</string> @@ -699,7 +707,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Vybrat vše"</string> - <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Označit text"</string> + <string name="selectText" msgid="4862359311088898878">"Vybrat slovo"</string> <string name="cut" msgid="3092569408438626261">"Vyjmout"</string> <string name="copy" msgid="2681946229533511987">"Kopírovat"</string> <string name="paste" msgid="5629880836805036433">"Vložit"</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 7b3e82c..3e6a63c 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -266,8 +266,8 @@ <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Tillader, at et program frigør plads på telefonen ved at slette filer i programmets cachemappe. Adgang er normalt meget begrænset til systemprocesser."</string> <string name="permlab_movePackage" msgid="728454979946503926">"Flyt programressourcer"</string> <string name="permdesc_movePackage" msgid="6323049291923925277">"Tillader, at et program flytter programressourcer fra interne til eksterne medier og omvendt."</string> - <string name="permlab_readLogs" msgid="4811921703882532070">"læs systemlogfiler"</string> - <string name="permdesc_readLogs" msgid="2257937955580475902">"Tillader, at et program læser fra systemets forskellige logfiler. Dermed kan generelle oplysninger om, hvad du laver med telefonen, registreres, men logfilerne bør ikke indeholde personlige eller private oplysninger."</string> + <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"læs systemlogfiler"</string> + <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Tillader, at et program læser fra systemets forskellige logfiler. Dermed kan generelle oplysninger om, hvad du laver med telefonen, registreres, men logfilerne bør ikke indeholde personlige eller private oplysninger."</string> <string name="permlab_diagnostic" msgid="8076743953908000342">"læs/skriv til ressourcer ejet af diag"</string> <string name="permdesc_diagnostic" msgid="3121238373951637049">"Tillader, at et program læser og skriver til alle ressourcer, der ejes af diag-gruppen, som f.eks. flier i /dev. Dette kan muligvis påvirke systemets stabilitet og sikkerhed. Dette bør KUN bruges til hardwarespecifikke diagnosticeringer foretaget af producent eller udbyder."</string> <string name="permlab_changeComponentState" msgid="79425198834329406">"aktiver eller deaktiver programkomponenter"</string> @@ -525,6 +525,14 @@ <string name="orgTypeWork" msgid="29268870505363872">"Arbejde"</string> <string name="orgTypeOther" msgid="3951781131570124082">"Andre"</string> <string name="orgTypeCustom" msgid="225523415372088322">"Tilpasset"</string> + <!-- no translation found for sipAddressTypeCustom (2473580593111590945) --> + <skip /> + <!-- no translation found for sipAddressTypeHome (6093598181069359295) --> + <skip /> + <!-- no translation found for sipAddressTypeWork (6920725730797099047) --> + <skip /> + <!-- no translation found for sipAddressTypeOther (4408436162950119849) --> + <skip /> <string name="contact_status_update_attribution" msgid="5112589886094402795">"via <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> via <xliff:g id="SOURCE">%2$s</xliff:g>"</string> <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Indtast PIN-kode"</string> @@ -699,7 +707,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Vælg alle"</string> - <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Marker tekst"</string> + <string name="selectText" msgid="4862359311088898878">"Vælg ord"</string> <string name="cut" msgid="3092569408438626261">"Klip"</string> <string name="copy" msgid="2681946229533511987">"Kopier"</string> <string name="paste" msgid="5629880836805036433">"Indsæt"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 4c5cc8c..c0ac156 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -266,8 +266,8 @@ <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Ermöglicht einer Anwendung, Telefonspeicher durch das Löschen von Dateien im Cache-Verzeichnis der Anwendung freizugeben. Der Zugriff beschränkt sich in der Regel auf Systemprozesse."</string> <string name="permlab_movePackage" msgid="728454979946503926">"Anwendungsressourcen verschieben"</string> <string name="permdesc_movePackage" msgid="6323049291923925277">"Ermöglicht einer Anwendung, Anwendungsressourcen von interne auf externe Medien zu verschieben und umgekehrt."</string> - <string name="permlab_readLogs" msgid="4811921703882532070">"System-Protokolldateien lesen"</string> - <string name="permdesc_readLogs" msgid="2257937955580475902">"Ermöglicht einer Anwendung, die verschiedenen Protokolldateien des Systems zu lesen. So können allgemeine Informationen zu den auf Ihrem Telefon durchgeführten Aktionen eingesehen werden, diese sollten jedoch keine persönlichen oder geheimen Daten enthalten."</string> + <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"System-Protokolldateien lesen"</string> + <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Ermöglicht einer Anwendung, die verschiedenen Protokolldateien des Systems zu lesen. So können allgemeine Informationen zu den auf Ihrem Telefon durchgeführten Aktionen eingesehen werden, diese sollten jedoch keine persönlichen oder geheimen Daten enthalten."</string> <string name="permlab_diagnostic" msgid="8076743953908000342">"Lese-/Schreibberechtigung für zu Diagnosegruppe gehörige Elemente"</string> <string name="permdesc_diagnostic" msgid="3121238373951637049">"Ermöglicht einer Anwendung, alle Elemente in der Diagnosegruppe zu lesen und zu bearbeiten, etwa Dateien in \"/dev\". Dies könnte eine potenzielle Gefährdung für die Stabilität und Sicherheit des Systems darstellen und sollte NUR für Hardware-spezifische Diagnosen des Herstellers oder Netzbetreibers verwendet werden."</string> <string name="permlab_changeComponentState" msgid="79425198834329406">"Anwendungskomponenten aktivieren oder deaktivieren"</string> @@ -525,6 +525,14 @@ <string name="orgTypeWork" msgid="29268870505363872">"Beruflich"</string> <string name="orgTypeOther" msgid="3951781131570124082">"Andere"</string> <string name="orgTypeCustom" msgid="225523415372088322">"Benutzerdefiniert"</string> + <!-- no translation found for sipAddressTypeCustom (2473580593111590945) --> + <skip /> + <!-- no translation found for sipAddressTypeHome (6093598181069359295) --> + <skip /> + <!-- no translation found for sipAddressTypeWork (6920725730797099047) --> + <skip /> + <!-- no translation found for sipAddressTypeOther (4408436162950119849) --> + <skip /> <string name="contact_status_update_attribution" msgid="5112589886094402795">"über <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> über <xliff:g id="SOURCE">%2$s</xliff:g>"</string> <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"PIN-Code eingeben"</string> @@ -536,7 +544,7 @@ <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Display gesperrt."</string> <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Drücken Sie die Menütaste, um das Telefon zu entsperren oder einen Notruf zu tätigen."</string> <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Zum Entsperren die Menütaste drücken"</string> - <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Schema für Entsperrung zeichnen"</string> + <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Muster zum Entsperren zeichnen"</string> <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Notruf"</string> <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Zurück zum Anruf"</string> <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Korrekt!"</string> @@ -699,7 +707,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Alles auswählen"</string> - <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Text auswählen"</string> + <string name="selectText" msgid="4862359311088898878">"Wort auswählen"</string> <string name="cut" msgid="3092569408438626261">"Ausschneiden"</string> <string name="copy" msgid="2681946229533511987">"Kopieren"</string> <string name="paste" msgid="5629880836805036433">"Einfügen"</string> @@ -788,7 +796,7 @@ <string name="usb_storage_button_mount" msgid="1052259930369508235">"USB-Speicher aktivieren"</string> <string name="usb_storage_error_message" msgid="2534784751603345363">"Bei der Verwendung Ihrer SD-Karte als USB-Speicher ist ein Problem aufgetreten."</string> <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB-Verbindung"</string> - <string name="usb_storage_notification_message" msgid="7380082404288219341">"Wählen Sie die Dateien aus, die von Ihrem oder auf Ihren Computer kopiert werden sollen."</string> + <string name="usb_storage_notification_message" msgid="7380082404288219341">"Zum Kopieren von Dateien zu/von Ihrem Computer."</string> <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"USB-Speicher deaktivieren"</string> <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Auswählen, um USB-Speicher zu deaktivieren."</string> <string name="usb_storage_stop_title" msgid="660129851708775853">"USB-Speicher in Verwendung"</string> @@ -809,7 +817,7 @@ <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="candidates_style" msgid="4333913089637062257"><u>"Kandidaten"</u></string> <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"SD-Karte wird vorbereitet"</string> - <string name="ext_media_checking_notification_message" msgid="8287319882926737053">"Nach Fehlern wird gesucht."</string> + <string name="ext_media_checking_notification_message" msgid="8287319882926737053">"Suche nach Fehlern"</string> <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"SD-Karte leer"</string> <string name="ext_media_nofs_notification_message" msgid="3817704088027829380">"SD-Karte ist leer oder verfügt über ein nicht unterstütztes Dateisystem."</string> <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Beschädigte SD-Karte"</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 45863e7..ca0eec7 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -266,8 +266,8 @@ <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Επιτρέπει σε μια εφαρμογή να αυξήσει τον ελεύθερο χώρο αποθήκευσης του τηλεφώνου διαγράφοντας αρχεία από τον κατάλογο προσωρινής μνήμης της εφαρμογής. Η πρόσβαση είναι συνήθως πολύ περιορισμένη στη διαδικασία συστήματος."</string> <string name="permlab_movePackage" msgid="728454979946503926">"Μετακίνηση πόρων εφαρμογής"</string> <string name="permdesc_movePackage" msgid="6323049291923925277">"Επιτρέπει σε μια εφαρμογή τη μετακίνηση πόρων εφαρμογής από ένα εσωτερικό σε ένα εξωτερικό μέσο και αντίστροφα."</string> - <string name="permlab_readLogs" msgid="4811921703882532070">"ανάγνωση αρχείων καταγραφής συστήματος"</string> - <string name="permdesc_readLogs" msgid="2257937955580475902">"Επιτρέπει σε μια εφαρμογή να αναγνώσει τα αρχεία καταγραφής του συστήματος. Έτσι μπορεί να ανακαλύψει γενικές πληροφορίες σχετικά με τις δραστηριότητές σας στο τηλέφωνο, όμως δεν θα πρέπει να περιέχουν προσωπικές ή ιδιωτικές πληροφορίες."</string> + <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"ανάγνωση αρχείων καταγραφής συστήματος"</string> + <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Επιτρέπει σε μια εφαρμογή να αναγνώσει τα αρχεία καταγραφής του συστήματος. Έτσι μπορεί να ανακαλύψει γενικές πληροφορίες σχετικά με τις δραστηριότητές σας στο τηλέφωνο, όμως δεν θα πρέπει να περιέχουν προσωπικές ή ιδιωτικές πληροφορίες."</string> <string name="permlab_diagnostic" msgid="8076743953908000342">"ανάγνωση/εγγραφή σε πόρους που ανήκουν στο διαγνωστικό"</string> <string name="permdesc_diagnostic" msgid="3121238373951637049">"Επιτρέπει σε μια εφαρμογή την ανάγνωση και την εγγραφή σε πόρο που ανήκει στην ομάδα διαγνωστικού (π.χ. αρχεία στον κατάλογο /dev). Αυτό ενδέχεται να επηρεάσει την σταθερότητα και την ασφάλεια του συστήματος. Θα πρέπει να χρησιμοποιείται ΜΟΝΟ για διαγνωστικά υλικού του κατασκευαστή ή του χειριστή."</string> <string name="permlab_changeComponentState" msgid="79425198834329406">"ενεργοποίηση ή απενεργοποίηση στοιχείων εφαρμογής"</string> @@ -525,6 +525,14 @@ <string name="orgTypeWork" msgid="29268870505363872">"Εργασία"</string> <string name="orgTypeOther" msgid="3951781131570124082">"Άλλο"</string> <string name="orgTypeCustom" msgid="225523415372088322">"Προσαρμοσμένο"</string> + <!-- no translation found for sipAddressTypeCustom (2473580593111590945) --> + <skip /> + <!-- no translation found for sipAddressTypeHome (6093598181069359295) --> + <skip /> + <!-- no translation found for sipAddressTypeWork (6920725730797099047) --> + <skip /> + <!-- no translation found for sipAddressTypeOther (4408436162950119849) --> + <skip /> <string name="contact_status_update_attribution" msgid="5112589886094402795">"μέσω <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> μέσω <xliff:g id="SOURCE">%2$s</xliff:g>"</string> <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Πληκτρολογήστε τον κωδικό αριθμό PIN"</string> @@ -699,7 +707,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Επιλογή όλων"</string> - <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Επιλογή κειμένου"</string> + <string name="selectText" msgid="4862359311088898878">"Επιλογή λέξης"</string> <string name="cut" msgid="3092569408438626261">"Αποκοπή"</string> <string name="copy" msgid="2681946229533511987">"Αντιγραφή"</string> <string name="paste" msgid="5629880836805036433">"Επικόλληση"</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 2765e96..b0da375 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -266,8 +266,8 @@ <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Admite una aplicación que libera espacio de almacenamiento en el teléfono al eliminar archivos del directorio de memoria caché de la aplicación. En general, el acceso es muy restringido para el proceso del sistema."</string> <string name="permlab_movePackage" msgid="728454979946503926">"Mover recursos de la aplicación"</string> <string name="permdesc_movePackage" msgid="6323049291923925277">"Permite a una aplicación mover recursos de aplicación de medios internos a externos y viceversa."</string> - <string name="permlab_readLogs" msgid="4811921703882532070">"leer archivos de registro del sistema"</string> - <string name="permdesc_readLogs" msgid="2257937955580475902">"Admite una aplicación que lee diversos archivos de registro del sistema. Esto le permite descubrir información general sobre lo que haces con el teléfono, pero no debe contener información personal ni privada."</string> + <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"leer archivos de registro del sistema"</string> + <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Admite una aplicación que lee diversos archivos de registro del sistema. Esto le permite descubrir información general sobre lo que haces con el teléfono, pero no debe contener información personal ni privada."</string> <string name="permlab_diagnostic" msgid="8076743953908000342">"leer y escribir a recursos dentro del grupo de diagnóstico"</string> <string name="permdesc_diagnostic" msgid="3121238373951637049">"Admite una aplicación que lee y escribe a cualquier recurso dentro del grupo de diagnóstico; por ejemplo, archivos con /dev. Esto puede afectar potencialmente la estabilidad y la seguridad del sistema. Debe utilizarlo SÓLO el fabricante o el operador en los diagnósticos específicos del hardware."</string> <string name="permlab_changeComponentState" msgid="79425198834329406">"activar o desactivar componentes de la aplicación"</string> @@ -525,6 +525,14 @@ <string name="orgTypeWork" msgid="29268870505363872">"Trabajo"</string> <string name="orgTypeOther" msgid="3951781131570124082">"Otro"</string> <string name="orgTypeCustom" msgid="225523415372088322">"Personalizado"</string> + <!-- no translation found for sipAddressTypeCustom (2473580593111590945) --> + <skip /> + <!-- no translation found for sipAddressTypeHome (6093598181069359295) --> + <skip /> + <!-- no translation found for sipAddressTypeWork (6920725730797099047) --> + <skip /> + <!-- no translation found for sipAddressTypeOther (4408436162950119849) --> + <skip /> <string name="contact_status_update_attribution" msgid="5112589886094402795">"a través de <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> a través de <xliff:g id="SOURCE">%2$s</xliff:g>"</string> <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Ingresar el código de PIN"</string> @@ -699,7 +707,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Seleccionar todos"</string> - <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Seleccionar texto"</string> + <string name="selectText" msgid="4862359311088898878">"Seleccionar palabra"</string> <string name="cut" msgid="3092569408438626261">"Cortar"</string> <string name="copy" msgid="2681946229533511987">"Copiar"</string> <string name="paste" msgid="5629880836805036433">"Pegar"</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 0d2f932..74f5874 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -266,8 +266,8 @@ <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Permite que una aplicación libere espacio de almacenamiento en el teléfono mediante la eliminación de archivos en el directorio de caché de la aplicación. El acceso al proceso del sistema suele estar muy restringido."</string> <string name="permlab_movePackage" msgid="728454979946503926">"Mover recursos de aplicaciones"</string> <string name="permdesc_movePackage" msgid="6323049291923925277">"Permite que una aplicación mueva los recursos de aplicaciones de un medio interno a otro externo y viceversa."</string> - <string name="permlab_readLogs" msgid="4811921703882532070">"leer archivos de registro del sistema"</string> - <string name="permdesc_readLogs" msgid="2257937955580475902">"Permite que una aplicación lea los distintos archivos de registro del sistema. Con este permiso, la aplicación puede ver información general sobre las acciones que realiza el usuario con el teléfono, pero los registros no deberían contener información personal o privada."</string> + <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"leer archivos de registro del sistema"</string> + <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Permite que una aplicación lea los distintos archivos de registro del sistema. Con este permiso, la aplicación puede ver información general sobre las acciones que realiza el usuario con el teléfono, pero los registros no deberían contener información personal o privada."</string> <string name="permlab_diagnostic" msgid="8076743953908000342">"leer/escribir en los recursos propiedad del grupo de diagnóstico"</string> <string name="permdesc_diagnostic" msgid="3121238373951637049">"Permite que una aplicación lea y escriba en cualquier recurso propiedad del grupo de diagnóstico como, por ejemplo, archivos in/dev. Este permiso podría afectar a la seguridad y estabilidad del sistema. SÓLO se debe utilizar para diagnósticos específicos de hardware realizados por el fabricante o el operador."</string> <string name="permlab_changeComponentState" msgid="79425198834329406">"habilitar o inhabilitar componentes de la aplicación"</string> @@ -525,6 +525,14 @@ <string name="orgTypeWork" msgid="29268870505363872">"Trabajo"</string> <string name="orgTypeOther" msgid="3951781131570124082">"Otra"</string> <string name="orgTypeCustom" msgid="225523415372088322">"Personalizada"</string> + <!-- no translation found for sipAddressTypeCustom (2473580593111590945) --> + <skip /> + <!-- no translation found for sipAddressTypeHome (6093598181069359295) --> + <skip /> + <!-- no translation found for sipAddressTypeWork (6920725730797099047) --> + <skip /> + <!-- no translation found for sipAddressTypeOther (4408436162950119849) --> + <skip /> <string name="contact_status_update_attribution" msgid="5112589886094402795">"a través de <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> a través de <xliff:g id="SOURCE">%2$s</xliff:g>"</string> <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Introduce el código PIN"</string> @@ -699,7 +707,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Seleccionar todo"</string> - <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Seleccionar texto"</string> + <string name="selectText" msgid="4862359311088898878">"Seleccionar palabra"</string> <string name="cut" msgid="3092569408438626261">"Cortar"</string> <string name="copy" msgid="2681946229533511987">"Copiar"</string> <string name="paste" msgid="5629880836805036433">"Pegar"</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index b4f8046..bc69793 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -266,8 +266,8 @@ <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Permet à une application de libérer de l\'espace dans la mémoire du téléphone en supprimant des fichiers du répertoire du cache des applications. Cet accès est en général limité aux processus système."</string> <string name="permlab_movePackage" msgid="728454979946503926">"Déplacer des ressources d\'application"</string> <string name="permdesc_movePackage" msgid="6323049291923925277">"Autorise l\'application à déplacer des ressources d\'application d\'un support interne à un support externe et inversement."</string> - <string name="permlab_readLogs" msgid="4811921703882532070">"Lecture des fichiers journaux du système"</string> - <string name="permdesc_readLogs" msgid="2257937955580475902">"Permet à une application de lire les différents fichiers journaux du système afin d\'obtenir des informations générales sur la façon dont vous utilisez votre téléphone, sans pour autant récupérer des informations d\'ordre personnel ou privé."</string> + <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"Lecture des fichiers journaux du système"</string> + <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Permet à une application de lire les différents fichiers journaux du système afin d\'obtenir des informations générales sur la façon dont vous utilisez votre téléphone, sans pour autant récupérer des informations d\'ordre personnel ou privé."</string> <string name="permlab_diagnostic" msgid="8076743953908000342">"Lecture/écriture dans les ressources appartenant aux diagnostics"</string> <string name="permdesc_diagnostic" msgid="3121238373951637049">"Permet à une application de lire et d\'éditer toute ressource appartenant au groupe de diagnostics (par exemple, les fichiers in/dev). Ceci peut affecter la stabilité et la sécurité du système. Cette fonctionnalité est UNIQUEMENT réservée aux diagnostics matériels effectués par le fabricant ou l\'opérateur."</string> <string name="permlab_changeComponentState" msgid="79425198834329406">"Activer ou désactiver des éléments de l\'application"</string> @@ -434,7 +434,7 @@ <string name="policydesc_wipeData" msgid="2314060933796396205">"Rétablit les paramètres d\'usine, supprimant toutes vos données sans demande de confirmation."</string> <string-array name="phoneTypes"> <item msgid="8901098336658710359">"Domicile"</item> - <item msgid="869923650527136615">"Portable"</item> + <item msgid="869923650527136615">"Mobile"</item> <item msgid="7897544654242874543">"Bureau"</item> <item msgid="1103601433382158155">"Télécopie bureau"</item> <item msgid="1735177144948329370">"Télécopie domicile"</item> @@ -525,6 +525,14 @@ <string name="orgTypeWork" msgid="29268870505363872">"Bureau"</string> <string name="orgTypeOther" msgid="3951781131570124082">"Autre"</string> <string name="orgTypeCustom" msgid="225523415372088322">"Personnalisé"</string> + <!-- no translation found for sipAddressTypeCustom (2473580593111590945) --> + <skip /> + <!-- no translation found for sipAddressTypeHome (6093598181069359295) --> + <skip /> + <!-- no translation found for sipAddressTypeWork (6920725730797099047) --> + <skip /> + <!-- no translation found for sipAddressTypeOther (4408436162950119849) --> + <skip /> <string name="contact_status_update_attribution" msgid="5112589886094402795">"via <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> via <xliff:g id="SOURCE">%2$s</xliff:g>"</string> <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Saisissez le code PIN"</string> @@ -699,7 +707,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Tout sélectionner"</string> - <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Sélectionner le texte"</string> + <string name="selectText" msgid="4862359311088898878">"Sélectionner texte"</string> <string name="cut" msgid="3092569408438626261">"Couper"</string> <string name="copy" msgid="2681946229533511987">"Copier"</string> <string name="paste" msgid="5629880836805036433">"Coller"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index d4019b6..85415bd 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -266,8 +266,8 @@ <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Consente a un\'applicazione di liberare spazio sul telefono eliminando file nella directory della cache dell\'applicazione. L\'accesso è generalmente limitato a processi di sistema."</string> <string name="permlab_movePackage" msgid="728454979946503926">"Spostare risorse dell\'applicazione"</string> <string name="permdesc_movePackage" msgid="6323049291923925277">"Consente a un\'applicazione di spostare risorse applicative da supporti interni a esterni e viceversa."</string> - <string name="permlab_readLogs" msgid="4811921703882532070">"lettura file di registro sistema"</string> - <string name="permdesc_readLogs" msgid="2257937955580475902">"Consente a un\'applicazione di leggere vari file di registro del sistema per trovare informazioni generali sulle operazioni effettuate con il telefono. Tali file non dovrebbero contenere informazioni personali o riservate."</string> + <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"lettura file di registro sistema"</string> + <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Consente a un\'applicazione di leggere vari file di registro del sistema per trovare informazioni generali sulle operazioni effettuate con il telefono. Tali file non dovrebbero contenere informazioni personali o riservate."</string> <string name="permlab_diagnostic" msgid="8076743953908000342">"lettura/scrittura risorse di proprietà di diag"</string> <string name="permdesc_diagnostic" msgid="3121238373951637049">"Consente a un\'applicazione di leggere le risorse del gruppo diag e scrivere a esse, per esempio i file in /dev. Questa capacità potrebbe influire sulla stabilità e sicurezza del sistema. Dovrebbe essere utilizzata SOLTANTO per diagnostiche specifiche dell\'hardware effettuate dal produttore o dall\'operatore."</string> <string name="permlab_changeComponentState" msgid="79425198834329406">"attivazione/disattivazione componenti applicazioni"</string> @@ -525,6 +525,14 @@ <string name="orgTypeWork" msgid="29268870505363872">"Lavoro"</string> <string name="orgTypeOther" msgid="3951781131570124082">"Altro"</string> <string name="orgTypeCustom" msgid="225523415372088322">"Personalizzato"</string> + <!-- no translation found for sipAddressTypeCustom (2473580593111590945) --> + <skip /> + <!-- no translation found for sipAddressTypeHome (6093598181069359295) --> + <skip /> + <!-- no translation found for sipAddressTypeWork (6920725730797099047) --> + <skip /> + <!-- no translation found for sipAddressTypeOther (4408436162950119849) --> + <skip /> <string name="contact_status_update_attribution" msgid="5112589886094402795">"tramite <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> tramite <xliff:g id="SOURCE">%2$s</xliff:g>"</string> <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Inserisci il PIN"</string> @@ -699,7 +707,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Seleziona tutto"</string> - <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Seleziona testo"</string> + <string name="selectText" msgid="4862359311088898878">"Seleziona parola"</string> <string name="cut" msgid="3092569408438626261">"Taglia"</string> <string name="copy" msgid="2681946229533511987">"Copia"</string> <string name="paste" msgid="5629880836805036433">"Incolla"</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index ae44bb2..70a3019 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -266,8 +266,8 @@ <string name="permdesc_clearAppCache" msgid="7740465694193671402">"アプリケーションのキャッシュディレクトリからファイルを削除して携帯電話のメモリを解放することをアプリケーションに許可します。通常、アクセスはシステムプロセスのみに制限されます。"</string> <string name="permlab_movePackage" msgid="728454979946503926">"アプリケーションリソースの移動"</string> <string name="permdesc_movePackage" msgid="6323049291923925277">"内部と外部のメディア間でのアプリケーションリソースの移動をアプリケーションに許可します。"</string> - <string name="permlab_readLogs" msgid="4811921703882532070">"システムログファイルの読み取り"</string> - <string name="permdesc_readLogs" msgid="2257937955580475902">"システムのさまざまなログファイルの読み取りをアプリケーションに許可します。これにより携帯電話の使用状況に関する全般情報が取得されますが、個人情報や非公開情報が含まれることはありません。"</string> + <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"システムログファイルの読み取り"</string> + <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"システムのさまざまなログファイルの読み取りをアプリケーションに許可します。これにより携帯電話の使用状況に関する全般情報が取得されますが、個人情報や非公開情報が含まれることはありません。"</string> <string name="permlab_diagnostic" msgid="8076743953908000342">"diagが所有するリソースの読み書き"</string> <string name="permdesc_diagnostic" msgid="3121238373951637049">"diagグループが所有するリソース(例:/dev内のファイル)への読み書きをアプリケーションに許可します。システムの安定性とセキュリティに影響する恐れがあります。メーカー/オペレーターによるハードウェア固有の診断以外には使用しないでください。"</string> <string name="permlab_changeComponentState" msgid="79425198834329406">"アプリケーションのコンポーネントを有効/無効にする"</string> @@ -525,6 +525,14 @@ <string name="orgTypeWork" msgid="29268870505363872">"勤務先"</string> <string name="orgTypeOther" msgid="3951781131570124082">"その他"</string> <string name="orgTypeCustom" msgid="225523415372088322">"カスタム"</string> + <!-- no translation found for sipAddressTypeCustom (2473580593111590945) --> + <skip /> + <!-- no translation found for sipAddressTypeHome (6093598181069359295) --> + <skip /> + <!-- no translation found for sipAddressTypeWork (6920725730797099047) --> + <skip /> + <!-- no translation found for sipAddressTypeOther (4408436162950119849) --> + <skip /> <string name="contact_status_update_attribution" msgid="5112589886094402795">"<xliff:g id="SOURCE">%1$s</xliff:g>経由"</string> <string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g>、更新元: <xliff:g id="SOURCE">%2$s</xliff:g>"</string> <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"PINコードを入力"</string> @@ -699,7 +707,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"すべて選択"</string> - <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"テキストを選択"</string> + <string name="selectText" msgid="4862359311088898878">"語句を選択"</string> <string name="cut" msgid="3092569408438626261">"切り取り"</string> <string name="copy" msgid="2681946229533511987">"コピー"</string> <string name="paste" msgid="5629880836805036433">"貼り付け"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 040f9e8..0f33772 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -266,8 +266,8 @@ <string name="permdesc_clearAppCache" msgid="7740465694193671402">"애플리케이션이 애플리케이션 캐시 디렉토리에 있는 파일을 삭제하여 휴대전화의 저장공간을 늘릴 수 있도록 합니다. 액세스는 일반적으로 시스템 프로세스로 제한됩니다."</string> <string name="permlab_movePackage" msgid="728454979946503926">"애플리케이션 리소스 이동"</string> <string name="permdesc_movePackage" msgid="6323049291923925277">"애플리케이션이 애플리케이션 리소스를 내부에서 외부 미디어로 또는 그 반대로 이동할 수 있도록 합니다."</string> - <string name="permlab_readLogs" msgid="4811921703882532070">"시스템 로그 파일 읽기"</string> - <string name="permdesc_readLogs" msgid="2257937955580475902">"애플리케이션이 시스템의 다양한 로그 파일을 읽을 수 있도록 합니다. 이 경우 애플리케이션은 사용자가 휴대전화로 수행하는 작업에 대한 일반적인 정보를 검색할 수 있습니다. 하지만 로그 파일에 어떠한 개인정보도 포함되어서는 안 됩니다."</string> + <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"시스템 로그 파일 읽기"</string> + <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"애플리케이션이 시스템의 다양한 로그 파일을 읽을 수 있도록 합니다. 이 경우 애플리케이션은 사용자가 휴대전화로 수행하는 작업에 대한 일반적인 정보를 검색할 수 있습니다. 하지만 로그 파일에 어떠한 개인정보도 포함되어서는 안 됩니다."</string> <string name="permlab_diagnostic" msgid="8076743953908000342">"진단 그룹 소유의 리소스 읽기/쓰기"</string> <string name="permdesc_diagnostic" msgid="3121238373951637049">"애플리케이션이 진단 그룹 소유의 리소스(예: /dev에 있는 파일)를 읽고 쓸 수 있도록 합니다. 이 기능은 시스템 안정성 및 보안에 영향을 미칠 수 있으므로 제조업체 또는 사업자가 하드웨어 관련 진단을 수행하는 경우에만 사용해야 합니다."</string> <string name="permlab_changeComponentState" msgid="79425198834329406">"애플리케이션 구성 요소 사용 또는 사용 안함"</string> @@ -525,6 +525,14 @@ <string name="orgTypeWork" msgid="29268870505363872">"직장"</string> <string name="orgTypeOther" msgid="3951781131570124082">"기타"</string> <string name="orgTypeCustom" msgid="225523415372088322">"맞춤설정"</string> + <!-- no translation found for sipAddressTypeCustom (2473580593111590945) --> + <skip /> + <!-- no translation found for sipAddressTypeHome (6093598181069359295) --> + <skip /> + <!-- no translation found for sipAddressTypeWork (6920725730797099047) --> + <skip /> + <!-- no translation found for sipAddressTypeOther (4408436162950119849) --> + <skip /> <string name="contact_status_update_attribution" msgid="5112589886094402795">"<xliff:g id="SOURCE">%1$s</xliff:g>을(를) 통해"</string> <string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g>(<xliff:g id="SOURCE">%2$s</xliff:g> 사용)"</string> <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"PIN 코드 입력"</string> @@ -699,7 +707,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"모두 선택"</string> - <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"텍스트 선택"</string> + <string name="selectText" msgid="4862359311088898878">"단어 선택"</string> <string name="cut" msgid="3092569408438626261">"잘라내기"</string> <string name="copy" msgid="2681946229533511987">"복사"</string> <string name="paste" msgid="5629880836805036433">"붙여넣기"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index 4ca84ed..b3727b4 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -266,8 +266,8 @@ <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Lar applikasjonen frigjøre lagringsplass ved å slette filer i applikasjoners hurtigbufferkatalog. Tilgangen er vanligvis sterkt begrenset, til systemprosesser."</string> <string name="permlab_movePackage" msgid="728454979946503926">"Flytter programressurser"</string> <string name="permdesc_movePackage" msgid="6323049291923925277">"Gir et program tillatelse til å flytte programressurser fra interne til eksterne medier og omvendt."</string> - <string name="permlab_readLogs" msgid="4811921703882532070">"lese systemets loggfiler"</string> - <string name="permdesc_readLogs" msgid="2257937955580475902">"Lar applikasjonen lese fra diverse loggfiler på systemet. Disse inneholder generell informasjon om hva som gjøres med telefonen, men skal ikke inneholde personlig eller privat informasjon."</string> + <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"lese systemets loggfiler"</string> + <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Lar applikasjonen lese fra diverse loggfiler på systemet. Disse inneholder generell informasjon om hva som gjøres med telefonen, men skal ikke inneholde personlig eller privat informasjon."</string> <string name="permlab_diagnostic" msgid="8076743953908000342">"lese/skrive ressurser eid av diag"</string> <string name="permdesc_diagnostic" msgid="3121238373951637049">"Lar applikasjonen lese og skrive enhver ressurs eid av gruppen diag; for eksempel, filer i /dev. Dette kan potensielt påvirke systemets sikkerhet og stabilitet. Dette bør KUN brukes for maskinvarespesifikke diagnoseverktøy laget av operatøren eller produsenten."</string> <string name="permlab_changeComponentState" msgid="79425198834329406">"aktivere eller deaktigere applikasjonskomponenter"</string> @@ -525,6 +525,14 @@ <string name="orgTypeWork" msgid="29268870505363872">"Arbeid"</string> <string name="orgTypeOther" msgid="3951781131570124082">"Annen"</string> <string name="orgTypeCustom" msgid="225523415372088322">"Egendefinert"</string> + <!-- no translation found for sipAddressTypeCustom (2473580593111590945) --> + <skip /> + <!-- no translation found for sipAddressTypeHome (6093598181069359295) --> + <skip /> + <!-- no translation found for sipAddressTypeWork (6920725730797099047) --> + <skip /> + <!-- no translation found for sipAddressTypeOther (4408436162950119849) --> + <skip /> <string name="contact_status_update_attribution" msgid="5112589886094402795">"via <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> via <xliff:g id="SOURCE">%2$s</xliff:g>"</string> <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Skriv inn PIN-kode:"</string> @@ -699,7 +707,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Merk alt"</string> - <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Merk tekst"</string> + <string name="selectText" msgid="4862359311088898878">"Velg ord"</string> <string name="cut" msgid="3092569408438626261">"Klipp ut"</string> <string name="copy" msgid="2681946229533511987">"Kopier"</string> <string name="paste" msgid="5629880836805036433">"Lim inn"</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index c8f0068..9c5d6bf 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -266,8 +266,8 @@ <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Hiermee kan een toepassing opslagruimte op de telefoon vrij maken door bestanden te verwijderen uit de cachemap van de toepassing. De toegang is doorgaans beperkt tot het systeemproces."</string> <string name="permlab_movePackage" msgid="728454979946503926">"Toepassingsbronnen verplaatsen"</string> <string name="permdesc_movePackage" msgid="6323049291923925277">"Een toepassing toestaan toepassingsbronnen te verplaatsen van interne naar externe media en omgekeerd."</string> - <string name="permlab_readLogs" msgid="4811921703882532070">"systeemlogbestanden lezen"</string> - <string name="permdesc_readLogs" msgid="2257937955580475902">"Hiermee kan een toepassing de verschillende logbestanden van het systeem lezen. De toepassing kan op deze manier algemene informatie achterhalen over uw telefoongebruik. Hierin is geen persoonlijke of privé-informatie opgenomen."</string> + <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"systeemlogbestanden lezen"</string> + <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Hiermee kan een toepassing de verschillende logbestanden van het systeem lezen. De toepassing kan op deze manier algemene informatie achterhalen over uw telefoongebruik. Hierin is geen persoonlijke of privé-informatie opgenomen."</string> <string name="permlab_diagnostic" msgid="8076743953908000342">"lezen/schrijven naar bronnen van diag"</string> <string name="permdesc_diagnostic" msgid="3121238373951637049">"Hiermee kan een toepassing lezen en schrijven naar elke bron die hoort bij de diagnostische groep, zoals bestanden in /dev. Hierdoor kan de systeemstabiliteit en -veiligheid worden beïnvloed. Dit mag ALLEEN worden gebruikt voor hardwarespecifieke diagnostiek door de fabrikant of operator."</string> <string name="permlab_changeComponentState" msgid="79425198834329406">"toepassingscomponenten in- of uitschakelen"</string> @@ -525,6 +525,14 @@ <string name="orgTypeWork" msgid="29268870505363872">"Werk"</string> <string name="orgTypeOther" msgid="3951781131570124082">"Overig"</string> <string name="orgTypeCustom" msgid="225523415372088322">"Aangepast"</string> + <!-- no translation found for sipAddressTypeCustom (2473580593111590945) --> + <skip /> + <!-- no translation found for sipAddressTypeHome (6093598181069359295) --> + <skip /> + <!-- no translation found for sipAddressTypeWork (6920725730797099047) --> + <skip /> + <!-- no translation found for sipAddressTypeOther (4408436162950119849) --> + <skip /> <string name="contact_status_update_attribution" msgid="5112589886094402795">"via <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> via <xliff:g id="SOURCE">%2$s</xliff:g>"</string> <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"PIN-code invoeren"</string> @@ -699,7 +707,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Alles selecteren"</string> - <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Tekst selecteren"</string> + <string name="selectText" msgid="4862359311088898878">"Woord selecteren"</string> <string name="cut" msgid="3092569408438626261">"Knippen"</string> <string name="copy" msgid="2681946229533511987">"Kopiëren"</string> <string name="paste" msgid="5629880836805036433">"Plakken"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index ae897a8..f61d1d6 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -266,8 +266,8 @@ <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Pozwala aplikacji na zwalnianie pamięci telefonu przez usuwanie plików z katalogu pamięci podręcznej aplikacji. Dostęp jest bardzo ograniczony, z reguły do procesów systemu."</string> <string name="permlab_movePackage" msgid="728454979946503926">"Przenoszenie zasobów aplikacji"</string> <string name="permdesc_movePackage" msgid="6323049291923925277">"Zezwala aplikacji na przeniesienie zasobów aplikacji z nośnika wewnętrznego na zewnętrzny i odwrotnie."</string> - <string name="permlab_readLogs" msgid="4811921703882532070">"czytanie plików dziennika systemu"</string> - <string name="permdesc_readLogs" msgid="2257937955580475902">"Umożliwia aplikacji czytanie różnych plików dziennika systemowego. Pozwala to na uzyskanie ogólnych informacji o czynnościach wykonywanych w telefonie, ale bez ujawniania danych osobowych lub osobistych informacji."</string> + <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"czytanie plików dziennika systemu"</string> + <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Umożliwia aplikacji czytanie różnych plików dziennika systemowego. Pozwala to na uzyskanie ogólnych informacji o czynnościach wykonywanych w telefonie, ale bez ujawniania danych osobowych lub osobistych informacji."</string> <string name="permlab_diagnostic" msgid="8076743953908000342">"czytanie/zapisywanie w zasobach należących do diagnostyki"</string> <string name="permdesc_diagnostic" msgid="3121238373951637049">"Pozwala aplikacji na czytanie i zapisywanie we wszystkich zasobach posiadanych przez diagnozowaną grupę, jak na przykład pliki w katalogu /dev. Może to potencjalnie wpłynąć na stabilność i bezpieczeństwo systemu. Powinno być wykorzystywane TYLKO w celach diagnozowania sprzętu przez producenta lub operatora."</string> <string name="permlab_changeComponentState" msgid="79425198834329406">"włączanie lub wyłączanie składników aplikacji"</string> @@ -525,6 +525,14 @@ <string name="orgTypeWork" msgid="29268870505363872">"Służbowy"</string> <string name="orgTypeOther" msgid="3951781131570124082">"Inny"</string> <string name="orgTypeCustom" msgid="225523415372088322">"Niestandardowy"</string> + <!-- no translation found for sipAddressTypeCustom (2473580593111590945) --> + <skip /> + <!-- no translation found for sipAddressTypeHome (6093598181069359295) --> + <skip /> + <!-- no translation found for sipAddressTypeWork (6920725730797099047) --> + <skip /> + <!-- no translation found for sipAddressTypeOther (4408436162950119849) --> + <skip /> <string name="contact_status_update_attribution" msgid="5112589886094402795">"przez <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> przez <xliff:g id="SOURCE">%2$s</xliff:g>"</string> <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Wprowadź kod PIN"</string> @@ -699,7 +707,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Zaznacz wszystko"</string> - <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Zaznacz tekst"</string> + <string name="selectText" msgid="4862359311088898878">"Zaznacz wyraz"</string> <string name="cut" msgid="3092569408438626261">"Wytnij"</string> <string name="copy" msgid="2681946229533511987">"Kopiuj"</string> <string name="paste" msgid="5629880836805036433">"Wklej"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index b9f9be2..5b44e61 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -266,8 +266,8 @@ <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Permite a uma aplicação libertar espaço de armazenamento no telefone eliminando ficheiros no directório da cache da aplicação. Geralmente, o acesso é muito limitado para processamento do sistema."</string> <string name="permlab_movePackage" msgid="728454979946503926">"Mover recursos de aplicações"</string> <string name="permdesc_movePackage" msgid="6323049291923925277">"Permite que uma aplicação mova recursos de aplicações de meios internos para meios externos e vice-versa."</string> - <string name="permlab_readLogs" msgid="4811921703882532070">"ler ficheiros de registo do sistema"</string> - <string name="permdesc_readLogs" msgid="2257937955580475902">"Permite a uma aplicação ler a partir dos diversos ficheiros de registo do sistema. Isto permite descobrir informações gerais sobre a forma como o utilizador usa o telefone, mas estas não devem conter quaisquer dados pessoais ou privados."</string> + <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"ler ficheiros de registo do sistema"</string> + <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Permite a uma aplicação ler a partir dos diversos ficheiros de registo do sistema. Isto permite descobrir informações gerais sobre a forma como o utilizador usa o telefone, mas estas não devem conter quaisquer dados pessoais ou privados."</string> <string name="permlab_diagnostic" msgid="8076743953908000342">"ler/escrever em recursos propriedade de diag"</string> <string name="permdesc_diagnostic" msgid="3121238373951637049">"Permite a uma aplicação ler e escrever em qualquer recurso que seja propriedade do grupo diag. Por exemplo, ficheiros em /dev. Isto pode afectar potencialmente a estabilidade e a segurança do sistema e deve ser utilizado APENAS para diagnósticos específicos do hardware pelo fabricante ou pelo operador."</string> <string name="permlab_changeComponentState" msgid="79425198834329406">"activar ou desactivar componentes da aplicação"</string> @@ -525,6 +525,14 @@ <string name="orgTypeWork" msgid="29268870505363872">"Emprego"</string> <string name="orgTypeOther" msgid="3951781131570124082">"Outro"</string> <string name="orgTypeCustom" msgid="225523415372088322">"Personalizado"</string> + <!-- no translation found for sipAddressTypeCustom (2473580593111590945) --> + <skip /> + <!-- no translation found for sipAddressTypeHome (6093598181069359295) --> + <skip /> + <!-- no translation found for sipAddressTypeWork (6920725730797099047) --> + <skip /> + <!-- no translation found for sipAddressTypeOther (4408436162950119849) --> + <skip /> <string name="contact_status_update_attribution" msgid="5112589886094402795">"através do <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> através de <xliff:g id="SOURCE">%2$s</xliff:g>"</string> <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Introduzir código PIN"</string> @@ -699,7 +707,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Seleccionar tudo"</string> - <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Seleccionar texto"</string> + <string name="selectText" msgid="4862359311088898878">"Seleccionar palavra"</string> <string name="cut" msgid="3092569408438626261">"Cortar"</string> <string name="copy" msgid="2681946229533511987">"Copiar"</string> <string name="paste" msgid="5629880836805036433">"Colar"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 7cc266a..60e9108 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -266,8 +266,8 @@ <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Permite que um aplicativo libere o espaço de armazenamento do telefone excluindo arquivos no diretório de cache do aplicativo. O acesso é normalmente muito restrito para o processo do sistema."</string> <string name="permlab_movePackage" msgid="728454979946503926">"Mover recursos do aplicativo"</string> <string name="permdesc_movePackage" msgid="6323049291923925277">"Permite que um aplicativo mova os recursos do aplicativo da mídia interna para a externa e vice-versa."</string> - <string name="permlab_readLogs" msgid="4811921703882532070">"ler arquivos de registro do sistema"</string> - <string name="permdesc_readLogs" msgid="2257937955580475902">"Permite que um aplicativo leia os diversos arquivos de registro do sistema. Isso permite que ele descubra informações gerais sobre o que você está fazendo com o telefone, porém esses arquivos não devem conter informações pessoais ou privadas."</string> + <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"ler arquivos de registro do sistema"</string> + <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Permite que um aplicativo leia os diversos arquivos de registro do sistema. Isso permite que ele descubra informações gerais sobre o que você está fazendo com o telefone, porém esses arquivos não devem conter informações pessoais ou privadas."</string> <string name="permlab_diagnostic" msgid="8076743953908000342">"ler/gravar em recursos pertencentes ao diag"</string> <string name="permdesc_diagnostic" msgid="3121238373951637049">"Permite que um aplicativo leia e grave em qualquer recurso que pertença ao grupo de diagnósticos; por exemplo, arquivos em /dev. Isso possivelmente pode afetar a estabilidade e a segurança do sistema. Isso deve ser usado APENAS para diagnósticos específicos do hardware realizados pelo fabricante ou pelo operador."</string> <string name="permlab_changeComponentState" msgid="79425198834329406">"ativar ou desativar os componentes do aplicativo"</string> @@ -525,6 +525,14 @@ <string name="orgTypeWork" msgid="29268870505363872">"Comercial"</string> <string name="orgTypeOther" msgid="3951781131570124082">"Outros"</string> <string name="orgTypeCustom" msgid="225523415372088322">"Personalizado"</string> + <!-- no translation found for sipAddressTypeCustom (2473580593111590945) --> + <skip /> + <!-- no translation found for sipAddressTypeHome (6093598181069359295) --> + <skip /> + <!-- no translation found for sipAddressTypeWork (6920725730797099047) --> + <skip /> + <!-- no translation found for sipAddressTypeOther (4408436162950119849) --> + <skip /> <string name="contact_status_update_attribution" msgid="5112589886094402795">"por meio de <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> via <xliff:g id="SOURCE">%2$s</xliff:g>"</string> <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Digite o código PIN"</string> @@ -699,7 +707,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Selecionar tudo"</string> - <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Selecionar texto"</string> + <string name="selectText" msgid="4862359311088898878">"Selecionar palavra"</string> <string name="cut" msgid="3092569408438626261">"Recortar"</string> <string name="copy" msgid="2681946229533511987">"Copiar"</string> <string name="paste" msgid="5629880836805036433">"Colar"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 29b7e46..9475d2d 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -266,8 +266,8 @@ <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Позволяет приложению освобождать память телефона с помощью удаления файлов из каталога кэша приложений. Обычно это разрешается только системным процессам."</string> <string name="permlab_movePackage" msgid="728454979946503926">"Перемещать ресурсы приложения"</string> <string name="permdesc_movePackage" msgid="6323049291923925277">"Позволяет приложению перемещать ресурсы приложения с внутренних на внешние носители и наоборот."</string> - <string name="permlab_readLogs" msgid="4811921703882532070">"считывать системные файлы журналов"</string> - <string name="permdesc_readLogs" msgid="2257937955580475902">"Позволяет приложению считывать информацию из различных журналов системы. Приложение может получить сведения о работе пользователя с телефоном, но они не должны содержать какой-либо личной или конфиденциальной информации."</string> + <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"считывать системные файлы журналов"</string> + <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Позволяет приложению считывать информацию из различных журналов системы. Приложение может получить сведения о работе пользователя с телефоном, но они не должны содержать какой-либо личной или конфиденциальной информации."</string> <string name="permlab_diagnostic" msgid="8076743953908000342">"считывать/записывать данные в ресурсы, принадлежащие группе диагностики"</string> <string name="permdesc_diagnostic" msgid="3121238373951637049">"Позволяет приложению считывать и записывать данные в любые ресурсы, принадлежащие группе диагностики (например, файлы в каталоге /dev). Это может повлиять на стабильность и безопасность системы. Эта возможность может быть использована ТОЛЬКО производителем или оператором для диагностики аппаратного обеспечения."</string> <string name="permlab_changeComponentState" msgid="79425198834329406">"включать или отключать компоненты приложения"</string> @@ -525,6 +525,14 @@ <string name="orgTypeWork" msgid="29268870505363872">"Работа"</string> <string name="orgTypeOther" msgid="3951781131570124082">"Другое"</string> <string name="orgTypeCustom" msgid="225523415372088322">"Создать свой ярлык"</string> + <!-- no translation found for sipAddressTypeCustom (2473580593111590945) --> + <skip /> + <!-- no translation found for sipAddressTypeHome (6093598181069359295) --> + <skip /> + <!-- no translation found for sipAddressTypeWork (6920725730797099047) --> + <skip /> + <!-- no translation found for sipAddressTypeOther (4408436162950119849) --> + <skip /> <string name="contact_status_update_attribution" msgid="5112589886094402795">"с помощью <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> с помощью <xliff:g id="SOURCE">%2$s</xliff:g>"</string> <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Введите PIN-код"</string> @@ -699,7 +707,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Выбрать все"</string> - <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Выбрать текст"</string> + <string name="selectText" msgid="4862359311088898878">"Выберите слово"</string> <string name="cut" msgid="3092569408438626261">"Вырезать"</string> <string name="copy" msgid="2681946229533511987">"Копировать"</string> <string name="paste" msgid="5629880836805036433">"Вставить"</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index b53f219..085cc29 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -266,8 +266,8 @@ <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Tillåter att ett program frigör lagringsutrymme i telefonen genom att ta bort filer i programmets katalog för cachelagring. Åtkomst är mycket begränsad, vanligtvis till systemprocesser."</string> <string name="permlab_movePackage" msgid="728454979946503926">"Flytta programresurser"</string> <string name="permdesc_movePackage" msgid="6323049291923925277">"Tillåter att ett program flyttar programresurser från interna till externa medier och tvärt om."</string> - <string name="permlab_readLogs" msgid="4811921703882532070">"läsa systemets loggfiler"</string> - <string name="permdesc_readLogs" msgid="2257937955580475902">"Tillåter att ett program läser från systemets olika loggfiler. Det innebär att programmet kan upptäcka allmän information om vad du gör med telefonen, men den bör inte innehålla personlig eller privat information."</string> + <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"läsa systemets loggfiler"</string> + <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Tillåter att ett program läser från systemets olika loggfiler. Det innebär att programmet kan upptäcka allmän information om vad du gör med telefonen, men den bör inte innehålla personlig eller privat information."</string> <string name="permlab_diagnostic" msgid="8076743953908000342">"läsa/skriva till resurser som ägs av diag"</string> <string name="permdesc_diagnostic" msgid="3121238373951637049">"Tillåter att ett program läser och skriver till en resurs som ägs av diag-gruppen; till exempel filer i /dev. Detta kan eventuellt påverka systemets stabilitet och säkerhet. Detta bör ENDAST används av tillverkaren eller operatören för maskinvaruspecifik diagnostik."</string> <string name="permlab_changeComponentState" msgid="79425198834329406">"aktivera eller inaktivera programkomponenter"</string> @@ -525,6 +525,14 @@ <string name="orgTypeWork" msgid="29268870505363872">"Arbete"</string> <string name="orgTypeOther" msgid="3951781131570124082">"Övrigt"</string> <string name="orgTypeCustom" msgid="225523415372088322">"Anpassad"</string> + <!-- no translation found for sipAddressTypeCustom (2473580593111590945) --> + <skip /> + <!-- no translation found for sipAddressTypeHome (6093598181069359295) --> + <skip /> + <!-- no translation found for sipAddressTypeWork (6920725730797099047) --> + <skip /> + <!-- no translation found for sipAddressTypeOther (4408436162950119849) --> + <skip /> <string name="contact_status_update_attribution" msgid="5112589886094402795">"via <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> via <xliff:g id="SOURCE">%2$s</xliff:g>"</string> <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Ange PIN-kod"</string> @@ -699,7 +707,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Välj alla"</string> - <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Markera text"</string> + <string name="selectText" msgid="4862359311088898878">"Välj ord"</string> <string name="cut" msgid="3092569408438626261">"Klipp ut"</string> <string name="copy" msgid="2681946229533511987">"Kopiera"</string> <string name="paste" msgid="5629880836805036433">"Klistra in"</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index ea46db0..6efa8e0 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -266,8 +266,8 @@ <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Uygulamaların uygulama önbelleği dizinindeki dosyaları silerek telefonda yer açmasına izin verir. Erişim genellikle sistem işlemlerine ve yüksek düzeyde kısıtlı olarak verilir."</string> <string name="permlab_movePackage" msgid="728454979946503926">"Uygulama kaynaklarını taşı"</string> <string name="permdesc_movePackage" msgid="6323049291923925277">"Bir uygulamanın, uygulama kaynaklarını dahili ve harici ortamlar arasında taşımasına olanak tanır."</string> - <string name="permlab_readLogs" msgid="4811921703882532070">"sistem günlük dosyalarını oku"</string> - <string name="permdesc_readLogs" msgid="2257937955580475902">"Uygulamaların sistemin çeşitli günlük dosyalarından okumalarına izin verir. Bu, uygulamaların telefon ile neler yaptığınız ile ilgili genel bilgi bulmasına izin verir, ancak bunlar kişisel veya özel bir bilgi içermemelidir."</string> + <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"sistem günlük dosyalarını oku"</string> + <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"Uygulamaların sistemin çeşitli günlük dosyalarından okumalarına izin verir. Bu, uygulamaların telefon ile neler yaptığınız ile ilgili genel bilgi bulmasına izin verir, ancak bunlar kişisel veya özel bir bilgi içermemelidir."</string> <string name="permlab_diagnostic" msgid="8076743953908000342">"sahibi tanılama olan kaynakları oku/bunlara yaz"</string> <string name="permdesc_diagnostic" msgid="3121238373951637049">"Uygulamanın tanılama grubundaki bir kaynağa ait herhangi bir kaynağı; örneğin /dev içindeki dosyaları okumasına ve bunlara yazmasına izin verir. Bu işlevin sistem kararlılığını ve güvenliğini olumsuz etkileme olasılığı vardır. Üretici veya operatör tarafından YALNIZCA donanıma özgü tanılama için kullanılmalıdır."</string> <string name="permlab_changeComponentState" msgid="79425198834329406">"uygulama bileşenlerini etkinleştir veya devre dışı bırak"</string> @@ -525,6 +525,14 @@ <string name="orgTypeWork" msgid="29268870505363872">"İş"</string> <string name="orgTypeOther" msgid="3951781131570124082">"Diğer"</string> <string name="orgTypeCustom" msgid="225523415372088322">"Özel"</string> + <!-- no translation found for sipAddressTypeCustom (2473580593111590945) --> + <skip /> + <!-- no translation found for sipAddressTypeHome (6093598181069359295) --> + <skip /> + <!-- no translation found for sipAddressTypeWork (6920725730797099047) --> + <skip /> + <!-- no translation found for sipAddressTypeOther (4408436162950119849) --> + <skip /> <string name="contact_status_update_attribution" msgid="5112589886094402795">"<xliff:g id="SOURCE">%1$s</xliff:g> aracılığıyla"</string> <string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="SOURCE">%2$s</xliff:g> ile <xliff:g id="DATE">%1$s</xliff:g> tarihinde"</string> <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"PIN kodunu gir"</string> @@ -699,7 +707,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Tümünü seç"</string> - <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Metin seç"</string> + <string name="selectText" msgid="4862359311088898878">"Kelime seçin"</string> <string name="cut" msgid="3092569408438626261">"Kes"</string> <string name="copy" msgid="2681946229533511987">"Kopyala"</string> <string name="paste" msgid="5629880836805036433">"Yapıştır"</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index b963612..c8f2893 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -266,8 +266,8 @@ <string name="permdesc_clearAppCache" msgid="7740465694193671402">"允许应用程序通过删除应用程序缓存目录中的文件释放手机存储空间。通常此权限只适用于系统进程。"</string> <string name="permlab_movePackage" msgid="728454979946503926">"移动应用程序资源"</string> <string name="permdesc_movePackage" msgid="6323049291923925277">"允许应用程序在内部介质和外部介质之间移动应用程序资源。"</string> - <string name="permlab_readLogs" msgid="4811921703882532070">"读取系统日志文件"</string> - <string name="permdesc_readLogs" msgid="2257937955580475902">"允许应用程序从系统的各日志文件中读取信息。这样应用程序可以发现您的手机使用情况,但这些信息不应包含任何个人信息或保密信息。"</string> + <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"读取系统日志文件"</string> + <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"允许应用程序从系统的各日志文件中读取信息。这样应用程序可以发现您的手机使用情况,但这些信息不应包含任何个人信息或保密信息。"</string> <string name="permlab_diagnostic" msgid="8076743953908000342">"读取/写入诊断所拥有的资源"</string> <string name="permdesc_diagnostic" msgid="3121238373951637049">"允许应用程序读取/写入诊断组所拥有的任何资源(例如,/dev 中的文件)。这可能会影响系统稳定性和安全性。此权限仅供制造商或运营商诊断硬件问题。"</string> <string name="permlab_changeComponentState" msgid="79425198834329406">"启用或停用应用程序组件"</string> @@ -525,6 +525,14 @@ <string name="orgTypeWork" msgid="29268870505363872">"公司"</string> <string name="orgTypeOther" msgid="3951781131570124082">"其他"</string> <string name="orgTypeCustom" msgid="225523415372088322">"自定义"</string> + <!-- no translation found for sipAddressTypeCustom (2473580593111590945) --> + <skip /> + <!-- no translation found for sipAddressTypeHome (6093598181069359295) --> + <skip /> + <!-- no translation found for sipAddressTypeWork (6920725730797099047) --> + <skip /> + <!-- no translation found for sipAddressTypeOther (4408436162950119849) --> + <skip /> <string name="contact_status_update_attribution" msgid="5112589886094402795">"通过 <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"时间:<xliff:g id="DATE">%1$s</xliff:g>,方式:<xliff:g id="SOURCE">%2$s</xliff:g>"</string> <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"输入 PIN 码"</string> @@ -699,7 +707,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"全选"</string> - <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"选择文字"</string> + <string name="selectText" msgid="4862359311088898878">"选择文字"</string> <string name="cut" msgid="3092569408438626261">"剪切"</string> <string name="copy" msgid="2681946229533511987">"复制"</string> <string name="paste" msgid="5629880836805036433">"粘贴"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 939510c..fcfa464 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -266,8 +266,8 @@ <string name="permdesc_clearAppCache" msgid="7740465694193671402">"允許應用程式刪除快取目錄裡的檔案,釋放儲存空間。此操作通常受到系統程序嚴格限制。"</string> <string name="permlab_movePackage" msgid="728454979946503926">"移動應用程式資源"</string> <string name="permdesc_movePackage" msgid="6323049291923925277">"允許應用程式將應用程式資源從內部媒體移到外部媒體,反之亦可。"</string> - <string name="permlab_readLogs" msgid="4811921703882532070">"讀取系統記錄檔"</string> - <string name="permdesc_readLogs" msgid="2257937955580475902">"允許應用程式讀取系統記錄檔。此項操作可讓應用程式了解目前手機操作狀態,但內容應不含任何個人或隱私資訊。"</string> + <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"讀取系統記錄檔"</string> + <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" msgid="8896449437464867766">"允許應用程式讀取系統記錄檔。此項操作可讓應用程式了解目前手機操作狀態,但內容應不含任何個人或隱私資訊。"</string> <string name="permlab_diagnostic" msgid="8076743953908000342">"讀寫 diag 擁有的資源"</string> <string name="permdesc_diagnostic" msgid="3121238373951637049">"允許應用程式讀寫 diag 群組的資源;例如:/dev 裡的檔案。這可能會影響系統穩定性與安全性。此功能僅供製造商或技術人員用於硬體規格偵測。"</string> <string name="permlab_changeComponentState" msgid="79425198834329406">"啟用或停用應用程式元件"</string> @@ -525,6 +525,14 @@ <string name="orgTypeWork" msgid="29268870505363872">"公司"</string> <string name="orgTypeOther" msgid="3951781131570124082">"其他"</string> <string name="orgTypeCustom" msgid="225523415372088322">"自訂"</string> + <!-- no translation found for sipAddressTypeCustom (2473580593111590945) --> + <skip /> + <!-- no translation found for sipAddressTypeHome (6093598181069359295) --> + <skip /> + <!-- no translation found for sipAddressTypeWork (6920725730797099047) --> + <skip /> + <!-- no translation found for sipAddressTypeOther (4408436162950119849) --> + <skip /> <string name="contact_status_update_attribution" msgid="5112589886094402795">"透過 <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g>透過「<xliff:g id="SOURCE">%2$s</xliff:g>」"</string> <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"輸入 PIN 碼"</string> @@ -699,7 +707,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"全部選取"</string> - <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"選取文字"</string> + <string name="selectText" msgid="4862359311088898878">"選取字詞"</string> <string name="cut" msgid="3092569408438626261">"剪下"</string> <string name="copy" msgid="2681946229533511987">"複製"</string> <string name="paste" msgid="5629880836805036433">"貼上"</string> diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index fb49120..a8c00a6 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -75,7 +75,8 @@ header in the Action Bar. The primary differences between an icon and a logo are that logos are often wider and more detailed, and are used without an accompanying text caption. This must be a reference - to a Drawable resource containing the image definition. --> + to a Drawable resource containing the image definition. + @hide --> <attr name="logo" format="reference" /> <!-- Name of the activity to be launched to manage application's space on @@ -399,7 +400,8 @@ <attr name="syncable" format="boolean" /> <!-- Flag declaring this activity to be 'immersive'; immersive activities - should not be interrupted with other activities or notifications. --> + should not be interrupted with other activities or notifications. + @hide --> <attr name="immersive" format="boolean" /> <!-- Specify the order in which content providers hosted by a process @@ -715,7 +717,6 @@ <attr name="theme" /> <attr name="label" /> <attr name="icon" /> - <attr name="logo" /> <attr name="description" /> <attr name="permission" /> <attr name="process" /> @@ -774,7 +775,6 @@ <attr name="name" /> <attr name="label" /> <attr name="icon" /> - <attr name="logo" /> <attr name="permissionGroup" /> <attr name="description" /> <attr name="protectionLevel" /> @@ -799,7 +799,6 @@ <attr name="name" /> <attr name="label" /> <attr name="icon" /> - <attr name="logo" /> <attr name="description" /> </declare-styleable> @@ -829,7 +828,6 @@ <attr name="name" /> <attr name="label" /> <attr name="icon" /> - <attr name="logo" /> </declare-styleable> <!-- The <code>uses-permission</code> tag requests a @@ -1034,7 +1032,6 @@ <attr name="label" /> <attr name="description" /> <attr name="icon" /> - <attr name="logo" /> <attr name="process" /> <attr name="authorities" /> <attr name="syncable" /> @@ -1114,7 +1111,6 @@ <attr name="label" /> <attr name="description" /> <attr name="icon" /> - <attr name="logo" /> <attr name="permission" /> <attr name="process" /> <!-- Specify whether the service is enabled or not (that is, can be instantiated by the system). @@ -1147,7 +1143,6 @@ <attr name="label" /> <attr name="description" /> <attr name="icon" /> - <attr name="logo" /> <attr name="permission" /> <attr name="process" /> <!-- Specify whether the receiver is enabled or not (that is, can be instantiated by the system). @@ -1180,7 +1175,6 @@ <attr name="label" /> <attr name="description" /> <attr name="icon" /> - <attr name="logo" /> <attr name="launchMode" /> <attr name="screenOrientation" /> <attr name="configChanges" /> @@ -1206,7 +1200,6 @@ this activity. A value besides "unspecified" here overrides any value in the theme. --> <attr name="windowSoftInputMode" /> - <attr name="immersive" /> </declare-styleable> <!-- The <code>activity-alias</code> tag declares a new @@ -1235,7 +1228,6 @@ <attr name="label" /> <attr name="description" /> <attr name="icon" /> - <attr name="logo" /> <attr name="permission" /> <!-- Specify whether the activity-alias is enabled or not (that is, can be instantiated by the system). It can also be specified for an application as a whole, in which case a value of "false" @@ -1305,7 +1297,6 @@ parent="AndroidManifestActivity AndroidManifestReceiver AndroidManifestService"> <attr name="label" /> <attr name="icon" /> - <attr name="logo" /> <attr name="priority" /> </declare-styleable> @@ -1412,7 +1403,6 @@ <attr name="targetPackage" /> <attr name="label" /> <attr name="icon" /> - <attr name="logo" /> <attr name="handleProfiling" /> <attr name="functionalTest" /> </declare-styleable> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 808b371..ebccfb6 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1619,6 +1619,15 @@ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_setAlarm">set alarm in alarm clock</string> + <!-- Description of an application permission, listed so the user can choose whether + they want to allow the application to do this. --> + <string name="permdesc_setAlarm">Allows the application to set an alarm in + an installed alarm clock application. Some alarm clock applications may + not implement this feature.</string> + + <!-- Title of an application permission, listed so the user can choose whether + they want to allow the application to do this. --> <string name="permlab_writeGeolocationPermissions">Modify Browser geolocation permissions</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java index 975a4c2..1289a9e 100755 --- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java +++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java @@ -167,8 +167,7 @@ public class PackageManagerTests extends AndroidTestCase { return ipm; } - public boolean invokeInstallPackage(Uri packageURI, int flags, - GenericReceiver receiver) throws Exception { + public boolean invokeInstallPackage(Uri packageURI, int flags, GenericReceiver receiver) { PackageInstallObserver observer = new PackageInstallObserver(); final boolean received = false; mContext.registerReceiver(receiver, receiver.filter); @@ -180,11 +179,15 @@ public class PackageManagerTests extends AndroidTestCase { getPm().installPackage(packageURI, observer, flags, null); long waitTime = 0; while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) { - observer.wait(WAIT_TIME_INCR); - waitTime += WAIT_TIME_INCR; + try { + observer.wait(WAIT_TIME_INCR); + waitTime += WAIT_TIME_INCR; + } catch (InterruptedException e) { + Log.i(TAG, "Interrupted during sleep", e); + } } if(!observer.isDone()) { - throw new Exception("Timed out waiting for packageInstalled callback"); + fail("Timed out waiting for packageInstalled callback"); } if (observer.returnCode != PackageManager.INSTALL_SUCCEEDED) { Log.i(TAG, "Failed to install with error code = " + observer.returnCode); @@ -193,11 +196,15 @@ public class PackageManagerTests extends AndroidTestCase { // Verify we received the broadcast waitTime = 0; while((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME) ) { - receiver.wait(WAIT_TIME_INCR); - waitTime += WAIT_TIME_INCR; + try { + receiver.wait(WAIT_TIME_INCR); + waitTime += WAIT_TIME_INCR; + } catch (InterruptedException e) { + Log.i(TAG, "Interrupted during sleep", e); + } } if(!receiver.isDone()) { - throw new Exception("Timed out waiting for PACKAGE_ADDED notification"); + fail("Timed out waiting for PACKAGE_ADDED notification"); } return receiver.received; } @@ -207,7 +214,7 @@ public class PackageManagerTests extends AndroidTestCase { } } - public void invokeInstallPackageFail(Uri packageURI, int flags, int result) throws Exception { + public void invokeInstallPackageFail(Uri packageURI, int flags, int result) { PackageInstallObserver observer = new PackageInstallObserver(); try { // Wait on observer @@ -215,11 +222,15 @@ public class PackageManagerTests extends AndroidTestCase { getPm().installPackage(packageURI, observer, flags, null); long waitTime = 0; while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) { - observer.wait(WAIT_TIME_INCR); - waitTime += WAIT_TIME_INCR; + try { + observer.wait(WAIT_TIME_INCR); + waitTime += WAIT_TIME_INCR; + } catch (InterruptedException e) { + Log.i(TAG, "Interrupted during sleep", e); + } } if(!observer.isDone()) { - throw new Exception("Timed out waiting for packageInstalled callback"); + fail("Timed out waiting for packageInstalled callback"); } assertEquals(observer.returnCode, result); } @@ -265,7 +276,7 @@ public class PackageManagerTests extends AndroidTestCase { Environment.getExternalStorageDirectory().getPath()); sdSize = (long)sdStats.getAvailableBlocks() * (long)sdStats.getBlockSize(); - // TODO check for thesholds here + // TODO check for thresholds here return pkgLen <= sdSize; } @@ -368,12 +379,21 @@ public class PackageManagerTests extends AndroidTestCase { assertFalse((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0); assertTrue(info.nativeLibraryDir.startsWith(dataDir.getPath())); } else if (rLoc == INSTALL_LOC_SD){ - assertTrue((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0); - assertTrue(srcPath.startsWith(SECURE_CONTAINERS_PREFIX)); - assertTrue(publicSrcPath.startsWith(SECURE_CONTAINERS_PREFIX)); - assertTrue(info.nativeLibraryDir.startsWith(SECURE_CONTAINERS_PREFIX)); + assertTrue("Application flags (" + info.flags + + ") should contain FLAG_EXTERNAL_STORAGE", + (info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0); + assertTrue("The APK path (" + srcPath + ") should start with " + + SECURE_CONTAINERS_PREFIX, srcPath + .startsWith(SECURE_CONTAINERS_PREFIX)); + assertTrue("The public APK path (" + publicSrcPath + ") should start with " + + SECURE_CONTAINERS_PREFIX, publicSrcPath + .startsWith(SECURE_CONTAINERS_PREFIX)); + assertTrue("The native library path (" + info.nativeLibraryDir + + ") should start with " + SECURE_CONTAINERS_PREFIX, + info.nativeLibraryDir.startsWith(SECURE_CONTAINERS_PREFIX)); } else { // TODO handle error. Install should have failed. + fail("Install should have failed"); } } } catch (NameNotFoundException e) { @@ -544,8 +564,6 @@ public class PackageManagerTests extends AndroidTestCase { // Verify installed information assertInstall(pkg, flags, expInstallLocation); } - } catch (Exception e) { - failStr("Failed with exception : " + e); } finally { if (cleanUp) { cleanUpInstall(ip); diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml index 6bcaaaf..1fd7bba 100644 --- a/data/fonts/fonts.xml +++ b/data/fonts/fonts.xml @@ -44,5 +44,5 @@ <name>monaco</name> </font> <fallback ttf="DroidSansFallback" /> - <fallback ttf="DroidSansJapanese" /> -</fonts>
\ No newline at end of file + <fallback ttf="MTLmr3m" /> +</fonts> diff --git a/docs/html/sdk/adt_download.jd b/docs/html/sdk/adt_download.jd index 5e642d7..3da576a 100644 --- a/docs/html/sdk/adt_download.jd +++ b/docs/html/sdk/adt_download.jd @@ -22,10 +22,17 @@ ADT Installation</a>.</p> <th>Notes</th> </tr> <tr> + <td>0.9.9</td> + <td><a href="http://dl-ssl.google.com/android/ADT-0.9.9.zip">ADT-0.9.9.zip</a></td> + <td><nobr>8301681 bytes</nobr></td> + <td>7deff0c9b25940a74cea7a0815a3bc36</td> + <td>Requires SDK Tools, Revision 7 <em><nobr>September 2010</nobr></em></td> + </tr> + <tr> <td>0.9.8</td> <td><a href="http://dl-ssl.google.com/android/ADT-0.9.8.zip">ADT-0.9.8.zip</a></td> - <td><nobr>8703591 bytes</nobr></td> - <td>22070f8e52924605a3b3abf87c1ba39f</td> + <td><nobr>8301417 bytes</nobr></td> + <td>27e0de800512f13feae46fb554e6ee2f</td> <td>Requires SDK Tools, Revision 7 <em><nobr>September 2010</nobr></em></td> </tr> <tr> diff --git a/docs/html/sdk/eclipse-adt.jd b/docs/html/sdk/eclipse-adt.jd index a984d56..9f3c8b0 100644 --- a/docs/html/sdk/eclipse-adt.jd +++ b/docs/html/sdk/eclipse-adt.jd @@ -1,9 +1,9 @@ page.title=ADT Plugin for Eclipse sdk.preview=0 -adt.zip.version=0.9.8 -adt.zip.download=ADT-0.9.8.zip -adt.zip.bytes=8703591 -adt.zip.checksum=22070f8e52924605a3b3abf87c1ba39f +adt.zip.version=0.9.9 +adt.zip.download=ADT-0.9.9.zip +adt.zip.bytes=8301681 +adt.zip.checksum=7deff0c9b25940a74cea7a0815a3bc36 @jd:body @@ -100,11 +100,40 @@ padding: .25em 1em; </style> - - <div class="toggleable opened"> <a href="#" onclick="return toggleDiv(this)"> <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px" /> +ADT 0.9.9</a> <em>(September 2010)</em> + <div class="toggleme"> + + +</ul> +</dd> + +<dl> + +<dt>Dependencies:</dt> + +<dd><p>ADT 0.9.9 replaces ADT 0.9.8 and is designed for use with SDK Tools r7 +and later. ADT 0.9.9 includes the ADT 0.9.8 features as well as an important +bugfix, so we recommend that you upgrade as soon as possible. If you haven't +already installed SDK Tools r7 into your SDK, use the Android SDK Manager to do +so.</p></dd> + +<dt>General notes:</dt> +<dd> +<ul> +<li>Fixes a problem in project import, in which source files were deleted in some cases.</li> +<li>Includes all other ADT 0.9.8 features (see below).</li> +</ul> +</dd> +</dl> + </div> +</div> + +<div class="toggleable closed"> + <a href="#" onclick="return toggleDiv(this)"> + <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px" /> ADT 0.9.8</a> <em>(September 2010)</em> <div class="toggleme"> @@ -116,9 +145,7 @@ ADT 0.9.8</a> <em>(September 2010)</em> <dt>Dependencies:</dt> -<dd><p>ADT 0.9.8 is designed for use with SDK Tools r7 and later. Before -updating to ADT 0.9.8, we highly recommend that you use the Android SDK and -AVD Manager to install SDK Tools r7 into your SDK.</p></dd> +<dd><p>ADT 0.9.8 is now deprecated. Please use ADT 0.9.9 instead.</p></dd> <dt>General notes:</dt> <dd> diff --git a/docs/html/sdk/requirements.jd b/docs/html/sdk/requirements.jd index d710b8e..7b11654 100644 --- a/docs/html/sdk/requirements.jd +++ b/docs/html/sdk/requirements.jd @@ -6,7 +6,7 @@ Android applications using the Android SDK. </p> <h3>Supported Operating Systems</h3> <ul> - <li>Windows XP (32-bit) or Vista (32- or 64-bit)</li> + <li>Windows XP (32-bit), Vista (32- or 64-bit), or Windows 7 (32- or 64-bit)</li> <li>Mac OS X 10.5.8 or later (x86 only)</li> <li>Linux (tested on Linux Ubuntu Hardy Heron) <ul> diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs index a665e95..fdf4438 100644 --- a/docs/html/sdk/sdk_toc.cs +++ b/docs/html/sdk/sdk_toc.cs @@ -94,7 +94,7 @@ <span style="display:none" class="zh-TW"></span> </h2> <ul> - <li><a href="<?cs var:toroot ?>sdk/eclipse-adt.html">ADT 0.9.8 + <li><a href="<?cs var:toroot ?>sdk/eclipse-adt.html">ADT 0.9.9 <span style="display:none" class="de"></span> <span style="display:none" class="es"></span> <span style="display:none" class="fr"></span> diff --git a/include/utils/ZipFileRO.h b/include/utils/ZipFileRO.h index 97d31f4..9668bde 100644 --- a/include/utils/ZipFileRO.h +++ b/include/utils/ZipFileRO.h @@ -24,8 +24,9 @@ #ifndef __LIBS_ZIPFILERO_H #define __LIBS_ZIPFILERO_H -#include "Errors.h" -#include "FileMap.h" +#include <utils/Errors.h> +#include <utils/FileMap.h> +#include <utils/threads.h> #include <stdio.h> #include <stdlib.h> @@ -211,6 +212,9 @@ private: /* open Zip archive */ int mFd; + /* Lock for handling the file descriptor (seeks, etc) */ + mutable Mutex mFdLock; + /* zip file name */ char* mFileName; diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index a3e117f..13c58f0 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -517,12 +517,26 @@ status_t IPCThreadState::transact(int32_t handle, } if ((flags & TF_ONE_WAY) == 0) { + #if 0 + if (code == 4) { // relayout + LOGI(">>>>>> CALLING transaction 4"); + } else { + LOGI(">>>>>> CALLING transaction %d", code); + } + #endif if (reply) { err = waitForResponse(reply); } else { Parcel fakeReply; err = waitForResponse(&fakeReply); } + #if 0 + if (code == 4) { // relayout + LOGI("<<<<<< RETURNING transaction 4"); + } else { + LOGI("<<<<<< RETURNING transaction %d", code); + } + #endif IF_LOG_TRANSACTIONS() { TextOutput::Bundle _b(alog); diff --git a/libs/utils/ZipFileRO.cpp b/libs/utils/ZipFileRO.cpp index 2d53136..9fcae72 100644 --- a/libs/utils/ZipFileRO.cpp +++ b/libs/utils/ZipFileRO.cpp @@ -22,6 +22,7 @@ #include <utils/ZipFileRO.h> #include <utils/Log.h> #include <utils/misc.h> +#include <utils/threads.h> #include <zlib.h> @@ -195,7 +196,7 @@ bool ZipFileRO::mapCentralDirectory(void) free(scanBuf); return false; } else if (header != kLFHSignature) { - LOGV("Not a Zip archive (found 0x%08x)\n", val); + LOGV("Not a Zip archive (found 0x%08x)\n", header); free(scanBuf); return false; } @@ -496,15 +497,21 @@ bool ZipFileRO::getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen, } unsigned char lfhBuf[kLFHLen]; - if (lseek(mFd, localHdrOffset, SEEK_SET) != localHdrOffset) { - LOGW("failed seeking to lfh at offset %ld\n", localHdrOffset); - return false; - } - ssize_t actual = - TEMP_FAILURE_RETRY(read(mFd, lfhBuf, sizeof(lfhBuf))); - if (actual != sizeof(lfhBuf)) { - LOGW("failed reading lfh from offset %ld\n", localHdrOffset); - return false; + + { + AutoMutex _l(mFdLock); + + if (lseek(mFd, localHdrOffset, SEEK_SET) != localHdrOffset) { + LOGW("failed seeking to lfh at offset %ld\n", localHdrOffset); + return false; + } + + ssize_t actual = + TEMP_FAILURE_RETRY(read(mFd, lfhBuf, sizeof(lfhBuf))); + if (actual != sizeof(lfhBuf)) { + LOGW("failed reading lfh from offset %ld\n", localHdrOffset); + return false; + } } if (get4LE(lfhBuf) != kLFHSignature) { @@ -636,7 +643,7 @@ bool ZipFileRO::uncompressEntry(ZipEntryRO entry, void* buffer) const memcpy(buffer, ptr, uncompLen); } else { if (!inflateBuffer(buffer, ptr, uncompLen, compLen)) - goto bail; + goto unmap; } if (compLen > kSequentialMin) @@ -644,6 +651,8 @@ bool ZipFileRO::uncompressEntry(ZipEntryRO entry, void* buffer) const result = true; +unmap: + file->release(); bail: return result; } @@ -667,7 +676,7 @@ bool ZipFileRO::uncompressEntry(ZipEntryRO entry, int fd) const getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL); - const FileMap* file = createEntryFileMap(entry); + FileMap* file = createEntryFileMap(entry); if (file == NULL) { goto bail; } @@ -678,21 +687,23 @@ bool ZipFileRO::uncompressEntry(ZipEntryRO entry, int fd) const ssize_t actual = write(fd, ptr, uncompLen); if (actual < 0) { LOGE("Write failed: %s\n", strerror(errno)); - goto bail; + goto unmap; } else if ((size_t) actual != uncompLen) { LOGE("Partial write during uncompress (%zd of %zd)\n", (size_t)actual, (size_t)uncompLen); - goto bail; + goto unmap; } else { LOGI("+++ successful write\n"); } } else { if (!inflateBuffer(fd, ptr, uncompLen, compLen)) - goto bail; + goto unmap; } result = true; +unmap: + file->release(); bail: return result; } diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp index b16372d..cb2f0f9 100644 --- a/media/jni/audioeffect/android_media_AudioEffect.cpp +++ b/media/jni/audioeffect/android_media_AudioEffect.cpp @@ -304,14 +304,7 @@ android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_t lpJniStorage->mCallbackData.audioEffect_class, &lpJniStorage->mCallbackData); - if (jId) { - nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL); - if (nId == NULL) { - LOGE("setup: Error retrieving id pointer"); - lStatus = AUDIOEFFECT_ERROR_BAD_VALUE; - goto setup_failure; - } - } else { + if (jId == NULL) { LOGE("setup: NULL java array for id pointer"); lStatus = AUDIOEFFECT_ERROR_BAD_VALUE; goto setup_failure; @@ -336,8 +329,13 @@ android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_t goto setup_failure; } + nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL); + if (nId == NULL) { + LOGE("setup: Error retrieving id pointer"); + lStatus = AUDIOEFFECT_ERROR_BAD_VALUE; + goto setup_failure; + } nId[0] = lpAudioEffect->id(); - env->ReleasePrimitiveArrayCritical(jId, nId, 0); nId = NULL; diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp index 7b271ce..57cafd4 100644 --- a/media/jni/audioeffect/android_media_Visualizer.cpp +++ b/media/jni/audioeffect/android_media_Visualizer.cpp @@ -246,14 +246,7 @@ android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_th lpJniStorage->mCallbackData.visualizer_class, &lpJniStorage->mCallbackData); - if (jId) { - nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL); - if (nId == NULL) { - LOGE("setup: Error retrieving id pointer"); - lStatus = VISUALIZER_ERROR_BAD_VALUE; - goto setup_failure; - } - } else { + if (jId == NULL) { LOGE("setup: NULL java array for id pointer"); lStatus = VISUALIZER_ERROR_BAD_VALUE; goto setup_failure; @@ -275,8 +268,13 @@ android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_th goto setup_failure; } + nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL); + if (nId == NULL) { + LOGE("setup: Error retrieving id pointer"); + lStatus = VISUALIZER_ERROR_BAD_VALUE; + goto setup_failure; + } nId[0] = lpVisualizer->id(); - env->ReleasePrimitiveArrayCritical(jId, nId, 0); nId = NULL; @@ -424,7 +422,6 @@ android_media_visualizer_native_getWaveForm(JNIEnv *env, jobject thiz, jbyteArra jint status = translateError(lpVisualizer->getWaveForm((uint8_t *)nWaveform)); env->ReleasePrimitiveArrayCritical(jWaveform, nWaveform, 0); - return status; } diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index f0d8943..ba1e218 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -2111,7 +2111,15 @@ void MPEG4Writer::Track::writeTrackHeader( mOwner->endBox(); // d263 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { CHECK(mCodecSpecificData); - CHECK(mCodecSpecificDataSize > 0); + CHECK(mCodecSpecificDataSize >= 5); + + // Patch avcc's lengthSize field to match the number + // of bytes we use to indicate the size of a nal unit. + uint8_t *ptr = (uint8_t *)mCodecSpecificData; + ptr[4] = + (ptr[4] & 0xfc) + | (mOwner->useNalLengthFour() ? 3 : 1); + mOwner->beginBox("avcC"); mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); mOwner->endBox(); // avcC diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp index 0437263..2d1a278 100644 --- a/opengl/libs/EGL/egl.cpp +++ b/opengl/libs/EGL/egl.cpp @@ -428,19 +428,14 @@ static void(*findProcAddress(const char* name, // ---------------------------------------------------------------------------- -static void gl_no_context() { +static int gl_no_context() { tls_t* tls = getTLS(); if (tls->logCallWithNoContext == EGL_TRUE) { tls->logCallWithNoContext = EGL_FALSE; LOGE("call to OpenGL ES API with no current context " "(logged once per thread)"); } -} - -// Always return GL_INVALID_OPERATION from glGetError() when called from -// a thread without a bound context. -static GLenum gl_no_context_glGetError() { - return GL_INVALID_OPERATION; + return 0; } static void early_egl_init(void) @@ -454,8 +449,6 @@ static void early_egl_init(void) addr, sizeof(gHooksNoContext)); - gHooksNoContext.gl.glGetError = gl_no_context_glGetError; - setGlThreadSpecific(&gHooksNoContext); } diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp index 924737e..18dd483 100644 --- a/opengl/libs/GLES2/gl2.cpp +++ b/opengl/libs/GLES2/gl2.cpp @@ -58,6 +58,7 @@ using namespace android; "ldr r12, [r12, %[tls]] \n" \ "cmp r12, #0 \n" \ "ldrne pc, [r12, %[api]] \n" \ + "mov r0, #0 \n" \ "bx lr \n" \ : \ : [tls] "J"(TLS_SLOT_OPENGL_API*4), \ diff --git a/opengl/libs/GLES_CM/gl.cpp b/opengl/libs/GLES_CM/gl.cpp index d71ff76..ee29f12 100644 --- a/opengl/libs/GLES_CM/gl.cpp +++ b/opengl/libs/GLES_CM/gl.cpp @@ -114,6 +114,7 @@ GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type, "ldr r12, [r12, %[tls]] \n" \ "cmp r12, #0 \n" \ "ldrne pc, [r12, %[api]] \n" \ + "mov r0, #0 \n" \ "bx lr \n" \ : \ : [tls] "J"(TLS_SLOT_OPENGL_API*4), \ diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index ade93da..6e2bfdb 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -327,10 +327,7 @@ public class SettingsProvider extends ContentProvider { try { final String value = c.moveToNext() ? c.getString(0) : null; if (value == null) { - final SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); - String serial = SystemProperties.get("ro.serialno", ""); - random.setSeed( - (serial + System.nanoTime() + new SecureRandom().nextLong()).getBytes()); + final SecureRandom random = new SecureRandom(); final String newAndroidIdValue = Long.toHexString(random.nextLong()); Log.d(TAG, "Generated and saved new ANDROID_ID [" + newAndroidIdValue + "]"); final ContentValues values = new ContentValues(); @@ -342,8 +339,6 @@ public class SettingsProvider extends ContentProvider { } } return true; - } catch (NoSuchAlgorithmException e) { - return false; } finally { c.close(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java index d98bd7d..0ca0572 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java @@ -22,6 +22,7 @@ import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.graphics.Canvas; import android.util.Slog; +import android.util.Log; import android.view.ViewDebug; import android.widget.FrameLayout; @@ -124,4 +125,10 @@ public class StatusBarIconView extends AnimatedImageView { public StatusBarIcon getStatusBarIcon() { return mIcon; } + + protected void debug(int depth) { + super.debug(depth); + Log.d("View", debugIndent(depth) + "slot=" + mSlot); + Log.d("View", debugIndent(depth) + "icon=" + mIcon); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java index b555277..fece5ce 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java @@ -82,7 +82,8 @@ import com.android.systemui.statusbar.policy.StatusBarPolicy; public class StatusBarService extends Service implements CommandQueue.Callbacks { static final String TAG = "StatusBarService"; - static final boolean SPEW = true; + static final boolean SPEW_ICONS = true; + static final boolean SPEW = false; public static final String ACTION_STATUSBAR_START = "com.android.internal.policy.statusbar.START"; @@ -346,8 +347,10 @@ public class StatusBarService extends Service implements CommandQueue.Callbacks } public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) { - if (SPEW) Slog.d(TAG, "addIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex - + " icon=" + icon); + if (SPEW_ICONS) { + Slog.d(TAG, "addIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex + + " icon=" + icon); + } StatusBarIconView view = new StatusBarIconView(this, slot); view.set(icon); mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams(mIconSize, mIconSize)); @@ -355,14 +358,18 @@ public class StatusBarService extends Service implements CommandQueue.Callbacks public void updateIcon(String slot, int index, int viewIndex, StatusBarIcon old, StatusBarIcon icon) { - if (SPEW) Slog.d(TAG, "updateIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex - + " old=" + old + " icon=" + icon); + if (SPEW_ICONS) { + Slog.d(TAG, "updateIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex + + " old=" + old + " icon=" + icon); + } StatusBarIconView view = (StatusBarIconView)mStatusIcons.getChildAt(viewIndex); view.set(icon); } public void removeIcon(String slot, int index, int viewIndex) { - if (SPEW) Slog.d(TAG, "removeIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex); + if (SPEW_ICONS) { + Slog.d(TAG, "removeIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex); + } mStatusIcons.removeViewAt(viewIndex); } @@ -1175,50 +1182,17 @@ public class StatusBarService extends Service implements CommandQueue.Callbacks + " scroll " + mScrollView.getScrollX() + "," + mScrollView.getScrollY()); pw.println("mNotificationLinearLayout: " + viewInfo(mNotificationLinearLayout)); } - /* - synchronized (mNotificationData) { - int N = mNotificationData.ongoingCount(); - pw.println(" ongoingCount.size=" + N); - for (int i=0; i<N; i++) { - StatusBarNotification n = mNotificationData.getOngoing(i); - pw.println(" [" + i + "] key=" + n.key + " view=" + n.view); - pw.println(" data=" + n.data); - } - N = mNotificationData.latestCount(); - pw.println(" ongoingCount.size=" + N); - for (int i=0; i<N; i++) { - StatusBarNotification n = mNotificationData.getLatest(i); - pw.println(" [" + i + "] key=" + n.key + " view=" + n.view); - pw.println(" data=" + n.data); - } - } - */ - if (false) { - pw.println("see the logcat for a dump of the views we have created."); + if (true) { // must happen on ui thread mHandler.post(new Runnable() { public void run() { - mStatusBarView.getLocationOnScreen(mAbsPos); - Slog.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1] - + ") " + mStatusBarView.getWidth() + "x" - + mStatusBarView.getHeight()); - mStatusBarView.debug(); - - mExpandedView.getLocationOnScreen(mAbsPos); - Slog.d(TAG, "mExpandedView: ----- (" + mAbsPos[0] + "," + mAbsPos[1] - + ") " + mExpandedView.getWidth() + "x" - + mExpandedView.getHeight()); - mExpandedView.debug(); - - mTrackingView.getLocationOnScreen(mAbsPos); - Slog.d(TAG, "mTrackingView: ----- (" + mAbsPos[0] + "," + mAbsPos[1] - + ") " + mTrackingView.getWidth() + "x" - + mTrackingView.getHeight()); - mTrackingView.debug(); + Slog.d(TAG, "mStatusIcons:"); + mStatusIcons.debug(); } }); } + } void onBarViewAttached() { diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 274124b..384f527 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -232,8 +232,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void handleMotion(MotionEvent event, Runnable finishedCallback) { finishedCallback.run(); + synchronized (mLock) { - mPointerLocationView.addTouchEvent(event); + if (mPointerLocationView != null) { + mPointerLocationView.addTouchEvent(event); + } } } }; @@ -283,7 +286,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { // (See Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR.) int mIncallPowerBehavior; - int mLandscapeRotation = -1; + int mLandscapeRotation = -1; // default landscape rotation + int mSeascapeRotation = -1; // "other" landscape rotation, 180 degrees from mLandscapeRotation int mPortraitRotation = -1; // Nothing to see here, move along... @@ -353,9 +357,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { return true; } // The user preference says we can rotate, and the app is willing to rotate. + // Note we include SCREEN_ORIENTATION_LANDSCAPE since we can use the sensor to choose + // between the two possible landscape rotations. if (mAccelerometerDefault != 0 && (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER - || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) { + || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED + || appOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)) { return true; } // We're in a dock that has a rotation affinity, an the app is willing to rotate. @@ -364,7 +371,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Note we override the nosensor flag here. if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED - || appOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) { + || appOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR + || appOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) { return true; } } @@ -2050,20 +2058,20 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (d.getWidth() > d.getHeight()) { mPortraitRotation = Surface.ROTATION_90; mLandscapeRotation = Surface.ROTATION_0; + mSeascapeRotation = Surface.ROTATION_180; } else { mPortraitRotation = Surface.ROTATION_0; mLandscapeRotation = Surface.ROTATION_90; + mSeascapeRotation = Surface.ROTATION_270; } } synchronized (mLock) { - switch (orientation) { - case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE: - //always return landscape if orientation set to landscape - return mLandscapeRotation; - case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT: - //always return portrait if orientation set to portrait - return mPortraitRotation; + if (orientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) { + //always return portrait if orientation set to portrait + return mPortraitRotation; + } else if (orientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) { + return getCurrentLandscapeRotation(lastRotation); } // case for nosensor meaning ignore sensor and consider only lid // or orientation sensor disabled @@ -2083,6 +2091,26 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + private int getCurrentLandscapeRotation(int lastRotation) { + // landscape-only apps can take either landscape rotation + if (useSensorForOrientationLp(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)) { + int sensorRotation = mOrientationListener.getCurrentRotation(lastRotation); + if (isLandscapeOrSeascape(sensorRotation)) { + return sensorRotation; + } + } + // try to preserve the old rotation if it was landscape + if (isLandscapeOrSeascape(lastRotation)) { + return lastRotation; + } + // default to one of the two landscape rotations + return mLandscapeRotation; + } + + private boolean isLandscapeOrSeascape(int sensorRotation) { + return sensorRotation == mLandscapeRotation || sensorRotation == mSeascapeRotation; + } + public boolean detectSafeMode() { try { int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU); diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 56de765..8a732ed 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -4653,29 +4653,44 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid, goto Exit; } - { - Mutex::Autolock _l(mLock); + // check audio settings permission for global effects + if (sessionId == AudioSystem::SESSION_OUTPUT_MIX && !settingsAllowed()) { + lStatus = PERMISSION_DENIED; + goto Exit; + } - // check audio settings permission for global effects - if (sessionId == AudioSystem::SESSION_OUTPUT_MIX && !settingsAllowed()) { - lStatus = PERMISSION_DENIED; - goto Exit; - } + // Session AudioSystem::SESSION_OUTPUT_STAGE is reserved for output stage effects + // that can only be created by audio policy manager (running in same process) + if (sessionId == AudioSystem::SESSION_OUTPUT_STAGE && getpid() != pid) { + lStatus = PERMISSION_DENIED; + goto Exit; + } - // Session AudioSystem::SESSION_OUTPUT_STAGE is reserved for output stage effects - // that can only be created by audio policy manager (running in same process) - if (sessionId == AudioSystem::SESSION_OUTPUT_STAGE && getpid() != pid) { - lStatus = PERMISSION_DENIED; - goto Exit; - } + // check recording permission for visualizer + if ((memcmp(&pDesc->type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0 || + memcmp(&pDesc->uuid, &VISUALIZATION_UUID_, sizeof(effect_uuid_t)) == 0) && + !recordingAllowed()) { + lStatus = PERMISSION_DENIED; + goto Exit; + } - // check recording permission for visualizer - if ((memcmp(&pDesc->type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0 || - memcmp(&pDesc->uuid, &VISUALIZATION_UUID_, sizeof(effect_uuid_t)) == 0) && - !recordingAllowed()) { - lStatus = PERMISSION_DENIED; + if (output == 0) { + if (sessionId == AudioSystem::SESSION_OUTPUT_STAGE) { + // output must be specified by AudioPolicyManager when using session + // AudioSystem::SESSION_OUTPUT_STAGE + lStatus = BAD_VALUE; goto Exit; + } else if (sessionId == AudioSystem::SESSION_OUTPUT_MIX) { + // if the output returned by getOutputForEffect() is removed before we lock the + // mutex below, the call to checkPlaybackThread_l(output) below will detect it + // and we will exit safely + output = AudioSystem::getOutputForEffect(&desc); } + } + + { + Mutex::Autolock _l(mLock); + if (!EffectIsNullUuid(&pDesc->uuid)) { // if uuid is specified, request effect descriptor @@ -4744,32 +4759,24 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid, // If output is not specified try to find a matching audio session ID in one of the // output threads. - // TODO: allow attachment of effect to inputs + // If output is 0 here, sessionId is neither SESSION_OUTPUT_STAGE nor SESSION_OUTPUT_MIX + // because of code checking output when entering the function. if (output == 0) { - if (sessionId == AudioSystem::SESSION_OUTPUT_STAGE) { - // output must be specified by AudioPolicyManager when using session - // AudioSystem::SESSION_OUTPUT_STAGE - lStatus = BAD_VALUE; - goto Exit; - } else if (sessionId == AudioSystem::SESSION_OUTPUT_MIX) { - output = AudioSystem::getOutputForEffect(&desc); - LOGV("createEffect() got output %d for effect %s", output, desc.name); - } else { - // look for the thread where the specified audio session is present - for (size_t i = 0; i < mPlaybackThreads.size(); i++) { - if (mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId) != 0) { - output = mPlaybackThreads.keyAt(i); - break; - } - } - // If no output thread contains the requested session ID, default to - // first output. The effect chain will be moved to the correct output - // thread when a track with the same session ID is created - if (output == 0 && mPlaybackThreads.size()) { - output = mPlaybackThreads.keyAt(0); + // look for the thread where the specified audio session is present + for (size_t i = 0; i < mPlaybackThreads.size(); i++) { + if (mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId) != 0) { + output = mPlaybackThreads.keyAt(i); + break; } } + // If no output thread contains the requested session ID, default to + // first output. The effect chain will be moved to the correct output + // thread when a track with the same session ID is created + if (output == 0 && mPlaybackThreads.size()) { + output = mPlaybackThreads.keyAt(0); + } } + LOGV("createEffect() got output %d for effect %s", output, desc.name); PlaybackThread *thread = checkPlaybackThread_l(output); if (thread == NULL) { LOGE("createEffect() unknown output thread"); @@ -4777,6 +4784,8 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid, goto Exit; } + // TODO: allow attachment of effect to inputs + wclient = mClients.valueFor(pid); if (wclient != NULL) { diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index f38748b..b8b9e53 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -101,6 +101,64 @@ public class ConnectivityService extends IConnectivityManager.Stub { private boolean mTestMode; private static ConnectivityService sServiceInstance; + private static final int ENABLED = 1; + private static final int DISABLED = 0; + + // Share the event space with NetworkStateTracker (which can't see this + // internal class but sends us events). If you change these, change + // NetworkStateTracker.java too. + private static final int MIN_NETWORK_STATE_TRACKER_EVENT = 1; + private static final int MAX_NETWORK_STATE_TRACKER_EVENT = 100; + + /** + * used internally as a delayed event to make us switch back to the + * default network + */ + private static final int EVENT_RESTORE_DEFAULT_NETWORK = + MAX_NETWORK_STATE_TRACKER_EVENT + 1; + + /** + * used internally to change our mobile data enabled flag + */ + private static final int EVENT_CHANGE_MOBILE_DATA_ENABLED = + MAX_NETWORK_STATE_TRACKER_EVENT + 2; + + /** + * used internally to change our network preference setting + * arg1 = networkType to prefer + */ + private static final int EVENT_SET_NETWORK_PREFERENCE = + MAX_NETWORK_STATE_TRACKER_EVENT + 3; + + /** + * used internally to synchronize inet condition reports + * arg1 = networkType + * arg2 = condition (0 bad, 100 good) + */ + private static final int EVENT_INET_CONDITION_CHANGE = + MAX_NETWORK_STATE_TRACKER_EVENT + 4; + + /** + * used internally to mark the end of inet condition hold periods + * arg1 = networkType + */ + private static final int EVENT_INET_CONDITION_HOLD_END = + MAX_NETWORK_STATE_TRACKER_EVENT + 5; + + /** + * used internally to set the background data preference + * arg1 = TRUE for enabled, FALSE for disabled + */ + private static final int EVENT_SET_BACKGROUND_DATA = + MAX_NETWORK_STATE_TRACKER_EVENT + 6; + + /** + * used internally to set enable/disable cellular data + * arg1 = ENBALED or DISABLED + */ + private static final int EVENT_SET_MOBILE_DATA = + MAX_NETWORK_STATE_TRACKER_EVENT + 7; + private Handler mHandler; // list of DeathRecipients used to make sure features are turned off when @@ -344,30 +402,36 @@ public class ConnectivityService extends IConnectivityManager.Stub { * Sets the preferred network. * @param preference the new preference */ - public synchronized void setNetworkPreference(int preference) { + public void setNetworkPreference(int preference) { enforceChangePermission(); + + mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_NETWORK_PREFERENCE, preference, 0)); + } + + public int getNetworkPreference() { + enforceAccessPermission(); + int preference; + synchronized(this) { + preference = mNetworkPreference; + } + return preference; + } + + private void handleSetNetworkPreference(int preference) { if (ConnectivityManager.isNetworkTypeValid(preference) && mNetAttributes[preference] != null && mNetAttributes[preference].isDefault()) { if (mNetworkPreference != preference) { - persistNetworkPreference(preference); - mNetworkPreference = preference; + final ContentResolver cr = mContext.getContentResolver(); + Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE, preference); + synchronized(this) { + mNetworkPreference = preference; + } enforcePreference(); } } } - public int getNetworkPreference() { - enforceAccessPermission(); - return mNetworkPreference; - } - - private void persistNetworkPreference(int networkPreference) { - final ContentResolver cr = mContext.getContentResolver(); - Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE, - networkPreference); - } - private int getPersistedNetworkPreference() { final ContentResolver cr = mContext.getContentResolver(); @@ -586,8 +650,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetRequestersPids[usedNetworkType].add(currentPid); } } - mHandler.sendMessageDelayed(mHandler.obtainMessage( - NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK, + mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_RESTORE_DEFAULT_NETWORK, f), getRestoreDefaultNetworkDelay()); @@ -613,8 +676,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { synchronized(this) { mFeatureUsers.add(f); } - mHandler.sendMessageDelayed(mHandler.obtainMessage( - NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK, + mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_RESTORE_DEFAULT_NETWORK, f), getRestoreDefaultNetworkDelay()); return network.startUsingNetworkFeature(feature, @@ -784,15 +846,18 @@ public class ConnectivityService extends IConnectivityManager.Stub { android.Manifest.permission.CHANGE_BACKGROUND_DATA_SETTING, "ConnectivityService"); - if (getBackgroundDataSetting() == allowBackgroundDataUsage) return; - - Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.BACKGROUND_DATA, - allowBackgroundDataUsage ? 1 : 0); + mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_BACKGROUND_DATA, + (allowBackgroundDataUsage ? ENABLED : DISABLED), 0)); + } - Intent broadcast = new Intent( - ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED); - mContext.sendBroadcast(broadcast); + private void handleSetBackgroundData(boolean enabled) { + if (enabled != getBackgroundDataSetting()) { + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.BACKGROUND_DATA, enabled ? 1 : 0); + Intent broadcast = new Intent( + ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED); + mContext.sendBroadcast(broadcast); + } } /** @@ -809,10 +874,15 @@ public class ConnectivityService extends IConnectivityManager.Stub { /** * @see ConnectivityManager#setMobileDataEnabled(boolean) */ - public synchronized void setMobileDataEnabled(boolean enabled) { + public void setMobileDataEnabled(boolean enabled) { enforceChangePermission(); if (DBG) Slog.d(TAG, "setMobileDataEnabled(" + enabled + ")"); + mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_MOBILE_DATA, + (enabled ? ENABLED : DISABLED), 0)); + } + + private void handleSetMobileData(boolean enabled) { if (getMobileDataEnabled() == enabled) return; Settings.Secure.putInt(mContext.getContentResolver(), @@ -820,7 +890,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (enabled) { if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) { - if (DBG) Slog.d(TAG, "starting up " + mNetTrackers[ConnectivityManager.TYPE_MOBILE]); + if (DBG) { + Slog.d(TAG, "starting up " + mNetTrackers[ConnectivityManager.TYPE_MOBILE]); + } mNetTrackers[ConnectivityManager.TYPE_MOBILE].reconnect(); } } else { @@ -1486,74 +1558,42 @@ public class ConnectivityService extends IConnectivityManager.Stub { case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: // fill me in break; - case NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK: + case EVENT_RESTORE_DEFAULT_NETWORK: FeatureUser u = (FeatureUser)msg.obj; u.expire(); break; - case NetworkStateTracker.EVENT_INET_CONDITION_CHANGE: - if (DBG) { - Slog.d(TAG, "Inet connectivity change, net=" + - msg.arg1 + ", condition=" + msg.arg2 + - ",mActiveDefaultNetwork=" + mActiveDefaultNetwork); - } - if (mActiveDefaultNetwork == -1) { - if (DBG) Slog.d(TAG, "no active default network - aborting"); - break; - } - if (mActiveDefaultNetwork != msg.arg1) { - if (DBG) Slog.d(TAG, "given net not default - aborting"); - break; - } - mDefaultInetCondition = msg.arg2; - int delay; - if (mInetConditionChangeInFlight == false) { - if (DBG) Slog.d(TAG, "starting a change hold"); - // setup a new hold to debounce this - if (mDefaultInetCondition > 50) { - delay = Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.INET_CONDITION_DEBOUNCE_UP_DELAY, 500); - } else { - delay = Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.INET_CONDITION_DEBOUNCE_DOWN_DELAY, 3000); - } - mInetConditionChangeInFlight = true; - sendMessageDelayed(obtainMessage( - NetworkStateTracker.EVENT_INET_CONDITION_HOLD_END, - mActiveDefaultNetwork, mDefaultConnectionSequence), delay); - } else { - // we've set the new condition, when this hold ends that will get - // picked up - if (DBG) Slog.d(TAG, "currently in hold - not setting new end evt"); - } + case EVENT_INET_CONDITION_CHANGE: + { + int netType = msg.arg1; + int condition = msg.arg2; + handleInetConditionChange(netType, condition); break; - case NetworkStateTracker.EVENT_INET_CONDITION_HOLD_END: - if (DBG) { - Slog.d(TAG, "Inet hold end, net=" + msg.arg1 + - ", condition =" + mDefaultInetCondition + - ", published condition =" + mDefaultInetConditionPublished); - } - mInetConditionChangeInFlight = false; - - if (mActiveDefaultNetwork == -1) { - if (DBG) Slog.d(TAG, "no active default network - aborting"); - break; - } - if (mDefaultConnectionSequence != msg.arg2) { - if (DBG) Slog.d(TAG, "event hold for obsolete network - aborting"); - break; - } - if (mDefaultInetConditionPublished == mDefaultInetCondition) { - if (DBG) Slog.d(TAG, "no change in condition - aborting"); - break; - } - NetworkInfo networkInfo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(); - if (networkInfo.isConnected() == false) { - if (DBG) Slog.d(TAG, "default network not connected - aborting"); - break; - } - mDefaultInetConditionPublished = mDefaultInetCondition; - sendInetConditionBroadcast(networkInfo); + } + case EVENT_INET_CONDITION_HOLD_END: + { + int netType = msg.arg1; + int sequence = msg.arg2; + handleInetConditionHoldEnd(netType, sequence); break; + } + case EVENT_SET_NETWORK_PREFERENCE: + { + int preference = msg.arg1; + handleSetNetworkPreference(preference); + break; + } + case EVENT_SET_BACKGROUND_DATA: + { + boolean enabled = (msg.arg1 == ENABLED); + handleSetBackgroundData(enabled); + break; + } + case EVENT_SET_MOBILE_DATA: + { + boolean enabled = (msg.arg1 == ENABLED); + handleSetMobileData(enabled); + break; + } } } } @@ -1657,6 +1697,72 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } mHandler.sendMessage(mHandler.obtainMessage( - NetworkStateTracker.EVENT_INET_CONDITION_CHANGE, networkType, percentage)); + EVENT_INET_CONDITION_CHANGE, networkType, percentage)); + } + + private void handleInetConditionChange(int netType, int condition) { + if (DBG) { + Slog.d(TAG, "Inet connectivity change, net=" + + netType + ", condition=" + condition + + ",mActiveDefaultNetwork=" + mActiveDefaultNetwork); + } + if (mActiveDefaultNetwork == -1) { + if (DBG) Slog.d(TAG, "no active default network - aborting"); + return; + } + if (mActiveDefaultNetwork != netType) { + if (DBG) Slog.d(TAG, "given net not default - aborting"); + return; + } + mDefaultInetCondition = condition; + int delay; + if (mInetConditionChangeInFlight == false) { + if (DBG) Slog.d(TAG, "starting a change hold"); + // setup a new hold to debounce this + if (mDefaultInetCondition > 50) { + delay = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.INET_CONDITION_DEBOUNCE_UP_DELAY, 500); + } else { + delay = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.INET_CONDITION_DEBOUNCE_DOWN_DELAY, 3000); + } + mInetConditionChangeInFlight = true; + mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_INET_CONDITION_HOLD_END, + mActiveDefaultNetwork, mDefaultConnectionSequence), delay); + } else { + // we've set the new condition, when this hold ends that will get + // picked up + if (DBG) Slog.d(TAG, "currently in hold - not setting new end evt"); + } + } + + private void handleInetConditionHoldEnd(int netType, int sequence) { + if (DBG) { + Slog.d(TAG, "Inet hold end, net=" + netType + + ", condition =" + mDefaultInetCondition + + ", published condition =" + mDefaultInetConditionPublished); + } + mInetConditionChangeInFlight = false; + + if (mActiveDefaultNetwork == -1) { + if (DBG) Slog.d(TAG, "no active default network - aborting"); + return; + } + if (mDefaultConnectionSequence != sequence) { + if (DBG) Slog.d(TAG, "event hold for obsolete network - aborting"); + return; + } + if (mDefaultInetConditionPublished == mDefaultInetCondition) { + if (DBG) Slog.d(TAG, "no change in condition - aborting"); + return; + } + NetworkInfo networkInfo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(); + if (networkInfo.isConnected() == false) { + if (DBG) Slog.d(TAG, "default network not connected - aborting"); + return; + } + mDefaultInetConditionPublished = mDefaultInetCondition; + sendInetConditionBroadcast(networkInfo); + return; } } diff --git a/services/java/com/android/server/ProcessStats.java b/services/java/com/android/server/ProcessStats.java index 0c8c2fd..020f9ed 100644 --- a/services/java/com/android/server/ProcessStats.java +++ b/services/java/com/android/server/ProcessStats.java @@ -80,16 +80,24 @@ public class ProcessStats { PROC_SPACE_TERM|PROC_OUT_LONG, // 11: major faults PROC_SPACE_TERM, PROC_SPACE_TERM|PROC_OUT_LONG, // 13: utime - PROC_SPACE_TERM|PROC_OUT_LONG // 14: stime + PROC_SPACE_TERM|PROC_OUT_LONG, // 14: stime + PROC_SPACE_TERM, + PROC_SPACE_TERM, + PROC_SPACE_TERM, + PROC_SPACE_TERM, + PROC_SPACE_TERM, + PROC_SPACE_TERM, + PROC_SPACE_TERM|PROC_OUT_LONG, // 21: vsize }; static final int PROCESS_FULL_STAT_MINOR_FAULTS = 1; static final int PROCESS_FULL_STAT_MAJOR_FAULTS = 2; static final int PROCESS_FULL_STAT_UTIME = 3; static final int PROCESS_FULL_STAT_STIME = 4; + static final int PROCESS_FULL_STAT_VSIZE = 5; - private final String[] mProcessFullStatsStringData = new String[5]; - private final long[] mProcessFullStatsData = new long[5]; + private final String[] mProcessFullStatsStringData = new String[6]; + private final long[] mProcessFullStatsData = new long[6]; private static final int[] SYSTEM_CPU_FORMAT = new int[] { PROC_SPACE_TERM|PROC_COMBINE, @@ -171,6 +179,8 @@ public class ProcessStats { final ArrayList<Stats> threadStats; final ArrayList<Stats> workingThreads; + public boolean interesting; + public String baseName; public String name; int nameWidth; @@ -349,59 +359,62 @@ public class ProcessStats { + (parentPid < 0 ? "process" : "thread") + " pid " + pid + ": " + st); - final long uptime = SystemClock.uptimeMillis(); + if (st.interesting) { + final long uptime = SystemClock.uptimeMillis(); - final long[] procStats = mProcessStatsData; - if (!Process.readProcFile(st.statFile.toString(), - PROCESS_STATS_FORMAT, null, procStats, null)) { - continue; - } - - final long minfaults = procStats[PROCESS_STAT_MINOR_FAULTS]; - final long majfaults = procStats[PROCESS_STAT_MAJOR_FAULTS]; - final long utime = procStats[PROCESS_STAT_UTIME]; - final long stime = procStats[PROCESS_STAT_STIME]; - - if (utime == st.base_utime && stime == st.base_stime) { - st.rel_utime = 0; - st.rel_stime = 0; - st.rel_minfaults = 0; - st.rel_majfaults = 0; - if (st.active) { - st.active = false; + final long[] procStats = mProcessStatsData; + if (!Process.readProcFile(st.statFile.toString(), + PROCESS_STATS_FORMAT, null, procStats, null)) { + continue; } - continue; - } - if (!st.active) { - st.active = true; - } + final long minfaults = procStats[PROCESS_STAT_MINOR_FAULTS]; + final long majfaults = procStats[PROCESS_STAT_MAJOR_FAULTS]; + final long utime = procStats[PROCESS_STAT_UTIME]; + final long stime = procStats[PROCESS_STAT_STIME]; + + if (utime == st.base_utime && stime == st.base_stime) { + st.rel_utime = 0; + st.rel_stime = 0; + st.rel_minfaults = 0; + st.rel_majfaults = 0; + if (st.active) { + st.active = false; + } + continue; + } - if (parentPid < 0) { - getName(st, st.cmdlineFile); - if (st.threadStats != null) { - mCurThreadPids = collectStats(st.threadsDir, pid, false, - mCurThreadPids, st.threadStats); + if (!st.active) { + st.active = true; } + + if (parentPid < 0) { + getName(st, st.cmdlineFile); + if (st.threadStats != null) { + mCurThreadPids = collectStats(st.threadsDir, pid, false, + mCurThreadPids, st.threadStats); + } + } + + if (DEBUG) Slog.v("Load", "Stats changed " + st.name + " pid=" + st.pid + + " utime=" + utime + "-" + st.base_utime + + " stime=" + stime + "-" + st.base_stime + + " minfaults=" + minfaults + "-" + st.base_minfaults + + " majfaults=" + majfaults + "-" + st.base_majfaults); + + st.rel_uptime = uptime - st.base_uptime; + st.base_uptime = uptime; + st.rel_utime = (int)(utime - st.base_utime); + st.rel_stime = (int)(stime - st.base_stime); + st.base_utime = utime; + st.base_stime = stime; + st.rel_minfaults = (int)(minfaults - st.base_minfaults); + st.rel_majfaults = (int)(majfaults - st.base_majfaults); + st.base_minfaults = minfaults; + st.base_majfaults = majfaults; + st.working = true; } - if (DEBUG) Slog.v("Load", "Stats changed " + st.name + " pid=" + st.pid - + " utime=" + utime + "-" + st.base_utime - + " stime=" + stime + "-" + st.base_stime - + " minfaults=" + minfaults + "-" + st.base_minfaults - + " majfaults=" + majfaults + "-" + st.base_majfaults); - - st.rel_uptime = uptime - st.base_uptime; - st.base_uptime = uptime; - st.rel_utime = (int)(utime - st.base_utime); - st.rel_stime = (int)(stime - st.base_stime); - st.base_utime = utime; - st.base_stime = stime; - st.rel_minfaults = (int)(minfaults - st.base_minfaults); - st.rel_majfaults = (int)(majfaults - st.base_majfaults); - st.base_minfaults = minfaults; - st.base_majfaults = majfaults; - st.working = true; continue; } @@ -421,12 +434,24 @@ public class ProcessStats { if (Process.readProcFile(st.statFile.toString(), PROCESS_FULL_STATS_FORMAT, procStatsString, procStats, null)) { - st.baseName = procStatsString[0]; - st.base_minfaults = procStats[PROCESS_FULL_STAT_MINOR_FAULTS]; - st.base_majfaults = procStats[PROCESS_FULL_STAT_MAJOR_FAULTS]; - st.base_utime = procStats[PROCESS_FULL_STAT_UTIME]; - st.base_stime = procStats[PROCESS_FULL_STAT_STIME]; + // This is a possible way to filter out processes that + // are actually kernel threads... do we want to? Some + // of them do use CPU, but there can be a *lot* that are + // not doing anything. + if (true || procStats[PROCESS_FULL_STAT_VSIZE] != 0) { + st.interesting = true; + st.baseName = procStatsString[0]; + st.base_minfaults = procStats[PROCESS_FULL_STAT_MINOR_FAULTS]; + st.base_majfaults = procStats[PROCESS_FULL_STAT_MAJOR_FAULTS]; + st.base_utime = procStats[PROCESS_FULL_STAT_UTIME]; + st.base_stime = procStats[PROCESS_FULL_STAT_STIME]; + } else { + Slog.i(TAG, "Skipping kernel process pid " + pid + + " name " + procStatsString[0]); + st.baseName = procStatsString[0]; + } } else { + Slog.w(TAG, "Skipping unknown process pid " + pid); st.baseName = "<unknown>"; st.base_utime = st.base_stime = 0; st.base_minfaults = st.base_majfaults = 0; @@ -438,7 +463,7 @@ public class ProcessStats { mCurThreadPids = collectStats(st.threadsDir, pid, true, mCurThreadPids, st.threadStats); } - } else { + } else if (st.interesting) { st.name = st.baseName; st.nameWidth = onMeasureProcessName(st.name); } @@ -452,7 +477,7 @@ public class ProcessStats { st.rel_minfaults = 0; st.rel_majfaults = 0; st.added = true; - if (!first) { + if (!first && st.interesting) { st.working = true; } continue; @@ -624,6 +649,14 @@ public class ProcessStats { } } + final public int countStats() { + return mProcStats.size(); + } + + final public Stats getStats(int index) { + return mProcStats.get(index); + } + final public int countWorkingStats() { buildWorkingProcs(); return mWorkingProcs.size(); @@ -788,7 +821,8 @@ public class ProcessStats { private void getName(Stats st, String cmdlineFile) { String newName = st.name; - if (st.name == null || st.name.equals("app_process")) { + if (st.name == null || st.name.equals("app_process") + || st.name.equals("<pre-initialized>")) { String cmdName = readFile(cmdlineFile, '\0'); if (cmdName != null && cmdName.length() > 1) { newName = cmdName; diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index d7a1ac2..c637274 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -5679,9 +5679,12 @@ public class WindowManagerService extends IWindowManager.Stub int requestedWidth, int requestedHeight, int viewFlags, boolean insetsPending, Rect outFrame, Rect outContentInsets, Rect outVisibleInsets, Configuration outConfig, Surface outSurface) { - return relayoutWindow(this, window, attrs, + //Log.d(TAG, ">>>>>> ENTERED relayout from " + Binder.getCallingPid()); + int res = relayoutWindow(this, window, attrs, requestedWidth, requestedHeight, viewFlags, insetsPending, outFrame, outContentInsets, outVisibleInsets, outConfig, outSurface); + //Log.d(TAG, "<<<<<< EXITING relayout to " + Binder.getCallingPid()); + return res; } public void setTransparentRegion(IWindow window, Region region) { diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 4f0d2d5..223d77d 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -121,6 +121,8 @@ import java.io.PrintWriter; import java.lang.IllegalStateException; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -144,6 +146,7 @@ public final class ActivityManagerService extends ActivityManagerNative static final boolean DEBUG_BROADCAST = localLOGV || false; static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false; static final boolean DEBUG_SERVICE = localLOGV || false; + static final boolean DEBUG_SERVICE_EXECUTING = localLOGV || false; static final boolean DEBUG_VISBILITY = localLOGV || false; static final boolean DEBUG_PROCESSES = localLOGV || false; static final boolean DEBUG_PROVIDER = localLOGV || false; @@ -152,6 +155,8 @@ public final class ActivityManagerService extends ActivityManagerNative static final boolean DEBUG_RESULTS = localLOGV || false; static final boolean DEBUG_BACKUP = localLOGV || false; static final boolean DEBUG_CONFIGURATION = localLOGV || false; + static final boolean DEBUG_POWER = localLOGV || false; + static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false; static final boolean VALIDATE_TOKENS = false; static final boolean SHOW_ACTIVITY_START_TIME = true; @@ -197,8 +202,16 @@ public final class ActivityManagerService extends ActivityManagerNative // The minimum amount of time between successive GC requests for a process. static final int GC_MIN_INTERVAL = 60*1000; - // The rate at which we check for apps using excessive wake locks -- 15 mins. - static final int WAKE_LOCK_CHECK_DELAY = 15*60*1000; + // The rate at which we check for apps using excessive power -- 15 mins. + static final int POWER_CHECK_DELAY = (DEBUG_POWER_QUICK ? 2 : 15) * 60*1000; + + // The minimum sample duration we will allow before deciding we have + // enough data on wake locks to start killing things. + static final int WAKE_LOCK_MIN_CHECK_DURATION = (DEBUG_POWER_QUICK ? 1 : 5) * 60*1000; + + // The minimum sample duration we will allow before deciding we have + // enough data on CPU usage to start killing things. + static final int CPU_MIN_CHECK_DURATION = (DEBUG_POWER_QUICK ? 1 : 5) * 60*1000; // How long we allow a receiver to run before giving up on it. static final int BROADCAST_TIMEOUT = 10*1000; @@ -552,6 +565,11 @@ public final class ActivityManagerService extends ActivityManagerNative private final StringBuilder mStrictModeBuffer = new StringBuilder(); /** + * True if we have a pending unexpired BROADCAST_TIMEOUT_MSG posted to our handler. + */ + private boolean mPendingBroadcastTimeoutMessage; + + /** * Intent broadcast that we have tried to start, but are * waiting for its application's process to be created. We only * need one (instead of a list) because we always process broadcasts @@ -779,9 +797,14 @@ public final class ActivityManagerService extends ActivityManagerNative boolean mDidAppSwitch; /** - * Last time (in realtime) at which we checked for wake lock usage. + * Last time (in realtime) at which we checked for power usage. + */ + long mLastPowerCheckRealtime; + + /** + * Last time (in uptime) at which we checked for power usage. */ - long mLastWakeLockCheckTime; + long mLastPowerCheckUptime; /** * Set while we are wanting to sleep, to prevent any @@ -1052,17 +1075,8 @@ public final class ActivityManagerService extends ActivityManagerNative processNextBroadcast(true); } break; case BROADCAST_TIMEOUT_MSG: { - if (mDidDexOpt) { - mDidDexOpt = false; - Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG); - mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT); - return; - } - // Only process broadcast timeouts if the system is ready. That way - // PRE_BOOT_COMPLETED broadcasts can't timeout as they are intended - // to do heavy lifting for system up - if (mProcessesReady) { - broadcastTimeout(); + synchronized (ActivityManagerService.this) { + broadcastTimeoutLocked(true); } } break; case SERVICE_TIMEOUT_MSG: { @@ -1194,12 +1208,10 @@ public final class ActivityManagerService extends ActivityManagerNative } break; case CHECK_EXCESSIVE_WAKE_LOCKS_MSG: { synchronized (ActivityManagerService.this) { - checkExcessiveWakeLocksLocked(true); + checkExcessivePowerUsageLocked(true); removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG); - if (mSleeping) { - Message nmsg = obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG); - sendMessageDelayed(nmsg, WAKE_LOCK_CHECK_DELAY); - } + Message nmsg = obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG); + sendMessageDelayed(nmsg, POWER_CHECK_DELAY); } } break; } @@ -1394,7 +1406,8 @@ public final class ActivityManagerService extends ActivityManagerNative systemDir, "batterystats.bin").toString()); mBatteryStatsService.getActiveStatistics().readLocked(); mBatteryStatsService.getActiveStatistics().writeAsyncLocked(); - mOnBattery = mBatteryStatsService.getActiveStatistics().getIsOnBattery(); + mOnBattery = DEBUG_POWER ? true + : mBatteryStatsService.getActiveStatistics().getIsOnBattery(); mBatteryStatsService.getActiveStatistics().setCallback(this); mUsageStatsService = new UsageStatsService(new File( @@ -1514,10 +1527,12 @@ public final class ActivityManagerService extends ActivityManagerNative int perc = bstats.startAddingCpuLocked(); int totalUTime = 0; int totalSTime = 0; - final int N = mProcessStats.countWorkingStats(); + final int N = mProcessStats.countStats(); for (int i=0; i<N; i++) { - ProcessStats.Stats st - = mProcessStats.getWorkingStats(i); + ProcessStats.Stats st = mProcessStats.getStats(i); + if (!st.working) { + continue; + } ProcessRecord pr = mPidsSelfLocked.get(st.pid); int otherUTime = (st.rel_utime*perc)/100; int otherSTime = (st.rel_stime*perc)/100; @@ -1528,6 +1543,7 @@ public final class ActivityManagerService extends ActivityManagerNative ps.addCpuTimeLocked(st.rel_utime-otherUTime, st.rel_stime-otherSTime); ps.addSpeedStepTimes(cpuSpeedTimes); + pr.curCpuTime += (st.rel_utime+st.rel_stime) * 10; } else { BatteryStatsImpl.Uid.Proc ps = bstats.getProcessStatsLocked(st.name, st.pid); @@ -1564,7 +1580,7 @@ public final class ActivityManagerService extends ActivityManagerNative updateCpuStatsNow(); synchronized (this) { synchronized(mPidsSelfLocked) { - mOnBattery = onBattery; + mOnBattery = DEBUG_POWER ? true : onBattery; } } } @@ -2785,11 +2801,36 @@ public final class ActivityManagerService extends ActivityManagerNative } } + private final class AppNotResponding implements Runnable { + private final ProcessRecord mApp; + private final String mAnnotation; + + public AppNotResponding(ProcessRecord app, String annotation) { + mApp = app; + mAnnotation = annotation; + } + + @Override + public void run() { + appNotResponding(mApp, null, null, mAnnotation); + } + } + final void appNotResponding(ProcessRecord app, ActivityRecord activity, ActivityRecord parent, final String annotation) { ArrayList<Integer> firstPids = new ArrayList<Integer>(5); SparseArray<Boolean> lastPids = new SparseArray<Boolean>(20); + if (mController != null) { + try { + // 0 == continue, -1 = kill process immediately + int res = mController.appEarlyNotResponding(app.processName, app.pid, annotation); + if (res < 0 && app.pid != MY_PID) Process.killProcess(app.pid); + } catch (RemoteException e) { + mController = null; + } + } + long anrTime = SystemClock.uptimeMillis(); if (MONITOR_CPU_USAGE) { updateCpuStatsNow(); @@ -2840,10 +2881,6 @@ public final class ActivityManagerService extends ActivityManagerNative } } - final ProcessStats processStats = new ProcessStats(true); - - File tracesFile = dumpStackTraces(true, firstPids, processStats, lastPids); - // Log the ANR to the main log. StringBuilder info = mStringBuilder; info.setLength(0); @@ -2859,6 +2896,10 @@ public final class ActivityManagerService extends ActivityManagerNative info.append("Parent: ").append(parent.shortComponentName).append("\n"); } + final ProcessStats processStats = new ProcessStats(true); + + File tracesFile = dumpStackTraces(true, firstPids, processStats, lastPids); + String cpuInfo = null; if (MONITOR_CPU_USAGE) { updateCpuStatsNow(); @@ -3643,7 +3684,7 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.w(TAG, "Exception in new application when starting receiver " + br.curComponent.flattenToShortString(), e); badApp = true; - logBroadcastReceiverDiscard(br); + logBroadcastReceiverDiscardLocked(br); finishReceiverLocked(br.receiver, br.resultCode, br.resultData, br.resultExtras, br.resultAbort, true); scheduleBroadcastsLocked(); @@ -3735,7 +3776,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { // Start looking for apps that are abusing wake locks. Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG); - mHandler.sendMessageDelayed(nmsg, WAKE_LOCK_CHECK_DELAY); + mHandler.sendMessageDelayed(nmsg, POWER_CHECK_DELAY); // Tell anyone interested that we are done booting! SystemProperties.set("sys.boot_completed", "1"); broadcastIntentLocked(null, null, @@ -5648,10 +5689,10 @@ public final class ActivityManagerService extends ActivityManagerNative } // Initialize the wake times of all processes. - checkExcessiveWakeLocksLocked(false); + checkExcessivePowerUsageLocked(false); mHandler.removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG); Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG); - mHandler.sendMessageDelayed(nmsg, WAKE_LOCK_CHECK_DELAY); + mHandler.sendMessageDelayed(nmsg, POWER_CHECK_DELAY); } } @@ -5701,7 +5742,6 @@ public final class ActivityManagerService extends ActivityManagerNative mWindowManager.setEventDispatching(true); mSleeping = false; mMainStack.resumeTopActivityLocked(null); - mHandler.removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG); } } @@ -6320,7 +6360,7 @@ public final class ActivityManagerService extends ActivityManagerNative // The current broadcast is waiting for this app's receiver // to be finished. Looks like that's not going to happen, so // let the broadcast continue. - logBroadcastReceiverDiscard(r); + logBroadcastReceiverDiscardLocked(r); finishReceiverLocked(r.receiver, r.resultCode, r.resultData, r.resultExtras, r.resultAbort, true); reschedule = true; @@ -6329,7 +6369,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (r != null && r.curApp == app) { if (DEBUG_BROADCAST) Slog.v(TAG, "skip & discard pending app " + r); - logBroadcastReceiverDiscard(r); + logBroadcastReceiverDiscardLocked(r); finishReceiverLocked(r.receiver, r.resultCode, r.resultData, r.resultExtras, r.resultAbort, true); reschedule = true; @@ -6998,12 +7038,13 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println("Activity manager dump options:"); pw.println(" [-a] [-h] [cmd] ..."); pw.println(" cmd may be one of:"); - pw.println(" activities: activity stack state"); - pw.println(" broadcasts: broadcast state"); - pw.println(" intents: pending intent state"); - pw.println(" processes: process state"); - pw.println(" providers: content provider state"); - pw.println(" services: service state"); + pw.println(" a[ctivities]: activity stack state"); + pw.println(" b[roadcasts]: broadcast state"); + pw.println(" i[ntents]: pending intent state"); + pw.println(" p[rocesses]: process state"); + pw.println(" o[om]: out of memory management"); + pw.println(" prov[iders]: content provider state"); + pw.println(" s[ervices]: service state"); pw.println(" service [name]: service client-side state"); return; } else { @@ -7035,6 +7076,11 @@ public final class ActivityManagerService extends ActivityManagerNative dumpProcessesLocked(fd, pw, args, opti, true); } return; + } else if ("oom".equals(cmd) || "o".equals(cmd)) { + synchronized (this) { + dumpOomLocked(fd, pw, args, opti, true); + } + return; } else if ("providers".equals(cmd) || "prov".equals(cmd)) { synchronized (this) { dumpProvidersLocked(fd, pw, args, opti, true); @@ -7150,7 +7196,7 @@ public final class ActivityManagerService extends ActivityManagerNative return true; } - + boolean dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args, int opti, boolean dumpAll) { boolean needSep = false; @@ -7180,8 +7226,8 @@ public final class ActivityManagerService extends ActivityManagerNative if (needSep) pw.println(" "); needSep = true; pw.println(" Running processes (most recent first):"); - dumpProcessList(pw, this, mLruProcesses, " ", - "Proc", "PERS", true); + dumpProcessOomList(pw, this, mLruProcesses, " ", + "Proc", "PERS", false); needSep = true; } @@ -7212,7 +7258,7 @@ public final class ActivityManagerService extends ActivityManagerNative needSep = true; pw.println(" Persisent processes that are starting:"); dumpProcessList(pw, this, mPersistentStartingProcesses, " ", - "Starting Norm", "Restarting PERS", false); + "Starting Norm", "Restarting PERS"); } if (mStartingProcesses.size() > 0) { @@ -7220,7 +7266,7 @@ public final class ActivityManagerService extends ActivityManagerNative needSep = true; pw.println(" Processes that are starting:"); dumpProcessList(pw, this, mStartingProcesses, " ", - "Starting Norm", "Starting PERS", false); + "Starting Norm", "Starting PERS"); } if (mRemovedProcesses.size() > 0) { @@ -7228,7 +7274,7 @@ public final class ActivityManagerService extends ActivityManagerNative needSep = true; pw.println(" Processes that are being removed:"); dumpProcessList(pw, this, mRemovedProcesses, " ", - "Removed Norm", "Removed PERS", false); + "Removed Norm", "Removed PERS"); } if (mProcessesOnHold.size() > 0) { @@ -7236,26 +7282,10 @@ public final class ActivityManagerService extends ActivityManagerNative needSep = true; pw.println(" Processes that are on old until the system is ready:"); dumpProcessList(pw, this, mProcessesOnHold, " ", - "OnHold Norm", "OnHold PERS", false); + "OnHold Norm", "OnHold PERS"); } - if (mProcessesToGc.size() > 0) { - if (needSep) pw.println(" "); - needSep = true; - pw.println(" Processes that are waiting to GC:"); - long now = SystemClock.uptimeMillis(); - for (int i=0; i<mProcessesToGc.size(); i++) { - ProcessRecord proc = mProcessesToGc.get(i); - pw.print(" Process "); pw.println(proc); - pw.print(" lowMem="); pw.print(proc.reportLowMemory); - pw.print(", last gced="); - pw.print(now-proc.lastRequestedGc); - pw.print(" ms ago, last lowMem="); - pw.print(now-proc.lastLowMemory); - pw.println(" ms ago"); - - } - } + needSep = dumpProcessesToGc(fd, pw, args, opti, needSep, dumpAll); if (mProcessCrashTimes.getMap().size() > 0) { if (needSep) pw.println(" "); @@ -7319,6 +7349,12 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println(" mBooting=" + mBooting + " mBooted=" + mBooted + " mFactoryTest=" + mFactoryTest); + pw.print(" mLastPowerCheckRealtime="); + TimeUtils.formatDuration(mLastPowerCheckRealtime, pw); + pw.println(""); + pw.print(" mLastPowerCheckUptime="); + TimeUtils.formatDuration(mLastPowerCheckUptime, pw); + pw.println(""); pw.println(" mGoingToSleep=" + mMainStack.mGoingToSleep); pw.println(" mLaunchingActivity=" + mMainStack.mLaunchingActivity); pw.println(" mAdjSeq=" + mAdjSeq + " mLruSeq=" + mLruSeq); @@ -7327,6 +7363,75 @@ public final class ActivityManagerService extends ActivityManagerNative return true; } + boolean dumpProcessesToGc(FileDescriptor fd, PrintWriter pw, String[] args, + int opti, boolean needSep, boolean dumpAll) { + if (mProcessesToGc.size() > 0) { + if (needSep) pw.println(" "); + needSep = true; + pw.println(" Processes that are waiting to GC:"); + long now = SystemClock.uptimeMillis(); + for (int i=0; i<mProcessesToGc.size(); i++) { + ProcessRecord proc = mProcessesToGc.get(i); + pw.print(" Process "); pw.println(proc); + pw.print(" lowMem="); pw.print(proc.reportLowMemory); + pw.print(", last gced="); + pw.print(now-proc.lastRequestedGc); + pw.print(" ms ago, last lowMem="); + pw.print(now-proc.lastLowMemory); + pw.println(" ms ago"); + + } + } + return needSep; + } + + boolean dumpOomLocked(FileDescriptor fd, PrintWriter pw, String[] args, + int opti, boolean dumpAll) { + boolean needSep = false; + + if (mLruProcesses.size() > 0) { + ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>(mLruProcesses); + + Comparator<ProcessRecord> comparator = new Comparator<ProcessRecord>() { + @Override + public int compare(ProcessRecord object1, ProcessRecord object2) { + if (object1.setAdj != object2.setAdj) { + return object1.setAdj > object2.setAdj ? -1 : 1; + } + if (object1.setSchedGroup != object2.setSchedGroup) { + return object1.setSchedGroup > object2.setSchedGroup ? -1 : 1; + } + if (object1.keeping != object2.keeping) { + return object1.keeping ? -1 : 1; + } + if (object1.pid != object2.pid) { + return object1.pid > object2.pid ? -1 : 1; + } + return 0; + } + }; + + Collections.sort(procs, comparator); + + if (needSep) pw.println(" "); + needSep = true; + pw.println(" Process OOM control:"); + dumpProcessOomList(pw, this, procs, " ", + "Proc", "PERS", true); + needSep = true; + } + + needSep = dumpProcessesToGc(fd, pw, args, opti, needSep, dumpAll); + + pw.println(" "); + pw.println(" mHomeProcess: " + mHomeProcess); + if (mHeavyWeightProcess != null) { + pw.println(" mHeavyWeightProcess: " + mHeavyWeightProcess); + } + + return true; + } + /** * There are three ways to call this: * - no service specified: dump all the services @@ -7694,89 +7799,145 @@ public final class ActivityManagerService extends ActivityManagerNative private static final int dumpProcessList(PrintWriter pw, ActivityManagerService service, List list, - String prefix, String normalLabel, String persistentLabel, - boolean inclOomAdj) { + String prefix, String normalLabel, String persistentLabel) { int numPers = 0; final int N = list.size()-1; for (int i=N; i>=0; i--) { ProcessRecord r = (ProcessRecord)list.get(i); - if (false) { - pw.println(prefix + (r.persistent ? persistentLabel : normalLabel) - + " #" + i + ":"); - r.dump(pw, prefix + " "); - } else if (inclOomAdj) { - String oomAdj; - if (r.setAdj >= EMPTY_APP_ADJ) { - oomAdj = buildOomTag("empty", null, r.setAdj, EMPTY_APP_ADJ); - } else if (r.setAdj >= HIDDEN_APP_MIN_ADJ) { - oomAdj = buildOomTag("bak", " ", r.setAdj, HIDDEN_APP_MIN_ADJ); - } else if (r.setAdj >= HOME_APP_ADJ) { - oomAdj = buildOomTag("home ", null, r.setAdj, HOME_APP_ADJ); - } else if (r.setAdj >= SECONDARY_SERVER_ADJ) { - oomAdj = buildOomTag("svc", " ", r.setAdj, SECONDARY_SERVER_ADJ); - } else if (r.setAdj >= BACKUP_APP_ADJ) { - oomAdj = buildOomTag("bckup", null, r.setAdj, BACKUP_APP_ADJ); - } else if (r.setAdj >= HEAVY_WEIGHT_APP_ADJ) { - oomAdj = buildOomTag("hvy ", null, r.setAdj, HEAVY_WEIGHT_APP_ADJ); - } else if (r.setAdj >= PERCEPTIBLE_APP_ADJ) { - oomAdj = buildOomTag("prcp ", null, r.setAdj, PERCEPTIBLE_APP_ADJ); - } else if (r.setAdj >= VISIBLE_APP_ADJ) { - oomAdj = buildOomTag("vis ", null, r.setAdj, VISIBLE_APP_ADJ); - } else if (r.setAdj >= FOREGROUND_APP_ADJ) { - oomAdj = buildOomTag("fore ", null, r.setAdj, FOREGROUND_APP_ADJ); - } else if (r.setAdj >= CORE_SERVER_ADJ) { - oomAdj = buildOomTag("core ", null, r.setAdj, CORE_SERVER_ADJ); - } else if (r.setAdj >= SYSTEM_ADJ) { - oomAdj = buildOomTag("sys ", null, r.setAdj, SYSTEM_ADJ); + pw.println(String.format("%s%s #%2d: %s", + prefix, (r.persistent ? persistentLabel : normalLabel), + i, r.toString())); + if (r.persistent) { + numPers++; + } + } + return numPers; + } + + private static final void dumpProcessOomList(PrintWriter pw, + ActivityManagerService service, List<ProcessRecord> list, + String prefix, String normalLabel, String persistentLabel, + boolean inclDetails) { + + final long curRealtime = SystemClock.elapsedRealtime(); + final long realtimeSince = curRealtime - service.mLastPowerCheckRealtime; + final long curUptime = SystemClock.uptimeMillis(); + final long uptimeSince = curUptime - service.mLastPowerCheckUptime; + + final int N = list.size()-1; + for (int i=N; i>=0; i--) { + ProcessRecord r = list.get(i); + String oomAdj; + if (r.setAdj >= EMPTY_APP_ADJ) { + oomAdj = buildOomTag("empty", null, r.setAdj, EMPTY_APP_ADJ); + } else if (r.setAdj >= HIDDEN_APP_MIN_ADJ) { + oomAdj = buildOomTag("bak", " ", r.setAdj, HIDDEN_APP_MIN_ADJ); + } else if (r.setAdj >= HOME_APP_ADJ) { + oomAdj = buildOomTag("home ", null, r.setAdj, HOME_APP_ADJ); + } else if (r.setAdj >= SECONDARY_SERVER_ADJ) { + oomAdj = buildOomTag("svc", " ", r.setAdj, SECONDARY_SERVER_ADJ); + } else if (r.setAdj >= BACKUP_APP_ADJ) { + oomAdj = buildOomTag("bckup", null, r.setAdj, BACKUP_APP_ADJ); + } else if (r.setAdj >= HEAVY_WEIGHT_APP_ADJ) { + oomAdj = buildOomTag("hvy ", null, r.setAdj, HEAVY_WEIGHT_APP_ADJ); + } else if (r.setAdj >= PERCEPTIBLE_APP_ADJ) { + oomAdj = buildOomTag("prcp ", null, r.setAdj, PERCEPTIBLE_APP_ADJ); + } else if (r.setAdj >= VISIBLE_APP_ADJ) { + oomAdj = buildOomTag("vis ", null, r.setAdj, VISIBLE_APP_ADJ); + } else if (r.setAdj >= FOREGROUND_APP_ADJ) { + oomAdj = buildOomTag("fore ", null, r.setAdj, FOREGROUND_APP_ADJ); + } else if (r.setAdj >= CORE_SERVER_ADJ) { + oomAdj = buildOomTag("core ", null, r.setAdj, CORE_SERVER_ADJ); + } else if (r.setAdj >= SYSTEM_ADJ) { + oomAdj = buildOomTag("sys ", null, r.setAdj, SYSTEM_ADJ); + } else { + oomAdj = Integer.toString(r.setAdj); + } + String schedGroup; + switch (r.setSchedGroup) { + case Process.THREAD_GROUP_BG_NONINTERACTIVE: + schedGroup = "B"; + break; + case Process.THREAD_GROUP_DEFAULT: + schedGroup = "F"; + break; + default: + schedGroup = Integer.toString(r.setSchedGroup); + break; + } + pw.println(String.format("%s%s #%2d: adj=%s/%s %s (%s)", + prefix, (r.persistent ? persistentLabel : normalLabel), + N-i, oomAdj, schedGroup, r.toShortString(), r.adjType)); + if (r.adjSource != null || r.adjTarget != null) { + pw.print(prefix); + pw.print(" "); + if (r.adjTarget instanceof ComponentName) { + pw.print(((ComponentName)r.adjTarget).flattenToShortString()); + } else if (r.adjTarget != null) { + pw.print(r.adjTarget.toString()); } else { - oomAdj = Integer.toString(r.setAdj); - } - String schedGroup; - switch (r.setSchedGroup) { - case Process.THREAD_GROUP_BG_NONINTERACTIVE: - schedGroup = "B"; - break; - case Process.THREAD_GROUP_DEFAULT: - schedGroup = "F"; - break; - default: - schedGroup = Integer.toString(r.setSchedGroup); - break; + pw.print("{null}"); + } + pw.print("<="); + if (r.adjSource instanceof ProcessRecord) { + pw.print("Proc{"); + pw.print(((ProcessRecord)r.adjSource).toShortString()); + pw.println("}"); + } else if (r.adjSource != null) { + pw.println(r.adjSource.toString()); + } else { + pw.println("{null}"); } - pw.println(String.format("%s%s #%2d: adj=%s/%s %s (%s)", - prefix, (r.persistent ? persistentLabel : normalLabel), - N-i, oomAdj, schedGroup, r.toShortString(), r.adjType)); - if (r.adjSource != null || r.adjTarget != null) { - pw.print(prefix); - pw.print(" "); - if (r.adjTarget instanceof ComponentName) { - pw.print(((ComponentName)r.adjTarget).flattenToShortString()); - } else if (r.adjTarget != null) { - pw.print(r.adjTarget.toString()); - } else { - pw.print("{null}"); - } - pw.print("<="); - if (r.adjSource instanceof ProcessRecord) { - pw.print("Proc{"); - pw.print(((ProcessRecord)r.adjSource).toShortString()); - pw.println("}"); - } else if (r.adjSource != null) { - pw.println(r.adjSource.toString()); - } else { - pw.println("{null}"); + } + if (inclDetails) { + pw.print(prefix); + pw.print(" "); + pw.print("oom: max="); pw.print(r.maxAdj); + pw.print(" hidden="); pw.print(r.hiddenAdj); + pw.print(" curRaw="); pw.print(r.curRawAdj); + pw.print(" setRaw="); pw.print(r.setRawAdj); + pw.print(" cur="); pw.print(r.curAdj); + pw.print(" set="); pw.println(r.setAdj); + pw.print(prefix); + pw.print(" "); + pw.print("keeping="); pw.print(r.keeping); + pw.print(" hidden="); pw.print(r.hidden); + pw.print(" empty="); pw.println(r.empty); + + if (!r.keeping) { + if (r.lastWakeTime != 0) { + long wtime; + BatteryStatsImpl stats = service.mBatteryStatsService.getActiveStatistics(); + synchronized (stats) { + wtime = stats.getProcessWakeTime(r.info.uid, + r.pid, curRealtime); + } + long timeUsed = wtime - r.lastWakeTime; + pw.print(prefix); + pw.print(" "); + pw.print("keep awake over "); + TimeUtils.formatDuration(realtimeSince, pw); + pw.print(" used "); + TimeUtils.formatDuration(timeUsed, pw); + pw.print(" ("); + pw.print((timeUsed*100)/realtimeSince); + pw.println("%)"); + } + if (r.lastCpuTime != 0) { + long timeUsed = r.curCpuTime - r.lastCpuTime; + pw.print(prefix); + pw.print(" "); + pw.print("run cpu over "); + TimeUtils.formatDuration(uptimeSince, pw); + pw.print(" used "); + TimeUtils.formatDuration(timeUsed, pw); + pw.print(" ("); + pw.print((timeUsed*100)/uptimeSince); + pw.println("%)"); } } - } else { - pw.println(String.format("%s%s #%2d: %s", - prefix, (r.persistent ? persistentLabel : normalLabel), - i, r.toString())); - } - if (r.persistent) { - numPers++; } } - return numPers; } static final void dumpApplicationMemoryUsage(FileDescriptor fd, @@ -8405,7 +8566,11 @@ public final class ActivityManagerService extends ActivityManagerNative return null; } - private final void bumpServiceExecutingLocked(ServiceRecord r) { + private final void bumpServiceExecutingLocked(ServiceRecord r, String why) { + if (DEBUG_SERVICE) Log.v(TAG, ">>> EXECUTING " + + why + " of " + r + " in app " + r.app); + else if (DEBUG_SERVICE_EXECUTING) Log.v(TAG, ">>> EXECUTING " + + why + " of " + r.shortName); long now = SystemClock.uptimeMillis(); if (r.executeNesting == 0 && r.app != null) { if (r.app.executingServices.size() == 0) { @@ -8443,8 +8608,7 @@ public final class ActivityManagerService extends ActivityManagerNative grantUriPermissionUncheckedFromIntentLocked(si.targetPermissionUid, r.packageName, si.intent, si.getUriPermissionsLocked()); } - if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING start of " + r); - bumpServiceExecutingLocked(r); + bumpServiceExecutingLocked(r, "start"); if (!oomAdjusted) { oomAdjusted = true; updateOomAdjLocked(r.app); @@ -8477,9 +8641,7 @@ public final class ActivityManagerService extends ActivityManagerNative } if ((!i.requested || rebind) && i.apps.size() > 0) { try { - if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING bind of " + r - + " in " + i + ": shouldUnbind=" + i.hasBound); - bumpServiceExecutingLocked(r); + bumpServiceExecutingLocked(r, "bind"); r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind); if (!rebind) { i.requested = true; @@ -8514,8 +8676,7 @@ public final class ActivityManagerService extends ActivityManagerNative r.restartTime = r.lastActivity = SystemClock.uptimeMillis(); app.services.add(r); - if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING create of " + r + " " + r.intent); - bumpServiceExecutingLocked(r); + bumpServiceExecutingLocked(r, "create"); updateLruProcessLocked(app, true, true); boolean created = false; @@ -8767,9 +8928,7 @@ public final class ActivityManagerService extends ActivityManagerNative + ": hasBound=" + ibr.hasBound); if (r.app != null && r.app.thread != null && ibr.hasBound) { try { - if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING bring down unbind of " + r - + " for " + ibr); - bumpServiceExecutingLocked(r); + bumpServiceExecutingLocked(r, "bring down unbind"); updateOomAdjLocked(r.app); ibr.hasBound = false; r.app.thread.scheduleUnbindService(r, @@ -8820,12 +8979,7 @@ public final class ActivityManagerService extends ActivityManagerNative r.app.services.remove(r); if (r.app.thread != null) { try { - if (DEBUG_SERVICE) { - RuntimeException here = new RuntimeException(); - here.fillInStackTrace(); - Slog.v(TAG, ">>> EXECUTING stop of " + r, here); - } - bumpServiceExecutingLocked(r); + bumpServiceExecutingLocked(r, "stop"); mStoppingServices.add(r); updateOomAdjLocked(r.app); r.app.thread.scheduleStopService(r); @@ -9281,9 +9435,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0 && b.intent.hasBound) { try { - if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING unbind of " + s - + " from " + b); - bumpServiceExecutingLocked(s); + bumpServiceExecutingLocked(s, "unbind"); updateOomAdjLocked(s.app); b.intent.hasBound = false; // Assume the client doesn't want to know about a rebind; @@ -9504,14 +9656,20 @@ public final class ActivityManagerService extends ActivityManagerNative if (DEBUG_SERVICE) Slog.v(TAG, "<<< DONE EXECUTING " + r + ": nesting=" + r.executeNesting + ", inStopping=" + inStopping + ", app=" + r.app); + else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG, "<<< DONE EXECUTING " + r.shortName); r.executeNesting--; if (r.executeNesting <= 0 && r.app != null) { + if (DEBUG_SERVICE) Slog.v(TAG, + "Nesting at 0 of " + r.shortName); r.app.executingServices.remove(r); if (r.app.executingServices.size() == 0) { + if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG, + "No more executingServices of " + r.shortName); mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app); } if (inStopping) { - if (DEBUG_SERVICE) Slog.v(TAG, "doneExecuting remove stopping " + r); + if (DEBUG_SERVICE) Slog.v(TAG, + "doneExecuting remove stopping " + r); mStoppingServices.remove(r); } updateOomAdjLocked(r.app); @@ -9621,20 +9779,20 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!"); return; } + } - long oldIdent = Binder.clearCallingIdentity(); - try { - IBackupManager bm = IBackupManager.Stub.asInterface( - ServiceManager.getService(Context.BACKUP_SERVICE)); - bm.agentConnected(agentPackageName, agent); - } catch (RemoteException e) { - // can't happen; the backup manager service is local - } catch (Exception e) { - Slog.w(TAG, "Exception trying to deliver BackupAgent binding: "); - e.printStackTrace(); - } finally { - Binder.restoreCallingIdentity(oldIdent); - } + long oldIdent = Binder.clearCallingIdentity(); + try { + IBackupManager bm = IBackupManager.Stub.asInterface( + ServiceManager.getService(Context.BACKUP_SERVICE)); + bm.agentConnected(agentPackageName, agent); + } catch (RemoteException e) { + // can't happen; the backup manager service is local + } catch (Exception e) { + Slog.w(TAG, "Exception trying to deliver BackupAgent binding: "); + e.printStackTrace(); + } finally { + Binder.restoreCallingIdentity(oldIdent); } } @@ -10347,7 +10505,7 @@ public final class ActivityManagerService extends ActivityManagerNative Binder.restoreCallingIdentity(origId); } - private final void logBroadcastReceiverDiscard(BroadcastRecord r) { + private final void logBroadcastReceiverDiscardLocked(BroadcastRecord r) { if (r.nextReceiver > 0) { Object curReceiver = r.receivers.get(r.nextReceiver-1); if (curReceiver instanceof BroadcastFilter) { @@ -10375,67 +10533,108 @@ public final class ActivityManagerService extends ActivityManagerNative } } - private final void broadcastTimeout() { - ProcessRecord app = null; - String anrMessage = null; + private final void setBroadcastTimeoutLocked(long timeoutTime) { + if (! mPendingBroadcastTimeoutMessage) { + Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG); + mHandler.sendMessageAtTime(msg, timeoutTime); + mPendingBroadcastTimeoutMessage = true; + } + } - synchronized (this) { - if (mOrderedBroadcasts.size() == 0) { + private final void cancelBroadcastTimeoutLocked() { + if (mPendingBroadcastTimeoutMessage) { + mHandler.removeMessages(BROADCAST_TIMEOUT_MSG); + mPendingBroadcastTimeoutMessage = false; + } + } + + private final void broadcastTimeoutLocked(boolean fromMsg) { + if (fromMsg) { + mPendingBroadcastTimeoutMessage = false; + } + + if (mOrderedBroadcasts.size() == 0) { + return; + } + + long now = SystemClock.uptimeMillis(); + BroadcastRecord r = mOrderedBroadcasts.get(0); + if (fromMsg) { + if (mDidDexOpt) { + // Delay timeouts until dexopt finishes. + mDidDexOpt = false; + long timeoutTime = SystemClock.uptimeMillis() + BROADCAST_TIMEOUT; + setBroadcastTimeoutLocked(timeoutTime); return; } - long now = SystemClock.uptimeMillis(); - BroadcastRecord r = mOrderedBroadcasts.get(0); - if ((r.receiverTime+BROADCAST_TIMEOUT) > now) { + if (! mProcessesReady) { + // Only process broadcast timeouts if the system is ready. That way + // PRE_BOOT_COMPLETED broadcasts can't timeout as they are intended + // to do heavy lifting for system up. + return; + } + + long timeoutTime = r.receiverTime + BROADCAST_TIMEOUT; + if (timeoutTime > now) { + // We can observe premature timeouts because we do not cancel and reset the + // broadcast timeout message after each receiver finishes. Instead, we set up + // an initial timeout then kick it down the road a little further as needed + // when it expires. if (DEBUG_BROADCAST) Slog.v(TAG, "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for " - + (r.receiverTime + BROADCAST_TIMEOUT)); - Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG); - mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT); + + timeoutTime); + setBroadcastTimeoutLocked(timeoutTime); return; } + } - Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver); - r.receiverTime = now; - r.anrCount++; + Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver + + ", started " + (now - r.receiverTime) + "ms ago"); + r.receiverTime = now; + r.anrCount++; - // Current receiver has passed its expiration date. - if (r.nextReceiver <= 0) { - Slog.w(TAG, "Timeout on receiver with nextReceiver <= 0"); - return; - } + // Current receiver has passed its expiration date. + if (r.nextReceiver <= 0) { + Slog.w(TAG, "Timeout on receiver with nextReceiver <= 0"); + return; + } - Object curReceiver = r.receivers.get(r.nextReceiver-1); - Slog.w(TAG, "Receiver during timeout: " + curReceiver); - logBroadcastReceiverDiscard(r); - if (curReceiver instanceof BroadcastFilter) { - BroadcastFilter bf = (BroadcastFilter)curReceiver; - if (bf.receiverList.pid != 0 - && bf.receiverList.pid != MY_PID) { - synchronized (this.mPidsSelfLocked) { - app = this.mPidsSelfLocked.get( - bf.receiverList.pid); - } - } - } else { - app = r.curApp; - } - - if (app != null) { - anrMessage = "Broadcast of " + r.intent.toString(); - } + ProcessRecord app = null; + String anrMessage = null; - if (mPendingBroadcast == r) { - mPendingBroadcast = null; + Object curReceiver = r.receivers.get(r.nextReceiver-1); + Slog.w(TAG, "Receiver during timeout: " + curReceiver); + logBroadcastReceiverDiscardLocked(r); + if (curReceiver instanceof BroadcastFilter) { + BroadcastFilter bf = (BroadcastFilter)curReceiver; + if (bf.receiverList.pid != 0 + && bf.receiverList.pid != MY_PID) { + synchronized (this.mPidsSelfLocked) { + app = this.mPidsSelfLocked.get( + bf.receiverList.pid); + } } - - // Move on to the next receiver. - finishReceiverLocked(r.receiver, r.resultCode, r.resultData, - r.resultExtras, r.resultAbort, true); - scheduleBroadcastsLocked(); + } else { + app = r.curApp; } + if (app != null) { + anrMessage = "Broadcast of " + r.intent.toString(); + } + + if (mPendingBroadcast == r) { + mPendingBroadcast = null; + } + + // Move on to the next receiver. + finishReceiverLocked(r.receiver, r.resultCode, r.resultData, + r.resultExtras, r.resultAbort, true); + scheduleBroadcastsLocked(); + if (anrMessage != null) { - appNotResponding(app, null, null, anrMessage); + // Post the ANR to the handler since we do not want to process ANRs while + // potentially holding our lock. + mHandler.post(new AppNotResponding(app, anrMessage)); } } @@ -10477,9 +10676,10 @@ public final class ActivityManagerService extends ActivityManagerNative } - static void performReceive(ProcessRecord app, IIntentReceiver receiver, + static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver, Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky) throws RemoteException { + // Send the intent to the receiver asynchronously using one-way binder calls. if (app != null && app.thread != null) { // If we have an app thread, do the call through that so it is // correctly ordered with other one-way calls. @@ -10490,7 +10690,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } - private final void deliverToRegisteredReceiver(BroadcastRecord r, + private final void deliverToRegisteredReceiverLocked(BroadcastRecord r, BroadcastFilter filter, boolean ordered) { boolean skip = false; if (filter.requiredPermission != null) { @@ -10548,7 +10748,7 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.i(TAG, "Delivering to " + filter + " (seq=" + seq + "): " + r); } - performReceive(filter.receiverList.app, filter.receiverList.receiver, + performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver, new Intent(r.intent), r.resultCode, r.resultData, r.resultExtras, r.ordered, r.initialSticky); if (ordered) { @@ -10605,7 +10805,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (DEBUG_BROADCAST) Slog.v(TAG, "Delivering non-ordered to registered " + target + ": " + r); - deliverToRegisteredReceiver(r, (BroadcastFilter)target, false); + deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false); } addBroadcastToHistoryLocked(r); if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Done with parallel broadcast " @@ -10661,7 +10861,7 @@ public final class ActivityManagerService extends ActivityManagerNative // and continue to make progress. // // This is only done if the system is ready so that PRE_BOOT_COMPLETED - // receivers don't get executed with with timeouts. They're intended for + // receivers don't get executed with timeouts. They're intended for // one time heavy lifting after system upgrades and can take // significant amounts of time. int numReceivers = (r.receivers != null) ? r.receivers.size() : 0; @@ -10677,7 +10877,7 @@ public final class ActivityManagerService extends ActivityManagerNative + " numReceivers=" + numReceivers + " nextReceiver=" + r.nextReceiver + " state=" + r.state); - broadcastTimeout(); // forcibly finish this broadcast + broadcastTimeoutLocked(false); // forcibly finish this broadcast forceReceive = true; r.state = BroadcastRecord.IDLE; } @@ -10701,7 +10901,7 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.i(TAG, "Finishing broadcast " + r.intent.getAction() + " seq=" + seq + " app=" + r.callerApp); } - performReceive(r.callerApp, r.resultTo, + performReceiveLocked(r.callerApp, r.resultTo, new Intent(r.intent), r.resultCode, r.resultData, r.resultExtras, false, false); } catch (RemoteException e) { @@ -10710,7 +10910,7 @@ public final class ActivityManagerService extends ActivityManagerNative } if (DEBUG_BROADCAST) Slog.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG"); - mHandler.removeMessages(BROADCAST_TIMEOUT_MSG); + cancelBroadcastTimeoutLocked(); if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Finished with ordered broadcast " + r); @@ -10735,11 +10935,12 @@ public final class ActivityManagerService extends ActivityManagerNative if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing ordered broadcast " + r); + } + if (! mPendingBroadcastTimeoutMessage) { + long timeoutTime = r.receiverTime + BROADCAST_TIMEOUT; if (DEBUG_BROADCAST) Slog.v(TAG, - "Submitting BROADCAST_TIMEOUT_MSG for " + r + " at " - + (r.receiverTime + BROADCAST_TIMEOUT)); - Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG); - mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT); + "Submitting BROADCAST_TIMEOUT_MSG for " + r + " at " + timeoutTime); + setBroadcastTimeoutLocked(timeoutTime); } Object nextReceiver = r.receivers.get(recIdx); @@ -10750,7 +10951,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (DEBUG_BROADCAST) Slog.v(TAG, "Delivering ordered to registered " + filter + ": " + r); - deliverToRegisteredReceiver(r, filter, r.ordered); + deliverToRegisteredReceiverLocked(r, filter, r.ordered); if (r.receiver == null || !r.ordered) { // The receiver has already finished, so schedule to // process the next one. @@ -10858,7 +11059,7 @@ public final class ActivityManagerService extends ActivityManagerNative + info.activityInfo.applicationInfo.packageName + "/" + info.activityInfo.applicationInfo.uid + " for broadcast " + r.intent + ": process is bad"); - logBroadcastReceiverDiscard(r); + logBroadcastReceiverDiscardLocked(r); finishReceiverLocked(r.receiver, r.resultCode, r.resultData, r.resultExtras, r.resultAbort, true); scheduleBroadcastsLocked(); @@ -11187,6 +11388,7 @@ public final class ActivityManagerService extends ActivityManagerNative app.adjType = "fixed"; app.adjSeq = mAdjSeq; app.curRawAdj = app.maxAdj; + app.keeping = true; app.curSchedGroup = Process.THREAD_GROUP_DEFAULT; return (app.curAdj=app.maxAdj); } @@ -11194,6 +11396,7 @@ public final class ActivityManagerService extends ActivityManagerNative app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN; app.adjSource = null; app.adjTarget = null; + app.keeping = false; app.empty = false; app.hidden = false; @@ -11323,6 +11526,9 @@ public final class ActivityManagerService extends ActivityManagerNative if (adj > SECONDARY_SERVER_ADJ) { app.adjType = "started-bg-services"; } + // Don't kill this process because it is doing work; it + // has said it is doing work. + app.keeping = true; } if (s.connections.size() > 0 && (adj > FOREGROUND_APP_ADJ || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) { @@ -11356,6 +11562,9 @@ public final class ActivityManagerService extends ActivityManagerNative if (!client.hidden) { app.hidden = false; } + if (client.keeping) { + app.keeping = true; + } app.adjType = "service"; app.adjTypeCode = ActivityManager.RunningAppProcessInfo .REASON_SERVICE_IN_USE; @@ -11389,7 +11598,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } - // Finally, f this process has active services running in it, we + // Finally, if this process has active services running in it, we // would like to avoid killing it unless it would prevent the current // application from running. By default we put the process in // with the rest of the background processes; as we scan through @@ -11431,6 +11640,9 @@ public final class ActivityManagerService extends ActivityManagerNative if (!client.hidden) { app.hidden = false; } + if (client.keeping) { + app.keeping = true; + } app.adjType = "provider"; app.adjTypeCode = ActivityManager.RunningAppProcessInfo .REASON_PROVIDER_IN_USE; @@ -11450,6 +11662,7 @@ public final class ActivityManagerService extends ActivityManagerNative adj = FOREGROUND_APP_ADJ; schedGroup = Process.THREAD_GROUP_DEFAULT; app.hidden = false; + app.keeping = true; app.adjType = "provider"; app.adjTarget = cpr.name; } @@ -11467,6 +11680,9 @@ public final class ActivityManagerService extends ActivityManagerNative schedGroup = Process.THREAD_GROUP_DEFAULT; } } + if (adj < HIDDEN_APP_MIN_ADJ) { + app.keeping = true; + } app.curAdj = adj; app.curSchedGroup = schedGroup; @@ -11604,57 +11820,99 @@ public final class ActivityManagerService extends ActivityManagerNative } } - final void checkExcessiveWakeLocksLocked(boolean doKills) { + final void checkExcessivePowerUsageLocked(boolean doKills) { + updateCpuStatsNow(); + BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics(); - if (mLastWakeLockCheckTime == 0) { - doKills = false; + boolean doWakeKills = doKills; + boolean doCpuKills = doKills; + if (mLastPowerCheckRealtime == 0) { + doWakeKills = false; + } + if (mLastPowerCheckUptime == 0) { + doCpuKills = false; } if (stats.isScreenOn()) { - doKills = false; + doWakeKills = false; } final long curRealtime = SystemClock.elapsedRealtime(); - final long timeSince = curRealtime - mLastWakeLockCheckTime; - mLastWakeLockCheckTime = curRealtime; - if (timeSince < (WAKE_LOCK_CHECK_DELAY/3)) { - doKills = false; + final long realtimeSince = curRealtime - mLastPowerCheckRealtime; + final long curUptime = SystemClock.uptimeMillis(); + final long uptimeSince = curUptime - mLastPowerCheckUptime; + mLastPowerCheckRealtime = curRealtime; + mLastPowerCheckUptime = curUptime; + if (realtimeSince < WAKE_LOCK_MIN_CHECK_DURATION) { + doWakeKills = false; + } + if (uptimeSince < CPU_MIN_CHECK_DURATION) { + doCpuKills = false; } int i = mLruProcesses.size(); while (i > 0) { i--; ProcessRecord app = mLruProcesses.get(i); - if (app.curAdj >= HIDDEN_APP_MIN_ADJ) { + if (!app.keeping) { long wtime; synchronized (stats) { wtime = stats.getProcessWakeTime(app.info.uid, app.pid, curRealtime); } - long timeUsed = wtime - app.lastWakeTime; - if (false) { + long wtimeUsed = wtime - app.lastWakeTime; + long cputimeUsed = app.curCpuTime - app.lastCpuTime; + if (DEBUG_POWER) { StringBuilder sb = new StringBuilder(128); sb.append("Wake for "); app.toShortString(sb); sb.append(": over "); - TimeUtils.formatDuration(timeSince, sb); + TimeUtils.formatDuration(realtimeSince, sb); + sb.append(" used "); + TimeUtils.formatDuration(wtimeUsed, sb); + sb.append(" ("); + sb.append((wtimeUsed*100)/realtimeSince); + sb.append("%)"); + Slog.i(TAG, sb.toString()); + sb.setLength(0); + sb.append("CPU for "); + app.toShortString(sb); + sb.append(": over "); + TimeUtils.formatDuration(uptimeSince, sb); sb.append(" used "); - TimeUtils.formatDuration(timeUsed, sb); + TimeUtils.formatDuration(cputimeUsed, sb); sb.append(" ("); - sb.append((timeUsed*100)/timeSince); + sb.append((cputimeUsed*100)/uptimeSince); sb.append("%)"); Slog.i(TAG, sb.toString()); } // If a process has held a wake lock for more // than 50% of the time during this period, // that sounds pad. Kill! - if (doKills && timeSince > 0 - && ((timeUsed*100)/timeSince) >= 50) { - Slog.i(TAG, "Excessive wake lock in " + app.processName - + " (pid " + app.pid + "): held " + timeUsed - + " during " + timeSince); + if (doWakeKills && realtimeSince > 0 + && ((wtimeUsed*100)/realtimeSince) >= 50) { + synchronized (stats) { + stats.reportExcessiveWakeLocked(app.info.uid, app.processName, + realtimeSince, wtimeUsed); + } + Slog.w(TAG, "Excessive wake lock in " + app.processName + + " (pid " + app.pid + "): held " + wtimeUsed + + " during " + realtimeSince); EventLog.writeEvent(EventLogTags.AM_KILL, app.pid, app.processName, app.setAdj, "excessive wake lock"); Process.killProcessQuiet(app.pid); + } else if (doCpuKills && uptimeSince > 0 + && ((cputimeUsed*100)/uptimeSince) >= 50) { + synchronized (stats) { + stats.reportExcessiveCpuLocked(app.info.uid, app.processName, + uptimeSince, cputimeUsed); + } + Slog.w(TAG, "Excessive CPU in " + app.processName + + " (pid " + app.pid + "): used " + cputimeUsed + + " during " + uptimeSince); + EventLog.writeEvent(EventLogTags.AM_KILL, app.pid, + app.processName, app.setAdj, "excessive cpu"); + Process.killProcessQuiet(app.pid); } else { app.lastWakeTime = wtime; + app.lastCpuTime = app.curCpuTime; } } } @@ -11668,6 +11926,8 @@ public final class ActivityManagerService extends ActivityManagerNative return true; } + final boolean wasKeeping = app.keeping; + int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP, false); if ((app.pid != 0 && app.pid != MY_PID) || Process.supportsProcesses()) { @@ -11682,13 +11942,20 @@ public final class ActivityManagerService extends ActivityManagerNative // Likewise do a gc when an app is moving in to the // background (such as a service stopping). scheduleAppGcLocked(app); - // And note its current wake lock time. + } + + if (wasKeeping && !app.keeping) { + // This app is no longer something we want to keep. Note + // its current wake lock time to later know to kill it if + // it is not behaving well. BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics(); synchronized (stats) { app.lastWakeTime = stats.getProcessWakeTime(app.info.uid, app.pid, SystemClock.elapsedRealtime()); } + app.lastCpuTime = app.curCpuTime; } + app.setRawAdj = app.curRawAdj; } if (adj != app.setAdj) { diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java index 67df707..404c6be 100644 --- a/services/java/com/android/server/am/ProcessRecord.java +++ b/services/java/com/android/server/am/ProcessRecord.java @@ -60,6 +60,7 @@ class ProcessRecord { int setAdj; // Last set OOM adjustment for this process int curSchedGroup; // Currently desired scheduling class int setSchedGroup; // Last set to background scheduling class + boolean keeping; // Actively running code so don't kill due to that? boolean setIsForeground; // Running foreground UI when last set? boolean foregroundServices; // Running any services that are foreground? boolean bad; // True if disabled in the bad process list @@ -75,6 +76,8 @@ class ProcessRecord { ComponentName instrumentationResultClass;// copy of instrumentationClass BroadcastRecord curReceiver;// receiver currently running in the app long lastWakeTime; // How long proc held wake lock at last check + long lastCpuTime; // How long proc has run CPU at last check + long curCpuTime; // How long proc has run CPU most recently long lastRequestedGc; // When we last asked the app to do a gc long lastLowMemory; // When we last told the app that memory is low boolean reportLowMemory; // Set to true when waiting to report low mem @@ -131,13 +134,6 @@ class ProcessRecord { void dump(PrintWriter pw, String prefix) { final long now = SystemClock.uptimeMillis(); - long wtime; - synchronized (batteryStats.getBatteryStats()) { - wtime = batteryStats.getBatteryStats().getProcessWakeTime(info.uid, - pid, SystemClock.elapsedRealtime()); - } - long timeUsed = wtime - lastWakeTime; - if (info.className != null) { pw.print(prefix); pw.print("class="); pw.println(info.className); } @@ -170,6 +166,7 @@ class ProcessRecord { pw.print(prefix); pw.print("lastActivityTime="); TimeUtils.formatDuration(lastActivityTime, now, pw); pw.print(" lruWeight="); pw.print(lruWeight); + pw.print(" keeping="); pw.print(keeping); pw.print(" hidden="); pw.print(hidden); pw.print(" empty="); pw.println(empty); pw.print(prefix); pw.print("oom: max="); pw.print(maxAdj); @@ -188,9 +185,20 @@ class ProcessRecord { pw.print(" persistentActivities="); pw.println(persistentActivities); pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq); pw.print(" lruSeq="); pw.println(lruSeq); - pw.print(prefix); pw.print("lastWakeTime="); pw.print(lastWakeTime); - pw.print(" time used="); - TimeUtils.formatDuration(timeUsed, pw); pw.println(""); + if (!keeping) { + long wtime; + synchronized (batteryStats.getBatteryStats()) { + wtime = batteryStats.getBatteryStats().getProcessWakeTime(info.uid, + pid, SystemClock.elapsedRealtime()); + } + long timeUsed = wtime - lastWakeTime; + pw.print(prefix); pw.print("lastWakeTime="); pw.print(lastWakeTime); + pw.print(" time used="); + TimeUtils.formatDuration(timeUsed, pw); pw.println(""); + pw.print(prefix); pw.print("lastCpuTime="); pw.print(lastCpuTime); + pw.print(" time used="); + TimeUtils.formatDuration(curCpuTime-lastCpuTime, pw); pw.println(""); + } pw.print(prefix); pw.print("lastRequestedGc="); TimeUtils.formatDuration(lastRequestedGc, now, pw); pw.print(" lastLowMemory="); diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java index f35a68e..e5aceb4 100644 --- a/services/java/com/android/server/am/ServiceRecord.java +++ b/services/java/com/android/server/am/ServiceRecord.java @@ -347,7 +347,9 @@ class ServiceRecord extends Binder { // If it gave us a garbage notification, it doesn't // get to be foreground. ams.setServiceForeground(name, ServiceRecord.this, - localForegroundId, null, true); + 0, null, true); + ams.crashApplication(appUid, appPid, localPackageName, + "Bad notification for startForeground: " + e); } } }); diff --git a/services/java/com/android/server/sip/SipService.java b/services/java/com/android/server/sip/SipService.java index f1dcd5a..3f43e1c 100644 --- a/services/java/com/android/server/sip/SipService.java +++ b/services/java/com/android/server/sip/SipService.java @@ -30,8 +30,8 @@ import android.net.sip.ISipSessionListener; import android.net.sip.SipErrorCode; import android.net.sip.SipManager; import android.net.sip.SipProfile; +import android.net.sip.SipSession; import android.net.sip.SipSessionAdapter; -import android.net.sip.SipSessionState; import android.net.wifi.WifiManager; import android.os.Binder; import android.os.Bundle; @@ -143,7 +143,7 @@ public final class SipService extends ISipService.Stub { } private void openToReceiveCalls(SipProfile localProfile) { - open3(localProfile, SipManager.SIP_INCOMING_CALL_ACTION, null); + open3(localProfile, SipManager.ACTION_SIP_INCOMING_CALL, null); } public synchronized void open3(SipProfile localProfile, @@ -255,15 +255,15 @@ public final class SipService extends ISipService.Stub { private void notifyProfileAdded(SipProfile localProfile) { if (DEBUG) Log.d(TAG, "notify: profile added: " + localProfile); - Intent intent = new Intent(SipManager.SIP_ADD_PHONE_ACTION); - intent.putExtra(SipManager.LOCAL_URI_KEY, localProfile.getUriString()); + Intent intent = new Intent(SipManager.ACTION_SIP_ADD_PHONE); + intent.putExtra(SipManager.EXTRA_LOCAL_URI, localProfile.getUriString()); mContext.sendBroadcast(intent); } private void notifyProfileRemoved(SipProfile localProfile) { if (DEBUG) Log.d(TAG, "notify: profile removed: " + localProfile); - Intent intent = new Intent(SipManager.SIP_REMOVE_PHONE_ACTION); - intent.putExtra(SipManager.LOCAL_URI_KEY, localProfile.getUriString()); + Intent intent = new Intent(SipManager.ACTION_SIP_REMOVE_PHONE); + intent.putExtra(SipManager.EXTRA_LOCAL_URI, localProfile.getUriString()); mContext.sendBroadcast(intent); } @@ -474,8 +474,8 @@ public final class SipService extends ISipService.Stub { // send out incoming call broadcast addPendingSession(session); Intent intent = SipManager.createIncomingCallBroadcast( - mIncomingCallBroadcastAction, session.getCallId(), - sessionDescription); + session.getCallId(), sessionDescription) + .setAction(mIncomingCallBroadcastAction); if (DEBUG) Log.d(TAG, " ringing~~ " + getUri() + ": " + caller.getUri() + ": " + session.getCallId() + " " + mIncomingCallBroadcastAction); @@ -613,10 +613,10 @@ public final class SipService extends ISipService.Stub { try { int state = (mSession == null) - ? SipSessionState.READY_TO_CALL + ? SipSession.State.READY_TO_CALL : mSession.getState(); - if ((state == SipSessionState.REGISTERING) - || (state == SipSessionState.DEREGISTERING)) { + if ((state == SipSession.State.REGISTERING) + || (state == SipSession.State.DEREGISTERING)) { mProxy.onRegistering(mSession); } else if (mRegistered) { int duration = (int) @@ -1138,7 +1138,8 @@ public final class SipService extends ISipService.Stub { event.mTriggerTime += event.mPeriod; // run the callback in a new thread to prevent deadlock - new Thread(event.mCallback).start(); + new Thread(event.mCallback, "SipServiceTimerCallbackThread") + .start(); } if (DEBUG_TIMER) { Log.d(TAG, "after timeout execution"); diff --git a/services/java/com/android/server/sip/SipSessionGroup.java b/services/java/com/android/server/sip/SipSessionGroup.java index b4c2241..fa3f64a 100644 --- a/services/java/com/android/server/sip/SipSessionGroup.java +++ b/services/java/com/android/server/sip/SipSessionGroup.java @@ -25,11 +25,10 @@ import gov.nist.javax.sip.message.SIPMessage; import android.net.sip.ISipSession; import android.net.sip.ISipSessionListener; -import android.net.sip.SessionDescription; import android.net.sip.SipErrorCode; import android.net.sip.SipProfile; +import android.net.sip.SipSession; import android.net.sip.SipSessionAdapter; -import android.net.sip.SipSessionState; import android.text.TextUtils; import android.util.Log; @@ -85,7 +84,7 @@ class SipSessionGroup implements SipListener { private static final String ANONYMOUS = "anonymous"; private static final String SERVER_ERROR_PREFIX = "Response: "; private static final int EXPIRY_TIME = 3600; // in seconds - private static final int CANCEL_CALL_TIMER = 5; // in seconds + private static final int CANCEL_CALL_TIMER = 3; // in seconds private static final EventObject DEREGISTER = new EventObject("Deregister"); private static final EventObject END_CALL = new EventObject("End call"); @@ -121,7 +120,7 @@ class SipSessionGroup implements SipListener { reset(localIp); } - void reset(String localIp) throws SipException, IOException { + synchronized void reset(String localIp) throws SipException, IOException { mLocalIp = localIp; if (localIp == null) return; @@ -301,7 +300,7 @@ class SipSessionGroup implements SipListener { boolean processed = (session != null) && session.process(event); if (isLoggable && processed) { Log.d(TAG, "new state after: " - + SipSessionState.toString(session.mState)); + + SipSession.State.toString(session.mState)); } } catch (Throwable e) { Log.w(TAG, "event process error: " + event, e); @@ -332,7 +331,7 @@ class SipSessionGroup implements SipListener { public boolean process(EventObject evt) throws SipException { if (isLoggable(this, evt)) Log.d(TAG, " ~~~~~ " + this + ": " - + SipSessionState.toString(mState) + ": processing " + + SipSession.State.toString(mState) + ": processing " + log(evt)); if (isRequestEvent(Request.INVITE, evt)) { RequestEvent event = (RequestEvent) evt; @@ -342,13 +341,16 @@ class SipSessionGroup implements SipListener { newSession.mDialog = newSession.mServerTransaction.getDialog(); newSession.mInviteReceived = event; newSession.mPeerProfile = createPeerProfile(event.getRequest()); - newSession.mState = SipSessionState.INCOMING_CALL; + newSession.mState = SipSession.State.INCOMING_CALL; newSession.mPeerSessionDescription = extractContent(event.getRequest()); addSipSession(newSession); mProxy.onRinging(newSession, newSession.mPeerProfile, newSession.mPeerSessionDescription); return true; + } else if (isRequestEvent(Request.OPTIONS, evt)) { + mSipHelper.sendResponse((RequestEvent) evt, Response.OK); + return true; } else { return false; } @@ -358,7 +360,7 @@ class SipSessionGroup implements SipListener { class SipSessionImpl extends ISipSession.Stub { SipProfile mPeerProfile; SipSessionListenerProxy mProxy = new SipSessionListenerProxy(); - int mState = SipSessionState.READY_TO_CALL; + int mState = SipSession.State.READY_TO_CALL; RequestEvent mInviteReceived; Dialog mDialog; ServerTransaction mServerTransaction; @@ -378,7 +380,7 @@ class SipSessionGroup implements SipListener { sleep(timeout); if (mRunning) timeout(); } - }).start(); + }, "SipSessionTimerThread").start(); } synchronized void cancel() { @@ -413,7 +415,7 @@ class SipSessionGroup implements SipListener { mInCall = false; removeSipSession(this); mPeerProfile = null; - mState = SipSessionState.READY_TO_CALL; + mState = SipSession.State.READY_TO_CALL; mInviteReceived = null; mDialog = null; mServerTransaction = null; @@ -470,7 +472,7 @@ class SipSessionGroup implements SipListener { onError(e); } } - }).start(); + }, "SipSessionAsyncCmdThread").start(); } public void makeCall(SipProfile peerProfile, String sessionDescription, @@ -520,10 +522,10 @@ class SipSessionGroup implements SipListener { } public void sendKeepAlive() { - mState = SipSessionState.PINGING; + mState = SipSession.State.PINGING; try { processCommand(new OptionsCommand()); - while (SipSessionState.PINGING == mState) { + while (SipSession.State.PINGING == mState) { Thread.sleep(1000); } } catch (SipException e) { @@ -550,7 +552,7 @@ class SipSessionGroup implements SipListener { try { String s = super.toString(); return s.substring(s.indexOf("@")) + ":" - + SipSessionState.toString(mState); + + SipSession.State.toString(mState); } catch (Throwable e) { return super.toString(); } @@ -558,7 +560,7 @@ class SipSessionGroup implements SipListener { public boolean process(EventObject evt) throws SipException { if (isLoggable(this, evt)) Log.d(TAG, " ~~~~~ " + this + ": " - + SipSessionState.toString(mState) + ": processing " + + SipSession.State.toString(mState) + ": processing " + log(evt)); synchronized (SipSessionGroup.this) { if (isClosed()) return false; @@ -574,30 +576,30 @@ class SipSessionGroup implements SipListener { boolean processed; switch (mState) { - case SipSessionState.REGISTERING: - case SipSessionState.DEREGISTERING: + case SipSession.State.REGISTERING: + case SipSession.State.DEREGISTERING: processed = registeringToReady(evt); break; - case SipSessionState.PINGING: + case SipSession.State.PINGING: processed = keepAliveProcess(evt); break; - case SipSessionState.READY_TO_CALL: + case SipSession.State.READY_TO_CALL: processed = readyForCall(evt); break; - case SipSessionState.INCOMING_CALL: + case SipSession.State.INCOMING_CALL: processed = incomingCall(evt); break; - case SipSessionState.INCOMING_CALL_ANSWERING: + case SipSession.State.INCOMING_CALL_ANSWERING: processed = incomingCallToInCall(evt); break; - case SipSessionState.OUTGOING_CALL: - case SipSessionState.OUTGOING_CALL_RING_BACK: + case SipSession.State.OUTGOING_CALL: + case SipSession.State.OUTGOING_CALL_RING_BACK: processed = outgoingCall(evt); break; - case SipSessionState.OUTGOING_CALL_CANCELING: + case SipSession.State.OUTGOING_CALL_CANCELING: processed = outgoingCallToReady(evt); break; - case SipSessionState.IN_CALL: + case SipSession.State.IN_CALL: processed = inCall(evt); break; default: @@ -625,6 +627,9 @@ class SipSessionGroup implements SipListener { (TransactionTerminatedEvent) evt); } return true; + } else if (isRequestEvent(Request.OPTIONS, evt)) { + mSipHelper.sendResponse((RequestEvent) evt, Response.OK); + return true; } else if (evt instanceof DialogTerminatedEvent) { processDialogTerminated((DialogTerminatedEvent) evt); return true; @@ -644,8 +649,8 @@ class SipSessionGroup implements SipListener { private void processTransactionTerminated( TransactionTerminatedEvent event) { switch (mState) { - case SipSessionState.IN_CALL: - case SipSessionState.READY_TO_CALL: + case SipSession.State.IN_CALL: + case SipSession.State.READY_TO_CALL: Log.d(TAG, "Transaction terminated; do nothing"); break; default: @@ -664,27 +669,27 @@ class SipSessionGroup implements SipListener { ? event.getServerTransaction() : event.getClientTransaction(); - if ((current != target) && (mState != SipSessionState.PINGING)) { + if ((current != target) && (mState != SipSession.State.PINGING)) { Log.d(TAG, "not the current transaction; current=" + current + ", timed out=" + target); return; } switch (mState) { - case SipSessionState.REGISTERING: - case SipSessionState.DEREGISTERING: + case SipSession.State.REGISTERING: + case SipSession.State.DEREGISTERING: reset(); mProxy.onRegistrationTimeout(this); break; - case SipSessionState.INCOMING_CALL: - case SipSessionState.INCOMING_CALL_ANSWERING: - case SipSessionState.OUTGOING_CALL: - case SipSessionState.OUTGOING_CALL_CANCELING: + case SipSession.State.INCOMING_CALL: + case SipSession.State.INCOMING_CALL_ANSWERING: + case SipSession.State.OUTGOING_CALL: + case SipSession.State.OUTGOING_CALL_CANCELING: onError(SipErrorCode.TIME_OUT, event.toString()); break; - case SipSessionState.PINGING: + case SipSession.State.PINGING: reset(); mReRegisterFlag = true; - mState = SipSessionState.READY_TO_CALL; + mState = SipSession.State.READY_TO_CALL; break; default: @@ -758,7 +763,7 @@ class SipSessionGroup implements SipListener { switch (statusCode) { case Response.OK: int state = mState; - onRegistrationDone((state == SipSessionState.REGISTERING) + onRegistrationDone((state == SipSession.State.REGISTERING) ? getExpiryTime(((ResponseEvent) evt).getResponse()) : -1); mLastNonce = null; @@ -845,7 +850,7 @@ class SipSessionGroup implements SipListener { generateTag()); mDialog = mClientTransaction.getDialog(); addSipSession(this); - mState = SipSessionState.OUTGOING_CALL; + mState = SipSession.State.OUTGOING_CALL; mProxy.onCalling(this); startSessionTimer(cmd.getTimeout()); return true; @@ -855,7 +860,7 @@ class SipSessionGroup implements SipListener { generateTag(), duration); mDialog = mClientTransaction.getDialog(); addSipSession(this); - mState = SipSessionState.REGISTERING; + mState = SipSession.State.REGISTERING; mProxy.onRegistering(this); return true; } else if (DEREGISTER == evt) { @@ -863,7 +868,7 @@ class SipSessionGroup implements SipListener { generateTag(), 0); mDialog = mClientTransaction.getDialog(); addSipSession(this); - mState = SipSessionState.DEREGISTERING; + mState = SipSession.State.DEREGISTERING; mProxy.onRegistering(this); return true; } @@ -878,7 +883,7 @@ class SipSessionGroup implements SipListener { mLocalProfile, ((MakeCallCommand) evt).getSessionDescription(), mServerTransaction); - mState = SipSessionState.INCOMING_CALL_ANSWERING; + mState = SipSession.State.INCOMING_CALL_ANSWERING; startSessionTimer(((MakeCallCommand) evt).getTimeout()); return true; } else if (END_CALL == evt) { @@ -919,8 +924,8 @@ class SipSessionGroup implements SipListener { int statusCode = response.getStatusCode(); switch (statusCode) { case Response.RINGING: - if (mState == SipSessionState.OUTGOING_CALL) { - mState = SipSessionState.OUTGOING_CALL_RING_BACK; + if (mState == SipSession.State.OUTGOING_CALL) { + mState = SipSession.State.OUTGOING_CALL_RING_BACK; mProxy.onRingingBack(this); cancelSessionTimer(); } @@ -963,7 +968,7 @@ class SipSessionGroup implements SipListener { // response comes back yet. We are cheating for not checking // response. mSipHelper.sendCancel(mClientTransaction); - mState = SipSessionState.OUTGOING_CALL_CANCELING; + mState = SipSession.State.OUTGOING_CALL_CANCELING; startSessionTimer(CANCEL_CALL_TIMER); return true; } @@ -1019,7 +1024,7 @@ class SipSessionGroup implements SipListener { } else if (isRequestEvent(Request.INVITE, evt)) { // got Re-INVITE RequestEvent event = mInviteReceived = (RequestEvent) evt; - mState = SipSessionState.INCOMING_CALL; + mState = SipSession.State.INCOMING_CALL; mPeerSessionDescription = extractContent(event.getRequest()); mServerTransaction = null; mProxy.onRinging(this, mPeerProfile, mPeerSessionDescription); @@ -1032,7 +1037,7 @@ class SipSessionGroup implements SipListener { // to change call mClientTransaction = mSipHelper.sendReinvite(mDialog, ((MakeCallCommand) evt).getSessionDescription()); - mState = SipSessionState.OUTGOING_CALL; + mState = SipSession.State.OUTGOING_CALL; startSessionTimer(((MakeCallCommand) evt).getTimeout()); return true; } @@ -1060,14 +1065,14 @@ class SipSessionGroup implements SipListener { } private void establishCall() { - mState = SipSessionState.IN_CALL; + mState = SipSession.State.IN_CALL; mInCall = true; cancelSessionTimer(); mProxy.onCallEstablished(this, mPeerSessionDescription); } private void fallbackToPreviousInCall(int errorCode, String message) { - mState = SipSessionState.IN_CALL; + mState = SipSession.State.IN_CALL; mProxy.onCallChangeFailed(this, errorCode, message); } @@ -1089,8 +1094,8 @@ class SipSessionGroup implements SipListener { private void onError(int errorCode, String message) { cancelSessionTimer(); switch (mState) { - case SipSessionState.REGISTERING: - case SipSessionState.DEREGISTERING: + case SipSession.State.REGISTERING: + case SipSession.State.DEREGISTERING: onRegistrationFailed(errorCode, message); break; default: @@ -1264,7 +1269,7 @@ class SipSessionGroup implements SipListener { private static boolean isLoggable(SipSessionImpl s) { if (s != null) { switch (s.mState) { - case SipSessionState.PINGING: + case SipSession.State.PINGING: return DEBUG_PING; } } diff --git a/services/java/com/android/server/sip/SipSessionListenerProxy.java b/services/java/com/android/server/sip/SipSessionListenerProxy.java index a4cd102..f8be0a8 100644 --- a/services/java/com/android/server/sip/SipSessionListenerProxy.java +++ b/services/java/com/android/server/sip/SipSessionListenerProxy.java @@ -40,7 +40,7 @@ class SipSessionListenerProxy extends ISipSessionListener.Stub { // One thread for each calling back. // Note: Guarantee ordering if the issue becomes important. Currently, // the chance of handling two callback events at a time is none. - new Thread(runnable).start(); + new Thread(runnable, "SipSessionCallbackThread").start(); } public void onCalling(final ISipSession session) { diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java index 35aa3b3..45e6ccd 100755 --- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java +++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java @@ -27,7 +27,7 @@ import android.net.sip.SipErrorCode; import android.net.sip.SipException; import android.net.sip.SipManager; import android.net.sip.SipProfile; -import android.net.sip.SipSessionState; +import android.net.sip.SipSession; import android.os.AsyncResult; import android.os.Handler; import android.os.Looper; @@ -74,7 +74,9 @@ import java.util.List; public class SipPhone extends SipPhoneBase { private static final String LOG_TAG = "SipPhone"; private static final boolean LOCAL_DEBUG = true; - private static final int SESSION_TIMEOUT = 8; // in seconds + private static final int TIMEOUT_MAKE_CALL = 15; // in seconds + private static final int TIMEOUT_ANSWER_CALL = 8; // in seconds + private static final int TIMEOUT_HOLD_CALL = 15; // in seconds // A call that is ringing or (call) waiting private SipCall ringingCall = new SipCall(); @@ -92,7 +94,7 @@ public class SipPhone extends SipPhoneBase { foregroundCall = new SipCall(); backgroundCall = new SipCall(); mProfile = profile; - mSipManager = SipManager.getInstance(context); + mSipManager = SipManager.newInstance(context); // FIXME: what's this for SIP? //Change the system property @@ -690,7 +692,7 @@ public class SipPhone extends SipPhoneBase { void acceptCall() throws CallStateException { try { - mSipAudioCall.answerCall(SESSION_TIMEOUT); + mSipAudioCall.answerCall(TIMEOUT_ANSWER_CALL); } catch (SipException e) { throw new CallStateException("acceptCall(): " + e); } @@ -707,8 +709,8 @@ public class SipPhone extends SipPhoneBase { void dial() throws SipException { setState(Call.State.DIALING); - mSipAudioCall = mSipManager.makeAudioCall(mContext, mProfile, - mPeer, null, SESSION_TIMEOUT); + mSipAudioCall = mSipManager.makeAudioCall(mProfile, mPeer, null, + TIMEOUT_MAKE_CALL); mSipAudioCall.setRingbackToneEnabled(false); mSipAudioCall.setListener(mAdapter); } @@ -716,7 +718,7 @@ public class SipPhone extends SipPhoneBase { void hold() throws CallStateException { setState(Call.State.HOLDING); try { - mSipAudioCall.holdCall(SESSION_TIMEOUT); + mSipAudioCall.holdCall(TIMEOUT_HOLD_CALL); } catch (SipException e) { throw new CallStateException("hold(): " + e); } @@ -726,7 +728,7 @@ public class SipPhone extends SipPhoneBase { mSipAudioCall.setAudioGroup(audioGroup); setState(Call.State.ACTIVE); try { - mSipAudioCall.continueCall(SESSION_TIMEOUT); + mSipAudioCall.continueCall(TIMEOUT_HOLD_CALL); } catch (SipException e) { throw new CallStateException("unhold(): " + e); } @@ -808,20 +810,20 @@ public class SipPhone extends SipPhoneBase { if (sipAudioCall.isOnHold()) return Call.State.HOLDING; int sessionState = sipAudioCall.getState(); switch (sessionState) { - case SipSessionState.READY_TO_CALL: return Call.State.IDLE; - case SipSessionState.INCOMING_CALL: - case SipSessionState.INCOMING_CALL_ANSWERING: return Call.State.INCOMING; - case SipSessionState.OUTGOING_CALL: return Call.State.DIALING; - case SipSessionState.OUTGOING_CALL_RING_BACK: return Call.State.ALERTING; - case SipSessionState.OUTGOING_CALL_CANCELING: return Call.State.DISCONNECTING; - case SipSessionState.IN_CALL: return Call.State.ACTIVE; + case SipSession.State.READY_TO_CALL: return Call.State.IDLE; + case SipSession.State.INCOMING_CALL: + case SipSession.State.INCOMING_CALL_ANSWERING: return Call.State.INCOMING; + case SipSession.State.OUTGOING_CALL: return Call.State.DIALING; + case SipSession.State.OUTGOING_CALL_RING_BACK: return Call.State.ALERTING; + case SipSession.State.OUTGOING_CALL_CANCELING: return Call.State.DISCONNECTING; + case SipSession.State.IN_CALL: return Call.State.ACTIVE; default: Log.w(LOG_TAG, "illegal connection state: " + sessionState); return Call.State.DISCONNECTED; } } - private abstract class SipAudioCallAdapter extends SipAudioCall.Adapter { + private abstract class SipAudioCallAdapter extends SipAudioCall.Listener { protected abstract void onCallEnded(Connection.DisconnectCause cause); protected abstract void onError(Connection.DisconnectCause cause); diff --git a/tests/BatteryWaster/src/com/android/batterywaster/BatteryWaster.java b/tests/BatteryWaster/src/com/android/batterywaster/BatteryWaster.java index 48c4520..5fb09a7 100644 --- a/tests/BatteryWaster/src/com/android/batterywaster/BatteryWaster.java +++ b/tests/BatteryWaster/src/com/android/batterywaster/BatteryWaster.java @@ -25,6 +25,7 @@ import android.os.BatteryManager; import android.os.Bundle; import android.os.PowerManager; import android.view.View; +import android.view.WindowManager; import android.widget.CheckBox; import android.widget.TextView; @@ -38,7 +39,6 @@ public class BatteryWaster extends Activity { TextView mLog; DateFormat mDateFormat; IntentFilter mFilter; - PowerManager.WakeLock mWakeLock; PowerManager.WakeLock mPartialWakeLock; SpinThread mThread; @@ -65,24 +65,26 @@ public class BatteryWaster extends Activity { mFilter.addAction(Intent.ACTION_POWER_CONNECTED); PowerManager pm = (PowerManager)getSystemService(POWER_SERVICE); - mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "BatteryWaster"); - mWakeLock.setReferenceCounted(false); mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "BatteryWaster"); mPartialWakeLock.setReferenceCounted(false); } @Override - public void onPause() { - super.onPause(); - stopRunning(); + public void onResume() { + super.onResume(); + if (((CheckBox)findViewById(R.id.checkbox)).isChecked()) { + startRunning(); + } + if (((CheckBox)findViewById(R.id.checkbox_wake)).isChecked()) { + mWaking = true; + updateWakeLock(); + } } @Override public void onDestroy() { super.onDestroy(); - if (mWakeLock.isHeld()) { - mWakeLock.release(); - } + stopRunning(); if (mPartialWakeLock.isHeld()) { mPartialWakeLock.release(); } @@ -140,13 +142,9 @@ public class BatteryWaster extends Activity { void updateWakeLock() { if (mWasting) { - if (!mWakeLock.isHeld()) { - mWakeLock.acquire(); - } + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } else { - if (mWakeLock.isHeld()) { - mWakeLock.release(); - } + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } if (mWaking) { if (!mPartialWakeLock.isHeld()) { diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h index a1bc241..c5aa573 100644 --- a/tools/aapt/Bundle.h +++ b/tools/aapt/Bundle.h @@ -45,7 +45,7 @@ public: mRClassDir(NULL), mResourceIntermediatesDir(NULL), mManifestMinSdkVersion(NULL), mMinSdkVersion(NULL), mTargetSdkVersion(NULL), mMaxSdkVersion(NULL), mVersionCode(NULL), mVersionName(NULL), mCustomPackage(NULL), - mMaxResVersion(NULL), mDebugMode(false), + mMaxResVersion(NULL), mDebugMode(false), mProduct(NULL), mArgc(0), mArgv(NULL) {} ~Bundle(void) {} @@ -139,6 +139,8 @@ public: void setMaxResVersion(const char * val) { mMaxResVersion = val; } bool getDebugMode() { return mDebugMode; } void setDebugMode(bool val) { mDebugMode = val; } + const char* getProduct() const { return mProduct; } + void setProduct(const char * val) { mProduct = val; } /* * Set and get the file specification. @@ -237,6 +239,7 @@ private: const char* mCustomPackage; const char* mMaxResVersion; bool mDebugMode; + const char* mProduct; /* file specification */ int mArgc; diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp index 71c023d..739b01f 100644 --- a/tools/aapt/Main.cpp +++ b/tools/aapt/Main.cpp @@ -67,6 +67,7 @@ void usage(void) " [-A asset-source-dir] [-G class-list-file] [-P public-definitions-file] \\\n" " [-S resource-sources [-S resource-sources ...]] " " [-F apk-file] [-J R-file-dir] \\\n" + " [--product product1,product2,...] \\\n" " [raw-files-dir [raw-files-dir] ...]\n" "\n" " Package the android resources. It will read assets and resources that are\n" @@ -154,6 +155,9 @@ void usage(void) " components target the given package. Useful when used in\n" " conjunction with --rename-manifest-package to fix tests against\n" " a package that has been renamed.\n" + " --product\n" + " Specifies which variant to choose for strings that have\n" + " product variants\n" " --utf16\n" " changes default encoding for resources to UTF-16. Only useful when API\n" " level is set to 7 or higher where the default encoding is UTF-8.\n"); @@ -484,6 +488,15 @@ int main(int argc, char* const argv[]) bundle.setInstrumentationPackageNameOverride(argv[0]); } else if (strcmp(cp, "-auto-add-overlay") == 0) { bundle.setAutoAddOverlay(true); + } else if (strcmp(cp, "-product") == 0) { + argc--; + argv++; + if (!argc) { + fprintf(stderr, "ERROR: No argument supplied for '--product' option\n"); + wantUsage = true; + goto bail; + } + bundle.setProduct(argv[0]); } else { fprintf(stderr, "ERROR: Unknown option '-%s'\n", cp); wantUsage = true; diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp index 755b93b..532fb65 100644 --- a/tools/aapt/ResourceTable.cpp +++ b/tools/aapt/ResourceTable.cpp @@ -574,6 +574,7 @@ status_t parseAndAddBag(Bundle* bundle, const String16& itemIdent, int32_t curFormat, bool isFormatted, + const String16& product, bool pseudolocalize, const bool overwrite, ResourceTable* outTable) @@ -606,6 +607,32 @@ status_t parseAndAddBag(Bundle* bundle, return err; } +/* + * Returns true if needle is one of the elements in the comma-separated list + * haystack, false otherwise. + */ +bool isInProductList(const String16& needle, const String16& haystack) { + const char16_t *needle2 = needle.string(); + const char16_t *haystack2 = haystack.string(); + size_t needlesize = needle.size(); + + while (*haystack2 != '\0') { + if (strncmp16(haystack2, needle2, needlesize) == 0) { + if (haystack2[needlesize] == '\0' || haystack2[needlesize] == ',') { + return true; + } + } + + while (*haystack2 != '\0' && *haystack2 != ',') { + haystack2++; + } + if (*haystack2 == ',') { + haystack2++; + } + } + + return false; +} status_t parseAndAddEntry(Bundle* bundle, const sp<AaptFile>& in, @@ -618,6 +645,7 @@ status_t parseAndAddEntry(Bundle* bundle, bool curIsStyled, int32_t curFormat, bool isFormatted, + const String16& product, bool pseudolocalize, const bool overwrite, ResourceTable* outTable) @@ -634,6 +662,47 @@ status_t parseAndAddEntry(Bundle* bundle, return err; } + /* + * If a product type was specified on the command line + * and also in the string, and the two are not the same, + * return without adding the string. + */ + + const char *bundleProduct = bundle->getProduct(); + if (bundleProduct == NULL) { + bundleProduct = ""; + } + + if (product.size() != 0) { + /* + * If the command-line-specified product is empty, only "default" + * matches. Other variants are skipped. This is so generation + * of the R.java file when the product is not known is predictable. + */ + + if (bundleProduct[0] == '\0') { + if (strcmp16(String16("default").string(), product.string()) != 0) { + return NO_ERROR; + } + } else { + /* + * The command-line product is not empty. + * If the product for this string is on the command-line list, + * it matches. "default" also matches, but only if nothing + * else has matched already. + */ + + if (isInProductList(product, String16(bundleProduct))) { + ; + } else if (strcmp16(String16("default").string(), product.string()) == 0 && + !outTable->hasBagOrEntry(myPackage, curType, ident)) { + ; + } else { + return NO_ERROR; + } + } + } + NOISY(printf("Adding resource entry l=%c%c c=%c%c orien=%d d=%d id=%s: %s\n", config.language[0], config.language[1], config.country[0], config.country[1], @@ -713,6 +782,7 @@ status_t compileResourceFile(Bundle* bundle, const String16 translatable16("translatable"); const String16 formatted16("formatted"); const String16 false16("false"); + const String16 product16("product"); const String16 myPackage(assets->getPackage()); @@ -760,6 +830,7 @@ status_t compileResourceFile(Bundle* bundle, bool curIsStyled = false; bool curIsPseudolocalizable = false; bool curIsFormatted = fileIsTranslatable; + String16 curProduct; bool localHasErrors = false; if (strcmp16(block.getElementName(&len), skip16.string()) == 0) { @@ -1157,6 +1228,8 @@ status_t compileResourceFile(Bundle* bundle, translatable.setTo(block.getAttributeStringValue(i, &length)); } else if (strcmp16(attr, formatted16.string()) == 0) { formatted.setTo(block.getAttributeStringValue(i, &length)); + } else if (strcmp16(attr, product16.string()) == 0) { + curProduct.setTo(block.getAttributeStringValue(i, &length)); } } @@ -1374,7 +1447,7 @@ status_t compileResourceFile(Bundle* bundle, err = parseAndAddBag(bundle, in, &block, curParams, myPackage, curType, ident, parentIdent, itemIdent, curFormat, curIsFormatted, - false, overwrite, outTable); + curProduct, false, overwrite, outTable); if (err == NO_ERROR) { if (curIsPseudolocalizable && localeIsDefined(curParams) && bundle->getPseudolocalize()) { @@ -1383,7 +1456,7 @@ status_t compileResourceFile(Bundle* bundle, block.setPosition(parserPosition); err = parseAndAddBag(bundle, in, &block, pseudoParams, myPackage, curType, ident, parentIdent, itemIdent, curFormat, - curIsFormatted, true, overwrite, outTable); + curIsFormatted, curProduct, true, overwrite, outTable); #endif } } @@ -1407,7 +1480,7 @@ status_t compileResourceFile(Bundle* bundle, err = parseAndAddEntry(bundle, in, &block, curParams, myPackage, curType, ident, *curTag, curIsStyled, curFormat, curIsFormatted, - false, overwrite, outTable); + curProduct, false, overwrite, outTable); if (err < NO_ERROR) { // Why err < NO_ERROR instead of err != NO_ERROR? hasErrors = localHasErrors = true; @@ -1419,7 +1492,8 @@ status_t compileResourceFile(Bundle* bundle, block.setPosition(parserPosition); err = parseAndAddEntry(bundle, in, &block, pseudoParams, myPackage, curType, ident, *curTag, curIsStyled, curFormat, - curIsFormatted, true, overwrite, outTable); + curIsFormatted, curProduct, + true, overwrite, outTable); if (err != NO_ERROR) { hasErrors = localHasErrors = true; } diff --git a/voip/java/android/net/sip/SdpSessionDescription.java b/voip/java/android/net/sip/SdpSessionDescription.java deleted file mode 100644 index f6ae837..0000000 --- a/voip/java/android/net/sip/SdpSessionDescription.java +++ /dev/null @@ -1,428 +0,0 @@ -/* - * 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.sip; - -import gov.nist.javax.sdp.SessionDescriptionImpl; -import gov.nist.javax.sdp.fields.AttributeField; -import gov.nist.javax.sdp.fields.ConnectionField; -import gov.nist.javax.sdp.fields.MediaField; -import gov.nist.javax.sdp.fields.OriginField; -import gov.nist.javax.sdp.fields.ProtoVersionField; -import gov.nist.javax.sdp.fields.SessionNameField; -import gov.nist.javax.sdp.fields.TimeField; -import gov.nist.javax.sdp.parser.SDPAnnounceParser; - -import android.util.Log; - -import java.text.ParseException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Vector; -import javax.sdp.Connection; -import javax.sdp.MediaDescription; -import javax.sdp.SdpException; - -/** - * A session description that follows SDP (Session Description Protocol). - * Refer to <a href="http://tools.ietf.org/html/rfc4566">RFC 4566</a>. - * @hide - */ -public class SdpSessionDescription extends SessionDescription { - private static final String TAG = "SDP"; - private static final String AUDIO = "audio"; - private static final String RTPMAP = "rtpmap"; - private static final String PTIME = "ptime"; - private static final String SENDONLY = "sendonly"; - private static final String RECVONLY = "recvonly"; - private static final String INACTIVE = "inactive"; - - private SessionDescriptionImpl mSessionDescription; - - /** - * The audio codec information parsed from "rtpmap". - */ - public static class AudioCodec { - public final int payloadType; - public final String name; - public final int sampleRate; - public final int sampleCount; - - public AudioCodec(int payloadType, String name, int sampleRate, - int sampleCount) { - this.payloadType = payloadType; - this.name = name; - this.sampleRate = sampleRate; - this.sampleCount = sampleCount; - } - } - - /** - * The builder class used to create an {@link SdpSessionDescription} object. - */ - public static class Builder { - private SdpSessionDescription mSdp = new SdpSessionDescription(); - private SessionDescriptionImpl mSessionDescription; - - public Builder(String sessionName) throws SdpException { - mSessionDescription = new SessionDescriptionImpl(); - mSdp.mSessionDescription = mSessionDescription; - try { - ProtoVersionField proto = new ProtoVersionField(); - proto.setVersion(0); - mSessionDescription.addField(proto); - - TimeField time = new TimeField(); - time.setZero(); - mSessionDescription.addField(time); - - SessionNameField session = new SessionNameField(); - session.setValue(sessionName); - mSessionDescription.addField(session); - } catch (Exception e) { - throwSdpException(e); - } - } - - public Builder setConnectionInfo(String networkType, String addressType, - String addr) throws SdpException { - try { - ConnectionField connection = new ConnectionField(); - connection.setNetworkType(networkType); - connection.setAddressType(addressType); - connection.setAddress(addr); - mSessionDescription.addField(connection); - } catch (Exception e) { - throwSdpException(e); - } - return this; - } - - public Builder setOrigin(SipProfile user, long sessionId, - long sessionVersion, String networkType, String addressType, - String address) throws SdpException { - try { - OriginField origin = new OriginField(); - origin.setUsername(user.getUserName()); - origin.setSessionId(sessionId); - origin.setSessionVersion(sessionVersion); - origin.setAddressType(addressType); - origin.setNetworkType(networkType); - origin.setAddress(address); - mSessionDescription.addField(origin); - } catch (Exception e) { - throwSdpException(e); - } - return this; - } - - public Builder addMedia(String media, int port, int numPorts, - String transport, Integer... types) throws SdpException { - MediaField field = new MediaField(); - Vector<Integer> typeVector = new Vector<Integer>(); - Collections.addAll(typeVector, types); - try { - field.setMediaType(media); - field.setMediaPort(port); - field.setPortCount(numPorts); - field.setProtocol(transport); - field.setMediaFormats(typeVector); - mSessionDescription.addField(field); - } catch (Exception e) { - throwSdpException(e); - } - return this; - } - - public Builder addMediaAttribute(String type, String name, String value) - throws SdpException { - try { - MediaDescription md = mSdp.getMediaDescription(type); - if (md == null) { - throw new SdpException("Should add media first!"); - } - AttributeField attribute = new AttributeField(); - attribute.setName(name); - attribute.setValueAllowNull(value); - mSessionDescription.addField(attribute); - } catch (Exception e) { - throwSdpException(e); - } - return this; - } - - public Builder addSessionAttribute(String name, String value) - throws SdpException { - try { - AttributeField attribute = new AttributeField(); - attribute.setName(name); - attribute.setValueAllowNull(value); - mSessionDescription.addField(attribute); - } catch (Exception e) { - throwSdpException(e); - } - return this; - } - - private void throwSdpException(Exception e) throws SdpException { - if (e instanceof SdpException) { - throw (SdpException) e; - } else { - throw new SdpException(e.toString(), e); - } - } - - public String build() { - return mSdp.toString(); - } - } - - private SdpSessionDescription() { - } - - /** - * Constructor. - * - * @param sdpString an SDP session description to parse - */ - public SdpSessionDescription(String sdpString) throws SdpException { - try { - mSessionDescription = new SDPAnnounceParser(sdpString).parse(); - } catch (ParseException e) { - throw new SdpException(e.toString(), e); - } - verify(); - } - - /** - * Constructor. - * - * @param content a raw SDP session description to parse - */ - public SdpSessionDescription(byte[] content) throws SdpException { - this(new String(content)); - } - - private void verify() throws SdpException { - // make sure the syntax is correct over the fields we're interested in - Vector<MediaDescription> descriptions = (Vector<MediaDescription>) - mSessionDescription.getMediaDescriptions(false); - for (MediaDescription md : descriptions) { - md.getMedia().getMediaPort(); - Connection connection = md.getConnection(); - if (connection != null) connection.getAddress(); - md.getMedia().getFormats(); - } - Connection connection = mSessionDescription.getConnection(); - if (connection != null) connection.getAddress(); - } - - /** - * Gets the connection address of the media. - * - * @param type the media type; e.g., "AUDIO" - * @return the media connection address of the peer - */ - public String getPeerMediaAddress(String type) { - try { - MediaDescription md = getMediaDescription(type); - Connection connection = md.getConnection(); - if (connection == null) { - connection = mSessionDescription.getConnection(); - } - return ((connection == null) ? null : connection.getAddress()); - } catch (SdpException e) { - // should not occur - return null; - } - } - - /** - * Gets the connection port number of the media. - * - * @param type the media type; e.g., "AUDIO" - * @return the media connection port number of the peer - */ - public int getPeerMediaPort(String type) { - try { - MediaDescription md = getMediaDescription(type); - return md.getMedia().getMediaPort(); - } catch (SdpException e) { - // should not occur - return -1; - } - } - - private boolean containsAttribute(String type, String name) { - if (name == null) return false; - MediaDescription md = getMediaDescription(type); - Vector<AttributeField> v = (Vector<AttributeField>) - md.getAttributeFields(); - for (AttributeField field : v) { - if (name.equals(field.getAttribute().getName())) return true; - } - return false; - } - - /** - * Checks if the media is "sendonly". - * - * @param type the media type; e.g., "AUDIO" - * @return true if the media is "sendonly" - */ - public boolean isSendOnly(String type) { - boolean answer = containsAttribute(type, SENDONLY); - Log.d(TAG, " sendonly? " + answer); - return answer; - } - - /** - * Checks if the media is "recvonly". - * - * @param type the media type; e.g., "AUDIO" - * @return true if the media is "recvonly" - */ - public boolean isReceiveOnly(String type) { - boolean answer = containsAttribute(type, RECVONLY); - Log.d(TAG, " recvonly? " + answer); - return answer; - } - - /** - * Checks if the media is in sending; i.e., not "recvonly" and not - * "inactive". - * - * @param type the media type; e.g., "AUDIO" - * @return true if the media is sending - */ - public boolean isSending(String type) { - boolean answer = !containsAttribute(type, RECVONLY) - && !containsAttribute(type, INACTIVE); - - Log.d(TAG, " sending? " + answer); - return answer; - } - - /** - * Checks if the media is in receiving; i.e., not "sendonly" and not - * "inactive". - * - * @param type the media type; e.g., "AUDIO" - * @return true if the media is receiving - */ - public boolean isReceiving(String type) { - boolean answer = !containsAttribute(type, SENDONLY) - && !containsAttribute(type, INACTIVE); - Log.d(TAG, " receiving? " + answer); - return answer; - } - - private AudioCodec parseAudioCodec(String rtpmap, int ptime) { - String[] ss = rtpmap.split(" "); - int payloadType = Integer.parseInt(ss[0]); - - ss = ss[1].split("/"); - String name = ss[0]; - int sampleRate = Integer.parseInt(ss[1]); - int channelCount = 1; - if (ss.length > 2) channelCount = Integer.parseInt(ss[2]); - int sampleCount = sampleRate / (1000 / ptime) * channelCount; - return new AudioCodec(payloadType, name, sampleRate, sampleCount); - } - - /** - * Gets the list of audio codecs in this session description. - * - * @return the list of audio codecs in this session description - */ - public List<AudioCodec> getAudioCodecs() { - MediaDescription md = getMediaDescription(AUDIO); - if (md == null) return new ArrayList<AudioCodec>(); - - // FIXME: what happens if ptime is missing - int ptime = 20; - try { - String value = md.getAttribute(PTIME); - if (value != null) ptime = Integer.parseInt(value); - } catch (Throwable t) { - Log.w(TAG, "getCodecs(): ignored: " + t); - } - - List<AudioCodec> codecs = new ArrayList<AudioCodec>(); - Vector<AttributeField> v = (Vector<AttributeField>) - md.getAttributeFields(); - for (AttributeField field : v) { - try { - if (RTPMAP.equals(field.getName())) { - AudioCodec codec = parseAudioCodec(field.getValue(), ptime); - if (codec != null) codecs.add(codec); - } - } catch (Throwable t) { - Log.w(TAG, "getCodecs(): ignored: " + t); - } - } - return codecs; - } - - /** - * Gets the media description of the specified type. - * - * @param type the media type; e.g., "AUDIO" - * @return the media description of the specified type - */ - public MediaDescription getMediaDescription(String type) { - MediaDescription[] all = getMediaDescriptions(); - if ((all == null) || (all.length == 0)) return null; - for (MediaDescription md : all) { - String t = md.getMedia().getMedia(); - if (t.equalsIgnoreCase(type)) return md; - } - return null; - } - - /** - * Gets all the media descriptions in this session description. - * - * @return all the media descriptions in this session description - */ - public MediaDescription[] getMediaDescriptions() { - try { - Vector<MediaDescription> descriptions = (Vector<MediaDescription>) - mSessionDescription.getMediaDescriptions(false); - MediaDescription[] all = new MediaDescription[descriptions.size()]; - return descriptions.toArray(all); - } catch (SdpException e) { - Log.e(TAG, "getMediaDescriptions", e); - } - return null; - } - - @Override - public String getType() { - return "sdp"; - } - - @Override - public byte[] getContent() { - return mSessionDescription.toString().getBytes(); - } - - @Override - public String toString() { - return mSessionDescription.toString(); - } -} diff --git a/voip/java/android/net/sip/SessionDescription.aidl b/voip/java/android/net/sip/SessionDescription.aidl deleted file mode 100644 index a120d16..0000000 --- a/voip/java/android/net/sip/SessionDescription.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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.sip; - -parcelable SessionDescription; diff --git a/voip/java/android/net/sip/SessionDescription.java b/voip/java/android/net/sip/SessionDescription.java deleted file mode 100644 index d476f0b..0000000 --- a/voip/java/android/net/sip/SessionDescription.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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.sip; - -import android.os.Parcel; -import android.os.Parcelable; - -/** - * Abstract class of a session description. - * @hide - */ -public abstract class SessionDescription implements Parcelable { - /** @hide */ - public static final Parcelable.Creator<SessionDescription> CREATOR = - new Parcelable.Creator<SessionDescription>() { - public SessionDescription createFromParcel(Parcel in) { - return new SessionDescriptionImpl(in); - } - - public SessionDescription[] newArray(int size) { - return new SessionDescriptionImpl[size]; - } - }; - - /** - * Gets the type of the session description; e.g., "SDP". - * - * @return the session description type - */ - public abstract String getType(); - - /** - * Gets the raw content of the session description. - * - * @return the content of the session description - */ - public abstract byte[] getContent(); - - /** @hide */ - public void writeToParcel(Parcel out, int flags) { - out.writeString(getType()); - out.writeByteArray(getContent()); - } - - /** @hide */ - public int describeContents() { - return 0; - } - - private static class SessionDescriptionImpl extends SessionDescription { - private String mType; - private byte[] mContent; - - SessionDescriptionImpl(Parcel in) { - mType = in.readString(); - mContent = in.createByteArray(); - } - - @Override - public String getType() { - return mType; - } - - @Override - public byte[] getContent() { - return mContent; - } - } -} diff --git a/voip/java/android/net/sip/SipAudioCall.java b/voip/java/android/net/sip/SipAudioCall.java index 0069fe0..2f4fd90 100644 --- a/voip/java/android/net/sip/SipAudioCall.java +++ b/voip/java/android/net/sip/SipAudioCall.java @@ -16,120 +16,184 @@ package android.net.sip; +import android.content.Context; +import android.media.AudioManager; +import android.media.Ringtone; +import android.media.RingtoneManager; +import android.media.ToneGenerator; +import android.net.Uri; +import android.net.rtp.AudioCodec; import android.net.rtp.AudioGroup; import android.net.rtp.AudioStream; +import android.net.rtp.RtpStream; +import android.net.sip.SimpleSessionDescription.Media; +import android.net.wifi.WifiManager; import android.os.Message; +import android.os.RemoteException; +import android.os.Vibrator; +import android.provider.Settings; +import android.util.Log; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** - * Interface for making audio calls over SIP. - * @hide + * Class that handles an audio call over SIP. */ -public interface SipAudioCall { +/** @hide */ +public class SipAudioCall extends SipSessionAdapter { + private static final String TAG = SipAudioCall.class.getSimpleName(); + private static final boolean RELEASE_SOCKET = true; + private static final boolean DONT_RELEASE_SOCKET = false; + private static final int SESSION_TIMEOUT = 5; // in seconds + /** Listener class for all event callbacks. */ - public interface Listener { + public static class Listener { /** * Called when the call object is ready to make another call. + * The default implementation calls {@link #onChange}. * * @param call the call object that is ready to make another call */ - void onReadyToCall(SipAudioCall call); + public void onReadyToCall(SipAudioCall call) { + onChanged(call); + } /** * Called when a request is sent out to initiate a new call. + * The default implementation calls {@link #onChange}. * * @param call the call object that carries out the audio call */ - void onCalling(SipAudioCall call); + public void onCalling(SipAudioCall call) { + onChanged(call); + } /** * Called when a new call comes in. + * The default implementation calls {@link #onChange}. * * @param call the call object that carries out the audio call * @param caller the SIP profile of the caller */ - void onRinging(SipAudioCall call, SipProfile caller); + public void onRinging(SipAudioCall call, SipProfile caller) { + onChanged(call); + } /** - * Called when a RINGING response is received for the INVITE request sent + * Called when a RINGING response is received for the INVITE request + * sent. The default implementation calls {@link #onChange}. * * @param call the call object that carries out the audio call */ - void onRingingBack(SipAudioCall call); + public void onRingingBack(SipAudioCall call) { + onChanged(call); + } /** * Called when the session is established. + * The default implementation calls {@link #onChange}. * * @param call the call object that carries out the audio call */ - void onCallEstablished(SipAudioCall call); + public void onCallEstablished(SipAudioCall call) { + onChanged(call); + } /** * Called when the session is terminated. + * The default implementation calls {@link #onChange}. * * @param call the call object that carries out the audio call */ - void onCallEnded(SipAudioCall call); + public void onCallEnded(SipAudioCall call) { + onChanged(call); + } /** * Called when the peer is busy during session initialization. + * The default implementation calls {@link #onChange}. * * @param call the call object that carries out the audio call */ - void onCallBusy(SipAudioCall call); + public void onCallBusy(SipAudioCall call) { + onChanged(call); + } /** * Called when the call is on hold. + * The default implementation calls {@link #onChange}. * * @param call the call object that carries out the audio call */ - void onCallHeld(SipAudioCall call); + public void onCallHeld(SipAudioCall call) { + onChanged(call); + } /** - * Called when an error occurs. + * Called when an error occurs. The default implementation is no op. * * @param call the call object that carries out the audio call * @param errorCode error code of this error * @param errorMessage error message * @see SipErrorCode */ - void onError(SipAudioCall call, int errorCode, String errorMessage); + public void onError(SipAudioCall call, int errorCode, + String errorMessage) { + // no-op + } + + /** + * Called when an event occurs and the corresponding callback is not + * overridden. The default implementation is no op. Error events are + * not re-directed to this callback and are handled in {@link #onError}. + */ + public void onChanged(SipAudioCall call) { + // no-op + } } + private Context mContext; + private SipProfile mLocalProfile; + private SipAudioCall.Listener mListener; + private SipSession mSipSession; + + private long mSessionId = System.currentTimeMillis(); + private String mPeerSd; + + private AudioStream mAudioStream; + private AudioGroup mAudioGroup; + + private boolean mInCall = false; + private boolean mMuted = false; + private boolean mHold = false; + + private boolean mRingbackToneEnabled = true; + private boolean mRingtoneEnabled = true; + private Ringtone mRingtone; + private ToneGenerator mRingbackTone; + + private SipProfile mPendingCallRequest; + private WifiManager mWm; + private WifiManager.WifiLock mWifiHighPerfLock; + + private int mErrorCode = SipErrorCode.NO_ERROR; + private String mErrorMessage; + /** - * The adapter class for {@link Listener}. The default implementation of - * all callback methods is no-op. + * Creates a call object with the local SIP profile. + * @param context the context for accessing system services such as + * ringtone, audio, WIFI etc */ - public class Adapter implements Listener { - protected void onChanged(SipAudioCall call) { - } - public void onReadyToCall(SipAudioCall call) { - onChanged(call); - } - public void onCalling(SipAudioCall call) { - onChanged(call); - } - public void onRinging(SipAudioCall call, SipProfile caller) { - onChanged(call); - } - public void onRingingBack(SipAudioCall call) { - onChanged(call); - } - public void onCallEstablished(SipAudioCall call) { - onChanged(call); - } - public void onCallEnded(SipAudioCall call) { - onChanged(call); - } - public void onCallBusy(SipAudioCall call) { - onChanged(call); - } - public void onCallHeld(SipAudioCall call) { - onChanged(call); - } - public void onError(SipAudioCall call, int errorCode, - String errorMessage) { - onChanged(call); - } + public SipAudioCall(Context context, SipProfile localProfile) { + mContext = context; + mLocalProfile = localProfile; + mWm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); } /** @@ -139,7 +203,9 @@ public interface SipAudioCall { * @param listener to listen to the audio call events of this object * @see #setListener(Listener, boolean) */ - void setListener(Listener listener); + public void setListener(SipAudioCall.Listener listener) { + setListener(listener, false); + } /** * Sets the listener to listen to the audio call events. A @@ -150,44 +216,355 @@ public interface SipAudioCall { * @param callbackImmediately set to true if the caller wants to be called * back immediately on the current state */ - void setListener(Listener listener, boolean callbackImmediately); + public void setListener(SipAudioCall.Listener listener, + boolean callbackImmediately) { + mListener = listener; + try { + if ((listener == null) || !callbackImmediately) { + // do nothing + } else if (mErrorCode != SipErrorCode.NO_ERROR) { + listener.onError(this, mErrorCode, mErrorMessage); + } else if (mInCall) { + if (mHold) { + listener.onCallHeld(this); + } else { + listener.onCallEstablished(this); + } + } else { + int state = getState(); + switch (state) { + case SipSession.State.READY_TO_CALL: + listener.onReadyToCall(this); + break; + case SipSession.State.INCOMING_CALL: + listener.onRinging(this, getPeerProfile()); + break; + case SipSession.State.OUTGOING_CALL: + listener.onCalling(this); + break; + case SipSession.State.OUTGOING_CALL_RING_BACK: + listener.onRingingBack(this); + break; + } + } + } catch (Throwable t) { + Log.e(TAG, "setListener()", t); + } + } + + /** + * Checks if the call is established. + * + * @return true if the call is established + */ + public synchronized boolean isInCall() { + return mInCall; + } + + /** + * Checks if the call is on hold. + * + * @return true if the call is on hold + */ + public synchronized boolean isOnHold() { + return mHold; + } /** * Closes this object. This object is not usable after being closed. */ - void close(); + public void close() { + close(true); + } + + private synchronized void close(boolean closeRtp) { + if (closeRtp) stopCall(RELEASE_SOCKET); + stopRingbackTone(); + stopRinging(); + + mInCall = false; + mHold = false; + mSessionId = System.currentTimeMillis(); + mErrorCode = SipErrorCode.NO_ERROR; + mErrorMessage = null; + + if (mSipSession != null) { + mSipSession.setListener(null); + mSipSession = null; + } + } /** - * Initiates an audio call to the specified profile. The attempt will be - * timed out if the call is not established within {@code timeout} seconds - * and {@code Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)} - * will be called. + * Gets the local SIP profile. * - * @param callee the SIP profile to make the call to - * @param sipManager the {@link SipManager} object to help make call with - * @param timeout the timeout value in seconds - * @see Listener.onError + * @return the local SIP profile */ - void makeCall(SipProfile callee, SipManager sipManager, int timeout) - throws SipException; + public synchronized SipProfile getLocalProfile() { + return mLocalProfile; + } /** - * Starts the audio for the established call. This method should be called - * after {@link Listener#onCallEstablished} is called. + * Gets the peer's SIP profile. + * + * @return the peer's SIP profile */ - void startAudio(); + public synchronized SipProfile getPeerProfile() { + return (mSipSession == null) ? null : mSipSession.getPeerProfile(); + } + + /** + * Gets the state of the {@link SipSession} that carries this call. + * The value returned must be one of the states in {@link SipSession.State}. + * + * @return the session state + */ + public synchronized int getState() { + if (mSipSession == null) return SipSession.State.READY_TO_CALL; + return mSipSession.getState(); + } + + + /** + * Gets the {@link SipSession} that carries this call. + * + * @return the session object that carries this call + * @hide + */ + public synchronized SipSession getSipSession() { + return mSipSession; + } + + private SipSession.Listener createListener() { + return new SipSession.Listener() { + @Override + public void onCalling(SipSession session) { + Log.d(TAG, "calling... " + session); + Listener listener = mListener; + if (listener != null) { + try { + listener.onCalling(SipAudioCall.this); + } catch (Throwable t) { + Log.i(TAG, "onCalling(): " + t); + } + } + } + + @Override + public void onRingingBack(SipSession session) { + Log.d(TAG, "sip call ringing back: " + session); + if (!mInCall) startRingbackTone(); + Listener listener = mListener; + if (listener != null) { + try { + listener.onRingingBack(SipAudioCall.this); + } catch (Throwable t) { + Log.i(TAG, "onRingingBack(): " + t); + } + } + } + + @Override + public synchronized void onRinging(SipSession session, + SipProfile peerProfile, String sessionDescription) { + if ((mSipSession == null) || !mInCall + || !session.getCallId().equals(mSipSession.getCallId())) { + // should not happen + session.endCall(); + return; + } + + // session changing request + try { + String answer = createAnswer(sessionDescription).encode(); + mSipSession.answerCall(answer, SESSION_TIMEOUT); + } catch (Throwable e) { + Log.e(TAG, "onRinging()", e); + session.endCall(); + } + } + + @Override + public void onCallEstablished(SipSession session, + String sessionDescription) { + stopRingbackTone(); + stopRinging(); + mPeerSd = sessionDescription; + Log.v(TAG, "onCallEstablished()" + mPeerSd); + + Listener listener = mListener; + if (listener != null) { + try { + if (mHold) { + listener.onCallHeld(SipAudioCall.this); + } else { + listener.onCallEstablished(SipAudioCall.this); + } + } catch (Throwable t) { + Log.i(TAG, "onCallEstablished(): " + t); + } + } + } + + @Override + public void onCallEnded(SipSession session) { + Log.d(TAG, "sip call ended: " + session); + Listener listener = mListener; + if (listener != null) { + try { + listener.onCallEnded(SipAudioCall.this); + } catch (Throwable t) { + Log.i(TAG, "onCallEnded(): " + t); + } + } + close(); + } + + @Override + public void onCallBusy(SipSession session) { + Log.d(TAG, "sip call busy: " + session); + Listener listener = mListener; + if (listener != null) { + try { + listener.onCallBusy(SipAudioCall.this); + } catch (Throwable t) { + Log.i(TAG, "onCallBusy(): " + t); + } + } + close(false); + } + + @Override + public void onCallChangeFailed(SipSession session, int errorCode, + String message) { + Log.d(TAG, "sip call change failed: " + message); + mErrorCode = errorCode; + mErrorMessage = message; + Listener listener = mListener; + if (listener != null) { + try { + listener.onError(SipAudioCall.this, mErrorCode, + message); + } catch (Throwable t) { + Log.i(TAG, "onCallBusy(): " + t); + } + } + } + + @Override + public void onError(SipSession session, int errorCode, + String message) { + SipAudioCall.this.onError(errorCode, message); + } + + @Override + public void onRegistering(SipSession session) { + // irrelevant + } + + @Override + public void onRegistrationTimeout(SipSession session) { + // irrelevant + } + + @Override + public void onRegistrationFailed(SipSession session, int errorCode, + String message) { + // irrelevant + } + + @Override + public void onRegistrationDone(SipSession session, int duration) { + // irrelevant + } + }; + } + + private void onError(int errorCode, String message) { + Log.d(TAG, "sip session error: " + + SipErrorCode.toString(errorCode) + ": " + message); + mErrorCode = errorCode; + mErrorMessage = message; + Listener listener = mListener; + if (listener != null) { + try { + listener.onError(this, errorCode, message); + } catch (Throwable t) { + Log.i(TAG, "onError(): " + t); + } + } + synchronized (this) { + if ((errorCode == SipErrorCode.DATA_CONNECTION_LOST) + || !isInCall()) { + close(true); + } + } + } /** * Attaches an incoming call to this call object. * * @param session the session that receives the incoming call * @param sessionDescription the session description of the incoming call + * @throws SipException if the SIP service fails to attach this object to + * the session + */ + public synchronized void attachCall(SipSession session, + String sessionDescription) throws SipException { + mSipSession = session; + mPeerSd = sessionDescription; + Log.v(TAG, "attachCall()" + mPeerSd); + try { + session.setListener(createListener()); + + if (getState() == SipSession.State.INCOMING_CALL) startRinging(); + } catch (Throwable e) { + Log.e(TAG, "attachCall()", e); + throwSipException(e); + } + } + + /** + * Initiates an audio call to the specified profile. The attempt will be + * timed out if the call is not established within {@code timeout} seconds + * and {@code Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)} + * will be called. + * + * @param callee the SIP profile to make the call to + * @param sipManager the {@link SipManager} object to help make call with + * @param timeout the timeout value in seconds. Default value (defined by + * SIP protocol) is used if {@code timeout} is zero or negative. + * @see Listener.onError + * @throws SipException if the SIP service fails to create a session for the + * call */ - void attachCall(ISipSession session, String sessionDescription) - throws SipException; + public synchronized void makeCall(SipProfile peerProfile, + SipManager sipManager, int timeout) throws SipException { + SipSession s = mSipSession = sipManager.createSipSession( + mLocalProfile, createListener()); + if (s == null) { + throw new SipException( + "Failed to create SipSession; network available?"); + } + try { + mAudioStream = new AudioStream(InetAddress.getByName(getLocalIp())); + s.makeCall(peerProfile, createOffer().encode(), timeout); + } catch (IOException e) { + throw new SipException("makeCall()", e); + } + } - /** Ends a call. */ - void endCall() throws SipException; + /** + * Ends a call. + * @throws SipException if the SIP service fails to end the call + */ + public synchronized void endCall() throws SipException { + stopRinging(); + stopCall(RELEASE_SOCKET); + mInCall = false; + + // perform the above local ops first and then network op + if (mSipSession != null) mSipSession.endCall(); + } /** * Puts a call on hold. When succeeds, {@link Listener#onCallHeld} is @@ -196,10 +573,19 @@ public interface SipAudioCall { * {@code Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)} * will be called. * - * @param timeout the timeout value in seconds + * @param timeout the timeout value in seconds. Default value (defined by + * SIP protocol) is used if {@code timeout} is zero or negative. * @see Listener.onError + * @throws SipException if the SIP service fails to hold the call */ - void holdCall(int timeout) throws SipException; + public synchronized void holdCall(int timeout) throws SipException { + if (mHold) return; + mSipSession.changeCall(createHoldOffer().encode(), timeout); + mHold = true; + + AudioGroup audioGroup = getAudioGroup(); + if (audioGroup != null) audioGroup.setMode(AudioGroup.MODE_ON_HOLD); + } /** * Answers a call. The attempt will be timed out if the call is not @@ -207,10 +593,20 @@ public interface SipAudioCall { * {@code Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)} * will be called. * - * @param timeout the timeout value in seconds + * @param timeout the timeout value in seconds. Default value (defined by + * SIP protocol) is used if {@code timeout} is zero or negative. * @see Listener.onError + * @throws SipException if the SIP service fails to answer the call */ - void answerCall(int timeout) throws SipException; + public synchronized void answerCall(int timeout) throws SipException { + stopRinging(); + try { + mAudioStream = new AudioStream(InetAddress.getByName(getLocalIp())); + mSipSession.answerCall(createAnswer(mPeerSd).encode(), timeout); + } catch (IOException e) { + throw new SipException("answerCall()", e); + } + } /** * Continues a call that's on hold. When succeeds, @@ -219,45 +615,189 @@ public interface SipAudioCall { * {@code Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)} * will be called. * - * @param timeout the timeout value in seconds + * @param timeout the timeout value in seconds. Default value (defined by + * SIP protocol) is used if {@code timeout} is zero or negative. * @see Listener.onError + * @throws SipException if the SIP service fails to unhold the call */ - void continueCall(int timeout) throws SipException; + public synchronized void continueCall(int timeout) throws SipException { + if (!mHold) return; + mSipSession.changeCall(createContinueOffer().encode(), timeout); + mHold = false; + AudioGroup audioGroup = getAudioGroup(); + if (audioGroup != null) audioGroup.setMode(AudioGroup.MODE_NORMAL); + } - /** Puts the device to speaker mode. */ - void setSpeakerMode(boolean speakerMode); + private SimpleSessionDescription createOffer() { + SimpleSessionDescription offer = + new SimpleSessionDescription(mSessionId, getLocalIp()); + AudioCodec[] codecs = AudioCodec.getCodecs(); + Media media = offer.newMedia( + "audio", mAudioStream.getLocalPort(), 1, "RTP/AVP"); + for (AudioCodec codec : AudioCodec.getCodecs()) { + media.setRtpPayload(codec.type, codec.rtpmap, codec.fmtp); + } + media.setRtpPayload(127, "telephone-event/8000", "0-15"); + return offer; + } - /** Toggles mute. */ - void toggleMute(); + private SimpleSessionDescription createAnswer(String offerSd) { + SimpleSessionDescription offer = + new SimpleSessionDescription(offerSd); + SimpleSessionDescription answer = + new SimpleSessionDescription(mSessionId, getLocalIp()); + AudioCodec codec = null; + for (Media media : offer.getMedia()) { + if ((codec == null) && (media.getPort() > 0) + && "audio".equals(media.getType()) + && "RTP/AVP".equals(media.getProtocol())) { + // Find the first audio codec we supported. + for (int type : media.getRtpPayloadTypes()) { + codec = AudioCodec.getCodec(type, media.getRtpmap(type), + media.getFmtp(type)); + if (codec != null) { + break; + } + } + if (codec != null) { + Media reply = answer.newMedia( + "audio", mAudioStream.getLocalPort(), 1, "RTP/AVP"); + reply.setRtpPayload(codec.type, codec.rtpmap, codec.fmtp); - /** - * Checks if the call is on hold. - * - * @return true if the call is on hold - */ - boolean isOnHold(); + // Check if DTMF is supported in the same media. + for (int type : media.getRtpPayloadTypes()) { + String rtpmap = media.getRtpmap(type); + if ((type != codec.type) && (rtpmap != null) + && rtpmap.startsWith("telephone-event")) { + reply.setRtpPayload( + type, rtpmap, media.getFmtp(type)); + } + } + + // Handle recvonly and sendonly. + if (media.getAttribute("recvonly") != null) { + answer.setAttribute("sendonly", ""); + } else if(media.getAttribute("sendonly") != null) { + answer.setAttribute("recvonly", ""); + } else if(offer.getAttribute("recvonly") != null) { + answer.setAttribute("sendonly", ""); + } else if(offer.getAttribute("sendonly") != null) { + answer.setAttribute("recvonly", ""); + } + continue; + } + } + // Reject the media. + Media reply = answer.newMedia( + media.getType(), 0, 1, media.getProtocol()); + for (String format : media.getFormats()) { + reply.setFormat(format, null); + } + } + if (codec == null) { + throw new IllegalStateException("Reject SDP: no suitable codecs"); + } + return answer; + } + + private SimpleSessionDescription createHoldOffer() { + SimpleSessionDescription offer = createContinueOffer(); + offer.setAttribute("sendonly", ""); + return offer; + } + + private SimpleSessionDescription createContinueOffer() { + SimpleSessionDescription offer = + new SimpleSessionDescription(mSessionId, getLocalIp()); + Media media = offer.newMedia( + "audio", mAudioStream.getLocalPort(), 1, "RTP/AVP"); + AudioCodec codec = mAudioStream.getCodec(); + media.setRtpPayload(codec.type, codec.rtpmap, codec.fmtp); + int dtmfType = mAudioStream.getDtmfType(); + if (dtmfType != -1) { + media.setRtpPayload(dtmfType, "telephone-event/8000", "0-15"); + } + return offer; + } + + private void grabWifiHighPerfLock() { + if (mWifiHighPerfLock == null) { + Log.v(TAG, "acquire wifi high perf lock"); + mWifiHighPerfLock = ((WifiManager) + mContext.getSystemService(Context.WIFI_SERVICE)) + .createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, TAG); + mWifiHighPerfLock.acquire(); + } + } + + private void releaseWifiHighPerfLock() { + if (mWifiHighPerfLock != null) { + Log.v(TAG, "release wifi high perf lock"); + mWifiHighPerfLock.release(); + mWifiHighPerfLock = null; + } + } + + private boolean isWifiOn() { + return (mWm.getConnectionInfo().getBSSID() == null) ? false : true; + } + + /** Toggles mute. */ + public synchronized void toggleMute() { + AudioGroup audioGroup = getAudioGroup(); + if (audioGroup != null) { + audioGroup.setMode( + mMuted ? AudioGroup.MODE_NORMAL : AudioGroup.MODE_MUTED); + mMuted = !mMuted; + } + } /** * Checks if the call is muted. * * @return true if the call is muted */ - boolean isMuted(); + public synchronized boolean isMuted() { + return mMuted; + } + + /** Puts the device to speaker mode. */ + public synchronized void setSpeakerMode(boolean speakerMode) { + ((AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE)) + .setSpeakerphoneOn(speakerMode); + } /** - * Sends a DTMF code. + * Sends a DTMF code. According to RFC2833, event 0--9 maps to decimal + * value 0--9, '*' to 10, '#' to 11, event 'A'--'D' to 12--15, and event + * flash to 16. Currently, event flash is not supported. * - * @param code the DTMF code to send + * @param code the DTMF code to send. Value 0 to 15 (inclusive) are valid + * inputs. + * @see http://tools.ietf.org/html/rfc2833 */ - void sendDtmf(int code); + public void sendDtmf(int code) { + sendDtmf(code, null); + } /** - * Sends a DTMF code. + * Sends a DTMF code. According to RFC2833, event 0--9 maps to decimal + * value 0--9, '*' to 10, '#' to 11, event 'A'--'D' to 12--15, and event + * flash to 16. Currently, event flash is not supported. * - * @param code the DTMF code to send + * @param code the DTMF code to send. Value 0 to 15 (inclusive) are valid + * inputs. * @param result the result message to send when done */ - void sendDtmf(int code, Message result); + public synchronized void sendDtmf(int code, Message result) { + AudioGroup audioGroup = getAudioGroup(); + if ((audioGroup != null) && (mSipSession != null) + && (SipSession.State.IN_CALL == getState())) { + Log.v(TAG, "send DTMF: " + code); + audioGroup.sendDtmf(code); + } + if (result != null) result.sendToTarget(); + } /** * Gets the {@link AudioStream} object used in this call. The object @@ -268,8 +808,11 @@ public interface SipAudioCall { * * @return the {@link AudioStream} object or null if the RTP stream has not * yet been set up + * @hide */ - AudioStream getAudioStream(); + public synchronized AudioStream getAudioStream() { + return mAudioStream; + } /** * Gets the {@link AudioGroup} object which the {@link AudioStream} object @@ -283,8 +826,12 @@ public interface SipAudioCall { * @return the {@link AudioGroup} object or null if the RTP stream has not * yet been set up * @see #getAudioStream + * @hide */ - AudioGroup getAudioGroup(); + public synchronized AudioGroup getAudioGroup() { + if (mAudioGroup != null) return mAudioGroup; + return ((mAudioStream == null) ? null : mAudioStream.getGroup()); + } /** * Sets the {@link AudioGroup} object which the {@link AudioStream} object @@ -292,56 +839,214 @@ public interface SipAudioCall { * will be dynamically created when needed. * * @see #getAudioStream + * @hide */ - void setAudioGroup(AudioGroup audioGroup); + public synchronized void setAudioGroup(AudioGroup group) { + if ((mAudioStream != null) && (mAudioStream.getGroup() != null)) { + mAudioStream.join(group); + } + mAudioGroup = group; + } /** - * Checks if the call is established. - * - * @return true if the call is established + * Starts the audio for the established call. This method should be called + * after {@link Listener#onCallEstablished} is called. */ - boolean isInCall(); + public void startAudio() { + try { + startAudioInternal(); + } catch (UnknownHostException e) { + onError(SipErrorCode.PEER_NOT_REACHABLE, e.getMessage()); + } catch (Throwable e) { + onError(SipErrorCode.CLIENT_ERROR, e.getMessage()); + } + } - /** - * Gets the local SIP profile. - * - * @return the local SIP profile - */ - SipProfile getLocalProfile(); + private synchronized void startAudioInternal() throws UnknownHostException { + if (mPeerSd == null) { + Log.v(TAG, "startAudioInternal() mPeerSd = null"); + throw new IllegalStateException("mPeerSd = null"); + } - /** - * Gets the peer's SIP profile. - * - * @return the peer's SIP profile - */ - SipProfile getPeerProfile(); + stopCall(DONT_RELEASE_SOCKET); + mInCall = true; - /** - * Gets the state of the {@link ISipSession} that carries this call. - * The value returned must be one of the states in {@link SipSessionState}. - * - * @return the session state - */ - int getState(); + // Run exact the same logic in createAnswer() to setup mAudioStream. + SimpleSessionDescription offer = + new SimpleSessionDescription(mPeerSd); + AudioStream stream = mAudioStream; + AudioCodec codec = null; + for (Media media : offer.getMedia()) { + if ((codec == null) && (media.getPort() > 0) + && "audio".equals(media.getType()) + && "RTP/AVP".equals(media.getProtocol())) { + // Find the first audio codec we supported. + for (int type : media.getRtpPayloadTypes()) { + codec = AudioCodec.getCodec( + type, media.getRtpmap(type), media.getFmtp(type)); + if (codec != null) { + break; + } + } + + if (codec != null) { + // Associate with the remote host. + String address = media.getAddress(); + if (address == null) { + address = offer.getAddress(); + } + stream.associate(InetAddress.getByName(address), + media.getPort()); + + stream.setDtmfType(-1); + stream.setCodec(codec); + // Check if DTMF is supported in the same media. + for (int type : media.getRtpPayloadTypes()) { + String rtpmap = media.getRtpmap(type); + if ((type != codec.type) && (rtpmap != null) + && rtpmap.startsWith("telephone-event")) { + stream.setDtmfType(type); + } + } + + // Handle recvonly and sendonly. + if (mHold) { + stream.setMode(RtpStream.MODE_NORMAL); + } else if (media.getAttribute("recvonly") != null) { + stream.setMode(RtpStream.MODE_SEND_ONLY); + } else if(media.getAttribute("sendonly") != null) { + stream.setMode(RtpStream.MODE_RECEIVE_ONLY); + } else if(offer.getAttribute("recvonly") != null) { + stream.setMode(RtpStream.MODE_SEND_ONLY); + } else if(offer.getAttribute("sendonly") != null) { + stream.setMode(RtpStream.MODE_RECEIVE_ONLY); + } else { + stream.setMode(RtpStream.MODE_NORMAL); + } + break; + } + } + } + if (codec == null) { + throw new IllegalStateException("Reject SDP: no suitable codecs"); + } + + if (isWifiOn()) grabWifiHighPerfLock(); + + if (!mHold) { + /* The recorder volume will be very low if the device is in + * IN_CALL mode. Therefore, we have to set the mode to NORMAL + * in order to have the normal microphone level. + */ + ((AudioManager) mContext.getSystemService + (Context.AUDIO_SERVICE)) + .setMode(AudioManager.MODE_NORMAL); + } + + // AudioGroup logic: + AudioGroup audioGroup = getAudioGroup(); + if (mHold) { + if (audioGroup != null) { + audioGroup.setMode(AudioGroup.MODE_ON_HOLD); + } + // don't create an AudioGroup here; doing so will fail if + // there's another AudioGroup out there that's active + } else { + if (audioGroup == null) audioGroup = new AudioGroup(); + stream.join(audioGroup); + if (mMuted) { + audioGroup.setMode(AudioGroup.MODE_MUTED); + } else { + audioGroup.setMode(AudioGroup.MODE_NORMAL); + } + } + } + + private void stopCall(boolean releaseSocket) { + Log.d(TAG, "stop audiocall"); + releaseWifiHighPerfLock(); + if (mAudioStream != null) { + mAudioStream.join(null); + + if (releaseSocket) { + mAudioStream.release(); + mAudioStream = null; + } + } + } + + private String getLocalIp() { + return mSipSession.getLocalIp(); + } - /** - * Gets the {@link ISipSession} that carries this call. - * - * @return the session object that carries this call - */ - ISipSession getSipSession(); /** * Enables/disables the ring-back tone. * * @param enabled true to enable; false to disable */ - void setRingbackToneEnabled(boolean enabled); + public synchronized void setRingbackToneEnabled(boolean enabled) { + mRingbackToneEnabled = enabled; + } /** * Enables/disables the ring tone. * * @param enabled true to enable; false to disable */ - void setRingtoneEnabled(boolean enabled); + public synchronized void setRingtoneEnabled(boolean enabled) { + mRingtoneEnabled = enabled; + } + + private void startRingbackTone() { + if (!mRingbackToneEnabled) return; + if (mRingbackTone == null) { + // The volume relative to other sounds in the stream + int toneVolume = 80; + mRingbackTone = new ToneGenerator( + AudioManager.STREAM_VOICE_CALL, toneVolume); + } + mRingbackTone.startTone(ToneGenerator.TONE_CDMA_LOW_PBX_L); + } + + private void stopRingbackTone() { + if (mRingbackTone != null) { + mRingbackTone.stopTone(); + mRingbackTone.release(); + mRingbackTone = null; + } + } + + private void startRinging() { + if (!mRingtoneEnabled) return; + ((Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE)) + .vibrate(new long[] {0, 1000, 1000}, 1); + AudioManager am = (AudioManager) + mContext.getSystemService(Context.AUDIO_SERVICE); + if (am.getStreamVolume(AudioManager.STREAM_RING) > 0) { + String ringtoneUri = + Settings.System.DEFAULT_RINGTONE_URI.toString(); + mRingtone = RingtoneManager.getRingtone(mContext, + Uri.parse(ringtoneUri)); + mRingtone.play(); + } + } + + private void stopRinging() { + ((Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE)) + .cancel(); + if (mRingtone != null) mRingtone.stop(); + } + + private void throwSipException(Throwable throwable) throws SipException { + if (throwable instanceof SipException) { + throw (SipException) throwable; + } else { + throw new SipException("", throwable); + } + } + + private SipProfile getPeerProfile(SipSession session) { + return session.getPeerProfile(); + } } diff --git a/voip/java/android/net/sip/SipAudioCallImpl.java b/voip/java/android/net/sip/SipAudioCallImpl.java deleted file mode 100644 index 2f8d175..0000000 --- a/voip/java/android/net/sip/SipAudioCallImpl.java +++ /dev/null @@ -1,766 +0,0 @@ -/* - * 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.sip; - -import android.content.Context; -import android.media.AudioManager; -import android.media.Ringtone; -import android.media.RingtoneManager; -import android.media.ToneGenerator; -import android.net.Uri; -import android.net.rtp.AudioCodec; -import android.net.rtp.AudioGroup; -import android.net.rtp.AudioStream; -import android.net.rtp.RtpStream; -import android.net.sip.SimpleSessionDescription.Media; -import android.net.wifi.WifiManager; -import android.os.Message; -import android.os.RemoteException; -import android.os.Vibrator; -import android.provider.Settings; -import android.util.Log; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Class that handles an audio call over SIP. - */ -/** @hide */ -public class SipAudioCallImpl extends SipSessionAdapter - implements SipAudioCall { - private static final String TAG = SipAudioCallImpl.class.getSimpleName(); - private static final boolean RELEASE_SOCKET = true; - private static final boolean DONT_RELEASE_SOCKET = false; - private static final int SESSION_TIMEOUT = 5; // in seconds - - private Context mContext; - private SipProfile mLocalProfile; - private SipAudioCall.Listener mListener; - private ISipSession mSipSession; - - private long mSessionId = System.currentTimeMillis(); - private String mPeerSd; - - private AudioStream mAudioStream; - private AudioGroup mAudioGroup; - - private boolean mInCall = false; - private boolean mMuted = false; - private boolean mHold = false; - - private boolean mRingbackToneEnabled = true; - private boolean mRingtoneEnabled = true; - private Ringtone mRingtone; - private ToneGenerator mRingbackTone; - - private SipProfile mPendingCallRequest; - private WifiManager mWm; - private WifiManager.WifiLock mWifiHighPerfLock; - - private int mErrorCode = SipErrorCode.NO_ERROR; - private String mErrorMessage; - - public SipAudioCallImpl(Context context, SipProfile localProfile) { - mContext = context; - mLocalProfile = localProfile; - mWm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); - } - - public void setListener(SipAudioCall.Listener listener) { - setListener(listener, false); - } - - public void setListener(SipAudioCall.Listener listener, - boolean callbackImmediately) { - mListener = listener; - try { - if ((listener == null) || !callbackImmediately) { - // do nothing - } else if (mErrorCode != SipErrorCode.NO_ERROR) { - listener.onError(this, mErrorCode, mErrorMessage); - } else if (mInCall) { - if (mHold) { - listener.onCallHeld(this); - } else { - listener.onCallEstablished(this); - } - } else { - int state = getState(); - switch (state) { - case SipSessionState.READY_TO_CALL: - listener.onReadyToCall(this); - break; - case SipSessionState.INCOMING_CALL: - listener.onRinging(this, getPeerProfile(mSipSession)); - break; - case SipSessionState.OUTGOING_CALL: - listener.onCalling(this); - break; - case SipSessionState.OUTGOING_CALL_RING_BACK: - listener.onRingingBack(this); - break; - } - } - } catch (Throwable t) { - Log.e(TAG, "setListener()", t); - } - } - - public synchronized boolean isInCall() { - return mInCall; - } - - public synchronized boolean isOnHold() { - return mHold; - } - - public void close() { - close(true); - } - - private synchronized void close(boolean closeRtp) { - if (closeRtp) stopCall(RELEASE_SOCKET); - stopRingbackTone(); - stopRinging(); - - mInCall = false; - mHold = false; - mSessionId = System.currentTimeMillis(); - mErrorCode = SipErrorCode.NO_ERROR; - mErrorMessage = null; - - if (mSipSession != null) { - try { - mSipSession.setListener(null); - } catch (RemoteException e) { - // don't care - } - mSipSession = null; - } - } - - public synchronized SipProfile getLocalProfile() { - return mLocalProfile; - } - - public synchronized SipProfile getPeerProfile() { - try { - return (mSipSession == null) ? null : mSipSession.getPeerProfile(); - } catch (RemoteException e) { - return null; - } - } - - public synchronized int getState() { - if (mSipSession == null) return SipSessionState.READY_TO_CALL; - try { - return mSipSession.getState(); - } catch (RemoteException e) { - return SipSessionState.REMOTE_ERROR; - } - } - - - public synchronized ISipSession getSipSession() { - return mSipSession; - } - - @Override - public void onCalling(ISipSession session) { - Log.d(TAG, "calling... " + session); - Listener listener = mListener; - if (listener != null) { - try { - listener.onCalling(this); - } catch (Throwable t) { - Log.e(TAG, "onCalling()", t); - } - } - } - - @Override - public void onRingingBack(ISipSession session) { - Log.d(TAG, "sip call ringing back: " + session); - if (!mInCall) startRingbackTone(); - Listener listener = mListener; - if (listener != null) { - try { - listener.onRingingBack(this); - } catch (Throwable t) { - Log.e(TAG, "onRingingBack()", t); - } - } - } - - @Override - public synchronized void onRinging(ISipSession session, - SipProfile peerProfile, String sessionDescription) { - try { - if ((mSipSession == null) || !mInCall - || !session.getCallId().equals(mSipSession.getCallId())) { - // should not happen - session.endCall(); - return; - } - - // session changing request - try { - String answer = createAnswer(sessionDescription).encode(); - mSipSession.answerCall(answer, SESSION_TIMEOUT); - } catch (Throwable e) { - Log.e(TAG, "onRinging()", e); - session.endCall(); - } - } catch (RemoteException e) { - Log.e(TAG, "onRinging()", e); - } - } - - @Override - public void onCallEstablished(ISipSession session, - String sessionDescription) { - stopRingbackTone(); - stopRinging(); - mPeerSd = sessionDescription; - Log.v(TAG, "onCallEstablished()" + mPeerSd); - - Listener listener = mListener; - if (listener != null) { - try { - if (mHold) { - listener.onCallHeld(this); - } else { - listener.onCallEstablished(this); - } - } catch (Throwable t) { - Log.e(TAG, "onCallEstablished()", t); - } - } - } - - @Override - public void onCallEnded(ISipSession session) { - Log.d(TAG, "sip call ended: " + session); - Listener listener = mListener; - if (listener != null) { - try { - listener.onCallEnded(this); - } catch (Throwable t) { - Log.e(TAG, "onCallEnded()", t); - } - } - close(); - } - - @Override - public void onCallBusy(ISipSession session) { - Log.d(TAG, "sip call busy: " + session); - Listener listener = mListener; - if (listener != null) { - try { - listener.onCallBusy(this); - } catch (Throwable t) { - Log.e(TAG, "onCallBusy()", t); - } - } - close(false); - } - - @Override - public void onCallChangeFailed(ISipSession session, int errorCode, - String message) { - Log.d(TAG, "sip call change failed: " + message); - mErrorCode = errorCode; - mErrorMessage = message; - Listener listener = mListener; - if (listener != null) { - try { - listener.onError(this, mErrorCode, message); - } catch (Throwable t) { - Log.e(TAG, "onCallBusy()", t); - } - } - } - - @Override - public void onError(ISipSession session, int errorCode, String message) { - Log.d(TAG, "sip session error: " + SipErrorCode.toString(errorCode) - + ": " + message); - mErrorCode = errorCode; - mErrorMessage = message; - Listener listener = mListener; - if (listener != null) { - try { - listener.onError(this, errorCode, message); - } catch (Throwable t) { - Log.e(TAG, "onError()", t); - } - } - synchronized (this) { - if ((errorCode == SipErrorCode.DATA_CONNECTION_LOST) - || !isInCall()) { - close(true); - } - } - } - - public synchronized void attachCall(ISipSession session, - String sessionDescription) throws SipException { - mSipSession = session; - mPeerSd = sessionDescription; - Log.v(TAG, "attachCall()" + mPeerSd); - try { - session.setListener(this); - if (getState() == SipSessionState.INCOMING_CALL) startRinging(); - } catch (Throwable e) { - Log.e(TAG, "attachCall()", e); - throwSipException(e); - } - } - - public synchronized void makeCall(SipProfile peerProfile, - SipManager sipManager, int timeout) throws SipException { - try { - mSipSession = sipManager.createSipSession(mLocalProfile, this); - if (mSipSession == null) { - throw new SipException( - "Failed to create SipSession; network available?"); - } - mAudioStream = new AudioStream(InetAddress.getByName(getLocalIp())); - mSipSession.makeCall(peerProfile, createOffer().encode(), timeout); - } catch (Throwable e) { - if (e instanceof SipException) { - throw (SipException) e; - } else { - throwSipException(e); - } - } - } - - public synchronized void endCall() throws SipException { - try { - stopRinging(); - stopCall(RELEASE_SOCKET); - mInCall = false; - - // perform the above local ops first and then network op - if (mSipSession != null) mSipSession.endCall(); - } catch (Throwable e) { - throwSipException(e); - } - } - - public synchronized void answerCall(int timeout) throws SipException { - try { - stopRinging(); - mAudioStream = new AudioStream(InetAddress.getByName(getLocalIp())); - mSipSession.answerCall(createAnswer(mPeerSd).encode(), timeout); - } catch (Throwable e) { - Log.e(TAG, "answerCall()", e); - throwSipException(e); - } - } - - public synchronized void holdCall(int timeout) throws SipException { - if (mHold) return; - try { - mSipSession.changeCall(createHoldOffer().encode(), timeout); - } catch (Throwable e) { - throwSipException(e); - } - mHold = true; - AudioGroup audioGroup = getAudioGroup(); - if (audioGroup != null) audioGroup.setMode(AudioGroup.MODE_ON_HOLD); - } - - public synchronized void continueCall(int timeout) throws SipException { - if (!mHold) return; - try { - mSipSession.changeCall(createContinueOffer().encode(), timeout); - } catch (Throwable e) { - throwSipException(e); - } - mHold = false; - AudioGroup audioGroup = getAudioGroup(); - if (audioGroup != null) audioGroup.setMode(AudioGroup.MODE_NORMAL); - } - - private SimpleSessionDescription createOffer() { - SimpleSessionDescription offer = - new SimpleSessionDescription(mSessionId, getLocalIp()); - AudioCodec[] codecs = AudioCodec.getCodecs(); - Media media = offer.newMedia( - "audio", mAudioStream.getLocalPort(), 1, "RTP/AVP"); - for (AudioCodec codec : AudioCodec.getCodecs()) { - media.setRtpPayload(codec.type, codec.rtpmap, codec.fmtp); - } - media.setRtpPayload(127, "telephone-event/8000", "0-15"); - return offer; - } - - private SimpleSessionDescription createAnswer(String offerSd) { - SimpleSessionDescription offer = - new SimpleSessionDescription(offerSd); - SimpleSessionDescription answer = - new SimpleSessionDescription(mSessionId, getLocalIp()); - AudioCodec codec = null; - for (Media media : offer.getMedia()) { - if ((codec == null) && (media.getPort() > 0) - && "audio".equals(media.getType()) - && "RTP/AVP".equals(media.getProtocol())) { - // Find the first audio codec we supported. - for (int type : media.getRtpPayloadTypes()) { - codec = AudioCodec.getCodec(type, media.getRtpmap(type), - media.getFmtp(type)); - if (codec != null) { - break; - } - } - if (codec != null) { - Media reply = answer.newMedia( - "audio", mAudioStream.getLocalPort(), 1, "RTP/AVP"); - reply.setRtpPayload(codec.type, codec.rtpmap, codec.fmtp); - - // Check if DTMF is supported in the same media. - for (int type : media.getRtpPayloadTypes()) { - String rtpmap = media.getRtpmap(type); - if ((type != codec.type) && (rtpmap != null) - && rtpmap.startsWith("telephone-event")) { - reply.setRtpPayload( - type, rtpmap, media.getFmtp(type)); - } - } - - // Handle recvonly and sendonly. - if (media.getAttribute("recvonly") != null) { - answer.setAttribute("sendonly", ""); - } else if(media.getAttribute("sendonly") != null) { - answer.setAttribute("recvonly", ""); - } else if(offer.getAttribute("recvonly") != null) { - answer.setAttribute("sendonly", ""); - } else if(offer.getAttribute("sendonly") != null) { - answer.setAttribute("recvonly", ""); - } - continue; - } - } - // Reject the media. - Media reply = answer.newMedia( - media.getType(), 0, 1, media.getProtocol()); - for (String format : media.getFormats()) { - reply.setFormat(format, null); - } - } - if (codec == null) { - throw new IllegalStateException("Reject SDP: no suitable codecs"); - } - return answer; - } - - private SimpleSessionDescription createHoldOffer() { - SimpleSessionDescription offer = createContinueOffer(); - offer.setAttribute("sendonly", ""); - return offer; - } - - private SimpleSessionDescription createContinueOffer() { - SimpleSessionDescription offer = - new SimpleSessionDescription(mSessionId, getLocalIp()); - Media media = offer.newMedia( - "audio", mAudioStream.getLocalPort(), 1, "RTP/AVP"); - AudioCodec codec = mAudioStream.getCodec(); - media.setRtpPayload(codec.type, codec.rtpmap, codec.fmtp); - int dtmfType = mAudioStream.getDtmfType(); - if (dtmfType != -1) { - media.setRtpPayload(dtmfType, "telephone-event/8000", "0-15"); - } - return offer; - } - - private void grabWifiHighPerfLock() { - if (mWifiHighPerfLock == null) { - Log.v(TAG, "acquire wifi high perf lock"); - mWifiHighPerfLock = ((WifiManager) - mContext.getSystemService(Context.WIFI_SERVICE)) - .createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, TAG); - mWifiHighPerfLock.acquire(); - } - } - - private void releaseWifiHighPerfLock() { - if (mWifiHighPerfLock != null) { - Log.v(TAG, "release wifi high perf lock"); - mWifiHighPerfLock.release(); - mWifiHighPerfLock = null; - } - } - - private boolean isWifiOn() { - return (mWm.getConnectionInfo().getBSSID() == null) ? false : true; - } - - public synchronized void toggleMute() { - AudioGroup audioGroup = getAudioGroup(); - if (audioGroup != null) { - audioGroup.setMode( - mMuted ? AudioGroup.MODE_NORMAL : AudioGroup.MODE_MUTED); - mMuted = !mMuted; - } - } - - public synchronized boolean isMuted() { - return mMuted; - } - - public synchronized void setSpeakerMode(boolean speakerMode) { - ((AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE)) - .setSpeakerphoneOn(speakerMode); - } - - public void sendDtmf(int code) { - sendDtmf(code, null); - } - - public synchronized void sendDtmf(int code, Message result) { - AudioGroup audioGroup = getAudioGroup(); - if ((audioGroup != null) && (mSipSession != null) - && (SipSessionState.IN_CALL == getState())) { - Log.v(TAG, "send DTMF: " + code); - audioGroup.sendDtmf(code); - } - if (result != null) result.sendToTarget(); - } - - public synchronized AudioStream getAudioStream() { - return mAudioStream; - } - - public synchronized AudioGroup getAudioGroup() { - if (mAudioGroup != null) return mAudioGroup; - return ((mAudioStream == null) ? null : mAudioStream.getGroup()); - } - - public synchronized void setAudioGroup(AudioGroup group) { - if ((mAudioStream != null) && (mAudioStream.getGroup() != null)) { - mAudioStream.join(group); - } - mAudioGroup = group; - } - - public void startAudio() { - try { - startAudioInternal(); - } catch (UnknownHostException e) { - onError(mSipSession, SipErrorCode.PEER_NOT_REACHABLE, - e.getMessage()); - } catch (Throwable e) { - onError(mSipSession, SipErrorCode.CLIENT_ERROR, - e.getMessage()); - } - } - - private synchronized void startAudioInternal() throws UnknownHostException { - if (mPeerSd == null) { - Log.v(TAG, "startAudioInternal() mPeerSd = null"); - throw new IllegalStateException("mPeerSd = null"); - } - - stopCall(DONT_RELEASE_SOCKET); - mInCall = true; - - // Run exact the same logic in createAnswer() to setup mAudioStream. - SimpleSessionDescription offer = - new SimpleSessionDescription(mPeerSd); - AudioStream stream = mAudioStream; - AudioCodec codec = null; - for (Media media : offer.getMedia()) { - if ((codec == null) && (media.getPort() > 0) - && "audio".equals(media.getType()) - && "RTP/AVP".equals(media.getProtocol())) { - // Find the first audio codec we supported. - for (int type : media.getRtpPayloadTypes()) { - codec = AudioCodec.getCodec( - type, media.getRtpmap(type), media.getFmtp(type)); - if (codec != null) { - break; - } - } - - if (codec != null) { - // Associate with the remote host. - String address = media.getAddress(); - if (address == null) { - address = offer.getAddress(); - } - stream.associate(InetAddress.getByName(address), - media.getPort()); - - stream.setDtmfType(-1); - stream.setCodec(codec); - // Check if DTMF is supported in the same media. - for (int type : media.getRtpPayloadTypes()) { - String rtpmap = media.getRtpmap(type); - if ((type != codec.type) && (rtpmap != null) - && rtpmap.startsWith("telephone-event")) { - stream.setDtmfType(type); - } - } - - // Handle recvonly and sendonly. - if (mHold) { - stream.setMode(RtpStream.MODE_NORMAL); - } else if (media.getAttribute("recvonly") != null) { - stream.setMode(RtpStream.MODE_SEND_ONLY); - } else if(media.getAttribute("sendonly") != null) { - stream.setMode(RtpStream.MODE_RECEIVE_ONLY); - } else if(offer.getAttribute("recvonly") != null) { - stream.setMode(RtpStream.MODE_SEND_ONLY); - } else if(offer.getAttribute("sendonly") != null) { - stream.setMode(RtpStream.MODE_RECEIVE_ONLY); - } else { - stream.setMode(RtpStream.MODE_NORMAL); - } - break; - } - } - } - if (codec == null) { - throw new IllegalStateException("Reject SDP: no suitable codecs"); - } - - if (isWifiOn()) grabWifiHighPerfLock(); - - if (!mHold) { - /* The recorder volume will be very low if the device is in - * IN_CALL mode. Therefore, we have to set the mode to NORMAL - * in order to have the normal microphone level. - */ - ((AudioManager) mContext.getSystemService - (Context.AUDIO_SERVICE)) - .setMode(AudioManager.MODE_NORMAL); - } - - // AudioGroup logic: - AudioGroup audioGroup = getAudioGroup(); - if (mHold) { - if (audioGroup != null) { - audioGroup.setMode(AudioGroup.MODE_ON_HOLD); - } - // don't create an AudioGroup here; doing so will fail if - // there's another AudioGroup out there that's active - } else { - if (audioGroup == null) audioGroup = new AudioGroup(); - mAudioStream.join(audioGroup); - if (mMuted) { - audioGroup.setMode(AudioGroup.MODE_MUTED); - } else { - audioGroup.setMode(AudioGroup.MODE_NORMAL); - } - } - } - - private void stopCall(boolean releaseSocket) { - Log.d(TAG, "stop audiocall"); - releaseWifiHighPerfLock(); - if (mAudioStream != null) { - mAudioStream.join(null); - - if (releaseSocket) { - mAudioStream.release(); - mAudioStream = null; - } - } - } - - private String getLocalIp() { - try { - return mSipSession.getLocalIp(); - } catch (RemoteException e) { - throw new IllegalStateException(e); - } - } - - public synchronized void setRingbackToneEnabled(boolean enabled) { - mRingbackToneEnabled = enabled; - } - - public synchronized void setRingtoneEnabled(boolean enabled) { - mRingtoneEnabled = enabled; - } - - private void startRingbackTone() { - if (!mRingbackToneEnabled) return; - if (mRingbackTone == null) { - // The volume relative to other sounds in the stream - int toneVolume = 80; - mRingbackTone = new ToneGenerator( - AudioManager.STREAM_VOICE_CALL, toneVolume); - } - mRingbackTone.startTone(ToneGenerator.TONE_CDMA_LOW_PBX_L); - } - - private void stopRingbackTone() { - if (mRingbackTone != null) { - mRingbackTone.stopTone(); - mRingbackTone.release(); - mRingbackTone = null; - } - } - - private void startRinging() { - if (!mRingtoneEnabled) return; - ((Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE)) - .vibrate(new long[] {0, 1000, 1000}, 1); - AudioManager am = (AudioManager) - mContext.getSystemService(Context.AUDIO_SERVICE); - if (am.getStreamVolume(AudioManager.STREAM_RING) > 0) { - String ringtoneUri = - Settings.System.DEFAULT_RINGTONE_URI.toString(); - mRingtone = RingtoneManager.getRingtone(mContext, - Uri.parse(ringtoneUri)); - mRingtone.play(); - } - } - - private void stopRinging() { - ((Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE)) - .cancel(); - if (mRingtone != null) mRingtone.stop(); - } - - private void throwSipException(Throwable throwable) throws SipException { - if (throwable instanceof SipException) { - throw (SipException) throwable; - } else { - throw new SipException("", throwable); - } - } - - private SipProfile getPeerProfile(ISipSession session) { - try { - return session.getPeerProfile(); - } catch (RemoteException e) { - return null; - } - } -} diff --git a/voip/java/android/net/sip/SipManager.java b/voip/java/android/net/sip/SipManager.java index 31768d7..5976a04 100644 --- a/voip/java/android/net/sip/SipManager.java +++ b/voip/java/android/net/sip/SipManager.java @@ -30,8 +30,9 @@ import java.text.ParseException; * The class provides API for various SIP related tasks. Specifically, the API * allows an application to: * <ul> - * <li>register a {@link SipProfile} to have the background SIP service listen - * to incoming calls and broadcast them with registered command string. See + * <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)}, {@link #close}, {@link #isOpened} and * {@link #isRegistered}. It also facilitates handling of the incoming call @@ -40,39 +41,59 @@ import java.text.ParseException; * {@link #getOfferSessionDescription} and {@link #takeAudioCall}.</li> * <li>make/take SIP-based audio calls. See * {@link #makeAudioCall} and {@link #takeAudioCall}.</li> - * <li>register/unregister with a SIP service provider. See + * <li>register/unregister with a SIP service provider manually. See * {@link #register} and {@link #unregister}.</li> - * <li>process SIP events directly with a {@link ISipSession} created by + * <li>process SIP events directly with a {@link SipSession} created by * {@link #createSipSession}.</li> * </ul> * @hide */ public class SipManager { - /** @hide */ - public static final String SIP_INCOMING_CALL_ACTION = + /** + * Action string for the incoming call intent for the Phone app. + * Internal use only. + * @hide + */ + public static final String ACTION_SIP_INCOMING_CALL = "com.android.phone.SIP_INCOMING_CALL"; - /** @hide */ - public static final String SIP_ADD_PHONE_ACTION = + /** + * Action string for the add-phone intent. + * Internal use only. + * @hide + */ + public static final String ACTION_SIP_ADD_PHONE = "com.android.phone.SIP_ADD_PHONE"; - /** @hide */ - public static final String SIP_REMOVE_PHONE_ACTION = + /** + * Action string for the remove-phone intent. + * Internal use only. + * @hide + */ + public static final String ACTION_SIP_REMOVE_PHONE = "com.android.phone.SIP_REMOVE_PHONE"; - /** @hide */ - public static final String LOCAL_URI_KEY = "LOCAL SIPURI"; + /** + * Part of the ACTION_SIP_ADD_PHONE and ACTION_SIP_REMOVE_PHONE intents. + * Internal use only. + * @hide + */ + public static final String EXTRA_LOCAL_URI = "android:localSipUri"; - private static final String CALL_ID_KEY = "CallID"; - private static final String OFFER_SD_KEY = "OfferSD"; + /** 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 ISipService mSipService; + private Context mContext; /** - * Gets a manager instance. Returns null if SIP API is not supported. + * Creates a manager instance. Returns null if SIP API is not supported. * - * @param context application context for checking if SIP API is supported + * @param context application context for creating the manager object * @return the manager instance or null if SIP API is not supported */ - public static SipManager getInstance(Context context) { - return (isApiSupported(context) ? new SipManager() : null); + public static SipManager newInstance(Context context) { + return (isApiSupported(context) ? new SipManager(context) : null); } /** @@ -80,7 +101,7 @@ public class SipManager { */ public static boolean isApiSupported(Context context) { return true; - /* + /* TODO: uncomment this before ship return context.getPackageManager().hasSystemFeature( PackageManager.FEATURE_SIP); */ @@ -91,7 +112,7 @@ public class SipManager { */ public static boolean isVoipSupported(Context context) { return true; - /* + /* TODO: uncomment this before ship return context.getPackageManager().hasSystemFeature( PackageManager.FEATURE_SIP_VOIP) && isApiSupported(context); */ @@ -105,23 +126,21 @@ public class SipManager { com.android.internal.R.bool.config_sip_wifi_only); } - private SipManager() { + private SipManager(Context context) { + mContext = context; createSipService(); } private void createSipService() { - if (mSipService != null) return; IBinder b = ServiceManager.getService(Context.SIP_SERVICE); mSipService = ISipService.Stub.asInterface(b); } /** - * Opens the profile for making calls and/or receiving calls. Subsequent - * SIP calls can be made through the default phone UI. The caller may also - * make subsequent calls through {@link #makeAudioCall}. - * If the receiving-call option is enabled in the profile, the SIP service - * will register the profile to the corresponding server periodically in - * order to receive calls from the server. + * 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)} + * instead. * * @param localProfile the SIP profile to make calls from * @throws SipException if the profile contains incorrect settings or @@ -136,12 +155,11 @@ public class SipManager { } /** - * Opens the profile for making calls and/or receiving calls. Subsequent - * SIP calls can be made through the default phone UI. The caller may also - * make subsequent calls through {@link #makeAudioCall}. - * If the receiving-call option is enabled in the profile, the SIP service - * will register the profile to the corresponding server periodically in - * order to receive calls from the server. + * Opens the profile for making calls and/or receiving calls. The caller may + * make subsequent calls through {@link #makeAudioCall}. If the + * auto-registration option is enabled in the profile, the SIP service + * will register the profile to the corresponding SIP provider periodically + * 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 @@ -195,7 +213,8 @@ public class SipManager { } /** - * Checks if the specified profile is enabled to receive calls. + * Checks if the specified profile is opened in the SIP service for + * making and/or receiving calls. * * @param localProfileUri the URI of the profile in question * @return true if the profile is enabled to receive calls @@ -210,11 +229,16 @@ public class SipManager { } /** - * Checks if the specified profile is registered to the server for - * receiving calls. + * Checks if the SIP service has successfully registered the profile to the + * SIP provider (specified in the profile) for receiving calls. Returning + * true from this method also implies the profile is opened + * ({@link #isOpened}). * * @param localProfileUri the URI of the profile in question - * @return true if the profile is registered to the server + * @return true if the profile is registered to the SIP provider; false if + * the profile has not been opened in the SIP service or the SIP + * service has not yet successfully registered the profile to the SIP + * provider * @throws SipException if calling the SIP service results in an error */ public boolean isRegistered(String localProfileUri) throws SipException { @@ -231,7 +255,6 @@ public class SipManager { * {@code SipAudioCall.Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)} * will be called. * - * @param context context to create a {@link SipAudioCall} object * @param localProfile the SIP profile to make the call from * @param peerProfile the SIP profile to make the call to * @param listener to listen to the call events from {@link SipAudioCall}; @@ -241,10 +264,10 @@ public class SipManager { * @throws SipException if calling the SIP service results in an error * @see SipAudioCall.Listener.onError */ - public SipAudioCall makeAudioCall(Context context, SipProfile localProfile, + public SipAudioCall makeAudioCall(SipProfile localProfile, SipProfile peerProfile, SipAudioCall.Listener listener, int timeout) throws SipException { - SipAudioCall call = new SipAudioCallImpl(context, localProfile); + SipAudioCall call = new SipAudioCall(mContext, localProfile); call.setListener(listener); call.makeCall(peerProfile, this, timeout); return call; @@ -257,7 +280,6 @@ public class SipManager { * {@code SipAudioCall.Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)} * will be called. * - * @param context context to create a {@link SipAudioCall} object * @param localProfileUri URI of the SIP profile to make the call from * @param peerProfileUri URI of the SIP profile to make the call to * @param listener to listen to the call events from {@link SipAudioCall}; @@ -267,11 +289,11 @@ public class SipManager { * @throws SipException if calling the SIP service results in an error * @see SipAudioCall.Listener.onError */ - public SipAudioCall makeAudioCall(Context context, String localProfileUri, + public SipAudioCall makeAudioCall(String localProfileUri, String peerProfileUri, SipAudioCall.Listener listener, int timeout) throws SipException { try { - return makeAudioCall(context, + return makeAudioCall( new SipProfile.Builder(localProfileUri).build(), new SipProfile.Builder(peerProfileUri).build(), listener, timeout); @@ -281,15 +303,14 @@ public class SipManager { } /** - * The method calls {@code takeAudioCall(context, incomingCallIntent, + * The method calls {@code takeAudioCall(incomingCallIntent, * listener, true}. * - * @see #takeAudioCall(Context, Intent, SipAudioCall.Listener, boolean) + * @see #takeAudioCall(Intent, SipAudioCall.Listener, boolean) */ - public SipAudioCall takeAudioCall(Context context, - Intent incomingCallIntent, SipAudioCall.Listener listener) - throws SipException { - return takeAudioCall(context, incomingCallIntent, listener, true); + public SipAudioCall takeAudioCall(Intent incomingCallIntent, + SipAudioCall.Listener listener) throws SipException { + return takeAudioCall(incomingCallIntent, listener, true); } /** @@ -298,16 +319,15 @@ public class SipManager { * {@link SipAudioCall.Listener#onRinging} * callback. * - * @param context context to create a {@link SipAudioCall} object * @param incomingCallIntent the incoming call broadcast intent * @param listener to listen to the call events from {@link SipAudioCall}; * can be null * @return a {@link SipAudioCall} object * @throws SipException if calling the SIP service results in an error */ - public SipAudioCall takeAudioCall(Context context, - Intent incomingCallIntent, SipAudioCall.Listener listener, - boolean ringtoneEnabled) throws SipException { + public SipAudioCall takeAudioCall(Intent incomingCallIntent, + SipAudioCall.Listener listener, boolean ringtoneEnabled) + throws SipException { if (incomingCallIntent == null) return null; String callId = getCallId(incomingCallIntent); @@ -324,10 +344,10 @@ public class SipManager { try { ISipSession session = mSipService.getPendingSession(callId); if (session == null) return null; - SipAudioCall call = new SipAudioCallImpl( - context, session.getLocalProfile()); + SipAudioCall call = new SipAudioCall( + mContext, session.getLocalProfile()); call.setRingtoneEnabled(ringtoneEnabled); - call.attachCall(session, offerSd); + call.attachCall(new SipSession(session), offerSd); call.setListener(listener); return call; } catch (Throwable t) { @@ -355,7 +375,7 @@ public class SipManager { * @return the call ID or null if the intent does not contain it */ public static String getCallId(Intent incomingCallIntent) { - return incomingCallIntent.getStringExtra(CALL_ID_KEY); + return incomingCallIntent.getStringExtra(EXTRA_CALL_ID); } /** @@ -367,30 +387,30 @@ public class SipManager { * have it */ public static String getOfferSessionDescription(Intent incomingCallIntent) { - return incomingCallIntent.getStringExtra(OFFER_SD_KEY); + return incomingCallIntent.getStringExtra(EXTRA_OFFER_SD); } /** * Creates an incoming call broadcast intent. * - * @param action the action string to broadcast * @param callId the call ID of the incoming call * @param sessionDescription the session description of the incoming call * @return the incoming call intent * @hide */ - public static Intent createIncomingCallBroadcast(String action, - String callId, String sessionDescription) { - Intent intent = new Intent(action); - intent.putExtra(CALL_ID_KEY, callId); - intent.putExtra(OFFER_SD_KEY, sessionDescription); + public static Intent createIncomingCallBroadcast(String callId, + String sessionDescription) { + Intent intent = new Intent(); + intent.putExtra(EXTRA_CALL_ID, callId); + intent.putExtra(EXTRA_OFFER_SD, sessionDescription); return intent; } /** - * Registers the profile to the corresponding server for receiving calls. - * {@link #open} 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. + * 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. * * @param localProfile the SIP profile to register with * @param expiryTime registration expiration time (in seconds) @@ -409,8 +429,10 @@ public class SipManager { } /** - * Unregisters the profile from the corresponding server for not receiving - * further calls. + * Manually unregisters the profile from the corresponding SIP provider for + * stop receiving further calls. This may interference with the auto + * registration process in the SIP service if the auto-registration option + * in the profile is enabled. * * @param localProfile the SIP profile to register with * @param listener to listen to the registration events @@ -460,10 +482,11 @@ public class SipManager { * @param localProfile the SIP profile the session is associated with * @param listener to listen to SIP session events */ - public ISipSession createSipSession(SipProfile localProfile, - ISipSessionListener listener) throws SipException { + public SipSession createSipSession(SipProfile localProfile, + SipSession.Listener listener) throws SipException { try { - return mSipService.createSession(localProfile, listener); + ISipSession s = mSipService.createSession(localProfile, null); + return new SipSession(s, listener); } catch (RemoteException e) { throw new SipException("createSipSession()", e); } diff --git a/voip/java/android/net/sip/SipProfile.java b/voip/java/android/net/sip/SipProfile.java index 88bfba9..6d5cb3c 100644 --- a/voip/java/android/net/sip/SipProfile.java +++ b/voip/java/android/net/sip/SipProfile.java @@ -48,7 +48,6 @@ public class SipProfile implements Parcelable, Serializable, Cloneable { private boolean mAutoRegistration = true; private transient int mCallingUid = 0; - /** @hide */ public static final Parcelable.Creator<SipProfile> CREATOR = new Parcelable.Creator<SipProfile>() { public SipProfile createFromParcel(Parcel in) { @@ -287,7 +286,7 @@ public class SipProfile implements Parcelable, Serializable, Cloneable { mCallingUid = in.readInt(); } - /** @hide */ + @Override public void writeToParcel(Parcel out, int flags) { out.writeSerializable(mAddress); out.writeString(mProxyAddress); @@ -300,7 +299,7 @@ public class SipProfile implements Parcelable, Serializable, Cloneable { out.writeInt(mCallingUid); } - /** @hide */ + @Override public int describeContents() { return 0; } diff --git a/voip/java/android/net/sip/SipSession.java b/voip/java/android/net/sip/SipSession.java new file mode 100644 index 0000000..0cc7206 --- /dev/null +++ b/voip/java/android/net/sip/SipSession.java @@ -0,0 +1,531 @@ +/* + * 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.sip; + +import android.os.RemoteException; +import android.util.Log; + +/** + * A SIP session that is associated with a SIP dialog or a standalone + * transaction not within a dialog. + * @hide + */ +public final class SipSession { + private static final String TAG = "SipSession"; + + /** + * Defines {@link SipSession} states. + * @hide + */ + public static class State { + /** When session is ready to initiate a call or transaction. */ + public static final int READY_TO_CALL = 0; + + /** When the registration request is sent out. */ + public static final int REGISTERING = 1; + + /** When the unregistration request is sent out. */ + public static final int DEREGISTERING = 2; + + /** When an INVITE request is received. */ + public static final int INCOMING_CALL = 3; + + /** When an OK response is sent for the INVITE request received. */ + public static final int INCOMING_CALL_ANSWERING = 4; + + /** When an INVITE request is sent. */ + public static final int OUTGOING_CALL = 5; + + /** When a RINGING response is received for the INVITE request sent. */ + public static final int OUTGOING_CALL_RING_BACK = 6; + + /** When a CANCEL request is sent for the INVITE request sent. */ + public static final int OUTGOING_CALL_CANCELING = 7; + + /** When a call is established. */ + public static final int IN_CALL = 8; + + /** When an OPTIONS request is sent. */ + public static final int PINGING = 9; + + /** Not defined. */ + public static final int NOT_DEFINED = 101; + + /** + * Converts the state to string. + */ + public static String toString(int state) { + switch (state) { + case READY_TO_CALL: + return "READY_TO_CALL"; + case REGISTERING: + return "REGISTERING"; + case DEREGISTERING: + return "DEREGISTERING"; + case INCOMING_CALL: + return "INCOMING_CALL"; + case INCOMING_CALL_ANSWERING: + return "INCOMING_CALL_ANSWERING"; + case OUTGOING_CALL: + return "OUTGOING_CALL"; + case OUTGOING_CALL_RING_BACK: + return "OUTGOING_CALL_RING_BACK"; + case OUTGOING_CALL_CANCELING: + return "OUTGOING_CALL_CANCELING"; + case IN_CALL: + return "IN_CALL"; + case PINGING: + return "PINGING"; + default: + return "NOT_DEFINED"; + } + } + + private State() { + } + } + + /** + * Listener class that listens to {@link SipSession} events. + * @hide + */ + public static class Listener { + /** + * Called when an INVITE request is sent to initiate a new call. + * + * @param session the session object that carries out the transaction + */ + public void onCalling(SipSession session) { + } + + /** + * Called when an INVITE request is received. + * + * @param session the session object that carries out the transaction + * @param caller the SIP profile of the caller + * @param sessionDescription the caller's session description + */ + public void onRinging(SipSession session, SipProfile caller, + String sessionDescription) { + } + + /** + * Called when a RINGING response is received for the INVITE request sent + * + * @param session the session object that carries out the transaction + */ + public void onRingingBack(SipSession session) { + } + + /** + * Called when the session is established. + * + * @param session the session object that is associated with the dialog + * @param sessionDescription the peer's session description + */ + public void onCallEstablished(SipSession session, + String sessionDescription) { + } + + /** + * Called when the session is terminated. + * + * @param session the session object that is associated with the dialog + */ + public void onCallEnded(SipSession session) { + } + + /** + * Called when the peer is busy during session initialization. + * + * @param session the session object that carries out the transaction + */ + public void onCallBusy(SipSession session) { + } + + /** + * Called when an error occurs during session initialization and + * termination. + * + * @param session the session object that carries out the transaction + * @param errorCode error code defined in {@link SipErrorCode} + * @param errorMessage error message + */ + public void onError(SipSession session, int errorCode, + String errorMessage) { + } + + /** + * Called when an error occurs during session modification negotiation. + * + * @param session the session object that carries out the transaction + * @param errorCode error code defined in {@link SipErrorCode} + * @param errorMessage error message + */ + public void onCallChangeFailed(SipSession session, int errorCode, + String errorMessage) { + } + + /** + * Called when a registration request is sent. + * + * @param session the session object that carries out the transaction + */ + public void onRegistering(SipSession session) { + } + + /** + * Called when registration is successfully done. + * + * @param session the session object that carries out the transaction + * @param duration duration in second before the registration expires + */ + public void onRegistrationDone(SipSession session, int duration) { + } + + /** + * Called when the registration fails. + * + * @param session the session object that carries out the transaction + * @param errorCode error code defined in {@link SipErrorCode} + * @param errorMessage error message + */ + public void onRegistrationFailed(SipSession session, int errorCode, + String errorMessage) { + } + + /** + * Called when the registration gets timed out. + * + * @param session the session object that carries out the transaction + */ + public void onRegistrationTimeout(SipSession session) { + } + } + + private final ISipSession mSession; + private Listener mListener; + + SipSession(ISipSession realSession) { + mSession = realSession; + if (realSession != null) { + try { + realSession.setListener(createListener()); + } catch (RemoteException e) { + Log.e(TAG, "SipSession.setListener(): " + e); + } + } + } + + SipSession(ISipSession realSession, Listener listener) { + this(realSession); + setListener(listener); + } + + /** + * Gets the IP address of the local host on which this SIP session runs. + * + * @return the IP address of the local host + */ + public String getLocalIp() { + try { + return mSession.getLocalIp(); + } catch (RemoteException e) { + Log.e(TAG, "getLocalIp(): " + e); + return "127.0.0.1"; + } + } + + /** + * Gets the SIP profile that this session is associated with. + * + * @return the SIP profile that this session is associated with + */ + public SipProfile getLocalProfile() { + try { + return mSession.getLocalProfile(); + } catch (RemoteException e) { + Log.e(TAG, "getLocalProfile(): " + e); + return null; + } + } + + /** + * Gets the SIP profile that this session is connected to. Only available + * when the session is associated with a SIP dialog. + * + * @return the SIP profile that this session is connected to + */ + public SipProfile getPeerProfile() { + try { + return mSession.getPeerProfile(); + } catch (RemoteException e) { + Log.e(TAG, "getPeerProfile(): " + e); + return null; + } + } + + /** + * Gets the session state. The value returned must be one of the states in + * {@link SipSessionState}. + * + * @return the session state + */ + public int getState() { + try { + return mSession.getState(); + } catch (RemoteException e) { + Log.e(TAG, "getState(): " + e); + return State.NOT_DEFINED; + } + } + + /** + * Checks if the session is in a call. + * + * @return true if the session is in a call + */ + public boolean isInCall() { + try { + return mSession.isInCall(); + } catch (RemoteException e) { + Log.e(TAG, "isInCall(): " + e); + return false; + } + } + + /** + * Gets the call ID of the session. + * + * @return the call ID + */ + public String getCallId() { + try { + return mSession.getCallId(); + } catch (RemoteException e) { + Log.e(TAG, "getCallId(): " + e); + return null; + } + } + + + /** + * Sets the listener to listen to the session events. A {@code SipSession} + * can only hold one listener at a time. Subsequent calls to this method + * override the previous listener. + * + * @param listener to listen to the session events of this object + */ + public void setListener(Listener listener) { + mListener = listener; + } + + + /** + * Performs registration to the server specified by the associated local + * profile. The session listener is called back upon success or failure of + * registration. The method is only valid to call when the session state is + * in {@link SipSessionState#READY_TO_CALL}. + * + * @param duration duration in second before the registration expires + * @see Listener + */ + public void register(int duration) { + try { + mSession.register(duration); + } catch (RemoteException e) { + Log.e(TAG, "register(): " + e); + } + } + + /** + * Performs unregistration to the server specified by the associated local + * profile. Unregistration is technically the same as registration with zero + * expiration duration. The session listener is called back upon success or + * failure of unregistration. The method is only valid to call when the + * session state is in {@link SipSessionState#READY_TO_CALL}. + * + * @see Listener + */ + public void unregister() { + try { + mSession.unregister(); + } catch (RemoteException e) { + Log.e(TAG, "unregister(): " + e); + } + } + + /** + * Initiates a call to the specified profile. The session listener is called + * back upon defined session events. The method is only valid to call when + * the session state is in {@link SipSessionState#READY_TO_CALL}. + * + * @param callee the SIP profile to make the call to + * @param sessionDescription the session description of this call + * @param timeout the session will be timed out if the call is not + * established within {@code timeout} seconds. Default value (defined + * by SIP protocol) is used if {@code timeout} is zero or negative. + * @see Listener + */ + public void makeCall(SipProfile callee, String sessionDescription, + int timeout) { + try { + mSession.makeCall(callee, sessionDescription, timeout); + } catch (RemoteException e) { + Log.e(TAG, "makeCall(): " + e); + } + } + + /** + * Answers an incoming call with the specified session description. The + * method is only valid to call when the session state is in + * {@link SipSessionState#INCOMING_CALL}. + * + * @param sessionDescription the session description to answer this call + * @param timeout the session will be timed out if the call is not + * established within {@code timeout} seconds. Default value (defined + * by SIP protocol) is used if {@code timeout} is zero or negative. + */ + public void answerCall(String sessionDescription, int timeout) { + try { + mSession.answerCall(sessionDescription, timeout); + } catch (RemoteException e) { + Log.e(TAG, "answerCall(): " + e); + } + } + + /** + * Ends an established call, terminates an outgoing call or rejects an + * incoming call. The method is only valid to call when the session state is + * in {@link SipSessionState#IN_CALL}, + * {@link SipSessionState#INCOMING_CALL}, + * {@link SipSessionState#OUTGOING_CALL} or + * {@link SipSessionState#OUTGOING_CALL_RING_BACK}. + */ + public void endCall() { + try { + mSession.endCall(); + } catch (RemoteException e) { + Log.e(TAG, "endCall(): " + e); + } + } + + /** + * Changes the session description during a call. The method is only valid + * to call when the session state is in {@link SipSessionState#IN_CALL}. + * + * @param sessionDescription the new session description + * @param timeout the session will be timed out if the call is not + * established within {@code timeout} seconds. Default value (defined + * by SIP protocol) is used if {@code timeout} is zero or negative. + */ + public void changeCall(String sessionDescription, int timeout) { + try { + mSession.changeCall(sessionDescription, timeout); + } catch (RemoteException e) { + Log.e(TAG, "changeCall(): " + e); + } + } + + ISipSession getRealSession() { + return mSession; + } + + private ISipSessionListener createListener() { + return new ISipSessionListener.Stub() { + public void onCalling(ISipSession session) { + if (mListener != null) { + mListener.onCalling(SipSession.this); + } + } + + public void onRinging(ISipSession session, SipProfile caller, + String sessionDescription) { + if (mListener != null) { + mListener.onRinging(SipSession.this, caller, + sessionDescription); + } + } + + public void onRingingBack(ISipSession session) { + if (mListener != null) { + mListener.onRingingBack(SipSession.this); + } + } + + public void onCallEstablished(ISipSession session, + String sessionDescription) { + if (mListener != null) { + mListener.onCallEstablished(SipSession.this, + sessionDescription); + } + } + + public void onCallEnded(ISipSession session) { + if (mListener != null) { + mListener.onCallEnded(SipSession.this); + } + } + + public void onCallBusy(ISipSession session) { + if (mListener != null) { + mListener.onCallBusy(SipSession.this); + } + } + + public void onCallChangeFailed(ISipSession session, int errorCode, + String message) { + if (mListener != null) { + mListener.onCallChangeFailed(SipSession.this, errorCode, + message); + } + } + + public void onError(ISipSession session, int errorCode, String message) { + if (mListener != null) { + mListener.onError(SipSession.this, errorCode, message); + } + } + + public void onRegistering(ISipSession session) { + if (mListener != null) { + mListener.onRegistering(SipSession.this); + } + } + + public void onRegistrationDone(ISipSession session, int duration) { + if (mListener != null) { + mListener.onRegistrationDone(SipSession.this, duration); + } + } + + public void onRegistrationFailed(ISipSession session, int errorCode, + String message) { + if (mListener != null) { + mListener.onRegistrationFailed(SipSession.this, errorCode, + message); + } + } + + public void onRegistrationTimeout(ISipSession session) { + if (mListener != null) { + mListener.onRegistrationTimeout(SipSession.this); + } + } + }; + } +} diff --git a/voip/java/android/net/sip/SipSessionState.java b/voip/java/android/net/sip/SipSessionState.java deleted file mode 100644 index 31e9d3f..0000000 --- a/voip/java/android/net/sip/SipSessionState.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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.sip; - -/** - * Defines {@link ISipSession} states. - * @hide - */ -public class SipSessionState { - /** When session is ready to initiate a call or transaction. */ - public static final int READY_TO_CALL = 0; - - /** When the registration request is sent out. */ - public static final int REGISTERING = 1; - - /** When the unregistration request is sent out. */ - public static final int DEREGISTERING = 2; - - /** When an INVITE request is received. */ - public static final int INCOMING_CALL = 3; - - /** When an OK response is sent for the INVITE request received. */ - public static final int INCOMING_CALL_ANSWERING = 4; - - /** When an INVITE request is sent. */ - public static final int OUTGOING_CALL = 5; - - /** When a RINGING response is received for the INVITE request sent. */ - public static final int OUTGOING_CALL_RING_BACK = 6; - - /** When a CANCEL request is sent for the INVITE request sent. */ - public static final int OUTGOING_CALL_CANCELING = 7; - - /** When a call is established. */ - public static final int IN_CALL = 8; - - /** Some error occurs when making a remote call to {@link ISipSession}. */ - public static final int REMOTE_ERROR = 9; - - /** When an OPTIONS request is sent. */ - public static final int PINGING = 10; - - /** Not defined. */ - public static final int NOT_DEFINED = 101; - - /** - * Converts the state to string. - */ - public static String toString(int state) { - switch (state) { - case READY_TO_CALL: - return "READY_TO_CALL"; - case REGISTERING: - return "REGISTERING"; - case DEREGISTERING: - return "DEREGISTERING"; - case INCOMING_CALL: - return "INCOMING_CALL"; - case INCOMING_CALL_ANSWERING: - return "INCOMING_CALL_ANSWERING"; - case OUTGOING_CALL: - return "OUTGOING_CALL"; - case OUTGOING_CALL_RING_BACK: - return "OUTGOING_CALL_RING_BACK"; - case OUTGOING_CALL_CANCELING: - return "OUTGOING_CALL_CANCELING"; - case IN_CALL: - return "IN_CALL"; - case REMOTE_ERROR: - return "REMOTE_ERROR"; - case PINGING: - return "PINGING"; - default: - return "NOT_DEFINED"; - } - } - - private SipSessionState() { - } -} |
