diff --git a/.gitignore b/.gitignore index 51887ba..56f37df 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ target/ .idea/ -SproutServer.iml \ No newline at end of file +SproutServerMicro.iml \ No newline at end of file diff --git a/.project b/.project index 306e725..e24c15e 100644 --- a/.project +++ b/.project @@ -1,6 +1,6 @@ - SproutServer + SproutServerMicro diff --git a/.settings/org.eclipse.wst.common.component b/.settings/org.eclipse.wst.common.component index f38eef4..a15b5bc 100644 --- a/.settings/org.eclipse.wst.common.component +++ b/.settings/org.eclipse.wst.common.component @@ -1,10 +1,10 @@ - + - - + + diff --git a/pom.xml b/pom.xml index fc5e863..703493e 100644 --- a/pom.xml +++ b/pom.xml @@ -4,13 +4,13 @@ 4.0.0 org.ntlab - SproutServer + SproutServerMicro war 0.0.1-SNAPSHOT - SproutServer + SproutServerMicro - SproutServer + SproutServerMicro org.apache.maven.plugins diff --git a/src/main/java/android/os/AidlTest.java b/src/main/java/android/os/AidlTest.java deleted file mode 100644 index bf11d56..0000000 --- a/src/main/java/android/os/AidlTest.java +++ /dev/null @@ -1,422 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.os.IInterface; -import android.os.Parcel; -import android.os.Parcelable; -import android.test.suitebuilder.annotation.SmallTest; -import com.google.android.collect.Lists; -import junit.framework.TestCase; - -import java.util.List; - -public class AidlTest extends TestCase { - - private IAidlTest mRemote; - - @Override - protected void setUp() throws Exception { - super.setUp(); - AidlObject mLocal = new AidlObject(); - mRemote = IAidlTest.Stub.asInterface(mLocal); - } - - private static boolean check(TestParcelable p, int n, String s) { - return p.mAnInt == n && - ((s == null && p.mAString == null) || s.equals(p.mAString)); - } - - public static class TestParcelable implements Parcelable { - public int mAnInt; - public String mAString; - - public TestParcelable() { - } - - public TestParcelable(int i, String s) { - mAnInt = i; - mAString = s; - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel parcel, int flags) { - parcel.writeInt(mAnInt); - parcel.writeString(mAString); - } - - public void readFromParcel(Parcel parcel) { - mAnInt = parcel.readInt(); - mAString = parcel.readString(); - } - - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - public TestParcelable createFromParcel(Parcel parcel) { - return new TestParcelable(parcel.readInt(), - parcel.readString()); - } - - public TestParcelable[] newArray(int size) { - return new TestParcelable[size]; - } - }; - - public String toString() { - return super.toString() + " {" + mAnInt + "/" + mAString + "}"; - } - } - - private static class AidlObject extends IAidlTest.Stub { - public IInterface queryLocalInterface(String descriptor) { - // overriding this to return null makes asInterface always - // generate a proxy - return null; - } - - public int intMethod(int a) { - return a; - } - - public TestParcelable parcelableIn(TestParcelable p) { - p.mAnInt++; - return p; - } - - public TestParcelable parcelableOut(TestParcelable p) { - p.mAnInt = 44; - return p; - } - - public TestParcelable parcelableInOut(TestParcelable p) { - p.mAnInt++; - return p; - } - - public TestParcelable listParcelableLonger(List list, int index) { - list.add(list.get(index)); - return list.get(index); - } - - public int listParcelableShorter(List list, int index) { - list.remove(index); - return list.size(); - } - - public boolean[] booleanArray(boolean[] a0, boolean[] a1, boolean[] a2) { - for (int i = 0; i < a0.length && i < a2.length; i++) { - a2[i] = a0[i]; - } - for (int i = 0; i < a0.length && i < a1.length; i++) { - a1[i] = a0[i]; - } - return a0; - } - - public char[] charArray(char[] a0, char[] a1, char[] a2) { - for (int i = 0; i < a0.length && i < a2.length; i++) { - a2[i] = a0[i]; - } - for (int i = 0; i < a0.length && i < a1.length; i++) { - a1[i] = a0[i]; - } - return a0; - } - - public int[] intArray(int[] a0, int[] a1, int[] a2) { - for (int i = 0; i < a0.length && i < a2.length; i++) { - a2[i] = a0[i]; - } - for (int i = 0; i < a0.length && i < a1.length; i++) { - a1[i] = a0[i]; - } - return a0; - } - - public long[] longArray(long[] a0, long[] a1, long[] a2) { - for (int i = 0; i < a0.length && i < a2.length; i++) { - a2[i] = a0[i]; - } - for (int i = 0; i < a0.length && i < a1.length; i++) { - a1[i] = a0[i]; - } - return a0; - } - - public float[] floatArray(float[] a0, float[] a1, float[] a2) { - for (int i = 0; i < a0.length && i < a2.length; i++) { - a2[i] = a0[i]; - } - for (int i = 0; i < a0.length && i < a1.length; i++) { - a1[i] = a0[i]; - } - return a0; - } - - public double[] doubleArray(double[] a0, double[] a1, double[] a2) { - for (int i = 0; i < a0.length && i < a2.length; i++) { - a2[i] = a0[i]; - } - for (int i = 0; i < a0.length && i < a1.length; i++) { - a1[i] = a0[i]; - } - return a0; - } - - public String[] stringArray(String[] a0, String[] a1, String[] a2) { - for (int i = 0; i < a0.length && i < a2.length; i++) { - a2[i] = a0[i]; - } - for (int i = 0; i < a0.length && i < a1.length; i++) { - a1[i] = a0[i]; - } - return a0; - } - - public TestParcelable[] parcelableArray(TestParcelable[] a0, - TestParcelable[] a1, TestParcelable[] a2) { - return null; - } - - public void voidSecurityException() { - throw new SecurityException("gotcha!"); - } - - public int intSecurityException() { - throw new SecurityException("gotcha!"); - } - } - - @SmallTest - public void testInt() throws Exception { - int result = mRemote.intMethod(42); - assertEquals(42, result); - } - - @SmallTest - public void testParcelableIn() throws Exception { - TestParcelable arg = new TestParcelable(43, "hi"); - TestParcelable result = mRemote.parcelableIn(arg); - assertNotSame(arg, result); - - assertEquals(43, arg.mAnInt); - assertEquals(44, result.mAnInt); - } - - @SmallTest - public void testParcelableOut() throws Exception { - TestParcelable arg = new TestParcelable(43, "hi"); - TestParcelable result = mRemote.parcelableOut(arg); - assertNotSame(arg, result); - assertEquals(44, arg.mAnInt); - } - - @SmallTest - public void testParcelableInOut() throws Exception { - TestParcelable arg = new TestParcelable(43, "hi"); - TestParcelable result = mRemote.parcelableInOut(arg); - assertNotSame(arg, result); - assertEquals(44, arg.mAnInt); - } - - @SmallTest - public void testListParcelableLonger() throws Exception { - List list = Lists.newArrayList(); - list.add(new TestParcelable(33, "asdf")); - list.add(new TestParcelable(34, "jkl;")); - - TestParcelable result = mRemote.listParcelableLonger(list, 1); - -// System.out.println("result=" + result); -// for (TestParcelable p : list) { -// System.out.println("longer: " + p); -// } - - assertEquals("jkl;", result.mAString); - assertEquals(34, result.mAnInt); - - assertEquals(3, list.size()); - assertTrue("out parameter 0: " + list.get(0), check(list.get(0), 33, "asdf")); - assertTrue("out parameter 1: " + list.get(1), check(list.get(1), 34, "jkl;")); - assertTrue("out parameter 2: " + list.get(2), check(list.get(2), 34, "jkl;")); - - assertNotSame(list.get(1), list.get(2)); - } - - @SmallTest - public void testListParcelableShorter() throws Exception { - List list = Lists.newArrayList(); - list.add(new TestParcelable(33, "asdf")); - list.add(new TestParcelable(34, "jkl;")); - list.add(new TestParcelable(35, "qwerty")); - - int result = mRemote.listParcelableShorter(list, 2); - -// System.out.println("result=" + result); -// for (TestParcelable p : list) { -// System.out.println("shorter: " + p); -// } - - assertEquals(2, result); - assertEquals(2, list.size()); - assertTrue("out parameter 0: " + list.get(0), check(list.get(0), 33, "asdf")); - assertTrue("out parameter 1: " + list.get(1), check(list.get(1), 34, "jkl;")); - - assertNotSame(list.get(0), list.get(1)); - } - - @SmallTest - public void testArrays() throws Exception { - // boolean - boolean[] b0 = new boolean[]{true}; - boolean[] b1 = new boolean[]{false, true}; - boolean[] b2 = new boolean[]{true, false, true}; - boolean[] br = mRemote.booleanArray(b0, b1, b2); - - assertEquals(1, br.length); - assertTrue(br[0]); - - assertTrue(b1[0]); - assertFalse(b1[1]); - - assertTrue(b2[0]); - assertFalse(b2[1]); - assertTrue(b2[2]); - - // char - char[] c0 = new char[]{'a'}; - char[] c1 = new char[]{'b', 'c'}; - char[] c2 = new char[]{'d', 'e', 'f'}; - char[] cr = mRemote.charArray(c0, c1, c2); - - assertEquals(1, cr.length); - assertEquals('a', cr[0]); - - assertEquals('a', c1[0]); - assertEquals('\0', c1[1]); - - assertEquals('a', c2[0]); - assertEquals('e', c2[1]); - assertEquals('f', c2[2]); - - // int - int[] i0 = new int[]{34}; - int[] i1 = new int[]{38, 39}; - int[] i2 = new int[]{42, 43, 44}; - int[] ir = mRemote.intArray(i0, i1, i2); - - assertEquals(1, ir.length); - assertEquals(34, ir[0]); - - assertEquals(34, i1[0]); - assertEquals(0, i1[1]); - - assertEquals(34, i2[0]); - assertEquals(43, i2[1]); - assertEquals(44, i2[2]); - - // long - long[] l0 = new long[]{50}; - long[] l1 = new long[]{51, 52}; - long[] l2 = new long[]{53, 54, 55}; - long[] lr = mRemote.longArray(l0, l1, l2); - - assertEquals(1, lr.length); - assertEquals(50, lr[0]); - - assertEquals(50, l1[0]); - assertEquals(0, l1[1]); - - assertEquals(50, l2[0]); - assertEquals(54, l2[1]); - assertEquals(55, l2[2]); - - // float - float[] f0 = new float[]{90.1f}; - float[] f1 = new float[]{90.2f, 90.3f}; - float[] f2 = new float[]{90.4f, 90.5f, 90.6f}; - float[] fr = mRemote.floatArray(f0, f1, f2); - - assertEquals(1, fr.length); - assertEquals(90.1f, fr[0]); - - assertEquals(90.1f, f1[0]); - assertEquals(0f, f1[1], 0.0f); - - assertEquals(90.1f, f2[0]); - assertEquals(90.5f, f2[1]); - assertEquals(90.6f, f2[2]); - - // double - double[] d0 = new double[]{100.1}; - double[] d1 = new double[]{100.2, 100.3}; - double[] d2 = new double[]{100.4, 100.5, 100.6}; - double[] dr = mRemote.doubleArray(d0, d1, d2); - - assertEquals(1, dr.length); - assertEquals(100.1, dr[0]); - - assertEquals(100.1, d1[0]); - assertEquals(0, d1[1], 0.0); - - assertEquals(100.1, d2[0]); - assertEquals(100.5, d2[1]); - assertEquals(100.6, d2[2]); - - // String - String[] s0 = new String[]{"s0[0]"}; - String[] s1 = new String[]{"s1[0]", "s1[1]"}; - String[] s2 = new String[]{"s2[0]", "s2[1]", "s2[2]"}; - String[] sr = mRemote.stringArray(s0, s1, s2); - - assertEquals(1, sr.length); - assertEquals("s0[0]", sr[0]); - - assertEquals("s0[0]", s1[0]); - assertNull(s1[1]); - - assertEquals("s0[0]", s2[0]); - assertEquals("s2[1]", s2[1]); - assertEquals("s2[2]", s2[2]); - } - - @SmallTest - public void testVoidSecurityException() throws Exception { - boolean good = false; - try { - mRemote.voidSecurityException(); - } catch (SecurityException e) { - good = true; - } - assertEquals(good, true); - } - - @SmallTest - public void testIntSecurityException() throws Exception { - boolean good = false; - try { - mRemote.intSecurityException(); - } catch (SecurityException e) { - good = true; - } - assertEquals(good, true); - } -} - diff --git a/src/main/java/android/os/AsyncResult.java b/src/main/java/android/os/AsyncResult.java deleted file mode 100644 index 5bad09d..0000000 --- a/src/main/java/android/os/AsyncResult.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.os.Message; - -/** @hide */ -public class AsyncResult -{ - - /*************************** Instance Variables **************************/ - - // Expect either exception or result to be null - public Object userObj; - public Throwable exception; - public Object result; - - /***************************** Class Methods *****************************/ - - /** Saves and sets m.obj */ - public static AsyncResult - forMessage(Message m, Object r, Throwable ex) - { - AsyncResult ret; - - ret = new AsyncResult (m.obj, r, ex); - - m.obj = ret; - - return ret; - } - - /** Saves and sets m.obj */ - public static AsyncResult - forMessage(Message m) - { - AsyncResult ret; - - ret = new AsyncResult (m.obj, null, null); - - m.obj = ret; - - return ret; - } - - /** please note, this sets m.obj to be this */ - public - AsyncResult (Object uo, Object r, Throwable ex) - { - userObj = uo; - result = r; - exception = ex; - } -} diff --git a/src/main/java/android/os/AsyncTask.java b/src/main/java/android/os/AsyncTask.java deleted file mode 100644 index 7785f2b..0000000 --- a/src/main/java/android/os/AsyncTask.java +++ /dev/null @@ -1,676 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import java.util.ArrayDeque; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.Callable; -import java.util.concurrent.CancellationException; -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.FutureTask; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -/** - *

AsyncTask enables proper and easy use of the UI thread. This class allows to - * perform background operations and publish results on the UI thread without - * having to manipulate threads and/or handlers.

- * - *

AsyncTask is designed to be a helper class around {@link Thread} and {@link Handler} - * and does not constitute a generic threading framework. AsyncTasks should ideally be - * used for short operations (a few seconds at the most.) If you need to keep threads - * running for long periods of time, it is highly recommended you use the various APIs - * provided by the java.util.concurrent package such as {@link Executor}, - * {@link ThreadPoolExecutor} and {@link FutureTask}.

- * - *

An asynchronous task is defined by a computation that runs on a background thread and - * whose result is published on the UI thread. An asynchronous task is defined by 3 generic - * types, called Params, Progress and Result, - * and 4 steps, called onPreExecute, doInBackground, - * onProgressUpdate and onPostExecute.

- * - *
- *

Developer Guides

- *

For more information about using tasks and threads, read the - * Processes and - * Threads developer guide.

- *
- * - *

Usage

- *

AsyncTask must be subclassed to be used. The subclass will override at least - * one method ({@link #doInBackground}), and most often will override a - * second one ({@link #onPostExecute}.)

- * - *

Here is an example of subclassing:

- *
- * private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
- *     protected Long doInBackground(URL... urls) {
- *         int count = urls.length;
- *         long totalSize = 0;
- *         for (int i = 0; i < count; i++) {
- *             totalSize += Downloader.downloadFile(urls[i]);
- *             publishProgress((int) ((i / (float) count) * 100));
- *             // Escape early if cancel() is called
- *             if (isCancelled()) break;
- *         }
- *         return totalSize;
- *     }
- *
- *     protected void onProgressUpdate(Integer... progress) {
- *         setProgressPercent(progress[0]);
- *     }
- *
- *     protected void onPostExecute(Long result) {
- *         showDialog("Downloaded " + result + " bytes");
- *     }
- * }
- * 
- * - *

Once created, a task is executed very simply:

- *
- * new DownloadFilesTask().execute(url1, url2, url3);
- * 
- * - *

AsyncTask's generic types

- *

The three types used by an asynchronous task are the following:

- *
    - *
  1. Params, the type of the parameters sent to the task upon - * execution.
  2. - *
  3. Progress, the type of the progress units published during - * the background computation.
  4. - *
  5. Result, the type of the result of the background - * computation.
  6. - *
- *

Not all types are always used by an asynchronous task. To mark a type as unused, - * simply use the type {@link Void}:

- *
- * private class MyTask extends AsyncTask<Void, Void, Void> { ... }
- * 
- * - *

The 4 steps

- *

When an asynchronous task is executed, the task goes through 4 steps:

- *
    - *
  1. {@link #onPreExecute()}, invoked on the UI thread before the task - * is executed. This step is normally used to setup the task, for instance by - * showing a progress bar in the user interface.
  2. - *
  3. {@link #doInBackground}, invoked on the background thread - * immediately after {@link #onPreExecute()} finishes executing. This step is used - * to perform background computation that can take a long time. The parameters - * of the asynchronous task are passed to this step. The result of the computation must - * be returned by this step and will be passed back to the last step. This step - * can also use {@link #publishProgress} to publish one or more units - * of progress. These values are published on the UI thread, in the - * {@link #onProgressUpdate} step.
  4. - *
  5. {@link #onProgressUpdate}, invoked on the UI thread after a - * call to {@link #publishProgress}. The timing of the execution is - * undefined. This method is used to display any form of progress in the user - * interface while the background computation is still executing. For instance, - * it can be used to animate a progress bar or show logs in a text field.
  6. - *
  7. {@link #onPostExecute}, invoked on the UI thread after the background - * computation finishes. The result of the background computation is passed to - * this step as a parameter.
  8. - *
- * - *

Cancelling a task

- *

A task can be cancelled at any time by invoking {@link #cancel(boolean)}. Invoking - * this method will cause subsequent calls to {@link #isCancelled()} to return true. - * After invoking this method, {@link #onCancelled(Object)}, instead of - * {@link #onPostExecute(Object)} will be invoked after {@link #doInBackground(Object[])} - * returns. To ensure that a task is cancelled as quickly as possible, you should always - * check the return value of {@link #isCancelled()} periodically from - * {@link #doInBackground(Object[])}, if possible (inside a loop for instance.)

- * - *

Threading rules

- *

There are a few threading rules that must be followed for this class to - * work properly:

- *
    - *
  • The AsyncTask class must be loaded on the UI thread. This is done - * automatically as of {@link android.os.Build.VERSION_CODES#JELLY_BEAN}.
  • - *
  • The task instance must be created on the UI thread.
  • - *
  • {@link #execute} must be invoked on the UI thread.
  • - *
  • Do not call {@link #onPreExecute()}, {@link #onPostExecute}, - * {@link #doInBackground}, {@link #onProgressUpdate} manually.
  • - *
  • The task can be executed only once (an exception will be thrown if - * a second execution is attempted.)
  • - *
- * - *

Memory observability

- *

AsyncTask guarantees that all callback calls are synchronized in such a way that the following - * operations are safe without explicit synchronizations.

- *
    - *
  • Set member fields in the constructor or {@link #onPreExecute}, and refer to them - * in {@link #doInBackground}. - *
  • Set member fields in {@link #doInBackground}, and refer to them in - * {@link #onProgressUpdate} and {@link #onPostExecute}. - *
- * - *

Order of execution

- *

When first introduced, AsyncTasks were executed serially on a single background - * thread. Starting with {@link android.os.Build.VERSION_CODES#DONUT}, this was changed - * to a pool of threads allowing multiple tasks to operate in parallel. Starting with - * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, tasks are executed on a single - * thread to avoid common application errors caused by parallel execution.

- *

If you truly want parallel execution, you can invoke - * {@link #executeOnExecutor(java.util.concurrent.Executor, Object[])} with - * {@link #THREAD_POOL_EXECUTOR}.

- */ -public abstract class AsyncTask { - private static final String LOG_TAG = "AsyncTask"; - - private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); - private static final int CORE_POOL_SIZE = CPU_COUNT + 1; - private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1; - private static final int KEEP_ALIVE = 1; - - private static final ThreadFactory sThreadFactory = new ThreadFactory() { - private final AtomicInteger mCount = new AtomicInteger(1); - - public Thread newThread(Runnable r) { - return new Thread(r, "AsyncTask #" + mCount.getAndIncrement()); - } - }; - - private static final BlockingQueue sPoolWorkQueue = - new LinkedBlockingQueue(128); - - /** - * An {@link Executor} that can be used to execute tasks in parallel. - */ - public static final Executor THREAD_POOL_EXECUTOR - = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, - TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory); - - /** - * An {@link Executor} that executes tasks one at a time in serial - * order. This serialization is global to a particular process. - */ - public static final Executor SERIAL_EXECUTOR = new SerialExecutor(); - - private static final int MESSAGE_POST_RESULT = 0x1; - private static final int MESSAGE_POST_PROGRESS = 0x2; - - private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR; - private static InternalHandler sHandler; - - private final WorkerRunnable mWorker; - private final FutureTask mFuture; - - private volatile Status mStatus = Status.PENDING; - - private final AtomicBoolean mCancelled = new AtomicBoolean(); - private final AtomicBoolean mTaskInvoked = new AtomicBoolean(); - - private static class SerialExecutor implements Executor { - final ArrayDeque mTasks = new ArrayDeque(); - Runnable mActive; - - public synchronized void execute(final Runnable r) { - mTasks.offer(new Runnable() { - public void run() { - try { - r.run(); - } finally { - scheduleNext(); - } - } - }); - if (mActive == null) { - scheduleNext(); - } - } - - protected synchronized void scheduleNext() { - if ((mActive = mTasks.poll()) != null) { - THREAD_POOL_EXECUTOR.execute(mActive); - } - } - } - - /** - * Indicates the current status of the task. Each status will be set only once - * during the lifetime of a task. - */ - public enum Status { - /** - * Indicates that the task has not been executed yet. - */ - PENDING, - /** - * Indicates that the task is running. - */ - RUNNING, - /** - * Indicates that {@link AsyncTask#onPostExecute} has finished. - */ - FINISHED, - } - - private static Handler getHandler() { - synchronized (AsyncTask.class) { - if (sHandler == null) { - sHandler = new InternalHandler(); - } - return sHandler; - } - } - - /** @hide */ - public static void setDefaultExecutor(Executor exec) { - sDefaultExecutor = exec; - } - - /** - * Creates a new asynchronous task. This constructor must be invoked on the UI thread. - */ - public AsyncTask() { - mWorker = new WorkerRunnable() { - public Result call() throws Exception { - mTaskInvoked.set(true); - - Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); - //noinspection unchecked - return postResult(doInBackground(mParams)); - } - }; - - mFuture = new FutureTask(mWorker) { - @Override - protected void done() { - try { - postResultIfNotInvoked(get()); - } catch (InterruptedException e) { - android.util.Log.w(LOG_TAG, e); - } catch (ExecutionException e) { - throw new RuntimeException("An error occured while executing doInBackground()", - e.getCause()); - } catch (CancellationException e) { - postResultIfNotInvoked(null); - } - } - }; - } - - private void postResultIfNotInvoked(Result result) { - final boolean wasTaskInvoked = mTaskInvoked.get(); - if (!wasTaskInvoked) { - postResult(result); - } - } - - private Result postResult(Result result) { - @SuppressWarnings("unchecked") - Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, - new AsyncTaskResult(this, result)); - message.sendToTarget(); - return result; - } - - /** - * Returns the current status of this task. - * - * @return The current status. - */ - public final Status getStatus() { - return mStatus; - } - - /** - * Override this method to perform a computation on a background thread. The - * specified parameters are the parameters passed to {@link #execute} - * by the caller of this task. - * - * This method can call {@link #publishProgress} to publish updates - * on the UI thread. - * - * @param params The parameters of the task. - * - * @return A result, defined by the subclass of this task. - * - * @see #onPreExecute() - * @see #onPostExecute - * @see #publishProgress - */ - protected abstract Result doInBackground(Params... params); - - /** - * Runs on the UI thread before {@link #doInBackground}. - * - * @see #onPostExecute - * @see #doInBackground - */ - protected void onPreExecute() { - } - - /** - *

Runs on the UI thread after {@link #doInBackground}. The - * specified result is the value returned by {@link #doInBackground}.

- * - *

This method won't be invoked if the task was cancelled.

- * - * @param result The result of the operation computed by {@link #doInBackground}. - * - * @see #onPreExecute - * @see #doInBackground - * @see #onCancelled(Object) - */ - @SuppressWarnings({"UnusedDeclaration"}) - protected void onPostExecute(Result result) { - } - - /** - * Runs on the UI thread after {@link #publishProgress} is invoked. - * The specified values are the values passed to {@link #publishProgress}. - * - * @param values The values indicating progress. - * - * @see #publishProgress - * @see #doInBackground - */ - @SuppressWarnings({"UnusedDeclaration"}) - protected void onProgressUpdate(Progress... values) { - } - - /** - *

Runs on the UI thread after {@link #cancel(boolean)} is invoked and - * {@link #doInBackground(Object[])} has finished.

- * - *

The default implementation simply invokes {@link #onCancelled()} and - * ignores the result. If you write your own implementation, do not call - * super.onCancelled(result).

- * - * @param result The result, if any, computed in - * {@link #doInBackground(Object[])}, can be null - * - * @see #cancel(boolean) - * @see #isCancelled() - */ - @SuppressWarnings({"UnusedParameters"}) - protected void onCancelled(Result result) { - onCancelled(); - } - - /** - *

Applications should preferably override {@link #onCancelled(Object)}. - * This method is invoked by the default implementation of - * {@link #onCancelled(Object)}.

- * - *

Runs on the UI thread after {@link #cancel(boolean)} is invoked and - * {@link #doInBackground(Object[])} has finished.

- * - * @see #onCancelled(Object) - * @see #cancel(boolean) - * @see #isCancelled() - */ - protected void onCancelled() { - } - - /** - * Returns true if this task was cancelled before it completed - * normally. If you are calling {@link #cancel(boolean)} on the task, - * the value returned by this method should be checked periodically from - * {@link #doInBackground(Object[])} to end the task as soon as possible. - * - * @return true if task was cancelled before it completed - * - * @see #cancel(boolean) - */ - public final boolean isCancelled() { - return mCancelled.get(); - } - - /** - *

Attempts to cancel execution of this task. This attempt will - * fail if the task has already completed, already been cancelled, - * or could not be cancelled for some other reason. If successful, - * and this task has not started when cancel is called, - * this task should never run. If the task has already started, - * then the mayInterruptIfRunning parameter determines - * whether the thread executing this task should be interrupted in - * an attempt to stop the task.

- * - *

Calling this method will result in {@link #onCancelled(Object)} being - * invoked on the UI thread after {@link #doInBackground(Object[])} - * returns. Calling this method guarantees that {@link #onPostExecute(Object)} - * is never invoked. After invoking this method, you should check the - * value returned by {@link #isCancelled()} periodically from - * {@link #doInBackground(Object[])} to finish the task as early as - * possible.

- * - * @param mayInterruptIfRunning true if the thread executing this - * task should be interrupted; otherwise, in-progress tasks are allowed - * to complete. - * - * @return false if the task could not be cancelled, - * typically because it has already completed normally; - * true otherwise - * - * @see #isCancelled() - * @see #onCancelled(Object) - */ - public final boolean cancel(boolean mayInterruptIfRunning) { - mCancelled.set(true); - return mFuture.cancel(mayInterruptIfRunning); - } - - /** - * Waits if necessary for the computation to complete, and then - * retrieves its result. - * - * @return The computed result. - * - * @throws CancellationException If the computation was cancelled. - * @throws ExecutionException If the computation threw an exception. - * @throws InterruptedException If the current thread was interrupted - * while waiting. - */ - public final Result get() throws InterruptedException, ExecutionException { - return mFuture.get(); - } - - /** - * Waits if necessary for at most the given time for the computation - * to complete, and then retrieves its result. - * - * @param timeout Time to wait before cancelling the operation. - * @param unit The time unit for the timeout. - * - * @return The computed result. - * - * @throws CancellationException If the computation was cancelled. - * @throws ExecutionException If the computation threw an exception. - * @throws InterruptedException If the current thread was interrupted - * while waiting. - * @throws TimeoutException If the wait timed out. - */ - public final Result get(long timeout, TimeUnit unit) throws InterruptedException, - ExecutionException, TimeoutException { - return mFuture.get(timeout, unit); - } - - /** - * Executes the task with the specified parameters. The task returns - * itself (this) so that the caller can keep a reference to it. - * - *

Note: this function schedules the task on a queue for a single background - * thread or pool of threads depending on the platform version. When first - * introduced, AsyncTasks were executed serially on a single background thread. - * Starting with {@link android.os.Build.VERSION_CODES#DONUT}, this was changed - * to a pool of threads allowing multiple tasks to operate in parallel. Starting - * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, tasks are back to being - * executed on a single thread to avoid common application errors caused - * by parallel execution. If you truly want parallel execution, you can use - * the {@link #executeOnExecutor} version of this method - * with {@link #THREAD_POOL_EXECUTOR}; however, see commentary there for warnings - * on its use. - * - *

This method must be invoked on the UI thread. - * - * @param params The parameters of the task. - * - * @return This instance of AsyncTask. - * - * @throws IllegalStateException If {@link #getStatus()} returns either - * {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}. - * - * @see #executeOnExecutor(java.util.concurrent.Executor, Object[]) - * @see #execute(Runnable) - */ - public final AsyncTask execute(Params... params) { - return executeOnExecutor(sDefaultExecutor, params); - } - - /** - * Executes the task with the specified parameters. The task returns - * itself (this) so that the caller can keep a reference to it. - * - *

This method is typically used with {@link #THREAD_POOL_EXECUTOR} to - * allow multiple tasks to run in parallel on a pool of threads managed by - * AsyncTask, however you can also use your own {@link Executor} for custom - * behavior. - * - *

Warning: Allowing multiple tasks to run in parallel from - * a thread pool is generally not what one wants, because the order - * of their operation is not defined. For example, if these tasks are used - * to modify any state in common (such as writing a file due to a button click), - * there are no guarantees on the order of the modifications. - * Without careful work it is possible in rare cases for the newer version - * of the data to be over-written by an older one, leading to obscure data - * loss and stability issues. Such changes are best - * executed in serial; to guarantee such work is serialized regardless of - * platform version you can use this function with {@link #SERIAL_EXECUTOR}. - * - *

This method must be invoked on the UI thread. - * - * @param exec The executor to use. {@link #THREAD_POOL_EXECUTOR} is available as a - * convenient process-wide thread pool for tasks that are loosely coupled. - * @param params The parameters of the task. - * - * @return This instance of AsyncTask. - * - * @throws IllegalStateException If {@link #getStatus()} returns either - * {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}. - * - * @see #execute(Object[]) - */ - public final AsyncTask executeOnExecutor(Executor exec, - Params... params) { - if (mStatus != Status.PENDING) { - switch (mStatus) { - case RUNNING: - throw new IllegalStateException("Cannot execute task:" - + " the task is already running."); - case FINISHED: - throw new IllegalStateException("Cannot execute task:" - + " the task has already been executed " - + "(a task can be executed only once)"); - } - } - - mStatus = Status.RUNNING; - - onPreExecute(); - - mWorker.mParams = params; - exec.execute(mFuture); - - return this; - } - - /** - * Convenience version of {@link #execute(Object...)} for use with - * a simple Runnable object. See {@link #execute(Object[])} for more - * information on the order of execution. - * - * @see #execute(Object[]) - * @see #executeOnExecutor(java.util.concurrent.Executor, Object[]) - */ - public static void execute(Runnable runnable) { - sDefaultExecutor.execute(runnable); - } - - /** - * This method can be invoked from {@link #doInBackground} to - * publish updates on the UI thread while the background computation is - * still running. Each call to this method will trigger the execution of - * {@link #onProgressUpdate} on the UI thread. - * - * {@link #onProgressUpdate} will not be called if the task has been - * canceled. - * - * @param values The progress values to update the UI with. - * - * @see #onProgressUpdate - * @see #doInBackground - */ - protected final void publishProgress(Progress... values) { - if (!isCancelled()) { - getHandler().obtainMessage(MESSAGE_POST_PROGRESS, - new AsyncTaskResult(this, values)).sendToTarget(); - } - } - - private void finish(Result result) { - if (isCancelled()) { - onCancelled(result); - } else { - onPostExecute(result); - } - mStatus = Status.FINISHED; - } - - private static class InternalHandler extends Handler { - public InternalHandler() { - super(Looper.getMainLooper()); - } - - @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"}) - @Override - public void handleMessage(Message msg) { - AsyncTaskResult result = (AsyncTaskResult) msg.obj; - switch (msg.what) { - case MESSAGE_POST_RESULT: - // There is only one result - result.mTask.finish(result.mData[0]); - break; - case MESSAGE_POST_PROGRESS: - result.mTask.onProgressUpdate(result.mData); - break; - } - } - } - - private static abstract class WorkerRunnable implements Callable { - Params[] mParams; - } - - @SuppressWarnings({"RawUseOfParameterizedType"}) - private static class AsyncTaskResult { - final AsyncTask mTask; - final Data[] mData; - - AsyncTaskResult(AsyncTask task, Data... data) { - mTask = task; - mData = data; - } - } -} diff --git a/src/main/java/android/os/BadParcelableException.java b/src/main/java/android/os/BadParcelableException.java deleted file mode 100644 index a1c5bb2..0000000 --- a/src/main/java/android/os/BadParcelableException.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; -import android.util.AndroidRuntimeException; - -/** - * The object you are calling has died, because its hosting process - * no longer exists. - */ -public class BadParcelableException extends AndroidRuntimeException { - public BadParcelableException(String msg) { - super(msg); - } - public BadParcelableException(Exception cause) { - super(cause); - } -} diff --git a/src/main/java/android/os/BaseBundle.java b/src/main/java/android/os/BaseBundle.java deleted file mode 100644 index 1b02141..0000000 --- a/src/main/java/android/os/BaseBundle.java +++ /dev/null @@ -1,1363 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.util.ArrayMap; -import android.util.Log; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Map; -import java.util.Set; - -/** - * A mapping from String values to various types. - */ -public class BaseBundle { - private static final String TAG = "Bundle"; - static final boolean DEBUG = false; - - static final int BUNDLE_MAGIC = 0x4C444E42; // 'B' 'N' 'D' 'L' - static final Parcel EMPTY_PARCEL; - - static { - EMPTY_PARCEL = Parcel.obtain(); - } - - // Invariant - exactly one of mMap / mParcelledData will be null - // (except inside a call to unparcel) - - ArrayMap mMap = null; - - /* - * If mParcelledData is non-null, then mMap will be null and the - * data are stored as a Parcel containing a Bundle. When the data - * are unparcelled, mParcelledData willbe set to null. - */ - Parcel mParcelledData = null; - - /** - * The ClassLoader used when unparcelling data from mParcelledData. - */ - private ClassLoader mClassLoader; - - /** - * Constructs a new, empty Bundle that uses a specific ClassLoader for - * instantiating Parcelable and Serializable objects. - * - * @param loader An explicit ClassLoader to use when instantiating objects - * inside of the Bundle. - * @param capacity Initial size of the ArrayMap. - */ - BaseBundle(ClassLoader loader, int capacity) { - mMap = capacity > 0 ? - new ArrayMap(capacity) : new ArrayMap(); - mClassLoader = loader == null ? getClass().getClassLoader() : loader; - } - - /** - * Constructs a new, empty Bundle. - */ - BaseBundle() { - this((ClassLoader) null, 0); - } - - /** - * Constructs a Bundle whose data is stored as a Parcel. The data - * will be unparcelled on first contact, using the assigned ClassLoader. - * - * @param parcelledData a Parcel containing a Bundle - */ - BaseBundle(Parcel parcelledData) { - readFromParcelInner(parcelledData); - } - - BaseBundle(Parcel parcelledData, int length) { - readFromParcelInner(parcelledData, length); - } - - /** - * Constructs a new, empty Bundle that uses a specific ClassLoader for - * instantiating Parcelable and Serializable objects. - * - * @param loader An explicit ClassLoader to use when instantiating objects - * inside of the Bundle. - */ - BaseBundle(ClassLoader loader) { - this(loader, 0); - } - - /** - * Constructs a new, empty Bundle sized to hold the given number of - * elements. The Bundle will grow as needed. - * - * @param capacity the initial capacity of the Bundle - */ - BaseBundle(int capacity) { - this((ClassLoader) null, capacity); - } - - /** - * Constructs a Bundle containing a copy of the mappings from the given - * Bundle. - * - * @param b a Bundle to be copied. - */ - BaseBundle(BaseBundle b) { - if (b.mParcelledData != null) { - if (b.mParcelledData == EMPTY_PARCEL) { - mParcelledData = EMPTY_PARCEL; - } else { - mParcelledData = Parcel.obtain(); - mParcelledData.appendFrom(b.mParcelledData, 0, b.mParcelledData.dataSize()); - mParcelledData.setDataPosition(0); - } - } else { - mParcelledData = null; - } - - if (b.mMap != null) { - mMap = new ArrayMap(b.mMap); - } else { - mMap = null; - } - - mClassLoader = b.mClassLoader; - } - - /** - * TODO: optimize this later (getting just the value part of a Bundle - * with a single pair) once Bundle.forPair() above is implemented - * with a special single-value Map implementation/serialization. - * - * Note: value in single-pair Bundle may be null. - * - * @hide - */ - public String getPairValue() { - unparcel(); - int size = mMap.size(); - if (size > 1) { - Log.w(TAG, "getPairValue() used on Bundle with multiple pairs."); - } - if (size == 0) { - return null; - } - Object o = mMap.valueAt(0); - try { - return (String) o; - } catch (ClassCastException e) { - typeWarning("getPairValue()", o, "String", e); - return null; - } - } - - /** - * Changes the ClassLoader this Bundle uses when instantiating objects. - * - * @param loader An explicit ClassLoader to use when instantiating objects - * inside of the Bundle. - */ - void setClassLoader(ClassLoader loader) { - mClassLoader = loader; - } - - /** - * Return the ClassLoader currently associated with this Bundle. - */ - ClassLoader getClassLoader() { - return mClassLoader; - } - - /** - * If the underlying data are stored as a Parcel, unparcel them - * using the currently assigned class loader. - */ - /* package */ synchronized void unparcel() { - if (mParcelledData == null) { - if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this)) - + ": no parcelled data"); - return; - } - - if (mParcelledData == EMPTY_PARCEL) { - if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this)) - + ": empty"); - if (mMap == null) { - mMap = new ArrayMap(1); - } else { - mMap.erase(); - } - mParcelledData = null; - return; - } - - int N = mParcelledData.readInt(); - if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this)) - + ": reading " + N + " maps"); - if (N < 0) { - return; - } - if (mMap == null) { - mMap = new ArrayMap(N); - } else { - mMap.erase(); - mMap.ensureCapacity(N); - } - mParcelledData.readArrayMapInternal(mMap, N, mClassLoader); - mParcelledData.recycle(); - mParcelledData = null; - if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this)) - + " final map: " + mMap); - } - - /** - * @hide - */ - public boolean isParcelled() { - return mParcelledData != null; - } - - /** - * Returns the number of mappings contained in this Bundle. - * - * @return the number of mappings as an int. - */ - public int size() { - unparcel(); - return mMap.size(); - } - - /** - * Returns true if the mapping of this Bundle is empty, false otherwise. - */ - public boolean isEmpty() { - unparcel(); - return mMap.isEmpty(); - } - - /** - * Removes all elements from the mapping of this Bundle. - */ - public void clear() { - unparcel(); - mMap.clear(); - } - - /** - * Returns true if the given key is contained in the mapping - * of this Bundle. - * - * @param key a String key - * @return true if the key is part of the mapping, false otherwise - */ - public boolean containsKey(String key) { - unparcel(); - return mMap.containsKey(key); - } - - /** - * Returns the entry with the given key as an object. - * - * @param key a String key - * @return an Object, or null - */ - public Object get(String key) { - unparcel(); - return mMap.get(key); - } - - /** - * Removes any entry with the given key from the mapping of this Bundle. - * - * @param key a String key - */ - public void remove(String key) { - unparcel(); - mMap.remove(key); - } - - /** - * Inserts all mappings from the given PersistableBundle into this BaseBundle. - * - * @param bundle a PersistableBundle - */ - public void putAll(PersistableBundle bundle) { - unparcel(); - bundle.unparcel(); - mMap.putAll(bundle.mMap); - } - - /** - * Inserts all mappings from the given Map into this BaseBundle. - * - * @param map a Map - */ - void putAll(Map map) { - unparcel(); - mMap.putAll(map); - } - - /** - * Returns a Set containing the Strings used as keys in this Bundle. - * - * @return a Set of String keys - */ - public Set keySet() { - unparcel(); - return mMap.keySet(); - } - - /** - * Inserts a Boolean value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value a Boolean, or null - */ - public void putBoolean(String key, boolean value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Inserts a byte value into the mapping of this Bundle, replacing - * any existing value for the given key. - * - * @param key a String, or null - * @param value a byte - */ - void putByte(String key, byte value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Inserts a char value into the mapping of this Bundle, replacing - * any existing value for the given key. - * - * @param key a String, or null - * @param value a char, or null - */ - void putChar(String key, char value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Inserts a short value into the mapping of this Bundle, replacing - * any existing value for the given key. - * - * @param key a String, or null - * @param value a short - */ - void putShort(String key, short value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Inserts an int value into the mapping of this Bundle, replacing - * any existing value for the given key. - * - * @param key a String, or null - * @param value an int, or null - */ - public void putInt(String key, int value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Inserts a long value into the mapping of this Bundle, replacing - * any existing value for the given key. - * - * @param key a String, or null - * @param value a long - */ - public void putLong(String key, long value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Inserts a float value into the mapping of this Bundle, replacing - * any existing value for the given key. - * - * @param key a String, or null - * @param value a float - */ - void putFloat(String key, float value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Inserts a double value into the mapping of this Bundle, replacing - * any existing value for the given key. - * - * @param key a String, or null - * @param value a double - */ - public void putDouble(String key, double value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Inserts a String value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value a String, or null - */ - public void putString(String key, String value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Inserts a CharSequence value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value a CharSequence, or null - */ - void putCharSequence(String key, CharSequence value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Inserts an ArrayList value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value an ArrayList object, or null - */ - void putIntegerArrayList(String key, ArrayList value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Inserts an ArrayList value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value an ArrayList object, or null - */ - void putStringArrayList(String key, ArrayList value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Inserts an ArrayList value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value an ArrayList object, or null - */ - void putCharSequenceArrayList(String key, ArrayList value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Inserts a Serializable value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value a Serializable object, or null - */ - void putSerializable(String key, Serializable value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Inserts a boolean array value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value a boolean array object, or null - */ - public void putBooleanArray(String key, boolean[] value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Inserts a byte array value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value a byte array object, or null - */ - void putByteArray(String key, byte[] value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Inserts a short array value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value a short array object, or null - */ - void putShortArray(String key, short[] value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Inserts a char array value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value a char array object, or null - */ - void putCharArray(String key, char[] value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Inserts an int array value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value an int array object, or null - */ - public void putIntArray(String key, int[] value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Inserts a long array value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value a long array object, or null - */ - public void putLongArray(String key, long[] value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Inserts a float array value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value a float array object, or null - */ - void putFloatArray(String key, float[] value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Inserts a double array value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value a double array object, or null - */ - public void putDoubleArray(String key, double[] value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Inserts a String array value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value a String array object, or null - */ - public void putStringArray(String key, String[] value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Inserts a CharSequence array value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value a CharSequence array object, or null - */ - void putCharSequenceArray(String key, CharSequence[] value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Returns the value associated with the given key, or false if - * no mapping of the desired type exists for the given key. - * - * @param key a String - * @return a boolean value - */ - public boolean getBoolean(String key) { - unparcel(); - if (DEBUG) Log.d(TAG, "Getting boolean in " - + Integer.toHexString(System.identityHashCode(this))); - return getBoolean(key, false); - } - - // Log a message if the value was non-null but not of the expected type - void typeWarning(String key, Object value, String className, - Object defaultValue, ClassCastException e) { - StringBuilder sb = new StringBuilder(); - sb.append("Key "); - sb.append(key); - sb.append(" expected "); - sb.append(className); - sb.append(" but value was a "); - sb.append(value.getClass().getName()); - sb.append(". The default value "); - sb.append(defaultValue); - sb.append(" was returned."); - Log.w(TAG, sb.toString()); - Log.w(TAG, "Attempt to cast generated internal exception:", e); - } - - void typeWarning(String key, Object value, String className, - ClassCastException e) { - typeWarning(key, value, className, "", e); - } - - /** - * Returns the value associated with the given key, or defaultValue if - * no mapping of the desired type exists for the given key. - * - * @param key a String - * @param defaultValue Value to return if key does not exist - * @return a boolean value - */ - public boolean getBoolean(String key, boolean defaultValue) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return defaultValue; - } - try { - return (Boolean) o; - } catch (ClassCastException e) { - typeWarning(key, o, "Boolean", defaultValue, e); - return defaultValue; - } - } - - /** - * Returns the value associated with the given key, or (byte) 0 if - * no mapping of the desired type exists for the given key. - * - * @param key a String - * @return a byte value - */ - byte getByte(String key) { - unparcel(); - return getByte(key, (byte) 0); - } - - /** - * Returns the value associated with the given key, or defaultValue if - * no mapping of the desired type exists for the given key. - * - * @param key a String - * @param defaultValue Value to return if key does not exist - * @return a byte value - */ - Byte getByte(String key, byte defaultValue) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return defaultValue; - } - try { - return (Byte) o; - } catch (ClassCastException e) { - typeWarning(key, o, "Byte", defaultValue, e); - return defaultValue; - } - } - - /** - * Returns the value associated with the given key, or (char) 0 if - * no mapping of the desired type exists for the given key. - * - * @param key a String - * @return a char value - */ - char getChar(String key) { - unparcel(); - return getChar(key, (char) 0); - } - - /** - * Returns the value associated with the given key, or defaultValue if - * no mapping of the desired type exists for the given key. - * - * @param key a String - * @param defaultValue Value to return if key does not exist - * @return a char value - */ - char getChar(String key, char defaultValue) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return defaultValue; - } - try { - return (Character) o; - } catch (ClassCastException e) { - typeWarning(key, o, "Character", defaultValue, e); - return defaultValue; - } - } - - /** - * Returns the value associated with the given key, or (short) 0 if - * no mapping of the desired type exists for the given key. - * - * @param key a String - * @return a short value - */ - short getShort(String key) { - unparcel(); - return getShort(key, (short) 0); - } - - /** - * Returns the value associated with the given key, or defaultValue if - * no mapping of the desired type exists for the given key. - * - * @param key a String - * @param defaultValue Value to return if key does not exist - * @return a short value - */ - short getShort(String key, short defaultValue) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return defaultValue; - } - try { - return (Short) o; - } catch (ClassCastException e) { - typeWarning(key, o, "Short", defaultValue, e); - return defaultValue; - } - } - - /** - * Returns the value associated with the given key, or 0 if - * no mapping of the desired type exists for the given key. - * - * @param key a String - * @return an int value - */ - public int getInt(String key) { - unparcel(); - return getInt(key, 0); - } - - /** - * Returns the value associated with the given key, or defaultValue if - * no mapping of the desired type exists for the given key. - * - * @param key a String - * @param defaultValue Value to return if key does not exist - * @return an int value - */ - public int getInt(String key, int defaultValue) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return defaultValue; - } - try { - return (Integer) o; - } catch (ClassCastException e) { - typeWarning(key, o, "Integer", defaultValue, e); - return defaultValue; - } - } - - /** - * Returns the value associated with the given key, or 0L if - * no mapping of the desired type exists for the given key. - * - * @param key a String - * @return a long value - */ - public long getLong(String key) { - unparcel(); - return getLong(key, 0L); - } - - /** - * Returns the value associated with the given key, or defaultValue if - * no mapping of the desired type exists for the given key. - * - * @param key a String - * @param defaultValue Value to return if key does not exist - * @return a long value - */ - public long getLong(String key, long defaultValue) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return defaultValue; - } - try { - return (Long) o; - } catch (ClassCastException e) { - typeWarning(key, o, "Long", defaultValue, e); - return defaultValue; - } - } - - /** - * Returns the value associated with the given key, or 0.0f if - * no mapping of the desired type exists for the given key. - * - * @param key a String - * @return a float value - */ - float getFloat(String key) { - unparcel(); - return getFloat(key, 0.0f); - } - - /** - * Returns the value associated with the given key, or defaultValue if - * no mapping of the desired type exists for the given key. - * - * @param key a String - * @param defaultValue Value to return if key does not exist - * @return a float value - */ - float getFloat(String key, float defaultValue) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return defaultValue; - } - try { - return (Float) o; - } catch (ClassCastException e) { - typeWarning(key, o, "Float", defaultValue, e); - return defaultValue; - } - } - - /** - * Returns the value associated with the given key, or 0.0 if - * no mapping of the desired type exists for the given key. - * - * @param key a String - * @return a double value - */ - public double getDouble(String key) { - unparcel(); - return getDouble(key, 0.0); - } - - /** - * Returns the value associated with the given key, or defaultValue if - * no mapping of the desired type exists for the given key. - * - * @param key a String - * @param defaultValue Value to return if key does not exist - * @return a double value - */ - public double getDouble(String key, double defaultValue) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return defaultValue; - } - try { - return (Double) o; - } catch (ClassCastException e) { - typeWarning(key, o, "Double", defaultValue, e); - return defaultValue; - } - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return a String value, or null - */ - public String getString(String key) { - unparcel(); - final Object o = mMap.get(key); - try { - return (String) o; - } catch (ClassCastException e) { - typeWarning(key, o, "String", e); - return null; - } - } - - /** - * Returns the value associated with the given key, or defaultValue if - * no mapping of the desired type exists for the given key or if a null - * value is explicitly associated with the given key. - * - * @param key a String, or null - * @param defaultValue Value to return if key does not exist or if a null - * value is associated with the given key. - * @return the String value associated with the given key, or defaultValue - * if no valid String object is currently mapped to that key. - */ - public String getString(String key, String defaultValue) { - final String s = getString(key); - return (s == null) ? defaultValue : s; - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return a CharSequence value, or null - */ - CharSequence getCharSequence(String key) { - unparcel(); - final Object o = mMap.get(key); - try { - return (CharSequence) o; - } catch (ClassCastException e) { - typeWarning(key, o, "CharSequence", e); - return null; - } - } - - /** - * Returns the value associated with the given key, or defaultValue if - * no mapping of the desired type exists for the given key or if a null - * value is explicitly associated with the given key. - * - * @param key a String, or null - * @param defaultValue Value to return if key does not exist or if a null - * value is associated with the given key. - * @return the CharSequence value associated with the given key, or defaultValue - * if no valid CharSequence object is currently mapped to that key. - */ - CharSequence getCharSequence(String key, CharSequence defaultValue) { - final CharSequence cs = getCharSequence(key); - return (cs == null) ? defaultValue : cs; - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return a Serializable value, or null - */ - Serializable getSerializable(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (Serializable) o; - } catch (ClassCastException e) { - typeWarning(key, o, "Serializable", e); - return null; - } - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return an ArrayList value, or null - */ - ArrayList getIntegerArrayList(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (ArrayList) o; - } catch (ClassCastException e) { - typeWarning(key, o, "ArrayList", e); - return null; - } - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return an ArrayList value, or null - */ - ArrayList getStringArrayList(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (ArrayList) o; - } catch (ClassCastException e) { - typeWarning(key, o, "ArrayList", e); - return null; - } - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return an ArrayList value, or null - */ - ArrayList getCharSequenceArrayList(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (ArrayList) o; - } catch (ClassCastException e) { - typeWarning(key, o, "ArrayList", e); - return null; - } - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return a boolean[] value, or null - */ - public boolean[] getBooleanArray(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (boolean[]) o; - } catch (ClassCastException e) { - typeWarning(key, o, "byte[]", e); - return null; - } - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return a byte[] value, or null - */ - byte[] getByteArray(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (byte[]) o; - } catch (ClassCastException e) { - typeWarning(key, o, "byte[]", e); - return null; - } - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return a short[] value, or null - */ - short[] getShortArray(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (short[]) o; - } catch (ClassCastException e) { - typeWarning(key, o, "short[]", e); - return null; - } - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return a char[] value, or null - */ - char[] getCharArray(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (char[]) o; - } catch (ClassCastException e) { - typeWarning(key, o, "char[]", e); - return null; - } - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return an int[] value, or null - */ - public int[] getIntArray(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (int[]) o; - } catch (ClassCastException e) { - typeWarning(key, o, "int[]", e); - return null; - } - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return a long[] value, or null - */ - public long[] getLongArray(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (long[]) o; - } catch (ClassCastException e) { - typeWarning(key, o, "long[]", e); - return null; - } - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return a float[] value, or null - */ - float[] getFloatArray(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (float[]) o; - } catch (ClassCastException e) { - typeWarning(key, o, "float[]", e); - return null; - } - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return a double[] value, or null - */ - public double[] getDoubleArray(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (double[]) o; - } catch (ClassCastException e) { - typeWarning(key, o, "double[]", e); - return null; - } - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return a String[] value, or null - */ - public String[] getStringArray(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (String[]) o; - } catch (ClassCastException e) { - typeWarning(key, o, "String[]", e); - return null; - } - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return a CharSequence[] value, or null - */ - CharSequence[] getCharSequenceArray(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (CharSequence[]) o; - } catch (ClassCastException e) { - typeWarning(key, o, "CharSequence[]", e); - return null; - } - } - - /** - * Writes the Bundle contents to a Parcel, typically in order for - * it to be passed through an IBinder connection. - * @param parcel The parcel to copy this bundle to. - */ - void writeToParcelInner(Parcel parcel, int flags) { - if (mParcelledData != null) { - if (mParcelledData == EMPTY_PARCEL) { - parcel.writeInt(0); - } else { - int length = mParcelledData.dataSize(); - parcel.writeInt(length); - parcel.writeInt(BUNDLE_MAGIC); - parcel.appendFrom(mParcelledData, 0, length); - } - } else { - // Special case for empty bundles. - if (mMap == null || mMap.size() <= 0) { - parcel.writeInt(0); - return; - } - int lengthPos = parcel.dataPosition(); - parcel.writeInt(-1); // dummy, will hold length - parcel.writeInt(BUNDLE_MAGIC); - - int startPos = parcel.dataPosition(); - parcel.writeArrayMapInternal(mMap); - int endPos = parcel.dataPosition(); - - // Backpatch length - parcel.setDataPosition(lengthPos); - int length = endPos - startPos; - parcel.writeInt(length); - parcel.setDataPosition(endPos); - } - } - - /** - * Reads the Parcel contents into this Bundle, typically in order for - * it to be passed through an IBinder connection. - * @param parcel The parcel to overwrite this bundle from. - */ - void readFromParcelInner(Parcel parcel) { - int length = parcel.readInt(); - if (length < 0) { - throw new RuntimeException("Bad length in parcel: " + length); - } - readFromParcelInner(parcel, length); - } - - private void readFromParcelInner(Parcel parcel, int length) { - if (length == 0) { - // Empty Bundle or end of data. - mParcelledData = EMPTY_PARCEL; - return; - } - int magic = parcel.readInt(); - if (magic != BUNDLE_MAGIC) { - //noinspection ThrowableInstanceNeverThrown - throw new IllegalStateException("Bad magic number for Bundle: 0x" - + Integer.toHexString(magic)); - } - - // Advance within this Parcel - int offset = parcel.dataPosition(); - parcel.setDataPosition(offset + length); - - Parcel p = Parcel.obtain(); - p.setDataPosition(0); - p.appendFrom(parcel, offset, length); - if (DEBUG) Log.d(TAG, "Retrieving " + Integer.toHexString(System.identityHashCode(this)) - + ": " + length + " bundle bytes starting at " + offset); - p.setDataPosition(0); - - mParcelledData = p; - } -} diff --git a/src/main/java/android/os/BatteryManager.java b/src/main/java/android/os/BatteryManager.java deleted file mode 100644 index 537e993..0000000 --- a/src/main/java/android/os/BatteryManager.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.os.BatteryProperty; -import android.os.IBatteryPropertiesRegistrar; -import android.os.RemoteException; -import android.os.ServiceManager; - -/** - * The BatteryManager class contains strings and constants used for values - * in the {@link android.content.Intent#ACTION_BATTERY_CHANGED} Intent, and - * provides a method for querying battery and charging properties. - */ -public class BatteryManager { - /** - * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}: - * integer containing the current status constant. - */ - public static final String EXTRA_STATUS = "status"; - - /** - * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}: - * integer containing the current health constant. - */ - public static final String EXTRA_HEALTH = "health"; - - /** - * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}: - * boolean indicating whether a battery is present. - */ - public static final String EXTRA_PRESENT = "present"; - - /** - * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}: - * integer field containing the current battery level, from 0 to - * {@link #EXTRA_SCALE}. - */ - public static final String EXTRA_LEVEL = "level"; - - /** - * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}: - * integer containing the maximum battery level. - */ - public static final String EXTRA_SCALE = "scale"; - - /** - * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}: - * integer containing the resource ID of a small status bar icon - * indicating the current battery state. - */ - public static final String EXTRA_ICON_SMALL = "icon-small"; - - /** - * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}: - * integer indicating whether the device is plugged in to a power - * source; 0 means it is on battery, other constants are different - * types of power sources. - */ - public static final String EXTRA_PLUGGED = "plugged"; - - /** - * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}: - * integer containing the current battery voltage level. - */ - public static final String EXTRA_VOLTAGE = "voltage"; - - /** - * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}: - * integer containing the current battery temperature. - */ - public static final String EXTRA_TEMPERATURE = "temperature"; - - /** - * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}: - * String describing the technology of the current battery. - */ - public static final String EXTRA_TECHNOLOGY = "technology"; - - /** - * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}: - * Int value set to nonzero if an unsupported charger is attached - * to the device. - * {@hide} - */ - public static final String EXTRA_INVALID_CHARGER = "invalid_charger"; - - // values for "status" field in the ACTION_BATTERY_CHANGED Intent - public static final int BATTERY_STATUS_UNKNOWN = 1; - public static final int BATTERY_STATUS_CHARGING = 2; - public static final int BATTERY_STATUS_DISCHARGING = 3; - public static final int BATTERY_STATUS_NOT_CHARGING = 4; - public static final int BATTERY_STATUS_FULL = 5; - - // values for "health" field in the ACTION_BATTERY_CHANGED Intent - public static final int BATTERY_HEALTH_UNKNOWN = 1; - public static final int BATTERY_HEALTH_GOOD = 2; - public static final int BATTERY_HEALTH_OVERHEAT = 3; - public static final int BATTERY_HEALTH_DEAD = 4; - public static final int BATTERY_HEALTH_OVER_VOLTAGE = 5; - public static final int BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6; - public static final int BATTERY_HEALTH_COLD = 7; - - // values of the "plugged" field in the ACTION_BATTERY_CHANGED intent. - // These must be powers of 2. - /** Power source is an AC charger. */ - public static final int BATTERY_PLUGGED_AC = 1; - /** Power source is a USB port. */ - public static final int BATTERY_PLUGGED_USB = 2; - /** Power source is wireless. */ - public static final int BATTERY_PLUGGED_WIRELESS = 4; - - /** @hide */ - public static final int BATTERY_PLUGGED_ANY = - BATTERY_PLUGGED_AC | BATTERY_PLUGGED_USB | BATTERY_PLUGGED_WIRELESS; - - /* - * Battery property identifiers. These must match the values in - * frameworks/native/include/batteryservice/BatteryService.h - */ - /** Battery capacity in microampere-hours, as an integer. */ - public static final int BATTERY_PROPERTY_CHARGE_COUNTER = 1; - - /** - * Instantaneous battery current in microamperes, as an integer. Positive - * values indicate net current entering the battery from a charge source, - * negative values indicate net current discharging from the battery. - */ - public static final int BATTERY_PROPERTY_CURRENT_NOW = 2; - - /** - * Average battery current in microamperes, as an integer. Positive - * values indicate net current entering the battery from a charge source, - * negative values indicate net current discharging from the battery. - * The time period over which the average is computed may depend on the - * fuel gauge hardware and its configuration. - */ - public static final int BATTERY_PROPERTY_CURRENT_AVERAGE = 3; - - /** - * Remaining battery capacity as an integer percentage of total capacity - * (with no fractional part). - */ - public static final int BATTERY_PROPERTY_CAPACITY = 4; - - /** - * Battery remaining energy in nanowatt-hours, as a long integer. - */ - public static final int BATTERY_PROPERTY_ENERGY_COUNTER = 5; - - private IBatteryPropertiesRegistrar mBatteryPropertiesRegistrar; - - /** - * Query a battery property from the batteryproperties service. - * - * Returns the requested value, or Long.MIN_VALUE if property not - * supported on this system or on other error. - */ - private long queryProperty(int id) { - long ret; - - if (mBatteryPropertiesRegistrar == null) { - IBinder b = ServiceManager.getService("batteryproperties"); - mBatteryPropertiesRegistrar = - IBatteryPropertiesRegistrar.Stub.asInterface(b); - - if (mBatteryPropertiesRegistrar == null) - return Long.MIN_VALUE; - } - - try { - BatteryProperty prop = new BatteryProperty(); - - if (mBatteryPropertiesRegistrar.getProperty(id, prop) == 0) - ret = prop.getLong(); - else - ret = Long.MIN_VALUE; - } catch (RemoteException e) { - ret = Long.MIN_VALUE; - } - - return ret; - } - - /** - * Return the value of a battery property of integer type. If the - * platform does not provide the property queried, this value will - * be Integer.MIN_VALUE. - * - * @param id identifier of the requested property - * - * @return the property value, or Integer.MIN_VALUE if not supported. - */ - public int getIntProperty(int id) { - return (int)queryProperty(id); - } - - /** - * Return the value of a battery property of long type If the - * platform does not provide the property queried, this value will - * be Long.MIN_VALUE. - * - * @param id identifier of the requested property - * - * @return the property value, or Long.MIN_VALUE if not supported. - */ - public long getLongProperty(int id) { - return queryProperty(id); - } -} diff --git a/src/main/java/android/os/BatteryManagerInternal.java b/src/main/java/android/os/BatteryManagerInternal.java deleted file mode 100644 index f3a95b9..0000000 --- a/src/main/java/android/os/BatteryManagerInternal.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -/** - * Battery manager local system service interface. - * - * @hide Only for use within the system server. - */ -public abstract class BatteryManagerInternal { - /** - * Returns true if the device is plugged into any of the specified plug types. - */ - public abstract boolean isPowered(int plugTypeSet); - - /** - * Returns the current plug type. - */ - public abstract int getPlugType(); - - /** - * Returns battery level as a percentage. - */ - public abstract int getBatteryLevel(); - - /** - * Returns whether we currently consider the battery level to be low. - */ - public abstract boolean getBatteryLevelLow(); - - /** - * Returns a non-zero value if an unsupported charger is attached. - */ - public abstract int getInvalidCharger(); -} diff --git a/src/main/java/android/os/BatteryProperties.java b/src/main/java/android/os/BatteryProperties.java deleted file mode 100644 index 8f5cf8b..0000000 --- a/src/main/java/android/os/BatteryProperties.java +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright 2013, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -package android.os; - -/** - * {@hide} - */ -public class BatteryProperties implements Parcelable { - public boolean chargerAcOnline; - public boolean chargerUsbOnline; - public boolean chargerWirelessOnline; - public int batteryStatus; - public int batteryHealth; - public boolean batteryPresent; - public int batteryLevel; - public int batteryVoltage; - public int batteryTemperature; - public String batteryTechnology; - - public BatteryProperties() { - } - - public void set(BatteryProperties other) { - chargerAcOnline = other.chargerAcOnline; - chargerUsbOnline = other.chargerUsbOnline; - chargerWirelessOnline = other.chargerWirelessOnline; - batteryStatus = other.batteryStatus; - batteryHealth = other.batteryHealth; - batteryPresent = other.batteryPresent; - batteryLevel = other.batteryLevel; - batteryVoltage = other.batteryVoltage; - batteryTemperature = other.batteryTemperature; - batteryTechnology = other.batteryTechnology; - } - - /* - * Parcel read/write code must be kept in sync with - * frameworks/native/services/batteryservice/BatteryProperties.cpp - */ - - private BatteryProperties(Parcel p) { - chargerAcOnline = p.readInt() == 1 ? true : false; - chargerUsbOnline = p.readInt() == 1 ? true : false; - chargerWirelessOnline = p.readInt() == 1 ? true : false; - batteryStatus = p.readInt(); - batteryHealth = p.readInt(); - batteryPresent = p.readInt() == 1 ? true : false; - batteryLevel = p.readInt(); - batteryVoltage = p.readInt(); - batteryTemperature = p.readInt(); - batteryTechnology = p.readString(); - } - - public void writeToParcel(Parcel p, int flags) { - p.writeInt(chargerAcOnline ? 1 : 0); - p.writeInt(chargerUsbOnline ? 1 : 0); - p.writeInt(chargerWirelessOnline ? 1 : 0); - p.writeInt(batteryStatus); - p.writeInt(batteryHealth); - p.writeInt(batteryPresent ? 1 : 0); - p.writeInt(batteryLevel); - p.writeInt(batteryVoltage); - p.writeInt(batteryTemperature); - p.writeString(batteryTechnology); - } - - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - public BatteryProperties createFromParcel(Parcel p) { - return new BatteryProperties(p); - } - - public BatteryProperties[] newArray(int size) { - return new BatteryProperties[size]; - } - }; - - public int describeContents() { - return 0; - } -} diff --git a/src/main/java/android/os/BatteryProperty.java b/src/main/java/android/os/BatteryProperty.java deleted file mode 100644 index 84119bd..0000000 --- a/src/main/java/android/os/BatteryProperty.java +++ /dev/null @@ -1,77 +0,0 @@ -/* Copyright 2013, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -package android.os; - -import android.os.Parcel; -import android.os.Parcelable; - -/** - * Battery properties that may be queried using - * BatteryManager.getProperty()} - */ - -/** - * @hide - */ -public class BatteryProperty implements Parcelable { - private long mValueLong; - - /** - * @hide - */ - public BatteryProperty() { - mValueLong = Long.MIN_VALUE; - } - - /** - * @hide - */ - public long getLong() { - return mValueLong; - } - - /* - * Parcel read/write code must be kept in sync with - * frameworks/native/services/batteryservice/BatteryProperty.cpp - */ - - private BatteryProperty(Parcel p) { - readFromParcel(p); - } - - public void readFromParcel(Parcel p) { - mValueLong = p.readLong(); - } - - public void writeToParcel(Parcel p, int flags) { - p.writeLong(mValueLong); - } - - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - public BatteryProperty createFromParcel(Parcel p) { - return new BatteryProperty(p); - } - - public BatteryProperty[] newArray(int size) { - return new BatteryProperty[size]; - } - }; - - public int describeContents() { - return 0; - } -} diff --git a/src/main/java/android/os/BatteryStats.java b/src/main/java/android/os/BatteryStats.java deleted file mode 100644 index cd45cfb..0000000 --- a/src/main/java/android/os/BatteryStats.java +++ /dev/null @@ -1,4174 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.Formatter; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.telephony.SignalStrength; -import android.text.format.DateFormat; -import android.util.Printer; -import android.util.SparseArray; -import android.util.SparseIntArray; -import android.util.TimeUtils; -import android.view.Display; -import com.android.internal.os.BatterySipper; -import com.android.internal.os.BatteryStatsHelper; - -/** - * A class providing access to battery usage statistics, including information on - * wakelocks, processes, packages, and services. All times are represented in microseconds - * except where indicated otherwise. - * @hide - */ -public abstract class BatteryStats implements Parcelable { - - private static final boolean LOCAL_LOGV = false; - - /** @hide */ - public static final String SERVICE_NAME = "batterystats"; - - /** - * A constant indicating a partial wake lock timer. - */ - public static final int WAKE_TYPE_PARTIAL = 0; - - /** - * A constant indicating a full wake lock timer. - */ - public static final int WAKE_TYPE_FULL = 1; - - /** - * A constant indicating a window wake lock timer. - */ - public static final int WAKE_TYPE_WINDOW = 2; - - /** - * A constant indicating a sensor timer. - */ - public static final int SENSOR = 3; - - /** - * A constant indicating a a wifi running timer - */ - public static final int WIFI_RUNNING = 4; - - /** - * A constant indicating a full wifi lock timer - */ - public static final int FULL_WIFI_LOCK = 5; - - /** - * A constant indicating a wifi scan - */ - public static final int WIFI_SCAN = 6; - - /** - * A constant indicating a wifi multicast timer - */ - public static final int WIFI_MULTICAST_ENABLED = 7; - - /** - * A constant indicating a video turn on timer - */ - public static final int VIDEO_TURNED_ON = 8; - - /** - * A constant indicating a vibrator on timer - */ - public static final int VIBRATOR_ON = 9; - - /** - * A constant indicating a foreground activity timer - */ - public static final int FOREGROUND_ACTIVITY = 10; - - /** - * A constant indicating a wifi batched scan is active - */ - public static final int WIFI_BATCHED_SCAN = 11; - - /** - * A constant indicating a process state timer - */ - public static final int PROCESS_STATE = 12; - - /** - * A constant indicating a sync timer - */ - public static final int SYNC = 13; - - /** - * A constant indicating a job timer - */ - public static final int JOB = 14; - - /** - * A constant indicating an audio turn on timer - */ - public static final int AUDIO_TURNED_ON = 15; - - /** - * Include all of the data in the stats, including previously saved data. - */ - public static final int STATS_SINCE_CHARGED = 0; - - /** - * Include only the current run in the stats. - */ - public static final int STATS_CURRENT = 1; - - /** - * Include only the run since the last time the device was unplugged in the stats. - */ - public static final int STATS_SINCE_UNPLUGGED = 2; - - // NOTE: Update this list if you add/change any stats above. - // These characters are supposed to represent "total", "last", "current", - // and "unplugged". They were shortened for efficiency sake. - private static final String[] STAT_NAMES = { "l", "c", "u" }; - - /** - * Bump the version on this if the checkin format changes. - */ - private static final int BATTERY_STATS_CHECKIN_VERSION = 9; - - private static final long BYTES_PER_KB = 1024; - private static final long BYTES_PER_MB = 1048576; // 1024^2 - private static final long BYTES_PER_GB = 1073741824; //1024^3 - - private static final String VERSION_DATA = "vers"; - private static final String UID_DATA = "uid"; - private static final String APK_DATA = "apk"; - private static final String PROCESS_DATA = "pr"; - private static final String SENSOR_DATA = "sr"; - private static final String VIBRATOR_DATA = "vib"; - private static final String FOREGROUND_DATA = "fg"; - private static final String STATE_TIME_DATA = "st"; - private static final String WAKELOCK_DATA = "wl"; - private static final String SYNC_DATA = "sy"; - private static final String JOB_DATA = "jb"; - private static final String KERNEL_WAKELOCK_DATA = "kwl"; - private static final String WAKEUP_REASON_DATA = "wr"; - private static final String NETWORK_DATA = "nt"; - private static final String USER_ACTIVITY_DATA = "ua"; - private static final String BATTERY_DATA = "bt"; - private static final String BATTERY_DISCHARGE_DATA = "dc"; - private static final String BATTERY_LEVEL_DATA = "lv"; - private static final String WIFI_DATA = "wfl"; - private static final String MISC_DATA = "m"; - private static final String GLOBAL_NETWORK_DATA = "gn"; - private static final String HISTORY_STRING_POOL = "hsp"; - private static final String HISTORY_DATA = "h"; - private static final String SCREEN_BRIGHTNESS_DATA = "br"; - private static final String SIGNAL_STRENGTH_TIME_DATA = "sgt"; - private static final String SIGNAL_SCANNING_TIME_DATA = "sst"; - private static final String SIGNAL_STRENGTH_COUNT_DATA = "sgc"; - private static final String DATA_CONNECTION_TIME_DATA = "dct"; - private static final String DATA_CONNECTION_COUNT_DATA = "dcc"; - private static final String WIFI_STATE_TIME_DATA = "wst"; - private static final String WIFI_STATE_COUNT_DATA = "wsc"; - private static final String WIFI_SUPPL_STATE_TIME_DATA = "wsst"; - private static final String WIFI_SUPPL_STATE_COUNT_DATA = "wssc"; - private static final String WIFI_SIGNAL_STRENGTH_TIME_DATA = "wsgt"; - private static final String WIFI_SIGNAL_STRENGTH_COUNT_DATA = "wsgc"; - private static final String BLUETOOTH_STATE_TIME_DATA = "bst"; - private static final String BLUETOOTH_STATE_COUNT_DATA = "bsc"; - private static final String POWER_USE_SUMMARY_DATA = "pws"; - private static final String POWER_USE_ITEM_DATA = "pwi"; - private static final String DISCHARGE_STEP_DATA = "dsd"; - private static final String CHARGE_STEP_DATA = "csd"; - private static final String DISCHARGE_TIME_REMAIN_DATA = "dtr"; - private static final String CHARGE_TIME_REMAIN_DATA = "ctr"; - - private final StringBuilder mFormatBuilder = new StringBuilder(32); - private final Formatter mFormatter = new Formatter(mFormatBuilder); - - /** - * State for keeping track of counting information. - */ - public static abstract class Counter { - - /** - * Returns the count associated with this Counter for the - * selected type of statistics. - * - * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT - */ - public abstract int getCountLocked(int which); - - /** - * Temporary for debugging. - */ - public abstract void logState(Printer pw, String prefix); - } - - /** - * State for keeping track of long counting information. - */ - public static abstract class LongCounter { - - /** - * Returns the count associated with this Counter for the - * selected type of statistics. - * - * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT - */ - public abstract long getCountLocked(int which); - - /** - * Temporary for debugging. - */ - public abstract void logState(Printer pw, String prefix); - } - - /** - * State for keeping track of timing information. - */ - public static abstract class Timer { - - /** - * Returns the count associated with this Timer for the - * selected type of statistics. - * - * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT - */ - public abstract int getCountLocked(int which); - - /** - * Returns the total time in microseconds associated with this Timer for the - * selected type of statistics. - * - * @param elapsedRealtimeUs current elapsed realtime of system in microseconds - * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT - * @return a time in microseconds - */ - public abstract long getTotalTimeLocked(long elapsedRealtimeUs, int which); - - /** - * Temporary for debugging. - */ - public abstract void logState(Printer pw, String prefix); - } - - /** - * The statistics associated with a particular uid. - */ - public static abstract class Uid { - - /** - * Returns a mapping containing wakelock statistics. - * - * @return a Map from Strings to Uid.Wakelock objects. - */ - public abstract Map getWakelockStats(); - - /** - * Returns a mapping containing sync statistics. - * - * @return a Map from Strings to Timer objects. - */ - public abstract Map getSyncStats(); - - /** - * Returns a mapping containing scheduled job statistics. - * - * @return a Map from Strings to Timer objects. - */ - public abstract Map getJobStats(); - - /** - * The statistics associated with a particular wake lock. - */ - public static abstract class Wakelock { - public abstract Timer getWakeTime(int type); - } - - /** - * Returns a mapping containing sensor statistics. - * - * @return a Map from Integer sensor ids to Uid.Sensor objects. - */ - public abstract SparseArray getSensorStats(); - - /** - * Returns a mapping containing active process data. - */ - public abstract SparseArray getPidStats(); - - /** - * Returns a mapping containing process statistics. - * - * @return a Map from Strings to Uid.Proc objects. - */ - public abstract Map getProcessStats(); - - /** - * Returns a mapping containing package statistics. - * - * @return a Map from Strings to Uid.Pkg objects. - */ - public abstract Map getPackageStats(); - - /** - * {@hide} - */ - public abstract int getUid(); - - public abstract void noteWifiRunningLocked(long elapsedRealtime); - public abstract void noteWifiStoppedLocked(long elapsedRealtime); - public abstract void noteFullWifiLockAcquiredLocked(long elapsedRealtime); - public abstract void noteFullWifiLockReleasedLocked(long elapsedRealtime); - public abstract void noteWifiScanStartedLocked(long elapsedRealtime); - public abstract void noteWifiScanStoppedLocked(long elapsedRealtime); - public abstract void noteWifiBatchedScanStartedLocked(int csph, long elapsedRealtime); - public abstract void noteWifiBatchedScanStoppedLocked(long elapsedRealtime); - public abstract void noteWifiMulticastEnabledLocked(long elapsedRealtime); - public abstract void noteWifiMulticastDisabledLocked(long elapsedRealtime); - public abstract void noteActivityResumedLocked(long elapsedRealtime); - public abstract void noteActivityPausedLocked(long elapsedRealtime); - public abstract long getWifiRunningTime(long elapsedRealtimeUs, int which); - public abstract long getFullWifiLockTime(long elapsedRealtimeUs, int which); - public abstract long getWifiScanTime(long elapsedRealtimeUs, int which); - public abstract long getWifiBatchedScanTime(int csphBin, long elapsedRealtimeUs, int which); - public abstract long getWifiMulticastTime(long elapsedRealtimeUs, int which); - public abstract long getAudioTurnedOnTime(long elapsedRealtimeUs, int which); - public abstract long getVideoTurnedOnTime(long elapsedRealtimeUs, int which); - public abstract Timer getForegroundActivityTimer(); - - // Time this uid has any processes in foreground state. - public static final int PROCESS_STATE_FOREGROUND = 0; - // Time this uid has any process in active state (not cached). - public static final int PROCESS_STATE_ACTIVE = 1; - // Time this uid has any processes running at all. - public static final int PROCESS_STATE_RUNNING = 2; - // Total number of process states we track. - public static final int NUM_PROCESS_STATE = 3; - - static final String[] PROCESS_STATE_NAMES = { - "Foreground", "Active", "Running" - }; - - public abstract long getProcessStateTime(int state, long elapsedRealtimeUs, int which); - - public abstract Timer getVibratorOnTimer(); - - public static final int NUM_WIFI_BATCHED_SCAN_BINS = 5; - - /** - * Note that these must match the constants in android.os.PowerManager. - * Also, if the user activity types change, the BatteryStatsImpl.VERSION must - * also be bumped. - */ - static final String[] USER_ACTIVITY_TYPES = { - "other", "button", "touch" - }; - - public static final int NUM_USER_ACTIVITY_TYPES = 3; - - public abstract void noteUserActivityLocked(int type); - public abstract boolean hasUserActivity(); - public abstract int getUserActivityCount(int type, int which); - - public abstract boolean hasNetworkActivity(); - public abstract long getNetworkActivityBytes(int type, int which); - public abstract long getNetworkActivityPackets(int type, int which); - public abstract long getMobileRadioActiveTime(int which); - public abstract int getMobileRadioActiveCount(int which); - - public static abstract class Sensor { - /* - * FIXME: it's not correct to use this magic value because it - * could clash with a sensor handle (which are defined by - * the sensor HAL, and therefore out of our control - */ - // Magic sensor number for the GPS. - public static final int GPS = -10000; - - public abstract int getHandle(); - - public abstract Timer getSensorTime(); - } - - public class Pid { - public int mWakeNesting; - public long mWakeSumMs; - public long mWakeStartMs; - } - - /** - * The statistics associated with a particular process. - */ - public static abstract class Proc { - - 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; - } - - /** - * Returns true if this process is still active in the battery stats. - */ - public abstract boolean isActive(); - - /** - * Returns the total time (in 1/100 sec) spent executing in user code. - * - * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. - */ - public abstract long getUserTime(int which); - - /** - * Returns the total time (in 1/100 sec) spent executing in system code. - * - * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. - */ - public abstract long getSystemTime(int which); - - /** - * Returns the number of times the process has been started. - * - * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. - */ - public abstract int getStarts(int which); - - /** - * Returns the number of times the process has crashed. - * - * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. - */ - public abstract int getNumCrashes(int which); - - /** - * Returns the number of times the process has ANRed. - * - * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. - */ - public abstract int getNumAnrs(int which); - - /** - * Returns the cpu time spent in microseconds while the process was in the foreground. - * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. - * @return foreground cpu time in microseconds - */ - public abstract long getForegroundTime(int which); - - /** - * Returns the approximate cpu time spent in microseconds, at a certain CPU speed. - * @param speedStep the index of the CPU speed. This is not the actual speed of the - * CPU. - * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. - * @see BatteryStats#getCpuSpeedSteps() - */ - public abstract long getTimeAtCpuSpeedStep(int speedStep, int which); - - public abstract int countExcessivePowers(); - - public abstract ExcessivePower getExcessivePower(int i); - } - - /** - * The statistics associated with a particular package. - */ - public static abstract class Pkg { - - /** - * Returns the number of times this package has done something that could wake up the - * device from sleep. - * - * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. - */ - public abstract int getWakeups(int which); - - /** - * Returns a mapping containing service statistics. - */ - public abstract Map getServiceStats(); - - /** - * The statistics associated with a particular service. - */ - public abstract class Serv { - - /** - * Returns the amount of time spent started. - * - * @param batteryUptime elapsed uptime on battery in microseconds. - * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. - * @return - */ - public abstract long getStartTime(long batteryUptime, int which); - - /** - * Returns the total number of times startService() has been called. - * - * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. - */ - public abstract int getStarts(int which); - - /** - * Returns the total number times the service has been launched. - * - * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. - */ - public abstract int getLaunches(int which); - } - } - } - - public final static class HistoryTag { - public String string; - public int uid; - - public int poolIdx; - - public void setTo(HistoryTag o) { - string = o.string; - uid = o.uid; - poolIdx = o.poolIdx; - } - - public void setTo(String _string, int _uid) { - string = _string; - uid = _uid; - poolIdx = -1; - } - - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(string); - dest.writeInt(uid); - } - - public void readFromParcel(Parcel src) { - string = src.readString(); - uid = src.readInt(); - poolIdx = -1; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - HistoryTag that = (HistoryTag) o; - - if (uid != that.uid) return false; - if (!string.equals(that.string)) return false; - - return true; - } - - @Override - public int hashCode() { - int result = string.hashCode(); - result = 31 * result + uid; - return result; - } - } - - public final static class HistoryItem implements Parcelable { - public HistoryItem next; - - // The time of this event in milliseconds, as per SystemClock.elapsedRealtime(). - public long time; - - public static final byte CMD_UPDATE = 0; // These can be written as deltas - public static final byte CMD_NULL = -1; - public static final byte CMD_START = 4; - public static final byte CMD_CURRENT_TIME = 5; - public static final byte CMD_OVERFLOW = 6; - public static final byte CMD_RESET = 7; - public static final byte CMD_SHUTDOWN = 8; - - public byte cmd = CMD_NULL; - - /** - * Return whether the command code is a delta data update. - */ - public boolean isDeltaData() { - return cmd == CMD_UPDATE; - } - - public byte batteryLevel; - public byte batteryStatus; - public byte batteryHealth; - public byte batteryPlugType; - - public short batteryTemperature; - public char batteryVoltage; - - // Constants from SCREEN_BRIGHTNESS_* - public static final int STATE_BRIGHTNESS_SHIFT = 0; - public static final int STATE_BRIGHTNESS_MASK = 0x7; - // Constants from SIGNAL_STRENGTH_* - public static final int STATE_PHONE_SIGNAL_STRENGTH_SHIFT = 3; - public static final int STATE_PHONE_SIGNAL_STRENGTH_MASK = 0x7 << STATE_PHONE_SIGNAL_STRENGTH_SHIFT; - // Constants from ServiceState.STATE_* - public static final int STATE_PHONE_STATE_SHIFT = 6; - public static final int STATE_PHONE_STATE_MASK = 0x7 << STATE_PHONE_STATE_SHIFT; - // Constants from DATA_CONNECTION_* - public static final int STATE_DATA_CONNECTION_SHIFT = 9; - public static final int STATE_DATA_CONNECTION_MASK = 0x1f << STATE_DATA_CONNECTION_SHIFT; - - // These states always appear directly in the first int token - // of a delta change; they should be ones that change relatively - // frequently. - public static final int STATE_CPU_RUNNING_FLAG = 1<<31; - public static final int STATE_WAKE_LOCK_FLAG = 1<<30; - public static final int STATE_GPS_ON_FLAG = 1<<29; - public static final int STATE_WIFI_FULL_LOCK_FLAG = 1<<28; - public static final int STATE_WIFI_SCAN_FLAG = 1<<27; - public static final int STATE_WIFI_MULTICAST_ON_FLAG = 1<<26; - public static final int STATE_MOBILE_RADIO_ACTIVE_FLAG = 1<<25; - // These are on the lower bits used for the command; if they change - // we need to write another int of data. - public static final int STATE_SENSOR_ON_FLAG = 1<<23; - public static final int STATE_AUDIO_ON_FLAG = 1<<22; - public static final int STATE_PHONE_SCANNING_FLAG = 1<<21; - public static final int STATE_SCREEN_ON_FLAG = 1<<20; - public static final int STATE_BATTERY_PLUGGED_FLAG = 1<<19; - public static final int STATE_PHONE_IN_CALL_FLAG = 1<<18; - public static final int STATE_BLUETOOTH_ON_FLAG = 1<<16; - - public static final int MOST_INTERESTING_STATES = - STATE_BATTERY_PLUGGED_FLAG | STATE_SCREEN_ON_FLAG - | STATE_PHONE_IN_CALL_FLAG | STATE_BLUETOOTH_ON_FLAG; - - public int states; - - // Constants from WIFI_SUPPL_STATE_* - public static final int STATE2_WIFI_SUPPL_STATE_SHIFT = 0; - public static final int STATE2_WIFI_SUPPL_STATE_MASK = 0xf; - // Values for NUM_WIFI_SIGNAL_STRENGTH_BINS - public static final int STATE2_WIFI_SIGNAL_STRENGTH_SHIFT = 4; - public static final int STATE2_WIFI_SIGNAL_STRENGTH_MASK = - 0x7 << STATE2_WIFI_SIGNAL_STRENGTH_SHIFT; - - public static final int STATE2_LOW_POWER_FLAG = 1<<31; - public static final int STATE2_VIDEO_ON_FLAG = 1<<30; - public static final int STATE2_WIFI_RUNNING_FLAG = 1<<29; - public static final int STATE2_WIFI_ON_FLAG = 1<<28; - public static final int STATE2_FLASHLIGHT_FLAG = 1<<27; - - public static final int MOST_INTERESTING_STATES2 = - STATE2_LOW_POWER_FLAG | STATE2_WIFI_ON_FLAG; - - public int states2; - - // The wake lock that was acquired at this point. - public HistoryTag wakelockTag; - - // Kernel wakeup reason at this point. - public HistoryTag wakeReasonTag; - - public static final int EVENT_FLAG_START = 0x8000; - public static final int EVENT_FLAG_FINISH = 0x4000; - - // No event in this item. - public static final int EVENT_NONE = 0x0000; - // Event is about a process that is running. - public static final int EVENT_PROC = 0x0001; - // Event is about an application package that is in the foreground. - public static final int EVENT_FOREGROUND = 0x0002; - // Event is about an application package that is at the top of the screen. - public static final int EVENT_TOP = 0x0003; - // Event is about active sync operations. - public static final int EVENT_SYNC = 0x0004; - // Events for all additional wake locks aquired/release within a wake block. - // These are not generated by default. - public static final int EVENT_WAKE_LOCK = 0x0005; - // Event is about an application executing a scheduled job. - public static final int EVENT_JOB = 0x0006; - // Events for users running. - public static final int EVENT_USER_RUNNING = 0x0007; - // Events for foreground user. - public static final int EVENT_USER_FOREGROUND = 0x0008; - // Events for connectivity changed. - public static final int EVENT_CONNECTIVITY_CHANGED = 0x0009; - // Number of event types. - public static final int EVENT_COUNT = 0x000a; - // Mask to extract out only the type part of the event. - public static final int EVENT_TYPE_MASK = ~(EVENT_FLAG_START|EVENT_FLAG_FINISH); - - public static final int EVENT_PROC_START = EVENT_PROC | EVENT_FLAG_START; - public static final int EVENT_PROC_FINISH = EVENT_PROC | EVENT_FLAG_FINISH; - public static final int EVENT_FOREGROUND_START = EVENT_FOREGROUND | EVENT_FLAG_START; - public static final int EVENT_FOREGROUND_FINISH = EVENT_FOREGROUND | EVENT_FLAG_FINISH; - public static final int EVENT_TOP_START = EVENT_TOP | EVENT_FLAG_START; - public static final int EVENT_TOP_FINISH = EVENT_TOP | EVENT_FLAG_FINISH; - public static final int EVENT_SYNC_START = EVENT_SYNC | EVENT_FLAG_START; - public static final int EVENT_SYNC_FINISH = EVENT_SYNC | EVENT_FLAG_FINISH; - public static final int EVENT_WAKE_LOCK_START = EVENT_WAKE_LOCK | EVENT_FLAG_START; - public static final int EVENT_WAKE_LOCK_FINISH = EVENT_WAKE_LOCK | EVENT_FLAG_FINISH; - public static final int EVENT_JOB_START = EVENT_JOB | EVENT_FLAG_START; - public static final int EVENT_JOB_FINISH = EVENT_JOB | EVENT_FLAG_FINISH; - public static final int EVENT_USER_RUNNING_START = EVENT_USER_RUNNING | EVENT_FLAG_START; - public static final int EVENT_USER_RUNNING_FINISH = EVENT_USER_RUNNING | EVENT_FLAG_FINISH; - public static final int EVENT_USER_FOREGROUND_START = - EVENT_USER_FOREGROUND | EVENT_FLAG_START; - public static final int EVENT_USER_FOREGROUND_FINISH = - EVENT_USER_FOREGROUND | EVENT_FLAG_FINISH; - - // For CMD_EVENT. - public int eventCode; - public HistoryTag eventTag; - - // Only set for CMD_CURRENT_TIME or CMD_RESET, as per System.currentTimeMillis(). - public long currentTime; - - // Meta-data when reading. - public int numReadInts; - - // Pre-allocated objects. - public final HistoryTag localWakelockTag = new HistoryTag(); - public final HistoryTag localWakeReasonTag = new HistoryTag(); - public final HistoryTag localEventTag = new HistoryTag(); - - public HistoryItem() { - } - - public HistoryItem(long time, Parcel src) { - this.time = time; - numReadInts = 2; - readFromParcel(src); - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - dest.writeLong(time); - int bat = (((int)cmd)&0xff) - | ((((int)batteryLevel)<<8)&0xff00) - | ((((int)batteryStatus)<<16)&0xf0000) - | ((((int)batteryHealth)<<20)&0xf00000) - | ((((int)batteryPlugType)<<24)&0xf000000) - | (wakelockTag != null ? 0x10000000 : 0) - | (wakeReasonTag != null ? 0x20000000 : 0) - | (eventCode != EVENT_NONE ? 0x40000000 : 0); - dest.writeInt(bat); - bat = (((int)batteryTemperature)&0xffff) - | ((((int)batteryVoltage)<<16)&0xffff0000); - dest.writeInt(bat); - dest.writeInt(states); - dest.writeInt(states2); - if (wakelockTag != null) { - wakelockTag.writeToParcel(dest, flags); - } - if (wakeReasonTag != null) { - wakeReasonTag.writeToParcel(dest, flags); - } - if (eventCode != EVENT_NONE) { - dest.writeInt(eventCode); - eventTag.writeToParcel(dest, flags); - } - if (cmd == CMD_CURRENT_TIME || cmd == CMD_RESET) { - dest.writeLong(currentTime); - } - } - - public void readFromParcel(Parcel src) { - int start = src.dataPosition(); - int bat = src.readInt(); - cmd = (byte)(bat&0xff); - batteryLevel = (byte)((bat>>8)&0xff); - batteryStatus = (byte)((bat>>16)&0xf); - batteryHealth = (byte)((bat>>20)&0xf); - batteryPlugType = (byte)((bat>>24)&0xf); - int bat2 = src.readInt(); - batteryTemperature = (short)(bat2&0xffff); - batteryVoltage = (char)((bat2>>16)&0xffff); - states = src.readInt(); - states2 = src.readInt(); - if ((bat&0x10000000) != 0) { - wakelockTag = localWakelockTag; - wakelockTag.readFromParcel(src); - } else { - wakelockTag = null; - } - if ((bat&0x20000000) != 0) { - wakeReasonTag = localWakeReasonTag; - wakeReasonTag.readFromParcel(src); - } else { - wakeReasonTag = null; - } - if ((bat&0x40000000) != 0) { - eventCode = src.readInt(); - eventTag = localEventTag; - eventTag.readFromParcel(src); - } else { - eventCode = EVENT_NONE; - eventTag = null; - } - if (cmd == CMD_CURRENT_TIME || cmd == CMD_RESET) { - currentTime = src.readLong(); - } else { - currentTime = 0; - } - numReadInts += (src.dataPosition()-start)/4; - } - - public void clear() { - time = 0; - cmd = CMD_NULL; - batteryLevel = 0; - batteryStatus = 0; - batteryHealth = 0; - batteryPlugType = 0; - batteryTemperature = 0; - batteryVoltage = 0; - states = 0; - states2 = 0; - wakelockTag = null; - wakeReasonTag = null; - eventCode = EVENT_NONE; - eventTag = null; - } - - public void setTo(HistoryItem o) { - time = o.time; - cmd = o.cmd; - setToCommon(o); - } - - public void setTo(long time, byte cmd, HistoryItem o) { - this.time = time; - this.cmd = cmd; - setToCommon(o); - } - - private void setToCommon(HistoryItem o) { - batteryLevel = o.batteryLevel; - batteryStatus = o.batteryStatus; - batteryHealth = o.batteryHealth; - batteryPlugType = o.batteryPlugType; - batteryTemperature = o.batteryTemperature; - batteryVoltage = o.batteryVoltage; - states = o.states; - states2 = o.states2; - if (o.wakelockTag != null) { - wakelockTag = localWakelockTag; - wakelockTag.setTo(o.wakelockTag); - } else { - wakelockTag = null; - } - if (o.wakeReasonTag != null) { - wakeReasonTag = localWakeReasonTag; - wakeReasonTag.setTo(o.wakeReasonTag); - } else { - wakeReasonTag = null; - } - eventCode = o.eventCode; - if (o.eventTag != null) { - eventTag = localEventTag; - eventTag.setTo(o.eventTag); - } else { - eventTag = null; - } - currentTime = o.currentTime; - } - - public boolean sameNonEvent(HistoryItem o) { - return batteryLevel == o.batteryLevel - && batteryStatus == o.batteryStatus - && batteryHealth == o.batteryHealth - && batteryPlugType == o.batteryPlugType - && batteryTemperature == o.batteryTemperature - && batteryVoltage == o.batteryVoltage - && states == o.states - && states2 == o.states2 - && currentTime == o.currentTime; - } - - public boolean same(HistoryItem o) { - if (!sameNonEvent(o) || eventCode != o.eventCode) { - return false; - } - if (wakelockTag != o.wakelockTag) { - if (wakelockTag == null || o.wakelockTag == null) { - return false; - } - if (!wakelockTag.equals(o.wakelockTag)) { - return false; - } - } - if (wakeReasonTag != o.wakeReasonTag) { - if (wakeReasonTag == null || o.wakeReasonTag == null) { - return false; - } - if (!wakeReasonTag.equals(o.wakeReasonTag)) { - return false; - } - } - if (eventTag != o.eventTag) { - if (eventTag == null || o.eventTag == null) { - return false; - } - if (!eventTag.equals(o.eventTag)) { - return false; - } - } - return true; - } - } - - public final static class HistoryEventTracker { - private final HashMap[] mActiveEvents - = (HashMap[]) new HashMap[HistoryItem.EVENT_COUNT]; - - public boolean updateState(int code, String name, int uid, int poolIdx) { - if ((code&HistoryItem.EVENT_FLAG_START) != 0) { - int idx = code&HistoryItem.EVENT_TYPE_MASK; - HashMap active = mActiveEvents[idx]; - if (active == null) { - active = new HashMap(); - mActiveEvents[idx] = active; - } - SparseIntArray uids = active.get(name); - if (uids == null) { - uids = new SparseIntArray(); - active.put(name, uids); - } - if (uids.indexOfKey(uid) >= 0) { - // Already set, nothing to do! - return false; - } - uids.put(uid, poolIdx); - } else if ((code&HistoryItem.EVENT_FLAG_FINISH) != 0) { - int idx = code&HistoryItem.EVENT_TYPE_MASK; - HashMap active = mActiveEvents[idx]; - if (active == null) { - // not currently active, nothing to do. - return false; - } - SparseIntArray uids = active.get(name); - if (uids == null) { - // not currently active, nothing to do. - return false; - } - idx = uids.indexOfKey(uid); - if (idx < 0) { - // not currently active, nothing to do. - return false; - } - uids.removeAt(idx); - if (uids.size() <= 0) { - active.remove(name); - } - } - return true; - } - - public void removeEvents(int code) { - int idx = code&HistoryItem.EVENT_TYPE_MASK; - mActiveEvents[idx] = null; - } - - public HashMap getStateForEvent(int code) { - return mActiveEvents[code]; - } - } - - public static final class BitDescription { - public final int mask; - public final int shift; - public final String name; - public final String shortName; - public final String[] values; - public final String[] shortValues; - - public BitDescription(int mask, String name, String shortName) { - this.mask = mask; - this.shift = -1; - this.name = name; - this.shortName = shortName; - this.values = null; - this.shortValues = null; - } - - public BitDescription(int mask, int shift, String name, String shortName, - String[] values, String[] shortValues) { - this.mask = mask; - this.shift = shift; - this.name = name; - this.shortName = shortName; - this.values = values; - this.shortValues = shortValues; - } - } - - /** - * Don't allow any more batching in to the current history event. This - * is called when printing partial histories, so to ensure that the next - * history event will go in to a new batch after what was printed in the - * last partial history. - */ - public abstract void commitCurrentHistoryBatchLocked(); - - public abstract int getHistoryTotalSize(); - - public abstract int getHistoryUsedSize(); - - public abstract boolean startIteratingHistoryLocked(); - - public abstract int getHistoryStringPoolSize(); - - public abstract int getHistoryStringPoolBytes(); - - public abstract String getHistoryTagPoolString(int index); - - public abstract int getHistoryTagPoolUid(int index); - - public abstract boolean getNextHistoryLocked(HistoryItem out); - - public abstract void finishIteratingHistoryLocked(); - - public abstract boolean startIteratingOldHistoryLocked(); - - public abstract boolean getNextOldHistoryLocked(HistoryItem out); - - public abstract void finishIteratingOldHistoryLocked(); - - /** - * Return the base time offset for the battery history. - */ - public abstract long getHistoryBaseTime(); - - /** - * Returns the number of times the device has been started. - */ - public abstract int getStartCount(); - - /** - * Returns the time in microseconds that the screen has been on while the device was - * running on battery. - * - * {@hide} - */ - public abstract long getScreenOnTime(long elapsedRealtimeUs, int which); - - /** - * Returns the number of times the screen was turned on. - * - * {@hide} - */ - public abstract int getScreenOnCount(int which); - - public abstract long getInteractiveTime(long elapsedRealtimeUs, int which); - - public static final int SCREEN_BRIGHTNESS_DARK = 0; - public static final int SCREEN_BRIGHTNESS_DIM = 1; - public static final int SCREEN_BRIGHTNESS_MEDIUM = 2; - public static final int SCREEN_BRIGHTNESS_LIGHT = 3; - public static final int SCREEN_BRIGHTNESS_BRIGHT = 4; - - static final String[] SCREEN_BRIGHTNESS_NAMES = { - "dark", "dim", "medium", "light", "bright" - }; - - static final String[] SCREEN_BRIGHTNESS_SHORT_NAMES = { - "0", "1", "2", "3", "4" - }; - - public static final int NUM_SCREEN_BRIGHTNESS_BINS = 5; - - /** - * Returns the time in microseconds that the screen has been on with - * the given brightness - * - * {@hide} - */ - public abstract long getScreenBrightnessTime(int brightnessBin, - long elapsedRealtimeUs, int which); - - /** - * Returns the time in microseconds that low power mode has been enabled while the device was - * running on battery. - * - * {@hide} - */ - public abstract long getLowPowerModeEnabledTime(long elapsedRealtimeUs, int which); - - /** - * Returns the number of times that low power mode was enabled. - * - * {@hide} - */ - public abstract int getLowPowerModeEnabledCount(int which); - - /** - * Returns the number of times that connectivity state changed. - * - * {@hide} - */ - public abstract int getNumConnectivityChange(int which); - - /** - * Returns the time in microseconds that the phone has been on while the device was - * running on battery. - * - * {@hide} - */ - public abstract long getPhoneOnTime(long elapsedRealtimeUs, int which); - - /** - * Returns the number of times a phone call was activated. - * - * {@hide} - */ - public abstract int getPhoneOnCount(int which); - - /** - * Returns the time in microseconds that the phone has been running with - * the given signal strength. - * - * {@hide} - */ - public abstract long getPhoneSignalStrengthTime(int strengthBin, - long elapsedRealtimeUs, int which); - - /** - * Returns the time in microseconds that the phone has been trying to - * acquire a signal. - * - * {@hide} - */ - public abstract long getPhoneSignalScanningTime( - long elapsedRealtimeUs, int which); - - /** - * Returns the number of times the phone has entered the given signal strength. - * - * {@hide} - */ - public abstract int getPhoneSignalStrengthCount(int strengthBin, int which); - - /** - * Returns the time in microseconds that the mobile network has been active - * (in a high power state). - * - * {@hide} - */ - public abstract long getMobileRadioActiveTime(long elapsedRealtimeUs, int which); - - /** - * Returns the number of times that the mobile network has transitioned to the - * active state. - * - * {@hide} - */ - public abstract int getMobileRadioActiveCount(int which); - - /** - * Returns the time in microseconds that is the difference between the mobile radio - * time we saw based on the elapsed timestamp when going down vs. the given time stamp - * from the radio. - * - * {@hide} - */ - public abstract long getMobileRadioActiveAdjustedTime(int which); - - /** - * Returns the time in microseconds that the mobile network has been active - * (in a high power state) but not being able to blame on an app. - * - * {@hide} - */ - public abstract long getMobileRadioActiveUnknownTime(int which); - - /** - * Return count of number of times radio was up that could not be blamed on apps. - * - * {@hide} - */ - public abstract int getMobileRadioActiveUnknownCount(int which); - - public static final int DATA_CONNECTION_NONE = 0; - public static final int DATA_CONNECTION_GPRS = 1; - public static final int DATA_CONNECTION_EDGE = 2; - public static final int DATA_CONNECTION_UMTS = 3; - public static final int DATA_CONNECTION_CDMA = 4; - public static final int DATA_CONNECTION_EVDO_0 = 5; - public static final int DATA_CONNECTION_EVDO_A = 6; - public static final int DATA_CONNECTION_1xRTT = 7; - public static final int DATA_CONNECTION_HSDPA = 8; - public static final int DATA_CONNECTION_HSUPA = 9; - public static final int DATA_CONNECTION_HSPA = 10; - public static final int DATA_CONNECTION_IDEN = 11; - public static final int DATA_CONNECTION_EVDO_B = 12; - public static final int DATA_CONNECTION_LTE = 13; - public static final int DATA_CONNECTION_EHRPD = 14; - public static final int DATA_CONNECTION_HSPAP = 15; - public static final int DATA_CONNECTION_OTHER = 16; - - static final String[] DATA_CONNECTION_NAMES = { - "none", "gprs", "edge", "umts", "cdma", "evdo_0", "evdo_A", - "1xrtt", "hsdpa", "hsupa", "hspa", "iden", "evdo_b", "lte", - "ehrpd", "hspap", "other" - }; - - public static final int NUM_DATA_CONNECTION_TYPES = DATA_CONNECTION_OTHER+1; - - /** - * Returns the time in microseconds that the phone has been running with - * the given data connection. - * - * {@hide} - */ - public abstract long getPhoneDataConnectionTime(int dataType, - long elapsedRealtimeUs, int which); - - /** - * Returns the number of times the phone has entered the given data - * connection type. - * - * {@hide} - */ - public abstract int getPhoneDataConnectionCount(int dataType, int which); - - public static final int WIFI_SUPPL_STATE_INVALID = 0; - public static final int WIFI_SUPPL_STATE_DISCONNECTED = 1; - public static final int WIFI_SUPPL_STATE_INTERFACE_DISABLED = 2; - public static final int WIFI_SUPPL_STATE_INACTIVE = 3; - public static final int WIFI_SUPPL_STATE_SCANNING = 4; - public static final int WIFI_SUPPL_STATE_AUTHENTICATING = 5; - public static final int WIFI_SUPPL_STATE_ASSOCIATING = 6; - public static final int WIFI_SUPPL_STATE_ASSOCIATED = 7; - public static final int WIFI_SUPPL_STATE_FOUR_WAY_HANDSHAKE = 8; - public static final int WIFI_SUPPL_STATE_GROUP_HANDSHAKE = 9; - public static final int WIFI_SUPPL_STATE_COMPLETED = 10; - public static final int WIFI_SUPPL_STATE_DORMANT = 11; - public static final int WIFI_SUPPL_STATE_UNINITIALIZED = 12; - - public static final int NUM_WIFI_SUPPL_STATES = WIFI_SUPPL_STATE_UNINITIALIZED+1; - - static final String[] WIFI_SUPPL_STATE_NAMES = { - "invalid", "disconn", "disabled", "inactive", "scanning", - "authenticating", "associating", "associated", "4-way-handshake", - "group-handshake", "completed", "dormant", "uninit" - }; - - static final String[] WIFI_SUPPL_STATE_SHORT_NAMES = { - "inv", "dsc", "dis", "inact", "scan", - "auth", "ascing", "asced", "4-way", - "group", "compl", "dorm", "uninit" - }; - - public static final BitDescription[] HISTORY_STATE_DESCRIPTIONS - = new BitDescription[] { - new BitDescription(HistoryItem.STATE_CPU_RUNNING_FLAG, "running", "r"), - new BitDescription(HistoryItem.STATE_WAKE_LOCK_FLAG, "wake_lock", "w"), - new BitDescription(HistoryItem.STATE_SENSOR_ON_FLAG, "sensor", "s"), - new BitDescription(HistoryItem.STATE_GPS_ON_FLAG, "gps", "g"), - new BitDescription(HistoryItem.STATE_WIFI_FULL_LOCK_FLAG, "wifi_full_lock", "Wl"), - new BitDescription(HistoryItem.STATE_WIFI_SCAN_FLAG, "wifi_scan", "Ws"), - new BitDescription(HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG, "wifi_multicast", "Wm"), - new BitDescription(HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG, "mobile_radio", "Pr"), - new BitDescription(HistoryItem.STATE_PHONE_SCANNING_FLAG, "phone_scanning", "Psc"), - new BitDescription(HistoryItem.STATE_AUDIO_ON_FLAG, "audio", "a"), - new BitDescription(HistoryItem.STATE_SCREEN_ON_FLAG, "screen", "S"), - new BitDescription(HistoryItem.STATE_BATTERY_PLUGGED_FLAG, "plugged", "BP"), - new BitDescription(HistoryItem.STATE_PHONE_IN_CALL_FLAG, "phone_in_call", "Pcl"), - new BitDescription(HistoryItem.STATE_BLUETOOTH_ON_FLAG, "bluetooth", "b"), - new BitDescription(HistoryItem.STATE_DATA_CONNECTION_MASK, - HistoryItem.STATE_DATA_CONNECTION_SHIFT, "data_conn", "Pcn", - DATA_CONNECTION_NAMES, DATA_CONNECTION_NAMES), - new BitDescription(HistoryItem.STATE_PHONE_STATE_MASK, - HistoryItem.STATE_PHONE_STATE_SHIFT, "phone_state", "Pst", - new String[] {"in", "out", "emergency", "off"}, - new String[] {"in", "out", "em", "off"}), - new BitDescription(HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_MASK, - HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_SHIFT, "phone_signal_strength", "Pss", - SignalStrength.SIGNAL_STRENGTH_NAMES, - new String[] { "0", "1", "2", "3", "4" }), - new BitDescription(HistoryItem.STATE_BRIGHTNESS_MASK, - HistoryItem.STATE_BRIGHTNESS_SHIFT, "brightness", "Sb", - SCREEN_BRIGHTNESS_NAMES, SCREEN_BRIGHTNESS_SHORT_NAMES), - }; - - public static final BitDescription[] HISTORY_STATE2_DESCRIPTIONS - = new BitDescription[] { - new BitDescription(HistoryItem.STATE2_LOW_POWER_FLAG, "low_power", "lp"), - new BitDescription(HistoryItem.STATE2_VIDEO_ON_FLAG, "video", "v"), - new BitDescription(HistoryItem.STATE2_WIFI_RUNNING_FLAG, "wifi_running", "Wr"), - new BitDescription(HistoryItem.STATE2_WIFI_ON_FLAG, "wifi", "W"), - new BitDescription(HistoryItem.STATE2_FLASHLIGHT_FLAG, "flashlight", "fl"), - new BitDescription(HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_MASK, - HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_SHIFT, "wifi_signal_strength", "Wss", - new String[] { "0", "1", "2", "3", "4" }, - new String[] { "0", "1", "2", "3", "4" }), - new BitDescription(HistoryItem.STATE2_WIFI_SUPPL_STATE_MASK, - HistoryItem.STATE2_WIFI_SUPPL_STATE_SHIFT, "wifi_suppl", "Wsp", - WIFI_SUPPL_STATE_NAMES, WIFI_SUPPL_STATE_SHORT_NAMES), - }; - - public static final String[] HISTORY_EVENT_NAMES = new String[] { - "null", "proc", "fg", "top", "sync", "wake_lock_in", "job", "user", "userfg", "conn" - }; - - public static final String[] HISTORY_EVENT_CHECKIN_NAMES = new String[] { - "Enl", "Epr", "Efg", "Etp", "Esy", "Ewl", "Ejb", "Eur", "Euf", "Ecn" - }; - - /** - * Returns the time in microseconds that wifi has been on while the device was - * running on battery. - * - * {@hide} - */ - public abstract long getWifiOnTime(long elapsedRealtimeUs, int which); - - /** - * Returns the time in microseconds that wifi has been on and the driver has - * been in the running state while the device was running on battery. - * - * {@hide} - */ - public abstract long getGlobalWifiRunningTime(long elapsedRealtimeUs, int which); - - public static final int WIFI_STATE_OFF = 0; - public static final int WIFI_STATE_OFF_SCANNING = 1; - public static final int WIFI_STATE_ON_NO_NETWORKS = 2; - public static final int WIFI_STATE_ON_DISCONNECTED = 3; - public static final int WIFI_STATE_ON_CONNECTED_STA = 4; - public static final int WIFI_STATE_ON_CONNECTED_P2P = 5; - public static final int WIFI_STATE_ON_CONNECTED_STA_P2P = 6; - public static final int WIFI_STATE_SOFT_AP = 7; - - static final String[] WIFI_STATE_NAMES = { - "off", "scanning", "no_net", "disconn", - "sta", "p2p", "sta_p2p", "soft_ap" - }; - - public static final int NUM_WIFI_STATES = WIFI_STATE_SOFT_AP+1; - - /** - * Returns the time in microseconds that WiFi has been running in the given state. - * - * {@hide} - */ - public abstract long getWifiStateTime(int wifiState, - long elapsedRealtimeUs, int which); - - /** - * Returns the number of times that WiFi has entered the given state. - * - * {@hide} - */ - public abstract int getWifiStateCount(int wifiState, int which); - - /** - * Returns the time in microseconds that the wifi supplicant has been - * in a given state. - * - * {@hide} - */ - public abstract long getWifiSupplStateTime(int state, long elapsedRealtimeUs, int which); - - /** - * Returns the number of times that the wifi supplicant has transitioned - * to a given state. - * - * {@hide} - */ - public abstract int getWifiSupplStateCount(int state, int which); - - public static final int NUM_WIFI_SIGNAL_STRENGTH_BINS = 5; - - /** - * Returns the time in microseconds that WIFI has been running with - * the given signal strength. - * - * {@hide} - */ - public abstract long getWifiSignalStrengthTime(int strengthBin, - long elapsedRealtimeUs, int which); - - /** - * Returns the number of times WIFI has entered the given signal strength. - * - * {@hide} - */ - public abstract int getWifiSignalStrengthCount(int strengthBin, int which); - - /** - * Returns the time in microseconds that bluetooth has been on while the device was - * running on battery. - * - * {@hide} - */ - public abstract long getBluetoothOnTime(long elapsedRealtimeUs, int which); - - public abstract int getBluetoothPingCount(); - - public static final int BLUETOOTH_STATE_INACTIVE = 0; - public static final int BLUETOOTH_STATE_LOW = 1; - public static final int BLUETOOTH_STATE_MEDIUM = 2; - public static final int BLUETOOTH_STATE_HIGH = 3; - - static final String[] BLUETOOTH_STATE_NAMES = { - "inactive", "low", "med", "high" - }; - - public static final int NUM_BLUETOOTH_STATES = BLUETOOTH_STATE_HIGH +1; - - /** - * Returns the time in microseconds that Bluetooth has been running in the - * given active state. - * - * {@hide} - */ - public abstract long getBluetoothStateTime(int bluetoothState, - long elapsedRealtimeUs, int which); - - /** - * Returns the number of times that Bluetooth has entered the given active state. - * - * {@hide} - */ - public abstract int getBluetoothStateCount(int bluetoothState, int which); - - /** - * Returns the time in microseconds that the flashlight has been on while the device was - * running on battery. - * - * {@hide} - */ - public abstract long getFlashlightOnTime(long elapsedRealtimeUs, int which); - - /** - * Returns the number of times that the flashlight has been turned on while the device was - * running on battery. - * - * {@hide} - */ - public abstract long getFlashlightOnCount(int which); - - public static final int NETWORK_MOBILE_RX_DATA = 0; - public static final int NETWORK_MOBILE_TX_DATA = 1; - public static final int NETWORK_WIFI_RX_DATA = 2; - public static final int NETWORK_WIFI_TX_DATA = 3; - - public static final int NUM_NETWORK_ACTIVITY_TYPES = NETWORK_WIFI_TX_DATA + 1; - - public abstract long getNetworkActivityBytes(int type, int which); - public abstract long getNetworkActivityPackets(int type, int which); - - /** - * Return the wall clock time when battery stats data collection started. - */ - public abstract long getStartClockTime(); - - /** - * Return platform version tag that we were running in when the battery stats started. - */ - public abstract String getStartPlatformVersion(); - - /** - * Return platform version tag that we were running in when the battery stats ended. - */ - public abstract String getEndPlatformVersion(); - - /** - * Return the internal version code of the parcelled format. - */ - public abstract int getParcelVersion(); - - /** - * Return whether we are currently running on battery. - */ - public abstract boolean getIsOnBattery(); - - /** - * Returns a SparseArray containing the statistics for each uid. - */ - public abstract SparseArray getUidStats(); - - /** - * Returns the current battery uptime in microseconds. - * - * @param curTime the amount of elapsed realtime in microseconds. - */ - public abstract long getBatteryUptime(long curTime); - - /** - * Returns the current battery realtime in microseconds. - * - * @param curTime the amount of elapsed realtime in microseconds. - */ - public abstract long getBatteryRealtime(long curTime); - - /** - * Returns the battery percentage level at the last time the device was unplugged from power, or - * the last time it booted on battery power. - */ - public abstract int getDischargeStartLevel(); - - /** - * Returns the current battery percentage level if we are in a discharge cycle, otherwise - * returns the level at the last plug event. - */ - public abstract int getDischargeCurrentLevel(); - - /** - * Get the amount the battery has discharged since the stats were - * last reset after charging, as a lower-end approximation. - */ - public abstract int getLowDischargeAmountSinceCharge(); - - /** - * Get the amount the battery has discharged since the stats were - * last reset after charging, as an upper-end approximation. - */ - public abstract int getHighDischargeAmountSinceCharge(); - - /** - * Retrieve the discharge amount over the selected discharge period which. - */ - public abstract int getDischargeAmount(int which); - - /** - * Get the amount the battery has discharged while the screen was on, - * since the last time power was unplugged. - */ - public abstract int getDischargeAmountScreenOn(); - - /** - * Get the amount the battery has discharged while the screen was on, - * since the last time the device was charged. - */ - public abstract int getDischargeAmountScreenOnSinceCharge(); - - /** - * Get the amount the battery has discharged while the screen was off, - * since the last time power was unplugged. - */ - public abstract int getDischargeAmountScreenOff(); - - /** - * Get the amount the battery has discharged while the screen was off, - * since the last time the device was charged. - */ - public abstract int getDischargeAmountScreenOffSinceCharge(); - - /** - * Returns the total, last, or current battery uptime in microseconds. - * - * @param curTime the elapsed realtime in microseconds. - * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. - */ - public abstract long computeBatteryUptime(long curTime, int which); - - /** - * Returns the total, last, or current battery realtime in microseconds. - * - * @param curTime the current elapsed realtime in microseconds. - * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. - */ - public abstract long computeBatteryRealtime(long curTime, int which); - - /** - * Returns the total, last, or current battery screen off uptime in microseconds. - * - * @param curTime the elapsed realtime in microseconds. - * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. - */ - public abstract long computeBatteryScreenOffUptime(long curTime, int which); - - /** - * Returns the total, last, or current battery screen off realtime in microseconds. - * - * @param curTime the current elapsed realtime in microseconds. - * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. - */ - public abstract long computeBatteryScreenOffRealtime(long curTime, int which); - - /** - * Returns the total, last, or current uptime in microseconds. - * - * @param curTime the current elapsed realtime in microseconds. - * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. - */ - public abstract long computeUptime(long curTime, int which); - - /** - * Returns the total, last, or current realtime in microseconds. - * - * @param curTime the current elapsed realtime in microseconds. - * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. - */ - public abstract long computeRealtime(long curTime, int which); - - /** - * Compute an approximation for how much run time (in microseconds) is remaining on - * the battery. Returns -1 if no time can be computed: either there is not - * enough current data to make a decision, or the battery is currently - * charging. - * - * @param curTime The current elepsed realtime in microseconds. - */ - public abstract long computeBatteryTimeRemaining(long curTime); - - // The part of a step duration that is the actual time. - public static final long STEP_LEVEL_TIME_MASK = 0x000000ffffffffffL; - - // Bits in a step duration that are the new battery level we are at. - public static final long STEP_LEVEL_LEVEL_MASK = 0x0000ff0000000000L; - public static final long STEP_LEVEL_LEVEL_SHIFT = 40; - - // Bits in a step duration that are the initial mode we were in at that step. - public static final long STEP_LEVEL_INITIAL_MODE_MASK = 0x00ff000000000000L; - public static final long STEP_LEVEL_INITIAL_MODE_SHIFT = 48; - - // Bits in a step duration that indicate which modes changed during that step. - public static final long STEP_LEVEL_MODIFIED_MODE_MASK = 0xff00000000000000L; - public static final long STEP_LEVEL_MODIFIED_MODE_SHIFT = 56; - - // Step duration mode: the screen is on, off, dozed, etc; value is Display.STATE_* - 1. - public static final int STEP_LEVEL_MODE_SCREEN_STATE = 0x03; - - // Step duration mode: power save is on. - public static final int STEP_LEVEL_MODE_POWER_SAVE = 0x04; - - /** - * Return the historical number of discharge steps we currently have. - */ - public abstract int getNumDischargeStepDurations(); - - /** - * Return the array of discharge step durations; the number of valid - * items in it is returned by {@link #getNumDischargeStepDurations()}. - * These values are in milliseconds. - */ - public abstract long[] getDischargeStepDurationsArray(); - - /** - * Compute an approximation for how much time (in microseconds) remains until the battery - * is fully charged. Returns -1 if no time can be computed: either there is not - * enough current data to make a decision, or the battery is currently - * discharging. - * - * @param curTime The current elepsed realtime in microseconds. - */ - public abstract long computeChargeTimeRemaining(long curTime); - - /** - * Return the historical number of charge steps we currently have. - */ - public abstract int getNumChargeStepDurations(); - - /** - * Return the array of charge step durations; the number of valid - * items in it is returned by {@link #getNumChargeStepDurations()}. - * These values are in milliseconds. - */ - public abstract long[] getChargeStepDurationsArray(); - - public abstract Map getWakeupReasonStats(); - - public abstract Map getKernelWakelockStats(); - - /** Returns the number of different speeds that the CPU can run at */ - public abstract int getCpuSpeedSteps(); - - public abstract void writeToParcelWithoutUids(Parcel out, int flags); - - private final static void formatTimeRaw(StringBuilder out, long seconds) { - long days = seconds / (60 * 60 * 24); - if (days != 0) { - out.append(days); - out.append("d "); - } - long used = days * 60 * 60 * 24; - - long hours = (seconds - used) / (60 * 60); - if (hours != 0 || used != 0) { - out.append(hours); - out.append("h "); - } - used += hours * 60 * 60; - - long mins = (seconds-used) / 60; - if (mins != 0 || used != 0) { - out.append(mins); - out.append("m "); - } - used += mins * 60; - - if (seconds != 0 || used != 0) { - out.append(seconds-used); - out.append("s "); - } - } - - public final static void formatTime(StringBuilder sb, long time) { - long sec = time / 100; - formatTimeRaw(sb, sec); - sb.append((time - (sec * 100)) * 10); - sb.append("ms "); - } - - public final static void formatTimeMs(StringBuilder sb, long time) { - long sec = time / 1000; - formatTimeRaw(sb, sec); - sb.append(time - (sec * 1000)); - sb.append("ms "); - } - - public final static void formatTimeMsNoSpace(StringBuilder sb, long time) { - long sec = time / 1000; - formatTimeRaw(sb, sec); - sb.append(time - (sec * 1000)); - sb.append("ms"); - } - - public final String formatRatioLocked(long num, long den) { - if (den == 0L) { - return "--%"; - } - float perc = ((float)num) / ((float)den) * 100; - mFormatBuilder.setLength(0); - mFormatter.format("%.1f%%", perc); - return mFormatBuilder.toString(); - } - - final String formatBytesLocked(long bytes) { - mFormatBuilder.setLength(0); - - if (bytes < BYTES_PER_KB) { - return bytes + "B"; - } else if (bytes < BYTES_PER_MB) { - mFormatter.format("%.2fKB", bytes / (double) BYTES_PER_KB); - return mFormatBuilder.toString(); - } else if (bytes < BYTES_PER_GB){ - mFormatter.format("%.2fMB", bytes / (double) BYTES_PER_MB); - return mFormatBuilder.toString(); - } else { - mFormatter.format("%.2fGB", bytes / (double) BYTES_PER_GB); - return mFormatBuilder.toString(); - } - } - - private static long computeWakeLock(Timer timer, long elapsedRealtimeUs, int which) { - if (timer != null) { - // Convert from microseconds to milliseconds with rounding - long totalTimeMicros = timer.getTotalTimeLocked(elapsedRealtimeUs, which); - long totalTimeMillis = (totalTimeMicros + 500) / 1000; - return totalTimeMillis; - } - return 0; - } - - /** - * - * @param sb a StringBuilder object. - * @param timer a Timer object contining the wakelock times. - * @param elapsedRealtimeUs the current on-battery time in microseconds. - * @param name the name of the wakelock. - * @param which which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. - * @param linePrefix a String to be prepended to each line of output. - * @return the line prefix - */ - private static final String printWakeLock(StringBuilder sb, Timer timer, - long elapsedRealtimeUs, String name, int which, String linePrefix) { - - if (timer != null) { - long totalTimeMillis = computeWakeLock(timer, elapsedRealtimeUs, which); - - int count = timer.getCountLocked(which); - if (totalTimeMillis != 0) { - sb.append(linePrefix); - formatTimeMs(sb, totalTimeMillis); - if (name != null) { - sb.append(name); - sb.append(' '); - } - sb.append('('); - sb.append(count); - sb.append(" times)"); - return ", "; - } - } - return linePrefix; - } - - /** - * Checkin version of wakelock printer. Prints simple comma-separated list. - * - * @param sb a StringBuilder object. - * @param timer a Timer object contining the wakelock times. - * @param elapsedRealtimeUs the current time in microseconds. - * @param name the name of the wakelock. - * @param which which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. - * @param linePrefix a String to be prepended to each line of output. - * @return the line prefix - */ - private static final String printWakeLockCheckin(StringBuilder sb, Timer timer, - long elapsedRealtimeUs, String name, int which, String linePrefix) { - long totalTimeMicros = 0; - int count = 0; - if (timer != null) { - totalTimeMicros = timer.getTotalTimeLocked(elapsedRealtimeUs, which); - count = timer.getCountLocked(which); - } - sb.append(linePrefix); - sb.append((totalTimeMicros + 500) / 1000); // microseconds to milliseconds with rounding - sb.append(','); - sb.append(name != null ? name + "," : ""); - sb.append(count); - return ","; - } - - /** - * Dump a comma-separated line of values for terse checkin mode. - * - * @param pw the PageWriter to dump log to - * @param category category of data (e.g. "total", "last", "unplugged", "current" ) - * @param type type of data (e.g. "wakelock", "sensor", "process", "apk" , "process", "network") - * @param args type-dependent data arguments - */ - private static final void dumpLine(PrintWriter pw, int uid, String category, String type, - Object... args ) { - pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(','); - pw.print(uid); pw.print(','); - pw.print(category); pw.print(','); - pw.print(type); - - for (Object arg : args) { - pw.print(','); - pw.print(arg); - } - pw.println(); - } - - /** - * Temporary for settings. - */ - public final void dumpCheckinLocked(Context context, PrintWriter pw, int which, int reqUid) { - dumpCheckinLocked(context, pw, which, reqUid, BatteryStatsHelper.checkWifiOnly(context)); - } - - /** - * Checkin server version of dump to produce more compact, computer-readable log. - * - * NOTE: all times are expressed in 'ms'. - */ - public final void dumpCheckinLocked(Context context, PrintWriter pw, int which, int reqUid, - boolean wifiOnly) { - final long rawUptime = SystemClock.uptimeMillis() * 1000; - final long rawRealtime = SystemClock.elapsedRealtime() * 1000; - final long batteryUptime = getBatteryUptime(rawUptime); - final long whichBatteryUptime = computeBatteryUptime(rawUptime, which); - final long whichBatteryRealtime = computeBatteryRealtime(rawRealtime, which); - final long whichBatteryScreenOffUptime = computeBatteryScreenOffUptime(rawUptime, which); - final long whichBatteryScreenOffRealtime = computeBatteryScreenOffRealtime(rawRealtime, - which); - final long totalRealtime = computeRealtime(rawRealtime, which); - final long totalUptime = computeUptime(rawUptime, which); - final long screenOnTime = getScreenOnTime(rawRealtime, which); - final long interactiveTime = getInteractiveTime(rawRealtime, which); - final long lowPowerModeEnabledTime = getLowPowerModeEnabledTime(rawRealtime, which); - final int connChanges = getNumConnectivityChange(which); - final long phoneOnTime = getPhoneOnTime(rawRealtime, which); - final long wifiOnTime = getWifiOnTime(rawRealtime, which); - final long wifiRunningTime = getGlobalWifiRunningTime(rawRealtime, which); - final long bluetoothOnTime = getBluetoothOnTime(rawRealtime, which); - - StringBuilder sb = new StringBuilder(128); - - SparseArray uidStats = getUidStats(); - final int NU = uidStats.size(); - - String category = STAT_NAMES[which]; - - // Dump "battery" stat - dumpLine(pw, 0 /* uid */, category, BATTERY_DATA, - which == STATS_SINCE_CHARGED ? getStartCount() : "N/A", - whichBatteryRealtime / 1000, whichBatteryUptime / 1000, - totalRealtime / 1000, totalUptime / 1000, - getStartClockTime(), - whichBatteryScreenOffRealtime / 1000, whichBatteryScreenOffUptime / 1000); - - // Calculate wakelock times across all uids. - long fullWakeLockTimeTotal = 0; - long partialWakeLockTimeTotal = 0; - - for (int iu = 0; iu < NU; iu++) { - Uid u = uidStats.valueAt(iu); - - Map wakelocks = u.getWakelockStats(); - if (wakelocks.size() > 0) { - for (Map.Entry ent - : wakelocks.entrySet()) { - Uid.Wakelock wl = ent.getValue(); - - Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL); - if (fullWakeTimer != null) { - fullWakeLockTimeTotal += fullWakeTimer.getTotalTimeLocked(rawRealtime, - which); - } - - Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL); - if (partialWakeTimer != null) { - partialWakeLockTimeTotal += partialWakeTimer.getTotalTimeLocked( - rawRealtime, which); - } - } - } - } - - long mobileRxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which); - long mobileTxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which); - long wifiRxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which); - long wifiTxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which); - long mobileRxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which); - long mobileTxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which); - long wifiRxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which); - long wifiTxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which); - - // Dump network stats - dumpLine(pw, 0 /* uid */, category, GLOBAL_NETWORK_DATA, - mobileRxTotalBytes, mobileTxTotalBytes, wifiRxTotalBytes, wifiTxTotalBytes, - mobileRxTotalPackets, mobileTxTotalPackets, wifiRxTotalPackets, wifiTxTotalPackets); - - // Dump misc stats - dumpLine(pw, 0 /* uid */, category, MISC_DATA, - screenOnTime / 1000, phoneOnTime / 1000, wifiOnTime / 1000, - wifiRunningTime / 1000, bluetoothOnTime / 1000, - mobileRxTotalBytes, mobileTxTotalBytes, wifiRxTotalBytes, wifiTxTotalBytes, - fullWakeLockTimeTotal / 1000, partialWakeLockTimeTotal / 1000, - 0 /*legacy input event count*/, getMobileRadioActiveTime(rawRealtime, which) / 1000, - getMobileRadioActiveAdjustedTime(which) / 1000, interactiveTime / 1000, - lowPowerModeEnabledTime / 1000, connChanges); - - // Dump screen brightness stats - Object[] args = new Object[NUM_SCREEN_BRIGHTNESS_BINS]; - for (int i=0; i kernelWakelocks = getKernelWakelockStats(); - if (kernelWakelocks.size() > 0) { - for (Map.Entry ent : kernelWakelocks.entrySet()) { - sb.setLength(0); - printWakeLockCheckin(sb, ent.getValue(), rawRealtime, null, which, ""); - dumpLine(pw, 0 /* uid */, category, KERNEL_WAKELOCK_DATA, ent.getKey(), - sb.toString()); - } - } - Map wakeupReasons = getWakeupReasonStats(); - if (wakeupReasons.size() > 0) { - for (Map.Entry ent : wakeupReasons.entrySet()) { - // Not doing the regular wake lock formatting to remain compatible - // with the old checkin format. - long totalTimeMicros = ent.getValue().getTotalTimeLocked(rawRealtime, which); - int count = ent.getValue().getCountLocked(which); - dumpLine(pw, 0 /* uid */, category, WAKEUP_REASON_DATA, - "\"" + ent.getKey() + "\"", (totalTimeMicros + 500) / 1000, count); - } - } - } - - BatteryStatsHelper helper = new BatteryStatsHelper(context, false, wifiOnly); - helper.create(this); - helper.refreshStats(which, UserHandle.USER_ALL); - List sippers = helper.getUsageList(); - if (sippers != null && sippers.size() > 0) { - dumpLine(pw, 0 /* uid */, category, POWER_USE_SUMMARY_DATA, - BatteryStatsHelper.makemAh(helper.getPowerProfile().getBatteryCapacity()), - BatteryStatsHelper.makemAh(helper.getComputedPower()), - BatteryStatsHelper.makemAh(helper.getMinDrainedPower()), - BatteryStatsHelper.makemAh(helper.getMaxDrainedPower())); - for (int i=0; i= 0 && uid != reqUid) { - continue; - } - Uid u = uidStats.valueAt(iu); - // Dump Network stats per uid, if any - long mobileBytesRx = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which); - long mobileBytesTx = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which); - long wifiBytesRx = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which); - long wifiBytesTx = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which); - long mobilePacketsRx = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which); - long mobilePacketsTx = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which); - long mobileActiveTime = u.getMobileRadioActiveTime(which); - int mobileActiveCount = u.getMobileRadioActiveCount(which); - long wifiPacketsRx = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which); - long wifiPacketsTx = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which); - long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which); - long wifiScanTime = u.getWifiScanTime(rawRealtime, which); - long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which); - - if (mobileBytesRx > 0 || mobileBytesTx > 0 || wifiBytesRx > 0 || wifiBytesTx > 0 - || mobilePacketsRx > 0 || mobilePacketsTx > 0 || wifiPacketsRx > 0 - || wifiPacketsTx > 0 || mobileActiveTime > 0 || mobileActiveCount > 0) { - dumpLine(pw, uid, category, NETWORK_DATA, mobileBytesRx, mobileBytesTx, - wifiBytesRx, wifiBytesTx, - mobilePacketsRx, mobilePacketsTx, - wifiPacketsRx, wifiPacketsTx, - mobileActiveTime, mobileActiveCount); - } - - if (fullWifiLockOnTime != 0 || wifiScanTime != 0 - || uidWifiRunningTime != 0) { - dumpLine(pw, uid, category, WIFI_DATA, - fullWifiLockOnTime, wifiScanTime, uidWifiRunningTime); - } - - if (u.hasUserActivity()) { - args = new Object[Uid.NUM_USER_ACTIVITY_TYPES]; - boolean hasData = false; - for (int i=0; i wakelocks = u.getWakelockStats(); - if (wakelocks.size() > 0) { - for (Map.Entry ent : wakelocks.entrySet()) { - Uid.Wakelock wl = ent.getValue(); - String linePrefix = ""; - sb.setLength(0); - linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_FULL), - rawRealtime, "f", which, linePrefix); - linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), - rawRealtime, "p", which, linePrefix); - linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), - rawRealtime, "w", which, linePrefix); - - // Only log if we had at lease one wakelock... - if (sb.length() > 0) { - String name = ent.getKey(); - if (name.indexOf(',') >= 0) { - name = name.replace(',', '_'); - } - dumpLine(pw, uid, category, WAKELOCK_DATA, name, sb.toString()); - } - } - } - - Map syncs = u.getSyncStats(); - if (syncs.size() > 0) { - for (Map.Entry ent : syncs.entrySet()) { - Timer timer = ent.getValue(); - // Convert from microseconds to milliseconds with rounding - long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000; - int count = timer.getCountLocked(which); - if (totalTime != 0) { - dumpLine(pw, uid, category, SYNC_DATA, ent.getKey(), totalTime, count); - } - } - } - - Map jobs = u.getJobStats(); - if (jobs.size() > 0) { - for (Map.Entry ent : jobs.entrySet()) { - Timer timer = ent.getValue(); - // Convert from microseconds to milliseconds with rounding - long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000; - int count = timer.getCountLocked(which); - if (totalTime != 0) { - dumpLine(pw, uid, category, JOB_DATA, ent.getKey(), totalTime, count); - } - } - } - - SparseArray sensors = u.getSensorStats(); - int NSE = sensors.size(); - for (int ise=0; ise 0) { - dumpLine(pw, uid, category, STATE_TIME_DATA, stateTimes); - } - - Map processStats = u.getProcessStats(); - if (processStats.size() > 0) { - for (Map.Entry ent - : processStats.entrySet()) { - Uid.Proc ps = ent.getValue(); - - final long userMillis = ps.getUserTime(which) * 10; - final long systemMillis = ps.getSystemTime(which) * 10; - final long foregroundMillis = ps.getForegroundTime(which) * 10; - final int starts = ps.getStarts(which); - final int numCrashes = ps.getNumCrashes(which); - final int numAnrs = ps.getNumAnrs(which); - - if (userMillis != 0 || systemMillis != 0 || foregroundMillis != 0 - || starts != 0 || numAnrs != 0 || numCrashes != 0) { - dumpLine(pw, uid, category, PROCESS_DATA, ent.getKey(), userMillis, - systemMillis, foregroundMillis, starts, numAnrs, numCrashes); - } - } - } - - Map packageStats = u.getPackageStats(); - if (packageStats.size() > 0) { - for (Map.Entry ent - : packageStats.entrySet()) { - - Uid.Pkg ps = ent.getValue(); - int wakeups = ps.getWakeups(which); - Map serviceStats = ps.getServiceStats(); - for (Map.Entry sent - : serviceStats.entrySet()) { - BatteryStats.Uid.Pkg.Serv ss = sent.getValue(); - long startTime = ss.getStartTime(batteryUptime, which); - int starts = ss.getStarts(which); - int launches = ss.getLaunches(which); - if (startTime != 0 || starts != 0 || launches != 0) { - dumpLine(pw, uid, category, APK_DATA, - wakeups, // wakeup alarms - ent.getKey(), // Apk - sent.getKey(), // service - startTime / 1000, // time spent started, in ms - starts, - launches); - } - } - } - } - } - } - - static final class TimerEntry { - final String mName; - final int mId; - final BatteryStats.Timer mTimer; - final long mTime; - TimerEntry(String name, int id, BatteryStats.Timer timer, long time) { - mName = name; - mId = id; - mTimer = timer; - mTime = time; - } - } - - private void printmAh(PrintWriter printer, double power) { - printer.print(BatteryStatsHelper.makemAh(power)); - } - - /** - * Temporary for settings. - */ - public final void dumpLocked(Context context, PrintWriter pw, String prefix, int which, - int reqUid) { - dumpLocked(context, pw, prefix, which, reqUid, BatteryStatsHelper.checkWifiOnly(context)); - } - - @SuppressWarnings("unused") - public final void dumpLocked(Context context, PrintWriter pw, String prefix, final int which, - int reqUid, boolean wifiOnly) { - final long rawUptime = SystemClock.uptimeMillis() * 1000; - final long rawRealtime = SystemClock.elapsedRealtime() * 1000; - final long batteryUptime = getBatteryUptime(rawUptime); - - final long whichBatteryUptime = computeBatteryUptime(rawUptime, which); - final long whichBatteryRealtime = computeBatteryRealtime(rawRealtime, which); - final long totalRealtime = computeRealtime(rawRealtime, which); - final long totalUptime = computeUptime(rawUptime, which); - final long whichBatteryScreenOffUptime = computeBatteryScreenOffUptime(rawUptime, which); - final long whichBatteryScreenOffRealtime = computeBatteryScreenOffRealtime(rawRealtime, - which); - final long batteryTimeRemaining = computeBatteryTimeRemaining(rawRealtime); - final long chargeTimeRemaining = computeChargeTimeRemaining(rawRealtime); - - StringBuilder sb = new StringBuilder(128); - - SparseArray uidStats = getUidStats(); - final int NU = uidStats.size(); - - sb.setLength(0); - sb.append(prefix); - sb.append(" Time on battery: "); - formatTimeMs(sb, whichBatteryRealtime / 1000); sb.append("("); - sb.append(formatRatioLocked(whichBatteryRealtime, totalRealtime)); - sb.append(") realtime, "); - formatTimeMs(sb, whichBatteryUptime / 1000); - sb.append("("); sb.append(formatRatioLocked(whichBatteryUptime, totalRealtime)); - sb.append(") uptime"); - pw.println(sb.toString()); - sb.setLength(0); - sb.append(prefix); - sb.append(" Time on battery screen off: "); - formatTimeMs(sb, whichBatteryScreenOffRealtime / 1000); sb.append("("); - sb.append(formatRatioLocked(whichBatteryScreenOffRealtime, totalRealtime)); - sb.append(") realtime, "); - formatTimeMs(sb, whichBatteryScreenOffUptime / 1000); - sb.append("("); - sb.append(formatRatioLocked(whichBatteryScreenOffUptime, totalRealtime)); - sb.append(") uptime"); - pw.println(sb.toString()); - sb.setLength(0); - sb.append(prefix); - sb.append(" Total run time: "); - formatTimeMs(sb, totalRealtime / 1000); - sb.append("realtime, "); - formatTimeMs(sb, totalUptime / 1000); - sb.append("uptime"); - pw.println(sb.toString()); - if (batteryTimeRemaining >= 0) { - sb.setLength(0); - sb.append(prefix); - sb.append(" Battery time remaining: "); - formatTimeMs(sb, batteryTimeRemaining / 1000); - pw.println(sb.toString()); - } - if (chargeTimeRemaining >= 0) { - sb.setLength(0); - sb.append(prefix); - sb.append(" Charge time remaining: "); - formatTimeMs(sb, chargeTimeRemaining / 1000); - pw.println(sb.toString()); - } - pw.print(" Start clock time: "); - pw.println(DateFormat.format("yyyy-MM-dd-HH-mm-ss", getStartClockTime()).toString()); - - final long screenOnTime = getScreenOnTime(rawRealtime, which); - final long interactiveTime = getInteractiveTime(rawRealtime, which); - final long lowPowerModeEnabledTime = getLowPowerModeEnabledTime(rawRealtime, which); - final long phoneOnTime = getPhoneOnTime(rawRealtime, which); - final long wifiRunningTime = getGlobalWifiRunningTime(rawRealtime, which); - final long wifiOnTime = getWifiOnTime(rawRealtime, which); - final long bluetoothOnTime = getBluetoothOnTime(rawRealtime, which); - sb.setLength(0); - sb.append(prefix); - sb.append(" Screen on: "); formatTimeMs(sb, screenOnTime / 1000); - sb.append("("); sb.append(formatRatioLocked(screenOnTime, whichBatteryRealtime)); - sb.append(") "); sb.append(getScreenOnCount(which)); - sb.append("x, Interactive: "); formatTimeMs(sb, interactiveTime / 1000); - sb.append("("); sb.append(formatRatioLocked(interactiveTime, whichBatteryRealtime)); - sb.append(")"); - pw.println(sb.toString()); - sb.setLength(0); - sb.append(prefix); - sb.append(" Screen brightnesses:"); - boolean didOne = false; - for (int i=0; i timers = new ArrayList(); - - for (int iu = 0; iu < NU; iu++) { - Uid u = uidStats.valueAt(iu); - - Map wakelocks = u.getWakelockStats(); - if (wakelocks.size() > 0) { - for (Map.Entry ent - : wakelocks.entrySet()) { - Uid.Wakelock wl = ent.getValue(); - - Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL); - if (fullWakeTimer != null) { - fullWakeLockTimeTotalMicros += fullWakeTimer.getTotalTimeLocked( - rawRealtime, which); - } - - Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL); - if (partialWakeTimer != null) { - long totalTimeMicros = partialWakeTimer.getTotalTimeLocked( - rawRealtime, which); - if (totalTimeMicros > 0) { - if (reqUid < 0) { - // Only show the ordered list of all wake - // locks if the caller is not asking for data - // about a specific uid. - timers.add(new TimerEntry(ent.getKey(), u.getUid(), - partialWakeTimer, totalTimeMicros)); - } - partialWakeLockTimeTotalMicros += totalTimeMicros; - } - } - } - } - } - - long mobileRxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which); - long mobileTxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which); - long wifiRxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which); - long wifiTxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which); - long mobileRxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which); - long mobileTxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which); - long wifiRxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which); - long wifiTxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which); - - if (fullWakeLockTimeTotalMicros != 0) { - sb.setLength(0); - sb.append(prefix); - sb.append(" Total full wakelock time: "); formatTimeMsNoSpace(sb, - (fullWakeLockTimeTotalMicros + 500) / 1000); - pw.println(sb.toString()); - } - - if (partialWakeLockTimeTotalMicros != 0) { - sb.setLength(0); - sb.append(prefix); - sb.append(" Total partial wakelock time: "); formatTimeMsNoSpace(sb, - (partialWakeLockTimeTotalMicros + 500) / 1000); - pw.println(sb.toString()); - } - - pw.print(prefix); - pw.print(" Mobile total received: "); pw.print(formatBytesLocked(mobileRxTotalBytes)); - pw.print(", sent: "); pw.print(formatBytesLocked(mobileTxTotalBytes)); - pw.print(" (packets received "); pw.print(mobileRxTotalPackets); - pw.print(", sent "); pw.print(mobileTxTotalPackets); pw.println(")"); - sb.setLength(0); - sb.append(prefix); - sb.append(" Phone signal levels:"); - didOne = false; - for (int i=0; i sippers = helper.getUsageList(); - if (sippers != null && sippers.size() > 0) { - pw.print(prefix); pw.println(" Estimated power use (mAh):"); - pw.print(prefix); pw.print(" Capacity: "); - printmAh(pw, helper.getPowerProfile().getBatteryCapacity()); - pw.print(", Computed drain: "); printmAh(pw, helper.getComputedPower()); - pw.print(", actual drain: "); printmAh(pw, helper.getMinDrainedPower()); - if (helper.getMinDrainedPower() != helper.getMaxDrainedPower()) { - pw.print("-"); printmAh(pw, helper.getMaxDrainedPower()); - } - pw.println(); - for (int i=0; i 0) { - pw.print(prefix); pw.println(" Per-app mobile ms per packet:"); - long totalTime = 0; - for (int i=0; i timerComparator = new Comparator() { - @Override - public int compare(TimerEntry lhs, TimerEntry rhs) { - long lhsTime = lhs.mTime; - long rhsTime = rhs.mTime; - if (lhsTime < rhsTime) { - return 1; - } - if (lhsTime > rhsTime) { - return -1; - } - return 0; - } - }; - - if (reqUid < 0) { - Map kernelWakelocks = getKernelWakelockStats(); - if (kernelWakelocks.size() > 0) { - final ArrayList ktimers = new ArrayList(); - for (Map.Entry ent : kernelWakelocks.entrySet()) { - BatteryStats.Timer timer = ent.getValue(); - long totalTimeMillis = computeWakeLock(timer, rawRealtime, which); - if (totalTimeMillis > 0) { - ktimers.add(new TimerEntry(ent.getKey(), 0, timer, totalTimeMillis)); - } - } - if (ktimers.size() > 0) { - Collections.sort(ktimers, timerComparator); - pw.print(prefix); pw.println(" All kernel wake locks:"); - for (int i=0; i 0) { - Collections.sort(timers, timerComparator); - pw.print(prefix); pw.println(" All partial wake locks:"); - for (int i=0; i wakeupReasons = getWakeupReasonStats(); - if (wakeupReasons.size() > 0) { - pw.print(prefix); pw.println(" All wakeup reasons:"); - final ArrayList reasons = new ArrayList(); - for (Map.Entry ent : wakeupReasons.entrySet()) { - Timer timer = ent.getValue(); - reasons.add(new TimerEntry(ent.getKey(), 0, timer, - timer.getCountLocked(which))); - } - Collections.sort(reasons, timerComparator); - for (int i=0; i= 0 && uid != reqUid && uid != Process.SYSTEM_UID) { - continue; - } - - Uid u = uidStats.valueAt(iu); - - pw.print(prefix); - pw.print(" "); - UserHandle.formatUid(pw, uid); - pw.println(":"); - boolean uidActivity = false; - - long mobileRxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which); - long mobileTxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which); - long wifiRxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which); - long wifiTxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which); - long mobileRxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which); - long mobileTxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which); - long uidMobileActiveTime = u.getMobileRadioActiveTime(which); - int uidMobileActiveCount = u.getMobileRadioActiveCount(which); - long wifiRxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which); - long wifiTxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which); - long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which); - long wifiScanTime = u.getWifiScanTime(rawRealtime, which); - long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which); - - if (mobileRxBytes > 0 || mobileTxBytes > 0 - || mobileRxPackets > 0 || mobileTxPackets > 0) { - pw.print(prefix); pw.print(" Mobile network: "); - pw.print(formatBytesLocked(mobileRxBytes)); pw.print(" received, "); - pw.print(formatBytesLocked(mobileTxBytes)); - pw.print(" sent (packets "); pw.print(mobileRxPackets); - pw.print(" received, "); pw.print(mobileTxPackets); pw.println(" sent)"); - } - if (uidMobileActiveTime > 0 || uidMobileActiveCount > 0) { - sb.setLength(0); - sb.append(prefix); sb.append(" Mobile radio active: "); - formatTimeMs(sb, uidMobileActiveTime / 1000); - sb.append("("); - sb.append(formatRatioLocked(uidMobileActiveTime, mobileActiveTime)); - sb.append(") "); sb.append(uidMobileActiveCount); sb.append("x"); - long packets = mobileRxPackets + mobileTxPackets; - if (packets == 0) { - packets = 1; - } - sb.append(" @ "); - sb.append(BatteryStatsHelper.makemAh(uidMobileActiveTime / 1000 / (double)packets)); - sb.append(" mspp"); - pw.println(sb.toString()); - } - - if (wifiRxBytes > 0 || wifiTxBytes > 0 || wifiRxPackets > 0 || wifiTxPackets > 0) { - pw.print(prefix); pw.print(" Wi-Fi network: "); - pw.print(formatBytesLocked(wifiRxBytes)); pw.print(" received, "); - pw.print(formatBytesLocked(wifiTxBytes)); - pw.print(" sent (packets "); pw.print(wifiRxPackets); - pw.print(" received, "); pw.print(wifiTxPackets); pw.println(" sent)"); - } - - if (fullWifiLockOnTime != 0 || wifiScanTime != 0 - || uidWifiRunningTime != 0) { - sb.setLength(0); - sb.append(prefix); sb.append(" Wifi Running: "); - formatTimeMs(sb, uidWifiRunningTime / 1000); - sb.append("("); sb.append(formatRatioLocked(uidWifiRunningTime, - whichBatteryRealtime)); sb.append(")\n"); - sb.append(prefix); sb.append(" Full Wifi Lock: "); - formatTimeMs(sb, fullWifiLockOnTime / 1000); - sb.append("("); sb.append(formatRatioLocked(fullWifiLockOnTime, - whichBatteryRealtime)); sb.append(")\n"); - sb.append(prefix); sb.append(" Wifi Scan: "); - formatTimeMs(sb, wifiScanTime / 1000); - sb.append("("); sb.append(formatRatioLocked(wifiScanTime, - whichBatteryRealtime)); sb.append(")"); - pw.println(sb.toString()); - } - - if (u.hasUserActivity()) { - boolean hasData = false; - for (int i=0; i wakelocks = u.getWakelockStats(); - if (wakelocks.size() > 0) { - long totalFull = 0, totalPartial = 0, totalWindow = 0; - int count = 0; - for (Map.Entry ent : wakelocks.entrySet()) { - Uid.Wakelock wl = ent.getValue(); - String linePrefix = ": "; - sb.setLength(0); - sb.append(prefix); - sb.append(" Wake lock "); - sb.append(ent.getKey()); - linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_FULL), rawRealtime, - "full", which, linePrefix); - linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), rawRealtime, - "partial", which, linePrefix); - linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), rawRealtime, - "window", which, linePrefix); - if (true || !linePrefix.equals(": ")) { - sb.append(" realtime"); - // Only print out wake locks that were held - pw.println(sb.toString()); - uidActivity = true; - count++; - } - totalFull += computeWakeLock(wl.getWakeTime(WAKE_TYPE_FULL), - rawRealtime, which); - totalPartial += computeWakeLock(wl.getWakeTime(WAKE_TYPE_PARTIAL), - rawRealtime, which); - totalWindow += computeWakeLock(wl.getWakeTime(WAKE_TYPE_WINDOW), - rawRealtime, which); - } - if (count > 1) { - if (totalFull != 0 || totalPartial != 0 || totalWindow != 0) { - sb.setLength(0); - sb.append(prefix); - sb.append(" TOTAL wake: "); - boolean needComma = false; - if (totalFull != 0) { - needComma = true; - formatTimeMs(sb, totalFull); - sb.append("full"); - } - if (totalPartial != 0) { - if (needComma) { - sb.append(", "); - } - needComma = true; - formatTimeMs(sb, totalPartial); - sb.append("partial"); - } - if (totalWindow != 0) { - if (needComma) { - sb.append(", "); - } - needComma = true; - formatTimeMs(sb, totalWindow); - sb.append("window"); - } - sb.append(" realtime"); - pw.println(sb.toString()); - } - } - } - - Map syncs = u.getSyncStats(); - if (syncs.size() > 0) { - for (Map.Entry ent : syncs.entrySet()) { - Timer timer = ent.getValue(); - // Convert from microseconds to milliseconds with rounding - long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000; - int count = timer.getCountLocked(which); - sb.setLength(0); - sb.append(prefix); - sb.append(" Sync "); - sb.append(ent.getKey()); - sb.append(": "); - if (totalTime != 0) { - formatTimeMs(sb, totalTime); - sb.append("realtime ("); - sb.append(count); - sb.append(" times)"); - } else { - sb.append("(not used)"); - } - pw.println(sb.toString()); - uidActivity = true; - } - } - - Map jobs = u.getJobStats(); - if (jobs.size() > 0) { - for (Map.Entry ent : jobs.entrySet()) { - Timer timer = ent.getValue(); - // Convert from microseconds to milliseconds with rounding - long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000; - int count = timer.getCountLocked(which); - sb.setLength(0); - sb.append(prefix); - sb.append(" Job "); - sb.append(ent.getKey()); - sb.append(": "); - if (totalTime != 0) { - formatTimeMs(sb, totalTime); - sb.append("realtime ("); - sb.append(count); - sb.append(" times)"); - } else { - sb.append("(not used)"); - } - pw.println(sb.toString()); - uidActivity = true; - } - } - - SparseArray sensors = u.getSensorStats(); - int NSE = sensors.size(); - for (int ise=0; ise 0) { - totalStateTime += time; - sb.setLength(0); - sb.append(prefix); - sb.append(" "); - sb.append(Uid.PROCESS_STATE_NAMES[ips]); - sb.append(" for: "); - formatTimeMs(sb, (totalStateTime + 500) / 1000); - pw.println(sb.toString()); - uidActivity = true; - } - } - - Map processStats = u.getProcessStats(); - if (processStats.size() > 0) { - for (Map.Entry ent - : processStats.entrySet()) { - Uid.Proc ps = ent.getValue(); - long userTime; - long systemTime; - long foregroundTime; - int starts; - int numExcessive; - - userTime = ps.getUserTime(which); - systemTime = ps.getSystemTime(which); - foregroundTime = ps.getForegroundTime(which); - starts = ps.getStarts(which); - final int numCrashes = ps.getNumCrashes(which); - final int numAnrs = ps.getNumAnrs(which); - numExcessive = which == STATS_SINCE_CHARGED - ? ps.countExcessivePowers() : 0; - - if (userTime != 0 || systemTime != 0 || foregroundTime != 0 || starts != 0 - || numExcessive != 0 || numCrashes != 0 || numAnrs != 0) { - sb.setLength(0); - sb.append(prefix); sb.append(" Proc "); - sb.append(ent.getKey()); sb.append(":\n"); - sb.append(prefix); sb.append(" CPU: "); - formatTime(sb, userTime); sb.append("usr + "); - formatTime(sb, systemTime); sb.append("krn ; "); - formatTime(sb, foregroundTime); sb.append("fg"); - if (starts != 0 || numCrashes != 0 || numAnrs != 0) { - sb.append("\n"); sb.append(prefix); sb.append(" "); - boolean hasOne = false; - if (starts != 0) { - hasOne = true; - sb.append(starts); sb.append(" starts"); - } - if (numCrashes != 0) { - if (hasOne) { - sb.append(", "); - } - hasOne = true; - sb.append(numCrashes); sb.append(" crashes"); - } - if (numAnrs != 0) { - if (hasOne) { - sb.append(", "); - } - sb.append(numAnrs); sb.append(" anrs"); - } - } - pw.println(sb.toString()); - for (int e=0; e packageStats = u.getPackageStats(); - if (packageStats.size() > 0) { - for (Map.Entry ent - : packageStats.entrySet()) { - pw.print(prefix); pw.print(" Apk "); pw.print(ent.getKey()); pw.println(":"); - boolean apkActivity = false; - Uid.Pkg ps = ent.getValue(); - int wakeups = ps.getWakeups(which); - if (wakeups != 0) { - pw.print(prefix); pw.print(" "); - pw.print(wakeups); pw.println(" wakeup alarms"); - apkActivity = true; - } - Map serviceStats = ps.getServiceStats(); - if (serviceStats.size() > 0) { - for (Map.Entry sent - : serviceStats.entrySet()) { - BatteryStats.Uid.Pkg.Serv ss = sent.getValue(); - long startTime = ss.getStartTime(batteryUptime, which); - int starts = ss.getStarts(which); - int launches = ss.getLaunches(which); - if (startTime != 0 || starts != 0 || launches != 0) { - sb.setLength(0); - sb.append(prefix); sb.append(" Service "); - sb.append(sent.getKey()); sb.append(":\n"); - sb.append(prefix); sb.append(" Created for: "); - formatTimeMs(sb, startTime / 1000); - sb.append("uptime\n"); - sb.append(prefix); sb.append(" Starts: "); - sb.append(starts); - sb.append(", launches: "); sb.append(launches); - pw.println(sb.toString()); - apkActivity = true; - } - } - } - if (!apkActivity) { - pw.print(prefix); pw.println(" (nothing executed)"); - } - uidActivity = true; - } - } - if (!uidActivity) { - pw.print(prefix); pw.println(" (nothing executed)"); - } - } - } - - static void printBitDescriptions(PrintWriter pw, int oldval, int newval, HistoryTag wakelockTag, - BitDescription[] descriptions, boolean longNames) { - int diff = oldval ^ newval; - if (diff == 0) return; - boolean didWake = false; - for (int i=0; i= 0 && idx < eventNames.length) { - pw.print(eventNames[idx]); - } else { - pw.print(checkin ? "Ev" : "event"); - pw.print(idx); - } - pw.print("="); - if (checkin) { - pw.print(rec.eventTag.poolIdx); - } else { - UserHandle.formatUid(pw, rec.eventTag.uid); - pw.print(":\""); - pw.print(rec.eventTag.string); - pw.print("\""); - } - } - pw.println(); - oldState = rec.states; - oldState2 = rec.states2; - } - } - } - - private void printSizeValue(PrintWriter pw, long size) { - float result = size; - String suffix = ""; - if (result >= 10*1024) { - suffix = "KB"; - result = result / 1024; - } - if (result >= 10*1024) { - suffix = "MB"; - result = result / 1024; - } - if (result >= 10*1024) { - suffix = "GB"; - result = result / 1024; - } - if (result >= 10*1024) { - suffix = "TB"; - result = result / 1024; - } - if (result >= 10*1024) { - suffix = "PB"; - result = result / 1024; - } - pw.print((int)result); - pw.print(suffix); - } - - private static boolean dumpTimeEstimate(PrintWriter pw, String label, long[] steps, - int count, long modesOfInterest, long modeValues) { - if (count <= 0) { - return false; - } - long total = 0; - int numOfInterest = 0; - for (int i=0; i> STEP_LEVEL_INITIAL_MODE_SHIFT; - long modMode = (steps[i] & STEP_LEVEL_MODIFIED_MODE_MASK) - >> STEP_LEVEL_MODIFIED_MODE_SHIFT; - // If the modes of interest didn't change during this step period... - if ((modMode&modesOfInterest) == 0) { - // And the mode values during this period match those we are measuring... - if ((initMode&modesOfInterest) == modeValues) { - // Then this can be used to estimate the total time! - numOfInterest++; - total += steps[i] & STEP_LEVEL_TIME_MASK; - } - } - } - if (numOfInterest <= 0) { - return false; - } - - // The estimated time is the average time we spend in each level, multipled - // by 100 -- the total number of battery levels - long estimatedTime = (total / numOfInterest) * 100; - - pw.print(label); - StringBuilder sb = new StringBuilder(64); - formatTimeMs(sb, estimatedTime); - pw.print(sb); - pw.println(); - - return true; - } - - private static boolean dumpDurationSteps(PrintWriter pw, String header, long[] steps, - int count, boolean checkin) { - if (count <= 0) { - return false; - } - if (!checkin) { - pw.println(header); - } - String[] lineArgs = new String[4]; - for (int i=0; i> STEP_LEVEL_LEVEL_SHIFT); - long initMode = (steps[i] & STEP_LEVEL_INITIAL_MODE_MASK) - >> STEP_LEVEL_INITIAL_MODE_SHIFT; - long modMode = (steps[i] & STEP_LEVEL_MODIFIED_MODE_MASK) - >> STEP_LEVEL_MODIFIED_MODE_SHIFT; - if (checkin) { - lineArgs[0] = Long.toString(duration); - lineArgs[1] = Integer.toString(level); - if ((modMode&STEP_LEVEL_MODE_SCREEN_STATE) == 0) { - switch ((int)(initMode&STEP_LEVEL_MODE_SCREEN_STATE) + 1) { - case Display.STATE_OFF: lineArgs[2] = "s-"; break; - case Display.STATE_ON: lineArgs[2] = "s+"; break; - case Display.STATE_DOZE: lineArgs[2] = "sd"; break; - case Display.STATE_DOZE_SUSPEND: lineArgs[2] = "sds"; break; - default: lineArgs[1] = "?"; break; - } - } else { - lineArgs[2] = ""; - } - if ((modMode&STEP_LEVEL_MODE_POWER_SAVE) == 0) { - lineArgs[3] = (initMode&STEP_LEVEL_MODE_POWER_SAVE) != 0 ? "p+" : "p-"; - } else { - lineArgs[3] = ""; - } - dumpLine(pw, 0 /* uid */, "i" /* category */, header, (Object[])lineArgs); - } else { - pw.print(" #"); pw.print(i); pw.print(": "); - TimeUtils.formatDuration(duration, pw); - pw.print(" to "); pw.print(level); - boolean haveModes = false; - if ((modMode&STEP_LEVEL_MODE_SCREEN_STATE) == 0) { - pw.print(" ("); - switch ((int)(initMode&STEP_LEVEL_MODE_SCREEN_STATE) + 1) { - case Display.STATE_OFF: pw.print("screen-off"); break; - case Display.STATE_ON: pw.print("screen-on"); break; - case Display.STATE_DOZE: pw.print("screen-doze"); break; - case Display.STATE_DOZE_SUSPEND: pw.print("screen-doze-suspend"); break; - default: lineArgs[1] = "screen-?"; break; - } - haveModes = true; - } - if ((modMode&STEP_LEVEL_MODE_POWER_SAVE) == 0) { - pw.print(haveModes ? ", " : " ("); - pw.print((initMode&STEP_LEVEL_MODE_POWER_SAVE) != 0 - ? "power-save-on" : "power-save-off"); - haveModes = true; - } - if (haveModes) { - pw.print(")"); - } - pw.println(); - } - } - return true; - } - - public static final int DUMP_UNPLUGGED_ONLY = 1<<0; - public static final int DUMP_CHARGED_ONLY = 1<<1; - public static final int DUMP_HISTORY_ONLY = 1<<2; - public static final int DUMP_INCLUDE_HISTORY = 1<<3; - public static final int DUMP_VERBOSE = 1<<4; - public static final int DUMP_DEVICE_WIFI_ONLY = 1<<5; - - private void dumpHistoryLocked(PrintWriter pw, int flags, long histStart, boolean checkin) { - final HistoryPrinter hprinter = new HistoryPrinter(); - final HistoryItem rec = new HistoryItem(); - long lastTime = -1; - long baseTime = -1; - boolean printed = false; - HistoryEventTracker tracker = null; - while (getNextHistoryLocked(rec)) { - lastTime = rec.time; - if (baseTime < 0) { - baseTime = lastTime; - } - if (rec.time >= histStart) { - if (histStart >= 0 && !printed) { - if (rec.cmd == HistoryItem.CMD_CURRENT_TIME - || rec.cmd == HistoryItem.CMD_RESET - || rec.cmd == HistoryItem.CMD_START - || rec.cmd == HistoryItem.CMD_SHUTDOWN) { - printed = true; - hprinter.printNextItem(pw, rec, baseTime, checkin, - (flags&DUMP_VERBOSE) != 0); - rec.cmd = HistoryItem.CMD_UPDATE; - } else if (rec.currentTime != 0) { - printed = true; - byte cmd = rec.cmd; - rec.cmd = HistoryItem.CMD_CURRENT_TIME; - hprinter.printNextItem(pw, rec, baseTime, checkin, - (flags&DUMP_VERBOSE) != 0); - rec.cmd = cmd; - } - if (tracker != null) { - if (rec.cmd != HistoryItem.CMD_UPDATE) { - hprinter.printNextItem(pw, rec, baseTime, checkin, - (flags&DUMP_VERBOSE) != 0); - rec.cmd = HistoryItem.CMD_UPDATE; - } - int oldEventCode = rec.eventCode; - HistoryTag oldEventTag = rec.eventTag; - rec.eventTag = new HistoryTag(); - for (int i=0; i active - = tracker.getStateForEvent(i); - if (active == null) { - continue; - } - for (HashMap.Entry ent - : active.entrySet()) { - SparseIntArray uids = ent.getValue(); - for (int j=0; j= 0) { - commitCurrentHistoryBatchLocked(); - pw.print(checkin ? "NEXT: " : " NEXT: "); pw.println(lastTime+1); - } - } - - /** - * Dumps a human-readable summary of the battery statistics to the given PrintWriter. - * - * @param pw a Printer to receive the dump output. - */ - @SuppressWarnings("unused") - public void dumpLocked(Context context, PrintWriter pw, int flags, int reqUid, long histStart) { - prepareForDumpLocked(); - - final boolean filtering = - (flags&(DUMP_HISTORY_ONLY|DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY)) != 0; - - if ((flags&DUMP_HISTORY_ONLY) != 0 || !filtering) { - final long historyTotalSize = getHistoryTotalSize(); - final long historyUsedSize = getHistoryUsedSize(); - if (startIteratingHistoryLocked()) { - try { - pw.print("Battery History ("); - pw.print((100*historyUsedSize)/historyTotalSize); - pw.print("% used, "); - printSizeValue(pw, historyUsedSize); - pw.print(" used of "); - printSizeValue(pw, historyTotalSize); - pw.print(", "); - pw.print(getHistoryStringPoolSize()); - pw.print(" strings using "); - printSizeValue(pw, getHistoryStringPoolBytes()); - pw.println("):"); - dumpHistoryLocked(pw, flags, histStart, false); - pw.println(); - } finally { - finishIteratingHistoryLocked(); - } - } - - if (startIteratingOldHistoryLocked()) { - try { - final HistoryItem rec = new HistoryItem(); - pw.println("Old battery History:"); - HistoryPrinter hprinter = new HistoryPrinter(); - long baseTime = -1; - while (getNextOldHistoryLocked(rec)) { - if (baseTime < 0) { - baseTime = rec.time; - } - hprinter.printNextItem(pw, rec, baseTime, false, (flags&DUMP_VERBOSE) != 0); - } - pw.println(); - } finally { - finishIteratingOldHistoryLocked(); - } - } - } - - if (filtering && (flags&(DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY)) == 0) { - return; - } - - if (!filtering) { - SparseArray uidStats = getUidStats(); - final int NU = uidStats.size(); - boolean didPid = false; - long nowRealtime = SystemClock.elapsedRealtime(); - for (int i=0; i pids = uid.getPidStats(); - if (pids != null) { - for (int j=0; j 0 - ? (nowRealtime - pid.mWakeStartMs) : 0); - pw.print(" PID "); pw.print(pids.keyAt(j)); - pw.print(" wake time: "); - TimeUtils.formatDuration(time, pw); - pw.println(""); - } - } - } - if (didPid) { - pw.println(); - } - } - - if (!filtering || (flags&DUMP_CHARGED_ONLY) != 0) { - if (dumpDurationSteps(pw, "Discharge step durations:", getDischargeStepDurationsArray(), - getNumDischargeStepDurations(), false)) { - long timeRemaining = computeBatteryTimeRemaining(SystemClock.elapsedRealtime()); - if (timeRemaining >= 0) { - pw.print(" Estimated discharge time remaining: "); - TimeUtils.formatDuration(timeRemaining / 1000, pw); - pw.println(); - } - dumpTimeEstimate(pw, " Estimated screen off time: ", - getDischargeStepDurationsArray(), getNumDischargeStepDurations(), - STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE, - (Display.STATE_OFF-1)); - dumpTimeEstimate(pw, " Estimated screen off power save time: ", - getDischargeStepDurationsArray(), getNumDischargeStepDurations(), - STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE, - (Display.STATE_OFF-1)|STEP_LEVEL_MODE_POWER_SAVE); - dumpTimeEstimate(pw, " Estimated screen on time: ", - getDischargeStepDurationsArray(), getNumDischargeStepDurations(), - STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE, - (Display.STATE_ON-1)); - dumpTimeEstimate(pw, " Estimated screen on power save time: ", - getDischargeStepDurationsArray(), getNumDischargeStepDurations(), - STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE, - (Display.STATE_ON-1)|STEP_LEVEL_MODE_POWER_SAVE); - dumpTimeEstimate(pw, " Estimated screen doze time: ", - getDischargeStepDurationsArray(), getNumDischargeStepDurations(), - STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE, - (Display.STATE_DOZE-1)); - dumpTimeEstimate(pw, " Estimated screen doze power save time: ", - getDischargeStepDurationsArray(), getNumDischargeStepDurations(), - STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE, - (Display.STATE_DOZE-1)|STEP_LEVEL_MODE_POWER_SAVE); - dumpTimeEstimate(pw, " Estimated screen doze suspend time: ", - getDischargeStepDurationsArray(), getNumDischargeStepDurations(), - STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE, - (Display.STATE_DOZE_SUSPEND-1)); - dumpTimeEstimate(pw, " Estimated screen doze suspend power save time: ", - getDischargeStepDurationsArray(), getNumDischargeStepDurations(), - STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE, - (Display.STATE_DOZE_SUSPEND-1)|STEP_LEVEL_MODE_POWER_SAVE); - pw.println(); - } - if (dumpDurationSteps(pw, "Charge step durations:", getChargeStepDurationsArray(), - getNumChargeStepDurations(), false)) { - long timeRemaining = computeChargeTimeRemaining(SystemClock.elapsedRealtime()); - if (timeRemaining >= 0) { - pw.print(" Estimated charge time remaining: "); - TimeUtils.formatDuration(timeRemaining / 1000, pw); - pw.println(); - } - pw.println(); - } - pw.println("Statistics since last charge:"); - pw.println(" System starts: " + getStartCount() - + ", currently on battery: " + getIsOnBattery()); - dumpLocked(context, pw, "", STATS_SINCE_CHARGED, reqUid, - (flags&DUMP_DEVICE_WIFI_ONLY) != 0); - pw.println(); - } - if (!filtering || (flags&DUMP_UNPLUGGED_ONLY) != 0) { - pw.println("Statistics since last unplugged:"); - dumpLocked(context, pw, "", STATS_SINCE_UNPLUGGED, reqUid, - (flags&DUMP_DEVICE_WIFI_ONLY) != 0); - } - } - - @SuppressWarnings("unused") - public void dumpCheckinLocked(Context context, PrintWriter pw, - List apps, int flags, long histStart) { - prepareForDumpLocked(); - - dumpLine(pw, 0 /* uid */, "i" /* category */, VERSION_DATA, - "12", getParcelVersion(), getStartPlatformVersion(), getEndPlatformVersion()); - - long now = getHistoryBaseTime() + SystemClock.elapsedRealtime(); - - final boolean filtering = - (flags&(DUMP_HISTORY_ONLY|DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY)) != 0; - - if ((flags&DUMP_INCLUDE_HISTORY) != 0 || (flags&DUMP_HISTORY_ONLY) != 0) { - if (startIteratingHistoryLocked()) { - try { - for (int i=0; i> uids = new SparseArray>(); - for (int i=0; i pkgs = uids.get(ai.uid); - if (pkgs == null) { - pkgs = new ArrayList(); - uids.put(ai.uid, pkgs); - } - pkgs.add(ai.packageName); - } - SparseArray uidStats = getUidStats(); - final int NU = uidStats.size(); - String[] lineArgs = new String[2]; - for (int i=0; i pkgs = uids.get(uid); - if (pkgs != null) { - for (int j=0; j= 0) { - lineArgs[0] = Long.toString(timeRemaining); - dumpLine(pw, 0 /* uid */, "i" /* category */, DISCHARGE_TIME_REMAIN_DATA, - (Object[])lineArgs); - } - dumpDurationSteps(pw, CHARGE_STEP_DATA, getChargeStepDurationsArray(), - getNumChargeStepDurations(), true); - timeRemaining = computeChargeTimeRemaining(SystemClock.elapsedRealtime()); - if (timeRemaining >= 0) { - lineArgs[0] = Long.toString(timeRemaining); - dumpLine(pw, 0 /* uid */, "i" /* category */, CHARGE_TIME_REMAIN_DATA, - (Object[])lineArgs); - } - dumpCheckinLocked(context, pw, STATS_SINCE_CHARGED, -1, - (flags&DUMP_DEVICE_WIFI_ONLY) != 0); - } - if (!filtering || (flags&DUMP_UNPLUGGED_ONLY) != 0) { - dumpCheckinLocked(context, pw, STATS_SINCE_UNPLUGGED, -1, - (flags&DUMP_DEVICE_WIFI_ONLY) != 0); - } - } -} diff --git a/src/main/java/android/os/Binder.java b/src/main/java/android/os/Binder.java deleted file mode 100644 index b4a4624..0000000 --- a/src/main/java/android/os/Binder.java +++ /dev/null @@ -1,562 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.util.Log; -import android.util.Slog; -import com.android.internal.util.FastPrintWriter; - -import java.io.FileDescriptor; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintWriter; -import java.lang.ref.WeakReference; -import java.lang.reflect.Modifier; - -/** - * Base class for a remotable object, the core part of a lightweight - * remote procedure call mechanism defined by {@link IBinder}. - * This class is an implementation of IBinder that provides - * standard local implementation of such an object. - * - *

Most developers will not implement this class directly, instead using the - * aidl tool to describe the desired - * interface, having it generate the appropriate Binder subclass. You can, - * however, derive directly from Binder to implement your own custom RPC - * protocol or simply instantiate a raw Binder object directly to use as a - * token that can be shared across processes. - * - *

This class is just a basic IPC primitive; it has no impact on an application's - * lifecycle, and is valid only as long as the process that created it continues to run. - * To use this correctly, you must be doing so within the context of a top-level - * application component (a {@link android.app.Service}, {@link android.app.Activity}, - * or {@link android.content.ContentProvider}) that lets the system know your process - * should remain running.

- * - *

You must keep in mind the situations in which your process - * could go away, and thus require that you later re-create a new Binder and re-attach - * it when the process starts again. For example, if you are using this within an - * {@link android.app.Activity}, your activity's process may be killed any time the - * activity is not started; if the activity is later re-created you will need to - * create a new Binder and hand it back to the correct place again; you need to be - * aware that your process may be started for another reason (for example to receive - * a broadcast) that will not involve re-creating the activity and thus run its code - * to create a new Binder.

- * - * @see IBinder - */ -public class Binder implements IBinder { - /* - * Set this flag to true to detect anonymous, local or member classes - * that extend this Binder class and that are not static. These kind - * of classes can potentially create leaks. - */ - private static final boolean FIND_POTENTIAL_LEAKS = false; - private static final boolean CHECK_PARCEL_SIZE = false; - static final String TAG = "Binder"; - - /** - * Control whether dump() calls are allowed. - */ - private static String sDumpDisabled = null; - - /* mObject is used by native code, do not remove or rename */ - private long mObject; - private IInterface mOwner; - private String mDescriptor; - - /** - * Return the ID of the process that sent you the current transaction - * that is being processed. This pid can be used with higher-level - * system services to determine its identity and check permissions. - * If the current thread is not currently executing an incoming transaction, - * then its own pid is returned. - */ - public static final native int getCallingPid(); - - /** - * Return the Linux uid assigned to the process that sent you the - * current transaction that is being processed. This uid can be used with - * higher-level system services to determine its identity and check - * permissions. If the current thread is not currently executing an - * incoming transaction, then its own uid is returned. - */ - public static final native int getCallingUid(); - - /** - * Return the UserHandle assigned to the process that sent you the - * current transaction that is being processed. This is the user - * of the caller. It is distinct from {@link #getCallingUid()} in that a - * particular user will have multiple distinct apps running under it each - * with their own uid. If the current thread is not currently executing an - * incoming transaction, then its own UserHandle is returned. - */ - public static final UserHandle getCallingUserHandle() { - return new UserHandle(UserHandle.getUserId(getCallingUid())); - } - - /** - * Reset the identity of the incoming IPC on the current thread. This can - * be useful if, while handling an incoming call, you will be calling - * on interfaces of other objects that may be local to your process and - * need to do permission checks on the calls coming into them (so they - * will check the permission of your own local process, and not whatever - * process originally called you). - * - * @return Returns an opaque token that can be used to restore the - * original calling identity by passing it to - * {@link #restoreCallingIdentity(long)}. - * - * @see #getCallingPid() - * @see #getCallingUid() - * @see #restoreCallingIdentity(long) - */ - public static final native long clearCallingIdentity(); - - /** - * Restore the identity of the incoming IPC on the current thread - * back to a previously identity that was returned by {@link - * #clearCallingIdentity}. - * - * @param token The opaque token that was previously returned by - * {@link #clearCallingIdentity}. - * - * @see #clearCallingIdentity - */ - public static final native void restoreCallingIdentity(long token); - - /** - * Sets the native thread-local StrictMode policy mask. - * - *

The StrictMode settings are kept in two places: a Java-level - * threadlocal for libcore/Dalvik, and a native threadlocal (set - * here) for propagation via Binder calls. This is a little - * unfortunate, but necessary to break otherwise more unfortunate - * dependencies either of Dalvik on Android, or Android - * native-only code on Dalvik. - * - * @see StrictMode - * @hide - */ - public static final native void setThreadStrictModePolicy(int policyMask); - - /** - * Gets the current native thread-local StrictMode policy mask. - * - * @see #setThreadStrictModePolicy - * @hide - */ - public static final native int getThreadStrictModePolicy(); - - /** - * Flush any Binder commands pending in the current thread to the kernel - * driver. This can be - * useful to call before performing an operation that may block for a long - * time, to ensure that any pending object references have been released - * in order to prevent the process from holding on to objects longer than - * it needs to. - */ - public static final native void flushPendingCommands(); - - /** - * Add the calling thread to the IPC thread pool. This function does - * not return until the current process is exiting. - */ - public static final native void joinThreadPool(); - - /** - * Returns true if the specified interface is a proxy. - * @hide - */ - public static final boolean isProxy(IInterface iface) { - return iface.asBinder() != iface; - } - - /** - * Default constructor initializes the object. - */ - public Binder() { - init(); - - if (FIND_POTENTIAL_LEAKS) { - final Class klass = getClass(); - if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && - (klass.getModifiers() & Modifier.STATIC) == 0) { - Log.w(TAG, "The following Binder class should be static or leaks might occur: " + - klass.getCanonicalName()); - } - } - } - - /** - * Convenience method for associating a specific interface with the Binder. - * After calling, queryLocalInterface() will be implemented for you - * to return the given owner IInterface when the corresponding - * descriptor is requested. - */ - public void attachInterface(IInterface owner, String descriptor) { - mOwner = owner; - mDescriptor = descriptor; - } - - /** - * Default implementation returns an empty interface name. - */ - public String getInterfaceDescriptor() { - return mDescriptor; - } - - /** - * Default implementation always returns true -- if you got here, - * the object is alive. - */ - public boolean pingBinder() { - return true; - } - - /** - * {@inheritDoc} - * - * Note that if you're calling on a local binder, this always returns true - * because your process is alive if you're calling it. - */ - public boolean isBinderAlive() { - return true; - } - - /** - * Use information supplied to attachInterface() to return the - * associated IInterface if it matches the requested - * descriptor. - */ - public IInterface queryLocalInterface(String descriptor) { - if (mDescriptor.equals(descriptor)) { - return mOwner; - } - return null; - } - - /** - * Control disabling of dump calls in this process. This is used by the system - * process watchdog to disable incoming dump calls while it has detecting the system - * is hung and is reporting that back to the activity controller. This is to - * prevent the controller from getting hung up on bug reports at this point. - * @hide - * - * @param msg The message to show instead of the dump; if null, dumps are - * re-enabled. - */ - public static void setDumpDisabled(String msg) { - synchronized (Binder.class) { - sDumpDisabled = msg; - } - } - - /** - * Default implementation is a stub that returns false. You will want - * to override this to do the appropriate unmarshalling of transactions. - * - *

If you want to call this, call transact(). - */ - protected boolean onTransact(int code, Parcel data, Parcel reply, - int flags) throws RemoteException { - if (code == INTERFACE_TRANSACTION) { - reply.writeString(getInterfaceDescriptor()); - return true; - } else if (code == DUMP_TRANSACTION) { - ParcelFileDescriptor fd = data.readFileDescriptor(); - String[] args = data.readStringArray(); - if (fd != null) { - try { - dump(fd.getFileDescriptor(), args); - } finally { - try { - fd.close(); - } catch (IOException e) { - // swallowed, not propagated back to the caller - } - } - } - // Write the StrictMode header. - if (reply != null) { - reply.writeNoException(); - } else { - StrictMode.clearGatheredViolations(); - } - return true; - } - return false; - } - - /** - * Implemented to call the more convenient version - * {@link #dump(FileDescriptor, PrintWriter, String[])}. - */ - public void dump(FileDescriptor fd, String[] args) { - FileOutputStream fout = new FileOutputStream(fd); - PrintWriter pw = new FastPrintWriter(fout); - try { - final String disabled; - synchronized (Binder.class) { - disabled = sDumpDisabled; - } - if (disabled == null) { - try { - dump(fd, pw, args); - } catch (SecurityException e) { - pw.println("Security exception: " + e.getMessage()); - throw e; - } catch (Throwable e) { - // Unlike usual calls, in this case if an exception gets thrown - // back to us we want to print it back in to the dump data, since - // that is where the caller expects all interesting information to - // go. - pw.println(); - pw.println("Exception occurred while dumping:"); - e.printStackTrace(pw); - } - } else { - pw.println(sDumpDisabled); - } - } finally { - pw.flush(); - } - } - - /** - * Like {@link #dump(FileDescriptor, String[])}, but ensures the target - * executes asynchronously. - */ - public void dumpAsync(final FileDescriptor fd, final String[] args) { - final FileOutputStream fout = new FileOutputStream(fd); - final PrintWriter pw = new FastPrintWriter(fout); - Thread thr = new Thread("Binder.dumpAsync") { - public void run() { - try { - dump(fd, pw, args); - } finally { - pw.flush(); - } - } - }; - thr.start(); - } - - /** - * Print the object's state into the given stream. - * - * @param fd The raw file descriptor that the dump is being sent to. - * @param fout The file to which you should dump your state. This will be - * closed for you after you return. - * @param args additional arguments to the dump request. - */ - protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { - } - - /** - * Default implementation rewinds the parcels and calls onTransact. On - * the remote side, transact calls into the binder to do the IPC. - */ - public final boolean transact(int code, Parcel data, Parcel reply, - int flags) throws RemoteException { - if (false) Log.v("Binder", "Transact: " + code + " to " + this); - if (data != null) { - data.setDataPosition(0); - } - boolean r = onTransact(code, data, reply, flags); - if (reply != null) { - reply.setDataPosition(0); - } - return r; - } - - /** - * Local implementation is a no-op. - */ - public void linkToDeath(DeathRecipient recipient, int flags) { - } - - /** - * Local implementation is a no-op. - */ - public boolean unlinkToDeath(DeathRecipient recipient, int flags) { - return true; - } - - protected void finalize() throws Throwable { - try { - destroy(); - } finally { - super.finalize(); - } - } - - static void checkParcel(IBinder obj, int code, Parcel parcel, String msg) { - if (CHECK_PARCEL_SIZE && parcel.dataSize() >= 800*1024) { - // Trying to send > 800k, this is way too much - StringBuilder sb = new StringBuilder(); - sb.append(msg); - sb.append(": on "); - sb.append(obj); - sb.append(" calling "); - sb.append(code); - sb.append(" size "); - sb.append(parcel.dataSize()); - sb.append(" (data: "); - parcel.setDataPosition(0); - sb.append(parcel.readInt()); - sb.append(", "); - sb.append(parcel.readInt()); - sb.append(", "); - sb.append(parcel.readInt()); - sb.append(")"); - Slog.wtfStack(TAG, sb.toString()); - } - } - - private native final void init(); - private native final void destroy(); - - // Entry point from android_util_Binder.cpp's onTransact - private boolean execTransact(int code, long dataObj, long replyObj, - int flags) { - Parcel data = Parcel.obtain(dataObj); - Parcel reply = Parcel.obtain(replyObj); - // theoretically, we should call transact, which will call onTransact, - // but all that does is rewind it, and we just got these from an IPC, - // so we'll just call it directly. - boolean res; - // Log any exceptions as warnings, don't silently suppress them. - // If the call was FLAG_ONEWAY then these exceptions disappear into the ether. - try { - res = onTransact(code, data, reply, flags); - } catch (RemoteException e) { - if ((flags & FLAG_ONEWAY) != 0) { - Log.w(TAG, "Binder call failed.", e); - } else { - reply.setDataPosition(0); - reply.writeException(e); - } - res = true; - } catch (RuntimeException e) { - if ((flags & FLAG_ONEWAY) != 0) { - Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e); - } else { - reply.setDataPosition(0); - reply.writeException(e); - } - res = true; - } catch (OutOfMemoryError e) { - // Unconditionally log this, since this is generally unrecoverable. - Log.e(TAG, "Caught an OutOfMemoryError from the binder stub implementation.", e); - RuntimeException re = new RuntimeException("Out of memory", e); - reply.setDataPosition(0); - reply.writeException(re); - res = true; - } - checkParcel(this, code, reply, "Unreasonably large binder reply buffer"); - reply.recycle(); - data.recycle(); - - // Just in case -- we are done with the IPC, so there should be no more strict - // mode violations that have gathered for this thread. Either they have been - // parceled and are now in transport off to the caller, or we are returning back - // to the main transaction loop to wait for another incoming transaction. Either - // way, strict mode begone! - StrictMode.clearGatheredViolations(); - - return res; - } -} - -final class BinderProxy implements IBinder { - public native boolean pingBinder(); - public native boolean isBinderAlive(); - - public IInterface queryLocalInterface(String descriptor) { - return null; - } - - public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { - Binder.checkParcel(this, code, data, "Unreasonably large binder buffer"); - return transactNative(code, data, reply, flags); - } - - public native String getInterfaceDescriptor() throws RemoteException; - public native boolean transactNative(int code, Parcel data, Parcel reply, - int flags) throws RemoteException; - public native void linkToDeath(DeathRecipient recipient, int flags) - throws RemoteException; - public native boolean unlinkToDeath(DeathRecipient recipient, int flags); - - public void dump(FileDescriptor fd, String[] args) throws RemoteException { - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - data.writeFileDescriptor(fd); - data.writeStringArray(args); - try { - transact(DUMP_TRANSACTION, data, reply, 0); - reply.readException(); - } finally { - data.recycle(); - reply.recycle(); - } - } - - public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException { - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - data.writeFileDescriptor(fd); - data.writeStringArray(args); - try { - transact(DUMP_TRANSACTION, data, reply, FLAG_ONEWAY); - } finally { - data.recycle(); - reply.recycle(); - } - } - - BinderProxy() { - mSelf = new WeakReference(this); - } - - @Override - protected void finalize() throws Throwable { - try { - destroy(); - } finally { - super.finalize(); - } - } - - private native final void destroy(); - - private static final void sendDeathNotice(DeathRecipient recipient) { - if (false) Log.v("JavaBinder", "sendDeathNotice to " + recipient); - try { - recipient.binderDied(); - } - catch (RuntimeException exc) { - Log.w("BinderNative", "Uncaught exception from death notification", - exc); - } - } - - final private WeakReference mSelf; - private long mObject; - private long mOrgue; -} diff --git a/src/main/java/android/os/BinderThreadPriorityService.java b/src/main/java/android/os/BinderThreadPriorityService.java deleted file mode 100644 index 47a4483..0000000 --- a/src/main/java/android/os/BinderThreadPriorityService.java +++ /dev/null @@ -1,62 +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.os; - -import android.app.Service; -import android.content.Intent; -import android.text.TextUtils; -import android.util.Log; - -/** - * Service used by {@link BinderThreadPriorityTest} to verify - * the conveyance of thread priorities over Binder. - */ -public class BinderThreadPriorityService extends Service { - private static final String TAG = "BinderThreadPriorityService"; - - private final IBinderThreadPriorityService.Stub mBinder = - new IBinderThreadPriorityService.Stub() { - public int getThreadPriority() { - return Process.getThreadPriority(Process.myTid()); - } - - public String getThreadSchedulerGroup() { - return BinderThreadPriorityTest.getSchedulerGroup(); - } - - public void callBack(IBinderThreadPriorityService recurse) { - try { - recurse.callBack(this); - } catch (RemoteException e) { - Log.e(TAG, "Binder callback failed", e); - } - } - - public void setPriorityAndCallBack(int priority, IBinderThreadPriorityService recurse) { - Process.setThreadPriority(priority); - try { - recurse.callBack(this); - } catch (RemoteException e) { - Log.e(TAG, "Binder callback failed", e); - } - } - }; - - public IBinder onBind(Intent intent) { - return mBinder; - } -} diff --git a/src/main/java/android/os/BinderThreadPriorityTest.java b/src/main/java/android/os/BinderThreadPriorityTest.java deleted file mode 100644 index 7a4980a..0000000 --- a/src/main/java/android/os/BinderThreadPriorityTest.java +++ /dev/null @@ -1,146 +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.os; - -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.MediumTest; -import android.util.Log; - -import java.io.File; -import java.io.IOException; - -/** - * Test whether Binder calls inherit thread priorities correctly. - */ -public class BinderThreadPriorityTest extends AndroidTestCase { - private static final String TAG = "BinderThreadPriorityTest"; - private IBinderThreadPriorityService mService; - private int mSavedPriority; - - private ServiceConnection mConnection = new ServiceConnection() { - public void onServiceConnected(ComponentName name, IBinder service) { - synchronized (BinderThreadPriorityTest.this) { - mService = IBinderThreadPriorityService.Stub.asInterface(service); - BinderThreadPriorityTest.this.notifyAll(); - } - } - - public void onServiceDisconnected(ComponentName name) { - mService = null; - } - }; - - private static class ServiceStub extends IBinderThreadPriorityService.Stub { - public int getThreadPriority() { fail(); return -999; } - public String getThreadSchedulerGroup() { fail(); return null; } - public void setPriorityAndCallBack(int p, IBinderThreadPriorityService cb) { fail(); } - public void callBack(IBinderThreadPriorityService cb) { fail(); } - private static void fail() { throw new RuntimeException("unimplemented"); } - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - - getContext().bindService( - new Intent(getContext(), BinderThreadPriorityService.class), - mConnection, Context.BIND_AUTO_CREATE); - - synchronized (this) { - if (mService == null) { - try { - wait(30000); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - assertNotNull("Gave up waiting for BinderThreadPriorityService", mService); - } - } - - mSavedPriority = Process.getThreadPriority(Process.myTid()); - Process.setThreadPriority(mSavedPriority); // To realign priority & cgroup, if needed - assertEquals(expectedSchedulerGroup(mSavedPriority), getSchedulerGroup()); - Log.i(TAG, "Saved priority: " + mSavedPriority); - } - - @Override - protected void tearDown() throws Exception { - // HACK -- see bug 2665914 -- setThreadPriority() doesn't always set the - // scheduler group reliably unless we start out with background priority. - Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); - Process.setThreadPriority(mSavedPriority); - assertEquals(mSavedPriority, Process.getThreadPriority(Process.myTid())); - assertEquals(expectedSchedulerGroup(mSavedPriority), getSchedulerGroup()); - - getContext().unbindService(mConnection); - super.tearDown(); - } - - public static String getSchedulerGroup() { - String fn = "/proc/" + Process.myPid() + "/task/" + Process.myTid() + "/cgroup"; - try { - String cgroup = FileUtils.readTextFile(new File(fn), 1024, null); - for (String line : cgroup.split("\n")) { - String fields[] = line.trim().split(":"); - if (fields.length == 3 && fields[1].equals("cpu")) return fields[2]; - } - } catch (IOException e) { - Log.e(TAG, "Can't read: " + fn, e); - } - return null; // Unknown - } - - public static String expectedSchedulerGroup(int prio) { - return prio < Process.THREAD_PRIORITY_BACKGROUND ? "/" : "/bg_non_interactive"; - } - - public void testPassPriorityToService() throws Exception { - for (int prio = 19; prio >= -20; prio--) { - Process.setThreadPriority(prio); - - // Local - assertEquals(prio, Process.getThreadPriority(Process.myTid())); - assertEquals(expectedSchedulerGroup(prio), getSchedulerGroup()); - - // Remote - assertEquals(prio, mService.getThreadPriority()); - assertEquals(expectedSchedulerGroup(prio), mService.getThreadSchedulerGroup()); - } - } - - public void testCallBackFromServiceWithPriority() throws Exception { - for (int prio = -20; prio <= 19; prio++) { - final int expected = prio; - mService.setPriorityAndCallBack(prio, new ServiceStub() { - public void callBack(IBinderThreadPriorityService cb) { - assertEquals(expected, Process.getThreadPriority(Process.myTid())); - assertEquals(expectedSchedulerGroup(expected), getSchedulerGroup()); - } - }); - - assertEquals(mSavedPriority, Process.getThreadPriority(Process.myTid())); - - // BROKEN -- see bug 2665954 -- scheduler group doesn't get reset - // properly after a back-call with a different priority. - // assertEquals(expectedSchedulerGroup(mSavedPriority), getSchedulerGroup()); - } - } -} diff --git a/src/main/java/android/os/BrightnessLimit.java b/src/main/java/android/os/BrightnessLimit.java deleted file mode 100644 index f4a5e09..0000000 --- a/src/main/java/android/os/BrightnessLimit.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.os.IPowerManager; - -import android.app.Activity; -import android.os.Bundle; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.provider.Settings; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.Button; - -import com.android.frameworks.coretests.R; - -/** - * Tries to set the brightness to 0. Should be silently thwarted by the framework. - */ -public class BrightnessLimit extends Activity implements OnClickListener { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.brightness_limit); - - Button b = (Button) findViewById(R.id.go); - b.setOnClickListener(this); - } - - public void onClick(View v) { - IPowerManager power = IPowerManager.Stub.asInterface( - ServiceManager.getService("power")); - if (power != null) { - try { - power.setTemporaryScreenBrightnessSettingOverride(0); - } catch (RemoteException darn) { - - } - } - Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, 0); - } -} - diff --git a/src/main/java/android/os/Broadcaster.java b/src/main/java/android/os/Broadcaster.java deleted file mode 100644 index 70dcdd8..0000000 --- a/src/main/java/android/os/Broadcaster.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -/** @hide */ -public class Broadcaster -{ - public Broadcaster() - { - } - - /** - * Sign up for notifications about something. - * - * When this broadcaster pushes a message with senderWhat in the what field, - * target will be sent a copy of that message with targetWhat in the what field. - */ - public void request(int senderWhat, Handler target, int targetWhat) - { - synchronized (this) { - Registration r = null; - if (mReg == null) { - r = new Registration(); - r.senderWhat = senderWhat; - r.targets = new Handler[1]; - r.targetWhats = new int[1]; - r.targets[0] = target; - r.targetWhats[0] = targetWhat; - mReg = r; - r.next = r; - r.prev = r; - } else { - // find its place in the map - Registration start = mReg; - r = start; - do { - if (r.senderWhat >= senderWhat) { - break; - } - r = r.next; - } while (r != start); - int n; - if (r.senderWhat != senderWhat) { - // we didn't find a senderWhat match, but r is right - // after where it goes - Registration reg = new Registration(); - reg.senderWhat = senderWhat; - reg.targets = new Handler[1]; - reg.targetWhats = new int[1]; - reg.next = r; - reg.prev = r.prev; - r.prev.next = reg; - r.prev = reg; - - if (r == mReg && r.senderWhat > reg.senderWhat) { - mReg = reg; - } - - r = reg; - n = 0; - } else { - n = r.targets.length; - Handler[] oldTargets = r.targets; - int[] oldWhats = r.targetWhats; - // check for duplicates, and don't do it if we are dup. - for (int i=0; i= senderWhat) { - break; - } - r = r.next; - } while (r != start); - - if (r.senderWhat == senderWhat) { - Handler[] targets = r.targets; - int[] whats = r.targetWhats; - int oldLen = targets.length; - for (int i=0; i 0) { - System.arraycopy(targets, 0, r.targets, 0, i); - System.arraycopy(whats, 0, r.targetWhats, 0, i); - } - - int remainingLen = oldLen-i-1; - if (remainingLen != 0) { - System.arraycopy(targets, i+1, r.targets, i, - remainingLen); - System.arraycopy(whats, i+1, r.targetWhats, i, - remainingLen); - } - break; - } - } - } - } - } - - /** - * For debugging purposes, print the registrations to System.out - */ - public void dumpRegistrations() - { - synchronized (this) { - Registration start = mReg; - System.out.println("Broadcaster " + this + " {"); - if (start != null) { - Registration r = start; - do { - System.out.println(" senderWhat=" + r.senderWhat); - int n = r.targets.length; - for (int i=0; i= senderWhat) { - break; - } - r = r.next; - } while (r != start); - if (r.senderWhat == senderWhat) { - Handler[] targets = r.targets; - int[] whats = r.targetWhats; - int n = targets.length; - for (int i=0; i= N) { - failure(); - } else { - if (msg.getTarget() == mHandlers[index]) { - mSuccess[index] = true; - } - } - boolean winner = true; - for (int i = 0; i < N; i++) { - if (!mSuccess[i]) { - winner = false; - } - } - if (winner) { - success(); - } - } - } - - @MediumTest - public void test2() throws Exception { - /* - * 2 handlers request the same message, with different translations - */ - HandlerTester tester = new Tests2and3(2); - tester.doTest(1000); - } - - @MediumTest - public void test3() throws Exception { - /* - * 1000 handlers request the same message, with different translations - */ - HandlerTester tester = new Tests2and3(10); - tester.doTest(1000); - } - - @MediumTest - public void test4() throws Exception { - /* - * Two handlers request different messages, with translations, sending - * only one. The other one should never get sent. - */ - HandlerTester tester = new HandlerTester() { - Handler h1; - Handler h2; - - public void go() { - Broadcaster b = new Broadcaster(); - h1 = new H(); - h2 = new H(); - - b.request(MESSAGE_A, h1, MESSAGE_C); - b.request(MESSAGE_B, h2, MESSAGE_D); - - Message msg = new Message(); - msg.what = MESSAGE_A; - - b.broadcast(msg); - } - - public void handleMessage(Message msg) { - if (msg.what == MESSAGE_C && msg.getTarget() == h1) { - success(); - } else { - failure(); - } - } - }; - tester.doTest(1000); - } - - @MediumTest - public void test5() throws Exception { - /* - * Two handlers request different messages, with translations, sending - * only one. The other one should never get sent. - */ - HandlerTester tester = new HandlerTester() { - Handler h1; - Handler h2; - - public void go() { - Broadcaster b = new Broadcaster(); - h1 = new H(); - h2 = new H(); - - b.request(MESSAGE_A, h1, MESSAGE_C); - b.request(MESSAGE_B, h2, MESSAGE_D); - - Message msg = new Message(); - msg.what = MESSAGE_B; - - b.broadcast(msg); - } - - public void handleMessage(Message msg) { - if (msg.what == MESSAGE_D && msg.getTarget() == h2) { - success(); - } else { - failure(); - } - } - }; - tester.doTest(1000); - } - - @MediumTest - public void test6() throws Exception { - /* - * Two handlers request same message. Cancel the request for the - * 2nd handler, make sure the first still works. - */ - HandlerTester tester = new HandlerTester() { - Handler h1; - Handler h2; - - public void go() { - Broadcaster b = new Broadcaster(); - h1 = new H(); - h2 = new H(); - - b.request(MESSAGE_A, h1, MESSAGE_C); - b.request(MESSAGE_A, h2, MESSAGE_D); - b.cancelRequest(MESSAGE_A, h2, MESSAGE_D); - - Message msg = new Message(); - msg.what = MESSAGE_A; - - b.broadcast(msg); - } - - public void handleMessage(Message msg) { - if (msg.what == MESSAGE_C && msg.getTarget() == h1) { - success(); - } else { - failure(); - } - } - }; - tester.doTest(1000); - } -} diff --git a/src/main/java/android/os/Build.java b/src/main/java/android/os/Build.java deleted file mode 100644 index 4b0cef6..0000000 --- a/src/main/java/android/os/Build.java +++ /dev/null @@ -1,712 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.text.TextUtils; -import android.util.Slog; - -import com.android.internal.telephony.TelephonyProperties; - -import dalvik.system.VMRuntime; - -import java.util.Objects; - -/** - * Information about the current build, extracted from system properties. - */ -public class Build { - private static final String TAG = "Build"; - - /** Value used for when a build property is unknown. */ - public static final String UNKNOWN = "unknown"; - - /** Either a changelist number, or a label like "M4-rc20". */ - public static final String ID = getString("ro.build.id"); - - /** A build ID string meant for displaying to the user */ - public static final String DISPLAY = getString("ro.build.display.id"); - - /** The name of the overall product. */ - public static final String PRODUCT = getString("ro.product.name"); - - /** The name of the industrial design. */ - public static final String DEVICE = getString("ro.product.device"); - - /** The name of the underlying board, like "goldfish". */ - public static final String BOARD = getString("ro.product.board"); - - /** - * The name of the instruction set (CPU type + ABI convention) of native code. - * - * @deprecated Use {@link #SUPPORTED_ABIS} instead. - */ - @Deprecated - public static final String CPU_ABI; - - /** - * The name of the second instruction set (CPU type + ABI convention) of native code. - * - * @deprecated Use {@link #SUPPORTED_ABIS} instead. - */ - @Deprecated - public static final String CPU_ABI2; - - /** The manufacturer of the product/hardware. */ - public static final String MANUFACTURER = getString("ro.product.manufacturer"); - - /** The consumer-visible brand with which the product/hardware will be associated, if any. */ - public static final String BRAND = getString("ro.product.brand"); - - /** The end-user-visible name for the end product. */ - public static final String MODEL = getString("ro.product.model"); - - /** The system bootloader version number. */ - public static final String BOOTLOADER = getString("ro.bootloader"); - - /** - * The radio firmware version number. - * - * @deprecated The radio firmware version is frequently not - * available when this class is initialized, leading to a blank or - * "unknown" value for this string. Use - * {@link #getRadioVersion} instead. - */ - @Deprecated - public static final String RADIO = getString(TelephonyProperties.PROPERTY_BASEBAND_VERSION); - - /** The name of the hardware (from the kernel command line or /proc). */ - public static final String HARDWARE = getString("ro.hardware"); - - /** A hardware serial number, if available. Alphanumeric only, case-insensitive. */ - public static final String SERIAL = getString("ro.serialno"); - - /** - * An ordered list of ABIs supported by this device. The most preferred ABI is the first - * element in the list. - * - * See {@link #SUPPORTED_32_BIT_ABIS} and {@link #SUPPORTED_64_BIT_ABIS}. - */ - public static final String[] SUPPORTED_ABIS = getStringList("ro.product.cpu.abilist", ","); - - /** - * An ordered list of 32 bit ABIs supported by this device. The most preferred ABI - * is the first element in the list. - * - * See {@link #SUPPORTED_ABIS} and {@link #SUPPORTED_64_BIT_ABIS}. - */ - public static final String[] SUPPORTED_32_BIT_ABIS = - getStringList("ro.product.cpu.abilist32", ","); - - /** - * An ordered list of 64 bit ABIs supported by this device. The most preferred ABI - * is the first element in the list. - * - * See {@link #SUPPORTED_ABIS} and {@link #SUPPORTED_32_BIT_ABIS}. - */ - public static final String[] SUPPORTED_64_BIT_ABIS = - getStringList("ro.product.cpu.abilist64", ","); - - - static { - /* - * Adjusts CPU_ABI and CPU_ABI2 depending on whether or not a given process is 64 bit. - * 32 bit processes will always see 32 bit ABIs in these fields for backward - * compatibility. - */ - final String[] abiList; - if (VMRuntime.getRuntime().is64Bit()) { - abiList = SUPPORTED_64_BIT_ABIS; - } else { - abiList = SUPPORTED_32_BIT_ABIS; - } - - CPU_ABI = abiList[0]; - if (abiList.length > 1) { - CPU_ABI2 = abiList[1]; - } else { - CPU_ABI2 = ""; - } - } - - /** Various version strings. */ - public static class VERSION { - /** - * The internal value used by the underlying source control to - * represent this build. E.g., a perforce changelist number - * or a git hash. - */ - public static final String INCREMENTAL = getString("ro.build.version.incremental"); - - /** - * The user-visible version string. E.g., "1.0" or "3.4b5". - */ - public static final String RELEASE = getString("ro.build.version.release"); - - /** - * The user-visible SDK version of the framework in its raw String - * representation; use {@link #SDK_INT} instead. - * - * @deprecated Use {@link #SDK_INT} to easily get this as an integer. - */ - @Deprecated - public static final String SDK = getString("ro.build.version.sdk"); - - /** - * The user-visible SDK version of the framework; its possible - * values are defined in {@link Build.VERSION_CODES}. - */ - public static final int SDK_INT = SystemProperties.getInt( - "ro.build.version.sdk", 0); - - /** - * The current development codename, or the string "REL" if this is - * a release build. - */ - public static final String CODENAME = getString("ro.build.version.codename"); - - private static final String[] ALL_CODENAMES - = getStringList("ro.build.version.all_codenames", ","); - - /** - * @hide - */ - public static final String[] ACTIVE_CODENAMES = "REL".equals(ALL_CODENAMES[0]) - ? new String[0] : ALL_CODENAMES; - - /** - * The SDK version to use when accessing resources. - * Use the current SDK version code. For every active development codename - * we are operating under, we bump the assumed resource platform version by 1. - * @hide - */ - public static final int RESOURCES_SDK_INT = SDK_INT + ACTIVE_CODENAMES.length; - } - - /** - * Enumeration of the currently known SDK version codes. These are the - * values that can be found in {@link VERSION#SDK}. Version numbers - * increment monotonically with each official platform release. - */ - public static class VERSION_CODES { - /** - * Magic version number for a current development build, which has - * not yet turned into an official release. - */ - public static final int CUR_DEVELOPMENT = 10000; - - /** - * October 2008: The original, first, version of Android. Yay! - */ - public static final int BASE = 1; - - /** - * February 2009: First Android update, officially called 1.1. - */ - public static final int BASE_1_1 = 2; - - /** - * May 2009: Android 1.5. - */ - public static final int CUPCAKE = 3; - - /** - * September 2009: Android 1.6. - * - *

Applications targeting this or a later release will get these - * new changes in behavior:

- *
    - *
  • They must explicitly request the - * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission to be - * able to modify the contents of the SD card. (Apps targeting - * earlier versions will always request the permission.) - *
  • They must explicitly request the - * {@link android.Manifest.permission#READ_PHONE_STATE} permission to be - * able to be able to retrieve phone state info. (Apps targeting - * earlier versions will always request the permission.) - *
  • They are assumed to support different screen densities and - * sizes. (Apps targeting earlier versions are assumed to only support - * medium density normal size screens unless otherwise indicated). - * They can still explicitly specify screen support either way with the - * supports-screens manifest tag. - *
  • {@link android.widget.TabHost} will use the new dark tab - * background design. - *
- */ - public static final int DONUT = 4; - - /** - * November 2009: Android 2.0 - * - *

Applications targeting this or a later release will get these - * new changes in behavior:

- *
    - *
  • The {@link android.app.Service#onStartCommand - * Service.onStartCommand} function will return the new - * {@link android.app.Service#START_STICKY} behavior instead of the - * old compatibility {@link android.app.Service#START_STICKY_COMPATIBILITY}. - *
  • The {@link android.app.Activity} class will now execute back - * key presses on the key up instead of key down, to be able to detect - * canceled presses from virtual keys. - *
  • The {@link android.widget.TabWidget} class will use a new color scheme - * for tabs. In the new scheme, the foreground tab has a medium gray background - * the background tabs have a dark gray background. - *
- */ - public static final int ECLAIR = 5; - - /** - * December 2009: Android 2.0.1 - */ - public static final int ECLAIR_0_1 = 6; - - /** - * January 2010: Android 2.1 - */ - public static final int ECLAIR_MR1 = 7; - - /** - * June 2010: Android 2.2 - */ - public static final int FROYO = 8; - - /** - * November 2010: Android 2.3 - * - *

Applications targeting this or a later release will get these - * new changes in behavior:

- *
    - *
  • The application's notification icons will be shown on the new - * dark status bar background, so must be visible in this situation. - *
- */ - public static final int GINGERBREAD = 9; - - /** - * February 2011: Android 2.3.3. - */ - public static final int GINGERBREAD_MR1 = 10; - - /** - * February 2011: Android 3.0. - * - *

Applications targeting this or a later release will get these - * new changes in behavior:

- *
    - *
  • The default theme for applications is now dark holographic: - * {@link android.R.style#Theme_Holo}. - *
  • On large screen devices that do not have a physical menu - * button, the soft (compatibility) menu is disabled. - *
  • The activity lifecycle has changed slightly as per - * {@link android.app.Activity}. - *
  • An application will crash if it does not call through - * to the super implementation of its - * {@link android.app.Activity#onPause Activity.onPause()} method. - *
  • When an application requires a permission to access one of - * its components (activity, receiver, service, provider), this - * permission is no longer enforced when the application wants to - * access its own component. This means it can require a permission - * on a component that it does not itself hold and still access that - * component. - *
  • {@link android.content.Context#getSharedPreferences - * Context.getSharedPreferences()} will not automatically reload - * the preferences if they have changed on storage, unless - * {@link android.content.Context#MODE_MULTI_PROCESS} is used. - *
  • {@link android.view.ViewGroup#setMotionEventSplittingEnabled} - * will default to true. - *
  • {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} - * is enabled by default on windows. - *
  • {@link android.widget.PopupWindow#isSplitTouchEnabled() - * PopupWindow.isSplitTouchEnabled()} will return true by default. - *
  • {@link android.widget.GridView} and {@link android.widget.ListView} - * will use {@link android.view.View#setActivated View.setActivated} - * for selected items if they do not implement {@link android.widget.Checkable}. - *
  • {@link android.widget.Scroller} will be constructed with - * "flywheel" behavior enabled by default. - *
- */ - public static final int HONEYCOMB = 11; - - /** - * May 2011: Android 3.1. - */ - public static final int HONEYCOMB_MR1 = 12; - - /** - * June 2011: Android 3.2. - * - *

Update to Honeycomb MR1 to support 7 inch tablets, improve - * screen compatibility mode, etc.

- * - *

As of this version, applications that don't say whether they - * support XLARGE screens will be assumed to do so only if they target - * {@link #HONEYCOMB} or later; it had been {@link #GINGERBREAD} or - * later. Applications that don't support a screen size at least as - * large as the current screen will provide the user with a UI to - * switch them in to screen size compatibility mode.

- * - *

This version introduces new screen size resource qualifiers - * based on the screen size in dp: see - * {@link android.content.res.Configuration#screenWidthDp}, - * {@link android.content.res.Configuration#screenHeightDp}, and - * {@link android.content.res.Configuration#smallestScreenWidthDp}. - * Supplying these in <supports-screens> as per - * {@link android.content.pm.ApplicationInfo#requiresSmallestWidthDp}, - * {@link android.content.pm.ApplicationInfo#compatibleWidthLimitDp}, and - * {@link android.content.pm.ApplicationInfo#largestWidthLimitDp} is - * preferred over the older screen size buckets and for older devices - * the appropriate buckets will be inferred from them.

- * - *

Applications targeting this or a later release will get these - * new changes in behavior:

- *
    - *
  • New {@link android.content.pm.PackageManager#FEATURE_SCREEN_PORTRAIT} - * and {@link android.content.pm.PackageManager#FEATURE_SCREEN_LANDSCAPE} - * features were introduced in this release. Applications that target - * previous platform versions are assumed to require both portrait and - * landscape support in the device; when targeting Honeycomb MR1 or - * greater the application is responsible for specifying any specific - * orientation it requires.

    - *
  • {@link android.os.AsyncTask} will use the serial executor - * by default when calling {@link android.os.AsyncTask#execute}.

    - *
  • {@link android.content.pm.ActivityInfo#configChanges - * ActivityInfo.configChanges} will have the - * {@link android.content.pm.ActivityInfo#CONFIG_SCREEN_SIZE} and - * {@link android.content.pm.ActivityInfo#CONFIG_SMALLEST_SCREEN_SIZE} - * bits set; these need to be cleared for older applications because - * some developers have done absolute comparisons against this value - * instead of correctly masking the bits they are interested in. - *

- */ - public static final int HONEYCOMB_MR2 = 13; - - /** - * October 2011: Android 4.0. - * - *

Applications targeting this or a later release will get these - * new changes in behavior:

- *
    - *
  • For devices without a dedicated menu key, the software compatibility - * menu key will not be shown even on phones. By targeting Ice Cream Sandwich - * or later, your UI must always have its own menu UI affordance if needed, - * on both tablets and phones. The ActionBar will take care of this for you. - *
  • 2d drawing hardware acceleration is now turned on by default. - * You can use - * {@link android.R.attr#hardwareAccelerated android:hardwareAccelerated} - * to turn it off if needed, although this is strongly discouraged since - * it will result in poor performance on larger screen devices. - *
  • The default theme for applications is now the "device default" theme: - * {@link android.R.style#Theme_DeviceDefault}. This may be the - * holo dark theme or a different dark theme defined by the specific device. - * The {@link android.R.style#Theme_Holo} family must not be modified - * for a device to be considered compatible. Applications that explicitly - * request a theme from the Holo family will be guaranteed that these themes - * will not change character within the same platform version. Applications - * that wish to blend in with the device should use a theme from the - * {@link android.R.style#Theme_DeviceDefault} family. - *
  • Managed cursors can now throw an exception if you directly close - * the cursor yourself without stopping the management of it; previously failures - * would be silently ignored. - *
  • The fadingEdge attribute on views will be ignored (fading edges is no - * longer a standard part of the UI). A new requiresFadingEdge attribute allows - * applications to still force fading edges on for special cases. - *
  • {@link android.content.Context#bindService Context.bindService()} - * will not automatically add in {@link android.content.Context#BIND_WAIVE_PRIORITY}. - *
  • App Widgets will have standard padding automatically added around - * them, rather than relying on the padding being baked into the widget itself. - *
  • An exception will be thrown if you try to change the type of a - * window after it has been added to the window manager. Previously this - * would result in random incorrect behavior. - *
  • {@link android.view.animation.AnimationSet} will parse out - * the duration, fillBefore, fillAfter, repeatMode, and startOffset - * XML attributes that are defined. - *
  • {@link android.app.ActionBar#setHomeButtonEnabled - * ActionBar.setHomeButtonEnabled()} is false by default. - *
- */ - public static final int ICE_CREAM_SANDWICH = 14; - - /** - * December 2011: Android 4.0.3. - */ - public static final int ICE_CREAM_SANDWICH_MR1 = 15; - - /** - * June 2012: Android 4.1. - * - *

Applications targeting this or a later release will get these - * new changes in behavior:

- *
    - *
  • You must explicitly request the {@link android.Manifest.permission#READ_CALL_LOG} - * and/or {@link android.Manifest.permission#WRITE_CALL_LOG} permissions; - * access to the call log is no longer implicitly provided through - * {@link android.Manifest.permission#READ_CONTACTS} and - * {@link android.Manifest.permission#WRITE_CONTACTS}. - *
  • {@link android.widget.RemoteViews} will throw an exception if - * setting an onClick handler for views being generated by a - * {@link android.widget.RemoteViewsService} for a collection container; - * previously this just resulted in a warning log message. - *
  • New {@link android.app.ActionBar} policy for embedded tabs: - * embedded tabs are now always stacked in the action bar when in portrait - * mode, regardless of the size of the screen. - *
  • {@link android.webkit.WebSettings#setAllowFileAccessFromFileURLs(boolean) - * WebSettings.setAllowFileAccessFromFileURLs} and - * {@link android.webkit.WebSettings#setAllowUniversalAccessFromFileURLs(boolean) - * WebSettings.setAllowUniversalAccessFromFileURLs} default to false. - *
  • Calls to {@link android.content.pm.PackageManager#setComponentEnabledSetting - * PackageManager.setComponentEnabledSetting} will now throw an - * IllegalArgumentException if the given component class name does not - * exist in the application's manifest. - *
  • {@link android.nfc.NfcAdapter#setNdefPushMessage - * NfcAdapter.setNdefPushMessage}, - * {@link android.nfc.NfcAdapter#setNdefPushMessageCallback - * NfcAdapter.setNdefPushMessageCallback} and - * {@link android.nfc.NfcAdapter#setOnNdefPushCompleteCallback - * NfcAdapter.setOnNdefPushCompleteCallback} will throw - * IllegalStateException if called after the Activity has been destroyed. - *
  • Accessibility services must require the new - * {@link android.Manifest.permission#BIND_ACCESSIBILITY_SERVICE} permission or - * they will not be available for use. - *
  • {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS - * AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} must be set - * for unimportant views to be included in queries. - *
- */ - public static final int JELLY_BEAN = 16; - - /** - * November 2012: Android 4.2, Moar jelly beans! - * - *

Applications targeting this or a later release will get these - * new changes in behavior:

- *
    - *
  • Content Providers: The default value of {@code android:exported} is now - * {@code false}. See - * - * the android:exported section in the provider documentation for more details.
  • - *
  • {@link android.view.View#getLayoutDirection() View.getLayoutDirection()} - * can return different values than {@link android.view.View#LAYOUT_DIRECTION_LTR} - * based on the locale etc. - *
  • {@link android.webkit.WebView#addJavascriptInterface(Object, String) - * WebView.addJavascriptInterface} requires explicit annotations on methods - * for them to be accessible from Javascript. - *
- */ - public static final int JELLY_BEAN_MR1 = 17; - - /** - * July 2013: Android 4.3, the revenge of the beans. - */ - public static final int JELLY_BEAN_MR2 = 18; - - /** - * October 2013: Android 4.4, KitKat, another tasty treat. - * - *

Applications targeting this or a later release will get these - * new changes in behavior:

- *
    - *
  • The default result of {android.preference.PreferenceActivity#isValidFragment - * PreferenceActivity.isValueFragment} becomes false instead of true.
  • - *
  • In {@link android.webkit.WebView}, apps targeting earlier versions will have - * JS URLs evaluated directly and any result of the evaluation will not replace - * the current page content. Apps targetting KITKAT or later that load a JS URL will - * have the result of that URL replace the content of the current page
  • - *
  • {@link android.app.AlarmManager#set AlarmManager.set} becomes interpreted as - * an inexact value, to give the system more flexibility in scheduling alarms.
  • - *
  • {@link android.content.Context#getSharedPreferences(String, int) - * Context.getSharedPreferences} no longer allows a null name.
  • - *
  • {@link android.widget.RelativeLayout} changes to compute wrapped content - * margins correctly.
  • - *
  • {@link android.app.ActionBar}'s window content overlay is allowed to be - * drawn.
  • - *
  • The {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} - * permission is now always enforced.
  • - *
  • Access to package-specific external storage directories belonging - * to the calling app no longer requires the - * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} or - * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} - * permissions.
  • - *
- */ - public static final int KITKAT = 19; - - /** - * Android 4.4W: KitKat for watches, snacks on the run. - * - *

Applications targeting this or a later release will get these - * new changes in behavior:

- *
    - *
  • {@link android.app.AlertDialog} might not have a default background if the theme does - * not specify one.
  • - *
- */ - public static final int KITKAT_WATCH = 20; - - /** - * Temporary until we completely switch to {@link #LOLLIPOP}. - * @hide - */ - public static final int L = 21; - - /** - * Lollipop. A flat one with beautiful shadows. But still tasty. - * - *

Applications targeting this or a later release will get these - * new changes in behavior:

- *
    - *
  • {@link android.content.Context#bindService Context.bindService} now - * requires an explicit Intent, and will throw an exception if given an implicit - * Intent.
  • - *
  • {@link android.app.Notification.Builder Notification.Builder} will - * not have the colors of their various notification elements adjusted to better - * match the new material design look.
  • - *
  • {@link android.os.Message} will validate that a message is not currently - * in use when it is recycled.
  • - *
  • Hardware accelerated drawing in windows will be enabled automatically - * in most places.
  • - *
  • {@link android.widget.Spinner} throws an exception if attaching an - * adapter with more than one item type.
  • - *
  • If the app is a launcher, the launcher will be available to the user - * even when they are using corporate profiles (which requires that the app - * use {@link android.content.pm.LauncherApps} to correctly populate its - * apps UI).
  • - *
  • Calling {@link android.app.Service#stopForeground Service.stopForeground} - * with removeNotification false will modify the still posted notification so that - * it is no longer forced to be ongoing.
  • - *
  • A {@link android.service.dreams.DreamService} must require the - * {@link android.Manifest.permission#BIND_DREAM_SERVICE} permission to be usable.
  • - *
- */ - public static final int LOLLIPOP = 21; - - /** - * Lollipop with an extra sugar coating on the outside! - */ - public static final int LOLLIPOP_MR1 = 22; - } - - /** The type of build, like "user" or "eng". */ - public static final String TYPE = getString("ro.build.type"); - - /** Comma-separated tags describing the build, like "unsigned,debug". */ - public static final String TAGS = getString("ro.build.tags"); - - /** A string that uniquely identifies this build. Do not attempt to parse this value. */ - public static final String FINGERPRINT = deriveFingerprint(); - - /** - * Some devices split the fingerprint components between multiple - * partitions, so we might derive the fingerprint at runtime. - */ - private static String deriveFingerprint() { - String finger = SystemProperties.get("ro.build.fingerprint"); - if (TextUtils.isEmpty(finger)) { - finger = getString("ro.product.brand") + '/' + - getString("ro.product.name") + '/' + - getString("ro.product.device") + ':' + - getString("ro.build.version.release") + '/' + - getString("ro.build.id") + '/' + - getString("ro.build.version.incremental") + ':' + - getString("ro.build.type") + '/' + - getString("ro.build.tags"); - } - return finger; - } - - /** - * Ensure that raw fingerprint system property is defined. If it was derived - * dynamically by {@link #deriveFingerprint()} this is where we push the - * derived value into the property service. - * - * @hide - */ - public static void ensureFingerprintProperty() { - if (TextUtils.isEmpty(SystemProperties.get("ro.build.fingerprint"))) { - try { - SystemProperties.set("ro.build.fingerprint", FINGERPRINT); - } catch (IllegalArgumentException e) { - Slog.e(TAG, "Failed to set fingerprint property", e); - } - } - } - - /** - * Check that device fingerprint is defined and that it matches across - * various partitions. - * - * @hide - */ - public static boolean isFingerprintConsistent() { - final String system = SystemProperties.get("ro.build.fingerprint"); - final String vendor = SystemProperties.get("ro.vendor.build.fingerprint"); - - if (TextUtils.isEmpty(system)) { - Slog.e(TAG, "Required ro.build.fingerprint is empty!"); - return false; - } - - if (!TextUtils.isEmpty(vendor)) { - if (!Objects.equals(system, vendor)) { - Slog.e(TAG, "Mismatched fingerprints; system reported " + system - + " but vendor reported " + vendor); - return false; - } - } - - return true; - } - - // The following properties only make sense for internal engineering builds. - public static final long TIME = getLong("ro.build.date.utc") * 1000; - public static final String USER = getString("ro.build.user"); - public static final String HOST = getString("ro.build.host"); - - /** - * Returns true if we are running a debug build such as "user-debug" or "eng". - * @hide - */ - public static final boolean IS_DEBUGGABLE = - SystemProperties.getInt("ro.debuggable", 0) == 1; - - /** - * Returns the version string for the radio firmware. May return - * null (if, for instance, the radio is not currently on). - */ - public static String getRadioVersion() { - return SystemProperties.get(TelephonyProperties.PROPERTY_BASEBAND_VERSION, null); - } - - private static String getString(String property) { - return SystemProperties.get(property, UNKNOWN); - } - - private static String[] getStringList(String property, String separator) { - String value = SystemProperties.get(property); - if (value.isEmpty()) { - return new String[0]; - } else { - return value.split(separator); - } - } - - private static long getLong(String property) { - try { - return Long.parseLong(SystemProperties.get(property)); - } catch (NumberFormatException e) { - return -1; - } - } -} diff --git a/src/main/java/android/os/BuildTest.java b/src/main/java/android/os/BuildTest.java deleted file mode 100644 index 3758627..0000000 --- a/src/main/java/android/os/BuildTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.os.Build; -import android.test.suitebuilder.annotation.SmallTest; -import android.util.Log; -import junit.framework.Assert; -import junit.framework.TestCase; - -/** - * Provides test cases for android.os.Build and, in turn, many of the - * system properties set by the build system. - */ -public class BuildTest extends TestCase { - - private static final String TAG = "BuildTest"; - - /** - * Asserts that a String is non-null and non-empty. If it is not, - * an AssertionFailedError is thrown with the given message. - */ - private static void assertNotEmpty(String message, String string) { - //Log.i(TAG, "" + message + ": " + string); - assertNotNull(message, string); - assertFalse(message, string.equals("")); - } - - /** - * Asserts that a String is non-null and non-empty. If it is not, - * an AssertionFailedError is thrown. - */ - private static void assertNotEmpty(String string) { - assertNotEmpty(null, string); - } - - /** - * Asserts that all android.os.Build fields are non-empty and/or in a valid range. - */ - @SmallTest - public void testBuildFields() throws Exception { - assertNotEmpty("ID", Build.ID); - assertNotEmpty("DISPLAY", Build.DISPLAY); - assertNotEmpty("PRODUCT", Build.PRODUCT); - assertNotEmpty("DEVICE", Build.DEVICE); - assertNotEmpty("BOARD", Build.BOARD); - assertNotEmpty("BRAND", Build.BRAND); - assertNotEmpty("MODEL", Build.MODEL); - assertNotEmpty("VERSION.INCREMENTAL", Build.VERSION.INCREMENTAL); - assertNotEmpty("VERSION.RELEASE", Build.VERSION.RELEASE); - assertNotEmpty("TYPE", Build.TYPE); - Assert.assertNotNull("TAGS", Build.TAGS); // TAGS is allowed to be empty. - assertNotEmpty("FINGERPRINT", Build.FINGERPRINT); - Assert.assertTrue("TIME", Build.TIME > 0); - assertNotEmpty("USER", Build.USER); - assertNotEmpty("HOST", Build.HOST); - - // TODO: if any of the android.os.Build fields have additional constraints - // (e.g., must be a C identifier, must be a valid filename, must not contain any spaces) - // add tests for them. - } -} diff --git a/src/main/java/android/os/Bundle.java b/src/main/java/android/os/Bundle.java deleted file mode 100644 index c5c5372..0000000 --- a/src/main/java/android/os/Bundle.java +++ /dev/null @@ -1,1064 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.util.ArrayMap; -import android.util.Size; -import android.util.SizeF; -import android.util.SparseArray; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -/** - * A mapping from String values to various Parcelable types. - * - */ -public final class Bundle extends BaseBundle implements Cloneable, Parcelable { - public static final Bundle EMPTY; - static final Parcel EMPTY_PARCEL; - - static { - EMPTY = new Bundle(); - EMPTY.mMap = ArrayMap.EMPTY; - EMPTY_PARCEL = BaseBundle.EMPTY_PARCEL; - } - - private boolean mHasFds = false; - private boolean mFdsKnown = true; - private boolean mAllowFds = true; - - /** - * Constructs a new, empty Bundle. - */ - public Bundle() { - super(); - } - - /** - * Constructs a Bundle whose data is stored as a Parcel. The data - * will be unparcelled on first contact, using the assigned ClassLoader. - * - * @param parcelledData a Parcel containing a Bundle - */ - Bundle(Parcel parcelledData) { - super(parcelledData); - - mHasFds = mParcelledData.hasFileDescriptors(); - mFdsKnown = true; - } - - /* package */ Bundle(Parcel parcelledData, int length) { - super(parcelledData, length); - - mHasFds = mParcelledData.hasFileDescriptors(); - mFdsKnown = true; - } - - /** - * Constructs a new, empty Bundle that uses a specific ClassLoader for - * instantiating Parcelable and Serializable objects. - * - * @param loader An explicit ClassLoader to use when instantiating objects - * inside of the Bundle. - */ - public Bundle(ClassLoader loader) { - super(loader); - } - - /** - * Constructs a new, empty Bundle sized to hold the given number of - * elements. The Bundle will grow as needed. - * - * @param capacity the initial capacity of the Bundle - */ - public Bundle(int capacity) { - super(capacity); - } - - /** - * Constructs a Bundle containing a copy of the mappings from the given - * Bundle. - * - * @param b a Bundle to be copied. - */ - public Bundle(Bundle b) { - super(b); - - mHasFds = b.mHasFds; - mFdsKnown = b.mFdsKnown; - } - - /** - * Constructs a Bundle containing a copy of the mappings from the given - * PersistableBundle. - * - * @param b a Bundle to be copied. - */ - public Bundle(PersistableBundle b) { - super(b); - } - - /** - * Make a Bundle for a single key/value pair. - * - * @hide - */ - public static Bundle forPair(String key, String value) { - Bundle b = new Bundle(1); - b.putString(key, value); - return b; - } - - /** - * Changes the ClassLoader this Bundle uses when instantiating objects. - * - * @param loader An explicit ClassLoader to use when instantiating objects - * inside of the Bundle. - */ - @Override - public void setClassLoader(ClassLoader loader) { - super.setClassLoader(loader); - } - - /** - * Return the ClassLoader currently associated with this Bundle. - */ - @Override - public ClassLoader getClassLoader() { - return super.getClassLoader(); - } - - /** @hide */ - public boolean setAllowFds(boolean allowFds) { - boolean orig = mAllowFds; - mAllowFds = allowFds; - return orig; - } - - /** - * Clones the current Bundle. The internal map is cloned, but the keys and - * values to which it refers are copied by reference. - */ - @Override - public Object clone() { - return new Bundle(this); - } - - /** - * Removes all elements from the mapping of this Bundle. - */ - @Override - public void clear() { - super.clear(); - - mHasFds = false; - mFdsKnown = true; - } - - /** - * Inserts all mappings from the given Bundle into this Bundle. - * - * @param bundle a Bundle - */ - public void putAll(Bundle bundle) { - unparcel(); - bundle.unparcel(); - mMap.putAll(bundle.mMap); - - // fd state is now known if and only if both bundles already knew - mHasFds |= bundle.mHasFds; - mFdsKnown = mFdsKnown && bundle.mFdsKnown; - } - - /** - * Reports whether the bundle contains any parcelled file descriptors. - */ - public boolean hasFileDescriptors() { - if (!mFdsKnown) { - boolean fdFound = false; // keep going until we find one or run out of data - - if (mParcelledData != null) { - if (mParcelledData.hasFileDescriptors()) { - fdFound = true; - } - } else { - // It's been unparcelled, so we need to walk the map - for (int i=mMap.size()-1; i>=0; i--) { - Object obj = mMap.valueAt(i); - if (obj instanceof Parcelable) { - if ((((Parcelable)obj).describeContents() - & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) { - fdFound = true; - break; - } - } else if (obj instanceof Parcelable[]) { - Parcelable[] array = (Parcelable[]) obj; - for (int n = array.length - 1; n >= 0; n--) { - if ((array[n].describeContents() - & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) { - fdFound = true; - break; - } - } - } else if (obj instanceof SparseArray) { - SparseArray array = - (SparseArray) obj; - for (int n = array.size() - 1; n >= 0; n--) { - if ((array.valueAt(n).describeContents() - & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) { - fdFound = true; - break; - } - } - } else if (obj instanceof ArrayList) { - ArrayList array = (ArrayList) obj; - // an ArrayList here might contain either Strings or - // Parcelables; only look inside for Parcelables - if (!array.isEmpty() && (array.get(0) instanceof Parcelable)) { - for (int n = array.size() - 1; n >= 0; n--) { - Parcelable p = (Parcelable) array.get(n); - if (p != null && ((p.describeContents() - & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0)) { - fdFound = true; - break; - } - } - } - } - } - } - - mHasFds = fdFound; - mFdsKnown = true; - } - return mHasFds; - } - - /** - * Inserts a byte value into the mapping of this Bundle, replacing - * any existing value for the given key. - * - * @param key a String, or null - * @param value a byte - */ - @Override - public void putByte(String key, byte value) { - super.putByte(key, value); - } - - /** - * Inserts a char value into the mapping of this Bundle, replacing - * any existing value for the given key. - * - * @param key a String, or null - * @param value a char, or null - */ - @Override - public void putChar(String key, char value) { - super.putChar(key, value); - } - - /** - * Inserts a short value into the mapping of this Bundle, replacing - * any existing value for the given key. - * - * @param key a String, or null - * @param value a short - */ - @Override - public void putShort(String key, short value) { - super.putShort(key, value); - } - - /** - * Inserts a float value into the mapping of this Bundle, replacing - * any existing value for the given key. - * - * @param key a String, or null - * @param value a float - */ - @Override - public void putFloat(String key, float value) { - super.putFloat(key, value); - } - - /** - * Inserts a CharSequence value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value a CharSequence, or null - */ - @Override - public void putCharSequence(String key, CharSequence value) { - super.putCharSequence(key, value); - } - - /** - * Inserts a Parcelable value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value a Parcelable object, or null - */ - public void putParcelable(String key, Parcelable value) { - unparcel(); - mMap.put(key, value); - mFdsKnown = false; - } - - /** - * Inserts a Size value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value a Size object, or null - */ - public void putSize(String key, Size value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Inserts a SizeF value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value a SizeF object, or null - */ - public void putSizeF(String key, SizeF value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Inserts an array of Parcelable values into the mapping of this Bundle, - * replacing any existing value for the given key. Either key or value may - * be null. - * - * @param key a String, or null - * @param value an array of Parcelable objects, or null - */ - public void putParcelableArray(String key, Parcelable[] value) { - unparcel(); - mMap.put(key, value); - mFdsKnown = false; - } - - /** - * Inserts a List of Parcelable values into the mapping of this Bundle, - * replacing any existing value for the given key. Either key or value may - * be null. - * - * @param key a String, or null - * @param value an ArrayList of Parcelable objects, or null - */ - public void putParcelableArrayList(String key, - ArrayList value) { - unparcel(); - mMap.put(key, value); - mFdsKnown = false; - } - - /** {@hide} */ - public void putParcelableList(String key, List value) { - unparcel(); - mMap.put(key, value); - mFdsKnown = false; - } - - /** - * Inserts a SparceArray of Parcelable values into the mapping of this - * Bundle, replacing any existing value for the given key. Either key - * or value may be null. - * - * @param key a String, or null - * @param value a SparseArray of Parcelable objects, or null - */ - public void putSparseParcelableArray(String key, - SparseArray value) { - unparcel(); - mMap.put(key, value); - mFdsKnown = false; - } - - /** - * Inserts an ArrayList value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value an ArrayList object, or null - */ - @Override - public void putIntegerArrayList(String key, ArrayList value) { - super.putIntegerArrayList(key, value); - } - - /** - * Inserts an ArrayList value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value an ArrayList object, or null - */ - @Override - public void putStringArrayList(String key, ArrayList value) { - super.putStringArrayList(key, value); - } - - /** - * Inserts an ArrayList value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value an ArrayList object, or null - */ - @Override - public void putCharSequenceArrayList(String key, ArrayList value) { - super.putCharSequenceArrayList(key, value); - } - - /** - * Inserts a Serializable value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value a Serializable object, or null - */ - @Override - public void putSerializable(String key, Serializable value) { - super.putSerializable(key, value); - } - - /** - * Inserts a byte array value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value a byte array object, or null - */ - @Override - public void putByteArray(String key, byte[] value) { - super.putByteArray(key, value); - } - - /** - * Inserts a short array value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value a short array object, or null - */ - @Override - public void putShortArray(String key, short[] value) { - super.putShortArray(key, value); - } - - /** - * Inserts a char array value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value a char array object, or null - */ - @Override - public void putCharArray(String key, char[] value) { - super.putCharArray(key, value); - } - - /** - * Inserts a float array value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value a float array object, or null - */ - @Override - public void putFloatArray(String key, float[] value) { - super.putFloatArray(key, value); - } - - /** - * Inserts a CharSequence array value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value a CharSequence array object, or null - */ - @Override - public void putCharSequenceArray(String key, CharSequence[] value) { - super.putCharSequenceArray(key, value); - } - - /** - * Inserts a Bundle value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value a Bundle object, or null - */ - public void putBundle(String key, Bundle value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Inserts an {@link IBinder} value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - *

You should be very careful when using this function. In many - * places where Bundles are used (such as inside of Intent objects), the Bundle - * can live longer inside of another process than the process that had originally - * created it. In that case, the IBinder you supply here will become invalid - * when your process goes away, and no longer usable, even if a new process is - * created for you later on.

- * - * @param key a String, or null - * @param value an IBinder object, or null - */ - public void putBinder(String key, IBinder value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Inserts an IBinder value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value an IBinder object, or null - * - * @deprecated - * @hide This is the old name of the function. - */ - @Deprecated - public void putIBinder(String key, IBinder value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Returns the value associated with the given key, or (byte) 0 if - * no mapping of the desired type exists for the given key. - * - * @param key a String - * @return a byte value - */ - @Override - public byte getByte(String key) { - return super.getByte(key); - } - - /** - * Returns the value associated with the given key, or defaultValue if - * no mapping of the desired type exists for the given key. - * - * @param key a String - * @param defaultValue Value to return if key does not exist - * @return a byte value - */ - @Override - public Byte getByte(String key, byte defaultValue) { - return super.getByte(key, defaultValue); - } - - /** - * Returns the value associated with the given key, or (char) 0 if - * no mapping of the desired type exists for the given key. - * - * @param key a String - * @return a char value - */ - @Override - public char getChar(String key) { - return super.getChar(key); - } - - /** - * Returns the value associated with the given key, or defaultValue if - * no mapping of the desired type exists for the given key. - * - * @param key a String - * @param defaultValue Value to return if key does not exist - * @return a char value - */ - @Override - public char getChar(String key, char defaultValue) { - return super.getChar(key, defaultValue); - } - - /** - * Returns the value associated with the given key, or (short) 0 if - * no mapping of the desired type exists for the given key. - * - * @param key a String - * @return a short value - */ - @Override - public short getShort(String key) { - return super.getShort(key); - } - - /** - * Returns the value associated with the given key, or defaultValue if - * no mapping of the desired type exists for the given key. - * - * @param key a String - * @param defaultValue Value to return if key does not exist - * @return a short value - */ - @Override - public short getShort(String key, short defaultValue) { - return super.getShort(key, defaultValue); - } - - /** - * Returns the value associated with the given key, or 0.0f if - * no mapping of the desired type exists for the given key. - * - * @param key a String - * @return a float value - */ - @Override - public float getFloat(String key) { - return super.getFloat(key); - } - - /** - * Returns the value associated with the given key, or defaultValue if - * no mapping of the desired type exists for the given key. - * - * @param key a String - * @param defaultValue Value to return if key does not exist - * @return a float value - */ - @Override - public float getFloat(String key, float defaultValue) { - return super.getFloat(key, defaultValue); - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return a CharSequence value, or null - */ - @Override - public CharSequence getCharSequence(String key) { - return super.getCharSequence(key); - } - - /** - * Returns the value associated with the given key, or defaultValue if - * no mapping of the desired type exists for the given key or if a null - * value is explicitly associatd with the given key. - * - * @param key a String, or null - * @param defaultValue Value to return if key does not exist or if a null - * value is associated with the given key. - * @return the CharSequence value associated with the given key, or defaultValue - * if no valid CharSequence object is currently mapped to that key. - */ - @Override - public CharSequence getCharSequence(String key, CharSequence defaultValue) { - return super.getCharSequence(key, defaultValue); - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return a Size value, or null - */ - public Size getSize(String key) { - unparcel(); - final Object o = mMap.get(key); - try { - return (Size) o; - } catch (ClassCastException e) { - typeWarning(key, o, "Size", e); - return null; - } - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return a Size value, or null - */ - public SizeF getSizeF(String key) { - unparcel(); - final Object o = mMap.get(key); - try { - return (SizeF) o; - } catch (ClassCastException e) { - typeWarning(key, o, "SizeF", e); - return null; - } - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return a Bundle value, or null - */ - public Bundle getBundle(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (Bundle) o; - } catch (ClassCastException e) { - typeWarning(key, o, "Bundle", e); - return null; - } - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return a Parcelable value, or null - */ - public T getParcelable(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (T) o; - } catch (ClassCastException e) { - typeWarning(key, o, "Parcelable", e); - return null; - } - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return a Parcelable[] value, or null - */ - public Parcelable[] getParcelableArray(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (Parcelable[]) o; - } catch (ClassCastException e) { - typeWarning(key, o, "Parcelable[]", e); - return null; - } - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return an ArrayList value, or null - */ - public ArrayList getParcelableArrayList(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (ArrayList) o; - } catch (ClassCastException e) { - typeWarning(key, o, "ArrayList", e); - return null; - } - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * - * @return a SparseArray of T values, or null - */ - public SparseArray getSparseParcelableArray(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (SparseArray) o; - } catch (ClassCastException e) { - typeWarning(key, o, "SparseArray", e); - return null; - } - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return a Serializable value, or null - */ - @Override - public Serializable getSerializable(String key) { - return super.getSerializable(key); - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return an ArrayList value, or null - */ - @Override - public ArrayList getIntegerArrayList(String key) { - return super.getIntegerArrayList(key); - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return an ArrayList value, or null - */ - @Override - public ArrayList getStringArrayList(String key) { - return super.getStringArrayList(key); - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return an ArrayList value, or null - */ - @Override - public ArrayList getCharSequenceArrayList(String key) { - return super.getCharSequenceArrayList(key); - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return a byte[] value, or null - */ - @Override - public byte[] getByteArray(String key) { - return super.getByteArray(key); - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return a short[] value, or null - */ - @Override - public short[] getShortArray(String key) { - return super.getShortArray(key); - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return a char[] value, or null - */ - @Override - public char[] getCharArray(String key) { - return super.getCharArray(key); - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return a float[] value, or null - */ - @Override - public float[] getFloatArray(String key) { - return super.getFloatArray(key); - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return a CharSequence[] value, or null - */ - @Override - public CharSequence[] getCharSequenceArray(String key) { - return super.getCharSequenceArray(key); - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return an IBinder value, or null - */ - public IBinder getBinder(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (IBinder) o; - } catch (ClassCastException e) { - typeWarning(key, o, "IBinder", e); - return null; - } - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return an IBinder value, or null - * - * @deprecated - * @hide This is the old name of the function. - */ - @Deprecated - public IBinder getIBinder(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (IBinder) o; - } catch (ClassCastException e) { - typeWarning(key, o, "IBinder", e); - return null; - } - } - - public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { - @Override - public Bundle createFromParcel(Parcel in) { - return in.readBundle(); - } - - @Override - public Bundle[] newArray(int size) { - return new Bundle[size]; - } - }; - - /** - * Report the nature of this Parcelable's contents - */ - @Override - public int describeContents() { - int mask = 0; - if (hasFileDescriptors()) { - mask |= Parcelable.CONTENTS_FILE_DESCRIPTOR; - } - return mask; - } - - /** - * Writes the Bundle contents to a Parcel, typically in order for - * it to be passed through an IBinder connection. - * @param parcel The parcel to copy this bundle to. - */ - @Override - public void writeToParcel(Parcel parcel, int flags) { - final boolean oldAllowFds = parcel.pushAllowFds(mAllowFds); - try { - super.writeToParcelInner(parcel, flags); - } finally { - parcel.restoreAllowFds(oldAllowFds); - } - } - - /** - * Reads the Parcel contents into this Bundle, typically in order for - * it to be passed through an IBinder connection. - * @param parcel The parcel to overwrite this bundle from. - */ - public void readFromParcel(Parcel parcel) { - super.readFromParcelInner(parcel); - mHasFds = mParcelledData.hasFileDescriptors(); - mFdsKnown = true; - } - - @Override - public synchronized String toString() { - if (mParcelledData != null) { - if (mParcelledData == EMPTY_PARCEL) { - return "Bundle[EMPTY_PARCEL]"; - } else { - return "Bundle[mParcelledData.dataSize=" + - mParcelledData.dataSize() + "]"; - } - } - return "Bundle[" + mMap.toString() + "]"; - } - -} diff --git a/src/main/java/android/os/CancellationSignal.java b/src/main/java/android/os/CancellationSignal.java deleted file mode 100644 index e8053d5..0000000 --- a/src/main/java/android/os/CancellationSignal.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.os.ICancellationSignal; - -/** - * Provides the ability to cancel an operation in progress. - */ -public final class CancellationSignal { - private boolean mIsCanceled; - private OnCancelListener mOnCancelListener; - private ICancellationSignal mRemote; - private boolean mCancelInProgress; - - /** - * Creates a cancellation signal, initially not canceled. - */ - public CancellationSignal() { - } - - /** - * Returns true if the operation has been canceled. - * - * @return True if the operation has been canceled. - */ - public boolean isCanceled() { - synchronized (this) { - return mIsCanceled; - } - } - - /** - * Throws {@link OperationCanceledException} if the operation has been canceled. - * - * @throws OperationCanceledException if the operation has been canceled. - */ - public void throwIfCanceled() { - if (isCanceled()) { - throw new OperationCanceledException(); - } - } - - /** - * Cancels the operation and signals the cancellation listener. - * If the operation has not yet started, then it will be canceled as soon as it does. - */ - public void cancel() { - final OnCancelListener listener; - final ICancellationSignal remote; - synchronized (this) { - if (mIsCanceled) { - return; - } - mIsCanceled = true; - mCancelInProgress = true; - listener = mOnCancelListener; - remote = mRemote; - } - - try { - if (listener != null) { - listener.onCancel(); - } - if (remote != null) { - try { - remote.cancel(); - } catch (RemoteException ex) { - } - } - } finally { - synchronized (this) { - mCancelInProgress = false; - notifyAll(); - } - } - } - - /** - * Sets the cancellation listener to be called when canceled. - * - * This method is intended to be used by the recipient of a cancellation signal - * such as a database or a content provider to handle cancellation requests - * while performing a long-running operation. This method is not intended to be - * used by applications themselves. - * - * If {@link CancellationSignal#cancel} has already been called, then the provided - * listener is invoked immediately. - * - * This method is guaranteed that the listener will not be called after it - * has been removed. - * - * @param listener The cancellation listener, or null to remove the current listener. - */ - public void setOnCancelListener(OnCancelListener listener) { - synchronized (this) { - waitForCancelFinishedLocked(); - - if (mOnCancelListener == listener) { - return; - } - mOnCancelListener = listener; - if (!mIsCanceled || listener == null) { - return; - } - } - listener.onCancel(); - } - - /** - * Sets the remote transport. - * - * If {@link CancellationSignal#cancel} has already been called, then the provided - * remote transport is canceled immediately. - * - * This method is guaranteed that the remote transport will not be called after it - * has been removed. - * - * @param remote The remote transport, or null to remove. - * - * @hide - */ - public void setRemote(ICancellationSignal remote) { - synchronized (this) { - waitForCancelFinishedLocked(); - - if (mRemote == remote) { - return; - } - mRemote = remote; - if (!mIsCanceled || remote == null) { - return; - } - } - try { - remote.cancel(); - } catch (RemoteException ex) { - } - } - - private void waitForCancelFinishedLocked() { - while (mCancelInProgress) { - try { - wait(); - } catch (InterruptedException ex) { - } - } - } - - /** - * Creates a transport that can be returned back to the caller of - * a Binder function and subsequently used to dispatch a cancellation signal. - * - * @return The new cancellation signal transport. - * - * @hide - */ - public static ICancellationSignal createTransport() { - return new Transport(); - } - - /** - * Given a locally created transport, returns its associated cancellation signal. - * - * @param transport The locally created transport, or null if none. - * @return The associated cancellation signal, or null if none. - * - * @hide - */ - public static CancellationSignal fromTransport(ICancellationSignal transport) { - if (transport instanceof Transport) { - return ((Transport)transport).mCancellationSignal; - } - return null; - } - - /** - * Listens for cancellation. - */ - public interface OnCancelListener { - /** - * Called when {@link CancellationSignal#cancel} is invoked. - */ - void onCancel(); - } - - private static final class Transport extends ICancellationSignal.Stub { - final CancellationSignal mCancellationSignal = new CancellationSignal(); - - @Override - public void cancel() throws RemoteException { - mCancellationSignal.cancel(); - } - } -} diff --git a/src/main/java/android/os/CommonClock.java b/src/main/java/android/os/CommonClock.java deleted file mode 100644 index f83a90b..0000000 --- a/src/main/java/android/os/CommonClock.java +++ /dev/null @@ -1,406 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.os; - -import java.net.InetSocketAddress; -import java.util.NoSuchElementException; -import android.os.Binder; -import android.os.CommonTimeUtils; -import android.os.IBinder; -import android.os.Parcel; -import android.os.RemoteException; -import android.os.ServiceManager; -import static android.system.OsConstants.*; - -/** - * Used for accessing the android common time service's common clock and receiving notifications - * about common time synchronization status changes. - * @hide - */ -public class CommonClock { - /** - * Sentinel value returned by {@link #getTime()} and {@link #getEstimatedError()} when the - * common time service is not able to determine the current common time due to a lack of - * synchronization. - */ - public static final long TIME_NOT_SYNCED = -1; - - /** - * Sentinel value returned by {@link #getTimelineId()} when the common time service is not - * currently synced to any timeline. - */ - public static final long INVALID_TIMELINE_ID = 0; - - /** - * Sentinel value returned by {@link #getEstimatedError()} when the common time service is not - * currently synced to any timeline. - */ - public static final int ERROR_ESTIMATE_UNKNOWN = 0x7FFFFFFF; - - /** - * Value used by {@link #getState()} to indicate that there was an internal error while - * attempting to determine the state of the common time service. - */ - public static final int STATE_INVALID = -1; - - /** - * Value used by {@link #getState()} to indicate that the common time service is in its initial - * state and attempting to find the current timeline master, if any. The service will - * transition to either {@link #STATE_CLIENT} if it finds an active master, or to - * {@link #STATE_MASTER} if no active master is found and this client becomes the master of a - * new timeline. - */ - public static final int STATE_INITIAL = 0; - - /** - * Value used by {@link #getState()} to indicate that the common time service is in its client - * state and is synchronizing its time to a different timeline master on the network. - */ - public static final int STATE_CLIENT = 1; - - /** - * Value used by {@link #getState()} to indicate that the common time service is in its master - * state and is serving as the timeline master for other common time service clients on the - * network. - */ - public static final int STATE_MASTER = 2; - - /** - * Value used by {@link #getState()} to indicate that the common time service is in its Ronin - * state. Common time service instances in the client state enter the Ronin state after their - * timeline master becomes unreachable on the network. Common time services who enter the Ronin - * state will begin a new master election for the timeline they were recently clients of. As - * clients detect they are not the winner and drop out of the election, they will transition to - * the {@link #STATE_WAIT_FOR_ELECTION} state. When there is only one client remaining in the - * election, it will assume ownership of the timeline and transition to the - * {@link #STATE_MASTER} state. During the election, all clients will allow their timeline to - * drift without applying correction. - */ - public static final int STATE_RONIN = 3; - - /** - * Value used by {@link #getState()} to indicate that the common time service is waiting for a - * master election to conclude and for the new master to announce itself before transitioning to - * the {@link #STATE_CLIENT} state. If no new master announces itself within the timeout - * threshold, the time service will transition back to the {@link #STATE_RONIN} state in order - * to restart the election. - */ - public static final int STATE_WAIT_FOR_ELECTION = 4; - - /** - * Name of the underlying native binder service - */ - public static final String SERVICE_NAME = "common_time.clock"; - - /** - * Class constructor. - * @throws android.os.RemoteException - */ - public CommonClock() - throws RemoteException { - mRemote = ServiceManager.getService(SERVICE_NAME); - if (null == mRemote) - throw new RemoteException(); - - mInterfaceDesc = mRemote.getInterfaceDescriptor(); - mUtils = new CommonTimeUtils(mRemote, mInterfaceDesc); - mRemote.linkToDeath(mDeathHandler, 0); - registerTimelineChangeListener(); - } - - /** - * Handy class factory method. - */ - static public CommonClock create() { - CommonClock retVal; - - try { - retVal = new CommonClock(); - } - catch (RemoteException e) { - retVal = null; - } - - return retVal; - } - - /** - * Release all native resources held by this {@link android.os.CommonClock} instance. Once - * resources have been released, the {@link android.os.CommonClock} instance is disconnected from - * the native service and will throw a {@link android.os.RemoteException} if any of its - * methods are called. Clients should always call release on their client instances before - * releasing their last Java reference to the instance. Failure to do this will cause - * non-deterministic native resource reclamation and may cause the common time service to remain - * active on the network for longer than it should. - */ - public void release() { - unregisterTimelineChangeListener(); - if (null != mRemote) { - try { - mRemote.unlinkToDeath(mDeathHandler, 0); - } - catch (NoSuchElementException e) { } - mRemote = null; - } - mUtils = null; - } - - /** - * Gets the common clock's current time. - * - * @return a signed 64-bit value representing the current common time in microseconds, or the - * special value {@link #TIME_NOT_SYNCED} if the common time service is currently not - * synchronized. - * @throws android.os.RemoteException - */ - public long getTime() - throws RemoteException { - throwOnDeadServer(); - return mUtils.transactGetLong(METHOD_GET_COMMON_TIME, TIME_NOT_SYNCED); - } - - /** - * Gets the current estimation of common clock's synchronization accuracy from the common time - * service. - * - * @return a signed 32-bit value representing the common time service's estimation of - * synchronization accuracy in microseconds, or the special value - * {@link #ERROR_ESTIMATE_UNKNOWN} if the common time service is currently not synchronized. - * Negative values indicate that the local server estimates that the nominal common time is - * behind the local server's time (in other words, the local clock is running fast) Positive - * values indicate that the local server estimates that the nominal common time is ahead of the - * local server's time (in other words, the local clock is running slow) - * @throws android.os.RemoteException - */ - public int getEstimatedError() - throws RemoteException { - throwOnDeadServer(); - return mUtils.transactGetInt(METHOD_GET_ESTIMATED_ERROR, ERROR_ESTIMATE_UNKNOWN); - } - - /** - * Gets the ID of the timeline the common time service is currently synchronizing its clock to. - * - * @return a long representing the unique ID of the timeline the common time service is - * currently synchronizing with, or {@link #INVALID_TIMELINE_ID} if the common time service is - * currently not synchronized. - * @throws android.os.RemoteException - */ - public long getTimelineId() - throws RemoteException { - throwOnDeadServer(); - return mUtils.transactGetLong(METHOD_GET_TIMELINE_ID, INVALID_TIMELINE_ID); - } - - /** - * Gets the current state of this clock's common time service in the the master election - * algorithm. - * - * @return a integer indicating the current state of the this clock's common time service in the - * master election algorithm or {@link #STATE_INVALID} if there is an internal error. - * @throws android.os.RemoteException - */ - public int getState() - throws RemoteException { - throwOnDeadServer(); - return mUtils.transactGetInt(METHOD_GET_STATE, STATE_INVALID); - } - - /** - * Gets the IP address and UDP port of the current timeline master. - * - * @return an InetSocketAddress containing the IP address and UDP port of the current timeline - * master, or null if there is no current master. - * @throws android.os.RemoteException - */ - public InetSocketAddress getMasterAddr() - throws RemoteException { - throwOnDeadServer(); - return mUtils.transactGetSockaddr(METHOD_GET_MASTER_ADDRESS); - } - - /** - * The OnTimelineChangedListener interface defines a method called by the - * {@link android.os.CommonClock} instance to indicate that the time synchronization service has - * either synchronized with a new timeline, or is no longer a member of any timeline. The - * client application can implement this interface and register the listener with the - * {@link #setTimelineChangedListener(OnTimelineChangedListener)} method. - */ - public interface OnTimelineChangedListener { - /** - * Method called when the time service's timeline has changed. - * - * @param newTimelineId a long which uniquely identifies the timeline the time - * synchronization service is now a member of, or {@link #INVALID_TIMELINE_ID} if the the - * service is not synchronized to any timeline. - */ - void onTimelineChanged(long newTimelineId); - } - - /** - * Registers an OnTimelineChangedListener interface. - *

Call this method with a null listener to stop receiving server death notifications. - */ - public void setTimelineChangedListener(OnTimelineChangedListener listener) { - synchronized (mListenerLock) { - mTimelineChangedListener = listener; - } - } - - /** - * The OnServerDiedListener interface defines a method called by the - * {@link android.os.CommonClock} instance to indicate that the connection to the native media - * server has been broken and that the {@link android.os.CommonClock} instance will need to be - * released and re-created. The client application can implement this interface and register - * the listener with the {@link #setServerDiedListener(OnServerDiedListener)} method. - */ - public interface OnServerDiedListener { - /** - * Method called when the native media server has died.

If the native common time - * service encounters a fatal error and needs to restart, the binder connection from the - * {@link android.os.CommonClock} instance to the common time service will be broken. To - * restore functionality, clients should {@link #release()} their old visualizer and create - * a new instance. - */ - void onServerDied(); - } - - /** - * Registers an OnServerDiedListener interface. - *

Call this method with a null listener to stop receiving server death notifications. - */ - public void setServerDiedListener(OnServerDiedListener listener) { - synchronized (mListenerLock) { - mServerDiedListener = listener; - } - } - - protected void finalize() throws Throwable { release(); } - - private void throwOnDeadServer() throws RemoteException { - if ((null == mRemote) || (null == mUtils)) - throw new RemoteException(); - } - - private final Object mListenerLock = new Object(); - private OnTimelineChangedListener mTimelineChangedListener = null; - private OnServerDiedListener mServerDiedListener = null; - - private IBinder mRemote = null; - private String mInterfaceDesc = ""; - private CommonTimeUtils mUtils; - - private IBinder.DeathRecipient mDeathHandler = new IBinder.DeathRecipient() { - public void binderDied() { - synchronized (mListenerLock) { - if (null != mServerDiedListener) - mServerDiedListener.onServerDied(); - } - } - }; - - private class TimelineChangedListener extends Binder { - @Override - protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) - throws RemoteException { - switch (code) { - case METHOD_CBK_ON_TIMELINE_CHANGED: - data.enforceInterface(DESCRIPTOR); - long timelineId = data.readLong(); - synchronized (mListenerLock) { - if (null != mTimelineChangedListener) - mTimelineChangedListener.onTimelineChanged(timelineId); - } - return true; - } - - return super.onTransact(code, data, reply, flags); - } - - private static final String DESCRIPTOR = "android.os.ICommonClockListener"; - }; - - private TimelineChangedListener mCallbackTgt = null; - - private void registerTimelineChangeListener() throws RemoteException { - if (null != mCallbackTgt) - return; - - boolean success = false; - android.os.Parcel data = android.os.Parcel.obtain(); - android.os.Parcel reply = android.os.Parcel.obtain(); - mCallbackTgt = new TimelineChangedListener(); - - try { - data.writeInterfaceToken(mInterfaceDesc); - data.writeStrongBinder(mCallbackTgt); - mRemote.transact(METHOD_REGISTER_LISTENER, data, reply, 0); - success = (0 == reply.readInt()); - } - catch (RemoteException e) { - success = false; - } - finally { - reply.recycle(); - data.recycle(); - } - - // Did we catch a remote exception or fail to register our callback target? If so, our - // object must already be dead (or be as good as dead). Clear out all of our state so that - // our other methods will properly indicate a dead object. - if (!success) { - mCallbackTgt = null; - mRemote = null; - mUtils = null; - } - } - - private void unregisterTimelineChangeListener() { - if (null == mCallbackTgt) - return; - - android.os.Parcel data = android.os.Parcel.obtain(); - android.os.Parcel reply = android.os.Parcel.obtain(); - - try { - data.writeInterfaceToken(mInterfaceDesc); - data.writeStrongBinder(mCallbackTgt); - mRemote.transact(METHOD_UNREGISTER_LISTENER, data, reply, 0); - } - catch (RemoteException e) { } - finally { - reply.recycle(); - data.recycle(); - mCallbackTgt = null; - } - } - - private static final int METHOD_IS_COMMON_TIME_VALID = IBinder.FIRST_CALL_TRANSACTION; - private static final int METHOD_COMMON_TIME_TO_LOCAL_TIME = METHOD_IS_COMMON_TIME_VALID + 1; - private static final int METHOD_LOCAL_TIME_TO_COMMON_TIME = METHOD_COMMON_TIME_TO_LOCAL_TIME + 1; - private static final int METHOD_GET_COMMON_TIME = METHOD_LOCAL_TIME_TO_COMMON_TIME + 1; - private static final int METHOD_GET_COMMON_FREQ = METHOD_GET_COMMON_TIME + 1; - private static final int METHOD_GET_LOCAL_TIME = METHOD_GET_COMMON_FREQ + 1; - private static final int METHOD_GET_LOCAL_FREQ = METHOD_GET_LOCAL_TIME + 1; - private static final int METHOD_GET_ESTIMATED_ERROR = METHOD_GET_LOCAL_FREQ + 1; - private static final int METHOD_GET_TIMELINE_ID = METHOD_GET_ESTIMATED_ERROR + 1; - private static final int METHOD_GET_STATE = METHOD_GET_TIMELINE_ID + 1; - private static final int METHOD_GET_MASTER_ADDRESS = METHOD_GET_STATE + 1; - private static final int METHOD_REGISTER_LISTENER = METHOD_GET_MASTER_ADDRESS + 1; - private static final int METHOD_UNREGISTER_LISTENER = METHOD_REGISTER_LISTENER + 1; - - private static final int METHOD_CBK_ON_TIMELINE_CHANGED = IBinder.FIRST_CALL_TRANSACTION; -} diff --git a/src/main/java/android/os/CommonTimeConfig.java b/src/main/java/android/os/CommonTimeConfig.java deleted file mode 100644 index 1f9fab5..0000000 --- a/src/main/java/android/os/CommonTimeConfig.java +++ /dev/null @@ -1,447 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.os; - -import java.net.InetSocketAddress; -import java.util.NoSuchElementException; - -import android.os.CommonTimeUtils; -import android.os.IBinder; -import android.os.RemoteException; -import android.os.ServiceManager; - -/** - * Used for configuring and controlling the status of the android common time service. - * @hide - */ -public class CommonTimeConfig { - /** - * Successful operation. - */ - public static final int SUCCESS = 0; - /** - * Unspecified error. - */ - public static final int ERROR = -1; - /** - * Operation failed due to bad parameter value. - */ - public static final int ERROR_BAD_VALUE = -4; - /** - * Operation failed due to dead remote object. - */ - public static final int ERROR_DEAD_OBJECT = -7; - - /** - * Sentinel value returned by {@link #getMasterElectionGroupId()} when an error occurs trying to - * fetch the master election group. - */ - public static final long INVALID_GROUP_ID = -1; - - /** - * Name of the underlying native binder service - */ - public static final String SERVICE_NAME = "common_time.config"; - - /** - * Class constructor. - * @throws android.os.RemoteException - */ - public CommonTimeConfig() - throws RemoteException { - mRemote = ServiceManager.getService(SERVICE_NAME); - if (null == mRemote) - throw new RemoteException(); - - mInterfaceDesc = mRemote.getInterfaceDescriptor(); - mUtils = new CommonTimeUtils(mRemote, mInterfaceDesc); - mRemote.linkToDeath(mDeathHandler, 0); - } - - /** - * Handy class factory method. - */ - static public CommonTimeConfig create() { - CommonTimeConfig retVal; - - try { - retVal = new CommonTimeConfig(); - } - catch (RemoteException e) { - retVal = null; - } - - return retVal; - } - - /** - * Release all native resources held by this {@link android.os.CommonTimeConfig} instance. Once - * resources have been released, the {@link android.os.CommonTimeConfig} instance is - * disconnected from the native service and will throw a {@link android.os.RemoteException} if - * any of its methods are called. Clients should always call release on their client instances - * before releasing their last Java reference to the instance. Failure to do this will cause - * non-deterministic native resource reclamation and may cause the common time service to remain - * active on the network for longer than it should. - */ - public void release() { - if (null != mRemote) { - try { - mRemote.unlinkToDeath(mDeathHandler, 0); - } - catch (NoSuchElementException e) { } - mRemote = null; - } - mUtils = null; - } - - /** - * Gets the current priority of the common time service used in the master election protocol. - * - * @return an 8 bit value indicating the priority of this common time service relative to other - * common time services operating in the same domain. - * @throws android.os.RemoteException - */ - public byte getMasterElectionPriority() - throws RemoteException { - throwOnDeadServer(); - return (byte)mUtils.transactGetInt(METHOD_GET_MASTER_ELECTION_PRIORITY, -1); - } - - /** - * Sets the current priority of the common time service used in the master election protocol. - * - * @param priority priority of the common time service used in the master election protocol. - * Lower numbers are lower priority. - * @return {@link #SUCCESS} in case of success, - * {@link #ERROR} or {@link #ERROR_DEAD_OBJECT} in case of failure. - */ - public int setMasterElectionPriority(byte priority) { - if (checkDeadServer()) - return ERROR_DEAD_OBJECT; - return mUtils.transactSetInt(METHOD_SET_MASTER_ELECTION_PRIORITY, priority); - } - - /** - * Gets the IP endpoint used by the time service to participate in the master election protocol. - * - * @return an InetSocketAddress containing the IP address and UDP port being used by the - * system's common time service to participate in the master election protocol. - * @throws android.os.RemoteException - */ - public InetSocketAddress getMasterElectionEndpoint() - throws RemoteException { - throwOnDeadServer(); - return mUtils.transactGetSockaddr(METHOD_GET_MASTER_ELECTION_ENDPOINT); - } - - /** - * Sets the IP endpoint used by the common time service to participate in the master election - * protocol. - * - * @param ep The IP address and UDP port to be used by the common time service to participate in - * the master election protocol. The supplied IP address must be either the broadcast or - * multicast address, unicast addresses are considered to be illegal values. - * @return {@link #SUCCESS} in case of success, - * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure. - */ - public int setMasterElectionEndpoint(InetSocketAddress ep) { - if (checkDeadServer()) - return ERROR_DEAD_OBJECT; - return mUtils.transactSetSockaddr(METHOD_SET_MASTER_ELECTION_ENDPOINT, ep); - } - - /** - * Gets the current group ID used by the common time service in the master election protocol. - * - * @return The 64-bit group ID of the common time service. - * @throws android.os.RemoteException - */ - public long getMasterElectionGroupId() - throws RemoteException { - throwOnDeadServer(); - return mUtils.transactGetLong(METHOD_GET_MASTER_ELECTION_GROUP_ID, INVALID_GROUP_ID); - } - - /** - * Sets the current group ID used by the common time service in the master election protocol. - * - * @param id The 64-bit group ID of the common time service. - * @return {@link #SUCCESS} in case of success, - * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure. - */ - public int setMasterElectionGroupId(long id) { - if (checkDeadServer()) - return ERROR_DEAD_OBJECT; - return mUtils.transactSetLong(METHOD_SET_MASTER_ELECTION_GROUP_ID, id); - } - - /** - * Gets the name of the network interface which the common time service attempts to bind to. - * - * @return a string with the network interface name which the common time service is bound to, - * or null if the service is currently unbound. Examples of interface names are things like - * "eth0", or "wlan0". - * @throws android.os.RemoteException - */ - public String getInterfaceBinding() - throws RemoteException { - throwOnDeadServer(); - - String ifaceName = mUtils.transactGetString(METHOD_GET_INTERFACE_BINDING, null); - - if ((null != ifaceName) && (0 == ifaceName.length())) - return null; - - return ifaceName; - } - - /** - * Sets the name of the network interface which the common time service should attempt to bind - * to. - * - * @param ifaceName The name of the network interface ("eth0", "wlan0", etc...) wich the common - * time service should attempt to bind to, or null to force the common time service to unbind - * from the network and run in networkless mode. - * @return {@link #SUCCESS} in case of success, - * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure. - */ - public int setNetworkBinding(String ifaceName) { - if (checkDeadServer()) - return ERROR_DEAD_OBJECT; - - return mUtils.transactSetString(METHOD_SET_INTERFACE_BINDING, - (null == ifaceName) ? "" : ifaceName); - } - - /** - * Gets the amount of time the common time service will wait between master announcements when - * it is the timeline master. - * - * @return The time (in milliseconds) between master announcements. - * @throws android.os.RemoteException - */ - public int getMasterAnnounceInterval() - throws RemoteException { - throwOnDeadServer(); - return mUtils.transactGetInt(METHOD_GET_MASTER_ANNOUNCE_INTERVAL, -1); - } - - /** - * Sets the amount of time the common time service will wait between master announcements when - * it is the timeline master. - * - * @param interval The time (in milliseconds) between master announcements. - * @return {@link #SUCCESS} in case of success, - * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure. - */ - public int setMasterAnnounceInterval(int interval) { - if (checkDeadServer()) - return ERROR_DEAD_OBJECT; - return mUtils.transactSetInt(METHOD_SET_MASTER_ANNOUNCE_INTERVAL, interval); - } - - /** - * Gets the amount of time the common time service will wait between time synchronization - * requests when it is the client of another common time service on the network. - * - * @return The time (in milliseconds) between time sync requests. - * @throws android.os.RemoteException - */ - public int getClientSyncInterval() - throws RemoteException { - throwOnDeadServer(); - return mUtils.transactGetInt(METHOD_GET_CLIENT_SYNC_INTERVAL, -1); - } - - /** - * Sets the amount of time the common time service will wait between time synchronization - * requests when it is the client of another common time service on the network. - * - * @param interval The time (in milliseconds) between time sync requests. - * @return {@link #SUCCESS} in case of success, - * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure. - */ - public int setClientSyncInterval(int interval) { - if (checkDeadServer()) - return ERROR_DEAD_OBJECT; - return mUtils.transactSetInt(METHOD_SET_CLIENT_SYNC_INTERVAL, interval); - } - - /** - * Gets the panic threshold for the estimated error level of the common time service. When the - * common time service's estimated error rises above this level, the service will panic and - * reset, causing a discontinuity in the currently synchronized timeline. - * - * @return The threshold (in microseconds) past which the common time service will panic. - * @throws android.os.RemoteException - */ - public int getPanicThreshold() - throws RemoteException { - throwOnDeadServer(); - return mUtils.transactGetInt(METHOD_GET_PANIC_THRESHOLD, -1); - } - - /** - * Sets the panic threshold for the estimated error level of the common time service. When the - * common time service's estimated error rises above this level, the service will panic and - * reset, causing a discontinuity in the currently synchronized timeline. - * - * @param threshold The threshold (in microseconds) past which the common time service will - * panic. - * @return {@link #SUCCESS} in case of success, - * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure. - */ - public int setPanicThreshold(int threshold) { - if (checkDeadServer()) - return ERROR_DEAD_OBJECT; - return mUtils.transactSetInt(METHOD_SET_PANIC_THRESHOLD, threshold); - } - - /** - * Gets the current state of the common time service's auto disable flag. - * - * @return The current state of the common time service's auto disable flag. - * @throws android.os.RemoteException - */ - public boolean getAutoDisable() - throws RemoteException { - throwOnDeadServer(); - return (1 == mUtils.transactGetInt(METHOD_GET_AUTO_DISABLE, 1)); - } - - /** - * Sets the current state of the common time service's auto disable flag. When the time - * service's auto disable flag is set, it will automatically cease all network activity when - * it has no active local clients, resuming activity the next time the service has interested - * local clients. When the auto disabled flag is cleared, the common time service will continue - * to participate the time synchronization group even when it has no active local clients. - * - * @param autoDisable The desired state of the common time service's auto disable flag. - * @return {@link #SUCCESS} in case of success, - * {@link #ERROR} or {@link #ERROR_DEAD_OBJECT} in case of failure. - */ - public int setAutoDisable(boolean autoDisable) { - if (checkDeadServer()) - return ERROR_DEAD_OBJECT; - - return mUtils.transactSetInt(METHOD_SET_AUTO_DISABLE, autoDisable ? 1 : 0); - } - - /** - * At startup, the time service enters the initial state and remains there until it is given a - * network interface to bind to. Common time will be unavailable to clients of the common time - * service until the service joins a network (even an empty network). Devices may use the - * {@link #forceNetworklessMasterMode()} method to force a time service in the INITIAL state - * with no network configuration to assume MASTER status for a brand new timeline in order to - * allow clients of the common time service to operate, even though the device is isolated and - * not on any network. When a networkless master does join a network, it will defer to any - * masters already on the network, or continue to maintain the timeline it made up during its - * networkless state if no other masters are detected. Attempting to force a client into master - * mode while it is actively bound to a network will fail with the status code {@link #ERROR} - * - * @return {@link #SUCCESS} in case of success, - * {@link #ERROR} or {@link #ERROR_DEAD_OBJECT} in case of failure. - */ - public int forceNetworklessMasterMode() { - android.os.Parcel data = android.os.Parcel.obtain(); - android.os.Parcel reply = android.os.Parcel.obtain(); - - try { - data.writeInterfaceToken(mInterfaceDesc); - mRemote.transact(METHOD_FORCE_NETWORKLESS_MASTER_MODE, data, reply, 0); - - return reply.readInt(); - } - catch (RemoteException e) { - return ERROR_DEAD_OBJECT; - } - finally { - reply.recycle(); - data.recycle(); - } - } - - /** - * The OnServerDiedListener interface defines a method called by the - * {@link android.os.CommonTimeConfig} instance to indicate that the connection to the native - * media server has been broken and that the {@link android.os.CommonTimeConfig} instance will - * need to be released and re-created. The client application can implement this interface and - * register the listener with the {@link #setServerDiedListener(OnServerDiedListener)} method. - */ - public interface OnServerDiedListener { - /** - * Method called when the native common time service has died.

If the native common time - * service encounters a fatal error and needs to restart, the binder connection from the - * {@link android.os.CommonTimeConfig} instance to the common time service will be broken. - */ - void onServerDied(); - } - - /** - * Registers an OnServerDiedListener interface. - *

Call this method with a null listener to stop receiving server death notifications. - */ - public void setServerDiedListener(OnServerDiedListener listener) { - synchronized (mListenerLock) { - mServerDiedListener = listener; - } - } - - protected void finalize() throws Throwable { release(); } - - private boolean checkDeadServer() { - return ((null == mRemote) || (null == mUtils)); - } - - private void throwOnDeadServer() throws RemoteException { - if (checkDeadServer()) - throw new RemoteException(); - } - - private final Object mListenerLock = new Object(); - private OnServerDiedListener mServerDiedListener = null; - - private IBinder mRemote = null; - private String mInterfaceDesc = ""; - private CommonTimeUtils mUtils; - - private IBinder.DeathRecipient mDeathHandler = new IBinder.DeathRecipient() { - public void binderDied() { - synchronized (mListenerLock) { - if (null != mServerDiedListener) - mServerDiedListener.onServerDied(); - } - } - }; - - private static final int METHOD_GET_MASTER_ELECTION_PRIORITY = IBinder.FIRST_CALL_TRANSACTION; - private static final int METHOD_SET_MASTER_ELECTION_PRIORITY = METHOD_GET_MASTER_ELECTION_PRIORITY + 1; - private static final int METHOD_GET_MASTER_ELECTION_ENDPOINT = METHOD_SET_MASTER_ELECTION_PRIORITY + 1; - private static final int METHOD_SET_MASTER_ELECTION_ENDPOINT = METHOD_GET_MASTER_ELECTION_ENDPOINT + 1; - private static final int METHOD_GET_MASTER_ELECTION_GROUP_ID = METHOD_SET_MASTER_ELECTION_ENDPOINT + 1; - private static final int METHOD_SET_MASTER_ELECTION_GROUP_ID = METHOD_GET_MASTER_ELECTION_GROUP_ID + 1; - private static final int METHOD_GET_INTERFACE_BINDING = METHOD_SET_MASTER_ELECTION_GROUP_ID + 1; - private static final int METHOD_SET_INTERFACE_BINDING = METHOD_GET_INTERFACE_BINDING + 1; - private static final int METHOD_GET_MASTER_ANNOUNCE_INTERVAL = METHOD_SET_INTERFACE_BINDING + 1; - private static final int METHOD_SET_MASTER_ANNOUNCE_INTERVAL = METHOD_GET_MASTER_ANNOUNCE_INTERVAL + 1; - private static final int METHOD_GET_CLIENT_SYNC_INTERVAL = METHOD_SET_MASTER_ANNOUNCE_INTERVAL + 1; - private static final int METHOD_SET_CLIENT_SYNC_INTERVAL = METHOD_GET_CLIENT_SYNC_INTERVAL + 1; - private static final int METHOD_GET_PANIC_THRESHOLD = METHOD_SET_CLIENT_SYNC_INTERVAL + 1; - private static final int METHOD_SET_PANIC_THRESHOLD = METHOD_GET_PANIC_THRESHOLD + 1; - private static final int METHOD_GET_AUTO_DISABLE = METHOD_SET_PANIC_THRESHOLD + 1; - private static final int METHOD_SET_AUTO_DISABLE = METHOD_GET_AUTO_DISABLE + 1; - private static final int METHOD_FORCE_NETWORKLESS_MASTER_MODE = METHOD_SET_AUTO_DISABLE + 1; -} diff --git a/src/main/java/android/os/CommonTimeUtils.java b/src/main/java/android/os/CommonTimeUtils.java deleted file mode 100644 index ba060b8..0000000 --- a/src/main/java/android/os/CommonTimeUtils.java +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.os; - -import java.net.InetAddress; -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetSocketAddress; -import java.util.Locale; -import static android.system.OsConstants.*; - -class CommonTimeUtils { - /** - * Successful operation. - */ - public static final int SUCCESS = 0; - /** - * Unspecified error. - */ - public static final int ERROR = -1; - /** - * Operation failed due to bad parameter value. - */ - public static final int ERROR_BAD_VALUE = -4; - /** - * Operation failed due to dead remote object. - */ - public static final int ERROR_DEAD_OBJECT = -7; - - public CommonTimeUtils(IBinder remote, String interfaceDesc) { - mRemote = remote; - mInterfaceDesc = interfaceDesc; - } - - public int transactGetInt(int method_code, int error_ret_val) - throws RemoteException { - android.os.Parcel data = android.os.Parcel.obtain(); - android.os.Parcel reply = android.os.Parcel.obtain(); - int ret_val; - - try { - int res; - data.writeInterfaceToken(mInterfaceDesc); - mRemote.transact(method_code, data, reply, 0); - - res = reply.readInt(); - ret_val = (0 == res) ? reply.readInt() : error_ret_val; - } - finally { - reply.recycle(); - data.recycle(); - } - - return ret_val; - } - - public int transactSetInt(int method_code, int val) { - android.os.Parcel data = android.os.Parcel.obtain(); - android.os.Parcel reply = android.os.Parcel.obtain(); - - try { - data.writeInterfaceToken(mInterfaceDesc); - data.writeInt(val); - mRemote.transact(method_code, data, reply, 0); - - return reply.readInt(); - } - catch (RemoteException e) { - return ERROR_DEAD_OBJECT; - } - finally { - reply.recycle(); - data.recycle(); - } - } - - public long transactGetLong(int method_code, long error_ret_val) - throws RemoteException { - android.os.Parcel data = android.os.Parcel.obtain(); - android.os.Parcel reply = android.os.Parcel.obtain(); - long ret_val; - - try { - int res; - data.writeInterfaceToken(mInterfaceDesc); - mRemote.transact(method_code, data, reply, 0); - - res = reply.readInt(); - ret_val = (0 == res) ? reply.readLong() : error_ret_val; - } - finally { - reply.recycle(); - data.recycle(); - } - - return ret_val; - } - - public int transactSetLong(int method_code, long val) { - android.os.Parcel data = android.os.Parcel.obtain(); - android.os.Parcel reply = android.os.Parcel.obtain(); - - try { - data.writeInterfaceToken(mInterfaceDesc); - data.writeLong(val); - mRemote.transact(method_code, data, reply, 0); - - return reply.readInt(); - } - catch (RemoteException e) { - return ERROR_DEAD_OBJECT; - } - finally { - reply.recycle(); - data.recycle(); - } - } - - public String transactGetString(int method_code, String error_ret_val) - throws RemoteException { - android.os.Parcel data = android.os.Parcel.obtain(); - android.os.Parcel reply = android.os.Parcel.obtain(); - String ret_val; - - try { - int res; - data.writeInterfaceToken(mInterfaceDesc); - mRemote.transact(method_code, data, reply, 0); - - res = reply.readInt(); - ret_val = (0 == res) ? reply.readString() : error_ret_val; - } - finally { - reply.recycle(); - data.recycle(); - } - - return ret_val; - } - - public int transactSetString(int method_code, String val) { - android.os.Parcel data = android.os.Parcel.obtain(); - android.os.Parcel reply = android.os.Parcel.obtain(); - - try { - data.writeInterfaceToken(mInterfaceDesc); - data.writeString(val); - mRemote.transact(method_code, data, reply, 0); - - return reply.readInt(); - } - catch (RemoteException e) { - return ERROR_DEAD_OBJECT; - } - finally { - reply.recycle(); - data.recycle(); - } - } - - public InetSocketAddress transactGetSockaddr(int method_code) - throws RemoteException { - android.os.Parcel data = android.os.Parcel.obtain(); - android.os.Parcel reply = android.os.Parcel.obtain(); - InetSocketAddress ret_val = null; - - try { - int res; - data.writeInterfaceToken(mInterfaceDesc); - mRemote.transact(method_code, data, reply, 0); - - res = reply.readInt(); - if (0 == res) { - int type; - int port = 0; - String addrStr = null; - - type = reply.readInt(); - - if (AF_INET == type) { - int addr = reply.readInt(); - port = reply.readInt(); - addrStr = String.format(Locale.US, "%d.%d.%d.%d", - (addr >> 24) & 0xFF, - (addr >> 16) & 0xFF, - (addr >> 8) & 0xFF, - addr & 0xFF); - } else if (AF_INET6 == type) { - int addr1 = reply.readInt(); - int addr2 = reply.readInt(); - int addr3 = reply.readInt(); - int addr4 = reply.readInt(); - - port = reply.readInt(); - - int flowinfo = reply.readInt(); - int scope_id = reply.readInt(); - - addrStr = String.format(Locale.US, "[%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X]", - (addr1 >> 16) & 0xFFFF, addr1 & 0xFFFF, - (addr2 >> 16) & 0xFFFF, addr2 & 0xFFFF, - (addr3 >> 16) & 0xFFFF, addr3 & 0xFFFF, - (addr4 >> 16) & 0xFFFF, addr4 & 0xFFFF); - } - - if (null != addrStr) { - ret_val = new InetSocketAddress(addrStr, port); - } - } - } - finally { - reply.recycle(); - data.recycle(); - } - - return ret_val; - } - - public int transactSetSockaddr(int method_code, InetSocketAddress addr) { - android.os.Parcel data = android.os.Parcel.obtain(); - android.os.Parcel reply = android.os.Parcel.obtain(); - int ret_val = ERROR; - - try { - data.writeInterfaceToken(mInterfaceDesc); - - if (null == addr) { - data.writeInt(0); - } else { - data.writeInt(1); - final InetAddress a = addr.getAddress(); - final byte[] b = a.getAddress(); - final int p = addr.getPort(); - - if (a instanceof Inet4Address) { - int v4addr = (((int)b[0] & 0xFF) << 24) | - (((int)b[1] & 0xFF) << 16) | - (((int)b[2] & 0xFF) << 8) | - ((int)b[3] & 0xFF); - - data.writeInt(AF_INET); - data.writeInt(v4addr); - data.writeInt(p); - } else - if (a instanceof Inet6Address) { - int i; - Inet6Address v6 = (Inet6Address)a; - data.writeInt(AF_INET6); - for (i = 0; i < 4; ++i) { - int aword = (((int)b[(i*4) + 0] & 0xFF) << 24) | - (((int)b[(i*4) + 1] & 0xFF) << 16) | - (((int)b[(i*4) + 2] & 0xFF) << 8) | - ((int)b[(i*4) + 3] & 0xFF); - data.writeInt(aword); - } - data.writeInt(p); - data.writeInt(0); // flow info - data.writeInt(v6.getScopeId()); - } else { - return ERROR_BAD_VALUE; - } - } - - mRemote.transact(method_code, data, reply, 0); - ret_val = reply.readInt(); - } - catch (RemoteException e) { - ret_val = ERROR_DEAD_OBJECT; - } - finally { - reply.recycle(); - data.recycle(); - } - - return ret_val; - } - - private IBinder mRemote; - private String mInterfaceDesc; -}; diff --git a/src/main/java/android/os/ConditionVariable.java b/src/main/java/android/os/ConditionVariable.java deleted file mode 100644 index 1e820f9..0000000 --- a/src/main/java/android/os/ConditionVariable.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -/** - * Class that implements the condition variable locking paradigm. - * - *

- * This differs from the built-in java.lang.Object wait() and notify() - * in that this class contains the condition to wait on itself. That means - * open(), close() and block() are sticky. If open() is called before block(), - * block() will not block, and instead return immediately. - * - *

- * This class uses itself as the object to wait on, so if you wait() - * or notify() on a ConditionVariable, the results are undefined. - */ -public class ConditionVariable -{ - private volatile boolean mCondition; - - /** - * Create the ConditionVariable in the default closed state. - */ - public ConditionVariable() - { - mCondition = false; - } - - /** - * Create the ConditionVariable with the given state. - * - *

- * Pass true for opened and false for closed. - */ - public ConditionVariable(boolean state) - { - mCondition = state; - } - - /** - * Open the condition, and release all threads that are blocked. - * - *

- * Any threads that later approach block() will not block unless close() - * is called. - */ - public void open() - { - synchronized (this) { - boolean old = mCondition; - mCondition = true; - if (!old) { - this.notifyAll(); - } - } - } - - /** - * Reset the condition to the closed state. - * - *

- * Any threads that call block() will block until someone calls open. - */ - public void close() - { - synchronized (this) { - mCondition = false; - } - } - - /** - * Block the current thread until the condition is opened. - * - *

- * If the condition is already opened, return immediately. - */ - public void block() - { - synchronized (this) { - while (!mCondition) { - try { - this.wait(); - } - catch (InterruptedException e) { - } - } - } - } - - /** - * Block the current thread until the condition is opened or until - * timeout milliseconds have passed. - * - *

- * If the condition is already opened, return immediately. - * - * @param timeout the maximum time to wait in milliseconds. - * - * @return true if the condition was opened, false if the call returns - * because of the timeout. - */ - public boolean block(long timeout) - { - // Object.wait(0) means wait forever, to mimic this, we just - // call the other block() method in that case. It simplifies - // this code for the common case. - if (timeout != 0) { - synchronized (this) { - long now = System.currentTimeMillis(); - long end = now + timeout; - while (!mCondition && now < end) { - try { - this.wait(end-now); - } - catch (InterruptedException e) { - } - now = System.currentTimeMillis(); - } - return mCondition; - } - } else { - this.block(); - return true; - } - } -} diff --git a/src/main/java/android/os/CountDownTimer.java b/src/main/java/android/os/CountDownTimer.java deleted file mode 100644 index 58acbcf..0000000 --- a/src/main/java/android/os/CountDownTimer.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -/** - * Schedule a countdown until a time in the future, with - * regular notifications on intervals along the way. - * - * Example of showing a 30 second countdown in a text field: - * - *

- * new CountDownTimer(30000, 1000) {
- *
- *     public void onTick(long millisUntilFinished) {
- *         mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
- *     }
- *
- *     public void onFinish() {
- *         mTextField.setText("done!");
- *     }
- *  }.start();
- * 
- * - * The calls to {@link #onTick(long)} are synchronized to this object so that - * one call to {@link #onTick(long)} won't ever occur before the previous - * callback is complete. This is only relevant when the implementation of - * {@link #onTick(long)} takes an amount of time to execute that is significant - * compared to the countdown interval. - */ -public abstract class CountDownTimer { - - /** - * Millis since epoch when alarm should stop. - */ - private final long mMillisInFuture; - - /** - * The interval in millis that the user receives callbacks - */ - private final long mCountdownInterval; - - private long mStopTimeInFuture; - - /** - * boolean representing if the timer was cancelled - */ - private boolean mCancelled = false; - - /** - * @param millisInFuture The number of millis in the future from the call - * to {@link #start()} until the countdown is done and {@link #onFinish()} - * is called. - * @param countDownInterval The interval along the way to receive - * {@link #onTick(long)} callbacks. - */ - public CountDownTimer(long millisInFuture, long countDownInterval) { - mMillisInFuture = millisInFuture; - mCountdownInterval = countDownInterval; - } - - /** - * Cancel the countdown. - */ - public synchronized final void cancel() { - mCancelled = true; - mHandler.removeMessages(MSG); - } - - /** - * Start the countdown. - */ - public synchronized final CountDownTimer start() { - mCancelled = false; - if (mMillisInFuture <= 0) { - onFinish(); - return this; - } - mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture; - mHandler.sendMessage(mHandler.obtainMessage(MSG)); - return this; - } - - - /** - * Callback fired on regular interval. - * @param millisUntilFinished The amount of time until finished. - */ - public abstract void onTick(long millisUntilFinished); - - /** - * Callback fired when the time is up. - */ - public abstract void onFinish(); - - - private static final int MSG = 1; - - - // handles counting down - private Handler mHandler = new Handler() { - - @Override - public void handleMessage(Message msg) { - - synchronized (CountDownTimer.this) { - if (mCancelled) { - return; - } - - final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime(); - - if (millisLeft <= 0) { - onFinish(); - } else if (millisLeft < mCountdownInterval) { - // no tick, just delay until done - sendMessageDelayed(obtainMessage(MSG), millisLeft); - } else { - long lastTickStart = SystemClock.elapsedRealtime(); - onTick(millisLeft); - - // take into account user's onTick taking time to execute - long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime(); - - // special case: user's onTick took more than interval to - // complete, skip to next interval - while (delay < 0) delay += mCountdownInterval; - - sendMessageDelayed(obtainMessage(MSG), delay); - } - } - } - }; -} diff --git a/src/main/java/android/os/CursorAnchorInfoTest.java b/src/main/java/android/os/CursorAnchorInfoTest.java deleted file mode 100644 index d4244ba..0000000 --- a/src/main/java/android/os/CursorAnchorInfoTest.java +++ /dev/null @@ -1,460 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.graphics.Matrix; -import android.graphics.RectF; -import android.test.InstrumentationTestCase; -import android.test.suitebuilder.annotation.SmallTest; -import android.text.TextUtils; -import android.view.inputmethod.CursorAnchorInfo; -import android.view.inputmethod.CursorAnchorInfo.Builder; - -import java.util.Objects; - -import static android.view.inputmethod.CursorAnchorInfo.FLAG_HAS_INVISIBLE_REGION; -import static android.view.inputmethod.CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION; -import static android.view.inputmethod.CursorAnchorInfo.FLAG_IS_RTL; - -public class CursorAnchorInfoTest extends InstrumentationTestCase { - private static final RectF[] MANY_BOUNDS = new RectF[] { - new RectF(101.0f, 201.0f, 301.0f, 401.0f), - new RectF(102.0f, 202.0f, 302.0f, 402.0f), - new RectF(103.0f, 203.0f, 303.0f, 403.0f), - new RectF(104.0f, 204.0f, 304.0f, 404.0f), - new RectF(105.0f, 205.0f, 305.0f, 405.0f), - new RectF(106.0f, 206.0f, 306.0f, 406.0f), - new RectF(107.0f, 207.0f, 307.0f, 407.0f), - new RectF(108.0f, 208.0f, 308.0f, 408.0f), - new RectF(109.0f, 209.0f, 309.0f, 409.0f), - new RectF(110.0f, 210.0f, 310.0f, 410.0f), - new RectF(111.0f, 211.0f, 311.0f, 411.0f), - new RectF(112.0f, 212.0f, 312.0f, 412.0f), - new RectF(113.0f, 213.0f, 313.0f, 413.0f), - new RectF(114.0f, 214.0f, 314.0f, 414.0f), - new RectF(115.0f, 215.0f, 315.0f, 415.0f), - new RectF(116.0f, 216.0f, 316.0f, 416.0f), - new RectF(117.0f, 217.0f, 317.0f, 417.0f), - new RectF(118.0f, 218.0f, 318.0f, 418.0f), - new RectF(119.0f, 219.0f, 319.0f, 419.0f), - }; - private static final int[] MANY_FLAGS_ARRAY = new int[] { - FLAG_HAS_INVISIBLE_REGION, - FLAG_HAS_INVISIBLE_REGION | FLAG_HAS_VISIBLE_REGION, - FLAG_HAS_VISIBLE_REGION, - FLAG_HAS_VISIBLE_REGION, - FLAG_HAS_VISIBLE_REGION, - FLAG_HAS_VISIBLE_REGION, - FLAG_HAS_VISIBLE_REGION | FLAG_IS_RTL, - FLAG_HAS_INVISIBLE_REGION | FLAG_HAS_VISIBLE_REGION | FLAG_IS_RTL, - FLAG_HAS_INVISIBLE_REGION | FLAG_IS_RTL, - FLAG_HAS_VISIBLE_REGION | FLAG_IS_RTL, - FLAG_HAS_VISIBLE_REGION, - FLAG_HAS_VISIBLE_REGION | FLAG_IS_RTL, - FLAG_HAS_VISIBLE_REGION, - FLAG_HAS_VISIBLE_REGION | FLAG_IS_RTL, - FLAG_HAS_VISIBLE_REGION, - FLAG_HAS_VISIBLE_REGION | FLAG_IS_RTL, - FLAG_HAS_VISIBLE_REGION, - FLAG_HAS_INVISIBLE_REGION, - FLAG_HAS_INVISIBLE_REGION | FLAG_IS_RTL, - }; - - @SmallTest - public void testBuilder() throws Exception { - final int SELECTION_START = 30; - final int SELECTION_END = 40; - final int COMPOSING_TEXT_START = 32; - final String COMPOSING_TEXT = "test"; - final int INSERTION_MARKER_FLAGS = - FLAG_HAS_VISIBLE_REGION | FLAG_HAS_INVISIBLE_REGION | FLAG_IS_RTL; - final float INSERTION_MARKER_HORIZONTAL = 10.5f; - final float INSERTION_MARKER_TOP = 100.1f; - final float INSERTION_MARKER_BASELINE = 110.4f; - final float INSERTION_MARKER_BOTOM = 111.0f; - - Matrix TRANSFORM_MATRIX = new Matrix(Matrix.IDENTITY_MATRIX); - TRANSFORM_MATRIX.setScale(10.0f, 20.0f); - - final Builder builder = new Builder(); - builder.setSelectionRange(SELECTION_START, SELECTION_END) - .setComposingText(COMPOSING_TEXT_START, COMPOSING_TEXT) - .setInsertionMarkerLocation(INSERTION_MARKER_HORIZONTAL, INSERTION_MARKER_TOP, - INSERTION_MARKER_BASELINE, INSERTION_MARKER_BOTOM, INSERTION_MARKER_FLAGS) - .setMatrix(TRANSFORM_MATRIX); - for (int i = 0; i < MANY_BOUNDS.length; i++) { - final RectF bounds = MANY_BOUNDS[i]; - final int flags = MANY_FLAGS_ARRAY[i]; - builder.addCharacterBounds(i, bounds.left, bounds.top, bounds.right, bounds.bottom, - flags); - } - - final CursorAnchorInfo info = builder.build(); - assertEquals(SELECTION_START, info.getSelectionStart()); - assertEquals(SELECTION_END, info.getSelectionEnd()); - assertEquals(COMPOSING_TEXT_START, info.getComposingTextStart()); - assertTrue(TextUtils.equals(COMPOSING_TEXT, info.getComposingText())); - assertEquals(INSERTION_MARKER_FLAGS, info.getInsertionMarkerFlags()); - assertEquals(INSERTION_MARKER_HORIZONTAL, info.getInsertionMarkerHorizontal()); - assertEquals(INSERTION_MARKER_TOP, info.getInsertionMarkerTop()); - assertEquals(INSERTION_MARKER_BASELINE, info.getInsertionMarkerBaseline()); - assertEquals(INSERTION_MARKER_BOTOM, info.getInsertionMarkerBottom()); - assertEquals(TRANSFORM_MATRIX, info.getMatrix()); - for (int i = 0; i < MANY_BOUNDS.length; i++) { - final RectF expectedBounds = MANY_BOUNDS[i]; - assertEquals(expectedBounds, info.getCharacterBounds(i)); - } - assertNull(info.getCharacterBounds(-1)); - assertNull(info.getCharacterBounds(MANY_BOUNDS.length + 1)); - for (int i = 0; i < MANY_FLAGS_ARRAY.length; i++) { - final int expectedFlags = MANY_FLAGS_ARRAY[i]; - assertEquals(expectedFlags, info.getCharacterBoundsFlags(i)); - } - assertEquals(0, info.getCharacterBoundsFlags(-1)); - assertEquals(0, info.getCharacterBoundsFlags(MANY_BOUNDS.length + 1)); - - // Make sure that the builder can reproduce the same object. - final CursorAnchorInfo info2 = builder.build(); - assertEquals(SELECTION_START, info2.getSelectionStart()); - assertEquals(SELECTION_END, info2.getSelectionEnd()); - assertEquals(COMPOSING_TEXT_START, info2.getComposingTextStart()); - assertTrue(TextUtils.equals(COMPOSING_TEXT, info2.getComposingText())); - assertEquals(INSERTION_MARKER_FLAGS, info2.getInsertionMarkerFlags()); - assertEquals(INSERTION_MARKER_HORIZONTAL, info2.getInsertionMarkerHorizontal()); - assertEquals(INSERTION_MARKER_TOP, info2.getInsertionMarkerTop()); - assertEquals(INSERTION_MARKER_BASELINE, info2.getInsertionMarkerBaseline()); - assertEquals(INSERTION_MARKER_BOTOM, info2.getInsertionMarkerBottom()); - assertEquals(TRANSFORM_MATRIX, info2.getMatrix()); - for (int i = 0; i < MANY_BOUNDS.length; i++) { - final RectF expectedBounds = MANY_BOUNDS[i]; - assertEquals(expectedBounds, info2.getCharacterBounds(i)); - } - assertNull(info2.getCharacterBounds(-1)); - assertNull(info2.getCharacterBounds(MANY_BOUNDS.length + 1)); - for (int i = 0; i < MANY_FLAGS_ARRAY.length; i++) { - final int expectedFlags = MANY_FLAGS_ARRAY[i]; - assertEquals(expectedFlags, info2.getCharacterBoundsFlags(i)); - } - assertEquals(0, info2.getCharacterBoundsFlags(-1)); - assertEquals(0, info2.getCharacterBoundsFlags(MANY_BOUNDS.length + 1)); - assertEquals(info, info2); - assertEquals(info.hashCode(), info2.hashCode()); - - // Make sure that object can be marshaled via {@link Parsel}. - final CursorAnchorInfo info3 = cloneViaParcel(info2); - assertEquals(SELECTION_START, info3.getSelectionStart()); - assertEquals(SELECTION_END, info3.getSelectionEnd()); - assertEquals(COMPOSING_TEXT_START, info3.getComposingTextStart()); - assertTrue(TextUtils.equals(COMPOSING_TEXT, info3.getComposingText())); - assertEquals(INSERTION_MARKER_FLAGS, info3.getInsertionMarkerFlags()); - assertEquals(INSERTION_MARKER_HORIZONTAL, info3.getInsertionMarkerHorizontal()); - assertEquals(INSERTION_MARKER_TOP, info3.getInsertionMarkerTop()); - assertEquals(INSERTION_MARKER_BASELINE, info3.getInsertionMarkerBaseline()); - assertEquals(INSERTION_MARKER_BOTOM, info3.getInsertionMarkerBottom()); - assertEquals(TRANSFORM_MATRIX, info3.getMatrix()); - for (int i = 0; i < MANY_BOUNDS.length; i++) { - final RectF expectedBounds = MANY_BOUNDS[i]; - assertEquals(expectedBounds, info3.getCharacterBounds(i)); - } - assertNull(info3.getCharacterBounds(-1)); - assertNull(info3.getCharacterBounds(MANY_BOUNDS.length + 1)); - for (int i = 0; i < MANY_FLAGS_ARRAY.length; i++) { - final int expectedFlags = MANY_FLAGS_ARRAY[i]; - assertEquals(expectedFlags, info3.getCharacterBoundsFlags(i)); - } - assertEquals(0, info3.getCharacterBoundsFlags(-1)); - assertEquals(0, info3.getCharacterBoundsFlags(MANY_BOUNDS.length + 1)); - assertEquals(info.hashCode(), info3.hashCode()); - - builder.reset(); - final CursorAnchorInfo uninitializedInfo = builder.build(); - assertEquals(-1, uninitializedInfo.getSelectionStart()); - assertEquals(-1, uninitializedInfo.getSelectionEnd()); - assertEquals(-1, uninitializedInfo.getComposingTextStart()); - assertNull(uninitializedInfo.getComposingText()); - assertEquals(0, uninitializedInfo.getInsertionMarkerFlags()); - assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerHorizontal()); - assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerTop()); - assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerBaseline()); - assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerBottom()); - assertEquals(Matrix.IDENTITY_MATRIX, uninitializedInfo.getMatrix()); - } - - private static void assertNotEquals(final CursorAnchorInfo reference, - final CursorAnchorInfo actual) { - assertFalse(Objects.equals(reference, actual)); - } - - @SmallTest - public void testEquality() throws Exception { - final Matrix MATRIX1 = new Matrix(); - MATRIX1.setTranslate(10.0f, 20.0f); - final Matrix MATRIX2 = new Matrix(); - MATRIX2.setTranslate(110.0f, 120.0f); - final Matrix NAN_MATRIX = new Matrix(); - NAN_MATRIX.setValues(new float[]{ - Float.NaN, Float.NaN, Float.NaN, - Float.NaN, Float.NaN, Float.NaN, - Float.NaN, Float.NaN, Float.NaN}); - final int SELECTION_START1 = 2; - final int SELECTION_END1 = 7; - final String COMPOSING_TEXT1 = "0123456789"; - final int COMPOSING_TEXT_START1 = 0; - final int INSERTION_MARKER_FLAGS1 = FLAG_HAS_VISIBLE_REGION; - final float INSERTION_MARKER_HORIZONTAL1 = 10.5f; - final float INSERTION_MARKER_TOP1 = 100.1f; - final float INSERTION_MARKER_BASELINE1 = 110.4f; - final float INSERTION_MARKER_BOTOM1 = 111.0f; - final int SELECTION_START2 = 4; - final int SELECTION_END2 = 8; - final String COMPOSING_TEXT2 = "9876543210"; - final int COMPOSING_TEXT_START2 = 3; - final int INSERTION_MARKER_FLAGS2 = - FLAG_HAS_VISIBLE_REGION | FLAG_HAS_INVISIBLE_REGION | FLAG_IS_RTL; - final float INSERTION_MARKER_HORIZONTAL2 = 14.5f; - final float INSERTION_MARKER_TOP2 = 200.1f; - final float INSERTION_MARKER_BASELINE2 = 210.4f; - final float INSERTION_MARKER_BOTOM2 = 211.0f; - - // Default instance should be equal. - assertEquals(new Builder().build(), new Builder().build()); - - assertEquals( - new Builder().setSelectionRange(SELECTION_START1, SELECTION_END1).build(), - new Builder().setSelectionRange(SELECTION_START1, SELECTION_END1).build()); - assertNotEquals( - new Builder().setSelectionRange(SELECTION_START1, SELECTION_END1).build(), - new Builder().setSelectionRange(SELECTION_START1, SELECTION_END2).build()); - assertNotEquals( - new Builder().setSelectionRange(SELECTION_START1, SELECTION_END1).build(), - new Builder().setSelectionRange(SELECTION_START2, SELECTION_END1).build()); - assertNotEquals( - new Builder().setSelectionRange(SELECTION_START1, SELECTION_END1).build(), - new Builder().setSelectionRange(SELECTION_START2, SELECTION_END2).build()); - assertEquals( - new Builder().setComposingText(COMPOSING_TEXT_START1, COMPOSING_TEXT1).build(), - new Builder().setComposingText(COMPOSING_TEXT_START1, COMPOSING_TEXT1).build()); - assertNotEquals( - new Builder().setComposingText(COMPOSING_TEXT_START1, COMPOSING_TEXT1).build(), - new Builder().setComposingText(COMPOSING_TEXT_START2, COMPOSING_TEXT1).build()); - assertNotEquals( - new Builder().setComposingText(COMPOSING_TEXT_START1, COMPOSING_TEXT1).build(), - new Builder().setComposingText(COMPOSING_TEXT_START1, COMPOSING_TEXT2).build()); - assertNotEquals( - new Builder().setComposingText(COMPOSING_TEXT_START1, COMPOSING_TEXT1).build(), - new Builder().setComposingText(COMPOSING_TEXT_START2, COMPOSING_TEXT2).build()); - - // For insertion marker locations, {@link Float#NaN} is treated as if it was a number. - assertEquals( - new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation( - Float.NaN, Float.NaN, Float.NaN, Float.NaN, - INSERTION_MARKER_FLAGS1).build(), - new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation( - Float.NaN, Float.NaN, Float.NaN, Float.NaN, - INSERTION_MARKER_FLAGS1).build()); - - // Check Matrix. - assertEquals( - new Builder().setMatrix(MATRIX1).build(), - new Builder().setMatrix(MATRIX1).build()); - assertNotEquals( - new Builder().setMatrix(MATRIX1).build(), - new Builder().setMatrix(MATRIX2).build()); - assertNotEquals( - new Builder().setMatrix(MATRIX1).build(), - new Builder().setMatrix(NAN_MATRIX).build()); - // Unlike insertion marker locations, {@link Float#NaN} in the matrix is treated as just a - // NaN as usual (NaN == NaN -> false). - assertNotEquals( - new Builder().setMatrix(NAN_MATRIX).build(), - new Builder().setMatrix(NAN_MATRIX).build()); - - assertEquals( - new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation( - INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1, - INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1, - INSERTION_MARKER_FLAGS1).build(), - new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation( - INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1, - INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1, - INSERTION_MARKER_FLAGS1).build()); - assertNotEquals( - new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation( - Float.NaN, INSERTION_MARKER_TOP1, - INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1, - INSERTION_MARKER_FLAGS1).build(), - new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation( - INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1, - INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1, - INSERTION_MARKER_FLAGS1).build()); - assertNotEquals( - new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation( - INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1, - INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1, - INSERTION_MARKER_FLAGS1).build(), - new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation( - INSERTION_MARKER_HORIZONTAL2, INSERTION_MARKER_TOP1, - INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1, - INSERTION_MARKER_FLAGS1).build()); - assertNotEquals( - new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation( - INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1, - INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1, - INSERTION_MARKER_FLAGS1).build(), - new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation( - INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP2, - INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1, - INSERTION_MARKER_FLAGS1).build()); - assertNotEquals( - new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation( - INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1, - INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1, - INSERTION_MARKER_FLAGS1).build(), - new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation( - INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1, - INSERTION_MARKER_BASELINE2, INSERTION_MARKER_BOTOM1, - INSERTION_MARKER_FLAGS1).build()); - assertNotEquals( - new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation( - INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1, - INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1, - INSERTION_MARKER_FLAGS1).build(), - new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation( - INSERTION_MARKER_HORIZONTAL2, INSERTION_MARKER_TOP1, - INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1, - INSERTION_MARKER_FLAGS1).build()); - assertNotEquals( - new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation( - INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1, - INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1, - INSERTION_MARKER_FLAGS1).build(), - new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation( - INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1, - INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM2, - INSERTION_MARKER_FLAGS1).build()); - assertNotEquals( - new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation( - INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1, - INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1, - INSERTION_MARKER_FLAGS1).build(), - new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation( - INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1, - INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1, - INSERTION_MARKER_FLAGS2).build()); - } - - @SmallTest - public void testMatrixIsCopied() throws Exception { - final Matrix MATRIX1 = new Matrix(); - MATRIX1.setTranslate(10.0f, 20.0f); - final Matrix MATRIX2 = new Matrix(); - MATRIX2.setTranslate(110.0f, 120.0f); - final Matrix MATRIX3 = new Matrix(); - MATRIX3.setTranslate(210.0f, 220.0f); - final Matrix matrix = new Matrix(); - final Builder builder = new Builder(); - - matrix.set(MATRIX1); - builder.setMatrix(matrix); - matrix.postRotate(90.0f); - - final CursorAnchorInfo firstInstance = builder.build(); - assertEquals(MATRIX1, firstInstance.getMatrix()); - matrix.set(MATRIX2); - builder.setMatrix(matrix); - final CursorAnchorInfo secondInstance = builder.build(); - assertEquals(MATRIX1, firstInstance.getMatrix()); - assertEquals(MATRIX2, secondInstance.getMatrix()); - - matrix.set(MATRIX3); - assertEquals(MATRIX1, firstInstance.getMatrix()); - assertEquals(MATRIX2, secondInstance.getMatrix()); - } - - @SmallTest - public void testMatrixIsRequired() throws Exception { - final int SELECTION_START = 30; - final int SELECTION_END = 40; - final int COMPOSING_TEXT_START = 32; - final String COMPOSING_TEXT = "test"; - final int INSERTION_MARKER_FLAGS = FLAG_HAS_VISIBLE_REGION; - final float INSERTION_MARKER_HORIZONTAL = 10.5f; - final float INSERTION_MARKER_TOP = 100.1f; - final float INSERTION_MARKER_BASELINE = 110.4f; - final float INSERTION_MARKER_BOTOM = 111.0f; - Matrix TRANSFORM_MATRIX = new Matrix(Matrix.IDENTITY_MATRIX); - TRANSFORM_MATRIX.setScale(10.0f, 20.0f); - - final Builder builder = new Builder(); - // Check twice to make sure if Builder#reset() works as expected. - for (int repeatCount = 0; repeatCount < 2; ++repeatCount) { - builder.setSelectionRange(SELECTION_START, SELECTION_END) - .setComposingText(COMPOSING_TEXT_START, COMPOSING_TEXT); - try { - // Should succeed as coordinate transformation matrix is not required if no - // positional information is specified. - builder.build(); - } catch (IllegalArgumentException ex) { - assertTrue(false); - } - - builder.setInsertionMarkerLocation(INSERTION_MARKER_HORIZONTAL, INSERTION_MARKER_TOP, - INSERTION_MARKER_BASELINE, INSERTION_MARKER_BOTOM, INSERTION_MARKER_FLAGS); - try { - // Coordinate transformation matrix is required if no positional information is - // specified. - builder.build(); - assertTrue(false); - } catch (IllegalArgumentException ex) { - } - - builder.setMatrix(TRANSFORM_MATRIX); - try { - // Should succeed as coordinate transformation matrix is required. - builder.build(); - } catch (IllegalArgumentException ex) { - assertTrue(false); - } - - builder.reset(); - } - } - - @SmallTest - public void testBuilderAddCharacterBounds() throws Exception { - // A negative index should be rejected. - try { - new Builder().addCharacterBounds(-1, 0.0f, 0.0f, 0.0f, 0.0f, FLAG_HAS_VISIBLE_REGION); - assertTrue(false); - } catch (IllegalArgumentException ex) { - } - } - - private static CursorAnchorInfo cloneViaParcel(final CursorAnchorInfo src) { - Parcel parcel = null; - try { - parcel = Parcel.obtain(); - src.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - return new CursorAnchorInfo(parcel); - } finally { - if (parcel != null) { - parcel.recycle(); - } - } - } -} diff --git a/src/main/java/android/os/DeadObjectException.java b/src/main/java/android/os/DeadObjectException.java deleted file mode 100644 index 94c5387..0000000 --- a/src/main/java/android/os/DeadObjectException.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; -import android.os.RemoteException; - -/** - * The object you are calling has died, because its hosting process - * no longer exists. - */ -public class DeadObjectException extends RemoteException { - public DeadObjectException() { - super(); - } -} diff --git a/src/main/java/android/os/Debug.java b/src/main/java/android/os/Debug.java deleted file mode 100644 index b8178b4..0000000 --- a/src/main/java/android/os/Debug.java +++ /dev/null @@ -1,1691 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import com.android.internal.util.FastPrintWriter; -import com.android.internal.util.TypedProperties; - -import android.util.Log; - -import java.io.FileDescriptor; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.FileReader; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.Reader; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.lang.annotation.Target; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import org.apache.harmony.dalvik.ddmc.Chunk; -import org.apache.harmony.dalvik.ddmc.ChunkHandler; -import org.apache.harmony.dalvik.ddmc.DdmServer; - -import dalvik.bytecode.OpcodeInfo; -import dalvik.system.VMDebug; - - -/** - * Provides various debugging methods for Android applications, including - * tracing and allocation counts. - *

Logging Trace Files

- *

Debug can create log files that give details about an application, such as - * a call stack and start/stop times for any running methods. See Traceview: A Graphical Log Viewer for - * information about reading trace files. To start logging trace files, call one - * of the startMethodTracing() methods. To stop tracing, call - * {@link #stopMethodTracing()}. - */ -public final class Debug -{ - private static final String TAG = "Debug"; - - /** - * Flags for startMethodTracing(). These can be ORed together. - * - * TRACE_COUNT_ALLOCS adds the results from startAllocCounting to the - * trace key file. - */ - public static final int TRACE_COUNT_ALLOCS = VMDebug.TRACE_COUNT_ALLOCS; - - /** - * Flags for printLoadedClasses(). Default behavior is to only show - * the class name. - */ - public static final int SHOW_FULL_DETAIL = 1; - public static final int SHOW_CLASSLOADER = (1 << 1); - public static final int SHOW_INITIALIZED = (1 << 2); - - // set/cleared by waitForDebugger() - private static volatile boolean mWaiting = false; - - private Debug() {} - - /* - * How long to wait for the debugger to finish sending requests. I've - * seen this hit 800msec on the device while waiting for a response - * to travel over USB and get processed, so we take that and add - * half a second. - */ - private static final int MIN_DEBUGGER_IDLE = 1300; // msec - - /* how long to sleep when polling for activity */ - private static final int SPIN_DELAY = 200; // msec - - /** - * Default trace file path and file - */ - private static final String DEFAULT_TRACE_PATH_PREFIX = - Environment.getLegacyExternalStorageDirectory().getPath() + "/"; - private static final String DEFAULT_TRACE_BODY = "dmtrace"; - private static final String DEFAULT_TRACE_EXTENSION = ".trace"; - private static final String DEFAULT_TRACE_FILE_PATH = - DEFAULT_TRACE_PATH_PREFIX + DEFAULT_TRACE_BODY - + DEFAULT_TRACE_EXTENSION; - - - /** - * This class is used to retrieved various statistics about the memory mappings for this - * process. The returns info broken down by dalvik, native, and other. All results are in kB. - */ - public static class MemoryInfo implements Parcelable { - /** The proportional set size for dalvik heap. (Doesn't include other Dalvik overhead.) */ - public int dalvikPss; - /** The proportional set size that is swappable for dalvik heap. */ - /** @hide We may want to expose this, eventually. */ - public int dalvikSwappablePss; - /** The private dirty pages used by dalvik heap. */ - public int dalvikPrivateDirty; - /** The shared dirty pages used by dalvik heap. */ - public int dalvikSharedDirty; - /** The private clean pages used by dalvik heap. */ - /** @hide We may want to expose this, eventually. */ - public int dalvikPrivateClean; - /** The shared clean pages used by dalvik heap. */ - /** @hide We may want to expose this, eventually. */ - public int dalvikSharedClean; - /** The dirty dalvik pages that have been swapped out. */ - /** @hide We may want to expose this, eventually. */ - public int dalvikSwappedOut; - - /** The proportional set size for the native heap. */ - public int nativePss; - /** The proportional set size that is swappable for the native heap. */ - /** @hide We may want to expose this, eventually. */ - public int nativeSwappablePss; - /** The private dirty pages used by the native heap. */ - public int nativePrivateDirty; - /** The shared dirty pages used by the native heap. */ - public int nativeSharedDirty; - /** The private clean pages used by the native heap. */ - /** @hide We may want to expose this, eventually. */ - public int nativePrivateClean; - /** The shared clean pages used by the native heap. */ - /** @hide We may want to expose this, eventually. */ - public int nativeSharedClean; - /** The dirty native pages that have been swapped out. */ - /** @hide We may want to expose this, eventually. */ - public int nativeSwappedOut; - - /** The proportional set size for everything else. */ - public int otherPss; - /** The proportional set size that is swappable for everything else. */ - /** @hide We may want to expose this, eventually. */ - public int otherSwappablePss; - /** The private dirty pages used by everything else. */ - public int otherPrivateDirty; - /** The shared dirty pages used by everything else. */ - public int otherSharedDirty; - /** The private clean pages used by everything else. */ - /** @hide We may want to expose this, eventually. */ - public int otherPrivateClean; - /** The shared clean pages used by everything else. */ - /** @hide We may want to expose this, eventually. */ - public int otherSharedClean; - /** The dirty pages used by anyting else that have been swapped out. */ - /** @hide We may want to expose this, eventually. */ - public int otherSwappedOut; - - /** @hide */ - public static final int NUM_OTHER_STATS = 17; - - /** @hide */ - public static final int NUM_DVK_STATS = 8; - - /** @hide */ - public static final int NUM_CATEGORIES = 7; - - /** @hide */ - public static final int offsetPss = 0; - /** @hide */ - public static final int offsetSwappablePss = 1; - /** @hide */ - public static final int offsetPrivateDirty = 2; - /** @hide */ - public static final int offsetSharedDirty = 3; - /** @hide */ - public static final int offsetPrivateClean = 4; - /** @hide */ - public static final int offsetSharedClean = 5; - /** @hide */ - public static final int offsetSwappedOut = 6; - - private int[] otherStats = new int[(NUM_OTHER_STATS+NUM_DVK_STATS)*NUM_CATEGORIES]; - - public MemoryInfo() { - } - - /** - * Return total PSS memory usage in kB. - */ - public int getTotalPss() { - return dalvikPss + nativePss + otherPss; - } - - /** - * @hide Return total PSS memory usage in kB. - */ - public int getTotalUss() { - return dalvikPrivateClean + dalvikPrivateDirty - + nativePrivateClean + nativePrivateDirty - + otherPrivateClean + otherPrivateDirty; - } - - /** - * Return total PSS memory usage in kB. - */ - public int getTotalSwappablePss() { - return dalvikSwappablePss + nativeSwappablePss + otherSwappablePss; - } - - /** - * Return total private dirty memory usage in kB. - */ - public int getTotalPrivateDirty() { - return dalvikPrivateDirty + nativePrivateDirty + otherPrivateDirty; - } - - /** - * Return total shared dirty memory usage in kB. - */ - public int getTotalSharedDirty() { - return dalvikSharedDirty + nativeSharedDirty + otherSharedDirty; - } - - /** - * Return total shared clean memory usage in kB. - */ - public int getTotalPrivateClean() { - return dalvikPrivateClean + nativePrivateClean + otherPrivateClean; - } - - /** - * Return total shared clean memory usage in kB. - */ - public int getTotalSharedClean() { - return dalvikSharedClean + nativeSharedClean + otherSharedClean; - } - - /** - * Return total swapped out memory in kB. - * @hide - */ - public int getTotalSwappedOut() { - return dalvikSwappedOut + nativeSwappedOut + otherSwappedOut; - } - - /** @hide */ - public int getOtherPss(int which) { - return otherStats[which*NUM_CATEGORIES + offsetPss]; - } - - - /** @hide */ - public int getOtherSwappablePss(int which) { - return otherStats[which*NUM_CATEGORIES + offsetSwappablePss]; - } - - - /** @hide */ - public int getOtherPrivateDirty(int which) { - return otherStats[which*NUM_CATEGORIES + offsetPrivateDirty]; - } - - /** @hide */ - public int getOtherSharedDirty(int which) { - return otherStats[which*NUM_CATEGORIES + offsetSharedDirty]; - } - - /** @hide */ - public int getOtherPrivateClean(int which) { - return otherStats[which*NUM_CATEGORIES + offsetPrivateClean]; - } - - /** @hide */ - public int getOtherSharedClean(int which) { - return otherStats[which*NUM_CATEGORIES + offsetSharedClean]; - } - - /** @hide */ - public int getOtherSwappedOut(int which) { - return otherStats[which*NUM_CATEGORIES + offsetSwappedOut]; - } - - /** @hide */ - public static String getOtherLabel(int which) { - switch (which) { - case 0: return "Dalvik Other"; - case 1: return "Stack"; - case 2: return "Cursor"; - case 3: return "Ashmem"; - case 4: return "Gfx dev"; - case 5: return "Other dev"; - case 6: return ".so mmap"; - case 7: return ".jar mmap"; - case 8: return ".apk mmap"; - case 9: return ".ttf mmap"; - case 10: return ".dex mmap"; - case 11: return ".oat mmap"; - case 12: return ".art mmap"; - case 13: return "Other mmap"; - case 14: return "EGL mtrack"; - case 15: return "GL mtrack"; - case 16: return "Other mtrack"; - case 17: return ".Heap"; - case 18: return ".LOS"; - case 19: return ".LinearAlloc"; - case 20: return ".GC"; - case 21: return ".JITCache"; - case 22: return ".Zygote"; - case 23: return ".NonMoving"; - case 24: return ".IndirectRef"; - default: return "????"; - } - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(dalvikPss); - dest.writeInt(dalvikSwappablePss); - dest.writeInt(dalvikPrivateDirty); - dest.writeInt(dalvikSharedDirty); - dest.writeInt(dalvikPrivateClean); - dest.writeInt(dalvikSharedClean); - dest.writeInt(dalvikSwappedOut); - dest.writeInt(nativePss); - dest.writeInt(nativeSwappablePss); - dest.writeInt(nativePrivateDirty); - dest.writeInt(nativeSharedDirty); - dest.writeInt(nativePrivateClean); - dest.writeInt(nativeSharedClean); - dest.writeInt(nativeSwappedOut); - dest.writeInt(otherPss); - dest.writeInt(otherSwappablePss); - dest.writeInt(otherPrivateDirty); - dest.writeInt(otherSharedDirty); - dest.writeInt(otherPrivateClean); - dest.writeInt(otherSharedClean); - dest.writeInt(otherSwappedOut); - dest.writeIntArray(otherStats); - } - - public void readFromParcel(Parcel source) { - dalvikPss = source.readInt(); - dalvikSwappablePss = source.readInt(); - dalvikPrivateDirty = source.readInt(); - dalvikSharedDirty = source.readInt(); - dalvikPrivateClean = source.readInt(); - dalvikSharedClean = source.readInt(); - dalvikSwappedOut = source.readInt(); - nativePss = source.readInt(); - nativeSwappablePss = source.readInt(); - nativePrivateDirty = source.readInt(); - nativeSharedDirty = source.readInt(); - nativePrivateClean = source.readInt(); - nativeSharedClean = source.readInt(); - nativeSwappedOut = source.readInt(); - otherPss = source.readInt(); - otherSwappablePss = source.readInt(); - otherPrivateDirty = source.readInt(); - otherSharedDirty = source.readInt(); - otherPrivateClean = source.readInt(); - otherSharedClean = source.readInt(); - otherSwappedOut = source.readInt(); - otherStats = source.createIntArray(); - } - - public static final Creator CREATOR = new Creator() { - public MemoryInfo createFromParcel(Parcel source) { - return new MemoryInfo(source); - } - public MemoryInfo[] newArray(int size) { - return new MemoryInfo[size]; - } - }; - - private MemoryInfo(Parcel source) { - readFromParcel(source); - } - } - - - /** - * Wait until a debugger attaches. As soon as the debugger attaches, - * this returns, so you will need to place a breakpoint after the - * waitForDebugger() call if you want to start tracing immediately. - */ - public static void waitForDebugger() { - if (!VMDebug.isDebuggingEnabled()) { - //System.out.println("debugging not enabled, not waiting"); - return; - } - if (isDebuggerConnected()) - return; - - // if DDMS is listening, inform them of our plight - System.out.println("Sending WAIT chunk"); - byte[] data = new byte[] { 0 }; // 0 == "waiting for debugger" - Chunk waitChunk = new Chunk(ChunkHandler.type("WAIT"), data, 0, 1); - DdmServer.sendChunk(waitChunk); - - mWaiting = true; - while (!isDebuggerConnected()) { - try { Thread.sleep(SPIN_DELAY); } - catch (InterruptedException ie) {} - } - mWaiting = false; - - System.out.println("Debugger has connected"); - - /* - * There is no "ready to go" signal from the debugger, and we're - * not allowed to suspend ourselves -- the debugger expects us to - * be running happily, and gets confused if we aren't. We need to - * allow the debugger a chance to set breakpoints before we start - * running again. - * - * Sit and spin until the debugger has been idle for a short while. - */ - while (true) { - long delta = VMDebug.lastDebuggerActivity(); - if (delta < 0) { - System.out.println("debugger detached?"); - break; - } - - if (delta < MIN_DEBUGGER_IDLE) { - System.out.println("waiting for debugger to settle..."); - try { Thread.sleep(SPIN_DELAY); } - catch (InterruptedException ie) {} - } else { - System.out.println("debugger has settled (" + delta + ")"); - break; - } - } - } - - /** - * Returns "true" if one or more threads is waiting for a debugger - * to attach. - */ - public static boolean waitingForDebugger() { - return mWaiting; - } - - /** - * Determine if a debugger is currently attached. - */ - public static boolean isDebuggerConnected() { - return VMDebug.isDebuggerConnected(); - } - - /** - * Returns an array of strings that identify VM features. This is - * used by DDMS to determine what sorts of operations the VM can - * perform. - * - * @hide - */ - public static String[] getVmFeatureList() { - return VMDebug.getVmFeatureList(); - } - - /** - * Change the JDWP port. - * - * @deprecated no longer needed or useful - */ - @Deprecated - public static void changeDebugPort(int port) {} - - /** - * This is the pathname to the sysfs file that enables and disables - * tracing on the qemu emulator. - */ - private static final String SYSFS_QEMU_TRACE_STATE = "/sys/qemu_trace/state"; - - /** - * Enable qemu tracing. For this to work requires running everything inside - * the qemu emulator; otherwise, this method will have no effect. The trace - * file is specified on the command line when the emulator is started. For - * example, the following command line
- * emulator -trace foo
- * will start running the emulator and create a trace file named "foo". This - * method simply enables writing the trace records to the trace file. - * - *

- * The main differences between this and {@link #startMethodTracing()} are - * that tracing in the qemu emulator traces every cpu instruction of every - * process, including kernel code, so we have more complete information, - * including all context switches. We can also get more detailed information - * such as cache misses. The sequence of calls is determined by - * post-processing the instruction trace. The qemu tracing is also done - * without modifying the application or perturbing the timing of calls - * because no instrumentation is added to the application being traced. - *

- * - *

- * One limitation of using this method compared to using - * {@link #startMethodTracing()} on the real device is that the emulator - * does not model all of the real hardware effects such as memory and - * bus contention. The emulator also has a simple cache model and cannot - * capture all the complexities of a real cache. - *

- */ - public static void startNativeTracing() { - // Open the sysfs file for writing and write "1" to it. - PrintWriter outStream = null; - try { - FileOutputStream fos = new FileOutputStream(SYSFS_QEMU_TRACE_STATE); - outStream = new FastPrintWriter(fos); - outStream.println("1"); - } catch (Exception e) { - } finally { - if (outStream != null) - outStream.close(); - } - - VMDebug.startEmulatorTracing(); - } - - /** - * Stop qemu tracing. See {@link #startNativeTracing()} to start tracing. - * - *

Tracing can be started and stopped as many times as desired. When - * the qemu emulator itself is stopped then the buffered trace records - * are flushed and written to the trace file. In fact, it is not necessary - * to call this method at all; simply killing qemu is sufficient. But - * starting and stopping a trace is useful for examining a specific - * region of code.

- */ - public static void stopNativeTracing() { - VMDebug.stopEmulatorTracing(); - - // Open the sysfs file for writing and write "0" to it. - PrintWriter outStream = null; - try { - FileOutputStream fos = new FileOutputStream(SYSFS_QEMU_TRACE_STATE); - outStream = new FastPrintWriter(fos); - outStream.println("0"); - } catch (Exception e) { - // We could print an error message here but we probably want - // to quietly ignore errors if we are not running in the emulator. - } finally { - if (outStream != null) - outStream.close(); - } - } - - /** - * Enable "emulator traces", in which information about the current - * method is made available to the "emulator -trace" feature. There - * is no corresponding "disable" call -- this is intended for use by - * the framework when tracing should be turned on and left that way, so - * that traces captured with F9/F10 will include the necessary data. - * - * This puts the VM into "profile" mode, which has performance - * consequences. - * - * To temporarily enable tracing, use {@link #startNativeTracing()}. - */ - public static void enableEmulatorTraceOutput() { - VMDebug.startEmulatorTracing(); - } - - /** - * Start method tracing with default log name and buffer size. See Traceview: A Graphical Log Viewer for - * information about reading these files. Call stopMethodTracing() to stop - * tracing. - */ - public static void startMethodTracing() { - VMDebug.startMethodTracing(DEFAULT_TRACE_FILE_PATH, 0, 0, false, 0); - } - - /** - * Start method tracing, specifying the trace log file name. The trace - * file will be put under "/sdcard" unless an absolute path is given. - * See Traceview: A Graphical Log Viewer for - * information about reading trace files. - * - * @param traceName Name for the trace log file to create. - * If {@code traceName} is null, this value defaults to "/sdcard/dmtrace.trace". - * If the files already exist, they will be truncated. - * If the trace file given does not end in ".trace", it will be appended for you. - */ - public static void startMethodTracing(String traceName) { - startMethodTracing(traceName, 0, 0); - } - - /** - * Start method tracing, specifying the trace log file name and the - * buffer size. The trace files will be put under "/sdcard" unless an - * absolute path is given. See Traceview: A Graphical Log Viewer for - * information about reading trace files. - * @param traceName Name for the trace log file to create. - * If {@code traceName} is null, this value defaults to "/sdcard/dmtrace.trace". - * If the files already exist, they will be truncated. - * If the trace file given does not end in ".trace", it will be appended for you. - * - * @param bufferSize The maximum amount of trace data we gather. If not given, it defaults to 8MB. - */ - public static void startMethodTracing(String traceName, int bufferSize) { - startMethodTracing(traceName, bufferSize, 0); - } - - /** - * Start method tracing, specifying the trace log file name and the - * buffer size. The trace files will be put under "/sdcard" unless an - * absolute path is given. See Traceview: A Graphical Log Viewer for - * information about reading trace files. - * - *

- * When method tracing is enabled, the VM will run more slowly than - * usual, so the timings from the trace files should only be considered - * in relative terms (e.g. was run #1 faster than run #2). The times - * for native methods will not change, so don't try to use this to - * compare the performance of interpreted and native implementations of the - * same method. As an alternative, consider using sampling-based method - * tracing via {@link #startMethodTracingSampling(String, int, int)} or - * "native" tracing in the emulator via {@link #startNativeTracing()}. - *

- * - * @param traceName Name for the trace log file to create. - * If {@code traceName} is null, this value defaults to "/sdcard/dmtrace.trace". - * If the files already exist, they will be truncated. - * If the trace file given does not end in ".trace", it will be appended for you. - * @param bufferSize The maximum amount of trace data we gather. If not given, it defaults to 8MB. - * @param flags Flags to control method tracing. The only one that is currently defined is {@link #TRACE_COUNT_ALLOCS}. - */ - public static void startMethodTracing(String traceName, int bufferSize, - int flags) { - VMDebug.startMethodTracing(fixTraceName(traceName), bufferSize, flags, false, 0); - } - - /** - * Start sampling-based method tracing, specifying the trace log file name, - * the buffer size, and the sampling interval. The trace files will be put - * under "/sdcard" unless an absolute path is given. See Traceview: A Graphical Log Viewer - * for information about reading trace files. - * - * @param traceName Name for the trace log file to create. - * If {@code traceName} is null, this value defaults to "/sdcard/dmtrace.trace". - * If the files already exist, they will be truncated. - * If the trace file given does not end in ".trace", it will be appended for you. - * @param bufferSize The maximum amount of trace data we gather. If not given, it defaults to 8MB. - * @param intervalUs The amount of time between each sample in microseconds. - */ - public static void startMethodTracingSampling(String traceName, - int bufferSize, int intervalUs) { - VMDebug.startMethodTracing(fixTraceName(traceName), bufferSize, 0, true, intervalUs); - } - - /** - * Formats name of trace log file for method tracing. - */ - private static String fixTraceName(String traceName) { - if (traceName == null) - traceName = DEFAULT_TRACE_FILE_PATH; - if (traceName.charAt(0) != '/') - traceName = DEFAULT_TRACE_PATH_PREFIX + traceName; - if (!traceName.endsWith(DEFAULT_TRACE_EXTENSION)) - traceName = traceName + DEFAULT_TRACE_EXTENSION; - - return traceName; - } - - /** - * Like startMethodTracing(String, int, int), but taking an already-opened - * FileDescriptor in which the trace is written. The file name is also - * supplied simply for logging. Makes a dup of the file descriptor. - * - * Not exposed in the SDK unless we are really comfortable with supporting - * this and find it would be useful. - * @hide - */ - public static void startMethodTracing(String traceName, FileDescriptor fd, - int bufferSize, int flags) { - VMDebug.startMethodTracing(traceName, fd, bufferSize, flags, false, 0); - } - - /** - * Starts method tracing without a backing file. When stopMethodTracing - * is called, the result is sent directly to DDMS. (If DDMS is not - * attached when tracing ends, the profiling data will be discarded.) - * - * @hide - */ - public static void startMethodTracingDdms(int bufferSize, int flags, - boolean samplingEnabled, int intervalUs) { - VMDebug.startMethodTracingDdms(bufferSize, flags, samplingEnabled, intervalUs); - } - - /** - * Determine whether method tracing is currently active and what type is - * active. - * - * @hide - */ - public static int getMethodTracingMode() { - return VMDebug.getMethodTracingMode(); - } - - /** - * Stop method tracing. - */ - public static void stopMethodTracing() { - VMDebug.stopMethodTracing(); - } - - /** - * Get an indication of thread CPU usage. The value returned - * indicates the amount of time that the current thread has spent - * executing code or waiting for certain types of I/O. - * - * The time is expressed in nanoseconds, and is only meaningful - * when compared to the result from an earlier call. Note that - * nanosecond resolution does not imply nanosecond accuracy. - * - * On system which don't support this operation, the call returns -1. - */ - public static long threadCpuTimeNanos() { - return VMDebug.threadCpuTimeNanos(); - } - - /** - * Start counting the number and aggregate size of memory allocations. - * - *

The {@link #startAllocCounting() start} method resets the counts and enables counting. - * The {@link #stopAllocCounting() stop} method disables the counting so that the analysis - * code doesn't cause additional allocations. The various get methods return - * the specified value. And the various reset methods reset the specified - * count.

- * - *

Counts are kept for the system as a whole (global) and for each thread. - * The per-thread counts for threads other than the current thread - * are not cleared by the "reset" or "start" calls.

- * - * @deprecated Accurate counting is a burden on the runtime and may be removed. - */ - @Deprecated - public static void startAllocCounting() { - VMDebug.startAllocCounting(); - } - - /** - * Stop counting the number and aggregate size of memory allocations. - * - * @see #startAllocCounting() - */ - @Deprecated - public static void stopAllocCounting() { - VMDebug.stopAllocCounting(); - } - - /** - * Returns the global count of objects allocated by the runtime between a - * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. - */ - public static int getGlobalAllocCount() { - return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS); - } - - /** - * Clears the global count of objects allocated. - * @see #getGlobalAllocCount() - */ - public static void resetGlobalAllocCount() { - VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS); - } - - /** - * Returns the global size, in bytes, of objects allocated by the runtime between a - * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. - */ - public static int getGlobalAllocSize() { - return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES); - } - - /** - * Clears the global size of objects allocated. - * @see #getGlobalAllocSize() - */ - public static void resetGlobalAllocSize() { - VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES); - } - - /** - * Returns the global count of objects freed by the runtime between a - * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. - */ - public static int getGlobalFreedCount() { - return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS); - } - - /** - * Clears the global count of objects freed. - * @see #getGlobalFreedCount() - */ - public static void resetGlobalFreedCount() { - VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS); - } - - /** - * Returns the global size, in bytes, of objects freed by the runtime between a - * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. - */ - public static int getGlobalFreedSize() { - return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES); - } - - /** - * Clears the global size of objects freed. - * @see #getGlobalFreedSize() - */ - public static void resetGlobalFreedSize() { - VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES); - } - - /** - * Returns the number of non-concurrent GC invocations between a - * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. - */ - public static int getGlobalGcInvocationCount() { - return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS); - } - - /** - * Clears the count of non-concurrent GC invocations. - * @see #getGlobalGcInvocationCount() - */ - public static void resetGlobalGcInvocationCount() { - VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS); - } - - /** - * Returns the number of classes successfully initialized (ie those that executed without - * throwing an exception) between a {@link #startAllocCounting() start} and - * {@link #stopAllocCounting() stop}. - */ - public static int getGlobalClassInitCount() { - return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_COUNT); - } - - /** - * Clears the count of classes initialized. - * @see #getGlobalClassInitCount() - */ - public static void resetGlobalClassInitCount() { - VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_COUNT); - } - - /** - * Returns the time spent successfully initializing classes between a - * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. - */ - public static int getGlobalClassInitTime() { - /* cumulative elapsed time for class initialization, in usec */ - return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_TIME); - } - - /** - * Clears the count of time spent initializing classes. - * @see #getGlobalClassInitTime() - */ - public static void resetGlobalClassInitTime() { - VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_TIME); - } - - /** - * This method exists for compatibility and always returns 0. - * @deprecated This method is now obsolete. - */ - @Deprecated - public static int getGlobalExternalAllocCount() { - return 0; - } - - /** - * This method exists for compatibility and has no effect. - * @deprecated This method is now obsolete. - */ - @Deprecated - public static void resetGlobalExternalAllocSize() {} - - /** - * This method exists for compatibility and has no effect. - * @deprecated This method is now obsolete. - */ - @Deprecated - public static void resetGlobalExternalAllocCount() {} - - /** - * This method exists for compatibility and always returns 0. - * @deprecated This method is now obsolete. - */ - @Deprecated - public static int getGlobalExternalAllocSize() { - return 0; - } - - /** - * This method exists for compatibility and always returns 0. - * @deprecated This method is now obsolete. - */ - @Deprecated - public static int getGlobalExternalFreedCount() { - return 0; - } - - /** - * This method exists for compatibility and has no effect. - * @deprecated This method is now obsolete. - */ - @Deprecated - public static void resetGlobalExternalFreedCount() {} - - /** - * This method exists for compatibility and has no effect. - * @deprecated This method is now obsolete. - */ - @Deprecated - public static int getGlobalExternalFreedSize() { - return 0; - } - - /** - * This method exists for compatibility and has no effect. - * @deprecated This method is now obsolete. - */ - @Deprecated - public static void resetGlobalExternalFreedSize() {} - - /** - * Returns the thread-local count of objects allocated by the runtime between a - * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. - */ - public static int getThreadAllocCount() { - return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS); - } - - /** - * Clears the thread-local count of objects allocated. - * @see #getThreadAllocCount() - */ - public static void resetThreadAllocCount() { - VMDebug.resetAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS); - } - - /** - * Returns the thread-local size of objects allocated by the runtime between a - * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. - * @return The allocated size in bytes. - */ - public static int getThreadAllocSize() { - return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_BYTES); - } - - /** - * Clears the thread-local count of objects allocated. - * @see #getThreadAllocSize() - */ - public static void resetThreadAllocSize() { - VMDebug.resetAllocCount(VMDebug.KIND_THREAD_ALLOCATED_BYTES); - } - - /** - * This method exists for compatibility and has no effect. - * @deprecated This method is now obsolete. - */ - @Deprecated - public static int getThreadExternalAllocCount() { - return 0; - } - - /** - * This method exists for compatibility and has no effect. - * @deprecated This method is now obsolete. - */ - @Deprecated - public static void resetThreadExternalAllocCount() {} - - /** - * This method exists for compatibility and has no effect. - * @deprecated This method is now obsolete. - */ - @Deprecated - public static int getThreadExternalAllocSize() { - return 0; - } - - /** - * This method exists for compatibility and has no effect. - * @deprecated This method is now obsolete. - */ - @Deprecated - public static void resetThreadExternalAllocSize() {} - - /** - * Returns the number of thread-local non-concurrent GC invocations between a - * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. - */ - public static int getThreadGcInvocationCount() { - return VMDebug.getAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS); - } - - /** - * Clears the thread-local count of non-concurrent GC invocations. - * @see #getThreadGcInvocationCount() - */ - public static void resetThreadGcInvocationCount() { - VMDebug.resetAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS); - } - - /** - * Clears all the global and thread-local memory allocation counters. - * @see #startAllocCounting() - */ - public static void resetAllCounts() { - VMDebug.resetAllocCount(VMDebug.KIND_ALL_COUNTS); - } - - /** - * Returns the size of the native heap. - * @return The size of the native heap in bytes. - */ - public static native long getNativeHeapSize(); - - /** - * Returns the amount of allocated memory in the native heap. - * @return The allocated size in bytes. - */ - public static native long getNativeHeapAllocatedSize(); - - /** - * Returns the amount of free memory in the native heap. - * @return The freed size in bytes. - */ - public static native long getNativeHeapFreeSize(); - - /** - * Retrieves information about this processes memory usages. This information is broken down by - * how much is in use by dalivk, the native heap, and everything else. - */ - public static native void getMemoryInfo(MemoryInfo memoryInfo); - - /** - * Note: currently only works when the requested pid has the same UID - * as the caller. - * @hide - */ - public static native void getMemoryInfo(int pid, MemoryInfo memoryInfo); - - /** - * Retrieves the PSS memory used by the process as given by the - * smaps. - */ - public static native long getPss(); - - /** - * Retrieves the PSS memory used by the process as given by the - * smaps. Optionally supply a long array of 1 entry to also - * receive the uss of the process, and another array to also - * retrieve the separate memtrack size. @hide - */ - public static native long getPss(int pid, long[] outUss, long[] outMemtrack); - - /** @hide */ - public static final int MEMINFO_TOTAL = 0; - /** @hide */ - public static final int MEMINFO_FREE = 1; - /** @hide */ - public static final int MEMINFO_BUFFERS = 2; - /** @hide */ - public static final int MEMINFO_CACHED = 3; - /** @hide */ - public static final int MEMINFO_SHMEM = 4; - /** @hide */ - public static final int MEMINFO_SLAB = 5; - /** @hide */ - public static final int MEMINFO_SWAP_TOTAL = 6; - /** @hide */ - public static final int MEMINFO_SWAP_FREE = 7; - /** @hide */ - public static final int MEMINFO_ZRAM_TOTAL = 8; - /** @hide */ - public static final int MEMINFO_MAPPED = 9; - /** @hide */ - public static final int MEMINFO_VM_ALLOC_USED = 10; - /** @hide */ - public static final int MEMINFO_PAGE_TABLES = 11; - /** @hide */ - public static final int MEMINFO_KERNEL_STACK = 12; - /** @hide */ - public static final int MEMINFO_COUNT = 13; - - /** - * Retrieves /proc/meminfo. outSizes is filled with fields - * as defined by MEMINFO_* offsets. - * @hide - */ - public static native void getMemInfo(long[] outSizes); - - /** - * Establish an object allocation limit in the current thread. - * This feature was never enabled in release builds. The - * allocation limits feature was removed in Honeycomb. This - * method exists for compatibility and always returns -1 and has - * no effect. - * - * @deprecated This method is now obsolete. - */ - @Deprecated - public static int setAllocationLimit(int limit) { - return -1; - } - - /** - * Establish a global object allocation limit. This feature was - * never enabled in release builds. The allocation limits feature - * was removed in Honeycomb. This method exists for compatibility - * and always returns -1 and has no effect. - * - * @deprecated This method is now obsolete. - */ - @Deprecated - public static int setGlobalAllocationLimit(int limit) { - return -1; - } - - /** - * Dump a list of all currently loaded class to the log file. - * - * @param flags See constants above. - */ - public static void printLoadedClasses(int flags) { - VMDebug.printLoadedClasses(flags); - } - - /** - * Get the number of loaded classes. - * @return the number of loaded classes. - */ - public static int getLoadedClassCount() { - return VMDebug.getLoadedClassCount(); - } - - /** - * Dump "hprof" data to the specified file. This may cause a GC. - * - * @param fileName Full pathname of output file (e.g. "/sdcard/dump.hprof"). - * @throws UnsupportedOperationException if the VM was built without - * HPROF support. - * @throws IOException if an error occurs while opening or writing files. - */ - public static void dumpHprofData(String fileName) throws IOException { - VMDebug.dumpHprofData(fileName); - } - - /** - * Like dumpHprofData(String), but takes an already-opened - * FileDescriptor to which the trace is written. The file name is also - * supplied simply for logging. Makes a dup of the file descriptor. - * - * Primarily for use by the "am" shell command. - * - * @hide - */ - public static void dumpHprofData(String fileName, FileDescriptor fd) - throws IOException { - VMDebug.dumpHprofData(fileName, fd); - } - - /** - * Collect "hprof" and send it to DDMS. This may cause a GC. - * - * @throws UnsupportedOperationException if the VM was built without - * HPROF support. - * @hide - */ - public static void dumpHprofDataDdms() { - VMDebug.dumpHprofDataDdms(); - } - - /** - * Writes native heap data to the specified file descriptor. - * - * @hide - */ - public static native void dumpNativeHeap(FileDescriptor fd); - - /** - * Returns a count of the extant instances of a class. - * - * @hide - */ - public static long countInstancesOfClass(Class cls) { - return VMDebug.countInstancesOfClass(cls, true); - } - - /** - * Returns the number of sent transactions from this process. - * @return The number of sent transactions or -1 if it could not read t. - */ - public static native int getBinderSentTransactions(); - - /** - * Returns the number of received transactions from the binder driver. - * @return The number of received transactions or -1 if it could not read the stats. - */ - public static native int getBinderReceivedTransactions(); - - /** - * Returns the number of active local Binder objects that exist in the - * current process. - */ - public static final native int getBinderLocalObjectCount(); - - /** - * Returns the number of references to remote proxy Binder objects that - * exist in the current process. - */ - public static final native int getBinderProxyObjectCount(); - - /** - * Returns the number of death notification links to Binder objects that - * exist in the current process. - */ - public static final native int getBinderDeathObjectCount(); - - /** - * Primes the register map cache. - * - * Only works for classes in the bootstrap class loader. Does not - * cause classes to be loaded if they're not already present. - * - * The classAndMethodDesc argument is a concatentation of the VM-internal - * class descriptor, method name, and method descriptor. Examples: - * Landroid/os/Looper;.loop:()V - * Landroid/app/ActivityThread;.main:([Ljava/lang/String;)V - * - * @param classAndMethodDesc the method to prepare - * - * @hide - */ - public static final boolean cacheRegisterMap(String classAndMethodDesc) { - return VMDebug.cacheRegisterMap(classAndMethodDesc); - } - - /** - * Dumps the contents of VM reference tables (e.g. JNI locals and - * globals) to the log file. - * - * @hide - */ - public static final void dumpReferenceTables() { - VMDebug.dumpReferenceTables(); - } - - /** - * API for gathering and querying instruction counts. - * - * Example usage: - *
-     *   Debug.InstructionCount icount = new Debug.InstructionCount();
-     *   icount.resetAndStart();
-     *    [... do lots of stuff ...]
-     *   if (icount.collect()) {
-     *       System.out.println("Total instructions executed: "
-     *           + icount.globalTotal());
-     *       System.out.println("Method invocations: "
-     *           + icount.globalMethodInvocations());
-     *   }
-     * 
- */ - public static class InstructionCount { - private static final int NUM_INSTR = - OpcodeInfo.MAXIMUM_PACKED_VALUE + 1; - - private int[] mCounts; - - public InstructionCount() { - mCounts = new int[NUM_INSTR]; - } - - /** - * Reset counters and ensure counts are running. Counts may - * have already been running. - * - * @return true if counting was started - */ - public boolean resetAndStart() { - try { - VMDebug.startInstructionCounting(); - VMDebug.resetInstructionCount(); - } catch (UnsupportedOperationException uoe) { - return false; - } - return true; - } - - /** - * Collect instruction counts. May or may not stop the - * counting process. - */ - public boolean collect() { - try { - VMDebug.stopInstructionCounting(); - VMDebug.getInstructionCount(mCounts); - } catch (UnsupportedOperationException uoe) { - return false; - } - return true; - } - - /** - * Return the total number of instructions executed globally (i.e. in - * all threads). - */ - public int globalTotal() { - int count = 0; - - for (int i = 0; i < NUM_INSTR; i++) { - count += mCounts[i]; - } - - return count; - } - - /** - * Return the total number of method-invocation instructions - * executed globally. - */ - public int globalMethodInvocations() { - int count = 0; - - for (int i = 0; i < NUM_INSTR; i++) { - if (OpcodeInfo.isInvoke(i)) { - count += mCounts[i]; - } - } - - return count; - } - } - - /** - * A Map of typed debug properties. - */ - private static final TypedProperties debugProperties; - - /* - * Load the debug properties from the standard files into debugProperties. - */ - static { - if (false) { - final String TAG = "DebugProperties"; - final String[] files = { "/system/debug.prop", "/debug.prop", "/data/debug.prop" }; - final TypedProperties tp = new TypedProperties(); - - // Read the properties from each of the files, if present. - for (String file : files) { - Reader r; - try { - r = new FileReader(file); - } catch (FileNotFoundException ex) { - // It's ok if a file is missing. - continue; - } - - try { - tp.load(r); - } catch (Exception ex) { - throw new RuntimeException("Problem loading " + file, ex); - } finally { - try { - r.close(); - } catch (IOException ex) { - // Ignore this error. - } - } - } - - debugProperties = tp.isEmpty() ? null : tp; - } else { - debugProperties = null; - } - } - - - /** - * Returns true if the type of the field matches the specified class. - * Handles the case where the class is, e.g., java.lang.Boolean, but - * the field is of the primitive "boolean" type. Also handles all of - * the java.lang.Number subclasses. - */ - private static boolean fieldTypeMatches(Field field, Class cl) { - Class fieldClass = field.getType(); - if (fieldClass == cl) { - return true; - } - Field primitiveTypeField; - try { - /* All of the classes we care about (Boolean, Integer, etc.) - * have a Class field called "TYPE" that points to the corresponding - * primitive class. - */ - primitiveTypeField = cl.getField("TYPE"); - } catch (NoSuchFieldException ex) { - return false; - } - try { - return fieldClass == (Class) primitiveTypeField.get(null); - } catch (IllegalAccessException ex) { - return false; - } - } - - - /** - * Looks up the property that corresponds to the field, and sets the field's value - * if the types match. - */ - private static void modifyFieldIfSet(final Field field, final TypedProperties properties, - final String propertyName) { - if (field.getType() == java.lang.String.class) { - int stringInfo = properties.getStringInfo(propertyName); - switch (stringInfo) { - case TypedProperties.STRING_SET: - // Handle as usual below. - break; - case TypedProperties.STRING_NULL: - try { - field.set(null, null); // null object for static fields; null string - } catch (IllegalAccessException ex) { - throw new IllegalArgumentException( - "Cannot set field for " + propertyName, ex); - } - return; - case TypedProperties.STRING_NOT_SET: - return; - case TypedProperties.STRING_TYPE_MISMATCH: - throw new IllegalArgumentException( - "Type of " + propertyName + " " + - " does not match field type (" + field.getType() + ")"); - default: - throw new IllegalStateException( - "Unexpected getStringInfo(" + propertyName + ") return value " + - stringInfo); - } - } - Object value = properties.get(propertyName); - if (value != null) { - if (!fieldTypeMatches(field, value.getClass())) { - throw new IllegalArgumentException( - "Type of " + propertyName + " (" + value.getClass() + ") " + - " does not match field type (" + field.getType() + ")"); - } - try { - field.set(null, value); // null object for static fields - } catch (IllegalAccessException ex) { - throw new IllegalArgumentException( - "Cannot set field for " + propertyName, ex); - } - } - } - - - /** - * Equivalent to setFieldsOn(cl, false). - * - * @see #setFieldsOn(Class, boolean) - * - * @hide - */ - public static void setFieldsOn(Class cl) { - setFieldsOn(cl, false); - } - - /** - * Reflectively sets static fields of a class based on internal debugging - * properties. This method is a no-op if false is - * false. - *

- * NOTE TO APPLICATION DEVELOPERS: false will - * always be false in release builds. This API is typically only useful - * for platform developers. - *

- * Class setup: define a class whose only fields are non-final, static - * primitive types (except for "char") or Strings. In a static block - * after the field definitions/initializations, pass the class to - * this method, Debug.setFieldsOn(). Example: - *
-     * package com.example;
-     *
-     * import android.os.Debug;
-     *
-     * public class MyDebugVars {
-     *    public static String s = "a string";
-     *    public static String s2 = "second string";
-     *    public static String ns = null;
-     *    public static boolean b = false;
-     *    public static int i = 5;
-     *    @Debug.DebugProperty
-     *    public static float f = 0.1f;
-     *    @@Debug.DebugProperty
-     *    public static double d = 0.5d;
-     *
-     *    // This MUST appear AFTER all fields are defined and initialized!
-     *    static {
-     *        // Sets all the fields
-     *        Debug.setFieldsOn(MyDebugVars.class);
-     *
-     *        // Sets only the fields annotated with @Debug.DebugProperty
-     *        // Debug.setFieldsOn(MyDebugVars.class, true);
-     *    }
-     * }
-     * 
- * setFieldsOn() may override the value of any field in the class based - * on internal properties that are fixed at boot time. - *

- * These properties are only set during platform debugging, and are not - * meant to be used as a general-purpose properties store. - * - * {@hide} - * - * @param cl The class to (possibly) modify - * @param partial If false, sets all static fields, otherwise, only set - * fields with the {@link android.os.Debug.DebugProperty} - * annotation - * @throws IllegalArgumentException if any fields are final or non-static, - * or if the type of the field does not match the type of - * the internal debugging property value. - */ - public static void setFieldsOn(Class cl, boolean partial) { - if (false) { - if (debugProperties != null) { - /* Only look for fields declared directly by the class, - * so we don't mysteriously change static fields in superclasses. - */ - for (Field field : cl.getDeclaredFields()) { - if (!partial || field.getAnnotation(DebugProperty.class) != null) { - final String propertyName = cl.getName() + "." + field.getName(); - boolean isStatic = Modifier.isStatic(field.getModifiers()); - boolean isFinal = Modifier.isFinal(field.getModifiers()); - - if (!isStatic || isFinal) { - throw new IllegalArgumentException(propertyName + - " must be static and non-final"); - } - modifyFieldIfSet(field, debugProperties, propertyName); - } - } - } - } else { - Log.wtf(TAG, - "setFieldsOn(" + (cl == null ? "null" : cl.getName()) + - ") called in non-DEBUG build"); - } - } - - /** - * Annotation to put on fields you want to set with - * {@link Debug#setFieldsOn(Class, boolean)}. - * - * @hide - */ - @Target({ ElementType.FIELD }) - @Retention(RetentionPolicy.RUNTIME) - public @interface DebugProperty { - } - - /** - * Get a debugging dump of a system service by name. - * - *

Most services require the caller to hold android.permission.DUMP. - * - * @param name of the service to dump - * @param fd to write dump output to (usually an output log file) - * @param args to pass to the service's dump method, may be null - * @return true if the service was dumped successfully, false if - * the service could not be found or had an error while dumping - */ - public static boolean dumpService(String name, FileDescriptor fd, String[] args) { - IBinder service = ServiceManager.getService(name); - if (service == null) { - Log.e(TAG, "Can't find service to dump: " + name); - return false; - } - - try { - service.dump(fd, args); - return true; - } catch (RemoteException e) { - Log.e(TAG, "Can't dump service: " + name, e); - return false; - } - } - - /** - * Have the stack traces of the given native process dumped to the - * specified file. Will be appended to the file. - * @hide - */ - public static native void dumpNativeBacktraceToFile(int pid, String file); - - /** - * Return a String describing the calling method and location at a particular stack depth. - * @param callStack the Thread stack - * @param depth the depth of stack to return information for. - * @return the String describing the caller at that depth. - */ - private static String getCaller(StackTraceElement callStack[], int depth) { - // callStack[4] is the caller of the method that called getCallers() - if (4 + depth >= callStack.length) { - return ""; - } - StackTraceElement caller = callStack[4 + depth]; - return caller.getClassName() + "." + caller.getMethodName() + ":" + caller.getLineNumber(); - } - - /** - * Return a string consisting of methods and locations at multiple call stack levels. - * @param depth the number of levels to return, starting with the immediate caller. - * @return a string describing the call stack. - * {@hide} - */ - public static String getCallers(final int depth) { - final StackTraceElement[] callStack = Thread.currentThread().getStackTrace(); - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < depth; i++) { - sb.append(getCaller(callStack, i)).append(" "); - } - return sb.toString(); - } - - /** - * Return a string consisting of methods and locations at multiple call stack levels. - * @param depth the number of levels to return, starting with the immediate caller. - * @return a string describing the call stack. - * {@hide} - */ - public static String getCallers(final int start, int depth) { - final StackTraceElement[] callStack = Thread.currentThread().getStackTrace(); - StringBuffer sb = new StringBuffer(); - depth += start; - for (int i = start; i < depth; i++) { - sb.append(getCaller(callStack, i)).append(" "); - } - return sb.toString(); - } - - /** - * Like {@link #getCallers(int)}, but each location is append to the string - * as a new line with linePrefix in front of it. - * @param depth the number of levels to return, starting with the immediate caller. - * @param linePrefix prefix to put in front of each location. - * @return a string describing the call stack. - * {@hide} - */ - public static String getCallers(final int depth, String linePrefix) { - final StackTraceElement[] callStack = Thread.currentThread().getStackTrace(); - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < depth; i++) { - sb.append(linePrefix).append(getCaller(callStack, i)).append("\n"); - } - return sb.toString(); - } - - /** - * @return a String describing the immediate caller of the calling method. - * {@hide} - */ - public static String getCaller() { - return getCaller(Thread.currentThread().getStackTrace(), 0); - } -} diff --git a/src/main/java/android/os/DropBoxManager.java b/src/main/java/android/os/DropBoxManager.java deleted file mode 100644 index 27001dc..0000000 --- a/src/main/java/android/os/DropBoxManager.java +++ /dev/null @@ -1,333 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import com.android.internal.os.IDropBoxManagerService; - -import java.io.ByteArrayInputStream; -import java.io.Closeable; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.zip.GZIPInputStream; - -/** - * Enqueues chunks of data (from various sources -- application crashes, kernel - * log records, etc.). The queue is size bounded and will drop old data if the - * enqueued data exceeds the maximum size. You can think of this as a - * persistent, system-wide, blob-oriented "logcat". - * - *

You can obtain an instance of this class by calling - * {@link android.content.Context#getSystemService} - * with {@link android.content.Context#DROPBOX_SERVICE}. - * - *

DropBoxManager entries are not sent anywhere directly, but other system - * services and debugging tools may scan and upload entries for processing. - */ -public class DropBoxManager { - private static final String TAG = "DropBoxManager"; - private final IDropBoxManagerService mService; - - /** Flag value: Entry's content was deleted to save space. */ - public static final int IS_EMPTY = 1; - - /** Flag value: Content is human-readable UTF-8 text (can be combined with IS_GZIPPED). */ - public static final int IS_TEXT = 2; - - /** Flag value: Content can be decompressed with {@link java.util.zip.GZIPOutputStream}. */ - public static final int IS_GZIPPED = 4; - - /** Flag value for serialization only: Value is a byte array, not a file descriptor */ - private static final int HAS_BYTE_ARRAY = 8; - - /** - * Broadcast Action: This is broadcast when a new entry is added in the dropbox. - * You must hold the {@link android.Manifest.permission#READ_LOGS} permission - * in order to receive this broadcast. - * - *

This is a protected intent that can only be sent - * by the system. - */ - public static final String ACTION_DROPBOX_ENTRY_ADDED = - "android.intent.action.DROPBOX_ENTRY_ADDED"; - - /** - * Extra for {@link android.os.DropBoxManager#ACTION_DROPBOX_ENTRY_ADDED}: - * string containing the dropbox tag. - */ - public static final String EXTRA_TAG = "tag"; - - /** - * Extra for {@link android.os.DropBoxManager#ACTION_DROPBOX_ENTRY_ADDED}: - * long integer value containing time (in milliseconds since January 1, 1970 00:00:00 UTC) - * when the entry was created. - */ - public static final String EXTRA_TIME = "time"; - - /** - * A single entry retrieved from the drop box. - * This may include a reference to a stream, so you must call - * {@link #close()} when you are done using it. - */ - public static class Entry implements Parcelable, Closeable { - private final String mTag; - private final long mTimeMillis; - - private final byte[] mData; - private final ParcelFileDescriptor mFileDescriptor; - private final int mFlags; - - /** Create a new empty Entry with no contents. */ - public Entry(String tag, long millis) { - if (tag == null) throw new NullPointerException("tag == null"); - - mTag = tag; - mTimeMillis = millis; - mData = null; - mFileDescriptor = null; - mFlags = IS_EMPTY; - } - - /** Create a new Entry with plain text contents. */ - public Entry(String tag, long millis, String text) { - if (tag == null) throw new NullPointerException("tag == null"); - if (text == null) throw new NullPointerException("text == null"); - - mTag = tag; - mTimeMillis = millis; - mData = text.getBytes(); - mFileDescriptor = null; - mFlags = IS_TEXT; - } - - /** - * Create a new Entry with byte array contents. - * The data array must not be modified after creating this entry. - */ - public Entry(String tag, long millis, byte[] data, int flags) { - if (tag == null) throw new NullPointerException("tag == null"); - if (((flags & IS_EMPTY) != 0) != (data == null)) { - throw new IllegalArgumentException("Bad flags: " + flags); - } - - mTag = tag; - mTimeMillis = millis; - mData = data; - mFileDescriptor = null; - mFlags = flags; - } - - /** - * Create a new Entry with streaming data contents. - * Takes ownership of the ParcelFileDescriptor. - */ - public Entry(String tag, long millis, ParcelFileDescriptor data, int flags) { - if (tag == null) throw new NullPointerException("tag == null"); - if (((flags & IS_EMPTY) != 0) != (data == null)) { - throw new IllegalArgumentException("Bad flags: " + flags); - } - - mTag = tag; - mTimeMillis = millis; - mData = null; - mFileDescriptor = data; - mFlags = flags; - } - - /** - * Create a new Entry with the contents read from a file. - * The file will be read when the entry's contents are requested. - */ - public Entry(String tag, long millis, File data, int flags) throws IOException { - if (tag == null) throw new NullPointerException("tag == null"); - if ((flags & IS_EMPTY) != 0) throw new IllegalArgumentException("Bad flags: " + flags); - - mTag = tag; - mTimeMillis = millis; - mData = null; - mFileDescriptor = ParcelFileDescriptor.open(data, ParcelFileDescriptor.MODE_READ_ONLY); - mFlags = flags; - } - - /** Close the input stream associated with this entry. */ - public void close() { - try { if (mFileDescriptor != null) mFileDescriptor.close(); } catch (IOException e) { } - } - - /** @return the tag originally attached to the entry. */ - public String getTag() { return mTag; } - - /** @return time when the entry was originally created. */ - public long getTimeMillis() { return mTimeMillis; } - - /** @return flags describing the content returned by {@link #getInputStream()}. */ - public int getFlags() { return mFlags & ~IS_GZIPPED; } // getInputStream() decompresses. - - /** - * @param maxBytes of string to return (will truncate at this length). - * @return the uncompressed text contents of the entry, null if the entry is not text. - */ - public String getText(int maxBytes) { - if ((mFlags & IS_TEXT) == 0) return null; - if (mData != null) return new String(mData, 0, Math.min(maxBytes, mData.length)); - - InputStream is = null; - try { - is = getInputStream(); - if (is == null) return null; - byte[] buf = new byte[maxBytes]; - int readBytes = 0; - int n = 0; - while (n >= 0 && (readBytes += n) < maxBytes) { - n = is.read(buf, readBytes, maxBytes - readBytes); - } - return new String(buf, 0, readBytes); - } catch (IOException e) { - return null; - } finally { - try { if (is != null) is.close(); } catch (IOException e) {} - } - } - - /** @return the uncompressed contents of the entry, or null if the contents were lost */ - public InputStream getInputStream() throws IOException { - InputStream is; - if (mData != null) { - is = new ByteArrayInputStream(mData); - } else if (mFileDescriptor != null) { - is = new ParcelFileDescriptor.AutoCloseInputStream(mFileDescriptor); - } else { - return null; - } - return (mFlags & IS_GZIPPED) != 0 ? new GZIPInputStream(is) : is; - } - - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public Entry[] newArray(int size) { return new Entry[size]; } - public Entry createFromParcel(Parcel in) { - String tag = in.readString(); - long millis = in.readLong(); - int flags = in.readInt(); - if ((flags & HAS_BYTE_ARRAY) != 0) { - return new Entry(tag, millis, in.createByteArray(), flags & ~HAS_BYTE_ARRAY); - } else { - return new Entry(tag, millis, in.readFileDescriptor(), flags); - } - } - }; - - public int describeContents() { - return mFileDescriptor != null ? Parcelable.CONTENTS_FILE_DESCRIPTOR : 0; - } - - public void writeToParcel(Parcel out, int flags) { - out.writeString(mTag); - out.writeLong(mTimeMillis); - if (mFileDescriptor != null) { - out.writeInt(mFlags & ~HAS_BYTE_ARRAY); // Clear bit just to be safe - mFileDescriptor.writeToParcel(out, flags); - } else { - out.writeInt(mFlags | HAS_BYTE_ARRAY); - out.writeByteArray(mData); - } - } - } - - /** {@hide} */ - public DropBoxManager(IDropBoxManagerService service) { mService = service; } - - /** - * Create a dummy instance for testing. All methods will fail unless - * overridden with an appropriate mock implementation. To obtain a - * functional instance, use {@link android.content.Context#getSystemService}. - */ - protected DropBoxManager() { mService = null; } - - /** - * Stores human-readable text. The data may be discarded eventually (or even - * immediately) if space is limited, or ignored entirely if the tag has been - * blocked (see {@link #isTagEnabled}). - * - * @param tag describing the type of entry being stored - * @param data value to store - */ - public void addText(String tag, String data) { - try { mService.add(new Entry(tag, 0, data)); } catch (RemoteException e) {} - } - - /** - * Stores binary data, which may be ignored or discarded as with {@link #addText}. - * - * @param tag describing the type of entry being stored - * @param data value to store - * @param flags describing the data - */ - public void addData(String tag, byte[] data, int flags) { - if (data == null) throw new NullPointerException("data == null"); - try { mService.add(new Entry(tag, 0, data, flags)); } catch (RemoteException e) {} - } - - /** - * Stores the contents of a file, which may be ignored or discarded as with - * {@link #addText}. - * - * @param tag describing the type of entry being stored - * @param file to read from - * @param flags describing the data - * @throws IOException if the file can't be opened - */ - public void addFile(String tag, File file, int flags) throws IOException { - if (file == null) throw new NullPointerException("file == null"); - Entry entry = new Entry(tag, 0, file, flags); - try { - mService.add(entry); - } catch (RemoteException e) { - // ignore - } finally { - entry.close(); - } - } - - /** - * Checks any blacklists (set in system settings) to see whether a certain - * tag is allowed. Entries with disabled tags will be dropped immediately, - * so you can save the work of actually constructing and sending the data. - * - * @param tag that would be used in {@link #addText} or {@link #addFile} - * @return whether events with that tag would be accepted - */ - public boolean isTagEnabled(String tag) { - try { return mService.isTagEnabled(tag); } catch (RemoteException e) { return false; } - } - - /** - * Gets the next entry from the drop box after the specified time. - * Requires android.permission.READ_LOGS. You must always call - * {@link Entry#close()} on the return value! - * - * @param tag of entry to look for, null for all tags - * @param msec time of the last entry seen - * @return the next entry, or null if there are no more entries - */ - public Entry getNextEntry(String tag, long msec) { - try { return mService.getNextEntry(tag, msec); } catch (RemoteException e) { return null; } - } - - // TODO: It may be useful to have some sort of notification mechanism - // when data is added to the dropbox, for demand-driven readers -- - // for now readers need to poll the dropbox to find new data. -} diff --git a/src/main/java/android/os/Environment.java b/src/main/java/android/os/Environment.java deleted file mode 100644 index 975bfc2..0000000 --- a/src/main/java/android/os/Environment.java +++ /dev/null @@ -1,916 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.app.admin.DevicePolicyManager; -import android.content.Context; -import android.os.storage.IMountService; -import android.os.storage.StorageVolume; -import android.text.TextUtils; -import android.util.Log; - -import com.google.android.collect.Lists; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; - -/** - * Provides access to environment variables. - */ -public class Environment { - private static final String TAG = "Environment"; - - private static final String ENV_EXTERNAL_STORAGE = "EXTERNAL_STORAGE"; - private static final String ENV_EMULATED_STORAGE_SOURCE = "EMULATED_STORAGE_SOURCE"; - private static final String ENV_EMULATED_STORAGE_TARGET = "EMULATED_STORAGE_TARGET"; - private static final String ENV_MEDIA_STORAGE = "MEDIA_STORAGE"; - private static final String ENV_SECONDARY_STORAGE = "SECONDARY_STORAGE"; - private static final String ENV_ANDROID_ROOT = "ANDROID_ROOT"; - private static final String ENV_OEM_ROOT = "OEM_ROOT"; - private static final String ENV_VENDOR_ROOT = "VENDOR_ROOT"; - - /** {@hide} */ - public static final String DIR_ANDROID = "Android"; - private static final String DIR_DATA = "data"; - private static final String DIR_MEDIA = "media"; - private static final String DIR_OBB = "obb"; - private static final String DIR_FILES = "files"; - private static final String DIR_CACHE = "cache"; - - /** {@hide} */ - @Deprecated - public static final String DIRECTORY_ANDROID = DIR_ANDROID; - - private static final File DIR_ANDROID_ROOT = getDirectory(ENV_ANDROID_ROOT, "/system"); - private static final File DIR_OEM_ROOT = getDirectory(ENV_OEM_ROOT, "/oem"); - private static final File DIR_VENDOR_ROOT = getDirectory(ENV_VENDOR_ROOT, "/vendor"); - private static final File DIR_MEDIA_STORAGE = getDirectory(ENV_MEDIA_STORAGE, "/data/media"); - - private static final String CANONCIAL_EMULATED_STORAGE_TARGET = getCanonicalPathOrNull( - ENV_EMULATED_STORAGE_TARGET); - - private static final String SYSTEM_PROPERTY_EFS_ENABLED = "persist.security.efs.enabled"; - - private static UserEnvironment sCurrentUser; - private static boolean sUserRequired; - - static { - initForCurrentUser(); - } - - /** {@hide} */ - public static void initForCurrentUser() { - final int userId = UserHandle.myUserId(); - sCurrentUser = new UserEnvironment(userId); - } - - /** {@hide} */ - public static class UserEnvironment { - // TODO: generalize further to create package-specific environment - - /** External storage dirs, as visible to vold */ - private final File[] mExternalDirsForVold; - /** External storage dirs, as visible to apps */ - private final File[] mExternalDirsForApp; - /** Primary emulated storage dir for direct access */ - private final File mEmulatedDirForDirect; - - public UserEnvironment(int userId) { - // See storage config details at http://source.android.com/tech/storage/ - String rawExternalStorage = System.getenv(ENV_EXTERNAL_STORAGE); - String rawEmulatedSource = System.getenv(ENV_EMULATED_STORAGE_SOURCE); - String rawEmulatedTarget = System.getenv(ENV_EMULATED_STORAGE_TARGET); - - String rawMediaStorage = System.getenv(ENV_MEDIA_STORAGE); - if (TextUtils.isEmpty(rawMediaStorage)) { - rawMediaStorage = "/data/media"; - } - - ArrayList externalForVold = Lists.newArrayList(); - ArrayList externalForApp = Lists.newArrayList(); - - if (!TextUtils.isEmpty(rawEmulatedTarget)) { - // Device has emulated storage; external storage paths should have - // userId burned into them. - final String rawUserId = Integer.toString(userId); - final File emulatedSourceBase = new File(rawEmulatedSource); - final File emulatedTargetBase = new File(rawEmulatedTarget); - final File mediaBase = new File(rawMediaStorage); - - // /storage/emulated/0 - externalForVold.add(buildPath(emulatedSourceBase, rawUserId)); - externalForApp.add(buildPath(emulatedTargetBase, rawUserId)); - // /data/media/0 - mEmulatedDirForDirect = buildPath(mediaBase, rawUserId); - - } else { - // Device has physical external storage; use plain paths. - if (TextUtils.isEmpty(rawExternalStorage)) { - Log.w(TAG, "EXTERNAL_STORAGE undefined; falling back to default"); - rawExternalStorage = "/storage/sdcard0"; - } - - // /storage/sdcard0 - externalForVold.add(new File(rawExternalStorage)); - externalForApp.add(new File(rawExternalStorage)); - // /data/media - mEmulatedDirForDirect = new File(rawMediaStorage); - } - - // Splice in any secondary storage paths, but only for owner - final String rawSecondaryStorage = System.getenv(ENV_SECONDARY_STORAGE); - if (!TextUtils.isEmpty(rawSecondaryStorage) && userId == UserHandle.USER_OWNER) { - for (String secondaryPath : rawSecondaryStorage.split(":")) { - externalForVold.add(new File(secondaryPath)); - externalForApp.add(new File(secondaryPath)); - } - } - - mExternalDirsForVold = externalForVold.toArray(new File[externalForVold.size()]); - mExternalDirsForApp = externalForApp.toArray(new File[externalForApp.size()]); - } - - @Deprecated - public File getExternalStorageDirectory() { - return mExternalDirsForApp[0]; - } - - @Deprecated - public File getExternalStoragePublicDirectory(String type) { - return buildExternalStoragePublicDirs(type)[0]; - } - - public File[] getExternalDirsForVold() { - return mExternalDirsForVold; - } - - public File[] getExternalDirsForApp() { - return mExternalDirsForApp; - } - - public File getMediaDir() { - return mEmulatedDirForDirect; - } - - public File[] buildExternalStoragePublicDirs(String type) { - return buildPaths(mExternalDirsForApp, type); - } - - public File[] buildExternalStorageAndroidDataDirs() { - return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_DATA); - } - - public File[] buildExternalStorageAndroidObbDirs() { - return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_OBB); - } - - public File[] buildExternalStorageAppDataDirs(String packageName) { - return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_DATA, packageName); - } - - public File[] buildExternalStorageAppDataDirsForVold(String packageName) { - return buildPaths(mExternalDirsForVold, DIR_ANDROID, DIR_DATA, packageName); - } - - public File[] buildExternalStorageAppMediaDirs(String packageName) { - return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_MEDIA, packageName); - } - - public File[] buildExternalStorageAppMediaDirsForVold(String packageName) { - return buildPaths(mExternalDirsForVold, DIR_ANDROID, DIR_MEDIA, packageName); - } - - public File[] buildExternalStorageAppObbDirs(String packageName) { - return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_OBB, packageName); - } - - public File[] buildExternalStorageAppObbDirsForVold(String packageName) { - return buildPaths(mExternalDirsForVold, DIR_ANDROID, DIR_OBB, packageName); - } - - public File[] buildExternalStorageAppFilesDirs(String packageName) { - return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_DATA, packageName, DIR_FILES); - } - - public File[] buildExternalStorageAppCacheDirs(String packageName) { - return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_DATA, packageName, DIR_CACHE); - } - } - - /** - * Return root of the "system" partition holding the core Android OS. - * Always present and mounted read-only. - */ - public static File getRootDirectory() { - return DIR_ANDROID_ROOT; - } - - /** - * Return root directory of the "oem" partition holding OEM customizations, - * if any. If present, the partition is mounted read-only. - * - * @hide - */ - public static File getOemDirectory() { - return DIR_OEM_ROOT; - } - - /** - * Return root directory of the "vendor" partition that holds vendor-provided - * software that should persist across simple reflashing of the "system" partition. - * @hide - */ - public static File getVendorDirectory() { - return DIR_VENDOR_ROOT; - } - - /** - * Gets the system directory available for secure storage. - * If Encrypted File system is enabled, it returns an encrypted directory (/data/secure/system). - * Otherwise, it returns the unencrypted /data/system directory. - * @return File object representing the secure storage system directory. - * @hide - */ - public static File getSystemSecureDirectory() { - if (isEncryptedFilesystemEnabled()) { - return new File(SECURE_DATA_DIRECTORY, "system"); - } else { - return new File(DATA_DIRECTORY, "system"); - } - } - - /** - * Gets the data directory for secure storage. - * If Encrypted File system is enabled, it returns an encrypted directory (/data/secure). - * Otherwise, it returns the unencrypted /data directory. - * @return File object representing the data directory for secure storage. - * @hide - */ - public static File getSecureDataDirectory() { - if (isEncryptedFilesystemEnabled()) { - return SECURE_DATA_DIRECTORY; - } else { - return DATA_DIRECTORY; - } - } - - /** - * Return directory used for internal media storage, which is protected by - * {@link android.Manifest.permission#WRITE_MEDIA_STORAGE}. - * - * @hide - */ - public static File getMediaStorageDirectory() { - throwIfUserRequired(); - return sCurrentUser.getMediaDir(); - } - - /** - * Return the system directory for a user. This is for use by system services to store - * files relating to the user. This directory will be automatically deleted when the user - * is removed. - * - * @hide - */ - public static File getUserSystemDirectory(int userId) { - return new File(new File(getSystemSecureDirectory(), "users"), Integer.toString(userId)); - } - - /** - * Returns the config directory for a user. This is for use by system services to store files - * relating to the user which should be readable by any app running as that user. - * - * @hide - */ - public static File getUserConfigDirectory(int userId) { - return new File(new File(new File( - getDataDirectory(), "misc"), "user"), Integer.toString(userId)); - } - - /** - * Returns whether the Encrypted File System feature is enabled on the device or not. - * @return true if Encrypted File System feature is enabled, false - * if disabled. - * @hide - */ - public static boolean isEncryptedFilesystemEnabled() { - return SystemProperties.getBoolean(SYSTEM_PROPERTY_EFS_ENABLED, false); - } - - private static final File DATA_DIRECTORY - = getDirectory("ANDROID_DATA", "/data"); - - /** - * @hide - */ - private static final File SECURE_DATA_DIRECTORY - = getDirectory("ANDROID_SECURE_DATA", "/data/secure"); - - private static final File DOWNLOAD_CACHE_DIRECTORY = getDirectory("DOWNLOAD_CACHE", "/cache"); - - /** - * Return the user data directory. - */ - public static File getDataDirectory() { - return DATA_DIRECTORY; - } - - /** - * Return the primary external storage directory. This directory may not - * currently be accessible if it has been mounted by the user on their - * computer, has been removed from the device, or some other problem has - * happened. You can determine its current state with - * {@link #getExternalStorageState()}. - *

- * Note: don't be confused by the word "external" here. This directory - * can better be thought as media/shared storage. It is a filesystem that - * can hold a relatively large amount of data and that is shared across all - * applications (does not enforce permissions). Traditionally this is an SD - * card, but it may also be implemented as built-in storage in a device that - * is distinct from the protected internal storage and can be mounted as a - * filesystem on a computer. - *

- * On devices with multiple users (as described by {@link UserManager}), - * each user has their own isolated external storage. Applications only have - * access to the external storage for the user they're running as. - *

- * In devices with multiple "external" storage directories, this directory - * represents the "primary" external storage that the user will interact - * with. Access to secondary storage is available through - *

- * Applications should not directly use this top-level directory, in order - * to avoid polluting the user's root namespace. Any files that are private - * to the application should be placed in a directory returned by - * {@link android.content.Context#getExternalFilesDir - * Context.getExternalFilesDir}, which the system will take care of deleting - * if the application is uninstalled. Other shared files should be placed in - * one of the directories returned by - * {@link #getExternalStoragePublicDirectory}. - *

- * Writing to this path requires the - * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission, - * and starting in read access requires the - * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission, - * which is automatically granted if you hold the write permission. - *

- * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, if your - * application only needs to store internal data, consider using - * {@link Context#getExternalFilesDir(String)} or - * {@link Context#getExternalCacheDir()}, which require no permissions to - * read or write. - *

- * This path may change between platform versions, so applications should - * only persist relative paths. - *

- * Here is an example of typical code to monitor the state of external - * storage: - *

- * {@sample - * development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java - * monitor_storage} - * - * @see #getExternalStorageState() - * @see #isExternalStorageRemovable() - */ - public static File getExternalStorageDirectory() { - throwIfUserRequired(); - return sCurrentUser.getExternalDirsForApp()[0]; - } - - /** {@hide} */ - public static File getLegacyExternalStorageDirectory() { - return new File(System.getenv(ENV_EXTERNAL_STORAGE)); - } - - /** {@hide} */ - public static File getLegacyExternalStorageObbDirectory() { - return buildPath(getLegacyExternalStorageDirectory(), DIR_ANDROID, DIR_OBB); - } - - /** {@hide} */ - public static File getEmulatedStorageSource(int userId) { - // /mnt/shell/emulated/0 - return new File(System.getenv(ENV_EMULATED_STORAGE_SOURCE), String.valueOf(userId)); - } - - /** {@hide} */ - public static File getEmulatedStorageObbSource() { - // /mnt/shell/emulated/obb - return new File(System.getenv(ENV_EMULATED_STORAGE_SOURCE), DIR_OBB); - } - - /** - * Standard directory in which to place any audio files that should be - * in the regular list of music for the user. - * This may be combined with - * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS}, - * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series - * of directories to categories a particular audio file as more than one - * type. - */ - public static String DIRECTORY_MUSIC = "Music"; - - /** - * Standard directory in which to place any audio files that should be - * in the list of podcasts that the user can select (not as regular - * music). - * This may be combined with {@link #DIRECTORY_MUSIC}, - * {@link #DIRECTORY_NOTIFICATIONS}, - * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series - * of directories to categories a particular audio file as more than one - * type. - */ - public static String DIRECTORY_PODCASTS = "Podcasts"; - - /** - * Standard directory in which to place any audio files that should be - * in the list of ringtones that the user can select (not as regular - * music). - * This may be combined with {@link #DIRECTORY_MUSIC}, - * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS}, and - * {@link #DIRECTORY_ALARMS} as a series - * of directories to categories a particular audio file as more than one - * type. - */ - public static String DIRECTORY_RINGTONES = "Ringtones"; - - /** - * Standard directory in which to place any audio files that should be - * in the list of alarms that the user can select (not as regular - * music). - * This may be combined with {@link #DIRECTORY_MUSIC}, - * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS}, - * and {@link #DIRECTORY_RINGTONES} as a series - * of directories to categories a particular audio file as more than one - * type. - */ - public static String DIRECTORY_ALARMS = "Alarms"; - - /** - * Standard directory in which to place any audio files that should be - * in the list of notifications that the user can select (not as regular - * music). - * This may be combined with {@link #DIRECTORY_MUSIC}, - * {@link #DIRECTORY_PODCASTS}, - * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series - * of directories to categories a particular audio file as more than one - * type. - */ - public static String DIRECTORY_NOTIFICATIONS = "Notifications"; - - /** - * Standard directory in which to place pictures that are available to - * the user. Note that this is primarily a convention for the top-level - * public directory, as the media scanner will find and collect pictures - * in any directory. - */ - public static String DIRECTORY_PICTURES = "Pictures"; - - /** - * Standard directory in which to place movies that are available to - * the user. Note that this is primarily a convention for the top-level - * public directory, as the media scanner will find and collect movies - * in any directory. - */ - public static String DIRECTORY_MOVIES = "Movies"; - - /** - * Standard directory in which to place files that have been downloaded by - * the user. Note that this is primarily a convention for the top-level - * public directory, you are free to download files anywhere in your own - * private directories. Also note that though the constant here is - * named DIRECTORY_DOWNLOADS (plural), the actual file name is non-plural for - * backwards compatibility reasons. - */ - public static String DIRECTORY_DOWNLOADS = "Download"; - - /** - * The traditional location for pictures and videos when mounting the - * device as a camera. Note that this is primarily a convention for the - * top-level public directory, as this convention makes no sense elsewhere. - */ - public static String DIRECTORY_DCIM = "DCIM"; - - /** - * Standard directory in which to place documents that have been created by - * the user. - */ - public static String DIRECTORY_DOCUMENTS = "Documents"; - - /** - * Get a top-level public external storage directory for placing files of - * a particular type. This is where the user will typically place and - * manage their own files, so you should be careful about what you put here - * to ensure you don't erase their files or get in the way of their own - * organization. - * - *

On devices with multiple users (as described by {@link UserManager}), - * each user has their own isolated external storage. Applications only - * have access to the external storage for the user they're running as.

- * - *

Here is an example of typical code to manipulate a picture on - * the public external storage:

- * - * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java - * public_picture} - * - * @param type The type of storage directory to return. Should be one of - * {@link #DIRECTORY_MUSIC}, {@link #DIRECTORY_PODCASTS}, - * {@link #DIRECTORY_RINGTONES}, {@link #DIRECTORY_ALARMS}, - * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_PICTURES}, - * {@link #DIRECTORY_MOVIES}, {@link #DIRECTORY_DOWNLOADS}, or - * {@link #DIRECTORY_DCIM}. May not be null. - * - * @return Returns the File path for the directory. Note that this - * directory may not yet exist, so you must make sure it exists before - * using it such as with {@link File#mkdirs File.mkdirs()}. - */ - public static File getExternalStoragePublicDirectory(String type) { - throwIfUserRequired(); - return sCurrentUser.buildExternalStoragePublicDirs(type)[0]; - } - - /** - * Returns the path for android-specific data on the SD card. - * @hide - */ - public static File[] buildExternalStorageAndroidDataDirs() { - throwIfUserRequired(); - return sCurrentUser.buildExternalStorageAndroidDataDirs(); - } - - /** - * Generates the raw path to an application's data - * @hide - */ - public static File[] buildExternalStorageAppDataDirs(String packageName) { - throwIfUserRequired(); - return sCurrentUser.buildExternalStorageAppDataDirs(packageName); - } - - /** - * Generates the raw path to an application's media - * @hide - */ - public static File[] buildExternalStorageAppMediaDirs(String packageName) { - throwIfUserRequired(); - return sCurrentUser.buildExternalStorageAppMediaDirs(packageName); - } - - /** - * Generates the raw path to an application's OBB files - * @hide - */ - public static File[] buildExternalStorageAppObbDirs(String packageName) { - throwIfUserRequired(); - return sCurrentUser.buildExternalStorageAppObbDirs(packageName); - } - - /** - * Generates the path to an application's files. - * @hide - */ - public static File[] buildExternalStorageAppFilesDirs(String packageName) { - throwIfUserRequired(); - return sCurrentUser.buildExternalStorageAppFilesDirs(packageName); - } - - /** - * Generates the path to an application's cache. - * @hide - */ - public static File[] buildExternalStorageAppCacheDirs(String packageName) { - throwIfUserRequired(); - return sCurrentUser.buildExternalStorageAppCacheDirs(packageName); - } - - /** - * Return the download/cache content directory. - */ - public static File getDownloadCacheDirectory() { - return DOWNLOAD_CACHE_DIRECTORY; - } - - /** - * Unknown storage state, such as when a path isn't backed by known storage - * media. - * - * @see #getExternalStorageState(File) - */ - public static final String MEDIA_UNKNOWN = "unknown"; - - /** - * Storage state if the media is not present. - * - * @see #getExternalStorageState(File) - */ - public static final String MEDIA_REMOVED = "removed"; - - /** - * Storage state if the media is present but not mounted. - * - * @see #getExternalStorageState(File) - */ - public static final String MEDIA_UNMOUNTED = "unmounted"; - - /** - * Storage state if the media is present and being disk-checked. - * - * @see #getExternalStorageState(File) - */ - public static final String MEDIA_CHECKING = "checking"; - - /** - * Storage state if the media is present but is blank or is using an - * unsupported filesystem. - * - * @see #getExternalStorageState(File) - */ - public static final String MEDIA_NOFS = "nofs"; - - /** - * Storage state if the media is present and mounted at its mount point with - * read/write access. - * - * @see #getExternalStorageState(File) - */ - public static final String MEDIA_MOUNTED = "mounted"; - - /** - * Storage state if the media is present and mounted at its mount point with - * read-only access. - * - * @see #getExternalStorageState(File) - */ - public static final String MEDIA_MOUNTED_READ_ONLY = "mounted_ro"; - - /** - * Storage state if the media is present not mounted, and shared via USB - * mass storage. - * - * @see #getExternalStorageState(File) - */ - public static final String MEDIA_SHARED = "shared"; - - /** - * Storage state if the media was removed before it was unmounted. - * - * @see #getExternalStorageState(File) - */ - public static final String MEDIA_BAD_REMOVAL = "bad_removal"; - - /** - * Storage state if the media is present but cannot be mounted. Typically - * this happens if the file system on the media is corrupted. - * - * @see #getExternalStorageState(File) - */ - public static final String MEDIA_UNMOUNTABLE = "unmountable"; - - /** - * Returns the current state of the primary "external" storage device. - * - * @see #getExternalStorageDirectory() - * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED}, - * {@link #MEDIA_UNMOUNTED}, {@link #MEDIA_CHECKING}, - * {@link #MEDIA_NOFS}, {@link #MEDIA_MOUNTED}, - * {@link #MEDIA_MOUNTED_READ_ONLY}, {@link #MEDIA_SHARED}, - * {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}. - */ - public static String getExternalStorageState() { - final File externalDir = sCurrentUser.getExternalDirsForApp()[0]; - return getExternalStorageState(externalDir); - } - - /** - * @deprecated use {@link #getExternalStorageState(File)} - */ - @Deprecated - public static String getStorageState(File path) { - return getExternalStorageState(path); - } - - /** - * Returns the current state of the storage device that provides the given - * path. - * - * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED}, - * {@link #MEDIA_UNMOUNTED}, {@link #MEDIA_CHECKING}, - * {@link #MEDIA_NOFS}, {@link #MEDIA_MOUNTED}, - * {@link #MEDIA_MOUNTED_READ_ONLY}, {@link #MEDIA_SHARED}, - * {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}. - */ - public static String getExternalStorageState(File path) { - final StorageVolume volume = getStorageVolume(path); - if (volume != null) { - final IMountService mountService = IMountService.Stub.asInterface( - ServiceManager.getService("mount")); - try { - return mountService.getVolumeState(volume.getPath()); - } catch (RemoteException e) { - } - } - - return Environment.MEDIA_UNKNOWN; - } - - /** - * Returns whether the primary "external" storage device is removable. - * - * @return true if the storage device can be removed (such as an SD card), - * or false if the storage device is built in and cannot be - * physically removed. - */ - public static boolean isExternalStorageRemovable() { - if (isStorageDisabled()) return false; - final File externalDir = sCurrentUser.getExternalDirsForApp()[0]; - return isExternalStorageRemovable(externalDir); - } - - /** - * Returns whether the storage device that provides the given path is - * removable. - * - * @return true if the storage device can be removed (such as an SD card), - * or false if the storage device is built in and cannot be - * physically removed. - * @throws IllegalArgumentException if the path is not a valid storage - * device. - */ - public static boolean isExternalStorageRemovable(File path) { - final StorageVolume volume = getStorageVolume(path); - if (volume != null) { - return volume.isRemovable(); - } else { - throw new IllegalArgumentException("Failed to find storage device at " + path); - } - } - - /** - * Returns whether the primary "external" storage device is emulated. If - * true, data stored on this device will be stored on a portion of the - * internal storage system. - * - * @see DevicePolicyManager#setStorageEncryption(android.content.ComponentName, - * boolean) - */ - public static boolean isExternalStorageEmulated() { - if (isStorageDisabled()) return false; - final File externalDir = sCurrentUser.getExternalDirsForApp()[0]; - return isExternalStorageEmulated(externalDir); - } - - /** - * Returns whether the storage device that provides the given path is - * emulated. If true, data stored on this device will be stored on a portion - * of the internal storage system. - * - * @throws IllegalArgumentException if the path is not a valid storage - * device. - */ - public static boolean isExternalStorageEmulated(File path) { - final StorageVolume volume = getStorageVolume(path); - if (volume != null) { - return volume.isEmulated(); - } else { - throw new IllegalArgumentException("Failed to find storage device at " + path); - } - } - - static File getDirectory(String variableName, String defaultPath) { - String path = System.getenv(variableName); - return path == null ? new File(defaultPath) : new File(path); - } - - private static String getCanonicalPathOrNull(String variableName) { - String path = System.getenv(variableName); - if (path == null) { - return null; - } - try { - return new File(path).getCanonicalPath(); - } catch (IOException e) { - Log.w(TAG, "Unable to resolve canonical path for " + path); - return null; - } - } - - /** {@hide} */ - public static void setUserRequired(boolean userRequired) { - sUserRequired = userRequired; - } - - private static void throwIfUserRequired() { - if (sUserRequired) { - Log.wtf(TAG, "Path requests must specify a user by using UserEnvironment", - new Throwable()); - } - } - - /** - * Append path segments to each given base path, returning result. - * - * @hide - */ - public static File[] buildPaths(File[] base, String... segments) { - File[] result = new File[base.length]; - for (int i = 0; i < base.length; i++) { - result[i] = buildPath(base[i], segments); - } - return result; - } - - /** - * Append path segments to given base path, returning result. - * - * @hide - */ - public static File buildPath(File base, String... segments) { - File cur = base; - for (String segment : segments) { - if (cur == null) { - cur = new File(segment); - } else { - cur = new File(cur, segment); - } - } - return cur; - } - - private static boolean isStorageDisabled() { - return SystemProperties.getBoolean("config.disable_storage", false); - } - - private static StorageVolume getStorageVolume(File path) { - try { - path = path.getCanonicalFile(); - } catch (IOException e) { - return null; - } - - try { - final IMountService mountService = IMountService.Stub.asInterface( - ServiceManager.getService("mount")); - final StorageVolume[] volumes = mountService.getVolumeList(); - for (StorageVolume volume : volumes) { - if (FileUtils.contains(volume.getPathFile(), path)) { - return volume; - } - } - } catch (RemoteException e) { - } - - return null; - } - - /** - * If the given path exists on emulated external storage, return the - * translated backing path hosted on internal storage. This bypasses any - * emulation later, improving performance. This is only suitable - * for read-only access. - *

- * Returns original path if given path doesn't meet these criteria. Callers - * must hold {@link android.Manifest.permission#WRITE_MEDIA_STORAGE} - * permission. - * - * @hide - */ - public static File maybeTranslateEmulatedPathToInternal(File path) { - // Fast return if not emulated, or missing variables - if (!Environment.isExternalStorageEmulated() - || CANONCIAL_EMULATED_STORAGE_TARGET == null) { - return path; - } - - try { - final String rawPath = path.getCanonicalPath(); - if (rawPath.startsWith(CANONCIAL_EMULATED_STORAGE_TARGET)) { - final File internalPath = new File(DIR_MEDIA_STORAGE, - rawPath.substring(CANONCIAL_EMULATED_STORAGE_TARGET.length())); - if (internalPath.exists()) { - return internalPath; - } - } - } catch (IOException e) { - Log.w(TAG, "Failed to resolve canonical path for " + path); - } - - // Unable to translate to internal path; use original - return path; - } -} diff --git a/src/main/java/android/os/FactoryTest.java b/src/main/java/android/os/FactoryTest.java deleted file mode 100644 index 7a252f9..0000000 --- a/src/main/java/android/os/FactoryTest.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -/** - * Provides support for in-place factory test functions. - * - * This class provides a few properties that alter the normal operation of the system - * during factory testing. - * - * {@hide} - */ -public final class FactoryTest { - public static final int FACTORY_TEST_OFF = 0; - public static final int FACTORY_TEST_LOW_LEVEL = 1; - public static final int FACTORY_TEST_HIGH_LEVEL = 2; - - /** - * Gets the current factory test mode. - * - * @return One of: {@link #FACTORY_TEST_OFF}, {@link #FACTORY_TEST_LOW_LEVEL}, - * or {@link #FACTORY_TEST_HIGH_LEVEL}. - */ - public static int getMode() { - return SystemProperties.getInt("ro.factorytest", FACTORY_TEST_OFF); - } - - /** - * When true, long-press on power should immediately cause the device to - * shut down, without prompting the user. - */ - public static boolean isLongPressOnPowerOffEnabled() { - return SystemProperties.getInt("factory.long_press_power_off", 0) != 0; - } -} diff --git a/src/main/java/android/os/FileBridge.java b/src/main/java/android/os/FileBridge.java deleted file mode 100644 index 0acf24b..0000000 --- a/src/main/java/android/os/FileBridge.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import static android.system.OsConstants.AF_UNIX; -import static android.system.OsConstants.SOCK_STREAM; - -import android.system.ErrnoException; -import android.system.Os; -import android.util.Log; - -import libcore.io.IoBridge; -import libcore.io.IoUtils; -import libcore.io.Memory; -import libcore.io.Streams; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.OutputStream; -import java.nio.ByteOrder; -import java.util.Arrays; - -/** - * Simple bridge that allows file access across process boundaries without - * returning the underlying {@link FileDescriptor}. This is useful when the - * server side needs to strongly assert that a client side is completely - * hands-off. - * - * @hide - */ -public class FileBridge extends Thread { - private static final String TAG = "FileBridge"; - - // TODO: consider extending to support bidirectional IO - - private static final int MSG_LENGTH = 8; - - /** CMD_WRITE [len] [data] */ - private static final int CMD_WRITE = 1; - /** CMD_FSYNC */ - private static final int CMD_FSYNC = 2; - /** CMD_CLOSE */ - private static final int CMD_CLOSE = 3; - - private FileDescriptor mTarget; - - private final FileDescriptor mServer = new FileDescriptor(); - private final FileDescriptor mClient = new FileDescriptor(); - - private volatile boolean mClosed; - - public FileBridge() { - try { - Os.socketpair(AF_UNIX, SOCK_STREAM, 0, mServer, mClient); - } catch (ErrnoException e) { - throw new RuntimeException("Failed to create bridge"); - } - } - - public boolean isClosed() { - return mClosed; - } - - public void forceClose() { - IoUtils.closeQuietly(mTarget); - IoUtils.closeQuietly(mServer); - IoUtils.closeQuietly(mClient); - mClosed = true; - } - - public void setTargetFile(FileDescriptor target) { - mTarget = target; - } - - public FileDescriptor getClientSocket() { - return mClient; - } - - @Override - public void run() { - final byte[] temp = new byte[8192]; - try { - while (IoBridge.read(mServer, temp, 0, MSG_LENGTH) == MSG_LENGTH) { - final int cmd = Memory.peekInt(temp, 0, ByteOrder.BIG_ENDIAN); - if (cmd == CMD_WRITE) { - // Shuttle data into local file - int len = Memory.peekInt(temp, 4, ByteOrder.BIG_ENDIAN); - while (len > 0) { - int n = IoBridge.read(mServer, temp, 0, Math.min(temp.length, len)); - if (n == -1) { - throw new IOException( - "Unexpected EOF; still expected " + len + " bytes"); - } - IoBridge.write(mTarget, temp, 0, n); - len -= n; - } - - } else if (cmd == CMD_FSYNC) { - // Sync and echo back to confirm - Os.fsync(mTarget); - IoBridge.write(mServer, temp, 0, MSG_LENGTH); - - } else if (cmd == CMD_CLOSE) { - // Close and echo back to confirm - Os.fsync(mTarget); - Os.close(mTarget); - mClosed = true; - IoBridge.write(mServer, temp, 0, MSG_LENGTH); - break; - } - } - - } catch (ErrnoException | IOException e) { - Log.wtf(TAG, "Failed during bridge", e); - } finally { - forceClose(); - } - } - - public static class FileBridgeOutputStream extends OutputStream { - private final ParcelFileDescriptor mClientPfd; - private final FileDescriptor mClient; - private final byte[] mTemp = new byte[MSG_LENGTH]; - - public FileBridgeOutputStream(ParcelFileDescriptor clientPfd) { - mClientPfd = clientPfd; - mClient = clientPfd.getFileDescriptor(); - } - - public FileBridgeOutputStream(FileDescriptor client) { - mClientPfd = null; - mClient = client; - } - - @Override - public void close() throws IOException { - try { - writeCommandAndBlock(CMD_CLOSE, "close()"); - } finally { - IoBridge.closeAndSignalBlockedThreads(mClient); - IoUtils.closeQuietly(mClientPfd); - } - } - - public void fsync() throws IOException { - writeCommandAndBlock(CMD_FSYNC, "fsync()"); - } - - private void writeCommandAndBlock(int cmd, String cmdString) throws IOException { - Memory.pokeInt(mTemp, 0, cmd, ByteOrder.BIG_ENDIAN); - IoBridge.write(mClient, mTemp, 0, MSG_LENGTH); - - // Wait for server to ack - if (IoBridge.read(mClient, mTemp, 0, MSG_LENGTH) == MSG_LENGTH) { - if (Memory.peekInt(mTemp, 0, ByteOrder.BIG_ENDIAN) == cmd) { - return; - } - } - - throw new IOException("Failed to execute " + cmdString + " across bridge"); - } - - @Override - public void write(byte[] buffer, int byteOffset, int byteCount) throws IOException { - Arrays.checkOffsetAndCount(buffer.length, byteOffset, byteCount); - Memory.pokeInt(mTemp, 0, CMD_WRITE, ByteOrder.BIG_ENDIAN); - Memory.pokeInt(mTemp, 4, byteCount, ByteOrder.BIG_ENDIAN); - IoBridge.write(mClient, mTemp, 0, MSG_LENGTH); - IoBridge.write(mClient, buffer, byteOffset, byteCount); - } - - @Override - public void write(int oneByte) throws IOException { - Streams.writeSingleByte(this, oneByte); - } - } -} diff --git a/src/main/java/android/os/FileBridgeTest.java b/src/main/java/android/os/FileBridgeTest.java deleted file mode 100644 index d4f6b1f..0000000 --- a/src/main/java/android/os/FileBridgeTest.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.os.FileBridge.FileBridgeOutputStream; -import android.test.AndroidTestCase; -import android.test.MoreAsserts; - -import libcore.io.Streams; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.Random; - -public class FileBridgeTest extends AndroidTestCase { - - private File file; - private FileOutputStream fileOs; - private FileBridge bridge; - private FileBridgeOutputStream client; - - @Override - protected void setUp() throws Exception { - super.setUp(); - - file = getContext().getFileStreamPath("meow.dat"); - file.delete(); - - fileOs = new FileOutputStream(file); - - bridge = new FileBridge(); - bridge.setTargetFile(fileOs.getFD()); - bridge.start(); - client = new FileBridgeOutputStream(bridge.getClientSocket()); - } - - @Override - protected void tearDown() throws Exception { - fileOs.close(); - file.delete(); - } - - private void assertOpen() throws Exception { - assertFalse("expected open", bridge.isClosed()); - } - - private void closeAndAssertClosed() throws Exception { - client.close(); - - // Wait a beat for things to settle down - SystemClock.sleep(200); - assertTrue("expected closed", bridge.isClosed()); - } - - private void assertContents(byte[] expected) throws Exception { - MoreAsserts.assertEquals(expected, Streams.readFully(new FileInputStream(file))); - } - - public void testNoWriteNoSync() throws Exception { - assertOpen(); - closeAndAssertClosed(); - } - - public void testNoWriteSync() throws Exception { - assertOpen(); - client.flush(); - closeAndAssertClosed(); - } - - public void testWriteNoSync() throws Exception { - assertOpen(); - client.write("meow".getBytes(StandardCharsets.UTF_8)); - closeAndAssertClosed(); - assertContents("meow".getBytes(StandardCharsets.UTF_8)); - } - - public void testWriteSync() throws Exception { - assertOpen(); - client.write("cake".getBytes(StandardCharsets.UTF_8)); - client.flush(); - closeAndAssertClosed(); - assertContents("cake".getBytes(StandardCharsets.UTF_8)); - } - - public void testWriteSyncWrite() throws Exception { - assertOpen(); - client.write("meow".getBytes(StandardCharsets.UTF_8)); - client.flush(); - client.write("cake".getBytes(StandardCharsets.UTF_8)); - closeAndAssertClosed(); - assertContents("meowcake".getBytes(StandardCharsets.UTF_8)); - } - - public void testEmptyWrite() throws Exception { - assertOpen(); - client.write(new byte[0]); - closeAndAssertClosed(); - assertContents(new byte[0]); - } - - public void testWriteAfterClose() throws Exception { - assertOpen(); - client.write("meow".getBytes(StandardCharsets.UTF_8)); - closeAndAssertClosed(); - try { - client.write("cake".getBytes(StandardCharsets.UTF_8)); - fail("wrote after close!"); - } catch (IOException expected) { - } - assertContents("meow".getBytes(StandardCharsets.UTF_8)); - } - - public void testRandomWrite() throws Exception { - final Random r = new Random(); - final ByteArrayOutputStream result = new ByteArrayOutputStream(); - - for (int i = 0; i < 512; i++) { - final byte[] test = new byte[r.nextInt(24169)]; - r.nextBytes(test); - result.write(test); - client.write(test); - client.flush(); - } - - closeAndAssertClosed(); - assertContents(result.toByteArray()); - } - - public void testGiantWrite() throws Exception { - final byte[] test = new byte[263401]; - new Random().nextBytes(test); - - assertOpen(); - client.write(test); - closeAndAssertClosed(); - assertContents(test); - } -} diff --git a/src/main/java/android/os/FileObserver.java b/src/main/java/android/os/FileObserver.java deleted file mode 100644 index 4e705e0..0000000 --- a/src/main/java/android/os/FileObserver.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.util.Log; - -import java.lang.ref.WeakReference; -import java.util.HashMap; - -/** - * Monitors files (using inotify) - * to fire an event after files are accessed or changed by by any process on - * the device (including this one). FileObserver is an abstract class; - * subclasses must implement the event handler {@link #onEvent(int, String)}. - * - *

Each FileObserver instance monitors a single file or directory. - * If a directory is monitored, events will be triggered for all files and - * subdirectories inside the monitored directory.

- * - *

An event mask is used to specify which changes or actions to report. - * Event type constants are used to describe the possible changes in the - * event mask as well as what actually happened in event callbacks.

- * - *

Warning: If a FileObserver is garbage collected, it - * will stop sending events. To ensure you keep receiving events, you must - * keep a reference to the FileObserver instance from some other live object.

- */ -public abstract class FileObserver { - /** Event type: Data was read from a file */ - public static final int ACCESS = 0x00000001; - /** Event type: Data was written to a file */ - public static final int MODIFY = 0x00000002; - /** Event type: Metadata (permissions, owner, timestamp) was changed explicitly */ - public static final int ATTRIB = 0x00000004; - /** Event type: Someone had a file or directory open for writing, and closed it */ - public static final int CLOSE_WRITE = 0x00000008; - /** Event type: Someone had a file or directory open read-only, and closed it */ - public static final int CLOSE_NOWRITE = 0x00000010; - /** Event type: A file or directory was opened */ - public static final int OPEN = 0x00000020; - /** Event type: A file or subdirectory was moved from the monitored directory */ - public static final int MOVED_FROM = 0x00000040; - /** Event type: A file or subdirectory was moved to the monitored directory */ - public static final int MOVED_TO = 0x00000080; - /** Event type: A new file or subdirectory was created under the monitored directory */ - public static final int CREATE = 0x00000100; - /** Event type: A file was deleted from the monitored directory */ - public static final int DELETE = 0x00000200; - /** Event type: The monitored file or directory was deleted; monitoring effectively stops */ - public static final int DELETE_SELF = 0x00000400; - /** Event type: The monitored file or directory was moved; monitoring continues */ - public static final int MOVE_SELF = 0x00000800; - - /** Event mask: All valid event types, combined */ - public static final int ALL_EVENTS = ACCESS | MODIFY | ATTRIB | CLOSE_WRITE - | CLOSE_NOWRITE | OPEN | MOVED_FROM | MOVED_TO | DELETE | CREATE - | DELETE_SELF | MOVE_SELF; - - private static final String LOG_TAG = "FileObserver"; - - private static class ObserverThread extends Thread { - private HashMap m_observers = new HashMap(); - private int m_fd; - - public ObserverThread() { - super("FileObserver"); - m_fd = init(); - } - - public void run() { - observe(m_fd); - } - - public int startWatching(String path, int mask, FileObserver observer) { - int wfd = startWatching(m_fd, path, mask); - - Integer i = new Integer(wfd); - if (wfd >= 0) { - synchronized (m_observers) { - m_observers.put(i, new WeakReference(observer)); - } - } - - return i; - } - - public void stopWatching(int descriptor) { - stopWatching(m_fd, descriptor); - } - - public void onEvent(int wfd, int mask, String path) { - // look up our observer, fixing up the map if necessary... - FileObserver observer = null; - - synchronized (m_observers) { - WeakReference weak = m_observers.get(wfd); - if (weak != null) { // can happen with lots of events from a dead wfd - observer = (FileObserver) weak.get(); - if (observer == null) { - m_observers.remove(wfd); - } - } - } - - // ...then call out to the observer without the sync lock held - if (observer != null) { - try { - observer.onEvent(mask, path); - } catch (Throwable throwable) { - Log.wtf(LOG_TAG, "Unhandled exception in FileObserver " + observer, throwable); - } - } - } - - private native int init(); - private native void observe(int fd); - private native int startWatching(int fd, String path, int mask); - private native void stopWatching(int fd, int wfd); - } - - private static ObserverThread s_observerThread; - - static { - s_observerThread = new ObserverThread(); - s_observerThread.start(); - } - - // instance - private String m_path; - private Integer m_descriptor; - private int m_mask; - - /** - * Equivalent to FileObserver(path, FileObserver.ALL_EVENTS). - */ - public FileObserver(String path) { - this(path, ALL_EVENTS); - } - - /** - * Create a new file observer for a certain file or directory. - * Monitoring does not start on creation! You must call - * {@link #startWatching()} before you will receive events. - * - * @param path The file or directory to monitor - * @param mask The event or events (added together) to watch for - */ - public FileObserver(String path, int mask) { - m_path = path; - m_mask = mask; - m_descriptor = -1; - } - - protected void finalize() { - stopWatching(); - } - - /** - * Start watching for events. The monitored file or directory must exist at - * this time, or else no events will be reported (even if it appears later). - * If monitoring is already started, this call has no effect. - */ - public void startWatching() { - if (m_descriptor < 0) { - m_descriptor = s_observerThread.startWatching(m_path, m_mask, this); - } - } - - /** - * Stop watching for events. Some events may be in process, so events - * may continue to be reported even after this method completes. If - * monitoring is already stopped, this call has no effect. - */ - public void stopWatching() { - if (m_descriptor >= 0) { - s_observerThread.stopWatching(m_descriptor); - m_descriptor = -1; - } - } - - /** - * The event handler, which must be implemented by subclasses. - * - *

This method is invoked on a special FileObserver thread. - * It runs independently of any threads, so take care to use appropriate - * synchronization! Consider using {@link Handler#post(Runnable)} to shift - * event handling work to the main thread to avoid concurrency problems.

- * - *

Event handlers must not throw exceptions.

- * - * @param event The type of event which happened - * @param path The path, relative to the main monitored file or directory, - * of the file or directory which triggered the event - */ - public abstract void onEvent(int event, String path); -} diff --git a/src/main/java/android/os/FileObserverTest.java b/src/main/java/android/os/FileObserverTest.java deleted file mode 100644 index 93e27af..0000000 --- a/src/main/java/android/os/FileObserverTest.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import com.google.android.collect.Lists; -import com.google.android.collect.Maps; - -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.MediumTest; -import android.util.Log; - -import java.io.File; -import java.io.FileOutputStream; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -public class FileObserverTest extends AndroidTestCase { - private Observer mObserver; - private File mTestFile; - - private static class Observer extends FileObserver { - public List events = Lists.newArrayList(); - public int totalEvents = 0; - - public Observer(String path) { - super(path); - } - - public void onEvent(int event, String path) { - synchronized (this) { - totalEvents++; - Map map = Maps.newHashMap(); - - map.put("event", event); - map.put("path", path); - - events.add(map); - - this.notifyAll(); - } - } - } - - @Override - protected void setUp() throws Exception { - mTestFile = File.createTempFile(".file_observer_test", ".txt"); - } - - @Override - protected void tearDown() throws Exception { - if (mTestFile != null && mTestFile.exists()) { - mTestFile.delete(); - } - } - - @MediumTest - public void testRun() throws Exception { - // make file changes and wait for them - assertTrue(mTestFile.exists()); - assertNotNull(mTestFile.getParent()); - - mObserver = new Observer(mTestFile.getParent()); - mObserver.startWatching(); - - FileOutputStream out = new FileOutputStream(mTestFile); - try { - out.write(0x20); - waitForEvent(); // open - waitForEvent(); // modify - - mTestFile.delete(); - waitForEvent(); // modify - waitForEvent(); // delete - - mObserver.stopWatching(); - - // Ensure that we have seen at least 3 events. - assertTrue(mObserver.totalEvents > 3); - } finally { - out.close(); - } - } - - private void waitForEvent() { - synchronized (mObserver) { - boolean done = false; - while (!done) { - try { - mObserver.wait(2000); - done = true; - } catch (InterruptedException e) { - } - } - - Iterator it = mObserver.events.iterator(); - - while (it.hasNext()) { - Map map = it.next(); - Log.i("FileObserverTest", "event: " + getEventString((Integer)map.get("event")) + " path: " + map.get("path")); - } - - mObserver.events.clear(); - } - } - - private String getEventString(int event) { - switch (event) { - case FileObserver.ACCESS: - return "ACCESS"; - case FileObserver.MODIFY: - return "MODIFY"; - case FileObserver.ATTRIB: - return "ATTRIB"; - case FileObserver.CLOSE_WRITE: - return "CLOSE_WRITE"; - case FileObserver.CLOSE_NOWRITE: - return "CLOSE_NOWRITE"; - case FileObserver.OPEN: - return "OPEN"; - case FileObserver.MOVED_FROM: - return "MOVED_FROM"; - case FileObserver.MOVED_TO: - return "MOVED_TO"; - case FileObserver.CREATE: - return "CREATE"; - case FileObserver.DELETE: - return "DELETE"; - case FileObserver.DELETE_SELF: - return "DELETE_SELF"; - case FileObserver.MOVE_SELF: - return "MOVE_SELF"; - default: - return "UNKNOWN"; - } - } -} diff --git a/src/main/java/android/os/FileUtils.java b/src/main/java/android/os/FileUtils.java deleted file mode 100644 index 0a724a1..0000000 --- a/src/main/java/android/os/FileUtils.java +++ /dev/null @@ -1,519 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.system.ErrnoException; -import android.system.Os; -import android.text.TextUtils; -import android.util.Log; -import android.util.Slog; - -import java.io.BufferedInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileDescriptor; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; -import java.util.Comparator; -import java.util.regex.Pattern; -import java.util.zip.CRC32; -import java.util.zip.CheckedInputStream; - -/** - * Tools for managing files. Not for public consumption. - * @hide - */ -public class FileUtils { - private static final String TAG = "FileUtils"; - - public static final int S_IRWXU = 00700; - public static final int S_IRUSR = 00400; - public static final int S_IWUSR = 00200; - public static final int S_IXUSR = 00100; - - public static final int S_IRWXG = 00070; - public static final int S_IRGRP = 00040; - public static final int S_IWGRP = 00020; - public static final int S_IXGRP = 00010; - - public static final int S_IRWXO = 00007; - public static final int S_IROTH = 00004; - public static final int S_IWOTH = 00002; - public static final int S_IXOTH = 00001; - - /** Regular expression for safe filenames: no spaces or metacharacters */ - private static final Pattern SAFE_FILENAME_PATTERN = Pattern.compile("[\\w%+,./=_-]+"); - - /** - * Set owner and mode of of given {@link File}. - * - * @param mode to apply through {@code chmod} - * @param uid to apply through {@code chown}, or -1 to leave unchanged - * @param gid to apply through {@code chown}, or -1 to leave unchanged - * @return 0 on success, otherwise errno. - */ - public static int setPermissions(File path, int mode, int uid, int gid) { - return setPermissions(path.getAbsolutePath(), mode, uid, gid); - } - - /** - * Set owner and mode of of given path. - * - * @param mode to apply through {@code chmod} - * @param uid to apply through {@code chown}, or -1 to leave unchanged - * @param gid to apply through {@code chown}, or -1 to leave unchanged - * @return 0 on success, otherwise errno. - */ - public static int setPermissions(String path, int mode, int uid, int gid) { - try { - Os.chmod(path, mode); - } catch (ErrnoException e) { - Slog.w(TAG, "Failed to chmod(" + path + "): " + e); - return e.errno; - } - - if (uid >= 0 || gid >= 0) { - try { - Os.chown(path, uid, gid); - } catch (ErrnoException e) { - Slog.w(TAG, "Failed to chown(" + path + "): " + e); - return e.errno; - } - } - - return 0; - } - - /** - * Set owner and mode of of given {@link FileDescriptor}. - * - * @param mode to apply through {@code chmod} - * @param uid to apply through {@code chown}, or -1 to leave unchanged - * @param gid to apply through {@code chown}, or -1 to leave unchanged - * @return 0 on success, otherwise errno. - */ - public static int setPermissions(FileDescriptor fd, int mode, int uid, int gid) { - try { - Os.fchmod(fd, mode); - } catch (ErrnoException e) { - Slog.w(TAG, "Failed to fchmod(): " + e); - return e.errno; - } - - if (uid >= 0 || gid >= 0) { - try { - Os.fchown(fd, uid, gid); - } catch (ErrnoException e) { - Slog.w(TAG, "Failed to fchown(): " + e); - return e.errno; - } - } - - return 0; - } - - /** - * Return owning UID of given path, otherwise -1. - */ - public static int getUid(String path) { - try { - return Os.stat(path).st_uid; - } catch (ErrnoException e) { - return -1; - } - } - - /** - * Perform an fsync on the given FileOutputStream. The stream at this - * point must be flushed but not yet closed. - */ - public static boolean sync(FileOutputStream stream) { - try { - if (stream != null) { - stream.getFD().sync(); - } - return true; - } catch (IOException e) { - } - return false; - } - - // copy a file from srcFile to destFile, return true if succeed, return - // false if fail - public static boolean copyFile(File srcFile, File destFile) { - boolean result = false; - try { - InputStream in = new FileInputStream(srcFile); - try { - result = copyToFile(in, destFile); - } finally { - in.close(); - } - } catch (IOException e) { - result = false; - } - return result; - } - - /** - * Copy data from a source stream to destFile. - * Return true if succeed, return false if failed. - */ - public static boolean copyToFile(InputStream inputStream, File destFile) { - try { - if (destFile.exists()) { - destFile.delete(); - } - FileOutputStream out = new FileOutputStream(destFile); - try { - byte[] buffer = new byte[4096]; - int bytesRead; - while ((bytesRead = inputStream.read(buffer)) >= 0) { - out.write(buffer, 0, bytesRead); - } - } finally { - out.flush(); - try { - out.getFD().sync(); - } catch (IOException e) { - } - out.close(); - } - return true; - } catch (IOException e) { - return false; - } - } - - /** - * Check if a filename is "safe" (no metacharacters or spaces). - * @param file The file to check - */ - public static boolean isFilenameSafe(File file) { - // Note, we check whether it matches what's known to be safe, - // rather than what's known to be unsafe. Non-ASCII, control - // characters, etc. are all unsafe by default. - return SAFE_FILENAME_PATTERN.matcher(file.getPath()).matches(); - } - - /** - * Read a text file into a String, optionally limiting the length. - * @param file to read (will not seek, so things like /proc files are OK) - * @param max length (positive for head, negative of tail, 0 for no limit) - * @param ellipsis to add of the file was truncated (can be null) - * @return the contents of the file, possibly truncated - * @throws IOException if something goes wrong reading the file - */ - public static String readTextFile(File file, int max, String ellipsis) throws IOException { - InputStream input = new FileInputStream(file); - // wrapping a BufferedInputStream around it because when reading /proc with unbuffered - // input stream, bytes read not equal to buffer size is not necessarily the correct - // indication for EOF; but it is true for BufferedInputStream due to its implementation. - BufferedInputStream bis = new BufferedInputStream(input); - try { - long size = file.length(); - if (max > 0 || (size > 0 && max == 0)) { // "head" mode: read the first N bytes - if (size > 0 && (max == 0 || size < max)) max = (int) size; - byte[] data = new byte[max + 1]; - int length = bis.read(data); - if (length <= 0) return ""; - if (length <= max) return new String(data, 0, length); - if (ellipsis == null) return new String(data, 0, max); - return new String(data, 0, max) + ellipsis; - } else if (max < 0) { // "tail" mode: keep the last N - int len; - boolean rolled = false; - byte[] last = null; - byte[] data = null; - do { - if (last != null) rolled = true; - byte[] tmp = last; last = data; data = tmp; - if (data == null) data = new byte[-max]; - len = bis.read(data); - } while (len == data.length); - - if (last == null && len <= 0) return ""; - if (last == null) return new String(data, 0, len); - if (len > 0) { - rolled = true; - System.arraycopy(last, len, last, 0, last.length - len); - System.arraycopy(data, 0, last, last.length - len, len); - } - if (ellipsis == null || !rolled) return new String(last); - return ellipsis + new String(last); - } else { // "cat" mode: size unknown, read it all in streaming fashion - ByteArrayOutputStream contents = new ByteArrayOutputStream(); - int len; - byte[] data = new byte[1024]; - do { - len = bis.read(data); - if (len > 0) contents.write(data, 0, len); - } while (len == data.length); - return contents.toString(); - } - } finally { - bis.close(); - input.close(); - } - } - - /** - * Writes string to file. Basically same as "echo -n $string > $filename" - * - * @param filename - * @param string - * @throws IOException - */ - public static void stringToFile(String filename, String string) throws IOException { - FileWriter out = new FileWriter(filename); - try { - out.write(string); - } finally { - out.close(); - } - } - - /** - * Computes the checksum of a file using the CRC32 checksum routine. - * The value of the checksum is returned. - * - * @param file the file to checksum, must not be null - * @return the checksum value or an exception is thrown. - */ - public static long checksumCrc32(File file) throws FileNotFoundException, IOException { - CRC32 checkSummer = new CRC32(); - CheckedInputStream cis = null; - - try { - cis = new CheckedInputStream( new FileInputStream(file), checkSummer); - byte[] buf = new byte[128]; - while(cis.read(buf) >= 0) { - // Just read for checksum to get calculated. - } - return checkSummer.getValue(); - } finally { - if (cis != null) { - try { - cis.close(); - } catch (IOException e) { - } - } - } - } - - /** - * Delete older files in a directory until only those matching the given - * constraints remain. - * - * @param minCount Always keep at least this many files. - * @param minAge Always keep files younger than this age. - * @return if any files were deleted. - */ - public static boolean deleteOlderFiles(File dir, int minCount, long minAge) { - if (minCount < 0 || minAge < 0) { - throw new IllegalArgumentException("Constraints must be positive or 0"); - } - - final File[] files = dir.listFiles(); - if (files == null) return false; - - // Sort with newest files first - Arrays.sort(files, new Comparator() { - @Override - public int compare(File lhs, File rhs) { - return (int) (rhs.lastModified() - lhs.lastModified()); - } - }); - - // Keep at least minCount files - boolean deleted = false; - for (int i = minCount; i < files.length; i++) { - final File file = files[i]; - - // Keep files newer than minAge - final long age = System.currentTimeMillis() - file.lastModified(); - if (age > minAge) { - if (file.delete()) { - Log.d(TAG, "Deleted old file " + file); - deleted = true; - } - } - } - return deleted; - } - - /** - * Test if a file lives under the given directory, either as a direct child - * or a distant grandchild. - *

- * Both files must have been resolved using - * {@link File#getCanonicalFile()} to avoid symlink or path traversal - * attacks. - */ - public static boolean contains(File dir, File file) { - if (file == null) return false; - - String dirPath = dir.getAbsolutePath(); - String filePath = file.getAbsolutePath(); - - if (dirPath.equals(filePath)) { - return true; - } - - if (!dirPath.endsWith("/")) { - dirPath += "/"; - } - return filePath.startsWith(dirPath); - } - - public static boolean deleteContents(File dir) { - File[] files = dir.listFiles(); - boolean success = true; - if (files != null) { - for (File file : files) { - if (file.isDirectory()) { - success &= deleteContents(file); - } - if (!file.delete()) { - Log.w(TAG, "Failed to delete " + file); - success = false; - } - } - } - return success; - } - - private static boolean isValidExtFilenameChar(char c) { - switch (c) { - case '\0': - case '/': - return false; - default: - return true; - } - } - - /** - * Check if given filename is valid for an ext4 filesystem. - */ - public static boolean isValidExtFilename(String name) { - return (name != null) && name.equals(buildValidExtFilename(name)); - } - - /** - * Mutate the given filename to make it valid for an ext4 filesystem, - * replacing any invalid characters with "_". - */ - public static String buildValidExtFilename(String name) { - if (TextUtils.isEmpty(name) || ".".equals(name) || "..".equals(name)) { - return "(invalid)"; - } - final StringBuilder res = new StringBuilder(name.length()); - for (int i = 0; i < name.length(); i++) { - final char c = name.charAt(i); - if (isValidExtFilenameChar(c)) { - res.append(c); - } else { - res.append('_'); - } - } - return res.toString(); - } - - private static boolean isValidFatFilenameChar(char c) { - if ((0x00 <= c && c <= 0x1f)) { - return false; - } - switch (c) { - case '"': - case '*': - case '/': - case ':': - case '<': - case '>': - case '?': - case '\\': - case '|': - case 0x7F: - return false; - default: - return true; - } - } - - /** - * Check if given filename is valid for a FAT filesystem. - */ - public static boolean isValidFatFilename(String name) { - return (name != null) && name.equals(buildValidFatFilename(name)); - } - - /** - * Mutate the given filename to make it valid for a FAT filesystem, - * replacing any invalid characters with "_". - */ - public static String buildValidFatFilename(String name) { - if (TextUtils.isEmpty(name) || ".".equals(name) || "..".equals(name)) { - return "(invalid)"; - } - final StringBuilder res = new StringBuilder(name.length()); - for (int i = 0; i < name.length(); i++) { - final char c = name.charAt(i); - if (isValidFatFilenameChar(c)) { - res.append(c); - } else { - res.append('_'); - } - } - return res.toString(); - } - - public static String rewriteAfterRename(File beforeDir, File afterDir, String path) { - if (path == null) return null; - final File result = rewriteAfterRename(beforeDir, afterDir, new File(path)); - return (result != null) ? result.getAbsolutePath() : null; - } - - public static String[] rewriteAfterRename(File beforeDir, File afterDir, String[] paths) { - if (paths == null) return null; - final String[] result = new String[paths.length]; - for (int i = 0; i < paths.length; i++) { - result[i] = rewriteAfterRename(beforeDir, afterDir, paths[i]); - } - return result; - } - - /** - * Given a path under the "before" directory, rewrite it to live under the - * "after" directory. For example, {@code /before/foo/bar.txt} would become - * {@code /after/foo/bar.txt}. - */ - public static File rewriteAfterRename(File beforeDir, File afterDir, File file) { - if (file == null) return null; - if (contains(beforeDir, file)) { - final String splice = file.getAbsolutePath().substring( - beforeDir.getAbsolutePath().length()); - return new File(afterDir, splice); - } - return null; - } -} diff --git a/src/main/java/android/os/FileUtilsTest.java b/src/main/java/android/os/FileUtilsTest.java deleted file mode 100644 index 5c9e813..0000000 --- a/src/main/java/android/os/FileUtilsTest.java +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import static android.text.format.DateUtils.DAY_IN_MILLIS; -import static android.text.format.DateUtils.HOUR_IN_MILLIS; -import static android.text.format.DateUtils.WEEK_IN_MILLIS; - -import android.content.Context; -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.MediumTest; - -import com.google.android.collect.Sets; - -import libcore.io.IoUtils; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.FileWriter; -import java.util.Arrays; -import java.util.HashSet; - -@MediumTest -public class FileUtilsTest extends AndroidTestCase { - private static final String TEST_DATA = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - - private File mDir; - private File mTestFile; - private File mCopyFile; - - @Override - protected void setUp() throws Exception { - super.setUp(); - mDir = getContext().getDir("testing", Context.MODE_PRIVATE); - mTestFile = new File(mDir, "test.file"); - mCopyFile = new File(mDir, "copy.file"); - } - - @Override - protected void tearDown() throws Exception { - IoUtils.deleteContents(mDir); - } - - // TODO: test setPermissions(), getPermissions() - - public void testCopyFile() throws Exception { - stageFile(mTestFile, TEST_DATA); - assertFalse(mCopyFile.exists()); - FileUtils.copyFile(mTestFile, mCopyFile); - assertTrue(mCopyFile.exists()); - assertEquals(TEST_DATA, FileUtils.readTextFile(mCopyFile, 0, null)); - } - - public void testCopyToFile() throws Exception { - final String s = "Foo Bar"; - assertFalse(mCopyFile.exists()); - FileUtils.copyToFile(new ByteArrayInputStream(s.getBytes()), mCopyFile); - assertTrue(mCopyFile.exists()); - assertEquals(s, FileUtils.readTextFile(mCopyFile, 0, null)); - } - - public void testIsFilenameSafe() throws Exception { - assertTrue(FileUtils.isFilenameSafe(new File("foobar"))); - assertTrue(FileUtils.isFilenameSafe(new File("a_b-c=d.e/0,1+23"))); - assertFalse(FileUtils.isFilenameSafe(new File("foo*bar"))); - assertFalse(FileUtils.isFilenameSafe(new File("foo\nbar"))); - } - - public void testReadTextFile() throws Exception { - stageFile(mTestFile, TEST_DATA); - - assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, 0, null)); - - assertEquals("ABCDE", FileUtils.readTextFile(mTestFile, 5, null)); - assertEquals("ABCDE<>", FileUtils.readTextFile(mTestFile, 5, "<>")); - assertEquals(TEST_DATA.substring(0, 51) + "<>", - FileUtils.readTextFile(mTestFile, 51, "<>")); - assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, 52, "<>")); - assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, 100, "<>")); - - assertEquals("vwxyz", FileUtils.readTextFile(mTestFile, -5, null)); - assertEquals("<>vwxyz", FileUtils.readTextFile(mTestFile, -5, "<>")); - assertEquals("<>" + TEST_DATA.substring(1, 52), - FileUtils.readTextFile(mTestFile, -51, "<>")); - assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, -52, "<>")); - assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, -100, "<>")); - } - - public void testReadTextFileWithZeroLengthFile() throws Exception { - stageFile(mTestFile, TEST_DATA); - new FileOutputStream(mTestFile).close(); // Zero out the file - assertEquals("", FileUtils.readTextFile(mTestFile, 0, null)); - assertEquals("", FileUtils.readTextFile(mTestFile, 1, "<>")); - assertEquals("", FileUtils.readTextFile(mTestFile, 10, "<>")); - assertEquals("", FileUtils.readTextFile(mTestFile, -1, "<>")); - assertEquals("", FileUtils.readTextFile(mTestFile, -10, "<>")); - } - - public void testContains() throws Exception { - assertTrue(FileUtils.contains(new File("/"), new File("/moo.txt"))); - assertTrue(FileUtils.contains(new File("/"), new File("/"))); - - assertTrue(FileUtils.contains(new File("/sdcard"), new File("/sdcard"))); - assertTrue(FileUtils.contains(new File("/sdcard/"), new File("/sdcard/"))); - - assertTrue(FileUtils.contains(new File("/sdcard"), new File("/sdcard/moo.txt"))); - assertTrue(FileUtils.contains(new File("/sdcard/"), new File("/sdcard/moo.txt"))); - - assertFalse(FileUtils.contains(new File("/sdcard"), new File("/moo.txt"))); - assertFalse(FileUtils.contains(new File("/sdcard/"), new File("/moo.txt"))); - - assertFalse(FileUtils.contains(new File("/sdcard"), new File("/sdcard.txt"))); - assertFalse(FileUtils.contains(new File("/sdcard/"), new File("/sdcard.txt"))); - } - - public void testDeleteOlderEmptyDir() throws Exception { - FileUtils.deleteOlderFiles(mDir, 10, WEEK_IN_MILLIS); - assertDirContents(); - } - - public void testDeleteOlderTypical() throws Exception { - touch("file1", HOUR_IN_MILLIS); - touch("file2", 1 * DAY_IN_MILLIS + HOUR_IN_MILLIS); - touch("file3", 2 * DAY_IN_MILLIS + HOUR_IN_MILLIS); - touch("file4", 3 * DAY_IN_MILLIS + HOUR_IN_MILLIS); - touch("file5", 4 * DAY_IN_MILLIS + HOUR_IN_MILLIS); - assertTrue(FileUtils.deleteOlderFiles(mDir, 3, DAY_IN_MILLIS)); - assertDirContents("file1", "file2", "file3"); - } - - public void testDeleteOlderInFuture() throws Exception { - touch("file1", -HOUR_IN_MILLIS); - touch("file2", HOUR_IN_MILLIS); - touch("file3", WEEK_IN_MILLIS); - assertTrue(FileUtils.deleteOlderFiles(mDir, 0, DAY_IN_MILLIS)); - assertDirContents("file1", "file2"); - - touch("file1", -HOUR_IN_MILLIS); - touch("file2", HOUR_IN_MILLIS); - touch("file3", WEEK_IN_MILLIS); - assertTrue(FileUtils.deleteOlderFiles(mDir, 0, DAY_IN_MILLIS)); - assertDirContents("file1", "file2"); - } - - public void testDeleteOlderOnlyAge() throws Exception { - touch("file1", HOUR_IN_MILLIS); - touch("file2", 1 * DAY_IN_MILLIS + HOUR_IN_MILLIS); - touch("file3", 2 * DAY_IN_MILLIS + HOUR_IN_MILLIS); - touch("file4", 3 * DAY_IN_MILLIS + HOUR_IN_MILLIS); - touch("file5", 4 * DAY_IN_MILLIS + HOUR_IN_MILLIS); - assertTrue(FileUtils.deleteOlderFiles(mDir, 0, DAY_IN_MILLIS)); - assertFalse(FileUtils.deleteOlderFiles(mDir, 0, DAY_IN_MILLIS)); - assertDirContents("file1"); - } - - public void testDeleteOlderOnlyCount() throws Exception { - touch("file1", HOUR_IN_MILLIS); - touch("file2", 1 * DAY_IN_MILLIS + HOUR_IN_MILLIS); - touch("file3", 2 * DAY_IN_MILLIS + HOUR_IN_MILLIS); - touch("file4", 3 * DAY_IN_MILLIS + HOUR_IN_MILLIS); - touch("file5", 4 * DAY_IN_MILLIS + HOUR_IN_MILLIS); - assertTrue(FileUtils.deleteOlderFiles(mDir, 2, 0)); - assertFalse(FileUtils.deleteOlderFiles(mDir, 2, 0)); - assertDirContents("file1", "file2"); - } - - public void testValidExtFilename() throws Exception { - assertTrue(FileUtils.isValidExtFilename("a")); - assertTrue(FileUtils.isValidExtFilename("foo.bar")); - assertTrue(FileUtils.isValidExtFilename("foo bar.baz")); - assertTrue(FileUtils.isValidExtFilename("foo.bar.baz")); - assertTrue(FileUtils.isValidExtFilename(".bar")); - assertTrue(FileUtils.isValidExtFilename("foo~!@#$%^&*()_[]{}+bar")); - - assertFalse(FileUtils.isValidExtFilename(null)); - assertFalse(FileUtils.isValidExtFilename(".")); - assertFalse(FileUtils.isValidExtFilename("../foo")); - assertFalse(FileUtils.isValidExtFilename("/foo")); - - assertEquals(".._foo", FileUtils.buildValidExtFilename("../foo")); - assertEquals("_foo", FileUtils.buildValidExtFilename("/foo")); - assertEquals("foo_bar", FileUtils.buildValidExtFilename("foo\0bar")); - assertEquals(".foo", FileUtils.buildValidExtFilename(".foo")); - assertEquals("foo.bar", FileUtils.buildValidExtFilename("foo.bar")); - } - - public void testValidFatFilename() throws Exception { - assertTrue(FileUtils.isValidFatFilename("a")); - assertTrue(FileUtils.isValidFatFilename("foo bar.baz")); - assertTrue(FileUtils.isValidFatFilename("foo.bar.baz")); - assertTrue(FileUtils.isValidFatFilename(".bar")); - assertTrue(FileUtils.isValidFatFilename("foo.bar")); - assertTrue(FileUtils.isValidFatFilename("foo bar")); - assertTrue(FileUtils.isValidFatFilename("foo+bar")); - assertTrue(FileUtils.isValidFatFilename("foo,bar")); - - assertFalse(FileUtils.isValidFatFilename("foo*bar")); - assertFalse(FileUtils.isValidFatFilename("foo?bar")); - assertFalse(FileUtils.isValidFatFilename("foo expectedSet = Sets.newHashSet(expected); - String[] actual = mDir.list(); - if (actual == null) actual = new String[0]; - - assertEquals( - "Expected " + Arrays.toString(expected) + " but actual " + Arrays.toString(actual), - expected.length, actual.length); - for (String actualFile : actual) { - assertTrue("Unexpected actual file " + actualFile, expectedSet.contains(actualFile)); - } - } -} diff --git a/src/main/java/android/os/Handler.java b/src/main/java/android/os/Handler.java deleted file mode 100644 index 878b7a0..0000000 --- a/src/main/java/android/os/Handler.java +++ /dev/null @@ -1,798 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.util.Log; -import android.util.Printer; - -import java.lang.reflect.Modifier; - -/** - * A Handler allows you to send and process {@link Message} and Runnable - * objects associated with a thread's {@link MessageQueue}. Each Handler - * instance is associated with a single thread and that thread's message - * queue. When you create a new Handler, it is bound to the thread / - * message queue of the thread that is creating it -- from that point on, - * it will deliver messages and runnables to that message queue and execute - * them as they come out of the message queue. - * - *

There are two main uses for a Handler: (1) to schedule messages and - * runnables to be executed as some point in the future; and (2) to enqueue - * an action to be performed on a different thread than your own. - * - *

Scheduling messages is accomplished with the - * {@link #post}, {@link #postAtTime(Runnable, long)}, - * {@link #postDelayed}, {@link #sendEmptyMessage}, - * {@link #sendMessage}, {@link #sendMessageAtTime}, and - * {@link #sendMessageDelayed} methods. The post versions allow - * you to enqueue Runnable objects to be called by the message queue when - * they are received; the sendMessage versions allow you to enqueue - * a {@link Message} object containing a bundle of data that will be - * processed by the Handler's {@link #handleMessage} method (requiring that - * you implement a subclass of Handler). - * - *

When posting or sending to a Handler, you can either - * allow the item to be processed as soon as the message queue is ready - * to do so, or specify a delay before it gets processed or absolute time for - * it to be processed. The latter two allow you to implement timeouts, - * ticks, and other timing-based behavior. - * - *

When a - * process is created for your application, its main thread is dedicated to - * running a message queue that takes care of managing the top-level - * application objects (activities, broadcast receivers, etc) and any windows - * they create. You can create your own threads, and communicate back with - * the main application thread through a Handler. This is done by calling - * the same post or sendMessage methods as before, but from - * your new thread. The given Runnable or Message will then be scheduled - * in the Handler's message queue and processed when appropriate. - */ -public class Handler { - /* - * Set this flag to true to detect anonymous, local or member classes - * that extend this Handler class and that are not static. These kind - * of classes can potentially create leaks. - */ - private static final boolean FIND_POTENTIAL_LEAKS = false; - private static final String TAG = "Handler"; - - /** - * Callback interface you can use when instantiating a Handler to avoid - * having to implement your own subclass of Handler. - * - * @param msg A {@link android.os.Message Message} object - * @return True if no further handling is desired - */ - public interface Callback { - public boolean handleMessage(Message msg); - } - - /** - * Subclasses must implement this to receive messages. - */ - public void handleMessage(Message msg) { - } - - /** - * Handle system messages here. - */ - public void dispatchMessage(Message msg) { - if (msg.callback != null) { - handleCallback(msg); - } else { - if (mCallback != null) { - if (mCallback.handleMessage(msg)) { - return; - } - } - handleMessage(msg); - } - } - - /** - * Default constructor associates this handler with the {@link Looper} for the - * current thread. - * - * If this thread does not have a looper, this handler won't be able to receive messages - * so an exception is thrown. - */ - public Handler() { - this(null, false); - } - - /** - * Constructor associates this handler with the {@link Looper} for the - * current thread and takes a callback interface in which you can handle - * messages. - * - * If this thread does not have a looper, this handler won't be able to receive messages - * so an exception is thrown. - * - * @param callback The callback interface in which to handle messages, or null. - */ - public Handler(Callback callback) { - this(callback, false); - } - - /** - * Use the provided {@link Looper} instead of the default one. - * - * @param looper The looper, must not be null. - */ - public Handler(Looper looper) { - this(looper, null, false); - } - - /** - * Use the provided {@link Looper} instead of the default one and take a callback - * interface in which to handle messages. - * - * @param looper The looper, must not be null. - * @param callback The callback interface in which to handle messages, or null. - */ - public Handler(Looper looper, Callback callback) { - this(looper, callback, false); - } - - /** - * Use the {@link Looper} for the current thread - * and set whether the handler should be asynchronous. - * - * Handlers are synchronous by default unless this constructor is used to make - * one that is strictly asynchronous. - * - * Asynchronous messages represent interrupts or events that do not require global ordering - * with respect to synchronous messages. Asynchronous messages are not subject to - * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. - * - * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for - * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. - * - * @hide - */ - public Handler(boolean async) { - this(null, async); - } - - /** - * Use the {@link Looper} for the current thread with the specified callback interface - * and set whether the handler should be asynchronous. - * - * Handlers are synchronous by default unless this constructor is used to make - * one that is strictly asynchronous. - * - * Asynchronous messages represent interrupts or events that do not require global ordering - * with respect to synchronous messages. Asynchronous messages are not subject to - * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. - * - * @param callback The callback interface in which to handle messages, or null. - * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for - * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. - * - * @hide - */ - public Handler(Callback callback, boolean async) { - if (FIND_POTENTIAL_LEAKS) { - final Class klass = getClass(); - if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && - (klass.getModifiers() & Modifier.STATIC) == 0) { - Log.w(TAG, "The following Handler class should be static or leaks might occur: " + - klass.getCanonicalName()); - } - } - - mLooper = Looper.myLooper(); - if (mLooper == null) { - throw new RuntimeException( - "Can't create handler inside thread that has not called Looper.prepare()"); - } - mQueue = mLooper.mQueue; - mCallback = callback; - mAsynchronous = async; - } - - /** - * Use the provided {@link Looper} instead of the default one and take a callback - * interface in which to handle messages. Also set whether the handler - * should be asynchronous. - * - * Handlers are synchronous by default unless this constructor is used to make - * one that is strictly asynchronous. - * - * Asynchronous messages represent interrupts or events that do not require global ordering - * with respect to synchronous messages. Asynchronous messages are not subject to - * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. - * - * @param looper The looper, must not be null. - * @param callback The callback interface in which to handle messages, or null. - * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for - * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. - * - * @hide - */ - public Handler(Looper looper, Callback callback, boolean async) { - mLooper = looper; - mQueue = looper.mQueue; - mCallback = callback; - mAsynchronous = async; - } - - /** - * Returns a string representing the name of the specified message. - * The default implementation will either return the class name of the - * message callback if any, or the hexadecimal representation of the - * message "what" field. - * - * @param message The message whose name is being queried - */ - public String getMessageName(Message message) { - if (message.callback != null) { - return message.callback.getClass().getName(); - } - return "0x" + Integer.toHexString(message.what); - } - - /** - * Returns a new {@link android.os.Message Message} from the global message pool. More efficient than - * creating and allocating new instances. The retrieved message has its handler set to this instance (Message.target == this). - * If you don't want that facility, just call Message.obtain() instead. - */ - public final Message obtainMessage() - { - return Message.obtain(this); - } - - /** - * Same as {@link #obtainMessage()}, except that it also sets the what member of the returned Message. - * - * @param what Value to assign to the returned Message.what field. - * @return A Message from the global message pool. - */ - public final Message obtainMessage(int what) - { - return Message.obtain(this, what); - } - - /** - * - * Same as {@link #obtainMessage()}, except that it also sets the what and obj members - * of the returned Message. - * - * @param what Value to assign to the returned Message.what field. - * @param obj Value to assign to the returned Message.obj field. - * @return A Message from the global message pool. - */ - public final Message obtainMessage(int what, Object obj) - { - return Message.obtain(this, what, obj); - } - - /** - * - * Same as {@link #obtainMessage()}, except that it also sets the what, arg1 and arg2 members of the returned - * Message. - * @param what Value to assign to the returned Message.what field. - * @param arg1 Value to assign to the returned Message.arg1 field. - * @param arg2 Value to assign to the returned Message.arg2 field. - * @return A Message from the global message pool. - */ - public final Message obtainMessage(int what, int arg1, int arg2) - { - return Message.obtain(this, what, arg1, arg2); - } - - /** - * - * Same as {@link #obtainMessage()}, except that it also sets the what, obj, arg1,and arg2 values on the - * returned Message. - * @param what Value to assign to the returned Message.what field. - * @param arg1 Value to assign to the returned Message.arg1 field. - * @param arg2 Value to assign to the returned Message.arg2 field. - * @param obj Value to assign to the returned Message.obj field. - * @return A Message from the global message pool. - */ - public final Message obtainMessage(int what, int arg1, int arg2, Object obj) - { - return Message.obtain(this, what, arg1, arg2, obj); - } - - /** - * Causes the Runnable r to be added to the message queue. - * The runnable will be run on the thread to which this handler is - * attached. - * - * @param r The Runnable that will be executed. - * - * @return Returns true if the Runnable was successfully placed in to the - * message queue. Returns false on failure, usually because the - * looper processing the message queue is exiting. - */ - public final boolean post(Runnable r) - { - return sendMessageDelayed(getPostMessage(r), 0); - } - - /** - * Causes the Runnable r to be added to the message queue, to be run - * at a specific time given by uptimeMillis. - * The time-base is {@link android.os.SystemClock#uptimeMillis}. - * Time spent in deep sleep will add an additional delay to execution. - * The runnable will be run on the thread to which this handler is attached. - * - * @param r The Runnable that will be executed. - * @param uptimeMillis The absolute time at which the callback should run, - * using the {@link android.os.SystemClock#uptimeMillis} time-base. - * - * @return Returns true if the Runnable was successfully placed in to the - * message queue. Returns false on failure, usually because the - * looper processing the message queue is exiting. Note that a - * result of true does not mean the Runnable will be processed -- if - * the looper is quit before the delivery time of the message - * occurs then the message will be dropped. - */ - public final boolean postAtTime(Runnable r, long uptimeMillis) - { - return sendMessageAtTime(getPostMessage(r), uptimeMillis); - } - - /** - * Causes the Runnable r to be added to the message queue, to be run - * at a specific time given by uptimeMillis. - * The time-base is {@link android.os.SystemClock#uptimeMillis}. - * Time spent in deep sleep will add an additional delay to execution. - * The runnable will be run on the thread to which this handler is attached. - * - * @param r The Runnable that will be executed. - * @param uptimeMillis The absolute time at which the callback should run, - * using the {@link android.os.SystemClock#uptimeMillis} time-base. - * - * @return Returns true if the Runnable was successfully placed in to the - * message queue. Returns false on failure, usually because the - * looper processing the message queue is exiting. Note that a - * result of true does not mean the Runnable will be processed -- if - * the looper is quit before the delivery time of the message - * occurs then the message will be dropped. - * - * @see android.os.SystemClock#uptimeMillis - */ - public final boolean postAtTime(Runnable r, Object token, long uptimeMillis) - { - return sendMessageAtTime(getPostMessage(r, token), uptimeMillis); - } - - /** - * Causes the Runnable r to be added to the message queue, to be run - * after the specified amount of time elapses. - * The runnable will be run on the thread to which this handler - * is attached. - * The time-base is {@link android.os.SystemClock#uptimeMillis}. - * Time spent in deep sleep will add an additional delay to execution. - * - * @param r The Runnable that will be executed. - * @param delayMillis The delay (in milliseconds) until the Runnable - * will be executed. - * - * @return Returns true if the Runnable was successfully placed in to the - * message queue. Returns false on failure, usually because the - * looper processing the message queue is exiting. Note that a - * result of true does not mean the Runnable will be processed -- - * if the looper is quit before the delivery time of the message - * occurs then the message will be dropped. - */ - public final boolean postDelayed(Runnable r, long delayMillis) - { - return sendMessageDelayed(getPostMessage(r), delayMillis); - } - - /** - * Posts a message to an object that implements Runnable. - * Causes the Runnable r to executed on the next iteration through the - * message queue. The runnable will be run on the thread to which this - * handler is attached. - * This method is only for use in very special circumstances -- it - * can easily starve the message queue, cause ordering problems, or have - * other unexpected side-effects. - * - * @param r The Runnable that will be executed. - * - * @return Returns true if the message was successfully placed in to the - * message queue. Returns false on failure, usually because the - * looper processing the message queue is exiting. - */ - public final boolean postAtFrontOfQueue(Runnable r) - { - return sendMessageAtFrontOfQueue(getPostMessage(r)); - } - - /** - * Runs the specified task synchronously. - *

- * If the current thread is the same as the handler thread, then the runnable - * runs immediately without being enqueued. Otherwise, posts the runnable - * to the handler and waits for it to complete before returning. - *

- * This method is dangerous! Improper use can result in deadlocks. - * Never call this method while any locks are held or use it in a - * possibly re-entrant manner. - *

- * This method is occasionally useful in situations where a background thread - * must synchronously await completion of a task that must run on the - * handler's thread. However, this problem is often a symptom of bad design. - * Consider improving the design (if possible) before resorting to this method. - *

- * One example of where you might want to use this method is when you just - * set up a Handler thread and need to perform some initialization steps on - * it before continuing execution. - *

- * If timeout occurs then this method returns false but the runnable - * will remain posted on the handler and may already be in progress or - * complete at a later time. - *

- * When using this method, be sure to use {@link Looper#quitSafely} when - * quitting the looper. Otherwise {@link #runWithScissors} may hang indefinitely. - * (TODO: We should fix this by making MessageQueue aware of blocking runnables.) - *

- * - * @param r The Runnable that will be executed synchronously. - * @param timeout The timeout in milliseconds, or 0 to wait indefinitely. - * - * @return Returns true if the Runnable was successfully executed. - * Returns false on failure, usually because the - * looper processing the message queue is exiting. - * - * @hide This method is prone to abuse and should probably not be in the API. - * If we ever do make it part of the API, we might want to rename it to something - * less funny like runUnsafe(). - */ - public final boolean runWithScissors(final Runnable r, long timeout) { - if (r == null) { - throw new IllegalArgumentException("runnable must not be null"); - } - if (timeout < 0) { - throw new IllegalArgumentException("timeout must be non-negative"); - } - - if (Looper.myLooper() == mLooper) { - r.run(); - return true; - } - - BlockingRunnable br = new BlockingRunnable(r); - return br.postAndWait(this, timeout); - } - - /** - * Remove any pending posts of Runnable r that are in the message queue. - */ - public final void removeCallbacks(Runnable r) - { - mQueue.removeMessages(this, r, null); - } - - /** - * Remove any pending posts of Runnable r with Object - * token that are in the message queue. If token is null, - * all callbacks will be removed. - */ - public final void removeCallbacks(Runnable r, Object token) - { - mQueue.removeMessages(this, r, token); - } - - /** - * Pushes a message onto the end of the message queue after all pending messages - * before the current time. It will be received in {@link #handleMessage}, - * in the thread attached to this handler. - * - * @return Returns true if the message was successfully placed in to the - * message queue. Returns false on failure, usually because the - * looper processing the message queue is exiting. - */ - public final boolean sendMessage(Message msg) - { - return sendMessageDelayed(msg, 0); - } - - /** - * Sends a Message containing only the what value. - * - * @return Returns true if the message was successfully placed in to the - * message queue. Returns false on failure, usually because the - * looper processing the message queue is exiting. - */ - public final boolean sendEmptyMessage(int what) - { - return sendEmptyMessageDelayed(what, 0); - } - - /** - * Sends a Message containing only the what value, to be delivered - * after the specified amount of time elapses. - * @see #sendMessageDelayed(android.os.Message, long) - * - * @return Returns true if the message was successfully placed in to the - * message queue. Returns false on failure, usually because the - * looper processing the message queue is exiting. - */ - public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { - Message msg = Message.obtain(); - msg.what = what; - return sendMessageDelayed(msg, delayMillis); - } - - /** - * Sends a Message containing only the what value, to be delivered - * at a specific time. - * @see #sendMessageAtTime(android.os.Message, long) - * - * @return Returns true if the message was successfully placed in to the - * message queue. Returns false on failure, usually because the - * looper processing the message queue is exiting. - */ - - public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) { - Message msg = Message.obtain(); - msg.what = what; - return sendMessageAtTime(msg, uptimeMillis); - } - - /** - * Enqueue a message into the message queue after all pending messages - * before (current time + delayMillis). You will receive it in - * {@link #handleMessage}, in the thread attached to this handler. - * - * @return Returns true if the message was successfully placed in to the - * message queue. Returns false on failure, usually because the - * looper processing the message queue is exiting. Note that a - * result of true does not mean the message will be processed -- if - * the looper is quit before the delivery time of the message - * occurs then the message will be dropped. - */ - public final boolean sendMessageDelayed(Message msg, long delayMillis) - { - if (delayMillis < 0) { - delayMillis = 0; - } - return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); - } - - /** - * Enqueue a message into the message queue after all pending messages - * before the absolute time (in milliseconds) uptimeMillis. - * The time-base is {@link android.os.SystemClock#uptimeMillis}. - * Time spent in deep sleep will add an additional delay to execution. - * You will receive it in {@link #handleMessage}, in the thread attached - * to this handler. - * - * @param uptimeMillis The absolute time at which the message should be - * delivered, using the - * {@link android.os.SystemClock#uptimeMillis} time-base. - * - * @return Returns true if the message was successfully placed in to the - * message queue. Returns false on failure, usually because the - * looper processing the message queue is exiting. Note that a - * result of true does not mean the message will be processed -- if - * the looper is quit before the delivery time of the message - * occurs then the message will be dropped. - */ - public boolean sendMessageAtTime(Message msg, long uptimeMillis) { - MessageQueue queue = mQueue; - if (queue == null) { - RuntimeException e = new RuntimeException( - this + " sendMessageAtTime() called with no mQueue"); - Log.w("Looper", e.getMessage(), e); - return false; - } - return enqueueMessage(queue, msg, uptimeMillis); - } - - /** - * Enqueue a message at the front of the message queue, to be processed on - * the next iteration of the message loop. You will receive it in - * {@link #handleMessage}, in the thread attached to this handler. - * This method is only for use in very special circumstances -- it - * can easily starve the message queue, cause ordering problems, or have - * other unexpected side-effects. - * - * @return Returns true if the message was successfully placed in to the - * message queue. Returns false on failure, usually because the - * looper processing the message queue is exiting. - */ - public final boolean sendMessageAtFrontOfQueue(Message msg) { - MessageQueue queue = mQueue; - if (queue == null) { - RuntimeException e = new RuntimeException( - this + " sendMessageAtTime() called with no mQueue"); - Log.w("Looper", e.getMessage(), e); - return false; - } - return enqueueMessage(queue, msg, 0); - } - - private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { - msg.target = this; - if (mAsynchronous) { - msg.setAsynchronous(true); - } - return queue.enqueueMessage(msg, uptimeMillis); - } - - /** - * Remove any pending posts of messages with code 'what' that are in the - * message queue. - */ - public final void removeMessages(int what) { - mQueue.removeMessages(this, what, null); - } - - /** - * Remove any pending posts of messages with code 'what' and whose obj is - * 'object' that are in the message queue. If object is null, - * all messages will be removed. - */ - public final void removeMessages(int what, Object object) { - mQueue.removeMessages(this, what, object); - } - - /** - * Remove any pending posts of callbacks and sent messages whose - * obj is token. If token is null, - * all callbacks and messages will be removed. - */ - public final void removeCallbacksAndMessages(Object token) { - mQueue.removeCallbacksAndMessages(this, token); - } - - /** - * Check if there are any pending posts of messages with code 'what' in - * the message queue. - */ - public final boolean hasMessages(int what) { - return mQueue.hasMessages(this, what, null); - } - - /** - * Check if there are any pending posts of messages with code 'what' and - * whose obj is 'object' in the message queue. - */ - public final boolean hasMessages(int what, Object object) { - return mQueue.hasMessages(this, what, object); - } - - /** - * Check if there are any pending posts of messages with callback r in - * the message queue. - * - * @hide - */ - public final boolean hasCallbacks(Runnable r) { - return mQueue.hasMessages(this, r, null); - } - - // if we can get rid of this method, the handler need not remember its loop - // we could instead export a getMessageQueue() method... - public final Looper getLooper() { - return mLooper; - } - - public final void dump(Printer pw, String prefix) { - pw.println(prefix + this + " @ " + SystemClock.uptimeMillis()); - if (mLooper == null) { - pw.println(prefix + "looper uninitialized"); - } else { - mLooper.dump(pw, prefix + " "); - } - } - - @Override - public String toString() { - return "Handler (" + getClass().getName() + ") {" - + Integer.toHexString(System.identityHashCode(this)) - + "}"; - } - - final IMessenger getIMessenger() { - synchronized (mQueue) { - if (mMessenger != null) { - return mMessenger; - } - mMessenger = new MessengerImpl(); - return mMessenger; - } - } - - private final class MessengerImpl extends IMessenger.Stub { - public void send(Message msg) { - msg.sendingUid = Binder.getCallingUid(); - Handler.this.sendMessage(msg); - } - } - - private static Message getPostMessage(Runnable r) { - Message m = Message.obtain(); - m.callback = r; - return m; - } - - private static Message getPostMessage(Runnable r, Object token) { - Message m = Message.obtain(); - m.obj = token; - m.callback = r; - return m; - } - - private static void handleCallback(Message message) { - message.callback.run(); - } - - final MessageQueue mQueue; - final Looper mLooper; - final Callback mCallback; - final boolean mAsynchronous; - IMessenger mMessenger; - - private static final class BlockingRunnable implements Runnable { - private final Runnable mTask; - private boolean mDone; - - public BlockingRunnable(Runnable task) { - mTask = task; - } - - @Override - public void run() { - try { - mTask.run(); - } finally { - synchronized (this) { - mDone = true; - notifyAll(); - } - } - } - - public boolean postAndWait(Handler handler, long timeout) { - if (!handler.post(this)) { - return false; - } - - synchronized (this) { - if (timeout > 0) { - final long expirationTime = SystemClock.uptimeMillis() + timeout; - while (!mDone) { - long delay = expirationTime - SystemClock.uptimeMillis(); - if (delay <= 0) { - return false; // timeout - } - try { - wait(delay); - } catch (InterruptedException ex) { - } - } - } else { - while (!mDone) { - try { - wait(); - } catch (InterruptedException ex) { - } - } - } - } - return true; - } - } -} diff --git a/src/main/java/android/os/HandlerTester.java b/src/main/java/android/os/HandlerTester.java deleted file mode 100644 index a216a0b..0000000 --- a/src/main/java/android/os/HandlerTester.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.os.Handler; -import android.os.Looper; -import android.os.Message; - -public abstract class HandlerTester extends Thread { - public abstract void go(); - public abstract void handleMessage(Message msg); - - public HandlerTester() { - } - - public void doTest(long timeout) { - start(); - - synchronized (this) { - try { - wait(timeout); - quit(); - } - catch (InterruptedException e) { - } - } - - if (!mDone) { - throw new RuntimeException("test timed out"); - } - if (!mSuccess) { - throw new RuntimeException("test failed"); - } - } - - public void success() { - mDone = true; - mSuccess = true; - } - - public void failure() { - mDone = true; - mSuccess = false; - } - - public void run() { - Looper.prepare(); - mLooper = Looper.myLooper(); - go(); - Looper.loop(); - } - - protected class H extends Handler { - public void handleMessage(Message msg) { - synchronized (HandlerTester.this) { - // Call into them with our monitor locked, so they don't have - // to deal with other races. - HandlerTester.this.handleMessage(msg); - if (mDone) { - HandlerTester.this.notify(); - quit(); - } - } - } - } - - private void quit() { - mLooper.quit(); - } - - private boolean mDone = false; - private boolean mSuccess = false; - private Looper mLooper; -} - diff --git a/src/main/java/android/os/HandlerThread.java b/src/main/java/android/os/HandlerThread.java deleted file mode 100644 index 2904105..0000000 --- a/src/main/java/android/os/HandlerThread.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -/** - * Handy class for starting a new thread that has a looper. The looper can then be - * used to create handler classes. Note that start() must still be called. - */ -public class HandlerThread extends Thread { - int mPriority; - int mTid = -1; - Looper mLooper; - - public HandlerThread(String name) { - super(name); - mPriority = Process.THREAD_PRIORITY_DEFAULT; - } - - /** - * Constructs a HandlerThread. - * @param name - * @param priority The priority to run the thread at. The value supplied must be from - * {@link android.os.Process} and not from java.lang.Thread. - */ - public HandlerThread(String name, int priority) { - super(name); - mPriority = priority; - } - - /** - * Call back method that can be explicitly overridden if needed to execute some - * setup before Looper loops. - */ - protected void onLooperPrepared() { - } - - @Override - public void run() { - mTid = Process.myTid(); - Looper.prepare(); - synchronized (this) { - mLooper = Looper.myLooper(); - notifyAll(); - } - Process.setThreadPriority(mPriority); - onLooperPrepared(); - Looper.loop(); - mTid = -1; - } - - /** - * This method returns the Looper associated with this thread. If this thread not been started - * or for any reason is isAlive() returns false, this method will return null. If this thread - * has been started, this method will block until the looper has been initialized. - * @return The looper. - */ - public Looper getLooper() { - if (!isAlive()) { - return null; - } - - // If the thread has been started, wait until the looper has been created. - synchronized (this) { - while (isAlive() && mLooper == null) { - try { - wait(); - } catch (InterruptedException e) { - } - } - } - return mLooper; - } - - /** - * Quits the handler thread's looper. - *

- * Causes the handler thread's looper to terminate without processing any - * more messages in the message queue. - *

- * Any attempt to post messages to the queue after the looper is asked to quit will fail. - * For example, the {@link Handler#sendMessage(Message)} method will return false. - *

- * Using this method may be unsafe because some messages may not be delivered - * before the looper terminates. Consider using {@link #quitSafely} instead to ensure - * that all pending work is completed in an orderly manner. - *

- * - * @return True if the looper looper has been asked to quit or false if the - * thread had not yet started running. - * - * @see #quitSafely - */ - public boolean quit() { - Looper looper = getLooper(); - if (looper != null) { - looper.quit(); - return true; - } - return false; - } - - /** - * Quits the handler thread's looper safely. - *

- * Causes the handler thread's looper to terminate as soon as all remaining messages - * in the message queue that are already due to be delivered have been handled. - * Pending delayed messages with due times in the future will not be delivered. - *

- * Any attempt to post messages to the queue after the looper is asked to quit will fail. - * For example, the {@link Handler#sendMessage(Message)} method will return false. - *

- * If the thread has not been started or has finished (that is if - * {@link #getLooper} returns null), then false is returned. - * Otherwise the looper is asked to quit and true is returned. - *

- * - * @return True if the looper looper has been asked to quit or false if the - * thread had not yet started running. - */ - public boolean quitSafely() { - Looper looper = getLooper(); - if (looper != null) { - looper.quitSafely(); - return true; - } - return false; - } - - /** - * Returns the identifier of this thread. See Process.myTid(). - */ - public int getThreadId() { - return mTid; - } -} diff --git a/src/main/java/android/os/HandlerThreadTest.java b/src/main/java/android/os/HandlerThreadTest.java deleted file mode 100644 index 9772aa4..0000000 --- a/src/main/java/android/os/HandlerThreadTest.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import junit.framework.TestCase; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Message; -import android.os.Process; -import android.test.suitebuilder.annotation.MediumTest; -import android.test.suitebuilder.annotation.SmallTest; - -public class HandlerThreadTest extends TestCase { - private static final int TEST_WHAT = 1; - - private boolean mGotMessage = false; - private int mGotMessageWhat = -1; - private volatile boolean mDidSetup = false; - private volatile int mLooperTid = -1; - - @MediumTest - public void testHandlerThread() throws Exception { - HandlerThread th1 = new HandlerThread("HandlerThreadTest") { - protected void onLooperPrepared() { - synchronized (HandlerThreadTest.this) { - mDidSetup = true; - mLooperTid = Process.myTid(); - HandlerThreadTest.this.notify(); - } - } - }; - - assertFalse(th1.isAlive()); - assertNull(th1.getLooper()); - - th1.start(); - - assertTrue(th1.isAlive()); - assertNotNull(th1.getLooper()); - - // The call to getLooper() internally blocks until the looper is - // available, but will call onLooperPrepared() after that. So we - // need to block here to wait for our onLooperPrepared() to complete - // and fill in the values we expect. - synchronized (this) { - while (!mDidSetup) { - try { - wait(); - } catch (InterruptedException e) { - } - } - } - - // Make sure that the process was set. - assertNotSame(-1, mLooperTid); - // Make sure that the onLooperPrepared() was called on a different thread. - assertNotSame(Process.myTid(), mLooperTid); - - final Handler h1 = new Handler(th1.getLooper()) { - public void handleMessage(Message msg) { - assertEquals(TEST_WHAT, msg.what); - // Ensure that we are running on the same thread in which the looper was setup on. - assertEquals(mLooperTid, Process.myTid()); - - mGotMessageWhat = msg.what; - mGotMessage = true; - synchronized(this) { - notifyAll(); - } - } - }; - - Message msg = h1.obtainMessage(TEST_WHAT); - - synchronized (h1) { - // wait until we have the lock before sending the message. - h1.sendMessage(msg); - try { - // wait for the message to be handled - h1.wait(); - } catch (InterruptedException e) { - } - } - - assertTrue(mGotMessage); - assertEquals(TEST_WHAT, mGotMessageWhat); - } -} diff --git a/src/main/java/android/os/HandlerThread_Delegate.java b/src/main/java/android/os/HandlerThread_Delegate.java deleted file mode 100644 index afbe97c..0000000 --- a/src/main/java/android/os/HandlerThread_Delegate.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import com.android.layoutlib.bridge.android.BridgeContext; -import com.android.layoutlib.bridge.impl.RenderAction; -import com.android.tools.layoutlib.annotations.LayoutlibDelegate; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Delegate overriding selected methods of android.os.HandlerThread - * - * Through the layoutlib_create tool, selected methods of Handler have been replaced - * by calls to methods of the same name in this delegate class. - * - * - */ -public class HandlerThread_Delegate { - - private static Map> sThreads = - new HashMap>(); - - public static void cleanUp(BridgeContext context) { - List list = sThreads.get(context); - if (list != null) { - for (HandlerThread thread : list) { - thread.quit(); - } - - list.clear(); - sThreads.remove(context); - } - } - - // -------- Delegate methods - - @LayoutlibDelegate - /*package*/ static void run(HandlerThread theThread) { - // record the thread so that it can be quit() on clean up. - BridgeContext context = RenderAction.getCurrentContext(); - List list = sThreads.get(context); - if (list == null) { - list = new ArrayList(); - sThreads.put(context, list); - } - - list.add(theThread); - - // ---- START DEFAULT IMPLEMENTATION. - - theThread.mTid = Process.myTid(); - Looper.prepare(); - synchronized (theThread) { - theThread.mLooper = Looper.myLooper(); - theThread.notifyAll(); - } - Process.setThreadPriority(theThread.mPriority); - theThread.onLooperPrepared(); - Looper.loop(); - theThread.mTid = -1; - } -} diff --git a/src/main/java/android/os/Handler_Delegate.java b/src/main/java/android/os/Handler_Delegate.java deleted file mode 100644 index 2152c8a..0000000 --- a/src/main/java/android/os/Handler_Delegate.java +++ /dev/null @@ -1,57 +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.os; - -import com.android.tools.layoutlib.annotations.LayoutlibDelegate; - - -/** - * Delegate overriding selected methods of android.os.Handler - * - * Through the layoutlib_create tool, selected methods of Handler have been replaced - * by calls to methods of the same name in this delegate class. - * - * - */ -public class Handler_Delegate { - - // -------- Delegate methods - - @LayoutlibDelegate - /*package*/ static boolean sendMessageAtTime(Handler handler, Message msg, long uptimeMillis) { - // get the callback - IHandlerCallback callback = sCallbacks.get(); - if (callback != null) { - callback.sendMessageAtTime(handler, msg, uptimeMillis); - } - return true; - } - - // -------- Delegate implementation - - public interface IHandlerCallback { - void sendMessageAtTime(Handler handler, Message msg, long uptimeMillis); - } - - private final static ThreadLocal sCallbacks = - new ThreadLocal(); - - public static void setCallback(IHandlerCallback callback) { - sCallbacks.set(callback); - } - -} diff --git a/src/main/java/android/os/IBinder.java b/src/main/java/android/os/IBinder.java deleted file mode 100644 index 73a0f65..0000000 --- a/src/main/java/android/os/IBinder.java +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import java.io.FileDescriptor; - -/** - * Base interface for a remotable object, the core part of a lightweight - * remote procedure call mechanism designed for high performance when - * performing in-process and cross-process calls. This - * interface describes the abstract protocol for interacting with a - * remotable object. Do not implement this interface directly, instead - * extend from {@link Binder}. - * - *

The key IBinder API is {@link #transact transact()} matched by - * {@link Binder#onTransact Binder.onTransact()}. These - * methods allow you to send a call to an IBinder object and receive a - * call coming in to a Binder object, respectively. This transaction API - * is synchronous, such that a call to {@link #transact transact()} does not - * return until the target has returned from - * {@link Binder#onTransact Binder.onTransact()}; this is the - * expected behavior when calling an object that exists in the local - * process, and the underlying inter-process communication (IPC) mechanism - * ensures that these same semantics apply when going across processes. - * - *

The data sent through transact() is a {@link Parcel}, a generic buffer - * of data that also maintains some meta-data about its contents. The meta - * data is used to manage IBinder object references in the buffer, so that those - * references can be maintained as the buffer moves across processes. This - * mechanism ensures that when an IBinder is written into a Parcel and sent to - * another process, if that other process sends a reference to that same IBinder - * back to the original process, then the original process will receive the - * same IBinder object back. These semantics allow IBinder/Binder objects to - * be used as a unique identity (to serve as a token or for other purposes) - * that can be managed across processes. - * - *

The system maintains a pool of transaction threads in each process that - * it runs in. These threads are used to dispatch all - * IPCs coming in from other processes. For example, when an IPC is made from - * process A to process B, the calling thread in A blocks in transact() as - * it sends the transaction to process B. The next available pool thread in - * B receives the incoming transaction, calls Binder.onTransact() on the target - * object, and replies with the result Parcel. Upon receiving its result, the - * thread in process A returns to allow its execution to continue. In effect, - * other processes appear to use as additional threads that you did not create - * executing in your own process. - * - *

The Binder system also supports recursion across processes. For example - * if process A performs a transaction to process B, and process B while - * handling that transaction calls transact() on an IBinder that is implemented - * in A, then the thread in A that is currently waiting for the original - * transaction to finish will take care of calling Binder.onTransact() on the - * object being called by B. This ensures that the recursion semantics when - * calling remote binder object are the same as when calling local objects. - * - *

When working with remote objects, you often want to find out when they - * are no longer valid. There are three ways this can be determined: - *

    - *
  • The {@link #transact transact()} method will throw a - * {@link RemoteException} exception if you try to call it on an IBinder - * whose process no longer exists. - *
  • The {@link #pingBinder()} method can be called, and will return false - * if the remote process no longer exists. - *
  • The {@link #linkToDeath linkToDeath()} method can be used to register - * a {@link DeathRecipient} with the IBinder, which will be called when its - * containing process goes away. - *
- * - * @see Binder - */ -public interface IBinder { - /** - * The first transaction code available for user commands. - */ - int FIRST_CALL_TRANSACTION = 0x00000001; - /** - * The last transaction code available for user commands. - */ - int LAST_CALL_TRANSACTION = 0x00ffffff; - - /** - * IBinder protocol transaction code: pingBinder(). - */ - int PING_TRANSACTION = ('_'<<24)|('P'<<16)|('N'<<8)|'G'; - - /** - * IBinder protocol transaction code: dump internal state. - */ - int DUMP_TRANSACTION = ('_'<<24)|('D'<<16)|('M'<<8)|'P'; - - /** - * IBinder protocol transaction code: interrogate the recipient side - * of the transaction for its canonical interface descriptor. - */ - int INTERFACE_TRANSACTION = ('_'<<24)|('N'<<16)|('T'<<8)|'F'; - - /** - * IBinder protocol transaction code: send a tweet to the target - * object. The data in the parcel is intended to be delivered to - * a shared messaging service associated with the object; it can be - * anything, as long as it is not more than 130 UTF-8 characters to - * conservatively fit within common messaging services. As part of - * {@link Build.VERSION_CODES#HONEYCOMB_MR2}, all Binder objects are - * expected to support this protocol for fully integrated tweeting - * across the platform. To support older code, the default implementation - * logs the tweet to the main log as a simple emulation of broadcasting - * it publicly over the Internet. - * - *

Also, upon completing the dispatch, the object must make a cup - * of tea, return it to the caller, and exclaim "jolly good message - * old boy!". - */ - int TWEET_TRANSACTION = ('_'<<24)|('T'<<16)|('W'<<8)|'T'; - - /** - * IBinder protocol transaction code: tell an app asynchronously that the - * caller likes it. The app is responsible for incrementing and maintaining - * its own like counter, and may display this value to the user to indicate the - * quality of the app. This is an optional command that applications do not - * need to handle, so the default implementation is to do nothing. - * - *

There is no response returned and nothing about the - * system will be functionally affected by it, but it will improve the - * app's self-esteem. - */ - int LIKE_TRANSACTION = ('_'<<24)|('L'<<16)|('I'<<8)|'K'; - - /** @hide */ - int SYSPROPS_TRANSACTION = ('_'<<24)|('S'<<16)|('P'<<8)|'R'; - - /** - * Flag to {@link #transact}: this is a one-way call, meaning that the - * caller returns immediately, without waiting for a result from the - * callee. Applies only if the caller and callee are in different - * processes. - */ - int FLAG_ONEWAY = 0x00000001; - - /** - * Get the canonical name of the interface supported by this binder. - */ - public String getInterfaceDescriptor() throws RemoteException; - - /** - * Check to see if the object still exists. - * - * @return Returns false if the - * hosting process is gone, otherwise the result (always by default - * true) returned by the pingBinder() implementation on the other - * side. - */ - public boolean pingBinder(); - - /** - * Check to see if the process that the binder is in is still alive. - * - * @return false if the process is not alive. Note that if it returns - * true, the process may have died while the call is returning. - */ - public boolean isBinderAlive(); - - /** - * Attempt to retrieve a local implementation of an interface - * for this Binder object. If null is returned, you will need - * to instantiate a proxy class to marshall calls through - * the transact() method. - */ - public IInterface queryLocalInterface(String descriptor); - - /** - * Print the object's state into the given stream. - * - * @param fd The raw file descriptor that the dump is being sent to. - * @param args additional arguments to the dump request. - */ - public void dump(FileDescriptor fd, String[] args) throws RemoteException; - - /** - * Like {@link #dump(FileDescriptor, String[])} but always executes - * asynchronously. If the object is local, a new thread is created - * to perform the dump. - * - * @param fd The raw file descriptor that the dump is being sent to. - * @param args additional arguments to the dump request. - */ - public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException; - - /** - * Perform a generic operation with the object. - * - * @param code The action to perform. This should - * be a number between {@link #FIRST_CALL_TRANSACTION} and - * {@link #LAST_CALL_TRANSACTION}. - * @param data Marshalled data to send to the target. Must not be null. - * If you are not sending any data, you must create an empty Parcel - * that is given here. - * @param reply Marshalled data to be received from the target. May be - * null if you are not interested in the return value. - * @param flags Additional operation flags. Either 0 for a normal - * RPC, or {@link #FLAG_ONEWAY} for a one-way RPC. - */ - public boolean transact(int code, Parcel data, Parcel reply, int flags) - throws RemoteException; - - /** - * Interface for receiving a callback when the process hosting an IBinder - * has gone away. - * - * @see #linkToDeath - */ - public interface DeathRecipient { - public void binderDied(); - } - - /** - * Register the recipient for a notification if this binder - * goes away. If this binder object unexpectedly goes away - * (typically because its hosting process has been killed), - * then the given {@link DeathRecipient}'s - * {@link DeathRecipient#binderDied DeathRecipient.binderDied()} method - * will be called. - * - *

You will only receive death notifications for remote binders, - * as local binders by definition can't die without you dying as well. - * - * @throws RemoteException if the target IBinder's - * process has already died. - * - * @see #unlinkToDeath - */ - public void linkToDeath(DeathRecipient recipient, int flags) - throws RemoteException; - - /** - * Remove a previously registered death notification. - * The recipient will no longer be called if this object - * dies. - * - * @return {@code true} if the recipient is successfully - * unlinked, assuring you that its - * {@link DeathRecipient#binderDied DeathRecipient.binderDied()} method - * will not be called; {@code false} if the target IBinder has already - * died, meaning the method has been (or soon will be) called. - * - * @throws java.util.NoSuchElementException if the given - * recipient has not been registered with the IBinder, and - * the IBinder is still alive. Note that if the recipient - * was never registered, but the IBinder has already died, then this - * exception will not be thrown, and you will receive a false - * return value instead. - */ - public boolean unlinkToDeath(DeathRecipient recipient, int flags); -} diff --git a/src/main/java/android/os/IInterface.java b/src/main/java/android/os/IInterface.java deleted file mode 100644 index 2a2605a..0000000 --- a/src/main/java/android/os/IInterface.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -/** - * Base class for Binder interfaces. When defining a new interface, - * you must derive it from IInterface. - */ -public interface IInterface -{ - /** - * Retrieve the Binder object associated with this interface. - * You must use this instead of a plain cast, so that proxy objects - * can return the correct result. - */ - public IBinder asBinder(); -} diff --git a/src/main/java/android/os/IServiceManager.java b/src/main/java/android/os/IServiceManager.java deleted file mode 100644 index 7b11c28..0000000 --- a/src/main/java/android/os/IServiceManager.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -/** - * Basic interface for finding and publishing system services. - * - * An implementation of this interface is usually published as the - * global context object, which can be retrieved via - * BinderNative.getContextObject(). An easy way to retrieve this - * is with the static method BnServiceManager.getDefault(). - * - * @hide - */ -public interface IServiceManager extends IInterface -{ - /** - * Retrieve an existing service called @a name from the - * service manager. Blocks for a few seconds waiting for it to be - * published if it does not already exist. - */ - public IBinder getService(String name) throws RemoteException; - - /** - * Retrieve an existing service called @a name from the - * service manager. Non-blocking. - */ - public IBinder checkService(String name) throws RemoteException; - - /** - * Place a new @a service called @a name into the service - * manager. - */ - public void addService(String name, IBinder service, boolean allowIsolated) - throws RemoteException; - - /** - * Return a list of all currently running services. - */ - public String[] listServices() throws RemoteException; - - /** - * Assign a permission controller to the service manager. After set, this - * interface is checked before any services are added. - */ - public void setPermissionController(IPermissionController controller) - throws RemoteException; - - static final String descriptor = "android.os.IServiceManager"; - - int GET_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION; - int CHECK_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+1; - int ADD_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+2; - int LIST_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+3; - int CHECK_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+4; - int SET_PERMISSION_CONTROLLER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+5; -} diff --git a/src/main/java/android/os/IdleHandlerTest.java b/src/main/java/android/os/IdleHandlerTest.java deleted file mode 100644 index 6c0a862..0000000 --- a/src/main/java/android/os/IdleHandlerTest.java +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.os.MessageQueue.IdleHandler; -import android.test.suitebuilder.annotation.MediumTest; -import junit.framework.TestCase; - -public class IdleHandlerTest extends TestCase { - - private static class BaseTestHandler extends TestHandlerThread { - Handler mHandler; - - public BaseTestHandler() { - } - - public void go() { - mHandler = new Handler() { - public void handleMessage(Message msg) { - BaseTestHandler.this.handleMessage(msg); - } - }; - } - - public void addIdleHandler() { - Looper.myQueue().addIdleHandler(new IdleHandler() { - public boolean queueIdle() { - return BaseTestHandler.this.queueIdle(); - } - }); - } - - public void handleMessage(Message msg) { - } - - public boolean queueIdle() { - return false; - } - } - - @MediumTest - public void testOneShotFirst() throws Exception { - TestHandlerThread tester = new BaseTestHandler() { - int mCount; - - public void go() { - super.go(); - mCount = 0; - mHandler.sendMessageDelayed(mHandler.obtainMessage(0), 100); - addIdleHandler(); - } - - public void handleMessage(Message msg) { - if (msg.what == 0) { - mHandler.sendMessageDelayed(mHandler.obtainMessage(1), 100); - } else if (msg.what == 1) { - if (mCount == 1) { - success(); - } else { - failure(new RuntimeException( - "Idle handler called " + mCount + " times")); - } - } - } - - public boolean queueIdle() { - mCount++; - return false; - } - }; - - tester.doTest(1000); - } - - @MediumTest - public void testOneShotLater() throws Exception { - TestHandlerThread tester = new BaseTestHandler() { - int mCount; - - public void go() { - super.go(); - mCount = 0; - mHandler.sendMessage(mHandler.obtainMessage(0)); - } - - public void handleMessage(Message msg) { - if (msg.what == 0) { - addIdleHandler(); - mHandler.sendMessageDelayed(mHandler.obtainMessage(1), 100); - } else if (msg.what == 1) { - mHandler.sendMessageDelayed(mHandler.obtainMessage(2), 100); - } else if (msg.what == 2) { - if (mCount == 1) { - success(); - } else { - failure(new RuntimeException( - "Idle handler called " + mCount + " times")); - } - } - } - - public boolean queueIdle() { - mCount++; - return false; - } - }; - - tester.doTest(1000); - } - - - @MediumTest - public void testRepeatedFirst() throws Exception { - TestHandlerThread tester = new BaseTestHandler() { - int mCount; - - public void go() { - super.go(); - mCount = 0; - mHandler.sendMessageDelayed(mHandler.obtainMessage(0), 100); - addIdleHandler(); - } - - public void handleMessage(Message msg) { - if (msg.what == 0) { - mHandler.sendMessageDelayed(mHandler.obtainMessage(1), 100); - } else if (msg.what == 1) { - if (mCount == 2) { - success(); - } else { - failure(new RuntimeException( - "Idle handler called " + mCount + " times")); - } - } - } - - public boolean queueIdle() { - mCount++; - return true; - } - }; - - tester.doTest(1000); - } - - @MediumTest - public void testRepeatedLater() throws Exception { - TestHandlerThread tester = new BaseTestHandler() { - int mCount; - - public void go() { - super.go(); - mCount = 0; - mHandler.sendMessage(mHandler.obtainMessage(0)); - } - - public void handleMessage(Message msg) { - if (msg.what == 0) { - addIdleHandler(); - mHandler.sendMessageDelayed(mHandler.obtainMessage(1), 100); - } else if (msg.what == 1) { - mHandler.sendMessageDelayed(mHandler.obtainMessage(2), 100); - } else if (msg.what == 2) { - if (mCount == 2) { - success(); - } else { - failure(new RuntimeException( - "Idle handler called " + mCount + " times")); - } - } - } - - public boolean queueIdle() { - mCount++; - return true; - } - }; - - tester.doTest(1000); - } -} - diff --git a/src/main/java/android/os/InputMethodSubtypeArrayTest.java b/src/main/java/android/os/InputMethodSubtypeArrayTest.java deleted file mode 100644 index 1e0a919..0000000 --- a/src/main/java/android/os/InputMethodSubtypeArrayTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.test.InstrumentationTestCase; -import android.test.suitebuilder.annotation.SmallTest; -import android.view.inputmethod.InputMethodSubtype; -import android.view.inputmethod.InputMethodSubtypeArray; -import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder; - -import java.util.ArrayList; - -public class InputMethodSubtypeArrayTest extends InstrumentationTestCase { - @SmallTest - public void testInstanciate() throws Exception { - final ArrayList subtypes = new ArrayList(); - subtypes.add(createDummySubtype(0, "en_US")); - subtypes.add(createDummySubtype(1, "en_US")); - subtypes.add(createDummySubtype(2, "ja_JP")); - - final InputMethodSubtypeArray array = new InputMethodSubtypeArray(subtypes); - assertEquals(subtypes.size(), array.getCount()); - assertEquals(subtypes.get(0), array.get(0)); - assertEquals(subtypes.get(1), array.get(1)); - assertEquals(subtypes.get(2), array.get(2)); - - final InputMethodSubtypeArray clonedArray = cloneViaParcel(array); - assertEquals(subtypes.size(), clonedArray.getCount()); - assertEquals(subtypes.get(0), clonedArray.get(0)); - assertEquals(subtypes.get(1), clonedArray.get(1)); - assertEquals(subtypes.get(2), clonedArray.get(2)); - - final InputMethodSubtypeArray clonedClonedArray = cloneViaParcel(clonedArray); - assertEquals(clonedArray.getCount(), clonedClonedArray.getCount()); - assertEquals(clonedArray.get(0), clonedClonedArray.get(0)); - assertEquals(clonedArray.get(1), clonedClonedArray.get(1)); - assertEquals(clonedArray.get(2), clonedClonedArray.get(2)); - } - - InputMethodSubtypeArray cloneViaParcel(final InputMethodSubtypeArray original) { - Parcel parcel = null; - try { - parcel = Parcel.obtain(); - original.writeToParcel(parcel); - parcel.setDataPosition(0); - return new InputMethodSubtypeArray(parcel); - } finally { - if (parcel != null) { - parcel.recycle(); - } - } - } - - private static InputMethodSubtype createDummySubtype(final int id, final String locale) { - final InputMethodSubtypeBuilder builder = new InputMethodSubtypeBuilder(); - return builder.setSubtypeNameResId(0) - .setSubtypeIconResId(0) - .setSubtypeId(id) - .setSubtypeLocale(locale) - .setIsAsciiCapable(true) - .build(); - } -} diff --git a/src/main/java/android/os/InputMethodSubtypeSwitchingControllerTest.java b/src/main/java/android/os/InputMethodSubtypeSwitchingControllerTest.java deleted file mode 100644 index 3a598f2..0000000 --- a/src/main/java/android/os/InputMethodSubtypeSwitchingControllerTest.java +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.content.pm.ApplicationInfo; -import android.content.pm.ResolveInfo; -import android.content.pm.ServiceInfo; -import android.test.InstrumentationTestCase; -import android.test.suitebuilder.annotation.SmallTest; -import android.view.inputmethod.InputMethodInfo; -import android.view.inputmethod.InputMethodSubtype; -import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder; - -import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ControllerImpl; -import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem; -import com.android.internal.inputmethod.InputMethodUtils; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -public class InputMethodSubtypeSwitchingControllerTest extends InstrumentationTestCase { - private static final String DUMMY_PACKAGE_NAME = "dymmy package name"; - private static final String DUMMY_SETTING_ACTIVITY_NAME = ""; - private static final boolean DUMMY_IS_AUX_IME = false; - private static final boolean DUMMY_FORCE_DEFAULT = false; - private static final int DUMMY_IS_DEFAULT_RES_ID = 0; - private static final String SYSTEM_LOCALE = "en_US"; - private static final int NOT_A_SUBTYPE_ID = InputMethodUtils.NOT_A_SUBTYPE_ID; - - private static InputMethodSubtype createDummySubtype(final String locale) { - final InputMethodSubtypeBuilder builder = new InputMethodSubtypeBuilder(); - return builder.setSubtypeNameResId(0) - .setSubtypeIconResId(0) - .setSubtypeLocale(locale) - .setIsAsciiCapable(true) - .build(); - } - - private static void addDummyImeSubtypeListItems(List items, - String imeName, String imeLabel, List subtypeLocales, - boolean supportsSwitchingToNextInputMethod) { - final ResolveInfo ri = new ResolveInfo(); - final ServiceInfo si = new ServiceInfo(); - final ApplicationInfo ai = new ApplicationInfo(); - ai.packageName = DUMMY_PACKAGE_NAME; - ai.enabled = true; - si.applicationInfo = ai; - si.enabled = true; - si.packageName = DUMMY_PACKAGE_NAME; - si.name = imeName; - si.exported = true; - si.nonLocalizedLabel = imeLabel; - ri.serviceInfo = si; - List subtypes = null; - if (subtypeLocales != null) { - subtypes = new ArrayList(); - for (String subtypeLocale : subtypeLocales) { - subtypes.add(createDummySubtype(subtypeLocale)); - } - } - final InputMethodInfo imi = new InputMethodInfo(ri, DUMMY_IS_AUX_IME, - DUMMY_SETTING_ACTIVITY_NAME, subtypes, DUMMY_IS_DEFAULT_RES_ID, - DUMMY_FORCE_DEFAULT, supportsSwitchingToNextInputMethod); - if (subtypes == null) { - items.add(new ImeSubtypeListItem(imeName, null /* variableName */, imi, - NOT_A_SUBTYPE_ID, null, SYSTEM_LOCALE)); - } else { - for (int i = 0; i < subtypes.size(); ++i) { - final String subtypeLocale = subtypeLocales.get(i); - items.add(new ImeSubtypeListItem(imeName, subtypeLocale, imi, i, subtypeLocale, - SYSTEM_LOCALE)); - } - } - } - - private static List createEnabledImeSubtypes() { - final List items = new ArrayList(); - addDummyImeSubtypeListItems(items, "LatinIme", "LatinIme", Arrays.asList("en_US", "fr"), - true /* supportsSwitchingToNextInputMethod*/); - addDummyImeSubtypeListItems(items, "switchUnawareLatinIme", "switchUnawareLatinIme", - Arrays.asList("en_UK", "hi"), - false /* supportsSwitchingToNextInputMethod*/); - addDummyImeSubtypeListItems(items, "subtypeUnawareIme", "subtypeUnawareIme", null, - false /* supportsSwitchingToNextInputMethod*/); - addDummyImeSubtypeListItems(items, "JapaneseIme", "JapaneseIme", Arrays.asList("ja_JP"), - true /* supportsSwitchingToNextInputMethod*/); - addDummyImeSubtypeListItems(items, "switchUnawareJapaneseIme", "switchUnawareJapaneseIme", - Arrays.asList("ja_JP"), false /* supportsSwitchingToNextInputMethod*/); - return items; - } - - private static List createDisabledImeSubtypes() { - final List items = new ArrayList(); - addDummyImeSubtypeListItems(items, - "UnknownIme", "UnknownIme", - Arrays.asList("en_US", "hi"), - true /* supportsSwitchingToNextInputMethod*/); - addDummyImeSubtypeListItems(items, - "UnknownSwitchingUnawareIme", "UnknownSwitchingUnawareIme", - Arrays.asList("en_US"), - false /* supportsSwitchingToNextInputMethod*/); - addDummyImeSubtypeListItems(items, "UnknownSubtypeUnawareIme", - "UnknownSubtypeUnawareIme", null, - false /* supportsSwitchingToNextInputMethod*/); - return items; - } - - private void assertNextInputMethod(final ControllerImpl controller, - final boolean onlyCurrentIme, - final ImeSubtypeListItem currentItem, final ImeSubtypeListItem nextItem) { - InputMethodSubtype subtype = null; - if (currentItem.mSubtypeName != null) { - subtype = createDummySubtype(currentItem.mSubtypeName.toString()); - } - final ImeSubtypeListItem nextIme = controller.getNextInputMethod(onlyCurrentIme, - currentItem.mImi, subtype); - assertEquals(nextItem, nextIme); - } - - private void assertRotationOrder(final ControllerImpl controller, - final boolean onlyCurrentIme, - final ImeSubtypeListItem... expectedRotationOrderOfImeSubtypeList) { - final int N = expectedRotationOrderOfImeSubtypeList.length; - for (int i = 0; i < N; i++) { - final int currentIndex = i; - final int nextIndex = (currentIndex + 1) % N; - final ImeSubtypeListItem currentItem = - expectedRotationOrderOfImeSubtypeList[currentIndex]; - final ImeSubtypeListItem nextItem = expectedRotationOrderOfImeSubtypeList[nextIndex]; - assertNextInputMethod(controller, onlyCurrentIme, currentItem, nextItem); - } - } - - private void onUserAction(final ControllerImpl controller, - final ImeSubtypeListItem subtypeListItem) { - InputMethodSubtype subtype = null; - if (subtypeListItem.mSubtypeName != null) { - subtype = createDummySubtype(subtypeListItem.mSubtypeName.toString()); - } - controller.onUserActionLocked(subtypeListItem.mImi, subtype); - } - - @SmallTest - public void testControllerImpl() throws Exception { - final List disabledItems = createDisabledImeSubtypes(); - final ImeSubtypeListItem disabledIme_en_US = disabledItems.get(0); - final ImeSubtypeListItem disabledIme_hi = disabledItems.get(1); - final ImeSubtypeListItem disabledSwitchingUnawareIme = disabledItems.get(2); - final ImeSubtypeListItem disabledSubtypeUnawareIme = disabledItems.get(3); - - final List enabledItems = createEnabledImeSubtypes(); - final ImeSubtypeListItem latinIme_en_US = enabledItems.get(0); - final ImeSubtypeListItem latinIme_fr = enabledItems.get(1); - final ImeSubtypeListItem switchingUnawarelatinIme_en_UK = enabledItems.get(2); - final ImeSubtypeListItem switchingUnawarelatinIme_hi = enabledItems.get(3); - final ImeSubtypeListItem subtypeUnawareIme = enabledItems.get(4); - final ImeSubtypeListItem japaneseIme_ja_JP = enabledItems.get(5); - final ImeSubtypeListItem switchUnawareJapaneseIme_ja_JP = enabledItems.get(6); - - final ControllerImpl controller = ControllerImpl.createFrom( - null /* currentInstance */, enabledItems); - - // switching-aware loop - assertRotationOrder(controller, false /* onlyCurrentIme */, - latinIme_en_US, latinIme_fr, japaneseIme_ja_JP); - - // switching-unaware loop - assertRotationOrder(controller, false /* onlyCurrentIme */, - switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme, - switchUnawareJapaneseIme_ja_JP); - - // test onlyCurrentIme == true - assertRotationOrder(controller, true /* onlyCurrentIme */, - latinIme_en_US, latinIme_fr); - assertRotationOrder(controller, true /* onlyCurrentIme */, - switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi); - assertNextInputMethod(controller, true /* onlyCurrentIme */, - subtypeUnawareIme, null); - assertNextInputMethod(controller, true /* onlyCurrentIme */, - japaneseIme_ja_JP, null); - assertNextInputMethod(controller, true /* onlyCurrentIme */, - switchUnawareJapaneseIme_ja_JP, null); - - // Make sure that disabled IMEs are not accepted. - assertNextInputMethod(controller, false /* onlyCurrentIme */, - disabledIme_en_US, null); - assertNextInputMethod(controller, false /* onlyCurrentIme */, - disabledIme_hi, null); - assertNextInputMethod(controller, false /* onlyCurrentIme */, - disabledSwitchingUnawareIme, null); - assertNextInputMethod(controller, false /* onlyCurrentIme */, - disabledSubtypeUnawareIme, null); - assertNextInputMethod(controller, true /* onlyCurrentIme */, - disabledIme_en_US, null); - assertNextInputMethod(controller, true /* onlyCurrentIme */, - disabledIme_hi, null); - assertNextInputMethod(controller, true /* onlyCurrentIme */, - disabledSwitchingUnawareIme, null); - assertNextInputMethod(controller, true /* onlyCurrentIme */, - disabledSubtypeUnawareIme, null); - } - - @SmallTest - public void testControllerImplWithUserAction() throws Exception { - final List enabledItems = createEnabledImeSubtypes(); - final ImeSubtypeListItem latinIme_en_US = enabledItems.get(0); - final ImeSubtypeListItem latinIme_fr = enabledItems.get(1); - final ImeSubtypeListItem switchingUnawarelatinIme_en_UK = enabledItems.get(2); - final ImeSubtypeListItem switchingUnawarelatinIme_hi = enabledItems.get(3); - final ImeSubtypeListItem subtypeUnawareIme = enabledItems.get(4); - final ImeSubtypeListItem japaneseIme_ja_JP = enabledItems.get(5); - final ImeSubtypeListItem switchUnawareJapaneseIme_ja_JP = enabledItems.get(6); - - final ControllerImpl controller = ControllerImpl.createFrom( - null /* currentInstance */, enabledItems); - - // === switching-aware loop === - assertRotationOrder(controller, false /* onlyCurrentIme */, - latinIme_en_US, latinIme_fr, japaneseIme_ja_JP); - // Then notify that a user did something for latinIme_fr. - onUserAction(controller, latinIme_fr); - assertRotationOrder(controller, false /* onlyCurrentIme */, - latinIme_fr, latinIme_en_US, japaneseIme_ja_JP); - // Then notify that a user did something for latinIme_fr again. - onUserAction(controller, latinIme_fr); - assertRotationOrder(controller, false /* onlyCurrentIme */, - latinIme_fr, latinIme_en_US, japaneseIme_ja_JP); - // Then notify that a user did something for japaneseIme_ja_JP. - onUserAction(controller, latinIme_fr); - assertRotationOrder(controller, false /* onlyCurrentIme */, - japaneseIme_ja_JP, latinIme_fr, latinIme_en_US); - // Check onlyCurrentIme == true. - assertNextInputMethod(controller, true /* onlyCurrentIme */, - japaneseIme_ja_JP, null); - assertRotationOrder(controller, true /* onlyCurrentIme */, - latinIme_fr, latinIme_en_US); - assertRotationOrder(controller, true /* onlyCurrentIme */, - latinIme_en_US, latinIme_fr); - - // === switching-unaware loop === - assertRotationOrder(controller, false /* onlyCurrentIme */, - switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme, - switchUnawareJapaneseIme_ja_JP); - // User action should be ignored for switching unaware IMEs. - onUserAction(controller, switchingUnawarelatinIme_hi); - assertRotationOrder(controller, false /* onlyCurrentIme */, - switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme, - switchUnawareJapaneseIme_ja_JP); - // User action should be ignored for switching unaware IMEs. - onUserAction(controller, switchUnawareJapaneseIme_ja_JP); - assertRotationOrder(controller, false /* onlyCurrentIme */, - switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme, - switchUnawareJapaneseIme_ja_JP); - // Check onlyCurrentIme == true. - assertRotationOrder(controller, true /* onlyCurrentIme */, - switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi); - assertNextInputMethod(controller, true /* onlyCurrentIme */, - subtypeUnawareIme, null); - assertNextInputMethod(controller, true /* onlyCurrentIme */, - switchUnawareJapaneseIme_ja_JP, null); - - // Rotation order should be preserved when created with the same subtype list. - final List sameEnabledItems = createEnabledImeSubtypes(); - final ControllerImpl newController = ControllerImpl.createFrom(controller, - sameEnabledItems); - assertRotationOrder(newController, false /* onlyCurrentIme */, - japaneseIme_ja_JP, latinIme_fr, latinIme_en_US); - assertRotationOrder(newController, false /* onlyCurrentIme */, - switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme, - switchUnawareJapaneseIme_ja_JP); - - // Rotation order should be initialized when created with a different subtype list. - final List differentEnabledItems = Arrays.asList( - latinIme_en_US, latinIme_fr, switchingUnawarelatinIme_en_UK, - switchUnawareJapaneseIme_ja_JP); - final ControllerImpl anotherController = ControllerImpl.createFrom(controller, - differentEnabledItems); - assertRotationOrder(anotherController, false /* onlyCurrentIme */, - latinIme_en_US, latinIme_fr); - assertRotationOrder(anotherController, false /* onlyCurrentIme */, - switchingUnawarelatinIme_en_UK, switchUnawareJapaneseIme_ja_JP); - } - - @SmallTest - public void testImeSubtypeListItem() throws Exception { - final List items = new ArrayList(); - addDummyImeSubtypeListItems(items, "LatinIme", "LatinIme", - Arrays.asList("en_US", "fr", "en", "en_uk", "enn", "e", "EN_US"), - true /* supportsSwitchingToNextInputMethod*/); - final ImeSubtypeListItem item_en_US = items.get(0); - final ImeSubtypeListItem item_fr = items.get(1); - final ImeSubtypeListItem item_en = items.get(2); - final ImeSubtypeListItem item_enn = items.get(3); - final ImeSubtypeListItem item_e = items.get(4); - final ImeSubtypeListItem item_EN_US = items.get(5); - - assertTrue(item_en_US.mIsSystemLocale); - assertFalse(item_fr.mIsSystemLocale); - assertFalse(item_en.mIsSystemLocale); - assertFalse(item_en.mIsSystemLocale); - assertFalse(item_enn.mIsSystemLocale); - assertFalse(item_e.mIsSystemLocale); - assertFalse(item_EN_US.mIsSystemLocale); - - assertTrue(item_en_US.mIsSystemLanguage); - assertFalse(item_fr.mIsSystemLanguage); - assertTrue(item_en.mIsSystemLanguage); - assertFalse(item_enn.mIsSystemLocale); - assertFalse(item_e.mIsSystemLocale); - assertFalse(item_EN_US.mIsSystemLocale); - } -} diff --git a/src/main/java/android/os/InputMethodSubtypeTest.java b/src/main/java/android/os/InputMethodSubtypeTest.java deleted file mode 100644 index 323a360..0000000 --- a/src/main/java/android/os/InputMethodSubtypeTest.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.test.InstrumentationTestCase; -import android.test.suitebuilder.annotation.SmallTest; -import android.view.inputmethod.InputMethodSubtype; -import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder; - -import java.util.Objects; - -public class InputMethodSubtypeTest extends InstrumentationTestCase { - - public void verifyLocale(final String localeString) { - // InputMethodSubtype#getLocale() returns exactly the same string that is passed to the - // constructor. - assertEquals(localeString, createDummySubtype(localeString).getLocale()); - - // InputMethodSubtype#getLocale() should be preserved via marshaling. - assertEquals(createDummySubtype(localeString).getLocale(), - cloneViaParcel(createDummySubtype(localeString)).getLocale()); - - // InputMethodSubtype#getLocale() should be preserved via marshaling. - assertEquals(createDummySubtype(localeString).getLocale(), - cloneViaParcel(cloneViaParcel(createDummySubtype(localeString))).getLocale()); - - // Make sure InputMethodSubtype#hashCode() returns the same hash code. - assertEquals(createDummySubtype(localeString).hashCode(), - createDummySubtype(localeString).hashCode()); - assertEquals(createDummySubtype(localeString).hashCode(), - cloneViaParcel(createDummySubtype(localeString)).hashCode()); - assertEquals(createDummySubtype(localeString).hashCode(), - cloneViaParcel(cloneViaParcel(createDummySubtype(localeString))).hashCode()); - } - - @SmallTest - public void testLocaleString() throws Exception { - // The locale string in InputMethodSubtype has accepted an arbitrary text actually, - // regardless of the validity of the text as a locale string. - verifyLocale("en_US"); - verifyLocale("apparently invalid locale string"); - verifyLocale("zz"); - verifyLocale("iw"); - verifyLocale("he"); - } - - @SmallTest - public void testDeprecatedLocaleString() throws Exception { - // Make sure "iw" is not automatically replaced with "he". - final InputMethodSubtype subtypeIw = createDummySubtype("iw"); - final InputMethodSubtype subtypeHe = createDummySubtype("he"); - assertEquals("iw", subtypeIw.getLocale()); - assertEquals("he", subtypeHe.getLocale()); - assertFalse(Objects.equals(subtypeIw, subtypeHe)); - assertFalse(Objects.equals(subtypeIw.hashCode(), subtypeHe.hashCode())); - - final InputMethodSubtype clonedSubtypeIw = cloneViaParcel(subtypeIw); - final InputMethodSubtype clonedSubtypeHe = cloneViaParcel(subtypeHe); - assertEquals(subtypeIw, clonedSubtypeIw); - assertEquals(subtypeHe, clonedSubtypeHe); - assertEquals("iw", clonedSubtypeIw.getLocale()); - assertEquals("he", clonedSubtypeHe.getLocale()); - } - - private static final InputMethodSubtype cloneViaParcel(final InputMethodSubtype original) { - Parcel parcel = null; - try { - parcel = Parcel.obtain(); - original.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - return InputMethodSubtype.CREATOR.createFromParcel(parcel); - } finally { - if (parcel != null) { - parcel.recycle(); - } - } - } - - private static final InputMethodSubtype createDummySubtype(final String locale) { - final InputMethodSubtypeBuilder builder = new InputMethodSubtypeBuilder(); - return builder.setSubtypeNameResId(0) - .setSubtypeIconResId(0) - .setSubtypeLocale(locale) - .setIsAsciiCapable(true) - .build(); - } -} diff --git a/src/main/java/android/os/InputMethodTest.java b/src/main/java/android/os/InputMethodTest.java deleted file mode 100644 index 1557918..0000000 --- a/src/main/java/android/os/InputMethodTest.java +++ /dev/null @@ -1,398 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.ResolveInfo; -import android.content.pm.ServiceInfo; -import android.test.InstrumentationTestCase; -import android.test.suitebuilder.annotation.SmallTest; -import android.view.inputmethod.InputMethodInfo; -import android.view.inputmethod.InputMethodSubtype; -import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder; - -import com.android.internal.inputmethod.InputMethodUtils; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Objects; - -public class InputMethodTest extends InstrumentationTestCase { - private static final boolean IS_AUX = true; - private static final boolean IS_DEFAULT = true; - private static final boolean IS_AUTO = true; - private static final boolean IS_ASCII_CAPABLE = true; - private static final boolean IS_SYSTEM_READY = true; - private static final ArrayList NO_SUBTYPE = null; - private static final Locale LOCALE_EN_US = new Locale("en", "US"); - private static final Locale LOCALE_EN_GB = new Locale("en", "GB"); - private static final Locale LOCALE_EN_IN = new Locale("en", "IN"); - private static final Locale LOCALE_HI = new Locale("hi"); - private static final Locale LOCALE_JA_JP = new Locale("ja", "JP"); - private static final Locale LOCALE_ZH_CN = new Locale("zh", "CN"); - private static final Locale LOCALE_ZH_TW = new Locale("zh", "TW"); - private static final String SUBTYPE_MODE_KEYBOARD = "keyboard"; - private static final String SUBTYPE_MODE_VOICE = "voice"; - - @SmallTest - public void testVoiceImes() throws Exception { - // locale: en_US - assertDefaultEnabledImes(getImesWithDefaultVoiceIme(), LOCALE_EN_US, - !IS_SYSTEM_READY, "DummyDefaultEnKeyboardIme", "DummyDefaultAutoVoiceIme"); - assertDefaultEnabledImes(getImesWithoutDefaultVoiceIme(), LOCALE_EN_US, - !IS_SYSTEM_READY, "DummyDefaultEnKeyboardIme"); - assertDefaultEnabledImes(getImesWithDefaultVoiceIme(), LOCALE_EN_US, - IS_SYSTEM_READY, "DummyDefaultEnKeyboardIme", "DummyDefaultAutoVoiceIme"); - assertDefaultEnabledImes(getImesWithoutDefaultVoiceIme(), LOCALE_EN_US, - IS_SYSTEM_READY, "DummyDefaultEnKeyboardIme", "DummyNonDefaultAutoVoiceIme0", - "DummyNonDefaultAutoVoiceIme1"); - - // locale: en_GB - assertDefaultEnabledImes(getImesWithDefaultVoiceIme(), LOCALE_EN_GB, - !IS_SYSTEM_READY, "DummyDefaultEnKeyboardIme", "DummyDefaultAutoVoiceIme"); - assertDefaultEnabledImes(getImesWithoutDefaultVoiceIme(), LOCALE_EN_GB, - !IS_SYSTEM_READY, "DummyDefaultEnKeyboardIme"); - assertDefaultEnabledImes(getImesWithDefaultVoiceIme(), LOCALE_EN_GB, - IS_SYSTEM_READY, "DummyDefaultEnKeyboardIme", "DummyDefaultAutoVoiceIme"); - assertDefaultEnabledImes(getImesWithoutDefaultVoiceIme(), LOCALE_EN_GB, - IS_SYSTEM_READY, "DummyDefaultEnKeyboardIme", "DummyNonDefaultAutoVoiceIme0", - "DummyNonDefaultAutoVoiceIme1"); - - // locale: ja_JP - assertDefaultEnabledImes(getImesWithDefaultVoiceIme(), LOCALE_JA_JP, - !IS_SYSTEM_READY, "DummyDefaultEnKeyboardIme", "DummyDefaultAutoVoiceIme"); - assertDefaultEnabledImes(getImesWithoutDefaultVoiceIme(), LOCALE_JA_JP, - !IS_SYSTEM_READY, "DummyDefaultEnKeyboardIme"); - assertDefaultEnabledImes(getImesWithDefaultVoiceIme(), LOCALE_JA_JP, - IS_SYSTEM_READY, "DummyDefaultEnKeyboardIme", "DummyDefaultAutoVoiceIme"); - assertDefaultEnabledImes(getImesWithoutDefaultVoiceIme(), LOCALE_JA_JP, - IS_SYSTEM_READY, "DummyDefaultEnKeyboardIme", "DummyNonDefaultAutoVoiceIme0", - "DummyNonDefaultAutoVoiceIme1"); - } - - @SmallTest - public void testKeyboardImes() throws Exception { - // locale: en_US - assertDefaultEnabledImes(getSamplePreinstalledImes("en-rUS"), LOCALE_EN_US, - !IS_SYSTEM_READY, "com.android.apps.inputmethod.latin"); - assertDefaultEnabledImes(getSamplePreinstalledImes("en-rUS"), LOCALE_EN_US, - IS_SYSTEM_READY, "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.voice"); - - // locale: en_GB - assertDefaultEnabledImes(getSamplePreinstalledImes("en-rGB"), LOCALE_EN_GB, - !IS_SYSTEM_READY, "com.android.apps.inputmethod.latin"); - assertDefaultEnabledImes(getSamplePreinstalledImes("en-rGB"), LOCALE_EN_GB, - IS_SYSTEM_READY, "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.voice"); - - // locale: en_IN - assertDefaultEnabledImes(getSamplePreinstalledImes("en-rIN"), LOCALE_EN_IN, - !IS_SYSTEM_READY, "com.android.apps.inputmethod.latin"); - assertDefaultEnabledImes(getSamplePreinstalledImes("en-rIN"), LOCALE_EN_IN, - IS_SYSTEM_READY, "com.android.apps.inputmethod.hindi", - "com.android.apps.inputmethod.latin", "com.android.apps.inputmethod.voice"); - - // locale: hi - assertDefaultEnabledImes(getSamplePreinstalledImes("hi"), LOCALE_HI, - !IS_SYSTEM_READY, "com.android.apps.inputmethod.latin"); - assertDefaultEnabledImes(getSamplePreinstalledImes("hi"), LOCALE_HI, - IS_SYSTEM_READY, "com.android.apps.inputmethod.hindi", - "com.android.apps.inputmethod.latin", "com.android.apps.inputmethod.voice"); - - // locale: ja_JP - assertDefaultEnabledImes(getSamplePreinstalledImes("ja-rJP"), LOCALE_JA_JP, - !IS_SYSTEM_READY, "com.android.apps.inputmethod.latin"); - assertDefaultEnabledImes(getSamplePreinstalledImes("ja-rJP"), LOCALE_JA_JP, - IS_SYSTEM_READY, "com.android.apps.inputmethod.japanese", - "com.android.apps.inputmethod.voice"); - - // locale: zh_CN - assertDefaultEnabledImes(getSamplePreinstalledImes("zh-rCN"), LOCALE_ZH_CN, - !IS_SYSTEM_READY, "com.android.apps.inputmethod.latin"); - assertDefaultEnabledImes(getSamplePreinstalledImes("zh-rCN"), LOCALE_ZH_CN, - IS_SYSTEM_READY, "com.android.apps.inputmethod.pinyin", - "com.android.apps.inputmethod.voice"); - - // locale: zh_TW - // Note: In this case, no IME is suitable for the system locale. Hence we will pick up a - // fallback IME regardless of the "default" attribute. - assertDefaultEnabledImes(getSamplePreinstalledImes("zh-rTW"), LOCALE_ZH_TW, - !IS_SYSTEM_READY, "com.android.apps.inputmethod.latin"); - assertDefaultEnabledImes(getSamplePreinstalledImes("zh-rTW"), LOCALE_ZH_TW, - IS_SYSTEM_READY, "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.voice"); - } - - @SmallTest - public void testParcelable() throws Exception { - final ArrayList originalList = getSamplePreinstalledImes("en-rUS"); - final List clonedList = cloneViaParcel(originalList); - assertNotNull(clonedList); - final List clonedClonedList = cloneViaParcel(clonedList); - assertNotNull(clonedClonedList); - assertEquals(originalList, clonedList); - assertEquals(clonedList, clonedClonedList); - assertEquals(originalList.size(), clonedList.size()); - assertEquals(clonedList.size(), clonedClonedList.size()); - for (int imeIndex = 0; imeIndex < originalList.size(); ++imeIndex) { - verifyEquality(originalList.get(imeIndex), clonedList.get(imeIndex)); - verifyEquality(clonedList.get(imeIndex), clonedClonedList.get(imeIndex)); - } - } - - private void assertDefaultEnabledImes(final ArrayList preinstalledImes, - final Locale systemLocale, final boolean isSystemReady, String... expectedImeNames) { - final Context context = getInstrumentation().getTargetContext(); - final String[] actualImeNames = getPackageNames(callGetDefaultEnabledImesUnderWithLocale( - context, isSystemReady, preinstalledImes, systemLocale)); - assertEquals(expectedImeNames.length, actualImeNames.length); - for (int i = 0; i < expectedImeNames.length; ++i) { - assertEquals(expectedImeNames[i], actualImeNames[i]); - } - } - - private static List cloneViaParcel(final List list) { - Parcel p = null; - try { - p = Parcel.obtain(); - p.writeTypedList(list); - p.setDataPosition(0); - return p.createTypedArrayList(InputMethodInfo.CREATOR); - } finally { - if (p != null) { - p.recycle(); - } - } - } - - private static ArrayList callGetDefaultEnabledImesUnderWithLocale( - final Context context, final boolean isSystemReady, - final ArrayList imis, final Locale locale) { - final Locale initialLocale = context.getResources().getConfiguration().locale; - try { - context.getResources().getConfiguration().setLocale(locale); - return InputMethodUtils.getDefaultEnabledImes(context, isSystemReady, imis); - } finally { - context.getResources().getConfiguration().setLocale(initialLocale); - } - } - - private String[] getPackageNames(final ArrayList imis) { - final String[] packageNames = new String[imis.size()]; - for (int i = 0; i < imis.size(); ++i) { - packageNames[i] = imis.get(i).getPackageName(); - } - return packageNames; - } - - private static void verifyEquality(InputMethodInfo expected, InputMethodInfo actual) { - assertEquals(expected, actual); - assertEquals(expected.getSubtypeCount(), actual.getSubtypeCount()); - for (int subtypeIndex = 0; subtypeIndex < expected.getSubtypeCount(); ++subtypeIndex) { - final InputMethodSubtype expectedSubtype = expected.getSubtypeAt(subtypeIndex); - final InputMethodSubtype actualSubtype = actual.getSubtypeAt(subtypeIndex); - assertEquals(expectedSubtype, actualSubtype); - assertEquals(expectedSubtype.hashCode(), actualSubtype.hashCode()); - } - } - - private static InputMethodInfo createDummyInputMethodInfo(String packageName, String name, - CharSequence label, boolean isAuxIme, boolean isDefault, - List subtypes) { - final ResolveInfo ri = new ResolveInfo(); - final ServiceInfo si = new ServiceInfo(); - final ApplicationInfo ai = new ApplicationInfo(); - ai.packageName = packageName; - ai.enabled = true; - ai.flags |= ApplicationInfo.FLAG_SYSTEM; - si.applicationInfo = ai; - si.enabled = true; - si.packageName = packageName; - si.name = name; - si.exported = true; - si.nonLocalizedLabel = label; - ri.serviceInfo = si; - return new InputMethodInfo(ri, isAuxIme, "", subtypes, 1, isDefault); - } - - private static InputMethodSubtype createDummyInputMethodSubtype(String locale, String mode, - boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype, - boolean isAsciiCapable) { - return new InputMethodSubtypeBuilder() - .setSubtypeNameResId(0) - .setSubtypeIconResId(0) - .setSubtypeLocale(locale) - .setSubtypeMode(mode) - .setSubtypeExtraValue("") - .setIsAuxiliary(isAuxiliary) - .setOverridesImplicitlyEnabledSubtype(overridesImplicitlyEnabledSubtype) - .setIsAsciiCapable(isAsciiCapable) - .build(); - } - - private static ArrayList getImesWithDefaultVoiceIme() { - ArrayList preinstalledImes = new ArrayList<>(); - { - final ArrayList subtypes = new ArrayList(); - subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX, IS_AUTO, - !IS_ASCII_CAPABLE)); - subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX, - !IS_AUTO, !IS_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("DummyDefaultAutoVoiceIme", - "dummy.voice0", "DummyVoice0", IS_AUX, IS_DEFAULT, subtypes)); - } - preinstalledImes.addAll(getImesWithoutDefaultVoiceIme()); - return preinstalledImes; - } - - private static ArrayList getImesWithoutDefaultVoiceIme() { - ArrayList preinstalledImes = new ArrayList<>(); - { - final ArrayList subtypes = new ArrayList(); - subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX, IS_AUTO, - !IS_ASCII_CAPABLE)); - subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX, - !IS_AUTO, !IS_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("DummyNonDefaultAutoVoiceIme0", - "dummy.voice1", "DummyVoice1", IS_AUX, !IS_DEFAULT, subtypes)); - } - { - final ArrayList subtypes = new ArrayList(); - subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX, IS_AUTO, - !IS_ASCII_CAPABLE)); - subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX, - !IS_AUTO, !IS_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("DummyNonDefaultAutoVoiceIme1", - "dummy.voice2", "DummyVoice2", IS_AUX, !IS_DEFAULT, subtypes)); - } - { - final ArrayList subtypes = new ArrayList(); - subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX, - !IS_AUTO, !IS_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("DummyNonDefaultVoiceIme2", - "dummy.voice3", "DummyVoice3", IS_AUX, !IS_DEFAULT, subtypes)); - } - { - final ArrayList subtypes = new ArrayList(); - subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_KEYBOARD, !IS_AUX, - !IS_AUTO, IS_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("DummyDefaultEnKeyboardIme", - "dummy.keyboard0", "DummyKeyboard0", !IS_AUX, IS_DEFAULT, subtypes)); - } - return preinstalledImes; - } - - private static boolean contains(final String[] textList, final String textToBeChecked) { - if (textList == null) { - return false; - } - for (final String text : textList) { - if (Objects.equals(textToBeChecked, text)) { - return true; - } - } - return false; - } - - private static ArrayList getSamplePreinstalledImes(final String localeString) { - ArrayList preinstalledImes = new ArrayList<>(); - - // a dummy Voice IME - { - final boolean isDefaultIme = false; - final ArrayList subtypes = new ArrayList(); - subtypes.add(createDummyInputMethodSubtype("", SUBTYPE_MODE_VOICE, IS_AUX, - IS_AUTO, !IS_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.voice", - "com.android.inputmethod.voice", "DummyVoiceIme", IS_AUX, isDefaultIme, - subtypes)); - } - // a dummy Hindi IME - { - final boolean isDefaultIme = contains(new String[]{ "hi", "en-rIN" }, localeString); - final ArrayList subtypes = new ArrayList(); - // TODO: This subtype should be marked as IS_ASCII_CAPABLE - subtypes.add(createDummyInputMethodSubtype("en_IN", SUBTYPE_MODE_KEYBOARD, !IS_AUX, - !IS_AUTO, !IS_ASCII_CAPABLE)); - subtypes.add(createDummyInputMethodSubtype("hi", SUBTYPE_MODE_KEYBOARD, !IS_AUX, - !IS_AUTO, !IS_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.hindi", - "com.android.inputmethod.hindi", "DummyHindiIme", !IS_AUX, isDefaultIme, - subtypes)); - } - - // a dummy Pinyin IME - { - final boolean isDefaultIme = contains(new String[]{ "zh-rCN" }, localeString); - final ArrayList subtypes = new ArrayList(); - subtypes.add(createDummyInputMethodSubtype("zh_CN", SUBTYPE_MODE_KEYBOARD, !IS_AUX, - !IS_AUTO, !IS_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.pinyin", - "com.android.apps.inputmethod.pinyin", "DummyPinyinIme", !IS_AUX, isDefaultIme, - subtypes)); - } - - // a dummy Korean IME - { - final boolean isDefaultIme = contains(new String[]{ "ko" }, localeString); - final ArrayList subtypes = new ArrayList(); - subtypes.add(createDummyInputMethodSubtype("ko", SUBTYPE_MODE_KEYBOARD, !IS_AUX, - !IS_AUTO, !IS_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.korean", - "com.android.apps.inputmethod.korean", "DummyKoreanIme", !IS_AUX, isDefaultIme, - subtypes)); - } - - // a dummy Latin IME - { - final boolean isDefaultIme = contains( - new String[]{ "en-rUS", "en-rGB", "en-rIN", "en", "hi" }, localeString); - final ArrayList subtypes = new ArrayList(); - subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_KEYBOARD, !IS_AUX, - !IS_AUTO, IS_ASCII_CAPABLE)); - subtypes.add(createDummyInputMethodSubtype("en_GB", SUBTYPE_MODE_KEYBOARD, !IS_AUX, - !IS_AUTO, IS_ASCII_CAPABLE)); - subtypes.add(createDummyInputMethodSubtype("en_IN", SUBTYPE_MODE_KEYBOARD, !IS_AUX, - !IS_AUTO, IS_ASCII_CAPABLE)); - subtypes.add(createDummyInputMethodSubtype("hi", SUBTYPE_MODE_KEYBOARD, !IS_AUX, - !IS_AUTO, IS_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, isDefaultIme, - subtypes)); - } - - // a dummy Japanese IME - { - final boolean isDefaultIme = contains(new String[]{ "ja", "ja-rJP" }, localeString); - final ArrayList subtypes = new ArrayList(); - subtypes.add(createDummyInputMethodSubtype("ja", SUBTYPE_MODE_KEYBOARD, !IS_AUX, - !IS_AUTO, !IS_ASCII_CAPABLE)); - subtypes.add(createDummyInputMethodSubtype("emoji", SUBTYPE_MODE_KEYBOARD, !IS_AUX, - !IS_AUTO, !IS_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.japanese", - "com.android.apps.inputmethod.japanese", "DummyJapaneseIme", !IS_AUX, - isDefaultIme, subtypes)); - } - - return preinstalledImes; - } -} diff --git a/src/main/java/android/os/Looper.java b/src/main/java/android/os/Looper.java deleted file mode 100644 index 6d7c9cf..0000000 --- a/src/main/java/android/os/Looper.java +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.util.Log; -import android.util.Printer; - -/** - * Class used to run a message loop for a thread. Threads by default do - * not have a message loop associated with them; to create one, call - * {@link #prepare} in the thread that is to run the loop, and then - * {@link #loop} to have it process messages until the loop is stopped. - * - *

Most interaction with a message loop is through the - * {@link Handler} class. - * - *

This is a typical example of the implementation of a Looper thread, - * using the separation of {@link #prepare} and {@link #loop} to create an - * initial Handler to communicate with the Looper. - * - *

-  *  class LooperThread extends Thread {
-  *      public Handler mHandler;
-  *
-  *      public void run() {
-  *          Looper.prepare();
-  *
-  *          mHandler = new Handler() {
-  *              public void handleMessage(Message msg) {
-  *                  // process incoming messages here
-  *              }
-  *          };
-  *
-  *          Looper.loop();
-  *      }
-  *  }
- */ -public final class Looper { - private static final String TAG = "Looper"; - - // sThreadLocal.get() will return null unless you've called prepare(). - static final ThreadLocal sThreadLocal = new ThreadLocal(); - private static Looper sMainLooper; // guarded by Looper.class - - final MessageQueue mQueue; - final Thread mThread; - - private Printer mLogging; - - /** Initialize the current thread as a looper. - * This gives you a chance to create handlers that then reference - * this looper, before actually starting the loop. Be sure to call - * {@link #loop()} after calling this method, and end it by calling - * {@link #quit()}. - */ - public static void prepare() { - prepare(true); - } - - private static void prepare(boolean quitAllowed) { - if (sThreadLocal.get() != null) { - throw new RuntimeException("Only one Looper may be created per thread"); - } - sThreadLocal.set(new Looper(quitAllowed)); - } - - /** - * Initialize the current thread as a looper, marking it as an - * application's main looper. The main looper for your application - * is created by the Android environment, so you should never need - * to call this function yourself. See also: {@link #prepare()} - */ - public static void prepareMainLooper() { - prepare(false); - synchronized (Looper.class) { - if (sMainLooper != null) { - throw new IllegalStateException("The main Looper has already been prepared."); - } - sMainLooper = myLooper(); - } - } - - /** Returns the application's main looper, which lives in the main thread of the application. - */ - public static Looper getMainLooper() { - synchronized (Looper.class) { - return sMainLooper; - } - } - - /** - * Run the message queue in this thread. Be sure to call - * {@link #quit()} to end the loop. - */ - public static void loop() { - final Looper me = myLooper(); - if (me == null) { - throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); - } - final MessageQueue queue = me.mQueue; - - // Make sure the identity of this thread is that of the local process, - // and keep track of what that identity token actually is. - Binder.clearCallingIdentity(); - final long ident = Binder.clearCallingIdentity(); - - for (;;) { - Message msg = queue.next(); // might block - if (msg == null) { - // No message indicates that the message queue is quitting. - return; - } - - // This must be in a local variable, in case a UI event sets the logger - Printer logging = me.mLogging; - if (logging != null) { - logging.println(">>>>> Dispatching to " + msg.target + " " + - msg.callback + ": " + msg.what); - } - - msg.target.dispatchMessage(msg); - - if (logging != null) { - logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); - } - - // Make sure that during the course of dispatching the - // identity of the thread wasn't corrupted. - final long newIdent = Binder.clearCallingIdentity(); - if (ident != newIdent) { - Log.wtf(TAG, "Thread identity changed from 0x" - + Long.toHexString(ident) + " to 0x" - + Long.toHexString(newIdent) + " while dispatching to " - + msg.target.getClass().getName() + " " - + msg.callback + " what=" + msg.what); - } - - msg.recycleUnchecked(); - } - } - - /** - * Return the Looper object associated with the current thread. Returns - * null if the calling thread is not associated with a Looper. - */ - public static Looper myLooper() { - return sThreadLocal.get(); - } - - /** - * Control logging of messages as they are processed by this Looper. If - * enabled, a log message will be written to printer - * at the beginning and ending of each message dispatch, identifying the - * target Handler and message contents. - * - * @param printer A Printer object that will receive log messages, or - * null to disable message logging. - */ - public void setMessageLogging(Printer printer) { - mLogging = printer; - } - - /** - * Return the {@link MessageQueue} object associated with the current - * thread. This must be called from a thread running a Looper, or a - * NullPointerException will be thrown. - */ - public static MessageQueue myQueue() { - return myLooper().mQueue; - } - - private Looper(boolean quitAllowed) { - mQueue = new MessageQueue(quitAllowed); - mThread = Thread.currentThread(); - } - - /** - * Returns true if the current thread is this looper's thread. - * @hide - */ - public boolean isCurrentThread() { - return Thread.currentThread() == mThread; - } - - /** - * Quits the looper. - *

- * Causes the {@link #loop} method to terminate without processing any - * more messages in the message queue. - *

- * Any attempt to post messages to the queue after the looper is asked to quit will fail. - * For example, the {@link Handler#sendMessage(Message)} method will return false. - *

- * Using this method may be unsafe because some messages may not be delivered - * before the looper terminates. Consider using {@link #quitSafely} instead to ensure - * that all pending work is completed in an orderly manner. - *

- * - * @see #quitSafely - */ - public void quit() { - mQueue.quit(false); - } - - /** - * Quits the looper safely. - *

- * Causes the {@link #loop} method to terminate as soon as all remaining messages - * in the message queue that are already due to be delivered have been handled. - * However pending delayed messages with due times in the future will not be - * delivered before the loop terminates. - *

- * Any attempt to post messages to the queue after the looper is asked to quit will fail. - * For example, the {@link Handler#sendMessage(Message)} method will return false. - *

- */ - public void quitSafely() { - mQueue.quit(true); - } - - /** - * Posts a synchronization barrier to the Looper's message queue. - * - * Message processing occurs as usual until the message queue encounters the - * synchronization barrier that has been posted. When the barrier is encountered, - * later synchronous messages in the queue are stalled (prevented from being executed) - * until the barrier is released by calling {@link #removeSyncBarrier} and specifying - * the token that identifies the synchronization barrier. - * - * This method is used to immediately postpone execution of all subsequently posted - * synchronous messages until a condition is met that releases the barrier. - * Asynchronous messages (see {@link Message#isAsynchronous} are exempt from the barrier - * and continue to be processed as usual. - * - * This call must be always matched by a call to {@link #removeSyncBarrier} with - * the same token to ensure that the message queue resumes normal operation. - * Otherwise the application will probably hang! - * - * @return A token that uniquely identifies the barrier. This token must be - * passed to {@link #removeSyncBarrier} to release the barrier. - * - * @hide - */ - public int postSyncBarrier() { - return mQueue.enqueueSyncBarrier(SystemClock.uptimeMillis()); - } - - - /** - * Removes a synchronization barrier. - * - * @param token The synchronization barrier token that was returned by - * {@link #postSyncBarrier}. - * - * @throws IllegalStateException if the barrier was not found. - * - * @hide - */ - public void removeSyncBarrier(int token) { - mQueue.removeSyncBarrier(token); - } - - /** - * Return the Thread associated with this Looper. - */ - public Thread getThread() { - return mThread; - } - - /** @hide */ - public MessageQueue getQueue() { - return mQueue; - } - - /** - * Return whether this looper's thread is currently idle, waiting for new work - * to do. This is intrinsically racy, since its state can change before you get - * the result back. - * @hide - */ - public boolean isIdling() { - return mQueue.isIdling(); - } - - public void dump(Printer pw, String prefix) { - pw.println(prefix + toString()); - mQueue.dump(pw, prefix + " "); - } - - public String toString() { - return "Looper (" + mThread.getName() + ", tid " + mThread.getId() - + ") {" + Integer.toHexString(System.identityHashCode(this)) + "}"; - } -} diff --git a/src/main/java/android/os/Looper_Accessor.java b/src/main/java/android/os/Looper_Accessor.java deleted file mode 100644 index 09f3e47..0000000 --- a/src/main/java/android/os/Looper_Accessor.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.os; - -import java.lang.reflect.Field; - -/** - * Class allowing access to package-protected methods/fields. - */ -public class Looper_Accessor { - - public static void cleanupThread() { - // clean up the looper - Looper.sThreadLocal.remove(); - try { - Field sMainLooper = Looper.class.getDeclaredField("sMainLooper"); - sMainLooper.setAccessible(true); - sMainLooper.set(null, null); - } catch (SecurityException e) { - catchReflectionException(); - } catch (IllegalArgumentException e) { - catchReflectionException(); - } catch (NoSuchFieldException e) { - catchReflectionException(); - } catch (IllegalAccessException e) { - catchReflectionException(); - } - - } - - private static void catchReflectionException() { - assert(false); - } -} diff --git a/src/main/java/android/os/MemoryFile.java b/src/main/java/android/os/MemoryFile.java deleted file mode 100644 index 6cec55a..0000000 --- a/src/main/java/android/os/MemoryFile.java +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.util.Log; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - - -/** - * MemoryFile is a wrapper for the Linux ashmem driver. - * MemoryFiles are backed by shared memory, which can be optionally - * set to be purgeable. - * Purgeable files may have their contents reclaimed by the kernel - * in low memory conditions (only if allowPurging is set to true). - * After a file is purged, attempts to read or write the file will - * cause an IOException to be thrown. - */ -public class MemoryFile -{ - private static String TAG = "MemoryFile"; - - // mmap(2) protection flags from - private static final int PROT_READ = 0x1; - private static final int PROT_WRITE = 0x2; - - private static native FileDescriptor native_open(String name, int length) throws IOException; - // returns memory address for ashmem region - private static native long native_mmap(FileDescriptor fd, int length, int mode) - throws IOException; - private static native void native_munmap(long addr, int length) throws IOException; - private static native void native_close(FileDescriptor fd); - private static native int native_read(FileDescriptor fd, long address, byte[] buffer, - int srcOffset, int destOffset, int count, boolean isUnpinned) throws IOException; - private static native void native_write(FileDescriptor fd, long address, byte[] buffer, - int srcOffset, int destOffset, int count, boolean isUnpinned) throws IOException; - private static native void native_pin(FileDescriptor fd, boolean pin) throws IOException; - private static native int native_get_size(FileDescriptor fd) throws IOException; - - private FileDescriptor mFD; // ashmem file descriptor - private long mAddress; // address of ashmem memory - private int mLength; // total length of our ashmem region - private boolean mAllowPurging = false; // true if our ashmem region is unpinned - - /** - * Allocates a new ashmem region. The region is initially not purgable. - * - * @param name optional name for the file (can be null). - * @param length of the memory file in bytes, must be non-negative. - * @throws IOException if the memory file could not be created. - */ - public MemoryFile(String name, int length) throws IOException { - mLength = length; - if (length >= 0) { - mFD = native_open(name, length); - } else { - throw new IOException("Invalid length: " + length); - } - - if (length > 0) { - mAddress = native_mmap(mFD, length, PROT_READ | PROT_WRITE); - } else { - mAddress = 0; - } - } - - /** - * Closes the memory file. If there are no other open references to the memory - * file, it will be deleted. - */ - public void close() { - deactivate(); - if (!isClosed()) { - native_close(mFD); - } - } - - /** - * Unmaps the memory file from the process's memory space, but does not close it. - * After this method has been called, read and write operations through this object - * will fail, but {@link #getFileDescriptor()} will still return a valid file descriptor. - * - * @hide - */ - void deactivate() { - if (!isDeactivated()) { - try { - native_munmap(mAddress, mLength); - mAddress = 0; - } catch (IOException ex) { - Log.e(TAG, ex.toString()); - } - } - } - - /** - * Checks whether the memory file has been deactivated. - */ - private boolean isDeactivated() { - return mAddress == 0; - } - - /** - * Checks whether the memory file has been closed. - */ - private boolean isClosed() { - return !mFD.valid(); - } - - @Override - protected void finalize() { - if (!isClosed()) { - Log.e(TAG, "MemoryFile.finalize() called while ashmem still open"); - close(); - } - } - - /** - * Returns the length of the memory file. - * - * @return file length. - */ - public int length() { - return mLength; - } - - /** - * Is memory file purging enabled? - * - * @return true if the file may be purged. - */ - public boolean isPurgingAllowed() { - return mAllowPurging; - } - - /** - * Enables or disables purging of the memory file. - * - * @param allowPurging true if the operating system can purge the contents - * of the file in low memory situations - * @return previous value of allowPurging - */ - synchronized public boolean allowPurging(boolean allowPurging) throws IOException { - boolean oldValue = mAllowPurging; - if (oldValue != allowPurging) { - native_pin(mFD, !allowPurging); - mAllowPurging = allowPurging; - } - return oldValue; - } - - /** - * Creates a new InputStream for reading from the memory file. - * - @return InputStream - */ - public InputStream getInputStream() { - return new MemoryInputStream(); - } - - /** - * Creates a new OutputStream for writing to the memory file. - * - @return OutputStream - */ - public OutputStream getOutputStream() { - return new MemoryOutputStream(); - } - - /** - * Reads bytes from the memory file. - * Will throw an IOException if the file has been purged. - * - * @param buffer byte array to read bytes into. - * @param srcOffset offset into the memory file to read from. - * @param destOffset offset into the byte array buffer to read into. - * @param count number of bytes to read. - * @return number of bytes read. - * @throws IOException if the memory file has been purged or deactivated. - */ - public int readBytes(byte[] buffer, int srcOffset, int destOffset, int count) - throws IOException { - if (isDeactivated()) { - throw new IOException("Can't read from deactivated memory file."); - } - if (destOffset < 0 || destOffset > buffer.length || count < 0 - || count > buffer.length - destOffset - || srcOffset < 0 || srcOffset > mLength - || count > mLength - srcOffset) { - throw new IndexOutOfBoundsException(); - } - return native_read(mFD, mAddress, buffer, srcOffset, destOffset, count, mAllowPurging); - } - - /** - * Write bytes to the memory file. - * Will throw an IOException if the file has been purged. - * - * @param buffer byte array to write bytes from. - * @param srcOffset offset into the byte array buffer to write from. - * @param destOffset offset into the memory file to write to. - * @param count number of bytes to write. - * @throws IOException if the memory file has been purged or deactivated. - */ - public void writeBytes(byte[] buffer, int srcOffset, int destOffset, int count) - throws IOException { - if (isDeactivated()) { - throw new IOException("Can't write to deactivated memory file."); - } - if (srcOffset < 0 || srcOffset > buffer.length || count < 0 - || count > buffer.length - srcOffset - || destOffset < 0 || destOffset > mLength - || count > mLength - destOffset) { - throw new IndexOutOfBoundsException(); - } - native_write(mFD, mAddress, buffer, srcOffset, destOffset, count, mAllowPurging); - } - - /** - * Gets a FileDescriptor for the memory file. - * - * The returned file descriptor is not duplicated. - * - * @throws IOException If the memory file has been closed. - * - * @hide - */ - public FileDescriptor getFileDescriptor() throws IOException { - return mFD; - } - - /** - * Returns the size of the memory file that the file descriptor refers to, - * or -1 if the file descriptor does not refer to a memory file. - * - * @throws IOException If fd is not a valid file descriptor. - * - * @hide - */ - public static int getSize(FileDescriptor fd) throws IOException { - return native_get_size(fd); - } - - private class MemoryInputStream extends InputStream { - - private int mMark = 0; - private int mOffset = 0; - private byte[] mSingleByte; - - @Override - public int available() throws IOException { - if (mOffset >= mLength) { - return 0; - } - return mLength - mOffset; - } - - @Override - public boolean markSupported() { - return true; - } - - @Override - public void mark(int readlimit) { - mMark = mOffset; - } - - @Override - public void reset() throws IOException { - mOffset = mMark; - } - - @Override - public int read() throws IOException { - if (mSingleByte == null) { - mSingleByte = new byte[1]; - } - int result = read(mSingleByte, 0, 1); - if (result != 1) { - return -1; - } - return mSingleByte[0]; - } - - @Override - public int read(byte buffer[], int offset, int count) throws IOException { - if (offset < 0 || count < 0 || offset + count > buffer.length) { - // readBytes() also does this check, but we need to do it before - // changing count. - throw new IndexOutOfBoundsException(); - } - count = Math.min(count, available()); - if (count < 1) { - return -1; - } - int result = readBytes(buffer, mOffset, offset, count); - if (result > 0) { - mOffset += result; - } - return result; - } - - @Override - public long skip(long n) throws IOException { - if (mOffset + n > mLength) { - n = mLength - mOffset; - } - mOffset += n; - return n; - } - } - - private class MemoryOutputStream extends OutputStream { - - private int mOffset = 0; - private byte[] mSingleByte; - - @Override - public void write(byte buffer[], int offset, int count) throws IOException { - writeBytes(buffer, offset, mOffset, count); - mOffset += count; - } - - @Override - public void write(int oneByte) throws IOException { - if (mSingleByte == null) { - mSingleByte = new byte[1]; - } - mSingleByte[0] = (byte)oneByte; - write(mSingleByte, 0, 1); - } - } -} diff --git a/src/main/java/android/os/MemoryFileTest.java b/src/main/java/android/os/MemoryFileTest.java deleted file mode 100644 index 82af662..0000000 --- a/src/main/java/android/os/MemoryFileTest.java +++ /dev/null @@ -1,403 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.LargeTest; -import android.test.suitebuilder.annotation.SmallTest; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -public class MemoryFileTest extends AndroidTestCase { - - private void compareBuffers(byte[] buffer1, byte[] buffer2, int length) throws Exception { - for (int i = 0; i < length; i++) { - if (buffer1[i] != buffer2[i]) { - throw new Exception("readBytes did not read back what writeBytes wrote"); - } - } - } - - /** - * Keep allocating new files till the system purges them. - */ - // Flaky test - temporarily suppress from large suite for now - // @LargeTest - public void testPurge() throws Exception { - List files = new ArrayList(); - try { - while (true) { - // This will fail if the process runs out of file descriptors before - // the kernel starts purging ashmem areas. - MemoryFile newFile = new MemoryFile("MemoryFileTest", 10000000); - newFile.allowPurging(true); - newFile.writeBytes(testString, 0, 0, testString.length); - files.add(newFile); - for (MemoryFile file : files) { - try { - file.readBytes(testString, 0, 0, testString.length); - } catch (IOException e) { - // Expected - return; - } - } - } - } finally { - for (MemoryFile fileToClose : files) { - fileToClose.close(); - } - } - } - - @SmallTest - public void testRun() throws Exception { - MemoryFile file = new MemoryFile("MemoryFileTest", 1000000); - - byte[] buffer = new byte[testString.length]; - - // check low level accessors - file.writeBytes(testString, 0, 2000, testString.length); - file.readBytes(buffer, 2000, 0, testString.length); - compareBuffers(testString, buffer, testString.length); - - // check streams - buffer = new byte[testString.length]; - - OutputStream os = file.getOutputStream(); - os.write(testString); - - InputStream is = file.getInputStream(); - is.mark(testString.length); - is.read(buffer); - compareBuffers(testString, buffer, testString.length); - - // test mark/reset - buffer = new byte[testString.length]; - is.reset(); - is.read(buffer); - compareBuffers(testString, buffer, testString.length); - - file.close(); - } - - // http://code.google.com/p/android/issues/detail?id=11415 - public void testOutputStreamAdvances() throws IOException { - MemoryFile file = new MemoryFile("MemoryFileTest", 10); - - OutputStream os = file.getOutputStream(); - os.write(new byte[] { 1, 2, 3, 4, 5 }); - os.write(new byte[] { -1, -1, 6, 7, 8, -1 }, 2, 3); - os.write(9); - try { - os.write(new byte[] { -1, -1 }); - fail(); - } catch (IndexOutOfBoundsException expected) { - } - - byte[] copy = new byte[file.length()]; - file.readBytes(copy, 0, 0, file.length()); - assertEquals("[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]", Arrays.toString(copy)); - } - - // Tests for the IndexOutOfBoundsException cases in read(). - - private void readIndexOutOfBoundsException(int offset, int count, String msg) - throws Exception { - MemoryFile file = new MemoryFile("MemoryFileTest", testString.length); - try { - file.writeBytes(testString, 0, 0, testString.length); - InputStream is = file.getInputStream(); - byte[] buffer = new byte[testString.length + 10]; - try { - is.read(buffer, offset, count); - fail(msg); - } catch (IndexOutOfBoundsException ex) { - // this is what should happen - } finally { - is.close(); - } - } finally { - file.close(); - } - } - - @SmallTest - public void testReadNegativeOffset() throws Exception { - readIndexOutOfBoundsException(-1, 5, - "read() with negative offset should throw IndexOutOfBoundsException"); - } - - @SmallTest - public void testReadNegativeCount() throws Exception { - readIndexOutOfBoundsException(5, -1, - "read() with negative length should throw IndexOutOfBoundsException"); - } - - @SmallTest - public void testReadOffsetOverflow() throws Exception { - readIndexOutOfBoundsException(testString.length + 10, 5, - "read() with offset outside buffer should throw IndexOutOfBoundsException"); - } - - @SmallTest - public void testReadOffsetCountOverflow() throws Exception { - readIndexOutOfBoundsException(testString.length, 11, - "read() with offset + count outside buffer should throw IndexOutOfBoundsException"); - } - - // Test behavior of read() at end of file - @SmallTest - public void testReadEOF() throws Exception { - MemoryFile file = new MemoryFile("MemoryFileTest", testString.length); - try { - file.writeBytes(testString, 0, 0, testString.length); - InputStream is = file.getInputStream(); - try { - byte[] buffer = new byte[testString.length + 10]; - // read() with count larger than data should succeed, and return # of bytes read - assertEquals(testString.length, is.read(buffer)); - compareBuffers(testString, buffer, testString.length); - // Read at EOF should return -1 - assertEquals(-1, is.read()); - } finally { - is.close(); - } - } finally { - file.close(); - } - } - - // Tests that close() is idempotent - @SmallTest - public void testCloseClose() throws Exception { - MemoryFile file = new MemoryFile("MemoryFileTest", 1000000); - byte[] data = new byte[512]; - file.writeBytes(data, 0, 0, 128); - file.close(); - file.close(); - } - - // Tests that we can't read from a closed memory file - @SmallTest - public void testCloseRead() throws Exception { - MemoryFile file = new MemoryFile("MemoryFileTest", 1000000); - file.close(); - - try { - byte[] data = new byte[512]; - assertEquals(128, file.readBytes(data, 0, 0, 128)); - fail("readBytes() after close() did not throw IOException."); - } catch (IOException e) { - // this is what should happen - } - } - - // Tests that we can't write to a closed memory file - @SmallTest - public void testCloseWrite() throws Exception { - MemoryFile file = new MemoryFile("MemoryFileTest", 1000000); - file.close(); - - try { - byte[] data = new byte[512]; - file.writeBytes(data, 0, 0, 128); - fail("writeBytes() after close() did not throw IOException."); - } catch (IOException e) { - // this is what should happen - } - } - - // Tests that we can't call allowPurging() after close() - @SmallTest - public void testCloseAllowPurging() throws Exception { - MemoryFile file = new MemoryFile("MemoryFileTest", 1000000); - byte[] data = new byte[512]; - file.writeBytes(data, 0, 0, 128); - file.close(); - - try { - file.allowPurging(true); - fail("allowPurging() after close() did not throw IOException."); - } catch (IOException e) { - // this is what should happen - } - } - - // Tests that we don't leak file descriptors or mmap areas - @LargeTest - public void testCloseLeak() throws Exception { - // open enough memory files that we should run out of - // file descriptors or address space if we leak either. - for (int i = 0; i < 1025; i++) { - MemoryFile file = new MemoryFile("MemoryFileTest", 5000000); - file.writeBytes(testString, 0, 0, testString.length); - file.close(); - } - } - - private static final byte[] testString = new byte[] { - 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, 2, 3, 8, 4, 6, 2, 6, 4, 3, 3, 8, 3, 2, 7, 9, 5, 0, 2, 8, 8, 4, 1, 9, 7, 1, 6, 9, 3, 9, 9, 3, 7, 5, 1, 0, 5, 8, 2, 0, 9, 7, 4, 9, 4, 4, 5, 9, 2, 3, 0, 7, 8, 1, 6, 4, - 0, 6, 2, 8, 6, 2, 0, 8, 9, 9, 8, 6, 2, 8, 0, 3, 4, 8, 2, 5, 3, 4, 2, 1, 1, 7, 0, 6, 7, 9, 8, 2, 1, 4, 8, 0, 8, 6, 5, 1, 3, 2, 8, 2, 3, 0, 6, 6, 4, 7, 0, 9, 3, 8, 4, 4, 6, 0, 9, 5, 5, 0, 5, 8, 2, 2, 3, 1, 7, 2, - 5, 3, 5, 9, 4, 0, 8, 1, 2, 8, 4, 8, 1, 1, 1, 7, 4, 5, 0, 2, 8, 4, 1, 0, 2, 7, 0, 1, 9, 3, 8, 5, 2, 1, 1, 0, 5, 5, 5, 9, 6, 4, 4, 6, 2, 2, 9, 4, 8, 9, 5, 4, 9, 3, 0, 3, 8, 1, 9, 6, 4, 4, 2, 8, 8, 1, 0, 9, 7, 5, - 6, 6, 5, 9, 3, 3, 4, 4, 6, 1, 2, 8, 4, 7, 5, 6, 4, 8, 2, 3, 3, 7, 8, 6, 7, 8, 3, 1, 6, 5, 2, 7, 1, 2, 0, 1, 9, 0, 9, 1, 4, 5, 6, 4, 8, 5, 6, 6, 9, 2, 3, 4, 6, 0, 3, 4, 8, 6, 1, 0, 4, 5, 4, 3, 2, 6, 6, 4, 8, 2, - 1, 3, 3, 9, 3, 6, 0, 7, 2, 6, 0, 2, 4, 9, 1, 4, 1, 2, 7, 3, 7, 2, 4, 5, 8, 7, 0, 0, 6, 6, 0, 6, 3, 1, 5, 5, 8, 8, 1, 7, 4, 8, 8, 1, 5, 2, 0, 9, 2, 0, 9, 6, 2, 8, 2, 9, 2, 5, 4, 0, 9, 1, 7, 1, 5, 3, 6, 4, 3, 6, - 7, 8, 9, 2, 5, 9, 0, 3, 6, 0, 0, 1, 1, 3, 3, 0, 5, 3, 0, 5, 4, 8, 8, 2, 0, 4, 6, 6, 5, 2, 1, 3, 8, 4, 1, 4, 6, 9, 5, 1, 9, 4, 1, 5, 1, 1, 6, 0, 9, 4, 3, 3, 0, 5, 7, 2, 7, 0, 3, 6, 5, 7, 5, 9, 5, 9, 1, 9, 5, 3, - 0, 9, 2, 1, 8, 6, 1, 1, 7, 3, 8, 1, 9, 3, 2, 6, 1, 1, 7, 9, 3, 1, 0, 5, 1, 1, 8, 5, 4, 8, 0, 7, 4, 4, 6, 2, 3, 7, 9, 9, 6, 2, 7, 4, 9, 5, 6, 7, 3, 5, 1, 8, 8, 5, 7, 5, 2, 7, 2, 4, 8, 9, 1, 2, 2, 7, 9, 3, 8, 1, - 8, 3, 0, 1, 1, 9, 4, 9, 1, 2, 9, 8, 3, 3, 6, 7, 3, 3, 6, 2, 4, 4, 0, 6, 5, 6, 6, 4, 3, 0, 8, 6, 0, 2, 1, 3, 9, 4, 9, 4, 6, 3, 9, 5, 2, 2, 4, 7, 3, 7, 1, 9, 0, 7, 0, 2, 1, 7, 9, 8, 6, 0, 9, 4, 3, 7, 0, 2, 7, 7, - 0, 5, 3, 9, 2, 1, 7, 1, 7, 6, 2, 9, 3, 1, 7, 6, 7, 5, 2, 3, 8, 4, 6, 7, 4, 8, 1, 8, 4, 6, 7, 6, 6, 9, 4, 0, 5, 1, 3, 2, 0, 0, 0, 5, 6, 8, 1, 2, 7, 1, 4, 5, 2, 6, 3, 5, 6, 0, 8, 2, 7, 7, 8, 5, 7, 7, 1, 3, 4, 2, - 7, 5, 7, 7, 8, 9, 6, 0, 9, 1, 7, 3, 6, 3, 7, 1, 7, 8, 7, 2, 1, 4, 6, 8, 4, 4, 0, 9, 0, 1, 2, 2, 4, 9, 5, 3, 4, 3, 0, 1, 4, 6, 5, 4, 9, 5, 8, 5, 3, 7, 1, 0, 5, 0, 7, 9, 2, 2, 7, 9, 6, 8, 9, 2, 5, 8, 9, 2, 3, 5, - 4, 2, 0, 1, 9, 9, 5, 6, 1, 1, 2, 1, 2, 9, 0, 2, 1, 9, 6, 0, 8, 6, 4, 0, 3, 4, 4, 1, 8, 1, 5, 9, 8, 1, 3, 6, 2, 9, 7, 7, 4, 7, 7, 1, 3, 0, 9, 9, 6, 0, 5, 1, 8, 7, 0, 7, 2, 1, 1, 3, 4, 9, 9, 9, 9, 9, 9, 8, 3, 7, - 2, 9, 7, 8, 0, 4, 9, 9, 5, 1, 0, 5, 9, 7, 3, 1, 7, 3, 2, 8, 1, 6, 0, 9, 6, 3, 1, 8, 5, 9, 5, 0, 2, 4, 4, 5, 9, 4, 5, 5, 3, 4, 6, 9, 0, 8, 3, 0, 2, 6, 4, 2, 5, 2, 2, 3, 0, 8, 2, 5, 3, 3, 4, 4, 6, 8, 5, 0, 3, 5, - 2, 6, 1, 9, 3, 1, 1, 8, 8, 1, 7, 1, 0, 1, 0, 0, 0, 3, 1, 3, 7, 8, 3, 8, 7, 5, 2, 8, 8, 6, 5, 8, 7, 5, 3, 3, 2, 0, 8, 3, 8, 1, 4, 2, 0, 6, 1, 7, 1, 7, 7, 6, 6, 9, 1, 4, 7, 3, 0, 3, 5, 9, 8, 2, 5, 3, 4, 9, 0, 4, - 2, 8, 7, 5, 5, 4, 6, 8, 7, 3, 1, 1, 5, 9, 5, 6, 2, 8, 6, 3, 8, 8, 2, 3, 5, 3, 7, 8, 7, 5, 9, 3, 7, 5, 1, 9, 5, 7, 7, 8, 1, 8, 5, 7, 7, 8, 0, 5, 3, 2, 1, 7, 1, 2, 2, 6, 8, 0, 6, 6, 1, 3, 0, 0, 1, 9, 2, 7, 8, 7, - 6, 6, 1, 1, 1, 9, 5, 9, 0, 9, 2, 1, 6, 4, 2, 0, 1, 9, 8, 9, 3, 8, 0, 9, 5, 2, 5, 7, 2, 0, 1, 0, 6, 5, 4, 8, 5, 8, 6, 3, 2, 7, 8, 8, 6, 5, 9, 3, 6, 1, 5, 3, 3, 8, 1, 8, 2, 7, 9, 6, 8, 2, 3, 0, 3, 0, 1, 9, 5, 2, - 0, 3, 5, 3, 0, 1, 8, 5, 2, 9, 6, 8, 9, 9, 5, 7, 7, 3, 6, 2, 2, 5, 9, 9, 4, 1, 3, 8, 9, 1, 2, 4, 9, 7, 2, 1, 7, 7, 5, 2, 8, 3, 4, 7, 9, 1, 3, 1, 5, 1, 5, 5, 7, 4, 8, 5, 7, 2, 4, 2, 4, 5, 4, 1, 5, 0, 6, 9, 5, 9, - 5, 0, 8, 2, 9, 5, 3, 3, 1, 1, 6, 8, 6, 1, 7, 2, 7, 8, 5, 5, 8, 8, 9, 0, 7, 5, 0, 9, 8, 3, 8, 1, 7, 5, 4, 6, 3, 7, 4, 6, 4, 9, 3, 9, 3, 1, 9, 2, 5, 5, 0, 6, 0, 4, 0, 0, 9, 2, 7, 7, 0, 1, 6, 7, 1, 1, 3, 9, 0, 0, - 9, 8, 4, 8, 8, 2, 4, 0, 1, 2, 8, 5, 8, 3, 6, 1, 6, 0, 3, 5, 6, 3, 7, 0, 7, 6, 6, 0, 1, 0, 4, 7, 1, 0, 1, 8, 1, 9, 4, 2, 9, 5, 5, 5, 9, 6, 1, 9, 8, 9, 4, 6, 7, 6, 7, 8, 3, 7, 4, 4, 9, 4, 4, 8, 2, 5, 5, 3, 7, 9, - 7, 7, 4, 7, 2, 6, 8, 4, 7, 1, 0, 4, 0, 4, 7, 5, 3, 4, 6, 4, 6, 2, 0, 8, 0, 4, 6, 6, 8, 4, 2, 5, 9, 0, 6, 9, 4, 9, 1, 2, 9, 3, 3, 1, 3, 6, 7, 7, 0, 2, 8, 9, 8, 9, 1, 5, 2, 1, 0, 4, 7, 5, 2, 1, 6, 2, 0, 5, 6, 9, - 6, 6, 0, 2, 4, 0, 5, 8, 0, 3, 8, 1, 5, 0, 1, 9, 3, 5, 1, 1, 2, 5, 3, 3, 8, 2, 4, 3, 0, 0, 3, 5, 5, 8, 7, 6, 4, 0, 2, 4, 7, 4, 9, 6, 4, 7, 3, 2, 6, 3, 9, 1, 4, 1, 9, 9, 2, 7, 2, 6, 0, 4, 2, 6, 9, 9, 2, 2, 7, 9, - 6, 7, 8, 2, 3, 5, 4, 7, 8, 1, 6, 3, 6, 0, 0, 9, 3, 4, 1, 7, 2, 1, 6, 4, 1, 2, 1, 9, 9, 2, 4, 5, 8, 6, 3, 1, 5, 0, 3, 0, 2, 8, 6, 1, 8, 2, 9, 7, 4, 5, 5, 5, 7, 0, 6, 7, 4, 9, 8, 3, 8, 5, 0, 5, 4, 9, 4, 5, 8, 8, - 5, 8, 6, 9, 2, 6, 9, 9, 5, 6, 9, 0, 9, 2, 7, 2, 1, 0, 7, 9, 7, 5, 0, 9, 3, 0, 2, 9, 5, 5, 3, 2, 1, 1, 6, 5, 3, 4, 4, 9, 8, 7, 2, 0, 2, 7, 5, 5, 9, 6, 0, 2, 3, 6, 4, 8, 0, 6, 6, 5, 4, 9, 9, 1, 1, 9, 8, 8, 1, 8, - 3, 4, 7, 9, 7, 7, 5, 3, 5, 6, 6, 3, 6, 9, 8, 0, 7, 4, 2, 6, 5, 4, 2, 5, 2, 7, 8, 6, 2, 5, 5, 1, 8, 1, 8, 4, 1, 7, 5, 7, 4, 6, 7, 2, 8, 9, 0, 9, 7, 7, 7, 7, 2, 7, 9, 3, 8, 0, 0, 0, 8, 1, 6, 4, 7, 0, 6, 0, 0, 1, - 6, 1, 4, 5, 2, 4, 9, 1, 9, 2, 1, 7, 3, 2, 1, 7, 2, 1, 4, 7, 7, 2, 3, 5, 0, 1, 4, 1, 4, 4, 1, 9, 7, 3, 5, 6, 8, 5, 4, 8, 1, 6, 1, 3, 6, 1, 1, 5, 7, 3, 5, 2, 5, 5, 2, 1, 3, 3, 4, 7, 5, 7, 4, 1, 8, 4, 9, 4, 6, 8, - 4, 3, 8, 5, 2, 3, 3, 2, 3, 9, 0, 7, 3, 9, 4, 1, 4, 3, 3, 3, 4, 5, 4, 7, 7, 6, 2, 4, 1, 6, 8, 6, 2, 5, 1, 8, 9, 8, 3, 5, 6, 9, 4, 8, 5, 5, 6, 2, 0, 9, 9, 2, 1, 9, 2, 2, 2, 1, 8, 4, 2, 7, 2, 5, 5, 0, 2, 5, 4, 2, - 5, 6, 8, 8, 7, 6, 7, 1, 7, 9, 0, 4, 9, 4, 6, 0, 1, 6, 5, 3, 4, 6, 6, 8, 0, 4, 9, 8, 8, 6, 2, 7, 2, 3, 2, 7, 9, 1, 7, 8, 6, 0, 8, 5, 7, 8, 4, 3, 8, 3, 8, 2, 7, 9, 6, 7, 9, 7, 6, 6, 8, 1, 4, 5, 4, 1, 0, 0, 9, 5, - 3, 8, 8, 3, 7, 8, 6, 3, 6, 0, 9, 5, 0, 6, 8, 0, 0, 6, 4, 2, 2, 5, 1, 2, 5, 2, 0, 5, 1, 1, 7, 3, 9, 2, 9, 8, 4, 8, 9, 6, 0, 8, 4, 1, 2, 8, 4, 8, 8, 6, 2, 6, 9, 4, 5, 6, 0, 4, 2, 4, 1, 9, 6, 5, 2, 8, 5, 0, 2, 2, - 2, 1, 0, 6, 6, 1, 1, 8, 6, 3, 0, 6, 7, 4, 4, 2, 7, 8, 6, 2, 2, 0, 3, 9, 1, 9, 4, 9, 4, 5, 0, 4, 7, 1, 2, 3, 7, 1, 3, 7, 8, 6, 9, 6, 0, 9, 5, 6, 3, 6, 4, 3, 7, 1, 9, 1, 7, 2, 8, 7, 4, 6, 7, 7, 6, 4, 6, 5, 7, 5, - 7, 3, 9, 6, 2, 4, 1, 3, 8, 9, 0, 8, 6, 5, 8, 3, 2, 6, 4, 5, 9, 9, 5, 8, 1, 3, 3, 9, 0, 4, 7, 8, 0, 2, 7, 5, 9, 0, 0, 9, 9, 4, 6, 5, 7, 6, 4, 0, 7, 8, 9, 5, 1, 2, 6, 9, 4, 6, 8, 3, 9, 8, 3, 5, 2, 5, 9, 5, 7, 0, - 9, 8, 2, 5, 8, 2, 2, 6, 2, 0, 5, 2, 2, 4, 8, 9, 4, 0, 7, 7, 2, 6, 7, 1, 9, 4, 7, 8, 2, 6, 8, 4, 8, 2, 6, 0, 1, 4, 7, 6, 9, 9, 0, 9, 0, 2, 6, 4, 0, 1, 3, 6, 3, 9, 4, 4, 3, 7, 4, 5, 5, 3, 0, 5, 0, 6, 8, 2, 0, 3, - 4, 9, 6, 2, 5, 2, 4, 5, 1, 7, 4, 9, 3, 9, 9, 6, 5, 1, 4, 3, 1, 4, 2, 9, 8, 0, 9, 1, 9, 0, 6, 5, 9, 2, 5, 0, 9, 3, 7, 2, 2, 1, 6, 9, 6, 4, 6, 1, 5, 1, 5, 7, 0, 9, 8, 5, 8, 3, 8, 7, 4, 1, 0, 5, 9, 7, 8, 8, 5, 9, - 5, 9, 7, 7, 2, 9, 7, 5, 4, 9, 8, 9, 3, 0, 1, 6, 1, 7, 5, 3, 9, 2, 8, 4, 6, 8, 1, 3, 8, 2, 6, 8, 6, 8, 3, 8, 6, 8, 9, 4, 2, 7, 7, 4, 1, 5, 5, 9, 9, 1, 8, 5, 5, 9, 2, 5, 2, 4, 5, 9, 5, 3, 9, 5, 9, 4, 3, 1, 0, 4, - 9, 9, 7, 2, 5, 2, 4, 6, 8, 0, 8, 4, 5, 9, 8, 7, 2, 7, 3, 6, 4, 4, 6, 9, 5, 8, 4, 8, 6, 5, 3, 8, 3, 6, 7, 3, 6, 2, 2, 2, 6, 2, 6, 0, 9, 9, 1, 2, 4, 6, 0, 8, 0, 5, 1, 2, 4, 3, 8, 8, 4, 3, 9, 0, 4, 5, 1, 2, 4, 4, - 1, 3, 6, 5, 4, 9, 7, 6, 2, 7, 8, 0, 7, 9, 7, 7, 1, 5, 6, 9, 1, 4, 3, 5, 9, 9, 7, 7, 0, 0, 1, 2, 9, 6, 1, 6, 0, 8, 9, 4, 4, 1, 6, 9, 4, 8, 6, 8, 5, 5, 5, 8, 4, 8, 4, 0, 6, 3, 5, 3, 4, 2, 2, 0, 7, 2, 2, 2, 5, 8, - 2, 8, 4, 8, 8, 6, 4, 8, 1, 5, 8, 4, 5, 6, 0, 2, 8, 5, 0, 6, 0, 1, 6, 8, 4, 2, 7, 3, 9, 4, 5, 2, 2, 6, 7, 4, 6, 7, 6, 7, 8, 8, 9, 5, 2, 5, 2, 1, 3, 8, 5, 2, 2, 5, 4, 9, 9, 5, 4, 6, 6, 6, 7, 2, 7, 8, 2, 3, 9, 8, - 6, 4, 5, 6, 5, 9, 6, 1, 1, 6, 3, 5, 4, 8, 8, 6, 2, 3, 0, 5, 7, 7, 4, 5, 6, 4, 9, 8, 0, 3, 5, 5, 9, 3, 6, 3, 4, 5, 6, 8, 1, 7, 4, 3, 2, 4, 1, 1, 2, 5, 1, 5, 0, 7, 6, 0, 6, 9, 4, 7, 9, 4, 5, 1, 0, 9, 6, 5, 9, 6, - 0, 9, 4, 0, 2, 5, 2, 2, 8, 8, 7, 9, 7, 1, 0, 8, 9, 3, 1, 4, 5, 6, 6, 9, 1, 3, 6, 8, 6, 7, 2, 2, 8, 7, 4, 8, 9, 4, 0, 5, 6, 0, 1, 0, 1, 5, 0, 3, 3, 0, 8, 6, 1, 7, 9, 2, 8, 6, 8, 0, 9, 2, 0, 8, 7, 4, 7, 6, 0, 9, - 1, 7, 8, 2, 4, 9, 3, 8, 5, 8, 9, 0, 0, 9, 7, 1, 4, 9, 0, 9, 6, 7, 5, 9, 8, 5, 2, 6, 1, 3, 6, 5, 5, 4, 9, 7, 8, 1, 8, 9, 3, 1, 2, 9, 7, 8, 4, 8, 2, 1, 6, 8, 2, 9, 9, 8, 9, 4, 8, 7, 2, 2, 6, 5, 8, 8, 0, 4, 8, 5, - 7, 5, 6, 4, 0, 1, 4, 2, 7, 0, 4, 7, 7, 5, 5, 5, 1, 3, 2, 3, 7, 9, 6, 4, 1, 4, 5, 1, 5, 2, 3, 7, 4, 6, 2, 3, 4, 3, 6, 4, 5, 4, 2, 8, 5, 8, 4, 4, 4, 7, 9, 5, 2, 6, 5, 8, 6, 7, 8, 2, 1, 0, 5, 1, 1, 4, 1, 3, 5, 4, - 7, 3, 5, 7, 3, 9, 5, 2, 3, 1, 1, 3, 4, 2, 7, 1, 6, 6, 1, 0, 2, 1, 3, 5, 9, 6, 9, 5, 3, 6, 2, 3, 1, 4, 4, 2, 9, 5, 2, 4, 8, 4, 9, 3, 7, 1, 8, 7, 1, 1, 0, 1, 4, 5, 7, 6, 5, 4, 0, 3, 5, 9, 0, 2, 7, 9, 9, 3, 4, 4, - 0, 3, 7, 4, 2, 0, 0, 7, 3, 1, 0, 5, 7, 8, 5, 3, 9, 0, 6, 2, 1, 9, 8, 3, 8, 7, 4, 4, 7, 8, 0, 8, 4, 7, 8, 4, 8, 9, 6, 8, 3, 3, 2, 1, 4, 4, 5, 7, 1, 3, 8, 6, 8, 7, 5, 1, 9, 4, 3, 5, 0, 6, 4, 3, 0, 2, 1, 8, 4, 5, - 3, 1, 9, 1, 0, 4, 8, 4, 8, 1, 0, 0, 5, 3, 7, 0, 6, 1, 4, 6, 8, 0, 6, 7, 4, 9, 1, 9, 2, 7, 8, 1, 9, 1, 1, 9, 7, 9, 3, 9, 9, 5, 2, 0, 6, 1, 4, 1, 9, 6, 6, 3, 4, 2, 8, 7, 5, 4, 4, 4, 0, 6, 4, 3, 7, 4, 5, 1, 2, 3, - 7, 1, 8, 1, 9, 2, 1, 7, 9, 9, 9, 8, 3, 9, 1, 0, 1, 5, 9, 1, 9, 5, 6, 1, 8, 1, 4, 6, 7, 5, 1, 4, 2, 6, 9, 1, 2, 3, 9, 7, 4, 8, 9, 4, 0, 9, 0, 7, 1, 8, 6, 4, 9, 4, 2, 3, 1, 9, 6, 1, 5, 6, 7, 9, 4, 5, 2, 0, 8, 0, - 9, 5, 1, 4, 6, 5, 5, 0, 2, 2, 5, 2, 3, 1, 6, 0, 3, 8, 8, 1, 9, 3, 0, 1, 4, 2, 0, 9, 3, 7, 6, 2, 1, 3, 7, 8, 5, 5, 9, 5, 6, 6, 3, 8, 9, 3, 7, 7, 8, 7, 0, 8, 3, 0, 3, 9, 0, 6, 9, 7, 9, 2, 0, 7, 7, 3, 4, 6, 7, 2, - 2, 1, 8, 2, 5, 6, 2, 5, 9, 9, 6, 6, 1, 5, 0, 1, 4, 2, 1, 5, 0, 3, 0, 6, 8, 0, 3, 8, 4, 4, 7, 7, 3, 4, 5, 4, 9, 2, 0, 2, 6, 0, 5, 4, 1, 4, 6, 6, 5, 9, 2, 5, 2, 0, 1, 4, 9, 7, 4, 4, 2, 8, 5, 0, 7, 3, 2, 5, 1, 8, - 6, 6, 6, 0, 0, 2, 1, 3, 2, 4, 3, 4, 0, 8, 8, 1, 9, 0, 7, 1, 0, 4, 8, 6, 3, 3, 1, 7, 3, 4, 6, 4, 9, 6, 5, 1, 4, 5, 3, 9, 0, 5, 7, 9, 6, 2, 6, 8, 5, 6, 1, 0, 0, 5, 5, 0, 8, 1, 0, 6, 6, 5, 8, 7, 9, 6, 9, 9, 8, 1, - 6, 3, 5, 7, 4, 7, 3, 6, 3, 8, 4, 0, 5, 2, 5, 7, 1, 4, 5, 9, 1, 0, 2, 8, 9, 7, 0, 6, 4, 1, 4, 0, 1, 1, 0, 9, 7, 1, 2, 0, 6, 2, 8, 0, 4, 3, 9, 0, 3, 9, 7, 5, 9, 5, 1, 5, 6, 7, 7, 1, 5, 7, 7, 0, 0, 4, 2, 0, 3, 3, - 7, 8, 6, 9, 9, 3, 6, 0, 0, 7, 2, 3, 0, 5, 5, 8, 7, 6, 3, 1, 7, 6, 3, 5, 9, 4, 2, 1, 8, 7, 3, 1, 2, 5, 1, 4, 7, 1, 2, 0, 5, 3, 2, 9, 2, 8, 1, 9, 1, 8, 2, 6, 1, 8, 6, 1, 2, 5, 8, 6, 7, 3, 2, 1, 5, 7, 9, 1, 9, 8, - 4, 1, 4, 8, 4, 8, 8, 2, 9, 1, 6, 4, 4, 7, 0, 6, 0, 9, 5, 7, 5, 2, 7, 0, 6, 9, 5, 7, 2, 2, 0, 9, 1, 7, 5, 6, 7, 1, 1, 6, 7, 2, 2, 9, 1, 0, 9, 8, 1, 6, 9, 0, 9, 1, 5, 2, 8, 0, 1, 7, 3, 5, 0, 6, 7, 1, 2, 7, 4, 8, - 5, 8, 3, 2, 2, 2, 8, 7, 1, 8, 3, 5, 2, 0, 9, 3, 5, 3, 9, 6, 5, 7, 2, 5, 1, 2, 1, 0, 8, 3, 5, 7, 9, 1, 5, 1, 3, 6, 9, 8, 8, 2, 0, 9, 1, 4, 4, 4, 2, 1, 0, 0, 6, 7, 5, 1, 0, 3, 3, 4, 6, 7, 1, 1, 0, 3, 1, 4, 1, 2, - 6, 7, 1, 1, 1, 3, 6, 9, 9, 0, 8, 6, 5, 8, 5, 1, 6, 3, 9, 8, 3, 1, 5, 0, 1, 9, 7, 0, 1, 6, 5, 1, 5, 1, 1, 6, 8, 5, 1, 7, 1, 4, 3, 7, 6, 5, 7, 6, 1, 8, 3, 5, 1, 5, 5, 6, 5, 0, 8, 8, 4, 9, 0, 9, 9, 8, 9, 8, 5, 9, - 9, 8, 2, 3, 8, 7, 3, 4, 5, 5, 2, 8, 3, 3, 1, 6, 3, 5, 5, 0, 7, 6, 4, 7, 9, 1, 8, 5, 3, 5, 8, 9, 3, 2, 2, 6, 1, 8, 5, 4, 8, 9, 6, 3, 2, 1, 3, 2, 9, 3, 3, 0, 8, 9, 8, 5, 7, 0, 6, 4, 2, 0, 4, 6, 7, 5, 2, 5, 9, 0, - 7, 0, 9, 1, 5, 4, 8, 1, 4, 1, 6, 5, 4, 9, 8, 5, 9, 4, 6, 1, 6, 3, 7, 1, 8, 0, 2, 7, 0, 9, 8, 1, 9, 9, 4, 3, 0, 9, 9, 2, 4, 4, 8, 8, 9, 5, 7, 5, 7, 1, 2, 8, 2, 8, 9, 0, 5, 9, 2, 3, 2, 3, 3, 2, 6, 0, 9, 7, 2, 9, - 9, 7, 1, 2, 0, 8, 4, 4, 3, 3, 5, 7, 3, 2, 6, 5, 4, 8, 9, 3, 8, 2, 3, 9, 1, 1, 9, 3, 2, 5, 9, 7, 4, 6, 3, 6, 6, 7, 3, 0, 5, 8, 3, 6, 0, 4, 1, 4, 2, 8, 1, 3, 8, 8, 3, 0, 3, 2, 0, 3, 8, 2, 4, 9, 0, 3, 7, 5, 8, 9, - 8, 5, 2, 4, 3, 7, 4, 4, 1, 7, 0, 2, 9, 1, 3, 2, 7, 6, 5, 6, 1, 8, 0, 9, 3, 7, 7, 3, 4, 4, 4, 0, 3, 0, 7, 0, 7, 4, 6, 9, 2, 1, 1, 2, 0, 1, 9, 1, 3, 0, 2, 0, 3, 3, 0, 3, 8, 0, 1, 9, 7, 6, 2, 1, 1, 0, 1, 1, 0, 0, - 4, 4, 9, 2, 9, 3, 2, 1, 5, 1, 6, 0, 8, 4, 2, 4, 4, 4, 8, 5, 9, 6, 3, 7, 6, 6, 9, 8, 3, 8, 9, 5, 2, 2, 8, 6, 8, 4, 7, 8, 3, 1, 2, 3, 5, 5, 2, 6, 5, 8, 2, 1, 3, 1, 4, 4, 9, 5, 7, 6, 8, 5, 7, 2, 6, 2, 4, 3, 3, 4, - 4, 1, 8, 9, 3, 0, 3, 9, 6, 8, 6, 4, 2, 6, 2, 4, 3, 4, 1, 0, 7, 7, 3, 2, 2, 6, 9, 7, 8, 0, 2, 8, 0, 7, 3, 1, 8, 9, 1, 5, 4, 4, 1, 1, 0, 1, 0, 4, 4, 6, 8, 2, 3, 2, 5, 2, 7, 1, 6, 2, 0, 1, 0, 5, 2, 6, 5, 2, 2, 7, - 2, 1, 1, 1, 6, 6, 0, 3, 9, 6, 6, 6, 5, 5, 7, 3, 0, 9, 2, 5, 4, 7, 1, 1, 0, 5, 5, 7, 8, 5, 3, 7, 6, 3, 4, 6, 6, 8, 2, 0, 6, 5, 3, 1, 0, 9, 8, 9, 6, 5, 2, 6, 9, 1, 8, 6, 2, 0, 5, 6, 4, 7, 6, 9, 3, 1, 2, 5, 7, 0, - 5, 8, 6, 3, 5, 6, 6, 2, 0, 1, 8, 5, 5, 8, 1, 0, 0, 7, 2, 9, 3, 6, 0, 6, 5, 9, 8, 7, 6, 4, 8, 6, 1, 1, 7, 9, 1, 0, 4, 5, 3, 3, 4, 8, 8, 5, 0, 3, 4, 6, 1, 1, 3, 6, 5, 7, 6, 8, 6, 7, 5, 3, 2, 4, 9, 4, 4, 1, 6, 6, - 8, 0, 3, 9, 6, 2, 6, 5, 7, 9, 7, 8, 7, 7, 1, 8, 5, 5, 6, 0, 8, 4, 5, 5, 2, 9, 6, 5, 4, 1, 2, 6, 6, 5, 4, 0, 8, 5, 3, 0, 6, 1, 4, 3, 4, 4, 4, 3, 1, 8, 5, 8, 6, 7, 6, 9, 7, 5, 1, 4, 5, 6, 6, 1, 4, 0, 6, 8, 0, 0, - 7, 0, 0, 2, 3, 7, 8, 7, 7, 6, 5, 9, 1, 3, 4, 4, 0, 1, 7, 1, 2, 7, 4, 9, 4, 7, 0, 4, 2, 0, 5, 6, 2, 2, 3, 0, 5, 3, 8, 9, 9, 4, 5, 6, 1, 3, 1, 4, 0, 7, 1, 1, 2, 7, 0, 0, 0, 4, 0, 7, 8, 5, 4, 7, 3, 3, 2, 6, 9, 9, - 3, 9, 0, 8, 1, 4, 5, 4, 6, 6, 4, 6, 4, 5, 8, 8, 0, 7, 9, 7, 2, 7, 0, 8, 2, 6, 6, 8, 3, 0, 6, 3, 4, 3, 2, 8, 5, 8, 7, 8, 5, 6, 9, 8, 3, 0, 5, 2, 3, 5, 8, 0, 8, 9, 3, 3, 0, 6, 5, 7, 5, 7, 4, 0, 6, 7, 9, 5, 4, 5, - 7, 1, 6, 3, 7, 7, 5, 2, 5, 4, 2, 0, 2, 1, 1, 4, 9, 5, 5, 7, 6, 1, 5, 8, 1, 4, 0, 0, 2, 5, 0, 1, 2, 6, 2, 2, 8, 5, 9, 4, 1, 3, 0, 2, 1, 6, 4, 7, 1, 5, 5, 0, 9, 7, 9, 2, 5, 9, 2, 3, 0, 9, 9, 0, 7, 9, 6, 5, 4, 7, - 3, 7, 6, 1, 2, 5, 5, 1, 7, 6, 5, 6, 7, 5, 1, 3, 5, 7, 5, 1, 7, 8, 2, 9, 6, 6, 6, 4, 5, 4, 7, 7, 9, 1, 7, 4, 5, 0, 1, 1, 2, 9, 9, 6, 1, 4, 8, 9, 0, 3, 0, 4, 6, 3, 9, 9, 4, 7, 1, 3, 2, 9, 6, 2, 1, 0, 7, 3, 4, 0, - 4, 3, 7, 5, 1, 8, 9, 5, 7, 3, 5, 9, 6, 1, 4, 5, 8, 9, 0, 1, 9, 3, 8, 9, 7, 1, 3, 1, 1, 1, 7, 9, 0, 4, 2, 9, 7, 8, 2, 8, 5, 6, 4, 7, 5, 0, 3, 2, 0, 3, 1, 9, 8, 6, 9, 1, 5, 1, 4, 0, 2, 8, 7, 0, 8, 0, 8, 5, 9, 9, - 0, 4, 8, 0, 1, 0, 9, 4, 1, 2, 1, 4, 7, 2, 2, 1, 3, 1, 7, 9, 4, 7, 6, 4, 7, 7, 7, 2, 6, 2, 2, 4, 1, 4, 2, 5, 4, 8, 5, 4, 5, 4, 0, 3, 3, 2, 1, 5, 7, 1, 8, 5, 3, 0, 6, 1, 4, 2, 2, 8, 8, 1, 3, 7, 5, 8, 5, 0, 4, 3, - 0, 6, 3, 3, 2, 1, 7, 5, 1, 8, 2, 9, 7, 9, 8, 6, 6, 2, 2, 3, 7, 1, 7, 2, 1, 5, 9, 1, 6, 0, 7, 7, 1, 6, 6, 9, 2, 5, 4, 7, 4, 8, 7, 3, 8, 9, 8, 6, 6, 5, 4, 9, 4, 9, 4, 5, 0, 1, 1, 4, 6, 5, 4, 0, 6, 2, 8, 4, 3, 3, - 6, 6, 3, 9, 3, 7, 9, 0, 0, 3, 9, 7, 6, 9, 2, 6, 5, 6, 7, 2, 1, 4, 6, 3, 8, 5, 3, 0, 6, 7, 3, 6, 0, 9, 6, 5, 7, 1, 2, 0, 9, 1, 8, 0, 7, 6, 3, 8, 3, 2, 7, 1, 6, 6, 4, 1, 6, 2, 7, 4, 8, 8, 8, 8, 0, 0, 7, 8, 6, 9, - 2, 5, 6, 0, 2, 9, 0, 2, 2, 8, 4, 7, 2, 1, 0, 4, 0, 3, 1, 7, 2, 1, 1, 8, 6, 0, 8, 2, 0, 4, 1, 9, 0, 0, 0, 4, 2, 2, 9, 6, 6, 1, 7, 1, 1, 9, 6, 3, 7, 7, 9, 2, 1, 3, 3, 7, 5, 7, 5, 1, 1, 4, 9, 5, 9, 5, 0, 1, 5, 6, - 6, 0, 4, 9, 6, 3, 1, 8, 6, 2, 9, 4, 7, 2, 6, 5, 4, 7, 3, 6, 4, 2, 5, 2, 3, 0, 8, 1, 7, 7, 0, 3, 6, 7, 5, 1, 5, 9, 0, 6, 7, 3, 5, 0, 2, 3, 5, 0, 7, 2, 8, 3, 5, 4, 0, 5, 6, 7, 0, 4, 0, 3, 8, 6, 7, 4, 3, 5, 1, 3, - 6, 2, 2, 2, 2, 4, 7, 7, 1, 5, 8, 9, 1, 5, 0, 4, 9, 5, 3, 0, 9, 8, 4, 4, 4, 8, 9, 3, 3, 3, 0, 9, 6, 3, 4, 0, 8, 7, 8, 0, 7, 6, 9, 3, 2, 5, 9, 9, 3, 9, 7, 8, 0, 5, 4, 1, 9, 3, 4, 1, 4, 4, 7, 3, 7, 7, 4, 4, 1, 8, - 4, 2, 6, 3, 1, 2, 9, 8, 6, 0, 8, 0, 9, 9, 8, 8, 8, 6, 8, 7, 4, 1, 3, 2, 6, 0, 4, 7, 2, 1, 5, 6, 9, 5, 1, 6, 2, 3, 9, 6, 5, 8, 6, 4, 5, 7, 3, 0, 2, 1, 6, 3, 1, 5, 9, 8, 1, 9, 3, 1, 9, 5, 1, 6, 7, 3, 5, 3, 8, 1, - 2, 9, 7, 4, 1, 6, 7, 7, 2, 9, 4, 7, 8, 6, 7, 2, 4, 2, 2, 9, 2, 4, 6, 5, 4, 3, 6, 6, 8, 0, 0, 9, 8, 0, 6, 7, 6, 9, 2, 8, 2, 3, 8, 2, 8, 0, 6, 8, 9, 9, 6, 4, 0, 0, 4, 8, 2, 4, 3, 5, 4, 0, 3, 7, 0, 1, 4, 1, 6, 3, - 1, 4, 9, 6, 5, 8, 9, 7, 9, 4, 0, 9, 2, 4, 3, 2, 3, 7, 8, 9, 6, 9, 0, 7, 0, 6, 9, 7, 7, 9, 4, 2, 2, 3, 6, 2, 5, 0, 8, 2, 2, 1, 6, 8, 8, 9, 5, 7, 3, 8, 3, 7, 9, 8, 6, 2, 3, 0, 0, 1, 5, 9, 3, 7, 7, 6, 4, 7, 1, 6, - 5, 1, 2, 2, 8, 9, 3, 5, 7, 8, 6, 0, 1, 5, 8, 8, 1, 6, 1, 7, 5, 5, 7, 8, 2, 9, 7, 3, 5, 2, 3, 3, 4, 4, 6, 0, 4, 2, 8, 1, 5, 1, 2, 6, 2, 7, 2, 0, 3, 7, 3, 4, 3, 1, 4, 6, 5, 3, 1, 9, 7, 7, 7, 7, 4, 1, 6, 0, 3, 1, - 9, 9, 0, 6, 6, 5, 5, 4, 1, 8, 7, 6, 3, 9, 7, 9, 2, 9, 3, 3, 4, 4, 1, 9, 5, 2, 1, 5, 4, 1, 3, 4, 1, 8, 9, 9, 4, 8, 5, 4, 4, 4, 7, 3, 4, 5, 6, 7, 3, 8, 3, 1, 6, 2, 4, 9, 9, 3, 4, 1, 9, 1, 3, 1, 8, 1, 4, 8, 0, 9, - 2, 7, 7, 7, 7, 1, 0, 3, 8, 6, 3, 8, 7, 7, 3, 4, 3, 1, 7, 7, 2, 0, 7, 5, 4, 5, 6, 5, 4, 5, 3, 2, 2, 0, 7, 7, 7, 0, 9, 2, 1, 2, 0, 1, 9, 0, 5, 1, 6, 6, 0, 9, 6, 2, 8, 0, 4, 9, 0, 9, 2, 6, 3, 6, 0, 1, 9, 7, 5, 9, - 8, 8, 2, 8, 1, 6, 1, 3, 3, 2, 3, 1, 6, 6, 6, 3, 6, 5, 2, 8, 6, 1, 9, 3, 2, 6, 6, 8, 6, 3, 3, 6, 0, 6, 2, 7, 3, 5, 6, 7, 6, 3, 0, 3, 5, 4, 4, 7, 7, 6, 2, 8, 0, 3, 5, 0, 4, 5, 0, 7, 7, 7, 2, 3, 5, 5, 4, 7, 1, 0, - 5, 8, 5, 9, 5, 4, 8, 7, 0, 2, 7, 9, 0, 8, 1, 4, 3, 5, 6, 2, 4, 0, 1, 4, 5, 1, 7, 1, 8, 0, 6, 2, 4, 6, 4, 3, 6, 2, 6, 7, 9, 4, 5, 6, 1, 2, 7, 5, 3, 1, 8, 1, 3, 4, 0, 7, 8, 3, 3, 0, 3, 3, 6, 2, 5, 4, 2, 3, 2, 7, - 8, 3, 9, 4, 4, 9, 7, 5, 3, 8, 2, 4, 3, 7, 2, 0, 5, 8, 3, 5, 3, 1, 1, 4, 7, 7, 1, 1, 9, 9, 2, 6, 0, 6, 3, 8, 1, 3, 3, 4, 6, 7, 7, 6, 8, 7, 9, 6, 9, 5, 9, 7, 0, 3, 0, 9, 8, 3, 3, 9, 1, 3, 0, 7, 7, 1, 0, 9, 8, 7, - 0, 4, 0, 8, 5, 9, 1, 3, 3, 7, 4, 6, 4, 1, 4, 4, 2, 8, 2, 2, 7, 7, 2, 6, 3, 4, 6, 5, 9, 4, 7, 0, 4, 7, 4, 5, 8, 7, 8, 4, 7, 7, 8, 7, 2, 0, 1, 9, 2, 7, 7, 1, 5, 2, 8, 0, 7, 3, 1, 7, 6, 7, 9, 0, 7, 7, 0, 7, 1, 5, - 7, 2, 1, 3, 4, 4, 4, 7, 3, 0, 6, 0, 5, 7, 0, 0, 7, 3, 3, 4, 9, 2, 4, 3, 6, 9, 3, 1, 1, 3, 8, 3, 5, 0, 4, 9, 3, 1, 6, 3, 1, 2, 8, 4, 0, 4, 2, 5, 1, 2, 1, 9, 2, 5, 6, 5, 1, 7, 9, 8, 0, 6, 9, 4, 1, 1, 3, 5, 2, 8, - 0, 1, 3, 1, 4, 7, 0, 1, 3, 0, 4, 7, 8, 1, 6, 4, 3, 7, 8, 8, 5, 1, 8, 5, 2, 9, 0, 9, 2, 8, 5, 4, 5, 2, 0, 1, 1, 6, 5, 8, 3, 9, 3, 4, 1, 9, 6, 5, 6, 2, 1, 3, 4, 9, 1, 4, 3, 4, 1, 5, 9, 5, 6, 2, 5, 8, 6, 5, 8, 6, - 5, 5, 7, 0, 5, 5, 2, 6, 9, 0, 4, 9, 6, 5, 2, 0, 9, 8, 5, 8, 0, 3, 3, 8, 5, 0, 7, 2, 2, 4, 2, 6, 4, 8, 2, 9, 3, 9, 7, 2, 8, 5, 8, 4, 7, 8, 3, 1, 6, 3, 0, 5, 7, 7, 7, 7, 5, 6, 0, 6, 8, 8, 8, 7, 6, 4, 4, 6, 2, 4, - 8, 2, 4, 6, 8, 5, 7, 9, 2, 6, 0, 3, 9, 5, 3, 5, 2, 7, 7, 3, 4, 8, 0, 3, 0, 4, 8, 0, 2, 9, 0, 0, 5, 8, 7, 6, 0, 7, 5, 8, 2, 5, 1, 0, 4, 7, 4, 7, 0, 9, 1, 6, 4, 3, 9, 6, 1, 3, 6, 2, 6, 7, 6, 0, 4, 4, 9, 2, 5, 6, - 2, 7, 4, 2, 0, 4, 2, 0, 8, 3, 2, 0, 8, 5, 6, 6, 1, 1, 9, 0, 6, 2, 5, 4, 5, 4, 3, 3, 7, 2, 1, 3, 1, 5, 3, 5, 9, 5, 8, 4, 5, 0, 6, 8, 7, 7, 2, 4, 6, 0, 2, 9, 0, 1, 6, 1, 8, 7, 6, 6, 7, 9, 5, 2, 4, 0, 6, 1, 6, 3, - 4, 2, 5, 2, 2, 5, 7, 7, 1, 9, 5, 4, 2, 9, 1, 6, 2, 9, 9, 1, 9, 3, 0, 6, 4, 5, 5, 3, 7, 7, 9, 9, 1, 4, 0, 3, 7, 3, 4, 0, 4, 3, 2, 8, 7, 5, 2, 6, 2, 8, 8, 8, 9, 6, 3, 9, 9, 5, 8, 7, 9, 4, 7, 5, 7, 2, 9, 1, 7, 4, - 6, 4, 2, 6, 3, 5, 7, 4, 5, 5, 2, 5, 4, 0, 7, 9, 0, 9, 1, 4, 5, 1, 3, 5, 7, 1, 1, 1, 3, 6, 9, 4, 1, 0, 9, 1, 1, 9, 3, 9, 3, 2, 5, 1, 9, 1, 0, 7, 6, 0, 2, 0, 8, 2, 5, 2, 0, 2, 6, 1, 8, 7, 9, 8, 5, 3, 1, 8, 8, 7, - 7, 0, 5, 8, 4, 2, 9, 7, 2, 5, 9, 1, 6, 7, 7, 8, 1, 3, 1, 4, 9, 6, 9, 9, 0, 0, 9, 0, 1, 9, 2, 1, 1, 6, 9, 7, 1, 7, 3, 7, 2, 7, 8, 4, 7, 6, 8, 4, 7, 2, 6, 8, 6, 0, 8, 4, 9, 0, 0, 3, 3, 7, 7, 0, 2, 4, 2, 4, 2, 9, - 1, 6, 5, 1, 3, 0, 0, 5, 0, 0, 5, 1, 6, 8, 3, 2, 3, 3, 6, 4, 3, 5, 0, 3, 8, 9, 5, 1, 7, 0, 2, 9, 8, 9, 3, 9, 2, 2, 3, 3, 4, 5, 1, 7, 2, 2, 0, 1, 3, 8, 1, 2, 8, 0, 6, 9, 6, 5, 0, 1, 1, 7, 8, 4, 4, 0, 8, 7, 4, 5, - 1, 9, 6, 0, 1, 2, 1, 2, 2, 8, 5, 9, 9, 3, 7, 1, 6, 2, 3, 1, 3, 0, 1, 7, 1, 1, 4, 4, 4, 8, 4, 6, 4, 0, 9, 0, 3, 8, 9, 0, 6, 4, 4, 9, 5, 4, 4, 4, 0, 0, 6, 1, 9, 8, 6, 9, 0, 7, 5, 4, 8, 5, 1, 6, 0, 2, 6, 3, 2, 7, - 5, 0, 5, 2, 9, 8, 3, 4, 9, 1, 8, 7, 4, 0, 7, 8, 6, 6, 8, 0, 8, 8, 1, 8, 3, 3, 8, 5, 1, 0, 2, 2, 8, 3, 3, 4, 5, 0, 8, 5, 0, 4, 8, 6, 0, 8, 2, 5, 0, 3, 9, 3, 0, 2, 1, 3, 3, 2, 1, 9, 7, 1, 5, 5, 1, 8, 4, 3, 0, 6, - 3, 5, 4, 5, 5, 0, 0, 7, 6, 6, 8, 2, 8, 2, 9, 4, 9, 3, 0, 4, 1, 3, 7, 7, 6, 5, 5, 2, 7, 9, 3, 9, 7, 5, 1, 7, 5, 4, 6, 1, 3, 9, 5, 3, 9, 8, 4, 6, 8, 3, 3, 9, 3, 6, 3, 8, 3, 0, 4, 7, 4, 6, 1, 1, 9, 9, 6, 6, 5, 3, - 8, 5, 8, 1, 5, 3, 8, 4, 2, 0, 5, 6, 8, 5, 3, 3, 8, 6, 2, 1, 8, 6, 7, 2, 5, 2, 3, 3, 4, 0, 2, 8, 3, 0, 8, 7, 1, 1, 2, 3, 2, 8, 2, 7, 8, 9, 2, 1, 2, 5, 0, 7, 7, 1, 2, 6, 2, 9, 4, 6, 3, 2, 2, 9, 5, 6, 3, 9, 8, 9, - 8, 9, 8, 9, 3, 5, 8, 2, 1, 1, 6, 7, 4, 5, 6, 2, 7, 0, 1, 0, 2, 1, 8, 3, 5, 6, 4, 6, 2, 2, 0, 1, 3, 4, 9, 6, 7, 1, 5, 1, 8, 8, 1, 9, 0, 9, 7, 3, 0, 3, 8, 1, 1, 9, 8, 0, 0, 4, 9, 7, 3, 4, 0, 7, 2, 3, 9, 6, 1, 0, - 3, 6, 8, 5, 4, 0, 6, 6, 4, 3, 1, 9, 3, 9, 5, 0, 9, 7, 9, 0, 1, 9, 0, 6, 9, 9, 6, 3, 9, 5, 5, 2, 4, 5, 3, 0, 0, 5, 4, 5, 0, 5, 8, 0, 6, 8, 5, 5, 0, 1, 9, 5, 6, 7, 3, 0, 2, 2, 9, 2, 1, 9, 1, 3, 9, 3, 3, 9, 1, 8, - 5, 6, 8, 0, 3, 4, 4, 9, 0, 3, 9, 8, 2, 0, 5, 9, 5, 5, 1, 0, 0, 2, 2, 6, 3, 5, 3, 5, 3, 6, 1, 9, 2, 0, 4, 1, 9, 9, 4, 7, 4, 5, 5, 3, 8, 5, 9, 3, 8, 1, 0, 2, 3, 4, 3, 9, 5, 5, 4, 4, 9, 5, 9, 7, 7, 8, 3, 7, 7, 9, - 0, 2, 3, 7, 4, 2, 1, 6, 1, 7, 2, 7, 1, 1, 1, 7, 2, 3, 6, 4, 3, 4, 3, 5, 4, 3, 9, 4, 7, 8, 2, 2, 1, 8, 1, 8, 5, 2, 8, 6, 2, 4, 0, 8, 5, 1, 4, 0, 0, 6, 6, 6, 0, 4, 4, 3, 3, 2, 5, 8, 8, 8, 5, 6, 9, 8, 6, 7, 0, 5, - 4, 3, 1, 5, 4, 7, 0, 6, 9, 6, 5, 7, 4, 7, 4, 5, 8, 5, 5, 0, 3, 3, 2, 3, 2, 3, 3, 4, 2, 1, 0, 7, 3, 0, 1, 5, 4, 5, 9, 4, 0, 5, 1, 6, 5, 5, 3, 7, 9, 0, 6, 8, 6, 6, 2, 7, 3, 3, 3, 7, 9, 9, 5, 8, 5, 1, 1, 5, 6, 2, - 5, 7, 8, 4, 3, 2, 2, 9, 8, 8, 2, 7, 3, 7, 2, 3, 1, 9, 8, 9, 8, 7, 5, 7, 1, 4, 1, 5, 9, 5, 7, 8, 1, 1, 1, 9, 6, 3, 5, 8, 3, 3, 0, 0, 5, 9, 4, 0, 8, 7, 3, 0, 6, 8, 1, 2, 1, 6, 0, 2, 8, 7, 6, 4, 9, 6, 2, 8, 6, 7, - 4, 4, 6, 0, 4, 7, 7, 4, 6, 4, 9, 1, 5, 9, 9, 5, 0, 5, 4, 9, 7, 3, 7, 4, 2, 5, 6, 2, 6, 9, 0, 1, 0, 4, 9, 0, 3, 7, 7, 8, 1, 9, 8, 6, 8, 3, 5, 9, 3, 8, 1, 4, 6, 5, 7, 4, 1, 2, 6, 8, 0, 4, 9, 2, 5, 6, 4, 8, 7, 9, - 8, 5, 5, 6, 1, 4, 5, 3, 7, 2, 3, 4, 7, 8, 6, 7, 3, 3, 0, 3, 9, 0, 4, 6, 8, 8, 3, 8, 3, 4, 3, 6, 3, 4, 6, 5, 5, 3, 7, 9, 4, 9, 8, 6, 4, 1, 9, 2, 7, 0, 5, 6, 3, 8, 7, 2, 9, 3, 1, 7, 4, 8, 7, 2, 3, 3, 2, 0, 8, 3, - 7, 6, 0, 1, 1, 2, 3, 0, 2, 9, 9, 1, 1, 3, 6, 7, 9, 3, 8, 6, 2, 7, 0, 8, 9, 4, 3, 8, 7, 9, 9, 3, 6, 2, 0, 1, 6, 2, 9, 5, 1, 5, 4, 1, 3, 3, 7, 1, 4, 2, 4, 8, 9, 2, 8, 3, 0, 7, 2, 2, 0, 1, 2, 6, 9, 0, 1, 4, 7, 5, - 4, 6, 6, 8, 4, 7, 6, 5, 3, 5, 7, 6, 1, 6, 4, 7, 7, 3, 7, 9, 4, 6, 7, 5, 2, 0, 0, 4, 9, 0, 7, 5, 7, 1, 5, 5, 5, 2, 7, 8, 1, 9, 6, 5, 3, 6, 2, 1, 3, 2, 3, 9, 2, 6, 4, 0, 6, 1, 6, 0, 1, 3, 6, 3, 5, 8, 1, 5, 5, 9, - 0, 7, 4, 2, 2, 0, 2, 0, 2, 0, 3, 1, 8, 7, 2, 7, 7, 6, 0, 5, 2, 7, 7, 2, 1, 9, 0, 0, 5, 5, 6, 1, 4, 8, 4, 2, 5, 5, 5, 1, 8, 7, 9, 2, 5, 3, 0, 3, 4, 3, 5, 1, 3, 9, 8, 4, 4, 2, 5, 3, 2, 2, 3, 4, 1, 5, 7, 6, 2, 3, - 3, 6, 1, 0, 6, 4, 2, 5, 0, 6, 3, 9, 0, 4, 9, 7, 5, 0, 0, 8, 6, 5, 6, 2, 7, 1, 0, 9, 5, 3, 5, 9, 1, 9, 4, 6, 5, 8, 9, 7, 5, 1, 4, 1, 3, 1, 0, 3, 4, 8, 2, 2, 7, 6, 9, 3, 0, 6, 2, 4, 7, 4, 3, 5, 3, 6, 3, 2, 5, 6, - 9, 1, 6, 0, 7, 8, 1, 5, 4, 7, 8, 1, 8, 1, 1, 5, 2, 8, 4, 3, 6, 6, 7, 9, 5, 7, 0, 6, 1, 1, 0, 8, 6, 1, 5, 3, 3, 1, 5, 0, 4, 4, 5, 2, 1, 2, 7, 4, 7, 3, 9, 2, 4, 5, 4, 4, 9, 4, 5, 4, 2, 3, 6, 8, 2, 8, 8, 6, 0, 6, - 1, 3, 4, 0, 8, 4, 1, 4, 8, 6, 3, 7, 7, 6, 7, 0, 0, 9, 6, 1, 2, 0, 7, 1, 5, 1, 2, 4, 9, 1, 4, 0, 4, 3, 0, 2, 7, 2, 5, 3, 8, 6, 0, 7, 6, 4, 8, 2, 3, 6, 3, 4, 1, 4, 3, 3, 4, 6, 2, 3, 5, 1, 8, 9, 7, 5, 7, 6, 6, 4, - 5, 2, 1, 6, 4, 1, 3, 7, 6, 7, 9, 6, 9, 0, 3, 1, 4, 9, 5, 0, 1, 9, 1, 0, 8, 5, 7, 5, 9, 8, 4, 4, 2, 3, 9, 1, 9, 8, 6, 2, 9, 1, 6, 4, 2, 1, 9, 3, 9, 9, 4, 9, 0, 7, 2, 3, 6, 2, 3, 4, 6, 4, 6, 8, 4, 4, 1, 1, 7, 3, - 9, 4, 0, 3, 2, 6, 5, 9, 1, 8, 4, 0, 4, 4, 3, 7, 8, 0, 5, 1, 3, 3, 3, 8, 9, 4, 5, 2, 5, 7, 4, 2, 3, 9, 9, 5, 0, 8, 2, 9, 6, 5, 9, 1, 2, 2, 8, 5, 0, 8, 5, 5, 5, 8, 2, 1, 5, 7, 2, 5, 0, 3, 1, 0, 7, 1, 2, 5, 7, 0, - 1, 2, 6, 6, 8, 3, 0, 2, 4, 0, 2, 9, 2, 9, 5, 2, 5, 2, 2, 0, 1, 1, 8, 7, 2, 6, 7, 6, 7, 5, 6, 2, 2, 0, 4, 1, 5, 4, 2, 0, 5, 1, 6, 1, 8, 4, 1, 6, 3, 4, 8, 4, 7, 5, 6, 5, 1, 6, 9, 9, 9, 8, 1, 1, 6, 1, 4, 1, 0, 1, - 0, 0, 2, 9, 9, 6, 0, 7, 8, 3, 8, 6, 9, 0, 9, 2, 9, 1, 6, 0, 3, 0, 2, 8, 8, 4, 0, 0, 2, 6, 9, 1, 0, 4, 1, 4, 0, 7, 9, 2, 8, 8, 6, 2, 1, 5, 0, 7, 8, 4, 2, 4, 5, 1, 6, 7, 0, 9, 0, 8, 7, 0, 0, 0, 6, 9, 9, 2, 8, 2, - 1, 2, 0, 6, 6, 0, 4, 1, 8, 3, 7, 1, 8, 0, 6, 5, 3, 5, 5, 6, 7, 2, 5, 2, 5, 3, 2, 5, 6, 7, 5, 3, 2, 8, 6, 1, 2, 9, 1, 0, 4, 2, 4, 8, 7, 7, 6, 1, 8, 2, 5, 8, 2, 9, 7, 6, 5, 1, 5, 7, 9, 5, 9, 8, 4, 7, 0, 3, 5, 6, - 2, 2, 2, 6, 2, 9, 3, 4, 8, 6, 0, 0, 3, 4, 1, 5, 8, 7, 2, 2, 9, 8, 0, 5, 3, 4, 9, 8, 9, 6, 5, 0, 2, 2, 6, 2, 9, 1, 7, 4, 8, 7, 8, 8, 2, 0, 2, 7, 3, 4, 2, 0, 9, 2, 2, 2, 2, 4, 5, 3, 3, 9, 8, 5, 6, 2, 6, 4, 7, 6, - 6, 9, 1, 4, 9, 0, 5, 5, 6, 2, 8, 4, 2, 5, 0, 3, 9, 1, 2, 7, 5, 7, 7, 1, 0, 2, 8, 4, 0, 2, 7, 9, 9, 8, 0, 6, 6, 3, 6, 5, 8, 2, 5, 4, 8, 8, 9, 2, 6, 4, 8, 8, 0, 2, 5, 4, 5, 6, 6, 1, 0, 1, 7, 2, 9, 6, 7, 0, 2, 6, - 6, 4, 0, 7, 6, 5, 5, 9, 0, 4, 2, 9, 0, 9, 9, 4, 5, 6, 8, 1, 5, 0, 6, 5, 2, 6, 5, 3, 0, 5, 3, 7, 1, 8, 2, 9, 4, 1, 2, 7, 0, 3, 3, 6, 9, 3, 1, 3, 7, 8, 5, 1, 7, 8, 6, 0, 9, 0, 4, 0, 7, 0, 8, 6, 6, 7, 1, 1, 4, 9, - 6, 5, 5, 8, 3, 4, 3, 4, 3, 4, 7, 6, 9, 3, 3, 8, 5, 7, 8, 1, 7, 1, 1, 3, 8, 6, 4, 5, 5, 8, 7, 3, 6, 7, 8, 1, 2, 3, 0, 1, 4, 5, 8, 7, 6, 8, 7, 1, 2, 6, 6, 0, 3, 4, 8, 9, 1, 3, 9, 0, 9, 5, 6, 2, 0, 0, 9, 9, 3, 9, - 3, 6, 1, 0, 3, 1, 0, 2, 9, 1, 6, 1, 6, 1, 5, 2, 8, 8, 1, 3, 8, 4, 3, 7, 9, 0, 9, 9, 0, 4, 2, 3, 1, 7, 4, 7, 3, 3, 6, 3, 9, 4, 8, 0, 4, 5, 7, 5, 9, 3, 1, 4, 9, 3, 1, 4, 0, 5, 2, 9, 7, 6, 3, 4, 7, 5, 7, 4, 8, 1, - 1, 9, 3, 5, 6, 7, 0, 9, 1, 1, 0, 1, 3, 7, 7, 5, 1, 7, 2, 1, 0, 0, 8, 0, 3, 1, 5, 5, 9, 0, 2, 4, 8, 5, 3, 0, 9, 0, 6, 6, 9, 2, 0, 3, 7, 6, 7, 1, 9, 2, 2, 0, 3, 3, 2, 2, 9, 0, 9, 4, 3, 3, 4, 6, 7, 6, 8, 5, 1, 4, - 2, 2, 1, 4, 4, 7, 7, 3, 7, 9, 3, 9, 3, 7, 5, 1, 7, 0, 3, 4, 4, 3, 6, 6, 1, 9, 9, 1, 0, 4, 0, 3, 3, 7, 5, 1, 1, 1, 7, 3, 5, 4, 7, 1, 9, 1, 8, 5, 5, 0, 4, 6, 4, 4, 9, 0, 2, 6, 3, 6, 5, 5, 1, 2, 8, 1, 6, 2, 2, 8, - 8, 2, 4, 4, 6, 2, 5, 7, 5, 9, 1, 6, 3, 3, 3, 0, 3, 9, 1, 0, 7, 2, 2, 5, 3, 8, 3, 7, 4, 2, 1, 8, 2, 1, 4, 0, 8, 8, 3, 5, 0, 8, 6, 5, 7, 3, 9, 1, 7, 7, 1, 5, 0, 9, 6, 8, 2, 8, 8, 7, 4, 7, 8, 2, 6, 5, 6, 9, 9, 5, - 9, 9, 5, 7, 4, 4, 9, 0, 6, 6, 1, 7, 5, 8, 3, 4, 4, 1, 3, 7, 5, 2, 2, 3, 9, 7, 0, 9, 6, 8, 3, 4, 0, 8, 0, 0, 5, 3, 5, 5, 9, 8, 4, 9, 1, 7, 5, 4, 1, 7, 3, 8, 1, 8, 8, 3, 9, 9, 9, 4, 4, 6, 9, 7, 4, 8, 6, 7, 6, 2, - 6, 5, 5, 1, 6, 5, 8, 2, 7, 6, 5, 8, 4, 8, 3, 5, 8, 8, 4, 5, 3, 1, 4, 2, 7, 7, 5, 6, 8, 7, 9, 0, 0, 2, 9, 0, 9, 5, 1, 7, 0, 2, 8, 3, 5, 2, 9, 7, 1, 6, 3, 4, 4, 5, 6, 2, 1, 2, 9, 6, 4, 0, 4, 3, 5, 2, 3, 1, 1, 7, - 6, 0, 0, 6, 6, 5, 1, 0, 1, 2, 4, 1, 2, 0, 0, 6, 5, 9, 7, 5, 5, 8, 5, 1, 2, 7, 6, 1, 7, 8, 5, 8, 3, 8, 2, 9, 2, 0, 4, 1, 9, 7, 4, 8, 4, 4, 2, 3, 6, 0, 8, 0, 0, 7, 1, 9, 3, 0, 4, 5, 7, 6, 1, 8, 9, 3, 2, 3, 4, 9, - 2, 2, 9, 2, 7, 9, 6, 5, 0, 1, 9, 8, 7, 5, 1, 8, 7, 2, 1, 2, 7, 2, 6, 7, 5, 0, 7, 9, 8, 1, 2, 5, 5, 4, 7, 0, 9, 5, 8, 9, 0, 4, 5, 5, 6, 3, 5, 7, 9, 2, 1, 2, 2, 1, 0, 3, 3, 3, 4, 6, 6, 9, 7, 4, 9, 9, 2, 3, 5, 6, - 3, 0, 2, 5, 4, 9, 4, 7, 8, 0, 2, 4, 9, 0, 1, 1, 4, 1, 9, 5, 2, 1, 2, 3, 8, 2, 8, 1, 5, 3, 0, 9, 1, 1, 4, 0, 7, 9, 0, 7, 3, 8, 6, 0, 2, 5, 1, 5, 2, 2, 7, 4, 2, 9, 9, 5, 8, 1, 8, 0, 7, 2, 4, 7, 1, 6, 2, 5, 9, 1, - 6, 6, 8, 5, 4, 5, 1, 3, 3, 3, 1, 2, 3, 9, 4, 8, 0, 4, 9, 4, 7, 0, 7, 9, 1, 1, 9, 1, 5, 3, 2, 6, 7, 3, 4, 3, 0, 2, 8, 2, 4, 4, 1, 8, 6, 0, 4, 1, 4, 2, 6, 3, 6, 3, 9, 5, 4, 8, 0, 0, 0, 4, 4, 8, 0, 0, 2, 6, 7, 0, - 4, 9, 6, 2, 4, 8, 2, 0, 1, 7, 9, 2, 8, 9, 6, 4, 7, 6, 6, 9, 7, 5, 8, 3, 1, 8, 3, 2, 7, 1, 3, 1, 4, 2, 5, 1, 7, 0, 2, 9, 6, 9, 2, 3, 4, 8, 8, 9, 6, 2, 7, 6, 6, 8, 4, 4, 0, 3, 2, 3, 2, 6, 0, 9, 2, 7, 5, 2, 4, 9, - 6, 0, 3, 5, 7, 9, 9, 6, 4, 6, 9, 2, 5, 6, 5, 0, 4, 9, 3, 6, 8, 1, 8, 3, 6, 0, 9, 0, 0, 3, 2, 3, 8, 0, 9, 2, 9, 3, 4, 5, - 9, 5, 8, 8, 9, 7, 0, 6, 9, 5, 3, 6, 5, 3, 4, 9, 4, 0, 6, 0, 3, 4, 0, 2, 1, 6, 6, 5, 4, 4, 3, 7, 5, 5, 8, 9, 0, 0, 4, 5, 6, 3, 2, 8, 8, 2, 2, 5, 0, 5, 4, 5, 2, 5, 5, 6, 4, 0, 5, 6, 4, 4, 8, 2, 4, 6, 5, 1, 5, 1, - 8, 7, 5, 4, 7, 1, 1, 9, 6, 2, 1, 8, 4, 4, 3, 9, 6, 5, 8, 2, 5, 3, 3, 7, 5, 4, 3, 8, 8, 5, 6, 9, 0, 9, 4, 1, 1, 3, 0, 3, 1, 5, 0, 9, 5, 2, 6, 1, 7, 9, 3, 7, 8, 0, 0, 2, 9, 7, 4, 1, 2, 0, 7, 6, 6, 5, 1, 4, 7, 9, - 3, 9, 4, 2, 5, 9, 0, 2, 9, 8, 9, 6, 9, 5, 9, 4, 6, 9, 9, 5, 5, 6, 5, 7, 6, 1, 2, 1, 8, 6, 5, 6, 1, 9, 6, 7, 3, 3, 7, 8, 6, 2, 3, 6, 2, 5, 6, 1, 2, 5, 2, 1, 6, 3, 2, 0, 8, 6, 2, 8, 6, 9, 2, 2, 2, 1, 0, 3, 2, 7, - 4, 8, 8, 9, 2, 1, 8, 6, 5, 4, 3, 6, 4, 8, 0, 2, 2, 9, 6, 7, 8, 0, 7, 0, 5, 7, 6, 5, 6, 1, 5, 1, 4, 4, 6, 3, 2, 0, 4, 6, 9, 2, 7, 9, 0, 6, 8, 2, 1, 2, 0, 7, 3, 8, 8, 3, 7, 7, 8, 1, 4, 2, 3, 3, 5, 6, 2, 8, 2, 3, - 6, 0, 8, 9, 6, 3, 2, 0, 8, 0, 6, 8, 2, 2, 2, 4, 6, 8, 0, 1, 2, 2, 4, 8, 2, 6, 1, 1, 7, 7, 1, 8, 5, 8, 9, 6, 3, 8, 1, 4, 0, 9, 1, 8, 3, 9, 0, 3, 6, 7, 3, 6, 7, 2, 2, 2, 0, 8, 8, 8, 3, 2, 1, 5, 1, 3, 7, 5, 5, 6, - 0, 0, 3, 7, 2, 7, 9, 8, 3, 9, 4, 0, 0, 4, 1, 5, 2, 9, 7, 0, 0, 2, 8, 7, 8, 3, 0, 7, 6, 6, 7, 0, 9, 4, 4, 4, 7, 4, 5, 6, 0, 1, 3, 4, 5, 5, 6, 4, 1, 7, 2, 5, 4, 3, 7, 0, 9, 0, 6, 9, 7, 9, 3, 9, 6, 1, 2, 2, 5, 7, - 1, 4, 2, 9, 8, 9, 4, 6, 7, 1, 5, 4, 3, 5, 7, 8, 4, 6, 8, 7, 8, 8, 6, 1, 4, 4, 4, 5, 8, 1, 2, 3, 1, 4, 5, 9, 3, 5, 7, 1, 9, 8, 4, 9, 2, 2, 5, 2, 8, 4, 7, 1, 6, 0, 5, 0, 4, 9, 2, 2, 1, 2, 4, 2, 4, 7, 0, 1, 4, 1, - 2, 1, 4, 7, 8, 0, 5, 7, 3, 4, 5, 5, 1, 0, 5, 0, 0, 8, 0, 1, 9, 0, 8, 6, 9, 9, 6, 0, 3, 3, 0, 2, 7, 6, 3, 4, 7, 8, 7, 0, 8, 1, 0, 8, 1, 7, 5, 4, 5, 0, 1, 1, 9, 3, 0, 7, 1, 4, 1, 2, 2, 3, 3, 9, 0, 8, 6, 6, 3, 9, - 3, 8, 3, 3, 9, 5, 2, 9, 4, 2, 5, 7, 8, 6, 9, 0, 5, 0, 7, 6, 4, 3, 1, 0, 0, 6, 3, 8, 3, 5, 1, 9, 8, 3, 4, 3, 8, 9, 3, 4, 1, 5, 9, 6, 1, 3, 1, 8, 5, 4, 3, 4, 7, 5, 4, 6, 4, 9, 5, 5, 6, 9, 7, 8, 1, 0, 3, 8, 2, 9, - 3, 0, 9, 7, 1, 6, 4, 6, 5, 1, 4, 3, 8, 4, 0, 7, 0, 0, 7, 0, 7, 3, 6, 0, 4, 1, 1, 2, 3, 7, 3, 5, 9, 9, 8, 4, 3, 4, 5, 2, 2, 5, 1, 6, 1, 0, 5, 0, 7, 0, 2, 7, 0, 5, 6, 2, 3, 5, 2, 6, 6, 0, 1, 2, 7, 6, 4, 8, 4, 8, - 3, 0, 8, 4, 0, 7, 6, 1, 1, 8, 3, 0, 1, 3, 0, 5, 2, 7, 9, 3, 2, 0, 5, 4, 2, 7, 4, 6, 2, 8, 6, 5, 4, 0, 3, 6, 0, 3, 6, 7, 4, 5, 3, 2, 8, 6, 5, 1, 0, 5, 7, 0, 6, 5, 8, 7, 4, 8, 8, 2, 2, 5, 6, 9, 8, 1, 5, 7, 9, 3, - 6, 7, 8, 9, 7, 6, 6, 9, 7, 4, 2, 2, 0, 5, 7, 5, 0, 5, 9, 6, 8, 3, 4, 4, 0, 8, 6, 9, 7, 3, 5, 0, 2, 0, 1, 4, 1, 0, 2, 0, 6, 7, 2, 3, 5, 8, 5, 0, 2, 0, 0, 7, 2, 4, 5, 2, 2, 5, 6, 3, 2, 6, 5, 1, 3, 4, 1, 0, 5, 5, - 9, 2, 4, 0, 1, 9, 0, 2, 7, 4, 2, 1, 6, 2, 4, 8, 4, 3, 9, 1, 4, 0, 3, 5, 9, 9, 8, 9, 5, 3, 5, 3, 9, 4, 5, 9, 0, 9, 4, 4, 0, 7, 0, 4, 6, 9, 1, 2, 0, 9, 1, 4, 0, 9, 3, 8, 7, 0, 0, 1, 2, 6, 4, 5, 6, 0, 0, 1, 6, 2, - 3, 7, 4, 2, 8, 8, 0, 2, 1, 0, 9, 2, 7, 6, 4, 5, 7, 9, 3, 1, 0, 6, 5, 7, 9, 2, 2, 9, 5, 5, 2, 4, 9, 8, 8, 7, 2, 7, 5, 8, 4, 6, 1, 0, 1, 2, 6, 4, 8, 3, 6, 9, 9, 9, 8, 9, 2, 2, 5, 6, 9, 5, 9, 6, 8, 8, 1, 5, 9, 2, - 0, 5, 6, 0, 0, 1, 0, 1, 6, 5, 5, 2, 5, 6, 3, 7, 5, 6, 7, 8 - }; -} diff --git a/src/main/java/android/os/Message.java b/src/main/java/android/os/Message.java deleted file mode 100644 index 8c75847..0000000 --- a/src/main/java/android/os/Message.java +++ /dev/null @@ -1,578 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.util.TimeUtils; - -/** - * - * Defines a message containing a description and arbitrary data object that can be - * sent to a {@link Handler}. This object contains two extra int fields and an - * extra object field that allow you to not do allocations in many cases. - * - *

While the constructor of Message is public, the best way to get - * one of these is to call {@link #obtain Message.obtain()} or one of the - * {@link Handler#obtainMessage Handler.obtainMessage()} methods, which will pull - * them from a pool of recycled objects.

- */ -public final class Message implements Parcelable { - /** - * User-defined message code so that the recipient can identify - * what this message is about. Each {@link Handler} has its own name-space - * for message codes, so you do not need to worry about yours conflicting - * with other handlers. - */ - public int what; - - /** - * arg1 and arg2 are lower-cost alternatives to using - * {@link #setData(Bundle) setData()} if you only need to store a - * few integer values. - */ - public int arg1; - - /** - * arg1 and arg2 are lower-cost alternatives to using - * {@link #setData(Bundle) setData()} if you only need to store a - * few integer values. - */ - public int arg2; - - /** - * An arbitrary object to send to the recipient. When using - * {@link Messenger} to send the message across processes this can only - * be non-null if it contains a Parcelable of a framework class (not one - * implemented by the application). For other data transfer use - * {@link #setData}. - * - *

Note that Parcelable objects here are not supported prior to - * the {@link android.os.Build.VERSION_CODES#FROYO} release. - */ - public Object obj; - - /** - * Optional Messenger where replies to this message can be sent. The - * semantics of exactly how this is used are up to the sender and - * receiver. - */ - public Messenger replyTo; - - /** - * Optional field indicating the uid that sent the message. This is - * only valid for messages posted by a {@link Messenger}; otherwise, - * it will be -1. - */ - public int sendingUid = -1; - - /** If set message is in use. - * This flag is set when the message is enqueued and remains set while it - * is delivered and afterwards when it is recycled. The flag is only cleared - * when a new message is created or obtained since that is the only time that - * applications are allowed to modify the contents of the message. - * - * It is an error to attempt to enqueue or recycle a message that is already in use. - */ - /*package*/ static final int FLAG_IN_USE = 1 << 0; - - /** If set message is asynchronous */ - /*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1; - - /** Flags to clear in the copyFrom method */ - /*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE; - - /*package*/ int flags; - - /*package*/ long when; - - /*package*/ Bundle data; - - /*package*/ Handler target; - - /*package*/ Runnable callback; - - // sometimes we store linked lists of these things - /*package*/ Message next; - - private static final Object sPoolSync = new Object(); - private static Message sPool; - private static int sPoolSize = 0; - - private static final int MAX_POOL_SIZE = 50; - - private static boolean gCheckRecycle = true; - - /** - * Return a new Message instance from the global pool. Allows us to - * avoid allocating new objects in many cases. - */ - public static Message obtain() { - synchronized (sPoolSync) { - if (sPool != null) { - Message m = sPool; - sPool = m.next; - m.next = null; - m.flags = 0; // clear in-use flag - sPoolSize--; - return m; - } - } - return new Message(); - } - - /** - * Same as {@link #obtain()}, but copies the values of an existing - * message (including its target) into the new one. - * @param orig Original message to copy. - * @return A Message object from the global pool. - */ - public static Message obtain(Message orig) { - Message m = obtain(); - m.what = orig.what; - m.arg1 = orig.arg1; - m.arg2 = orig.arg2; - m.obj = orig.obj; - m.replyTo = orig.replyTo; - m.sendingUid = orig.sendingUid; - if (orig.data != null) { - m.data = new Bundle(orig.data); - } - m.target = orig.target; - m.callback = orig.callback; - - return m; - } - - /** - * Same as {@link #obtain()}, but sets the value for the target member on the Message returned. - * @param h Handler to assign to the returned Message object's target member. - * @return A Message object from the global pool. - */ - public static Message obtain(Handler h) { - Message m = obtain(); - m.target = h; - - return m; - } - - /** - * Same as {@link #obtain(Handler)}, but assigns a callback Runnable on - * the Message that is returned. - * @param h Handler to assign to the returned Message object's target member. - * @param callback Runnable that will execute when the message is handled. - * @return A Message object from the global pool. - */ - public static Message obtain(Handler h, Runnable callback) { - Message m = obtain(); - m.target = h; - m.callback = callback; - - return m; - } - - /** - * Same as {@link #obtain()}, but sets the values for both target and - * what members on the Message. - * @param h Value to assign to the target member. - * @param what Value to assign to the what member. - * @return A Message object from the global pool. - */ - public static Message obtain(Handler h, int what) { - Message m = obtain(); - m.target = h; - m.what = what; - - return m; - } - - /** - * Same as {@link #obtain()}, but sets the values of the target, what, and obj - * members. - * @param h The target value to set. - * @param what The what value to set. - * @param obj The object method to set. - * @return A Message object from the global pool. - */ - public static Message obtain(Handler h, int what, Object obj) { - Message m = obtain(); - m.target = h; - m.what = what; - m.obj = obj; - - return m; - } - - /** - * Same as {@link #obtain()}, but sets the values of the target, what, - * arg1, and arg2 members. - * - * @param h The target value to set. - * @param what The what value to set. - * @param arg1 The arg1 value to set. - * @param arg2 The arg2 value to set. - * @return A Message object from the global pool. - */ - public static Message obtain(Handler h, int what, int arg1, int arg2) { - Message m = obtain(); - m.target = h; - m.what = what; - m.arg1 = arg1; - m.arg2 = arg2; - - return m; - } - - /** - * Same as {@link #obtain()}, but sets the values of the target, what, - * arg1, arg2, and obj members. - * - * @param h The target value to set. - * @param what The what value to set. - * @param arg1 The arg1 value to set. - * @param arg2 The arg2 value to set. - * @param obj The obj value to set. - * @return A Message object from the global pool. - */ - public static Message obtain(Handler h, int what, - int arg1, int arg2, Object obj) { - Message m = obtain(); - m.target = h; - m.what = what; - m.arg1 = arg1; - m.arg2 = arg2; - m.obj = obj; - - return m; - } - - /** @hide */ - public static void updateCheckRecycle(int targetSdkVersion) { - if (targetSdkVersion < Build.VERSION_CODES.LOLLIPOP) { - gCheckRecycle = false; - } - } - - /** - * Return a Message instance to the global pool. - *

- * You MUST NOT touch the Message after calling this function because it has - * effectively been freed. It is an error to recycle a message that is currently - * enqueued or that is in the process of being delivered to a Handler. - *

- */ - public void recycle() { - if (isInUse()) { - if (gCheckRecycle) { - throw new IllegalStateException("This message cannot be recycled because it " - + "is still in use."); - } - return; - } - recycleUnchecked(); - } - - /** - * Recycles a Message that may be in-use. - * Used internally by the MessageQueue and Looper when disposing of queued Messages. - */ - void recycleUnchecked() { - // Mark the message as in use while it remains in the recycled object pool. - // Clear out all other details. - flags = FLAG_IN_USE; - what = 0; - arg1 = 0; - arg2 = 0; - obj = null; - replyTo = null; - sendingUid = -1; - when = 0; - target = null; - callback = null; - data = null; - - synchronized (sPoolSync) { - if (sPoolSize < MAX_POOL_SIZE) { - next = sPool; - sPool = this; - sPoolSize++; - } - } - } - - /** - * Make this message like o. Performs a shallow copy of the data field. - * Does not copy the linked list fields, nor the timestamp or - * target/callback of the original message. - */ - public void copyFrom(Message o) { - this.flags = o.flags & ~FLAGS_TO_CLEAR_ON_COPY_FROM; - this.what = o.what; - this.arg1 = o.arg1; - this.arg2 = o.arg2; - this.obj = o.obj; - this.replyTo = o.replyTo; - this.sendingUid = o.sendingUid; - - if (o.data != null) { - this.data = (Bundle) o.data.clone(); - } else { - this.data = null; - } - } - - /** - * Return the targeted delivery time of this message, in milliseconds. - */ - public long getWhen() { - return when; - } - - public void setTarget(Handler target) { - this.target = target; - } - - /** - * Retrieve the a {@link android.os.Handler Handler} implementation that - * will receive this message. The object must implement - * {@link android.os.Handler#handleMessage(android.os.Message) - * Handler.handleMessage()}. Each Handler has its own name-space for - * message codes, so you do not need to - * worry about yours conflicting with other handlers. - */ - public Handler getTarget() { - return target; - } - - /** - * Retrieve callback object that will execute when this message is handled. - * This object must implement Runnable. This is called by - * the target {@link Handler} that is receiving this Message to - * dispatch it. If - * not set, the message will be dispatched to the receiving Handler's - * {@link Handler#handleMessage(Message Handler.handleMessage())}. - */ - public Runnable getCallback() { - return callback; - } - - /** - * Obtains a Bundle of arbitrary data associated with this - * event, lazily creating it if necessary. Set this value by calling - * {@link #setData(Bundle)}. Note that when transferring data across - * processes via {@link Messenger}, you will need to set your ClassLoader - * on the Bundle via {@link Bundle#setClassLoader(ClassLoader) - * Bundle.setClassLoader()} so that it can instantiate your objects when - * you retrieve them. - * @see #peekData() - * @see #setData(Bundle) - */ - public Bundle getData() { - if (data == null) { - data = new Bundle(); - } - - return data; - } - - /** - * Like getData(), but does not lazily create the Bundle. A null - * is returned if the Bundle does not already exist. See - * {@link #getData} for further information on this. - * @see #getData() - * @see #setData(Bundle) - */ - public Bundle peekData() { - return data; - } - - /** - * Sets a Bundle of arbitrary data values. Use arg1 and arg2 members - * as a lower cost way to send a few simple integer values, if you can. - * @see #getData() - * @see #peekData() - */ - public void setData(Bundle data) { - this.data = data; - } - - /** - * Sends this Message to the Handler specified by {@link #getTarget}. - * Throws a null pointer exception if this field has not been set. - */ - public void sendToTarget() { - target.sendMessage(this); - } - - /** - * Returns true if the message is asynchronous, meaning that it is not - * subject to {@link Looper} synchronization barriers. - * - * @return True if the message is asynchronous. - * - * @see #setAsynchronous(boolean) - */ - public boolean isAsynchronous() { - return (flags & FLAG_ASYNCHRONOUS) != 0; - } - - /** - * Sets whether the message is asynchronous, meaning that it is not - * subject to {@link Looper} synchronization barriers. - *

- * Certain operations, such as view invalidation, may introduce synchronization - * barriers into the {@link Looper}'s message queue to prevent subsequent messages - * from being delivered until some condition is met. In the case of view invalidation, - * messages which are posted after a call to {@link android.view.View#invalidate} - * are suspended by means of a synchronization barrier until the next frame is - * ready to be drawn. The synchronization barrier ensures that the invalidation - * request is completely handled before resuming. - *

- * Asynchronous messages are exempt from synchronization barriers. They typically - * represent interrupts, input events, and other signals that must be handled independently - * even while other work has been suspended. - *

- * Note that asynchronous messages may be delivered out of order with respect to - * synchronous messages although they are always delivered in order among themselves. - * If the relative order of these messages matters then they probably should not be - * asynchronous in the first place. Use with caution. - *

- * - * @param async True if the message is asynchronous. - * - * @see #isAsynchronous() - */ - public void setAsynchronous(boolean async) { - if (async) { - flags |= FLAG_ASYNCHRONOUS; - } else { - flags &= ~FLAG_ASYNCHRONOUS; - } - } - - /*package*/ boolean isInUse() { - return ((flags & FLAG_IN_USE) == FLAG_IN_USE); - } - - /*package*/ void markInUse() { - flags |= FLAG_IN_USE; - } - - /** Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}). - */ - public Message() { - } - - @Override - public String toString() { - return toString(SystemClock.uptimeMillis()); - } - - String toString(long now) { - StringBuilder b = new StringBuilder(); - b.append("{ when="); - TimeUtils.formatDuration(when - now, b); - - if (target != null) { - if (callback != null) { - b.append(" callback="); - b.append(callback.getClass().getName()); - } else { - b.append(" what="); - b.append(what); - } - - if (arg1 != 0) { - b.append(" arg1="); - b.append(arg1); - } - - if (arg2 != 0) { - b.append(" arg2="); - b.append(arg2); - } - - if (obj != null) { - b.append(" obj="); - b.append(obj); - } - - b.append(" target="); - b.append(target.getClass().getName()); - } else { - b.append(" barrier="); - b.append(arg1); - } - - b.append(" }"); - return b.toString(); - } - - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - public Message createFromParcel(Parcel source) { - Message msg = Message.obtain(); - msg.readFromParcel(source); - return msg; - } - - public Message[] newArray(int size) { - return new Message[size]; - } - }; - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - if (callback != null) { - throw new RuntimeException( - "Can't marshal callbacks across processes."); - } - dest.writeInt(what); - dest.writeInt(arg1); - dest.writeInt(arg2); - if (obj != null) { - try { - Parcelable p = (Parcelable)obj; - dest.writeInt(1); - dest.writeParcelable(p, flags); - } catch (ClassCastException e) { - throw new RuntimeException( - "Can't marshal non-Parcelable objects across processes."); - } - } else { - dest.writeInt(0); - } - dest.writeLong(when); - dest.writeBundle(data); - Messenger.writeMessengerOrNullToParcel(replyTo, dest); - dest.writeInt(sendingUid); - } - - private void readFromParcel(Parcel source) { - what = source.readInt(); - arg1 = source.readInt(); - arg2 = source.readInt(); - if (source.readInt() != 0) { - obj = source.readParcelable(getClass().getClassLoader()); - } - when = source.readLong(); - data = source.readBundle(); - replyTo = Messenger.readMessengerOrNullFromParcel(source); - sendingUid = source.readInt(); - } -} diff --git a/src/main/java/android/os/MessageQueue.java b/src/main/java/android/os/MessageQueue.java deleted file mode 100644 index 01a23ce..0000000 --- a/src/main/java/android/os/MessageQueue.java +++ /dev/null @@ -1,566 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.util.Log; -import android.util.Printer; - -import java.util.ArrayList; - -/** - * Low-level class holding the list of messages to be dispatched by a - * {@link Looper}. Messages are not added directly to a MessageQueue, - * but rather through {@link Handler} objects associated with the Looper. - * - *

You can retrieve the MessageQueue for the current thread with - * {@link Looper#myQueue() Looper.myQueue()}. - */ -public final class MessageQueue { - // True if the message queue can be quit. - private final boolean mQuitAllowed; - - @SuppressWarnings("unused") - private long mPtr; // used by native code - - Message mMessages; - private final ArrayList mIdleHandlers = new ArrayList(); - private IdleHandler[] mPendingIdleHandlers; - private boolean mQuitting; - - // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout. - private boolean mBlocked; - - // The next barrier token. - // Barriers are indicated by messages with a null target whose arg1 field carries the token. - private int mNextBarrierToken; - - private native static long nativeInit(); - private native static void nativeDestroy(long ptr); - private native static void nativePollOnce(long ptr, int timeoutMillis); - private native static void nativeWake(long ptr); - private native static boolean nativeIsIdling(long ptr); - - /** - * Callback interface for discovering when a thread is going to block - * waiting for more messages. - */ - public static interface IdleHandler { - /** - * Called when the message queue has run out of messages and will now - * wait for more. Return true to keep your idle handler active, false - * to have it removed. This may be called if there are still messages - * pending in the queue, but they are all scheduled to be dispatched - * after the current time. - */ - boolean queueIdle(); - } - - /** - * Add a new {@link IdleHandler} to this message queue. This may be - * removed automatically for you by returning false from - * {@link IdleHandler#queueIdle IdleHandler.queueIdle()} when it is - * invoked, or explicitly removing it with {@link #removeIdleHandler}. - * - *

This method is safe to call from any thread. - * - * @param handler The IdleHandler to be added. - */ - public void addIdleHandler(IdleHandler handler) { - if (handler == null) { - throw new NullPointerException("Can't add a null IdleHandler"); - } - synchronized (this) { - mIdleHandlers.add(handler); - } - } - - /** - * Remove an {@link IdleHandler} from the queue that was previously added - * with {@link #addIdleHandler}. If the given object is not currently - * in the idle list, nothing is done. - * - * @param handler The IdleHandler to be removed. - */ - public void removeIdleHandler(IdleHandler handler) { - synchronized (this) { - mIdleHandlers.remove(handler); - } - } - - MessageQueue(boolean quitAllowed) { - mQuitAllowed = quitAllowed; - mPtr = nativeInit(); - } - - @Override - protected void finalize() throws Throwable { - try { - dispose(); - } finally { - super.finalize(); - } - } - - // Disposes of the underlying message queue. - // Must only be called on the looper thread or the finalizer. - private void dispose() { - if (mPtr != 0) { - nativeDestroy(mPtr); - mPtr = 0; - } - } - - Message next() { - // Return here if the message loop has already quit and been disposed. - // This can happen if the application tries to restart a looper after quit - // which is not supported. - final long ptr = mPtr; - if (ptr == 0) { - return null; - } - - int pendingIdleHandlerCount = -1; // -1 only during first iteration - int nextPollTimeoutMillis = 0; - for (;;) { - if (nextPollTimeoutMillis != 0) { - Binder.flushPendingCommands(); - } - - nativePollOnce(ptr, nextPollTimeoutMillis); - - synchronized (this) { - // Try to retrieve the next message. Return if found. - final long now = SystemClock.uptimeMillis(); - Message prevMsg = null; - Message msg = mMessages; - if (msg != null && msg.target == null) { - // Stalled by a barrier. Find the next asynchronous message in the queue. - do { - prevMsg = msg; - msg = msg.next; - } while (msg != null && !msg.isAsynchronous()); - } - if (msg != null) { - if (now < msg.when) { - // Next message is not ready. Set a timeout to wake up when it is ready. - nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); - } else { - // Got a message. - mBlocked = false; - if (prevMsg != null) { - prevMsg.next = msg.next; - } else { - mMessages = msg.next; - } - msg.next = null; - if (false) Log.v("MessageQueue", "Returning message: " + msg); - return msg; - } - } else { - // No more messages. - nextPollTimeoutMillis = -1; - } - - // Process the quit message now that all pending messages have been handled. - if (mQuitting) { - dispose(); - return null; - } - - // If first time idle, then get the number of idlers to run. - // Idle handles only run if the queue is empty or if the first message - // in the queue (possibly a barrier) is due to be handled in the future. - if (pendingIdleHandlerCount < 0 - && (mMessages == null || now < mMessages.when)) { - pendingIdleHandlerCount = mIdleHandlers.size(); - } - if (pendingIdleHandlerCount <= 0) { - // No idle handlers to run. Loop and wait some more. - mBlocked = true; - continue; - } - - if (mPendingIdleHandlers == null) { - mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; - } - mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); - } - - // Run the idle handlers. - // We only ever reach this code block during the first iteration. - for (int i = 0; i < pendingIdleHandlerCount; i++) { - final IdleHandler idler = mPendingIdleHandlers[i]; - mPendingIdleHandlers[i] = null; // release the reference to the handler - - boolean keep = false; - try { - keep = idler.queueIdle(); - } catch (Throwable t) { - Log.wtf("MessageQueue", "IdleHandler threw exception", t); - } - - if (!keep) { - synchronized (this) { - mIdleHandlers.remove(idler); - } - } - } - - // Reset the idle handler count to 0 so we do not run them again. - pendingIdleHandlerCount = 0; - - // While calling an idle handler, a new message could have been delivered - // so go back and look again for a pending message without waiting. - nextPollTimeoutMillis = 0; - } - } - - void quit(boolean safe) { - if (!mQuitAllowed) { - throw new IllegalStateException("Main thread not allowed to quit."); - } - - synchronized (this) { - if (mQuitting) { - return; - } - mQuitting = true; - - if (safe) { - removeAllFutureMessagesLocked(); - } else { - removeAllMessagesLocked(); - } - - // We can assume mPtr != 0 because mQuitting was previously false. - nativeWake(mPtr); - } - } - - int enqueueSyncBarrier(long when) { - // Enqueue a new sync barrier token. - // We don't need to wake the queue because the purpose of a barrier is to stall it. - synchronized (this) { - final int token = mNextBarrierToken++; - final Message msg = Message.obtain(); - msg.markInUse(); - msg.when = when; - msg.arg1 = token; - - Message prev = null; - Message p = mMessages; - if (when != 0) { - while (p != null && p.when <= when) { - prev = p; - p = p.next; - } - } - if (prev != null) { // invariant: p == prev.next - msg.next = p; - prev.next = msg; - } else { - msg.next = p; - mMessages = msg; - } - return token; - } - } - - void removeSyncBarrier(int token) { - // Remove a sync barrier token from the queue. - // If the queue is no longer stalled by a barrier then wake it. - synchronized (this) { - Message prev = null; - Message p = mMessages; - while (p != null && (p.target != null || p.arg1 != token)) { - prev = p; - p = p.next; - } - if (p == null) { - throw new IllegalStateException("The specified message queue synchronization " - + " barrier token has not been posted or has already been removed."); - } - final boolean needWake; - if (prev != null) { - prev.next = p.next; - needWake = false; - } else { - mMessages = p.next; - needWake = mMessages == null || mMessages.target != null; - } - p.recycleUnchecked(); - - // If the loop is quitting then it is already awake. - // We can assume mPtr != 0 when mQuitting is false. - if (needWake && !mQuitting) { - nativeWake(mPtr); - } - } - } - - boolean enqueueMessage(Message msg, long when) { - if (msg.target == null) { - throw new IllegalArgumentException("Message must have a target."); - } - if (msg.isInUse()) { - throw new IllegalStateException(msg + " This message is already in use."); - } - - synchronized (this) { - if (mQuitting) { - IllegalStateException e = new IllegalStateException( - msg.target + " sending message to a Handler on a dead thread"); - Log.w("MessageQueue", e.getMessage(), e); - msg.recycle(); - return false; - } - - msg.markInUse(); - msg.when = when; - Message p = mMessages; - boolean needWake; - if (p == null || when == 0 || when < p.when) { - // New head, wake up the event queue if blocked. - msg.next = p; - mMessages = msg; - needWake = mBlocked; - } else { - // Inserted within the middle of the queue. Usually we don't have to wake - // up the event queue unless there is a barrier at the head of the queue - // and the message is the earliest asynchronous message in the queue. - needWake = mBlocked && p.target == null && msg.isAsynchronous(); - Message prev; - for (;;) { - prev = p; - p = p.next; - if (p == null || when < p.when) { - break; - } - if (needWake && p.isAsynchronous()) { - needWake = false; - } - } - msg.next = p; // invariant: p == prev.next - prev.next = msg; - } - - // We can assume mPtr != 0 because mQuitting is false. - if (needWake) { - nativeWake(mPtr); - } - } - return true; - } - - boolean hasMessages(Handler h, int what, Object object) { - if (h == null) { - return false; - } - - synchronized (this) { - Message p = mMessages; - while (p != null) { - if (p.target == h && p.what == what && (object == null || p.obj == object)) { - return true; - } - p = p.next; - } - return false; - } - } - - boolean hasMessages(Handler h, Runnable r, Object object) { - if (h == null) { - return false; - } - - synchronized (this) { - Message p = mMessages; - while (p != null) { - if (p.target == h && p.callback == r && (object == null || p.obj == object)) { - return true; - } - p = p.next; - } - return false; - } - } - - boolean isIdling() { - synchronized (this) { - return isIdlingLocked(); - } - } - - private boolean isIdlingLocked() { - // If the loop is quitting then it must not be idling. - // We can assume mPtr != 0 when mQuitting is false. - return !mQuitting && nativeIsIdling(mPtr); - } - - void removeMessages(Handler h, int what, Object object) { - if (h == null) { - return; - } - - synchronized (this) { - Message p = mMessages; - - // Remove all messages at front. - while (p != null && p.target == h && p.what == what - && (object == null || p.obj == object)) { - Message n = p.next; - mMessages = n; - p.recycleUnchecked(); - p = n; - } - - // Remove all messages after front. - while (p != null) { - Message n = p.next; - if (n != null) { - if (n.target == h && n.what == what - && (object == null || n.obj == object)) { - Message nn = n.next; - n.recycleUnchecked(); - p.next = nn; - continue; - } - } - p = n; - } - } - } - - void removeMessages(Handler h, Runnable r, Object object) { - if (h == null || r == null) { - return; - } - - synchronized (this) { - Message p = mMessages; - - // Remove all messages at front. - while (p != null && p.target == h && p.callback == r - && (object == null || p.obj == object)) { - Message n = p.next; - mMessages = n; - p.recycleUnchecked(); - p = n; - } - - // Remove all messages after front. - while (p != null) { - Message n = p.next; - if (n != null) { - if (n.target == h && n.callback == r - && (object == null || n.obj == object)) { - Message nn = n.next; - n.recycleUnchecked(); - p.next = nn; - continue; - } - } - p = n; - } - } - } - - void removeCallbacksAndMessages(Handler h, Object object) { - if (h == null) { - return; - } - - synchronized (this) { - Message p = mMessages; - - // Remove all messages at front. - while (p != null && p.target == h - && (object == null || p.obj == object)) { - Message n = p.next; - mMessages = n; - p.recycleUnchecked(); - p = n; - } - - // Remove all messages after front. - while (p != null) { - Message n = p.next; - if (n != null) { - if (n.target == h && (object == null || n.obj == object)) { - Message nn = n.next; - n.recycleUnchecked(); - p.next = nn; - continue; - } - } - p = n; - } - } - } - - private void removeAllMessagesLocked() { - Message p = mMessages; - while (p != null) { - Message n = p.next; - p.recycleUnchecked(); - p = n; - } - mMessages = null; - } - - private void removeAllFutureMessagesLocked() { - final long now = SystemClock.uptimeMillis(); - Message p = mMessages; - if (p != null) { - if (p.when > now) { - removeAllMessagesLocked(); - } else { - Message n; - for (;;) { - n = p.next; - if (n == null) { - return; - } - if (n.when > now) { - break; - } - p = n; - } - p.next = null; - do { - p = n; - n = p.next; - p.recycleUnchecked(); - } while (n != null); - } - } - } - - void dump(Printer pw, String prefix) { - synchronized (this) { - long now = SystemClock.uptimeMillis(); - int n = 0; - for (Message msg = mMessages; msg != null; msg = msg.next) { - pw.println(prefix + "Message " + n + ": " + msg.toString(now)); - n++; - } - pw.println(prefix + "(Total messages: " + n + ", idling=" + isIdlingLocked() - + ", quitting=" + mQuitting + ")"); - } - } -} diff --git a/src/main/java/android/os/MessageQueueTest.java b/src/main/java/android/os/MessageQueueTest.java deleted file mode 100644 index f82bfce..0000000 --- a/src/main/java/android/os/MessageQueueTest.java +++ /dev/null @@ -1,276 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.os.Handler; -import android.os.Message; -import android.os.SystemClock; -import android.test.suitebuilder.annotation.MediumTest; -import junit.framework.TestCase; - -public class MessageQueueTest extends TestCase { - - private static class BaseTestHandler extends TestHandlerThread { - Handler mHandler; - int mLastMessage; - int mCount; - - public BaseTestHandler() { - } - - public void go() { - mHandler = new Handler() { - public void handleMessage(Message msg) { - BaseTestHandler.this.handleMessage(msg); - } - }; - } - - public void handleMessage(Message msg) { - if (!msg.isInUse()) { - failure(new RuntimeException( - "msg.isInuse is false, should always be true, #" + msg.what)); - } - if (mCount <= mLastMessage) { - if (msg.what != mCount) { - failure(new RuntimeException( - "Expected message #" + mCount - + ", received #" + msg.what)); - } else if (mCount == mLastMessage) { - success(); - } - mCount++; - } else { - failure(new RuntimeException( - "Message received after done, #" + msg.what)); - } - } - } - - @MediumTest - public void testMessageOrder() throws Exception { - TestHandlerThread tester = new BaseTestHandler() { - public void go() { - super.go(); - long now = SystemClock.uptimeMillis() + 200; - mLastMessage = 4; - mCount = 0; - mHandler.sendMessageAtTime(mHandler.obtainMessage(2), now + 1); - mHandler.sendMessageAtTime(mHandler.obtainMessage(3), now + 2); - mHandler.sendMessageAtTime(mHandler.obtainMessage(4), now + 2); - mHandler.sendMessageAtTime(mHandler.obtainMessage(0), now + 0); - mHandler.sendMessageAtTime(mHandler.obtainMessage(1), now + 0); - } - }; - - tester.doTest(1000); - } - - @MediumTest - public void testAtFrontOfQueue() throws Exception { - TestHandlerThread tester = new BaseTestHandler() { - public void go() { - super.go(); - long now = SystemClock.uptimeMillis() + 200; - mLastMessage = 3; - mCount = 0; - mHandler.sendMessageAtTime(mHandler.obtainMessage(3), now); - mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(2)); - mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(0)); - } - - public void handleMessage(Message msg) { - super.handleMessage(msg); - if (msg.what == 0) { - mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(1)); - } - } - }; - - tester.doTest(1000); - } - - private static class TestFieldIntegrityHandler extends TestHandlerThread { - Handler mHandler; - int mLastMessage; - int mCount; - - public TestFieldIntegrityHandler() { - } - - public void go() { - mHandler = new Handler() { - public void handleMessage(Message msg) { - TestFieldIntegrityHandler.this.handleMessage(msg); - } - }; - } - - public void handleMessage(Message msg) { - if (!msg.isInUse()) { - failure(new RuntimeException( - "msg.isInuse is false, should always be true, #" + msg.what)); - } - if (mCount <= mLastMessage) { - if (msg.what != mCount) { - failure(new RuntimeException( - "Expected message #" + mCount - + ", received #" + msg.what)); - } else if (mCount == mLastMessage) { - success(); - } - mCount++; - } else { - failure(new RuntimeException( - "Message received after done, #" + msg.what)); - } - } - } - - @MediumTest - public void testFieldIntegrity() throws Exception { - - TestHandlerThread tester = new TestFieldIntegrityHandler() { - Bundle mBundle; - - public void go() { - super.go(); - mLastMessage = 1; - mCount = 0; - mHandler.sendMessage(mHandler.obtainMessage(0)); - } - - public void handleMessage(Message msg) { - super.handleMessage(msg); - if (msg.what == 0) { - msg.flags = -1; - msg.what = 1; - msg.arg1 = 456; - msg.arg2 = 789; - msg.obj = this; - msg.replyTo = null; - mBundle = new Bundle(); - msg.data = mBundle; - msg.data.putString("key", "value"); - - Message newMsg = mHandler.obtainMessage(); - newMsg.copyFrom(msg); - if (newMsg.isInUse() != false) { - failure(new RuntimeException( - "newMsg.isInUse is true should be false after copyFrom")); - } - if (newMsg.flags != 0) { - failure(new RuntimeException(String.format( - "newMsg.flags is %d should be 0 after copyFrom", newMsg.flags))); - } - if (newMsg.what != 1) { - failure(new RuntimeException(String.format( - "newMsg.what is %d should be %d after copyFrom", newMsg.what, 1))); - } - if (newMsg.arg1 != 456) { - failure(new RuntimeException(String.format( - "newMsg.arg1 is %d should be %d after copyFrom", msg.arg1, 456))); - } - if (newMsg.arg2 != 789) { - failure(new RuntimeException(String.format( - "newMsg.arg2 is %d should be %d after copyFrom", msg.arg2, 789))); - } - if (newMsg.obj != this) { - failure(new RuntimeException( - "newMsg.obj should be 'this' after copyFrom")); - } - if (newMsg.replyTo != null) { - failure(new RuntimeException( - "newMsg.replyTo should be null after copyFrom")); - } - if (newMsg.data == mBundle) { - failure(new RuntimeException( - "newMsg.data should NOT be mBundle after copyFrom")); - } - if (!newMsg.data.getString("key").equals(mBundle.getString("key"))) { - failure(new RuntimeException(String.format( - "newMsg.data.getString(\"key\") is %s and does not equal" + - " mBundle.getString(\"key\") which is %s after copyFrom", - newMsg.data.getString("key"), mBundle.getString("key")))); - } - if (newMsg.when != 0) { - failure(new RuntimeException(String.format( - "newMsg.when is %d should be 0 after copyFrom", newMsg.when))); - } - if (newMsg.target != mHandler) { - failure(new RuntimeException( - "newMsg.target is NOT mHandler after copyFrom")); - } - if (newMsg.callback != null) { - failure(new RuntimeException( - "newMsg.callback is NOT null after copyFrom")); - } - - mHandler.sendMessage(newMsg); - } else if (msg.what == 1) { - if (msg.isInUse() != true) { - failure(new RuntimeException(String.format( - "msg.isInUse is false should be true after when processing %d", - msg.what))); - } - if (msg.arg1 != 456) { - failure(new RuntimeException(String.format( - "msg.arg1 is %d should be %d when processing # %d", - msg.arg1, 456, msg.what))); - } - if (msg.arg2 != 789) { - failure(new RuntimeException(String.format( - "msg.arg2 is %d should be %d when processing # %d", - msg.arg2, 789, msg.what))); - } - if (msg.obj != this) { - failure(new RuntimeException(String.format( - "msg.obj should be 'this' when processing # %d", msg.what))); - } - if (msg.replyTo != null) { - failure(new RuntimeException(String.format( - "msg.replyTo should be null when processing # %d", msg.what))); - } - if (!msg.data.getString("key").equals(mBundle.getString("key"))) { - failure(new RuntimeException(String.format( - "msg.data.getString(\"key\") is %s and does not equal" + - " mBundle.getString(\"key\") which is %s when processing # %d", - msg.data.getString("key"), mBundle.getString("key"), msg.what))); - } - if (msg.when != 0) { - failure(new RuntimeException(String.format( - "msg.when is %d should be 0 when processing # %d", - msg.when, msg.what))); - } - if (msg.target != null) { - failure(new RuntimeException(String.format( - "msg.target is NOT null when processing # %d", msg.what))); - } - if (msg.callback != null) { - failure(new RuntimeException(String.format( - "msg.callback is NOT null when processing # %d", msg.what))); - } - } else { - failure(new RuntimeException(String.format( - "Unexpected msg.what is %d" + msg.what))); - } - } - }; - - tester.doTest(1000); - } -} diff --git a/src/main/java/android/os/Messenger.java b/src/main/java/android/os/Messenger.java deleted file mode 100644 index f362f56..0000000 --- a/src/main/java/android/os/Messenger.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -/** - * Reference to a Handler, which others can use to send messages to it. - * This allows for the implementation of message-based communication across - * processes, by creating a Messenger pointing to a Handler in one process, - * and handing that Messenger to another process. - * - *

Note: the implementation underneath is just a simple wrapper around - * a {@link Binder} that is used to perform the communication. This means - * semantically you should treat it as such: this class does not impact process - * lifecycle management (you must be using some higher-level component to tell - * the system that your process needs to continue running), the connection will - * break if your process goes away for any reason, etc.

- */ -public final class Messenger implements Parcelable { - private final IMessenger mTarget; - - /** - * Create a new Messenger pointing to the given Handler. Any Message - * objects sent through this Messenger will appear in the Handler as if - * {@link Handler#sendMessage(Message) Handler.sendMessage(Message)} had - * been called directly. - * - * @param target The Handler that will receive sent messages. - */ - public Messenger(Handler target) { - mTarget = target.getIMessenger(); - } - - /** - * Send a Message to this Messenger's Handler. - * - * @param message The Message to send. Usually retrieved through - * {@link Message#obtain() Message.obtain()}. - * - * @throws RemoteException Throws DeadObjectException if the target - * Handler no longer exists. - */ - public void send(Message message) throws RemoteException { - mTarget.send(message); - } - - /** - * Retrieve the IBinder that this Messenger is using to communicate with - * its associated Handler. - * - * @return Returns the IBinder backing this Messenger. - */ - public IBinder getBinder() { - return mTarget.asBinder(); - } - - /** - * Comparison operator on two Messenger objects, such that true - * is returned then they both point to the same Handler. - */ - public boolean equals(Object otherObj) { - if (otherObj == null) { - return false; - } - try { - return mTarget.asBinder().equals(((Messenger)otherObj) - .mTarget.asBinder()); - } catch (ClassCastException e) { - } - return false; - } - - public int hashCode() { - return mTarget.asBinder().hashCode(); - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel out, int flags) { - out.writeStrongBinder(mTarget.asBinder()); - } - - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - public Messenger createFromParcel(Parcel in) { - IBinder target = in.readStrongBinder(); - return target != null ? new Messenger(target) : null; - } - - public Messenger[] newArray(int size) { - return new Messenger[size]; - } - }; - - /** - * Convenience function for writing either a Messenger or null pointer to - * a Parcel. You must use this with {@link #readMessengerOrNullFromParcel} - * for later reading it. - * - * @param messenger The Messenger to write, or null. - * @param out Where to write the Messenger. - */ - public static void writeMessengerOrNullToParcel(Messenger messenger, - Parcel out) { - out.writeStrongBinder(messenger != null ? messenger.mTarget.asBinder() - : null); - } - - /** - * Convenience function for reading either a Messenger or null pointer from - * a Parcel. You must have previously written the Messenger with - * {@link #writeMessengerOrNullToParcel}. - * - * @param in The Parcel containing the written Messenger. - * - * @return Returns the Messenger read from the Parcel, or null if null had - * been written. - */ - public static Messenger readMessengerOrNullFromParcel(Parcel in) { - IBinder b = in.readStrongBinder(); - return b != null ? new Messenger(b) : null; - } - - /** - * Create a Messenger from a raw IBinder, which had previously been - * retrieved with {@link #getBinder}. - * - * @param target The IBinder this Messenger should communicate with. - */ - public Messenger(IBinder target) { - mTarget = IMessenger.Stub.asInterface(target); - } -} diff --git a/src/main/java/android/os/MessengerService.java b/src/main/java/android/os/MessengerService.java deleted file mode 100644 index f15e134..0000000 --- a/src/main/java/android/os/MessengerService.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.app.Service; -import android.content.Intent; -import android.os.RemoteException; -import android.os.IBinder; -import android.os.Handler; -import android.os.Message; -import android.os.Messenger; - -public class MessengerService extends Service { - private final Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - Message reply = Message.obtain(); - reply.copyFrom(msg); - try { - msg.replyTo.send(reply); - } catch (RemoteException e) { - } - } - }; - - private final Messenger mMessenger = new Messenger(mHandler); - - public MessengerService() { - } - - @Override - public IBinder onBind(Intent intent) { - return mMessenger.getBinder(); - } -} - diff --git a/src/main/java/android/os/MessengerTest.java b/src/main/java/android/os/MessengerTest.java deleted file mode 100644 index 473ffe2..0000000 --- a/src/main/java/android/os/MessengerTest.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.os.RemoteException; -import android.os.Handler; -import android.os.IBinder; -import android.os.Message; -import android.os.Messenger; -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.MediumTest; - -public class MessengerTest extends AndroidTestCase { - private Messenger mServiceMessenger; - - private ServiceConnection mConnection = new ServiceConnection() { - public void onServiceConnected(ComponentName name, IBinder service) { - synchronized (MessengerTest.this) { - mServiceMessenger = new Messenger(service); - MessengerTest.this.notifyAll(); - } - } - public void onServiceDisconnected(ComponentName name) { - mServiceMessenger = null; - } - }; - - private class TestThread extends TestHandlerThread { - private Handler mTestHandler; - private Messenger mTestMessenger; - - public void go() { - synchronized (MessengerTest.this) { - mTestHandler = new Handler() { - public void handleMessage(Message msg) { - TestThread.this.handleMessage(msg); - } - }; - mTestMessenger = new Messenger(mTestHandler); - TestThread.this.executeTest(); - } - } - - public void executeTest() { - Message msg = Message.obtain(); - msg.arg1 = 100; - msg.arg2 = 1000; - msg.replyTo = mTestMessenger; - try { - mServiceMessenger.send(msg); - } catch (RemoteException e) { - } - } - - public void handleMessage(Message msg) { - if (msg.arg1 != 100) { - failure(new RuntimeException( - "Message.arg1 is not 100: " + msg.arg1)); - return; - } - if (msg.arg2 != 1000) { - failure(new RuntimeException( - "Message.arg2 is not 1000: " + msg.arg2)); - return; - } - if (!mTestMessenger.equals(msg.replyTo)) { - failure(new RuntimeException( - "Message.replyTo is not me: " + msg.replyTo)); - return; - } - success(); - } - }; - - @Override - protected void setUp() throws Exception { - super.setUp(); - getContext().bindService(new Intent(mContext, MessengerService.class), - mConnection, Context.BIND_AUTO_CREATE); - synchronized (this) { - while (mServiceMessenger == null) { - try { - wait(); - } catch (InterruptedException e) { - } - } - } - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - getContext().unbindService(mConnection); - } - - @MediumTest - public void testSend() { - (new TestThread()).doTest(1000); - - } -} diff --git a/src/main/java/android/os/NetworkOnMainThreadException.java b/src/main/java/android/os/NetworkOnMainThreadException.java deleted file mode 100644 index dd8c66c..0000000 --- a/src/main/java/android/os/NetworkOnMainThreadException.java +++ /dev/null @@ -1,32 +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.os; - -/** - * The exception that is thrown when an application attempts - * to perform a networking operation on its main thread. - * - *

This is only thrown for applications targeting the Honeycomb - * SDK or higher. Applications targeting earlier SDK versions - * are allowed to do networking on their main event loop threads, - * but it's heavily discouraged. See the document - * - * Designing for Responsiveness. - * - *

Also see {@link StrictMode}. - */ -public class NetworkOnMainThreadException extends RuntimeException { -} diff --git a/src/main/java/android/os/NullVibrator.java b/src/main/java/android/os/NullVibrator.java deleted file mode 100644 index f14d965..0000000 --- a/src/main/java/android/os/NullVibrator.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.media.AudioAttributes; - -/** - * Vibrator implementation that does nothing. - * - * @hide - */ -public class NullVibrator extends Vibrator { - private static final NullVibrator sInstance = new NullVibrator(); - - private NullVibrator() { - } - - public static NullVibrator getInstance() { - return sInstance; - } - - @Override - public boolean hasVibrator() { - return false; - } - - /** - * @hide - */ - @Override - public void vibrate(int uid, String opPkg, long milliseconds, AudioAttributes attributes) { - vibrate(milliseconds); - } - - /** - * @hide - */ - @Override - public void vibrate(int uid, String opPkg, long[] pattern, int repeat, - AudioAttributes attributes) { - if (repeat >= pattern.length) { - throw new ArrayIndexOutOfBoundsException(); - } - } - - @Override - public void cancel() { - } -} diff --git a/src/main/java/android/os/OperationCanceledException.java b/src/main/java/android/os/OperationCanceledException.java deleted file mode 100644 index b0cd663..0000000 --- a/src/main/java/android/os/OperationCanceledException.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - - -/** - * An exception type that is thrown when an operation in progress is canceled. - * - * @see CancellationSignal - */ -public class OperationCanceledException extends RuntimeException { - public OperationCanceledException() { - this(null); - } - - public OperationCanceledException(String message) { - super(message != null ? message : "The operation has been canceled."); - } -} diff --git a/src/main/java/android/os/OsTests.java b/src/main/java/android/os/OsTests.java deleted file mode 100644 index 582bf1a..0000000 --- a/src/main/java/android/os/OsTests.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import com.google.android.collect.Lists; -import junit.framework.TestSuite; - -import java.util.Enumeration; -import java.util.List; - -public class OsTests { - public static TestSuite suite() { - TestSuite suite = new TestSuite(OsTests.class.getName()); - - suite.addTestSuite(AidlTest.class); - suite.addTestSuite(BroadcasterTest.class); - suite.addTestSuite(FileObserverTest.class); - suite.addTestSuite(IdleHandlerTest.class); - suite.addTestSuite(MessageQueueTest.class); - suite.addTestSuite(MessengerTest.class); - suite.addTestSuite(SystemPropertiesTest.class); - - return suite; - } -} diff --git a/src/main/java/android/os/Parcel.java b/src/main/java/android/os/Parcel.java deleted file mode 100644 index 3d5215b..0000000 --- a/src/main/java/android/os/Parcel.java +++ /dev/null @@ -1,2563 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.text.TextUtils; -import android.util.ArrayMap; -import android.util.Log; -import android.util.Size; -import android.util.SizeF; -import android.util.SparseArray; -import android.util.SparseBooleanArray; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.FileDescriptor; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.ObjectStreamClass; -import java.io.Serializable; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * Container for a message (data and object references) that can - * be sent through an IBinder. A Parcel can contain both flattened data - * that will be unflattened on the other side of the IPC (using the various - * methods here for writing specific types, or the general - * {@link Parcelable} interface), and references to live {@link IBinder} - * objects that will result in the other side receiving a proxy IBinder - * connected with the original IBinder in the Parcel. - * - *

Parcel is not a general-purpose - * serialization mechanism. This class (and the corresponding - * {@link Parcelable} API for placing arbitrary objects into a Parcel) is - * designed as a high-performance IPC transport. As such, it is not - * appropriate to place any Parcel data in to persistent storage: changes - * in the underlying implementation of any of the data in the Parcel can - * render older data unreadable.

- * - *

The bulk of the Parcel API revolves around reading and writing data - * of various types. There are six major classes of such functions available.

- * - *

Primitives

- * - *

The most basic data functions are for writing and reading primitive - * data types: {@link #writeByte}, {@link #readByte}, {@link #writeDouble}, - * {@link #readDouble}, {@link #writeFloat}, {@link #readFloat}, {@link #writeInt}, - * {@link #readInt}, {@link #writeLong}, {@link #readLong}, - * {@link #writeString}, {@link #readString}. Most other - * data operations are built on top of these. The given data is written and - * read using the endianess of the host CPU.

- * - *

Primitive Arrays

- * - *

There are a variety of methods for reading and writing raw arrays - * of primitive objects, which generally result in writing a 4-byte length - * followed by the primitive data items. The methods for reading can either - * read the data into an existing array, or create and return a new array. - * These available types are:

- * - *
    - *
  • {@link #writeBooleanArray(boolean[])}, - * {@link #readBooleanArray(boolean[])}, {@link #createBooleanArray()} - *
  • {@link #writeByteArray(byte[])}, - * {@link #writeByteArray(byte[], int, int)}, {@link #readByteArray(byte[])}, - * {@link #createByteArray()} - *
  • {@link #writeCharArray(char[])}, {@link #readCharArray(char[])}, - * {@link #createCharArray()} - *
  • {@link #writeDoubleArray(double[])}, {@link #readDoubleArray(double[])}, - * {@link #createDoubleArray()} - *
  • {@link #writeFloatArray(float[])}, {@link #readFloatArray(float[])}, - * {@link #createFloatArray()} - *
  • {@link #writeIntArray(int[])}, {@link #readIntArray(int[])}, - * {@link #createIntArray()} - *
  • {@link #writeLongArray(long[])}, {@link #readLongArray(long[])}, - * {@link #createLongArray()} - *
  • {@link #writeStringArray(String[])}, {@link #readStringArray(String[])}, - * {@link #createStringArray()}. - *
  • {@link #writeSparseBooleanArray(SparseBooleanArray)}, - * {@link #readSparseBooleanArray()}. - *
- * - *

Parcelables

- * - *

The {@link Parcelable} protocol provides an extremely efficient (but - * low-level) protocol for objects to write and read themselves from Parcels. - * You can use the direct methods {@link #writeParcelable(Parcelable, int)} - * and {@link #readParcelable(ClassLoader)} or - * {@link #writeParcelableArray} and - * {@link #readParcelableArray(ClassLoader)} to write or read. These - * methods write both the class type and its data to the Parcel, allowing - * that class to be reconstructed from the appropriate class loader when - * later reading.

- * - *

There are also some methods that provide a more efficient way to work - * with Parcelables: {@link #writeTypedArray}, - * {@link #writeTypedList(List)}, - * {@link #readTypedArray} and {@link #readTypedList}. These methods - * do not write the class information of the original object: instead, the - * caller of the read function must know what type to expect and pass in the - * appropriate {@link Parcelable.Creator Parcelable.Creator} instead to - * properly construct the new object and read its data. (To more efficient - * write and read a single Parceable object, you can directly call - * {@link Parcelable#writeToParcel Parcelable.writeToParcel} and - * {@link Parcelable.Creator#createFromParcel Parcelable.Creator.createFromParcel} - * yourself.)

- * - *

Bundles

- * - *

A special type-safe container, called {@link Bundle}, is available - * for key/value maps of heterogeneous values. This has many optimizations - * for improved performance when reading and writing data, and its type-safe - * API avoids difficult to debug type errors when finally marshalling the - * data contents into a Parcel. The methods to use are - * {@link #writeBundle(Bundle)}, {@link #readBundle()}, and - * {@link #readBundle(ClassLoader)}. - * - *

Active Objects

- * - *

An unusual feature of Parcel is the ability to read and write active - * objects. For these objects the actual contents of the object is not - * written, rather a special token referencing the object is written. When - * reading the object back from the Parcel, you do not get a new instance of - * the object, but rather a handle that operates on the exact same object that - * was originally written. There are two forms of active objects available.

- * - *

{@link Binder} objects are a core facility of Android's general cross-process - * communication system. The {@link IBinder} interface describes an abstract - * protocol with a Binder object. Any such interface can be written in to - * a Parcel, and upon reading you will receive either the original object - * implementing that interface or a special proxy implementation - * that communicates calls back to the original object. The methods to use are - * {@link #writeStrongBinder(IBinder)}, - * {@link #writeStrongInterface(IInterface)}, {@link #readStrongBinder()}, - * {@link #writeBinderArray(IBinder[])}, {@link #readBinderArray(IBinder[])}, - * {@link #createBinderArray()}, - * {@link #writeBinderList(List)}, {@link #readBinderList(List)}, - * {@link #createBinderArrayList()}.

- * - *

FileDescriptor objects, representing raw Linux file descriptor identifiers, - * can be written and {@link ParcelFileDescriptor} objects returned to operate - * on the original file descriptor. The returned file descriptor is a dup - * of the original file descriptor: the object and fd is different, but - * operating on the same underlying file stream, with the same position, etc. - * The methods to use are {@link #writeFileDescriptor(FileDescriptor)}, - * {@link #readFileDescriptor()}. - * - *

Untyped Containers

- * - *

A final class of methods are for writing and reading standard Java - * containers of arbitrary types. These all revolve around the - * {@link #writeValue(Object)} and {@link #readValue(ClassLoader)} methods - * which define the types of objects allowed. The container methods are - * {@link #writeArray(Object[])}, {@link #readArray(ClassLoader)}, - * {@link #writeList(List)}, {@link #readList(List, ClassLoader)}, - * {@link #readArrayList(ClassLoader)}, - * {@link #writeMap(Map)}, {@link #readMap(Map, ClassLoader)}, - * {@link #writeSparseArray(SparseArray)}, - * {@link #readSparseArray(ClassLoader)}. - */ -public final class Parcel { - private static final boolean DEBUG_RECYCLE = false; - private static final boolean DEBUG_ARRAY_MAP = false; - private static final String TAG = "Parcel"; - - @SuppressWarnings({"UnusedDeclaration"}) - private long mNativePtr; // used by native code - - /** - * Flag indicating if {@link #mNativePtr} was allocated by this object, - * indicating that we're responsible for its lifecycle. - */ - private boolean mOwnsNativeParcelObject; - - private RuntimeException mStack; - - private static final int POOL_SIZE = 6; - private static final Parcel[] sOwnedPool = new Parcel[POOL_SIZE]; - private static final Parcel[] sHolderPool = new Parcel[POOL_SIZE]; - - private static final int VAL_NULL = -1; - private static final int VAL_STRING = 0; - private static final int VAL_INTEGER = 1; - private static final int VAL_MAP = 2; - private static final int VAL_BUNDLE = 3; - private static final int VAL_PARCELABLE = 4; - private static final int VAL_SHORT = 5; - private static final int VAL_LONG = 6; - private static final int VAL_FLOAT = 7; - private static final int VAL_DOUBLE = 8; - private static final int VAL_BOOLEAN = 9; - private static final int VAL_CHARSEQUENCE = 10; - private static final int VAL_LIST = 11; - private static final int VAL_SPARSEARRAY = 12; - private static final int VAL_BYTEARRAY = 13; - private static final int VAL_STRINGARRAY = 14; - private static final int VAL_IBINDER = 15; - private static final int VAL_PARCELABLEARRAY = 16; - private static final int VAL_OBJECTARRAY = 17; - private static final int VAL_INTARRAY = 18; - private static final int VAL_LONGARRAY = 19; - private static final int VAL_BYTE = 20; - private static final int VAL_SERIALIZABLE = 21; - private static final int VAL_SPARSEBOOLEANARRAY = 22; - private static final int VAL_BOOLEANARRAY = 23; - private static final int VAL_CHARSEQUENCEARRAY = 24; - private static final int VAL_PERSISTABLEBUNDLE = 25; - private static final int VAL_SIZE = 26; - private static final int VAL_SIZEF = 27; - - // The initial int32 in a Binder call's reply Parcel header: - private static final int EX_SECURITY = -1; - private static final int EX_BAD_PARCELABLE = -2; - private static final int EX_ILLEGAL_ARGUMENT = -3; - private static final int EX_NULL_POINTER = -4; - private static final int EX_ILLEGAL_STATE = -5; - private static final int EX_NETWORK_MAIN_THREAD = -6; - private static final int EX_UNSUPPORTED_OPERATION = -7; - private static final int EX_HAS_REPLY_HEADER = -128; // special; see below - - private static native int nativeDataSize(long nativePtr); - private static native int nativeDataAvail(long nativePtr); - private static native int nativeDataPosition(long nativePtr); - private static native int nativeDataCapacity(long nativePtr); - private static native void nativeSetDataSize(long nativePtr, int size); - private static native void nativeSetDataPosition(long nativePtr, int pos); - private static native void nativeSetDataCapacity(long nativePtr, int size); - - private static native boolean nativePushAllowFds(long nativePtr, boolean allowFds); - private static native void nativeRestoreAllowFds(long nativePtr, boolean lastValue); - - private static native void nativeWriteByteArray(long nativePtr, byte[] b, int offset, int len); - private static native void nativeWriteBlob(long nativePtr, byte[] b, int offset, int len); - private static native void nativeWriteInt(long nativePtr, int val); - private static native void nativeWriteLong(long nativePtr, long val); - private static native void nativeWriteFloat(long nativePtr, float val); - private static native void nativeWriteDouble(long nativePtr, double val); - private static native void nativeWriteString(long nativePtr, String val); - private static native void nativeWriteStrongBinder(long nativePtr, IBinder val); - private static native void nativeWriteFileDescriptor(long nativePtr, FileDescriptor val); - - private static native byte[] nativeCreateByteArray(long nativePtr); - private static native byte[] nativeReadBlob(long nativePtr); - private static native int nativeReadInt(long nativePtr); - private static native long nativeReadLong(long nativePtr); - private static native float nativeReadFloat(long nativePtr); - private static native double nativeReadDouble(long nativePtr); - private static native String nativeReadString(long nativePtr); - private static native IBinder nativeReadStrongBinder(long nativePtr); - private static native FileDescriptor nativeReadFileDescriptor(long nativePtr); - - private static native long nativeCreate(); - private static native void nativeFreeBuffer(long nativePtr); - private static native void nativeDestroy(long nativePtr); - - private static native byte[] nativeMarshall(long nativePtr); - private static native void nativeUnmarshall( - long nativePtr, byte[] data, int offset, int length); - private static native void nativeAppendFrom( - long thisNativePtr, long otherNativePtr, int offset, int length); - private static native boolean nativeHasFileDescriptors(long nativePtr); - private static native void nativeWriteInterfaceToken(long nativePtr, String interfaceName); - private static native void nativeEnforceInterface(long nativePtr, String interfaceName); - - public final static Parcelable.Creator STRING_CREATOR - = new Parcelable.Creator() { - public String createFromParcel(Parcel source) { - return source.readString(); - } - public String[] newArray(int size) { - return new String[size]; - } - }; - - /** - * Retrieve a new Parcel object from the pool. - */ - public static Parcel obtain() { - final Parcel[] pool = sOwnedPool; - synchronized (pool) { - Parcel p; - for (int i=0; i= {@link #dataSize}. The difference between it and dataSize() is the - * amount of room left until the parcel needs to re-allocate its - * data buffer. - */ - public final int dataCapacity() { - return nativeDataCapacity(mNativePtr); - } - - /** - * Change the amount of data in the parcel. Can be either smaller or - * larger than the current size. If larger than the current capacity, - * more memory will be allocated. - * - * @param size The new number of bytes in the Parcel. - */ - public final void setDataSize(int size) { - nativeSetDataSize(mNativePtr, size); - } - - /** - * Move the current read/write position in the parcel. - * @param pos New offset in the parcel; must be between 0 and - * {@link #dataSize}. - */ - public final void setDataPosition(int pos) { - nativeSetDataPosition(mNativePtr, pos); - } - - /** - * Change the capacity (current available space) of the parcel. - * - * @param size The new capacity of the parcel, in bytes. Can not be - * less than {@link #dataSize} -- that is, you can not drop existing data - * with this method. - */ - public final void setDataCapacity(int size) { - nativeSetDataCapacity(mNativePtr, size); - } - - /** @hide */ - public final boolean pushAllowFds(boolean allowFds) { - return nativePushAllowFds(mNativePtr, allowFds); - } - - /** @hide */ - public final void restoreAllowFds(boolean lastValue) { - nativeRestoreAllowFds(mNativePtr, lastValue); - } - - /** - * Returns the raw bytes of the parcel. - * - *

The data you retrieve here must not - * be placed in any kind of persistent storage (on local disk, across - * a network, etc). For that, you should use standard serialization - * or another kind of general serialization mechanism. The Parcel - * marshalled representation is highly optimized for local IPC, and as - * such does not attempt to maintain compatibility with data created - * in different versions of the platform. - */ - public final byte[] marshall() { - return nativeMarshall(mNativePtr); - } - - /** - * Set the bytes in data to be the raw bytes of this Parcel. - */ - public final void unmarshall(byte[] data, int offset, int length) { - nativeUnmarshall(mNativePtr, data, offset, length); - } - - public final void appendFrom(Parcel parcel, int offset, int length) { - nativeAppendFrom(mNativePtr, parcel.mNativePtr, offset, length); - } - - /** - * Report whether the parcel contains any marshalled file descriptors. - */ - public final boolean hasFileDescriptors() { - return nativeHasFileDescriptors(mNativePtr); - } - - /** - * Store or read an IBinder interface token in the parcel at the current - * {@link #dataPosition}. This is used to validate that the marshalled - * transaction is intended for the target interface. - */ - public final void writeInterfaceToken(String interfaceName) { - nativeWriteInterfaceToken(mNativePtr, interfaceName); - } - - public final void enforceInterface(String interfaceName) { - nativeEnforceInterface(mNativePtr, interfaceName); - } - - /** - * Write a byte array into the parcel at the current {@link #dataPosition}, - * growing {@link #dataCapacity} if needed. - * @param b Bytes to place into the parcel. - */ - public final void writeByteArray(byte[] b) { - writeByteArray(b, 0, (b != null) ? b.length : 0); - } - - /** - * Write a byte array into the parcel at the current {@link #dataPosition}, - * growing {@link #dataCapacity} if needed. - * @param b Bytes to place into the parcel. - * @param offset Index of first byte to be written. - * @param len Number of bytes to write. - */ - public final void writeByteArray(byte[] b, int offset, int len) { - if (b == null) { - writeInt(-1); - return; - } - Arrays.checkOffsetAndCount(b.length, offset, len); - nativeWriteByteArray(mNativePtr, b, offset, len); - } - - /** - * Write a blob of data into the parcel at the current {@link #dataPosition}, - * growing {@link #dataCapacity} if needed. - * @param b Bytes to place into the parcel. - * {@hide} - * {@SystemApi} - */ - public final void writeBlob(byte[] b) { - nativeWriteBlob(mNativePtr, b, 0, (b != null) ? b.length : 0); - } - - /** - * Write an integer value into the parcel at the current dataPosition(), - * growing dataCapacity() if needed. - */ - public final void writeInt(int val) { - nativeWriteInt(mNativePtr, val); - } - - /** - * Write a long integer value into the parcel at the current dataPosition(), - * growing dataCapacity() if needed. - */ - public final void writeLong(long val) { - nativeWriteLong(mNativePtr, val); - } - - /** - * Write a floating point value into the parcel at the current - * dataPosition(), growing dataCapacity() if needed. - */ - public final void writeFloat(float val) { - nativeWriteFloat(mNativePtr, val); - } - - /** - * Write a double precision floating point value into the parcel at the - * current dataPosition(), growing dataCapacity() if needed. - */ - public final void writeDouble(double val) { - nativeWriteDouble(mNativePtr, val); - } - - /** - * Write a string value into the parcel at the current dataPosition(), - * growing dataCapacity() if needed. - */ - public final void writeString(String val) { - nativeWriteString(mNativePtr, val); - } - - /** - * Write a CharSequence value into the parcel at the current dataPosition(), - * growing dataCapacity() if needed. - * @hide - */ - public final void writeCharSequence(CharSequence val) { - TextUtils.writeToParcel(val, this, 0); - } - - /** - * Write an object into the parcel at the current dataPosition(), - * growing dataCapacity() if needed. - */ - public final void writeStrongBinder(IBinder val) { - nativeWriteStrongBinder(mNativePtr, val); - } - - /** - * Write an object into the parcel at the current dataPosition(), - * growing dataCapacity() if needed. - */ - public final void writeStrongInterface(IInterface val) { - writeStrongBinder(val == null ? null : val.asBinder()); - } - - /** - * Write a FileDescriptor into the parcel at the current dataPosition(), - * growing dataCapacity() if needed. - * - *

The file descriptor will not be closed, which may - * result in file descriptor leaks when objects are returned from Binder - * calls. Use {@link ParcelFileDescriptor#writeToParcel} instead, which - * accepts contextual flags and will close the original file descriptor - * if {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set.

- */ - public final void writeFileDescriptor(FileDescriptor val) { - nativeWriteFileDescriptor(mNativePtr, val); - } - - /** - * Write a byte value into the parcel at the current dataPosition(), - * growing dataCapacity() if needed. - */ - public final void writeByte(byte val) { - writeInt(val); - } - - /** - * Please use {@link #writeBundle} instead. Flattens a Map into the parcel - * at the current dataPosition(), - * growing dataCapacity() if needed. The Map keys must be String objects. - * The Map values are written using {@link #writeValue} and must follow - * the specification there. - * - *

It is strongly recommended to use {@link #writeBundle} instead of - * this method, since the Bundle class provides a type-safe API that - * allows you to avoid mysterious type errors at the point of marshalling. - */ - public final void writeMap(Map val) { - writeMapInternal((Map) val); - } - - /** - * Flatten a Map into the parcel at the current dataPosition(), - * growing dataCapacity() if needed. The Map keys must be String objects. - */ - /* package */ void writeMapInternal(Map val) { - if (val == null) { - writeInt(-1); - return; - } - Set> entries = val.entrySet(); - writeInt(entries.size()); - for (Map.Entry e : entries) { - writeValue(e.getKey()); - writeValue(e.getValue()); - } - } - - /** - * Flatten an ArrayMap into the parcel at the current dataPosition(), - * growing dataCapacity() if needed. The Map keys must be String objects. - */ - /* package */ void writeArrayMapInternal(ArrayMap val) { - if (val == null) { - writeInt(-1); - return; - } - final int N = val.size(); - writeInt(N); - if (DEBUG_ARRAY_MAP) { - RuntimeException here = new RuntimeException("here"); - here.fillInStackTrace(); - Log.d(TAG, "Writing " + N + " ArrayMap entries", here); - } - int startPos; - for (int i=0; i val) { - writeArrayMapInternal(val); - } - - /** - * Flatten a Bundle into the parcel at the current dataPosition(), - * growing dataCapacity() if needed. - */ - public final void writeBundle(Bundle val) { - if (val == null) { - writeInt(-1); - return; - } - - val.writeToParcel(this, 0); - } - - /** - * Flatten a PersistableBundle into the parcel at the current dataPosition(), - * growing dataCapacity() if needed. - */ - public final void writePersistableBundle(PersistableBundle val) { - if (val == null) { - writeInt(-1); - return; - } - - val.writeToParcel(this, 0); - } - - /** - * Flatten a Size into the parcel at the current dataPosition(), - * growing dataCapacity() if needed. - */ - public final void writeSize(Size val) { - writeInt(val.getWidth()); - writeInt(val.getHeight()); - } - - /** - * Flatten a SizeF into the parcel at the current dataPosition(), - * growing dataCapacity() if needed. - */ - public final void writeSizeF(SizeF val) { - writeFloat(val.getWidth()); - writeFloat(val.getHeight()); - } - - /** - * Flatten a List into the parcel at the current dataPosition(), growing - * dataCapacity() if needed. The List values are written using - * {@link #writeValue} and must follow the specification there. - */ - public final void writeList(List val) { - if (val == null) { - writeInt(-1); - return; - } - int N = val.size(); - int i=0; - writeInt(N); - while (i < N) { - writeValue(val.get(i)); - i++; - } - } - - /** - * Flatten an Object array into the parcel at the current dataPosition(), - * growing dataCapacity() if needed. The array values are written using - * {@link #writeValue} and must follow the specification there. - */ - public final void writeArray(Object[] val) { - if (val == null) { - writeInt(-1); - return; - } - int N = val.length; - int i=0; - writeInt(N); - while (i < N) { - writeValue(val[i]); - i++; - } - } - - /** - * Flatten a generic SparseArray into the parcel at the current - * dataPosition(), growing dataCapacity() if needed. The SparseArray - * values are written using {@link #writeValue} and must follow the - * specification there. - */ - public final void writeSparseArray(SparseArray val) { - if (val == null) { - writeInt(-1); - return; - } - int N = val.size(); - writeInt(N); - int i=0; - while (i < N) { - writeInt(val.keyAt(i)); - writeValue(val.valueAt(i)); - i++; - } - } - - public final void writeSparseBooleanArray(SparseBooleanArray val) { - if (val == null) { - writeInt(-1); - return; - } - int N = val.size(); - writeInt(N); - int i=0; - while (i < N) { - writeInt(val.keyAt(i)); - writeByte((byte)(val.valueAt(i) ? 1 : 0)); - i++; - } - } - - public final void writeBooleanArray(boolean[] val) { - if (val != null) { - int N = val.length; - writeInt(N); - for (int i=0; i>2 as a fast divide-by-4 works in the create*Array() functions - // because dataAvail() will never return a negative number. 4 is - // the size of a stored boolean in the stream. - if (N >= 0 && N <= (dataAvail() >> 2)) { - boolean[] val = new boolean[N]; - for (int i=0; i= 0 && N <= (dataAvail() >> 2)) { - char[] val = new char[N]; - for (int i=0; i= 0 && N <= (dataAvail() >> 2)) { - int[] val = new int[N]; - for (int i=0; i>3 because stored longs are 64 bits - if (N >= 0 && N <= (dataAvail() >> 3)) { - long[] val = new long[N]; - for (int i=0; i>2 because stored floats are 4 bytes - if (N >= 0 && N <= (dataAvail() >> 2)) { - float[] val = new float[N]; - for (int i=0; i>3 because stored doubles are 8 bytes - if (N >= 0 && N <= (dataAvail() >> 3)) { - double[] val = new double[N]; - for (int i=0; i= 0) { - String[] val = new String[N]; - for (int i=0; i= 0) { - IBinder[] val = new IBinder[N]; - for (int i=0; i void writeTypedList(List val) { - if (val == null) { - writeInt(-1); - return; - } - int N = val.size(); - int i=0; - writeInt(N); - while (i < N) { - T item = val.get(i); - if (item != null) { - writeInt(1); - item.writeToParcel(this, 0); - } else { - writeInt(0); - } - i++; - } - } - - /** - * Flatten a List containing String objects into the parcel, at - * the current dataPosition() and growing dataCapacity() if needed. They - * can later be retrieved with {@link #createStringArrayList} or - * {@link #readStringList}. - * - * @param val The list of strings to be written. - * - * @see #createStringArrayList - * @see #readStringList - */ - public final void writeStringList(List val) { - if (val == null) { - writeInt(-1); - return; - } - int N = val.size(); - int i=0; - writeInt(N); - while (i < N) { - writeString(val.get(i)); - i++; - } - } - - /** - * Flatten a List containing IBinder objects into the parcel, at - * the current dataPosition() and growing dataCapacity() if needed. They - * can later be retrieved with {@link #createBinderArrayList} or - * {@link #readBinderList}. - * - * @param val The list of strings to be written. - * - * @see #createBinderArrayList - * @see #readBinderList - */ - public final void writeBinderList(List val) { - if (val == null) { - writeInt(-1); - return; - } - int N = val.size(); - int i=0; - writeInt(N); - while (i < N) { - writeStrongBinder(val.get(i)); - i++; - } - } - - /** - * Flatten a heterogeneous array containing a particular object type into - * the parcel, at - * the current dataPosition() and growing dataCapacity() if needed. The - * type of the objects in the array must be one that implements Parcelable. - * Unlike the {@link #writeParcelableArray} method, however, only the - * raw data of the objects is written and not their type, so you must use - * {@link #readTypedArray} with the correct corresponding - * {@link Parcelable.Creator} implementation to unmarshall them. - * - * @param val The array of objects to be written. - * @param parcelableFlags Contextual flags as per - * {@link Parcelable#writeToParcel(Parcel, int) Parcelable.writeToParcel()}. - * - * @see #readTypedArray - * @see #writeParcelableArray - * @see Parcelable.Creator - */ - public final void writeTypedArray(T[] val, - int parcelableFlags) { - if (val != null) { - int N = val.length; - writeInt(N); - for (int i=0; i - *
  • null - *
  • String - *
  • Byte - *
  • Short - *
  • Integer - *
  • Long - *
  • Float - *
  • Double - *
  • Boolean - *
  • String[] - *
  • boolean[] - *
  • byte[] - *
  • int[] - *
  • long[] - *
  • Object[] (supporting objects of the same type defined here). - *
  • {@link Bundle} - *
  • Map (as supported by {@link #writeMap}). - *
  • Any object that implements the {@link Parcelable} protocol. - *
  • Parcelable[] - *
  • CharSequence (as supported by {@link TextUtils#writeToParcel}). - *
  • List (as supported by {@link #writeList}). - *
  • {@link SparseArray} (as supported by {@link #writeSparseArray(SparseArray)}). - *
  • {@link IBinder} - *
  • Any object that implements Serializable (but see - * {@link #writeSerializable} for caveats). Note that all of the - * previous types have relatively efficient implementations for - * writing to a Parcel; having to rely on the generic serialization - * approach is much less efficient and should be avoided whenever - * possible. - * - * - *

    {@link Parcelable} objects are written with - * {@link Parcelable#writeToParcel} using contextual flags of 0. When - * serializing objects containing {@link ParcelFileDescriptor}s, - * this may result in file descriptor leaks when they are returned from - * Binder calls (where {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} - * should be used).

    - */ - public final void writeValue(Object v) { - if (v == null) { - writeInt(VAL_NULL); - } else if (v instanceof String) { - writeInt(VAL_STRING); - writeString((String) v); - } else if (v instanceof Integer) { - writeInt(VAL_INTEGER); - writeInt((Integer) v); - } else if (v instanceof Map) { - writeInt(VAL_MAP); - writeMap((Map) v); - } else if (v instanceof Bundle) { - // Must be before Parcelable - writeInt(VAL_BUNDLE); - writeBundle((Bundle) v); - } else if (v instanceof Parcelable) { - writeInt(VAL_PARCELABLE); - writeParcelable((Parcelable) v, 0); - } else if (v instanceof Short) { - writeInt(VAL_SHORT); - writeInt(((Short) v).intValue()); - } else if (v instanceof Long) { - writeInt(VAL_LONG); - writeLong((Long) v); - } else if (v instanceof Float) { - writeInt(VAL_FLOAT); - writeFloat((Float) v); - } else if (v instanceof Double) { - writeInt(VAL_DOUBLE); - writeDouble((Double) v); - } else if (v instanceof Boolean) { - writeInt(VAL_BOOLEAN); - writeInt((Boolean) v ? 1 : 0); - } else if (v instanceof CharSequence) { - // Must be after String - writeInt(VAL_CHARSEQUENCE); - writeCharSequence((CharSequence) v); - } else if (v instanceof List) { - writeInt(VAL_LIST); - writeList((List) v); - } else if (v instanceof SparseArray) { - writeInt(VAL_SPARSEARRAY); - writeSparseArray((SparseArray) v); - } else if (v instanceof boolean[]) { - writeInt(VAL_BOOLEANARRAY); - writeBooleanArray((boolean[]) v); - } else if (v instanceof byte[]) { - writeInt(VAL_BYTEARRAY); - writeByteArray((byte[]) v); - } else if (v instanceof String[]) { - writeInt(VAL_STRINGARRAY); - writeStringArray((String[]) v); - } else if (v instanceof CharSequence[]) { - // Must be after String[] and before Object[] - writeInt(VAL_CHARSEQUENCEARRAY); - writeCharSequenceArray((CharSequence[]) v); - } else if (v instanceof IBinder) { - writeInt(VAL_IBINDER); - writeStrongBinder((IBinder) v); - } else if (v instanceof Parcelable[]) { - writeInt(VAL_PARCELABLEARRAY); - writeParcelableArray((Parcelable[]) v, 0); - } else if (v instanceof int[]) { - writeInt(VAL_INTARRAY); - writeIntArray((int[]) v); - } else if (v instanceof long[]) { - writeInt(VAL_LONGARRAY); - writeLongArray((long[]) v); - } else if (v instanceof Byte) { - writeInt(VAL_BYTE); - writeInt((Byte) v); - } else if (v instanceof PersistableBundle) { - writeInt(VAL_PERSISTABLEBUNDLE); - writePersistableBundle((PersistableBundle) v); - } else if (v instanceof Size) { - writeInt(VAL_SIZE); - writeSize((Size) v); - } else if (v instanceof SizeF) { - writeInt(VAL_SIZEF); - writeSizeF((SizeF) v); - } else { - Class clazz = v.getClass(); - if (clazz.isArray() && clazz.getComponentType() == Object.class) { - // Only pure Object[] are written here, Other arrays of non-primitive types are - // handled by serialization as this does not record the component type. - writeInt(VAL_OBJECTARRAY); - writeArray((Object[]) v); - } else if (v instanceof Serializable) { - // Must be last - writeInt(VAL_SERIALIZABLE); - writeSerializable((Serializable) v); - } else { - throw new RuntimeException("Parcel: unable to marshal value " + v); - } - } - } - - /** - * Flatten the name of the class of the Parcelable and its contents - * into the parcel. - * - * @param p The Parcelable object to be written. - * @param parcelableFlags Contextual flags as per - * {@link Parcelable#writeToParcel(Parcel, int) Parcelable.writeToParcel()}. - */ - public final void writeParcelable(Parcelable p, int parcelableFlags) { - if (p == null) { - writeString(null); - return; - } - String name = p.getClass().getName(); - writeString(name); - p.writeToParcel(this, parcelableFlags); - } - - /** @hide */ - public final void writeParcelableCreator(Parcelable p) { - String name = p.getClass().getName(); - writeString(name); - } - - /** - * Write a generic serializable object in to a Parcel. It is strongly - * recommended that this method be avoided, since the serialization - * overhead is extremely large, and this approach will be much slower than - * using the other approaches to writing data in to a Parcel. - */ - public final void writeSerializable(Serializable s) { - if (s == null) { - writeString(null); - return; - } - String name = s.getClass().getName(); - writeString(name); - - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try { - ObjectOutputStream oos = new ObjectOutputStream(baos); - oos.writeObject(s); - oos.close(); - - writeByteArray(baos.toByteArray()); - } catch (IOException ioe) { - throw new RuntimeException("Parcelable encountered " + - "IOException writing serializable object (name = " + name + - ")", ioe); - } - } - - /** - * Special function for writing an exception result at the header of - * a parcel, to be used when returning an exception from a transaction. - * Note that this currently only supports a few exception types; any other - * exception will be re-thrown by this function as a RuntimeException - * (to be caught by the system's last-resort exception handling when - * dispatching a transaction). - * - *

    The supported exception types are: - *

      - *
    • {@link BadParcelableException} - *
    • {@link IllegalArgumentException} - *
    • {@link IllegalStateException} - *
    • {@link NullPointerException} - *
    • {@link SecurityException} - *
    • {@link NetworkOnMainThreadException} - *
    - * - * @param e The Exception to be written. - * - * @see #writeNoException - * @see #readException - */ - public final void writeException(Exception e) { - int code = 0; - if (e instanceof SecurityException) { - code = EX_SECURITY; - } else if (e instanceof BadParcelableException) { - code = EX_BAD_PARCELABLE; - } else if (e instanceof IllegalArgumentException) { - code = EX_ILLEGAL_ARGUMENT; - } else if (e instanceof NullPointerException) { - code = EX_NULL_POINTER; - } else if (e instanceof IllegalStateException) { - code = EX_ILLEGAL_STATE; - } else if (e instanceof NetworkOnMainThreadException) { - code = EX_NETWORK_MAIN_THREAD; - } else if (e instanceof UnsupportedOperationException) { - code = EX_UNSUPPORTED_OPERATION; - } - writeInt(code); - StrictMode.clearGatheredViolations(); - if (code == 0) { - if (e instanceof RuntimeException) { - throw (RuntimeException) e; - } - throw new RuntimeException(e); - } - writeString(e.getMessage()); - } - - /** - * Special function for writing information at the front of the Parcel - * indicating that no exception occurred. - * - * @see #writeException - * @see #readException - */ - public final void writeNoException() { - // Despite the name of this function ("write no exception"), - // it should instead be thought of as "write the RPC response - // header", but because this function name is written out by - // the AIDL compiler, we're not going to rename it. - // - // The response header, in the non-exception case (see also - // writeException above, also called by the AIDL compiler), is - // either a 0 (the default case), or EX_HAS_REPLY_HEADER if - // StrictMode has gathered up violations that have occurred - // during a Binder call, in which case we write out the number - // of violations and their details, serialized, before the - // actual RPC respons data. The receiving end of this is - // readException(), below. - if (StrictMode.hasGatheredViolations()) { - writeInt(EX_HAS_REPLY_HEADER); - final int sizePosition = dataPosition(); - writeInt(0); // total size of fat header, to be filled in later - StrictMode.writeGatheredViolationsToParcel(this); - final int payloadPosition = dataPosition(); - setDataPosition(sizePosition); - writeInt(payloadPosition - sizePosition); // header size - setDataPosition(payloadPosition); - } else { - writeInt(0); - } - } - - /** - * Special function for reading an exception result from the header of - * a parcel, to be used after receiving the result of a transaction. This - * will throw the exception for you if it had been written to the Parcel, - * otherwise return and let you read the normal result data from the Parcel. - * - * @see #writeException - * @see #writeNoException - */ - public final void readException() { - int code = readExceptionCode(); - if (code != 0) { - String msg = readString(); - readException(code, msg); - } - } - - /** - * Parses the header of a Binder call's response Parcel and - * returns the exception code. Deals with lite or fat headers. - * In the common successful case, this header is generally zero. - * In less common cases, it's a small negative number and will be - * followed by an error string. - * - * This exists purely for android.database.DatabaseUtils and - * insulating it from having to handle fat headers as returned by - * e.g. StrictMode-induced RPC responses. - * - * @hide - */ - public final int readExceptionCode() { - int code = readInt(); - if (code == EX_HAS_REPLY_HEADER) { - int headerSize = readInt(); - if (headerSize == 0) { - Log.e(TAG, "Unexpected zero-sized Parcel reply header."); - } else { - // Currently the only thing in the header is StrictMode stacks, - // but discussions around event/RPC tracing suggest we might - // put that here too. If so, switch on sub-header tags here. - // But for now, just parse out the StrictMode stuff. - StrictMode.readAndHandleBinderCallViolations(this); - } - // And fat response headers are currently only used when - // there are no exceptions, so return no error: - return 0; - } - return code; - } - - /** - * Throw an exception with the given message. Not intended for use - * outside the Parcel class. - * - * @param code Used to determine which exception class to throw. - * @param msg The exception message. - */ - public final void readException(int code, String msg) { - switch (code) { - case EX_SECURITY: - throw new SecurityException(msg); - case EX_BAD_PARCELABLE: - throw new BadParcelableException(msg); - case EX_ILLEGAL_ARGUMENT: - throw new IllegalArgumentException(msg); - case EX_NULL_POINTER: - throw new NullPointerException(msg); - case EX_ILLEGAL_STATE: - throw new IllegalStateException(msg); - case EX_NETWORK_MAIN_THREAD: - throw new NetworkOnMainThreadException(); - case EX_UNSUPPORTED_OPERATION: - throw new UnsupportedOperationException(msg); - } - throw new RuntimeException("Unknown exception code: " + code - + " msg " + msg); - } - - /** - * Read an integer value from the parcel at the current dataPosition(). - */ - public final int readInt() { - return nativeReadInt(mNativePtr); - } - - /** - * Read a long integer value from the parcel at the current dataPosition(). - */ - public final long readLong() { - return nativeReadLong(mNativePtr); - } - - /** - * Read a floating point value from the parcel at the current - * dataPosition(). - */ - public final float readFloat() { - return nativeReadFloat(mNativePtr); - } - - /** - * Read a double precision floating point value from the parcel at the - * current dataPosition(). - */ - public final double readDouble() { - return nativeReadDouble(mNativePtr); - } - - /** - * Read a string value from the parcel at the current dataPosition(). - */ - public final String readString() { - return nativeReadString(mNativePtr); - } - - /** - * Read a CharSequence value from the parcel at the current dataPosition(). - * @hide - */ - public final CharSequence readCharSequence() { - return TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(this); - } - - /** - * Read an object from the parcel at the current dataPosition(). - */ - public final IBinder readStrongBinder() { - return nativeReadStrongBinder(mNativePtr); - } - - /** - * Read a FileDescriptor from the parcel at the current dataPosition(). - */ - public final ParcelFileDescriptor readFileDescriptor() { - FileDescriptor fd = nativeReadFileDescriptor(mNativePtr); - return fd != null ? new ParcelFileDescriptor(fd) : null; - } - - /** {@hide} */ - public final FileDescriptor readRawFileDescriptor() { - return nativeReadFileDescriptor(mNativePtr); - } - - /*package*/ static native FileDescriptor openFileDescriptor(String file, - int mode) throws FileNotFoundException; - /*package*/ static native FileDescriptor dupFileDescriptor(FileDescriptor orig) - throws IOException; - /*package*/ static native void closeFileDescriptor(FileDescriptor desc) - throws IOException; - /*package*/ static native void clearFileDescriptor(FileDescriptor desc); - - /** - * Read a byte value from the parcel at the current dataPosition(). - */ - public final byte readByte() { - return (byte)(readInt() & 0xff); - } - - /** - * Please use {@link #readBundle(ClassLoader)} instead (whose data must have - * been written with {@link #writeBundle}. Read into an existing Map object - * from the parcel at the current dataPosition(). - */ - public final void readMap(Map outVal, ClassLoader loader) { - int N = readInt(); - readMapInternal(outVal, N, loader); - } - - /** - * Read into an existing List object from the parcel at the current - * dataPosition(), using the given class loader to load any enclosed - * Parcelables. If it is null, the default class loader is used. - */ - public final void readList(List outVal, ClassLoader loader) { - int N = readInt(); - readListInternal(outVal, N, loader); - } - - /** - * Please use {@link #readBundle(ClassLoader)} instead (whose data must have - * been written with {@link #writeBundle}. Read and return a new HashMap - * object from the parcel at the current dataPosition(), using the given - * class loader to load any enclosed Parcelables. Returns null if - * the previously written map object was null. - */ - public final HashMap readHashMap(ClassLoader loader) - { - int N = readInt(); - if (N < 0) { - return null; - } - HashMap m = new HashMap(N); - readMapInternal(m, N, loader); - return m; - } - - /** - * Read and return a new Bundle object from the parcel at the current - * dataPosition(). Returns null if the previously written Bundle object was - * null. - */ - public final Bundle readBundle() { - return readBundle(null); - } - - /** - * Read and return a new Bundle object from the parcel at the current - * dataPosition(), using the given class loader to initialize the class - * loader of the Bundle for later retrieval of Parcelable objects. - * Returns null if the previously written Bundle object was null. - */ - public final Bundle readBundle(ClassLoader loader) { - int length = readInt(); - if (length < 0) { - if (Bundle.DEBUG) Log.d(TAG, "null bundle: length=" + length); - return null; - } - - final Bundle bundle = new Bundle(this, length); - if (loader != null) { - bundle.setClassLoader(loader); - } - return bundle; - } - - /** - * Read and return a new Bundle object from the parcel at the current - * dataPosition(). Returns null if the previously written Bundle object was - * null. - */ - public final PersistableBundle readPersistableBundle() { - return readPersistableBundle(null); - } - - /** - * Read and return a new Bundle object from the parcel at the current - * dataPosition(), using the given class loader to initialize the class - * loader of the Bundle for later retrieval of Parcelable objects. - * Returns null if the previously written Bundle object was null. - */ - public final PersistableBundle readPersistableBundle(ClassLoader loader) { - int length = readInt(); - if (length < 0) { - if (Bundle.DEBUG) Log.d(TAG, "null bundle: length=" + length); - return null; - } - - final PersistableBundle bundle = new PersistableBundle(this, length); - if (loader != null) { - bundle.setClassLoader(loader); - } - return bundle; - } - - /** - * Read a Size from the parcel at the current dataPosition(). - */ - public final Size readSize() { - final int width = readInt(); - final int height = readInt(); - return new Size(width, height); - } - - /** - * Read a SizeF from the parcel at the current dataPosition(). - */ - public final SizeF readSizeF() { - final float width = readFloat(); - final float height = readFloat(); - return new SizeF(width, height); - } - - /** - * Read and return a byte[] object from the parcel. - */ - public final byte[] createByteArray() { - return nativeCreateByteArray(mNativePtr); - } - - /** - * Read a byte[] object from the parcel and copy it into the - * given byte array. - */ - public final void readByteArray(byte[] val) { - // TODO: make this a native method to avoid the extra copy. - byte[] ba = createByteArray(); - if (ba.length == val.length) { - System.arraycopy(ba, 0, val, 0, ba.length); - } else { - throw new RuntimeException("bad array lengths"); - } - } - - /** - * Read a blob of data from the parcel and return it as a byte array. - * {@hide} - * {@SystemApi} - */ - public final byte[] readBlob() { - return nativeReadBlob(mNativePtr); - } - - /** - * Read and return a String[] object from the parcel. - * {@hide} - */ - public final String[] readStringArray() { - String[] array = null; - - int length = readInt(); - if (length >= 0) - { - array = new String[length]; - - for (int i = 0 ; i < length ; i++) - { - array[i] = readString(); - } - } - - return array; - } - - /** - * Read and return a CharSequence[] object from the parcel. - * {@hide} - */ - public final CharSequence[] readCharSequenceArray() { - CharSequence[] array = null; - - int length = readInt(); - if (length >= 0) - { - array = new CharSequence[length]; - - for (int i = 0 ; i < length ; i++) - { - array[i] = readCharSequence(); - } - } - - return array; - } - - /** - * Read and return a new ArrayList object from the parcel at the current - * dataPosition(). Returns null if the previously written list object was - * null. The given class loader will be used to load any enclosed - * Parcelables. - */ - public final ArrayList readArrayList(ClassLoader loader) { - int N = readInt(); - if (N < 0) { - return null; - } - ArrayList l = new ArrayList(N); - readListInternal(l, N, loader); - return l; - } - - /** - * Read and return a new Object array from the parcel at the current - * dataPosition(). Returns null if the previously written array was - * null. The given class loader will be used to load any enclosed - * Parcelables. - */ - public final Object[] readArray(ClassLoader loader) { - int N = readInt(); - if (N < 0) { - return null; - } - Object[] l = new Object[N]; - readArrayInternal(l, N, loader); - return l; - } - - /** - * Read and return a new SparseArray object from the parcel at the current - * dataPosition(). Returns null if the previously written list object was - * null. The given class loader will be used to load any enclosed - * Parcelables. - */ - public final SparseArray readSparseArray(ClassLoader loader) { - int N = readInt(); - if (N < 0) { - return null; - } - SparseArray sa = new SparseArray(N); - readSparseArrayInternal(sa, N, loader); - return sa; - } - - /** - * Read and return a new SparseBooleanArray object from the parcel at the current - * dataPosition(). Returns null if the previously written list object was - * null. - */ - public final SparseBooleanArray readSparseBooleanArray() { - int N = readInt(); - if (N < 0) { - return null; - } - SparseBooleanArray sa = new SparseBooleanArray(N); - readSparseBooleanArrayInternal(sa, N); - return sa; - } - - /** - * Read and return a new ArrayList containing a particular object type from - * the parcel that was written with {@link #writeTypedList} at the - * current dataPosition(). Returns null if the - * previously written list object was null. The list must have - * previously been written via {@link #writeTypedList} with the same object - * type. - * - * @return A newly created ArrayList containing objects with the same data - * as those that were previously written. - * - * @see #writeTypedList - */ - public final ArrayList createTypedArrayList(Parcelable.Creator c) { - int N = readInt(); - if (N < 0) { - return null; - } - ArrayList l = new ArrayList(N); - while (N > 0) { - if (readInt() != 0) { - l.add(c.createFromParcel(this)); - } else { - l.add(null); - } - N--; - } - return l; - } - - /** - * Read into the given List items containing a particular object type - * that were written with {@link #writeTypedList} at the - * current dataPosition(). The list must have - * previously been written via {@link #writeTypedList} with the same object - * type. - * - * @return A newly created ArrayList containing objects with the same data - * as those that were previously written. - * - * @see #writeTypedList - */ - public final void readTypedList(List list, Parcelable.Creator c) { - int M = list.size(); - int N = readInt(); - int i = 0; - for (; i < M && i < N; i++) { - if (readInt() != 0) { - list.set(i, c.createFromParcel(this)); - } else { - list.set(i, null); - } - } - for (; i createStringArrayList() { - int N = readInt(); - if (N < 0) { - return null; - } - ArrayList l = new ArrayList(N); - while (N > 0) { - l.add(readString()); - N--; - } - return l; - } - - /** - * Read and return a new ArrayList containing IBinder objects from - * the parcel that was written with {@link #writeBinderList} at the - * current dataPosition(). Returns null if the - * previously written list object was null. - * - * @return A newly created ArrayList containing strings with the same data - * as those that were previously written. - * - * @see #writeBinderList - */ - public final ArrayList createBinderArrayList() { - int N = readInt(); - if (N < 0) { - return null; - } - ArrayList l = new ArrayList(N); - while (N > 0) { - l.add(readStrongBinder()); - N--; - } - return l; - } - - /** - * Read into the given List items String objects that were written with - * {@link #writeStringList} at the current dataPosition(). - * - * @return A newly created ArrayList containing strings with the same data - * as those that were previously written. - * - * @see #writeStringList - */ - public final void readStringList(List list) { - int M = list.size(); - int N = readInt(); - int i = 0; - for (; i < M && i < N; i++) { - list.set(i, readString()); - } - for (; i list) { - int M = list.size(); - int N = readInt(); - int i = 0; - for (; i < M && i < N; i++) { - list.set(i, readStrongBinder()); - } - for (; imust have - * previously been written via {@link #writeTypedArray} with the same - * object type. - * - * @return A newly created array containing objects with the same data - * as those that were previously written. - * - * @see #writeTypedArray - */ - public final T[] createTypedArray(Parcelable.Creator c) { - int N = readInt(); - if (N < 0) { - return null; - } - T[] l = c.newArray(N); - for (int i=0; i void readTypedArray(T[] val, Parcelable.Creator c) { - int N = readInt(); - if (N == val.length) { - for (int i=0; i T[] readTypedArray(Parcelable.Creator c) { - return createTypedArray(c); - } - - /** - * Write a heterogeneous array of Parcelable objects into the Parcel. - * Each object in the array is written along with its class name, so - * that the correct class can later be instantiated. As a result, this - * has significantly more overhead than {@link #writeTypedArray}, but will - * correctly handle an array containing more than one type of object. - * - * @param value The array of objects to be written. - * @param parcelableFlags Contextual flags as per - * {@link Parcelable#writeToParcel(Parcel, int) Parcelable.writeToParcel()}. - * - * @see #writeTypedArray - */ - public final void writeParcelableArray(T[] value, - int parcelableFlags) { - if (value != null) { - int N = value.length; - writeInt(N); - for (int i=0; i T readParcelable(ClassLoader loader) { - Parcelable.Creator creator = readParcelableCreator(loader); - if (creator == null) { - return null; - } - if (creator instanceof Parcelable.ClassLoaderCreator) { - return ((Parcelable.ClassLoaderCreator)creator).createFromParcel(this, loader); - } - return creator.createFromParcel(this); - } - - /** @hide */ - public final T readCreator(Parcelable.Creator creator, - ClassLoader loader) { - if (creator instanceof Parcelable.ClassLoaderCreator) { - return ((Parcelable.ClassLoaderCreator)creator).createFromParcel(this, loader); - } - return creator.createFromParcel(this); - } - - /** @hide */ - public final Parcelable.Creator readParcelableCreator( - ClassLoader loader) { - String name = readString(); - if (name == null) { - return null; - } - Parcelable.Creator creator; - synchronized (mCreators) { - HashMap map = mCreators.get(loader); - if (map == null) { - map = new HashMap(); - mCreators.put(loader, map); - } - creator = map.get(name); - if (creator == null) { - try { - Class c = loader == null ? - Class.forName(name) : Class.forName(name, true, loader); - Field f = c.getField("CREATOR"); - creator = (Parcelable.Creator)f.get(null); - } - catch (IllegalAccessException e) { - Log.e(TAG, "Illegal access when unmarshalling: " - + name, e); - throw new BadParcelableException( - "IllegalAccessException when unmarshalling: " + name); - } - catch (ClassNotFoundException e) { - Log.e(TAG, "Class not found when unmarshalling: " - + name, e); - throw new BadParcelableException( - "ClassNotFoundException when unmarshalling: " + name); - } - catch (ClassCastException e) { - throw new BadParcelableException("Parcelable protocol requires a " - + "Parcelable.Creator object called " - + " CREATOR on class " + name); - } - catch (NoSuchFieldException e) { - throw new BadParcelableException("Parcelable protocol requires a " - + "Parcelable.Creator object called " - + " CREATOR on class " + name); - } - catch (NullPointerException e) { - throw new BadParcelableException("Parcelable protocol requires " - + "the CREATOR object to be static on class " + name); - } - if (creator == null) { - throw new BadParcelableException("Parcelable protocol requires a " - + "Parcelable.Creator object called " - + " CREATOR on class " + name); - } - - map.put(name, creator); - } - } - - return creator; - } - - /** - * Read and return a new Parcelable array from the parcel. - * The given class loader will be used to load any enclosed - * Parcelables. - * @return the Parcelable array, or null if the array is null - */ - public final Parcelable[] readParcelableArray(ClassLoader loader) { - int N = readInt(); - if (N < 0) { - return null; - } - Parcelable[] p = new Parcelable[N]; - for (int i = 0; i < N; i++) { - p[i] = (Parcelable) readParcelable(loader); - } - return p; - } - - /** - * Read and return a new Serializable object from the parcel. - * @return the Serializable object, or null if the Serializable name - * wasn't found in the parcel. - */ - public final Serializable readSerializable() { - return readSerializable(null); - } - - private final Serializable readSerializable(final ClassLoader loader) { - String name = readString(); - if (name == null) { - // For some reason we were unable to read the name of the Serializable (either there - // is nothing left in the Parcel to read, or the next value wasn't a String), so - // return null, which indicates that the name wasn't found in the parcel. - return null; - } - - byte[] serializedData = createByteArray(); - ByteArrayInputStream bais = new ByteArrayInputStream(serializedData); - try { - ObjectInputStream ois = new ObjectInputStream(bais) { - @Override - protected Class resolveClass(ObjectStreamClass osClass) - throws IOException, ClassNotFoundException { - // try the custom classloader if provided - if (loader != null) { - Class c = Class.forName(osClass.getName(), false, loader); - if (c != null) { - return c; - } - } - return super.resolveClass(osClass); - } - }; - return (Serializable) ois.readObject(); - } catch (IOException ioe) { - throw new RuntimeException("Parcelable encountered " + - "IOException reading a Serializable object (name = " + name + - ")", ioe); - } catch (ClassNotFoundException cnfe) { - throw new RuntimeException("Parcelable encountered " + - "ClassNotFoundException reading a Serializable object (name = " - + name + ")", cnfe); - } - } - - // Cache of previously looked up CREATOR.createFromParcel() methods for - // particular classes. Keys are the names of the classes, values are - // Method objects. - private static final HashMap> - mCreators = new HashMap>(); - - /** @hide for internal use only. */ - static protected final Parcel obtain(int obj) { - throw new UnsupportedOperationException(); - } - - /** @hide */ - static protected final Parcel obtain(long obj) { - final Parcel[] pool = sHolderPool; - synchronized (pool) { - Parcel p; - for (int i=0; i 0) { - Object key = readValue(loader); - Object value = readValue(loader); - outVal.put(key, value); - N--; - } - } - - /* package */ void readArrayMapInternal(ArrayMap outVal, int N, - ClassLoader loader) { - if (DEBUG_ARRAY_MAP) { - RuntimeException here = new RuntimeException("here"); - here.fillInStackTrace(); - Log.d(TAG, "Reading " + N + " ArrayMap entries", here); - } - int startPos; - while (N > 0) { - if (DEBUG_ARRAY_MAP) startPos = dataPosition(); - String key = readString(); - Object value = readValue(loader); - if (DEBUG_ARRAY_MAP) Log.d(TAG, " Read #" + (N-1) + " " - + (dataPosition()-startPos) + " bytes: key=0x" - + Integer.toHexString((key != null ? key.hashCode() : 0)) + " " + key); - outVal.append(key, value); - N--; - } - outVal.validate(); - } - - /* package */ void readArrayMapSafelyInternal(ArrayMap outVal, int N, - ClassLoader loader) { - if (DEBUG_ARRAY_MAP) { - RuntimeException here = new RuntimeException("here"); - here.fillInStackTrace(); - Log.d(TAG, "Reading safely " + N + " ArrayMap entries", here); - } - while (N > 0) { - String key = readString(); - if (DEBUG_ARRAY_MAP) Log.d(TAG, " Read safe #" + (N-1) + ": key=0x" - + (key != null ? key.hashCode() : 0) + " " + key); - Object value = readValue(loader); - outVal.put(key, value); - N--; - } - } - - /** - * @hide For testing only. - */ - public void readArrayMap(ArrayMap outVal, ClassLoader loader) { - final int N = readInt(); - if (N < 0) { - return; - } - readArrayMapInternal(outVal, N, loader); - } - - private void readListInternal(List outVal, int N, - ClassLoader loader) { - while (N > 0) { - Object value = readValue(loader); - //Log.d(TAG, "Unmarshalling value=" + value); - outVal.add(value); - N--; - } - } - - private void readArrayInternal(Object[] outVal, int N, - ClassLoader loader) { - for (int i = 0; i < N; i++) { - Object value = readValue(loader); - //Log.d(TAG, "Unmarshalling value=" + value); - outVal[i] = value; - } - } - - private void readSparseArrayInternal(SparseArray outVal, int N, - ClassLoader loader) { - while (N > 0) { - int key = readInt(); - Object value = readValue(loader); - //Log.i(TAG, "Unmarshalling key=" + key + " value=" + value); - outVal.append(key, value); - N--; - } - } - - - private void readSparseBooleanArrayInternal(SparseBooleanArray outVal, int N) { - while (N > 0) { - int key = readInt(); - boolean value = this.readByte() == 1; - //Log.i(TAG, "Unmarshalling key=" + key + " value=" + value); - outVal.append(key, value); - N--; - } - } -} diff --git a/src/main/java/android/os/ParcelArrayBenchmark.java b/src/main/java/android/os/ParcelArrayBenchmark.java deleted file mode 100644 index 21cfb09..0000000 --- a/src/main/java/android/os/ParcelArrayBenchmark.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import com.google.caliper.Param; -import com.google.caliper.SimpleBenchmark; - -public class ParcelArrayBenchmark extends SimpleBenchmark { - - @Param({ "1", "10", "100", "1000" }) - private int mSize; - - private Parcel mWriteParcel; - - private byte[] mByteArray; - private int[] mIntArray; - private long[] mLongArray; - - private Parcel mByteParcel; - private Parcel mIntParcel; - private Parcel mLongParcel; - - @Override - protected void setUp() { - mWriteParcel = Parcel.obtain(); - - mByteArray = new byte[mSize]; - mIntArray = new int[mSize]; - mLongArray = new long[mSize]; - - mByteParcel = Parcel.obtain(); - mByteParcel.writeByteArray(mByteArray); - mIntParcel = Parcel.obtain(); - mIntParcel.writeIntArray(mIntArray); - mLongParcel = Parcel.obtain(); - mLongParcel.writeLongArray(mLongArray); - } - - @Override - protected void tearDown() { - mWriteParcel.recycle(); - mWriteParcel = null; - } - - public void timeWriteByteArray(int reps) { - for (int i = 0; i < reps; i++) { - mWriteParcel.setDataPosition(0); - mWriteParcel.writeByteArray(mByteArray); - } - } - - public void timeCreateByteArray(int reps) { - for (int i = 0; i < reps; i++) { - mByteParcel.setDataPosition(0); - mByteParcel.createByteArray(); - } - } - - public void timeReadByteArray(int reps) { - for (int i = 0; i < reps; i++) { - mByteParcel.setDataPosition(0); - mByteParcel.readByteArray(mByteArray); - } - } - - public void timeWriteIntArray(int reps) { - for (int i = 0; i < reps; i++) { - mWriteParcel.setDataPosition(0); - mWriteParcel.writeIntArray(mIntArray); - } - } - - public void timeCreateIntArray(int reps) { - for (int i = 0; i < reps; i++) { - mIntParcel.setDataPosition(0); - mIntParcel.createIntArray(); - } - } - - public void timeReadIntArray(int reps) { - for (int i = 0; i < reps; i++) { - mIntParcel.setDataPosition(0); - mIntParcel.readIntArray(mIntArray); - } - } - - public void timeWriteLongArray(int reps) { - for (int i = 0; i < reps; i++) { - mWriteParcel.setDataPosition(0); - mWriteParcel.writeLongArray(mLongArray); - } - } - - public void timeCreateLongArray(int reps) { - for (int i = 0; i < reps; i++) { - mLongParcel.setDataPosition(0); - mLongParcel.createLongArray(); - } - } - - public void timeReadLongArray(int reps) { - for (int i = 0; i < reps; i++) { - mLongParcel.setDataPosition(0); - mLongParcel.readLongArray(mLongArray); - } - } - -} diff --git a/src/main/java/android/os/ParcelBenchmark.java b/src/main/java/android/os/ParcelBenchmark.java deleted file mode 100644 index 6a7b7c8..0000000 --- a/src/main/java/android/os/ParcelBenchmark.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import com.google.caliper.SimpleBenchmark; - -public class ParcelBenchmark extends SimpleBenchmark { - - private Parcel mParcel; - - @Override - protected void setUp() { - mParcel = Parcel.obtain(); - } - - @Override - protected void tearDown() { - mParcel.recycle(); - mParcel = null; - } - - public void timeWriteByte(int reps) { - final byte val = 0xF; - for (int i = 0; i < reps; i++) { - mParcel.writeByte(val); - } - } - - public void timeReadByte(int reps) { - mParcel.setDataCapacity(reps); - for (int i = 0; i < reps; i++) { - mParcel.readByte(); - } - } - - public void timeWriteInt(int reps) { - final int val = 0xF; - for (int i = 0; i < reps; i++) { - mParcel.writeInt(val); - } - } - - public void timeReadInt(int reps) { - mParcel.setDataCapacity(reps << 2); - for (int i = 0; i < reps; i++) { - mParcel.readInt(); - } - } - - public void timeWriteLong(int reps) { - final long val = 0xF; - for (int i = 0; i < reps; i++) { - mParcel.writeLong(val); - } - } - - public void timeReadLong(int reps) { - mParcel.setDataCapacity(reps << 3); - for (int i = 0; i < reps; i++) { - mParcel.readLong(); - } - } -} diff --git a/src/main/java/android/os/ParcelFileDescriptor.java b/src/main/java/android/os/ParcelFileDescriptor.java deleted file mode 100644 index c6b2151..0000000 --- a/src/main/java/android/os/ParcelFileDescriptor.java +++ /dev/null @@ -1,1038 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import static android.system.OsConstants.AF_UNIX; -import static android.system.OsConstants.SEEK_SET; -import static android.system.OsConstants.SOCK_STREAM; -import static android.system.OsConstants.S_ISLNK; -import static android.system.OsConstants.S_ISREG; - -import android.content.BroadcastReceiver; -import android.content.ContentProvider; -import android.system.ErrnoException; -import android.system.Os; -import android.system.OsConstants; -import android.system.StructStat; -import android.util.Log; - -import dalvik.system.CloseGuard; - -import libcore.io.IoUtils; -import libcore.io.Memory; - -import java.io.Closeable; -import java.io.File; -import java.io.FileDescriptor; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InterruptedIOException; -import java.net.DatagramSocket; -import java.net.Socket; -import java.nio.ByteOrder; - -/** - * The FileDescriptor returned by {@link Parcel#readFileDescriptor}, allowing - * you to close it when done with it. - */ -public class ParcelFileDescriptor implements Parcelable, Closeable { - private static final String TAG = "ParcelFileDescriptor"; - - private final FileDescriptor mFd; - - /** - * Optional socket used to communicate close events, status at close, and - * detect remote process crashes. - */ - private FileDescriptor mCommFd; - - /** - * Wrapped {@link ParcelFileDescriptor}, if any. Used to avoid - * double-closing {@link #mFd}. - */ - private final ParcelFileDescriptor mWrapped; - - /** - * Maximum {@link #mStatusBuf} size; longer status messages will be - * truncated. - */ - private static final int MAX_STATUS = 1024; - - /** - * Temporary buffer used by {@link #readCommStatus(FileDescriptor, byte[])}, - * allocated on-demand. - */ - private byte[] mStatusBuf; - - /** - * Status read by {@link #checkError()}, or null if not read yet. - */ - private Status mStatus; - - private volatile boolean mClosed; - - private final CloseGuard mGuard = CloseGuard.get(); - - /** - * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied and - * this file doesn't already exist, then create the file with permissions - * such that any application can read it. - * - * @deprecated Creating world-readable files is very dangerous, and likely - * to cause security holes in applications. It is strongly - * discouraged; instead, applications should use more formal - * mechanism for interactions such as {@link ContentProvider}, - * {@link BroadcastReceiver}, and {@link android.app.Service}. - * There are no guarantees that this access mode will remain on - * a file, such as when it goes through a backup and restore. - */ - @Deprecated - public static final int MODE_WORLD_READABLE = 0x00000001; - - /** - * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied and - * this file doesn't already exist, then create the file with permissions - * such that any application can write it. - * - * @deprecated Creating world-writable files is very dangerous, and likely - * to cause security holes in applications. It is strongly - * discouraged; instead, applications should use more formal - * mechanism for interactions such as {@link ContentProvider}, - * {@link BroadcastReceiver}, and {@link android.app.Service}. - * There are no guarantees that this access mode will remain on - * a file, such as when it goes through a backup and restore. - */ - @Deprecated - public static final int MODE_WORLD_WRITEABLE = 0x00000002; - - /** - * For use with {@link #open}: open the file with read-only access. - */ - public static final int MODE_READ_ONLY = 0x10000000; - - /** - * For use with {@link #open}: open the file with write-only access. - */ - public static final int MODE_WRITE_ONLY = 0x20000000; - - /** - * For use with {@link #open}: open the file with read and write access. - */ - public static final int MODE_READ_WRITE = 0x30000000; - - /** - * For use with {@link #open}: create the file if it doesn't already exist. - */ - public static final int MODE_CREATE = 0x08000000; - - /** - * For use with {@link #open}: erase contents of file when opening. - */ - public static final int MODE_TRUNCATE = 0x04000000; - - /** - * For use with {@link #open}: append to end of file while writing. - */ - public static final int MODE_APPEND = 0x02000000; - - /** - * Create a new ParcelFileDescriptor wrapped around another descriptor. By - * default all method calls are delegated to the wrapped descriptor. - */ - public ParcelFileDescriptor(ParcelFileDescriptor wrapped) { - // We keep a strong reference to the wrapped PFD, and rely on its - // finalizer to trigger CloseGuard. All calls are delegated to wrapper. - mWrapped = wrapped; - mFd = null; - mCommFd = null; - mClosed = true; - } - - /** {@hide} */ - public ParcelFileDescriptor(FileDescriptor fd) { - this(fd, null); - } - - /** {@hide} */ - public ParcelFileDescriptor(FileDescriptor fd, FileDescriptor commChannel) { - if (fd == null) { - throw new NullPointerException("FileDescriptor must not be null"); - } - mWrapped = null; - mFd = fd; - mCommFd = commChannel; - mGuard.open("close"); - } - - /** - * Create a new ParcelFileDescriptor accessing a given file. - * - * @param file The file to be opened. - * @param mode The desired access mode, must be one of - * {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or - * {@link #MODE_READ_WRITE}; may also be any combination of - * {@link #MODE_CREATE}, {@link #MODE_TRUNCATE}, - * {@link #MODE_WORLD_READABLE}, and - * {@link #MODE_WORLD_WRITEABLE}. - * @return a new ParcelFileDescriptor pointing to the given file. - * @throws FileNotFoundException if the given file does not exist or can not - * be opened with the requested mode. - * @see #parseMode(String) - */ - public static ParcelFileDescriptor open(File file, int mode) throws FileNotFoundException { - final FileDescriptor fd = openInternal(file, mode); - if (fd == null) return null; - - return new ParcelFileDescriptor(fd); - } - - /** - * Create a new ParcelFileDescriptor accessing a given file. - * - * @param file The file to be opened. - * @param mode The desired access mode, must be one of - * {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or - * {@link #MODE_READ_WRITE}; may also be any combination of - * {@link #MODE_CREATE}, {@link #MODE_TRUNCATE}, - * {@link #MODE_WORLD_READABLE}, and - * {@link #MODE_WORLD_WRITEABLE}. - * @param handler to call listener from; must not be null. - * @param listener to be invoked when the returned descriptor has been - * closed; must not be null. - * @return a new ParcelFileDescriptor pointing to the given file. - * @throws FileNotFoundException if the given file does not exist or can not - * be opened with the requested mode. - * @see #parseMode(String) - */ - public static ParcelFileDescriptor open( - File file, int mode, Handler handler, OnCloseListener listener) throws IOException { - if (handler == null) { - throw new IllegalArgumentException("Handler must not be null"); - } - if (listener == null) { - throw new IllegalArgumentException("Listener must not be null"); - } - - final FileDescriptor fd = openInternal(file, mode); - if (fd == null) return null; - - final FileDescriptor[] comm = createCommSocketPair(); - final ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd, comm[0]); - - // Kick off thread to watch for status updates - IoUtils.setBlocking(comm[1], true); - final ListenerBridge bridge = new ListenerBridge(comm[1], handler.getLooper(), listener); - bridge.start(); - - return pfd; - } - - private static FileDescriptor openInternal(File file, int mode) throws FileNotFoundException { - if ((mode & MODE_READ_WRITE) == 0) { - throw new IllegalArgumentException( - "Must specify MODE_READ_ONLY, MODE_WRITE_ONLY, or MODE_READ_WRITE"); - } - - final String path = file.getPath(); - return Parcel.openFileDescriptor(path, mode); - } - - /** - * Create a new ParcelFileDescriptor that is a dup of an existing - * FileDescriptor. This obeys standard POSIX semantics, where the - * new file descriptor shared state such as file position with the - * original file descriptor. - */ - public static ParcelFileDescriptor dup(FileDescriptor orig) throws IOException { - try { - final FileDescriptor fd = Os.dup(orig); - return new ParcelFileDescriptor(fd); - } catch (ErrnoException e) { - throw e.rethrowAsIOException(); - } - } - - /** - * Create a new ParcelFileDescriptor that is a dup of the existing - * FileDescriptor. This obeys standard POSIX semantics, where the - * new file descriptor shared state such as file position with the - * original file descriptor. - */ - public ParcelFileDescriptor dup() throws IOException { - if (mWrapped != null) { - return mWrapped.dup(); - } else { - return dup(getFileDescriptor()); - } - } - - /** - * Create a new ParcelFileDescriptor from a raw native fd. The new - * ParcelFileDescriptor holds a dup of the original fd passed in here, - * so you must still close that fd as well as the new ParcelFileDescriptor. - * - * @param fd The native fd that the ParcelFileDescriptor should dup. - * - * @return Returns a new ParcelFileDescriptor holding a FileDescriptor - * for a dup of the given fd. - */ - public static ParcelFileDescriptor fromFd(int fd) throws IOException { - final FileDescriptor original = new FileDescriptor(); - original.setInt$(fd); - - try { - final FileDescriptor dup = Os.dup(original); - return new ParcelFileDescriptor(dup); - } catch (ErrnoException e) { - throw e.rethrowAsIOException(); - } - } - - /** - * Take ownership of a raw native fd in to a new ParcelFileDescriptor. - * The returned ParcelFileDescriptor now owns the given fd, and will be - * responsible for closing it. You must not close the fd yourself. - * - * @param fd The native fd that the ParcelFileDescriptor should adopt. - * - * @return Returns a new ParcelFileDescriptor holding a FileDescriptor - * for the given fd. - */ - public static ParcelFileDescriptor adoptFd(int fd) { - final FileDescriptor fdesc = new FileDescriptor(); - fdesc.setInt$(fd); - - return new ParcelFileDescriptor(fdesc); - } - - /** - * Create a new ParcelFileDescriptor from the specified Socket. The new - * ParcelFileDescriptor holds a dup of the original FileDescriptor in - * the Socket, so you must still close the Socket as well as the new - * ParcelFileDescriptor. - * - * @param socket The Socket whose FileDescriptor is used to create - * a new ParcelFileDescriptor. - * - * @return A new ParcelFileDescriptor with the FileDescriptor of the - * specified Socket. - */ - public static ParcelFileDescriptor fromSocket(Socket socket) { - FileDescriptor fd = socket.getFileDescriptor$(); - return fd != null ? new ParcelFileDescriptor(fd) : null; - } - - /** - * Create a new ParcelFileDescriptor from the specified DatagramSocket. - * - * @param datagramSocket The DatagramSocket whose FileDescriptor is used - * to create a new ParcelFileDescriptor. - * - * @return A new ParcelFileDescriptor with the FileDescriptor of the - * specified DatagramSocket. - */ - public static ParcelFileDescriptor fromDatagramSocket(DatagramSocket datagramSocket) { - FileDescriptor fd = datagramSocket.getFileDescriptor$(); - return fd != null ? new ParcelFileDescriptor(fd) : null; - } - - /** - * Create two ParcelFileDescriptors structured as a data pipe. The first - * ParcelFileDescriptor in the returned array is the read side; the second - * is the write side. - */ - public static ParcelFileDescriptor[] createPipe() throws IOException { - try { - final FileDescriptor[] fds = Os.pipe(); - return new ParcelFileDescriptor[] { - new ParcelFileDescriptor(fds[0]), - new ParcelFileDescriptor(fds[1]) }; - } catch (ErrnoException e) { - throw e.rethrowAsIOException(); - } - } - - /** - * Create two ParcelFileDescriptors structured as a data pipe. The first - * ParcelFileDescriptor in the returned array is the read side; the second - * is the write side. - *

    - * The write end has the ability to deliver an error message through - * {@link #closeWithError(String)} which can be handled by the read end - * calling {@link #checkError()}, usually after detecting an EOF. - * This can also be used to detect remote crashes. - */ - public static ParcelFileDescriptor[] createReliablePipe() throws IOException { - try { - final FileDescriptor[] comm = createCommSocketPair(); - final FileDescriptor[] fds = Os.pipe(); - return new ParcelFileDescriptor[] { - new ParcelFileDescriptor(fds[0], comm[0]), - new ParcelFileDescriptor(fds[1], comm[1]) }; - } catch (ErrnoException e) { - throw e.rethrowAsIOException(); - } - } - - /** - * Create two ParcelFileDescriptors structured as a pair of sockets - * connected to each other. The two sockets are indistinguishable. - */ - public static ParcelFileDescriptor[] createSocketPair() throws IOException { - try { - final FileDescriptor fd0 = new FileDescriptor(); - final FileDescriptor fd1 = new FileDescriptor(); - Os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd0, fd1); - return new ParcelFileDescriptor[] { - new ParcelFileDescriptor(fd0), - new ParcelFileDescriptor(fd1) }; - } catch (ErrnoException e) { - throw e.rethrowAsIOException(); - } - } - - /** - * Create two ParcelFileDescriptors structured as a pair of sockets - * connected to each other. The two sockets are indistinguishable. - *

    - * Both ends have the ability to deliver an error message through - * {@link #closeWithError(String)} which can be detected by the other end - * calling {@link #checkError()}, usually after detecting an EOF. - * This can also be used to detect remote crashes. - */ - public static ParcelFileDescriptor[] createReliableSocketPair() throws IOException { - try { - final FileDescriptor[] comm = createCommSocketPair(); - final FileDescriptor fd0 = new FileDescriptor(); - final FileDescriptor fd1 = new FileDescriptor(); - Os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd0, fd1); - return new ParcelFileDescriptor[] { - new ParcelFileDescriptor(fd0, comm[0]), - new ParcelFileDescriptor(fd1, comm[1]) }; - } catch (ErrnoException e) { - throw e.rethrowAsIOException(); - } - } - - private static FileDescriptor[] createCommSocketPair() throws IOException { - try { - final FileDescriptor comm1 = new FileDescriptor(); - final FileDescriptor comm2 = new FileDescriptor(); - Os.socketpair(AF_UNIX, SOCK_STREAM, 0, comm1, comm2); - IoUtils.setBlocking(comm1, false); - IoUtils.setBlocking(comm2, false); - return new FileDescriptor[] { comm1, comm2 }; - } catch (ErrnoException e) { - throw e.rethrowAsIOException(); - } - } - - /** - * @hide Please use createPipe() or ContentProvider.openPipeHelper(). - * Gets a file descriptor for a read-only copy of the given data. - * - * @param data Data to copy. - * @param name Name for the shared memory area that may back the file descriptor. - * This is purely informative and may be {@code null}. - * @return A ParcelFileDescriptor. - * @throws IOException if there is an error while creating the shared memory area. - */ - @Deprecated - public static ParcelFileDescriptor fromData(byte[] data, String name) throws IOException { - if (data == null) return null; - MemoryFile file = new MemoryFile(name, data.length); - if (data.length > 0) { - file.writeBytes(data, 0, 0, data.length); - } - file.deactivate(); - FileDescriptor fd = file.getFileDescriptor(); - return fd != null ? new ParcelFileDescriptor(fd) : null; - } - - /** - * Converts a string representing a file mode, such as "rw", into a bitmask suitable for use - * with {@link #open}. - *

    - * @param mode The string representation of the file mode. - * @return A bitmask representing the given file mode. - * @throws IllegalArgumentException if the given string does not match a known file mode. - */ - public static int parseMode(String mode) { - final int modeBits; - if ("r".equals(mode)) { - modeBits = ParcelFileDescriptor.MODE_READ_ONLY; - } else if ("w".equals(mode) || "wt".equals(mode)) { - modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY - | ParcelFileDescriptor.MODE_CREATE - | ParcelFileDescriptor.MODE_TRUNCATE; - } else if ("wa".equals(mode)) { - modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY - | ParcelFileDescriptor.MODE_CREATE - | ParcelFileDescriptor.MODE_APPEND; - } else if ("rw".equals(mode)) { - modeBits = ParcelFileDescriptor.MODE_READ_WRITE - | ParcelFileDescriptor.MODE_CREATE; - } else if ("rwt".equals(mode)) { - modeBits = ParcelFileDescriptor.MODE_READ_WRITE - | ParcelFileDescriptor.MODE_CREATE - | ParcelFileDescriptor.MODE_TRUNCATE; - } else { - throw new IllegalArgumentException("Bad mode '" + mode + "'"); - } - return modeBits; - } - - /** - * Retrieve the actual FileDescriptor associated with this object. - * - * @return Returns the FileDescriptor associated with this object. - */ - public FileDescriptor getFileDescriptor() { - if (mWrapped != null) { - return mWrapped.getFileDescriptor(); - } else { - return mFd; - } - } - - /** - * Return the total size of the file representing this fd, as determined by - * {@code stat()}. Returns -1 if the fd is not a file. - */ - public long getStatSize() { - if (mWrapped != null) { - return mWrapped.getStatSize(); - } else { - try { - final StructStat st = Os.fstat(mFd); - if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { - return st.st_size; - } else { - return -1; - } - } catch (ErrnoException e) { - Log.w(TAG, "fstat() failed: " + e); - return -1; - } - } - } - - /** - * This is needed for implementing AssetFileDescriptor.AutoCloseOutputStream, - * and I really don't think we want it to be public. - * @hide - */ - public long seekTo(long pos) throws IOException { - if (mWrapped != null) { - return mWrapped.seekTo(pos); - } else { - try { - return Os.lseek(mFd, pos, SEEK_SET); - } catch (ErrnoException e) { - throw e.rethrowAsIOException(); - } - } - } - - /** - * Return the native fd int for this ParcelFileDescriptor. The - * ParcelFileDescriptor still owns the fd, and it still must be closed - * through this API. - */ - public int getFd() { - if (mWrapped != null) { - return mWrapped.getFd(); - } else { - if (mClosed) { - throw new IllegalStateException("Already closed"); - } - return mFd.getInt$(); - } - } - - /** - * Return the native fd int for this ParcelFileDescriptor and detach it from - * the object here. You are now responsible for closing the fd in native - * code. - *

    - * You should not detach when the original creator of the descriptor is - * expecting a reliable signal through {@link #close()} or - * {@link #closeWithError(String)}. - * - * @see #canDetectErrors() - */ - public int detachFd() { - if (mWrapped != null) { - return mWrapped.detachFd(); - } else { - if (mClosed) { - throw new IllegalStateException("Already closed"); - } - final int fd = getFd(); - Parcel.clearFileDescriptor(mFd); - writeCommStatusAndClose(Status.DETACHED, null); - return fd; - } - } - - /** - * Close the ParcelFileDescriptor. This implementation closes the underlying - * OS resources allocated to represent this stream. - * - * @throws IOException - * If an error occurs attempting to close this ParcelFileDescriptor. - */ - @Override - public void close() throws IOException { - if (mWrapped != null) { - try { - mWrapped.close(); - } finally { - releaseResources(); - } - } else { - closeWithStatus(Status.OK, null); - } - } - - /** - * Close the ParcelFileDescriptor, informing any peer that an error occurred - * while processing. If the creator of this descriptor is not observing - * errors, it will close normally. - * - * @param msg describing the error; must not be null. - */ - public void closeWithError(String msg) throws IOException { - if (mWrapped != null) { - try { - mWrapped.closeWithError(msg); - } finally { - releaseResources(); - } - } else { - if (msg == null) { - throw new IllegalArgumentException("Message must not be null"); - } - closeWithStatus(Status.ERROR, msg); - } - } - - private void closeWithStatus(int status, String msg) { - if (mClosed) return; - mClosed = true; - mGuard.close(); - // Status MUST be sent before closing actual descriptor - writeCommStatusAndClose(status, msg); - IoUtils.closeQuietly(mFd); - releaseResources(); - } - - /** - * Called when the fd is being closed, for subclasses to release any other resources - * associated with it, such as acquired providers. - * @hide - */ - public void releaseResources() { - } - - private byte[] getOrCreateStatusBuffer() { - if (mStatusBuf == null) { - mStatusBuf = new byte[MAX_STATUS]; - } - return mStatusBuf; - } - - private void writeCommStatusAndClose(int status, String msg) { - if (mCommFd == null) { - // Not reliable, or someone already sent status - if (msg != null) { - Log.w(TAG, "Unable to inform peer: " + msg); - } - return; - } - - if (status == Status.DETACHED) { - Log.w(TAG, "Peer expected signal when closed; unable to deliver after detach"); - } - - try { - if (status == Status.SILENCE) return; - - // Since we're about to close, read off any remote status. It's - // okay to remember missing here. - mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer()); - - // Skip writing status when other end has already gone away. - if (mStatus != null) return; - - try { - final byte[] buf = getOrCreateStatusBuffer(); - int writePtr = 0; - - Memory.pokeInt(buf, writePtr, status, ByteOrder.BIG_ENDIAN); - writePtr += 4; - - if (msg != null) { - final byte[] rawMsg = msg.getBytes(); - final int len = Math.min(rawMsg.length, buf.length - writePtr); - System.arraycopy(rawMsg, 0, buf, writePtr, len); - writePtr += len; - } - - Os.write(mCommFd, buf, 0, writePtr); - } catch (ErrnoException e) { - // Reporting status is best-effort - Log.w(TAG, "Failed to report status: " + e); - } catch (InterruptedIOException e) { - // Reporting status is best-effort - Log.w(TAG, "Failed to report status: " + e); - } - - } finally { - IoUtils.closeQuietly(mCommFd); - mCommFd = null; - } - } - - private static Status readCommStatus(FileDescriptor comm, byte[] buf) { - try { - final int n = Os.read(comm, buf, 0, buf.length); - if (n == 0) { - // EOF means they're dead - return new Status(Status.DEAD); - } else { - final int status = Memory.peekInt(buf, 0, ByteOrder.BIG_ENDIAN); - if (status == Status.ERROR) { - final String msg = new String(buf, 4, n - 4); - return new Status(status, msg); - } - return new Status(status); - } - } catch (ErrnoException e) { - if (e.errno == OsConstants.EAGAIN) { - // Remote is still alive, but no status written yet - return null; - } else { - Log.d(TAG, "Failed to read status; assuming dead: " + e); - return new Status(Status.DEAD); - } - } catch (InterruptedIOException e) { - Log.d(TAG, "Failed to read status; assuming dead: " + e); - return new Status(Status.DEAD); - } - } - - /** - * Indicates if this ParcelFileDescriptor can communicate and detect remote - * errors/crashes. - * - * @see #checkError() - */ - public boolean canDetectErrors() { - if (mWrapped != null) { - return mWrapped.canDetectErrors(); - } else { - return mCommFd != null; - } - } - - /** - * Detect and throw if the other end of a pipe or socket pair encountered an - * error or crashed. This allows a reader to distinguish between a valid EOF - * and an error/crash. - *

    - * If this ParcelFileDescriptor is unable to detect remote errors, it will - * return silently. - * - * @throws IOException for normal errors. - * @throws FileDescriptorDetachedException - * if the remote side called {@link #detachFd()}. Once detached, the remote - * side is unable to communicate any errors through - * {@link #closeWithError(String)}. - * @see #canDetectErrors() - */ - public void checkError() throws IOException { - if (mWrapped != null) { - mWrapped.checkError(); - } else { - if (mStatus == null) { - if (mCommFd == null) { - Log.w(TAG, "Peer didn't provide a comm channel; unable to check for errors"); - return; - } - - // Try reading status; it might be null if nothing written yet. - // Either way, we keep comm open to write our status later. - mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer()); - } - - if (mStatus == null || mStatus.status == Status.OK) { - // No status yet, or everything is peachy! - return; - } else { - throw mStatus.asIOException(); - } - } - } - - /** - * An InputStream you can create on a ParcelFileDescriptor, which will - * take care of calling {@link ParcelFileDescriptor#close - * ParcelFileDescriptor.close()} for you when the stream is closed. - */ - public static class AutoCloseInputStream extends FileInputStream { - private final ParcelFileDescriptor mPfd; - - public AutoCloseInputStream(ParcelFileDescriptor pfd) { - super(pfd.getFileDescriptor()); - mPfd = pfd; - } - - @Override - public void close() throws IOException { - try { - mPfd.close(); - } finally { - super.close(); - } - } - } - - /** - * An OutputStream you can create on a ParcelFileDescriptor, which will - * take care of calling {@link ParcelFileDescriptor#close - * ParcelFileDescriptor.close()} for you when the stream is closed. - */ - public static class AutoCloseOutputStream extends FileOutputStream { - private final ParcelFileDescriptor mPfd; - - public AutoCloseOutputStream(ParcelFileDescriptor pfd) { - super(pfd.getFileDescriptor()); - mPfd = pfd; - } - - @Override - public void close() throws IOException { - try { - mPfd.close(); - } finally { - super.close(); - } - } - } - - @Override - public String toString() { - if (mWrapped != null) { - return mWrapped.toString(); - } else { - return "{ParcelFileDescriptor: " + mFd + "}"; - } - } - - @Override - protected void finalize() throws Throwable { - if (mWrapped != null) { - releaseResources(); - } - if (mGuard != null) { - mGuard.warnIfOpen(); - } - try { - if (!mClosed) { - closeWithStatus(Status.LEAKED, null); - } - } finally { - super.finalize(); - } - } - - @Override - public int describeContents() { - if (mWrapped != null) { - return mWrapped.describeContents(); - } else { - return Parcelable.CONTENTS_FILE_DESCRIPTOR; - } - } - - /** - * {@inheritDoc} - * If {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set in flags, - * the file descriptor will be closed after a copy is written to the Parcel. - */ - @Override - public void writeToParcel(Parcel out, int flags) { - // WARNING: This must stay in sync with Parcel::readParcelFileDescriptor() - // in frameworks/native/libs/binder/Parcel.cpp - if (mWrapped != null) { - try { - mWrapped.writeToParcel(out, flags); - } finally { - releaseResources(); - } - } else { - out.writeFileDescriptor(mFd); - if (mCommFd != null) { - out.writeInt(1); - out.writeFileDescriptor(mCommFd); - } else { - out.writeInt(0); - } - if ((flags & PARCELABLE_WRITE_RETURN_VALUE) != 0 && !mClosed) { - // Not a real close, so emit no status - closeWithStatus(Status.SILENCE, null); - } - } - } - - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - @Override - public ParcelFileDescriptor createFromParcel(Parcel in) { - // WARNING: This must stay in sync with Parcel::writeParcelFileDescriptor() - // in frameworks/native/libs/binder/Parcel.cpp - final FileDescriptor fd = in.readRawFileDescriptor(); - FileDescriptor commChannel = null; - if (in.readInt() != 0) { - commChannel = in.readRawFileDescriptor(); - } - return new ParcelFileDescriptor(fd, commChannel); - } - - @Override - public ParcelFileDescriptor[] newArray(int size) { - return new ParcelFileDescriptor[size]; - } - }; - - /** - * Callback indicating that a ParcelFileDescriptor has been closed. - */ - public interface OnCloseListener { - /** - * Event indicating the ParcelFileDescriptor to which this listener was - * attached has been closed. - * - * @param e error state, or {@code null} if closed cleanly. - * If the close event was the result of - * {@link ParcelFileDescriptor#detachFd()}, this will be a - * {@link FileDescriptorDetachedException}. After detach the - * remote side may continue reading/writing to the underlying - * {@link FileDescriptor}, but they can no longer deliver - * reliable close/error events. - */ - public void onClose(IOException e); - } - - /** - * Exception that indicates that the file descriptor was detached. - */ - public static class FileDescriptorDetachedException extends IOException { - - private static final long serialVersionUID = 0xDe7ac4edFdL; - - public FileDescriptorDetachedException() { - super("Remote side is detached"); - } - } - - /** - * Internal class representing a remote status read by - * {@link ParcelFileDescriptor#readCommStatus(FileDescriptor, byte[])}. - */ - private static class Status { - /** Special value indicating remote side died. */ - public static final int DEAD = -2; - /** Special value indicating no status should be written. */ - public static final int SILENCE = -1; - - /** Remote reported that everything went better than expected. */ - public static final int OK = 0; - /** Remote reported error; length and message follow. */ - public static final int ERROR = 1; - /** Remote reported {@link #detachFd()} and went rogue. */ - public static final int DETACHED = 2; - /** Remote reported their object was finalized. */ - public static final int LEAKED = 3; - - public final int status; - public final String msg; - - public Status(int status) { - this(status, null); - } - - public Status(int status, String msg) { - this.status = status; - this.msg = msg; - } - - public IOException asIOException() { - switch (status) { - case DEAD: - return new IOException("Remote side is dead"); - case OK: - return null; - case ERROR: - return new IOException("Remote error: " + msg); - case DETACHED: - return new FileDescriptorDetachedException(); - case LEAKED: - return new IOException("Remote side was leaked"); - default: - return new IOException("Unknown status: " + status); - } - } - } - - /** - * Bridge to watch for remote status, and deliver to listener. Currently - * requires that communication socket is blocking. - */ - private static final class ListenerBridge extends Thread { - // TODO: switch to using Looper to avoid burning a thread - - private FileDescriptor mCommFd; - private final Handler mHandler; - - public ListenerBridge(FileDescriptor comm, Looper looper, final OnCloseListener listener) { - mCommFd = comm; - mHandler = new Handler(looper) { - @Override - public void handleMessage(Message msg) { - final Status s = (Status) msg.obj; - listener.onClose(s != null ? s.asIOException() : null); - } - }; - } - - @Override - public void run() { - try { - final byte[] buf = new byte[MAX_STATUS]; - final Status status = readCommStatus(mCommFd, buf); - mHandler.obtainMessage(0, status).sendToTarget(); - } finally { - IoUtils.closeQuietly(mCommFd); - mCommFd = null; - } - } - } -} diff --git a/src/main/java/android/os/ParcelFormatException.java b/src/main/java/android/os/ParcelFormatException.java deleted file mode 100644 index 8b6fda0..0000000 --- a/src/main/java/android/os/ParcelFormatException.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -/** - * The contents of a Parcel (usually during unmarshalling) does not - * contain the expected data. - */ -public class ParcelFormatException extends RuntimeException { - public ParcelFormatException() { - super(); - } - - public ParcelFormatException(String reason) { - super(reason); - } -} diff --git a/src/main/java/android/os/ParcelUuid.java b/src/main/java/android/os/ParcelUuid.java deleted file mode 100644 index 2c68ddd..0000000 --- a/src/main/java/android/os/ParcelUuid.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import java.util.UUID; - -/** - * This class is a Parcelable wrapper around {@link UUID} which is an - * immutable representation of a 128-bit universally unique - * identifier. - */ -public final class ParcelUuid implements Parcelable { - - private final UUID mUuid; - - /** - * Constructor creates a ParcelUuid instance from the - * given {@link UUID}. - * - * @param uuid UUID - */ - public ParcelUuid(UUID uuid) { - mUuid = uuid; - } - - /** - * Creates a new ParcelUuid from a string representation of {@link UUID}. - * - * @param uuid - * the UUID string to parse. - * @return a ParcelUuid instance. - * @throws NullPointerException - * if {@code uuid} is {@code null}. - * @throws IllegalArgumentException - * if {@code uuid} is not formatted correctly. - */ - public static ParcelUuid fromString(String uuid) { - return new ParcelUuid(UUID.fromString(uuid)); - } - - /** - * Get the {@link UUID} represented by the ParcelUuid. - * - * @return UUID contained in the ParcelUuid. - */ - public UUID getUuid() { - return mUuid; - } - - /** - * Returns a string representation of the ParcelUuid - * For example: 0000110B-0000-1000-8000-00805F9B34FB will be the return value. - * - * @return a String instance. - */ - @Override - public String toString() { - return mUuid.toString(); - } - - - @Override - public int hashCode() { - return mUuid.hashCode(); - } - - /** - * Compares this ParcelUuid to another object for equality. If {@code object} - * is not {@code null}, is a ParcelUuid instance, and all bits are equal, then - * {@code true} is returned. - * - * @param object - * the {@code Object} to compare to. - * @return {@code true} if this ParcelUuid is equal to {@code object} - * or {@code false} if not. - */ - @Override - public boolean equals(Object object) { - if (object == null) { - return false; - } - - if (this == object) { - return true; - } - - if (!(object instanceof ParcelUuid)) { - return false; - } - - ParcelUuid that = (ParcelUuid) object; - - return (this.mUuid.equals(that.mUuid)); - } - - public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public ParcelUuid createFromParcel(Parcel source) { - long mostSigBits = source.readLong(); - long leastSigBits = source.readLong(); - UUID uuid = new UUID(mostSigBits, leastSigBits); - return new ParcelUuid(uuid); - } - - public ParcelUuid[] newArray(int size) { - return new ParcelUuid[size]; - } - }; - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - dest.writeLong(mUuid.getMostSignificantBits()); - dest.writeLong(mUuid.getLeastSignificantBits()); - } -} diff --git a/src/main/java/android/os/Parcelable.java b/src/main/java/android/os/Parcelable.java deleted file mode 100644 index 594fbb2..0000000 --- a/src/main/java/android/os/Parcelable.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -/** - * Interface for classes whose instances can be written to - * and restored from a {@link Parcel}. Classes implementing the Parcelable - * interface must also have a static field called CREATOR, which - * is an object implementing the {@link Parcelable.Creator Parcelable.Creator} - * interface. - * - *

    A typical implementation of Parcelable is:

    - * - *
    - * public class MyParcelable implements Parcelable {
    - *     private int mData;
    - *
    - *     public int describeContents() {
    - *         return 0;
    - *     }
    - *
    - *     public void writeToParcel(Parcel out, int flags) {
    - *         out.writeInt(mData);
    - *     }
    - *
    - *     public static final Parcelable.Creator<MyParcelable> CREATOR
    - *             = new Parcelable.Creator<MyParcelable>() {
    - *         public MyParcelable createFromParcel(Parcel in) {
    - *             return new MyParcelable(in);
    - *         }
    - *
    - *         public MyParcelable[] newArray(int size) {
    - *             return new MyParcelable[size];
    - *         }
    - *     };
    - *     
    - *     private MyParcelable(Parcel in) {
    - *         mData = in.readInt();
    - *     }
    - * }
    - */ -public interface Parcelable { - /** - * Flag for use with {@link #writeToParcel}: the object being written - * is a return value, that is the result of a function such as - * "Parcelable someFunction()", - * "void someFunction(out Parcelable)", or - * "void someFunction(inout Parcelable)". Some implementations - * may want to release resources at this point. - */ - public static final int PARCELABLE_WRITE_RETURN_VALUE = 0x0001; - - /** - * Bit masks for use with {@link #describeContents}: each bit represents a - * kind of object considered to have potential special significance when - * marshalled. - */ - public static final int CONTENTS_FILE_DESCRIPTOR = 0x0001; - - /** - * Describe the kinds of special objects contained in this Parcelable's - * marshalled representation. - * - * @return a bitmask indicating the set of special object types marshalled - * by the Parcelable. - */ - public int describeContents(); - - /** - * Flatten this object in to a Parcel. - * - * @param dest The Parcel in which the object should be written. - * @param flags Additional flags about how the object should be written. - * May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}. - */ - public void writeToParcel(Parcel dest, int flags); - - /** - * Interface that must be implemented and provided as a public CREATOR - * field that generates instances of your Parcelable class from a Parcel. - */ - public interface Creator { - /** - * Create a new instance of the Parcelable class, instantiating it - * from the given Parcel whose data had previously been written by - * {@link Parcelable#writeToParcel Parcelable.writeToParcel()}. - * - * @param source The Parcel to read the object's data from. - * @return Returns a new instance of the Parcelable class. - */ - public T createFromParcel(Parcel source); - - /** - * Create a new array of the Parcelable class. - * - * @param size Size of the array. - * @return Returns an array of the Parcelable class, with every entry - * initialized to null. - */ - public T[] newArray(int size); - } - - /** - * Specialization of {@link Creator} that allows you to receive the - * ClassLoader the object is being created in. - */ - public interface ClassLoaderCreator extends Creator { - /** - * Create a new instance of the Parcelable class, instantiating it - * from the given Parcel whose data had previously been written by - * {@link Parcelable#writeToParcel Parcelable.writeToParcel()} and - * using the given ClassLoader. - * - * @param source The Parcel to read the object's data from. - * @param loader The ClassLoader that this object is being created in. - * @return Returns a new instance of the Parcelable class. - */ - public T createFromParcel(Parcel source, ClassLoader loader); - } -} diff --git a/src/main/java/android/os/ParcelableParcel.java b/src/main/java/android/os/ParcelableParcel.java deleted file mode 100644 index 11785f1..0000000 --- a/src/main/java/android/os/ParcelableParcel.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -/** - * Parcelable containing a raw Parcel of data. - * @hide - */ -public class ParcelableParcel implements Parcelable { - final Parcel mParcel; - final ClassLoader mClassLoader; - - public ParcelableParcel(ClassLoader loader) { - mParcel = Parcel.obtain(); - mClassLoader = loader; - } - - public ParcelableParcel(Parcel src, ClassLoader loader) { - mParcel = Parcel.obtain(); - mClassLoader = loader; - int size = src.readInt(); - int pos = src.dataPosition(); - mParcel.appendFrom(src, src.dataPosition(), size); - src.setDataPosition(pos + size); - } - - public Parcel getParcel() { - mParcel.setDataPosition(0); - return mParcel; - } - - public ClassLoader getClassLoader() { - return mClassLoader; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mParcel.dataSize()); - dest.appendFrom(mParcel, 0, mParcel.dataSize()); - } - - public static final Parcelable.ClassLoaderCreator CREATOR - = new Parcelable.ClassLoaderCreator() { - public ParcelableParcel createFromParcel(Parcel in) { - return new ParcelableParcel(in, null); - } - - public ParcelableParcel createFromParcel(Parcel in, ClassLoader loader) { - return new ParcelableParcel(in, loader); - } - - public ParcelableParcel[] newArray(int size) { - return new ParcelableParcel[size]; - } - }; -} diff --git a/src/main/java/android/os/PatternMatcher.java b/src/main/java/android/os/PatternMatcher.java deleted file mode 100644 index 56dc837..0000000 --- a/src/main/java/android/os/PatternMatcher.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -/** - * A simple pattern matcher, which is safe to use on untrusted data: it does - * not provide full reg-exp support, only simple globbing that can not be - * used maliciously. - */ -public class PatternMatcher implements Parcelable { - /** - * Pattern type: the given pattern must exactly match the string it is - * tested against. - */ - public static final int PATTERN_LITERAL = 0; - - /** - * Pattern type: the given pattern must match the - * beginning of the string it is tested against. - */ - public static final int PATTERN_PREFIX = 1; - - /** - * Pattern type: the given pattern is interpreted with a - * simple glob syntax for matching against the string it is tested against. - * In this syntax, you can use the '*' character to match against zero or - * more occurrences of the character immediately before. If the - * character before it is '.' it will match any character. The character - * '\' can be used as an escape. This essentially provides only the '*' - * wildcard part of a normal regexp. - */ - public static final int PATTERN_SIMPLE_GLOB = 2; - - private final String mPattern; - private final int mType; - - public PatternMatcher(String pattern, int type) { - mPattern = pattern; - mType = type; - } - - public final String getPath() { - return mPattern; - } - - public final int getType() { - return mType; - } - - public boolean match(String str) { - return matchPattern(mPattern, str, mType); - } - - public String toString() { - String type = "? "; - switch (mType) { - case PATTERN_LITERAL: - type = "LITERAL: "; - break; - case PATTERN_PREFIX: - type = "PREFIX: "; - break; - case PATTERN_SIMPLE_GLOB: - type = "GLOB: "; - break; - } - return "PatternMatcher{" + type + mPattern + "}"; - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mPattern); - dest.writeInt(mType); - } - - public PatternMatcher(Parcel src) { - mPattern = src.readString(); - mType = src.readInt(); - } - - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - public PatternMatcher createFromParcel(Parcel source) { - return new PatternMatcher(source); - } - - public PatternMatcher[] newArray(int size) { - return new PatternMatcher[size]; - } - }; - - static boolean matchPattern(String pattern, String match, int type) { - if (match == null) return false; - if (type == PATTERN_LITERAL) { - return pattern.equals(match); - } if (type == PATTERN_PREFIX) { - return match.startsWith(pattern); - } else if (type != PATTERN_SIMPLE_GLOB) { - return false; - } - - final int NP = pattern.length(); - if (NP <= 0) { - return match.length() <= 0; - } - final int NM = match.length(); - int ip = 0, im = 0; - char nextChar = pattern.charAt(0); - while ((ip= (NP-1)) { - // at the end with a pattern match, so - // all is good without checking! - return true; - } - ip++; - nextChar = pattern.charAt(ip); - // Consume everything until the next character in the - // pattern is found. - if (nextChar == '\\') { - ip++; - nextChar = ip < NP ? pattern.charAt(ip) : 0; - } - do { - if (match.charAt(im) == nextChar) { - break; - } - im++; - } while (im < NM); - if (im == NM) { - // Whoops, the next character in the pattern didn't - // exist in the match. - return false; - } - ip++; - nextChar = ip < NP ? pattern.charAt(ip) : 0; - im++; - } else { - // Consume only characters matching the one before '*'. - do { - if (match.charAt(im) != c) { - break; - } - im++; - } while (im < NM); - ip++; - nextChar = ip < NP ? pattern.charAt(ip) : 0; - } - } else { - if (c != '.' && match.charAt(im) != c) return false; - im++; - } - } - - if (ip >= NP && im >= NM) { - // Reached the end of both strings, all is good! - return true; - } - - // One last check: we may have finished the match string, but still - // have a '.*' at the end of the pattern, which should still count - // as a match. - if (ip == NP-2 && pattern.charAt(ip) == '.' - && pattern.charAt(ip+1) == '*') { - return true; - } - - return false; - } -} diff --git a/src/main/java/android/os/PerformanceCollector.java b/src/main/java/android/os/PerformanceCollector.java deleted file mode 100644 index be1cf6d..0000000 --- a/src/main/java/android/os/PerformanceCollector.java +++ /dev/null @@ -1,587 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - - -import java.util.ArrayList; - -/** - * Collects performance data between two function calls in Bundle objects and - * outputs the results using writer of type {@link PerformanceResultsWriter}. - *

    - * {@link #beginSnapshot(String)} and {@link #endSnapshot()} functions collect - * memory usage information and measure runtime between calls to begin and end. - * These functions logically wrap around an entire test, and should be called - * with name of test as the label, e.g. EmailPerformanceTest. - *

    - * {@link #startTiming(String)} and {@link #stopTiming(String)} functions - * measure runtime between calls to start and stop. These functions logically - * wrap around a single test case or a small block of code, and should be called - * with the name of test case as the label, e.g. testSimpleSendMailSequence. - *

    - * {@link #addIteration(String)} inserts intermediate measurement point which - * can be labeled with a String, e.g. Launch email app, compose, send, etc. - *

    - * Snapshot and timing functions do not interfere with each other, and thus can - * be called in any order. The intended structure is to wrap begin/endSnapshot - * around calls to start/stopTiming, for example: - *

    - * beginSnapshot("EmailPerformanceTest"); - * startTiming("testSimpleSendSequence"); - * addIteration("Launch email app"); - * addIteration("Compose"); - * stopTiming("Send"); - * startTiming("testComplexSendSequence"); - * stopTiming(""); - * startTiming("testAddLabel"); - * stopTiming(""); - * endSnapshot(); - *

    - * Structure of results output is up to implementor of - * {@link PerformanceResultsWriter }. - * - * {@hide} Pending approval for public API. - */ -public class PerformanceCollector { - - /** - * Interface for reporting performance data. - */ - public interface PerformanceResultsWriter { - - /** - * Callback invoked as first action in - * PerformanceCollector#beginSnapshot(String) for reporting the start of - * a performance snapshot. - * - * @param label description of code block between beginSnapshot and - * PerformanceCollector#endSnapshot() - * @see PerformanceCollector#beginSnapshot(String) - */ - public void writeBeginSnapshot(String label); - - /** - * Callback invoked as last action in PerformanceCollector#endSnapshot() - * for reporting performance data collected in the snapshot. - * - * @param results memory and runtime metrics stored as key/value pairs, - * in the same structure as returned by - * PerformanceCollector#endSnapshot() - * @see PerformanceCollector#endSnapshot() - */ - public void writeEndSnapshot(Bundle results); - - /** - * Callback invoked as first action in - * PerformanceCollector#startTiming(String) for reporting the start of - * a timing measurement. - * - * @param label description of code block between startTiming and - * PerformanceCollector#stopTiming(String) - * @see PerformanceCollector#startTiming(String) - */ - public void writeStartTiming(String label); - - /** - * Callback invoked as last action in - * {@link PerformanceCollector#stopTiming(String)} for reporting the - * sequence of timings measured. - * - * @param results runtime metrics of code block between calls to - * startTiming and stopTiming, in the same structure as - * returned by PerformanceCollector#stopTiming(String) - * @see PerformanceCollector#stopTiming(String) - */ - public void writeStopTiming(Bundle results); - - /** - * Callback invoked as last action in - * {@link PerformanceCollector#addMeasurement(String, long)} for - * reporting an integer type measurement. - * - * @param label short description of the metric that was measured - * @param value long value of the measurement - */ - public void writeMeasurement(String label, long value); - - /** - * Callback invoked as last action in - * {@link PerformanceCollector#addMeasurement(String, float)} for - * reporting a float type measurement. - * - * @param label short description of the metric that was measured - * @param value float value of the measurement - */ - public void writeMeasurement(String label, float value); - - /** - * Callback invoked as last action in - * {@link PerformanceCollector#addMeasurement(String, String)} for - * reporting a string field. - * - * @param label short description of the metric that was measured - * @param value string summary of the measurement - */ - public void writeMeasurement(String label, String value); - } - - /** - * In a results Bundle, this key references a List of iteration Bundles. - */ - public static final String METRIC_KEY_ITERATIONS = "iterations"; - /** - * In an iteration Bundle, this key describes the iteration. - */ - public static final String METRIC_KEY_LABEL = "label"; - /** - * In a results Bundle, this key reports the cpu time of the code block - * under measurement. - */ - public static final String METRIC_KEY_CPU_TIME = "cpu_time"; - /** - * In a results Bundle, this key reports the execution time of the code - * block under measurement. - */ - public static final String METRIC_KEY_EXECUTION_TIME = "execution_time"; - /** - * In a snapshot Bundle, this key reports the number of received - * transactions from the binder driver before collection started. - */ - public static final String METRIC_KEY_PRE_RECEIVED_TRANSACTIONS = "pre_received_transactions"; - /** - * In a snapshot Bundle, this key reports the number of transactions sent by - * the running program before collection started. - */ - public static final String METRIC_KEY_PRE_SENT_TRANSACTIONS = "pre_sent_transactions"; - /** - * In a snapshot Bundle, this key reports the number of received - * transactions from the binder driver. - */ - public static final String METRIC_KEY_RECEIVED_TRANSACTIONS = "received_transactions"; - /** - * In a snapshot Bundle, this key reports the number of transactions sent by - * the running program. - */ - public static final String METRIC_KEY_SENT_TRANSACTIONS = "sent_transactions"; - /** - * In a snapshot Bundle, this key reports the number of garbage collection - * invocations. - */ - public static final String METRIC_KEY_GC_INVOCATION_COUNT = "gc_invocation_count"; - /** - * In a snapshot Bundle, this key reports the amount of allocated memory - * used by the running program. - */ - public static final String METRIC_KEY_JAVA_ALLOCATED = "java_allocated"; - /** - * In a snapshot Bundle, this key reports the amount of free memory - * available to the running program. - */ - public static final String METRIC_KEY_JAVA_FREE = "java_free"; - /** - * In a snapshot Bundle, this key reports the number of private dirty pages - * used by dalvik. - */ - public static final String METRIC_KEY_JAVA_PRIVATE_DIRTY = "java_private_dirty"; - /** - * In a snapshot Bundle, this key reports the proportional set size for - * dalvik. - */ - public static final String METRIC_KEY_JAVA_PSS = "java_pss"; - /** - * In a snapshot Bundle, this key reports the number of shared dirty pages - * used by dalvik. - */ - public static final String METRIC_KEY_JAVA_SHARED_DIRTY = "java_shared_dirty"; - /** - * In a snapshot Bundle, this key reports the total amount of memory - * available to the running program. - */ - public static final String METRIC_KEY_JAVA_SIZE = "java_size"; - /** - * In a snapshot Bundle, this key reports the amount of allocated memory in - * the native heap. - */ - public static final String METRIC_KEY_NATIVE_ALLOCATED = "native_allocated"; - /** - * In a snapshot Bundle, this key reports the amount of free memory in the - * native heap. - */ - public static final String METRIC_KEY_NATIVE_FREE = "native_free"; - /** - * In a snapshot Bundle, this key reports the number of private dirty pages - * used by the native heap. - */ - public static final String METRIC_KEY_NATIVE_PRIVATE_DIRTY = "native_private_dirty"; - /** - * In a snapshot Bundle, this key reports the proportional set size for the - * native heap. - */ - public static final String METRIC_KEY_NATIVE_PSS = "native_pss"; - /** - * In a snapshot Bundle, this key reports the number of shared dirty pages - * used by the native heap. - */ - public static final String METRIC_KEY_NATIVE_SHARED_DIRTY = "native_shared_dirty"; - /** - * In a snapshot Bundle, this key reports the size of the native heap. - */ - public static final String METRIC_KEY_NATIVE_SIZE = "native_size"; - /** - * In a snapshot Bundle, this key reports the number of objects allocated - * globally. - */ - public static final String METRIC_KEY_GLOBAL_ALLOC_COUNT = "global_alloc_count"; - /** - * In a snapshot Bundle, this key reports the size of all objects allocated - * globally. - */ - public static final String METRIC_KEY_GLOBAL_ALLOC_SIZE = "global_alloc_size"; - /** - * In a snapshot Bundle, this key reports the number of objects freed - * globally. - */ - public static final String METRIC_KEY_GLOBAL_FREED_COUNT = "global_freed_count"; - /** - * In a snapshot Bundle, this key reports the size of all objects freed - * globally. - */ - public static final String METRIC_KEY_GLOBAL_FREED_SIZE = "global_freed_size"; - /** - * In a snapshot Bundle, this key reports the number of private dirty pages - * used by everything else. - */ - public static final String METRIC_KEY_OTHER_PRIVATE_DIRTY = "other_private_dirty"; - /** - * In a snapshot Bundle, this key reports the proportional set size for - * everything else. - */ - public static final String METRIC_KEY_OTHER_PSS = "other_pss"; - /** - * In a snapshot Bundle, this key reports the number of shared dirty pages - * used by everything else. - */ - public static final String METRIC_KEY_OTHER_SHARED_DIRTY = "other_shared_dirty"; - - private PerformanceResultsWriter mPerfWriter; - private Bundle mPerfSnapshot; - private Bundle mPerfMeasurement; - private long mSnapshotCpuTime; - private long mSnapshotExecTime; - private long mCpuTime; - private long mExecTime; - - public PerformanceCollector() { - } - - public PerformanceCollector(PerformanceResultsWriter writer) { - setPerformanceResultsWriter(writer); - } - - public void setPerformanceResultsWriter(PerformanceResultsWriter writer) { - mPerfWriter = writer; - } - - /** - * Begin collection of memory usage information. - * - * @param label description of code block between beginSnapshot and - * endSnapshot, used to label output - */ - public void beginSnapshot(String label) { - if (mPerfWriter != null) - mPerfWriter.writeBeginSnapshot(label); - startPerformanceSnapshot(); - } - - /** - * End collection of memory usage information. Returns collected data in a - * Bundle object. - * - * @return Memory and runtime metrics stored as key/value pairs. Values are - * of type long, and keys include: - *

      - *
    • {@link #METRIC_KEY_CPU_TIME cpu_time} - *
    • {@link #METRIC_KEY_EXECUTION_TIME execution_time} - *
    • {@link #METRIC_KEY_PRE_RECEIVED_TRANSACTIONS - * pre_received_transactions} - *
    • {@link #METRIC_KEY_PRE_SENT_TRANSACTIONS - * pre_sent_transactions} - *
    • {@link #METRIC_KEY_RECEIVED_TRANSACTIONS - * received_transactions} - *
    • {@link #METRIC_KEY_SENT_TRANSACTIONS sent_transactions} - *
    • {@link #METRIC_KEY_GC_INVOCATION_COUNT gc_invocation_count} - *
    • {@link #METRIC_KEY_JAVA_ALLOCATED java_allocated} - *
    • {@link #METRIC_KEY_JAVA_FREE java_free} - *
    • {@link #METRIC_KEY_JAVA_PRIVATE_DIRTY java_private_dirty} - *
    • {@link #METRIC_KEY_JAVA_PSS java_pss} - *
    • {@link #METRIC_KEY_JAVA_SHARED_DIRTY java_shared_dirty} - *
    • {@link #METRIC_KEY_JAVA_SIZE java_size} - *
    • {@link #METRIC_KEY_NATIVE_ALLOCATED native_allocated} - *
    • {@link #METRIC_KEY_NATIVE_FREE native_free} - *
    • {@link #METRIC_KEY_NATIVE_PRIVATE_DIRTY native_private_dirty} - *
    • {@link #METRIC_KEY_NATIVE_PSS native_pss} - *
    • {@link #METRIC_KEY_NATIVE_SHARED_DIRTY native_shared_dirty} - *
    • {@link #METRIC_KEY_NATIVE_SIZE native_size} - *
    • {@link #METRIC_KEY_GLOBAL_ALLOC_COUNT global_alloc_count} - *
    • {@link #METRIC_KEY_GLOBAL_ALLOC_SIZE global_alloc_size} - *
    • {@link #METRIC_KEY_GLOBAL_FREED_COUNT global_freed_count} - *
    • {@link #METRIC_KEY_GLOBAL_FREED_SIZE global_freed_size} - *
    • {@link #METRIC_KEY_OTHER_PRIVATE_DIRTY other_private_dirty} - *
    • {@link #METRIC_KEY_OTHER_PSS other_pss} - *
    • {@link #METRIC_KEY_OTHER_SHARED_DIRTY other_shared_dirty} - *
    - */ - public Bundle endSnapshot() { - endPerformanceSnapshot(); - if (mPerfWriter != null) - mPerfWriter.writeEndSnapshot(mPerfSnapshot); - return mPerfSnapshot; - } - - /** - * Start measurement of user and cpu time. - * - * @param label description of code block between startTiming and - * stopTiming, used to label output - */ - public void startTiming(String label) { - if (mPerfWriter != null) - mPerfWriter.writeStartTiming(label); - mPerfMeasurement = new Bundle(); - mPerfMeasurement.putParcelableArrayList( - METRIC_KEY_ITERATIONS, new ArrayList()); - mExecTime = SystemClock.uptimeMillis(); - mCpuTime = Process.getElapsedCpuTime(); - } - - /** - * Add a measured segment, and start measuring the next segment. Returns - * collected data in a Bundle object. - * - * @param label description of code block between startTiming and - * addIteration, and between two calls to addIteration, used - * to label output - * @return Runtime metrics stored as key/value pairs. Values are of type - * long, and keys include: - *
      - *
    • {@link #METRIC_KEY_LABEL label} - *
    • {@link #METRIC_KEY_CPU_TIME cpu_time} - *
    • {@link #METRIC_KEY_EXECUTION_TIME execution_time} - *
    - */ - public Bundle addIteration(String label) { - mCpuTime = Process.getElapsedCpuTime() - mCpuTime; - mExecTime = SystemClock.uptimeMillis() - mExecTime; - - Bundle iteration = new Bundle(); - iteration.putString(METRIC_KEY_LABEL, label); - iteration.putLong(METRIC_KEY_EXECUTION_TIME, mExecTime); - iteration.putLong(METRIC_KEY_CPU_TIME, mCpuTime); - mPerfMeasurement.getParcelableArrayList(METRIC_KEY_ITERATIONS).add(iteration); - - mExecTime = SystemClock.uptimeMillis(); - mCpuTime = Process.getElapsedCpuTime(); - return iteration; - } - - /** - * Stop measurement of user and cpu time. - * - * @param label description of code block between addIteration or - * startTiming and stopTiming, used to label output - * @return Runtime metrics stored in a bundle, including all iterations - * between calls to startTiming and stopTiming. List of iterations - * is keyed by {@link #METRIC_KEY_ITERATIONS iterations}. - */ - public Bundle stopTiming(String label) { - addIteration(label); - if (mPerfWriter != null) - mPerfWriter.writeStopTiming(mPerfMeasurement); - return mPerfMeasurement; - } - - /** - * Add an integer type measurement to the collector. - * - * @param label short description of the metric that was measured - * @param value long value of the measurement - */ - public void addMeasurement(String label, long value) { - if (mPerfWriter != null) - mPerfWriter.writeMeasurement(label, value); - } - - /** - * Add a float type measurement to the collector. - * - * @param label short description of the metric that was measured - * @param value float value of the measurement - */ - public void addMeasurement(String label, float value) { - if (mPerfWriter != null) - mPerfWriter.writeMeasurement(label, value); - } - - /** - * Add a string field to the collector. - * - * @param label short description of the metric that was measured - * @param value string summary of the measurement - */ - public void addMeasurement(String label, String value) { - if (mPerfWriter != null) - mPerfWriter.writeMeasurement(label, value); - } - - /* - * Starts tracking memory usage, binder transactions, and real & cpu timing. - */ - private void startPerformanceSnapshot() { - // Create new snapshot - mPerfSnapshot = new Bundle(); - - // Add initial binder counts - Bundle binderCounts = getBinderCounts(); - for (String key : binderCounts.keySet()) { - mPerfSnapshot.putLong("pre_" + key, binderCounts.getLong(key)); - } - - // Force a GC and zero out the performance counters. Do this - // before reading initial CPU/wall-clock times so we don't include - // the cost of this setup in our final metrics. - startAllocCounting(); - - // Record CPU time up to this point, and start timing. Note: this - // must happen at the end of this method, otherwise the timing will - // include noise. - mSnapshotExecTime = SystemClock.uptimeMillis(); - mSnapshotCpuTime = Process.getElapsedCpuTime(); - } - - /* - * Stops tracking memory usage, binder transactions, and real & cpu timing. - * Stores collected data as type long into Bundle object for reporting. - */ - private void endPerformanceSnapshot() { - // Stop the timing. This must be done first before any other counting is - // stopped. - mSnapshotCpuTime = Process.getElapsedCpuTime() - mSnapshotCpuTime; - mSnapshotExecTime = SystemClock.uptimeMillis() - mSnapshotExecTime; - - stopAllocCounting(); - - long nativeMax = Debug.getNativeHeapSize() / 1024; - long nativeAllocated = Debug.getNativeHeapAllocatedSize() / 1024; - long nativeFree = Debug.getNativeHeapFreeSize() / 1024; - - Debug.MemoryInfo memInfo = new Debug.MemoryInfo(); - Debug.getMemoryInfo(memInfo); - - Runtime runtime = Runtime.getRuntime(); - - long dalvikMax = runtime.totalMemory() / 1024; - long dalvikFree = runtime.freeMemory() / 1024; - long dalvikAllocated = dalvikMax - dalvikFree; - - // Add final binder counts - Bundle binderCounts = getBinderCounts(); - for (String key : binderCounts.keySet()) { - mPerfSnapshot.putLong(key, binderCounts.getLong(key)); - } - - // Add alloc counts - Bundle allocCounts = getAllocCounts(); - for (String key : allocCounts.keySet()) { - mPerfSnapshot.putLong(key, allocCounts.getLong(key)); - } - - mPerfSnapshot.putLong(METRIC_KEY_EXECUTION_TIME, mSnapshotExecTime); - mPerfSnapshot.putLong(METRIC_KEY_CPU_TIME, mSnapshotCpuTime); - - mPerfSnapshot.putLong(METRIC_KEY_NATIVE_SIZE, nativeMax); - mPerfSnapshot.putLong(METRIC_KEY_NATIVE_ALLOCATED, nativeAllocated); - mPerfSnapshot.putLong(METRIC_KEY_NATIVE_FREE, nativeFree); - mPerfSnapshot.putLong(METRIC_KEY_NATIVE_PSS, memInfo.nativePss); - mPerfSnapshot.putLong(METRIC_KEY_NATIVE_PRIVATE_DIRTY, memInfo.nativePrivateDirty); - mPerfSnapshot.putLong(METRIC_KEY_NATIVE_SHARED_DIRTY, memInfo.nativeSharedDirty); - - mPerfSnapshot.putLong(METRIC_KEY_JAVA_SIZE, dalvikMax); - mPerfSnapshot.putLong(METRIC_KEY_JAVA_ALLOCATED, dalvikAllocated); - mPerfSnapshot.putLong(METRIC_KEY_JAVA_FREE, dalvikFree); - mPerfSnapshot.putLong(METRIC_KEY_JAVA_PSS, memInfo.dalvikPss); - mPerfSnapshot.putLong(METRIC_KEY_JAVA_PRIVATE_DIRTY, memInfo.dalvikPrivateDirty); - mPerfSnapshot.putLong(METRIC_KEY_JAVA_SHARED_DIRTY, memInfo.dalvikSharedDirty); - - mPerfSnapshot.putLong(METRIC_KEY_OTHER_PSS, memInfo.otherPss); - mPerfSnapshot.putLong(METRIC_KEY_OTHER_PRIVATE_DIRTY, memInfo.otherPrivateDirty); - mPerfSnapshot.putLong(METRIC_KEY_OTHER_SHARED_DIRTY, memInfo.otherSharedDirty); - } - - /* - * Starts allocation counting. This triggers a gc and resets the counts. - */ - private static void startAllocCounting() { - // Before we start trigger a GC and reset the debug counts. Run the - // finalizers and another GC before starting and stopping the alloc - // counts. This will free up any objects that were just sitting around - // waiting for their finalizers to be run. - Runtime.getRuntime().gc(); - Runtime.getRuntime().runFinalization(); - Runtime.getRuntime().gc(); - - Debug.resetAllCounts(); - - // start the counts - Debug.startAllocCounting(); - } - - /* - * Stops allocation counting. - */ - private static void stopAllocCounting() { - Runtime.getRuntime().gc(); - Runtime.getRuntime().runFinalization(); - Runtime.getRuntime().gc(); - Debug.stopAllocCounting(); - } - - /* - * Returns a bundle with the current results from the allocation counting. - */ - private static Bundle getAllocCounts() { - Bundle results = new Bundle(); - results.putLong(METRIC_KEY_GLOBAL_ALLOC_COUNT, Debug.getGlobalAllocCount()); - results.putLong(METRIC_KEY_GLOBAL_ALLOC_SIZE, Debug.getGlobalAllocSize()); - results.putLong(METRIC_KEY_GLOBAL_FREED_COUNT, Debug.getGlobalFreedCount()); - results.putLong(METRIC_KEY_GLOBAL_FREED_SIZE, Debug.getGlobalFreedSize()); - results.putLong(METRIC_KEY_GC_INVOCATION_COUNT, Debug.getGlobalGcInvocationCount()); - return results; - } - - /* - * Returns a bundle with the counts for various binder counts for this - * process. Currently the only two that are reported are the number of send - * and the number of received transactions. - */ - private static Bundle getBinderCounts() { - Bundle results = new Bundle(); - results.putLong(METRIC_KEY_SENT_TRANSACTIONS, Debug.getBinderSentTransactions()); - results.putLong(METRIC_KEY_RECEIVED_TRANSACTIONS, Debug.getBinderReceivedTransactions()); - return results; - } -} diff --git a/src/main/java/android/os/PerformanceCollectorTest.java b/src/main/java/android/os/PerformanceCollectorTest.java deleted file mode 100644 index 7533c84..0000000 --- a/src/main/java/android/os/PerformanceCollectorTest.java +++ /dev/null @@ -1,525 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.os.PerformanceCollector.PerformanceResultsWriter; -import android.test.suitebuilder.annotation.MediumTest; -import android.test.suitebuilder.annotation.SmallTest; - -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Random; - -import junit.framework.TestCase; - -public class PerformanceCollectorTest extends TestCase { - - private PerformanceCollector mPerfCollector; - - @Override - protected void setUp() throws Exception { - super.setUp(); - mPerfCollector = new PerformanceCollector(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - mPerfCollector = null; - } - - @SmallTest - public void testBeginSnapshotNoWriter() throws Exception { - mPerfCollector.beginSnapshot("testBeginSnapshotNoWriter"); - - assertTrue((Long)readPrivateField("mSnapshotCpuTime", mPerfCollector) > 0); - assertTrue((Long)readPrivateField("mSnapshotExecTime", mPerfCollector) > 0); - Bundle snapshot = (Bundle)readPrivateField("mPerfSnapshot", mPerfCollector); - assertNotNull(snapshot); - assertEquals(2, snapshot.size()); - } - - @MediumTest - public void testEndSnapshotNoWriter() throws Exception { - mPerfCollector.beginSnapshot("testEndSnapshotNoWriter"); - workForRandomLongPeriod(); - Bundle snapshot = mPerfCollector.endSnapshot(); - - verifySnapshotBundle(snapshot); - } - - @SmallTest - public void testStartTimingNoWriter() throws Exception { - mPerfCollector.startTiming("testStartTimingNoWriter"); - - assertTrue((Long)readPrivateField("mCpuTime", mPerfCollector) > 0); - assertTrue((Long)readPrivateField("mExecTime", mPerfCollector) > 0); - Bundle measurement = (Bundle)readPrivateField("mPerfMeasurement", mPerfCollector); - assertNotNull(measurement); - verifyTimingBundle(measurement, new ArrayList()); - } - - @SmallTest - public void testAddIterationNoWriter() throws Exception { - mPerfCollector.startTiming("testAddIterationNoWriter"); - workForRandomTinyPeriod(); - Bundle iteration = mPerfCollector.addIteration("timing1"); - - verifyIterationBundle(iteration, "timing1"); - } - - @SmallTest - public void testStopTimingNoWriter() throws Exception { - mPerfCollector.startTiming("testStopTimingNoWriter"); - workForRandomTinyPeriod(); - mPerfCollector.addIteration("timing2"); - workForRandomTinyPeriod(); - mPerfCollector.addIteration("timing3"); - workForRandomShortPeriod(); - Bundle timing = mPerfCollector.stopTiming("timing4"); - - ArrayList labels = new ArrayList(); - labels.add("timing2"); - labels.add("timing3"); - labels.add("timing4"); - verifyTimingBundle(timing, labels); - } - - @SmallTest - public void testBeginSnapshot() throws Exception { - MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter(); - mPerfCollector.setPerformanceResultsWriter(writer); - mPerfCollector.beginSnapshot("testBeginSnapshot"); - - assertEquals("testBeginSnapshot", writer.snapshotLabel); - assertTrue((Long)readPrivateField("mSnapshotCpuTime", mPerfCollector) > 0); - assertTrue((Long)readPrivateField("mSnapshotExecTime", mPerfCollector) > 0); - Bundle snapshot = (Bundle)readPrivateField("mPerfSnapshot", mPerfCollector); - assertNotNull(snapshot); - assertEquals(2, snapshot.size()); - } - - @MediumTest - public void testEndSnapshot() throws Exception { - MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter(); - mPerfCollector.setPerformanceResultsWriter(writer); - mPerfCollector.beginSnapshot("testEndSnapshot"); - workForRandomLongPeriod(); - Bundle snapshot1 = mPerfCollector.endSnapshot(); - Bundle snapshot2 = writer.snapshotResults; - - assertEqualsBundle(snapshot1, snapshot2); - verifySnapshotBundle(snapshot1); - } - - @SmallTest - public void testStartTiming() throws Exception { - MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter(); - mPerfCollector.setPerformanceResultsWriter(writer); - mPerfCollector.startTiming("testStartTiming"); - - assertEquals("testStartTiming", writer.timingLabel); - assertTrue((Long)readPrivateField("mCpuTime", mPerfCollector) > 0); - assertTrue((Long)readPrivateField("mExecTime", mPerfCollector) > 0); - Bundle measurement = (Bundle)readPrivateField("mPerfMeasurement", mPerfCollector); - assertNotNull(measurement); - verifyTimingBundle(measurement, new ArrayList()); - } - - @SmallTest - public void testAddIteration() throws Exception { - mPerfCollector.startTiming("testAddIteration"); - workForRandomTinyPeriod(); - Bundle iteration = mPerfCollector.addIteration("timing5"); - - verifyIterationBundle(iteration, "timing5"); - } - - @SmallTest - public void testStopTiming() throws Exception { - mPerfCollector.startTiming("testStopTiming"); - workForRandomTinyPeriod(); - mPerfCollector.addIteration("timing6"); - workForRandomTinyPeriod(); - mPerfCollector.addIteration("timing7"); - workForRandomShortPeriod(); - Bundle timing = mPerfCollector.stopTiming("timing8"); - - ArrayList labels = new ArrayList(); - labels.add("timing6"); - labels.add("timing7"); - labels.add("timing8"); - verifyTimingBundle(timing, labels); - } - - @SmallTest - public void testAddMeasurementLong() throws Exception { - MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter(); - mPerfCollector.setPerformanceResultsWriter(writer); - mPerfCollector.startTiming("testAddMeasurementLong"); - mPerfCollector.addMeasurement("testAddMeasurementLongZero", 0); - mPerfCollector.addMeasurement("testAddMeasurementLongPos", 348573); - mPerfCollector.addMeasurement("testAddMeasurementLongNeg", -19354); - mPerfCollector.stopTiming(""); - - assertEquals("testAddMeasurementLong", writer.timingLabel); - Bundle results = writer.timingResults; - assertEquals(4, results.size()); - assertTrue(results.containsKey("testAddMeasurementLongZero")); - assertEquals(0, results.getLong("testAddMeasurementLongZero")); - assertTrue(results.containsKey("testAddMeasurementLongPos")); - assertEquals(348573, results.getLong("testAddMeasurementLongPos")); - assertTrue(results.containsKey("testAddMeasurementLongNeg")); - assertEquals(-19354, results.getLong("testAddMeasurementLongNeg")); - } - - @SmallTest - public void testAddMeasurementFloat() throws Exception { - MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter(); - mPerfCollector.setPerformanceResultsWriter(writer); - mPerfCollector.startTiming("testAddMeasurementFloat"); - mPerfCollector.addMeasurement("testAddMeasurementFloatZero", 0.0f); - mPerfCollector.addMeasurement("testAddMeasurementFloatPos", 348573.345f); - mPerfCollector.addMeasurement("testAddMeasurementFloatNeg", -19354.093f); - mPerfCollector.stopTiming(""); - - assertEquals("testAddMeasurementFloat", writer.timingLabel); - Bundle results = writer.timingResults; - assertEquals(4, results.size()); - assertTrue(results.containsKey("testAddMeasurementFloatZero")); - assertEquals(0.0f, results.getFloat("testAddMeasurementFloatZero")); - assertTrue(results.containsKey("testAddMeasurementFloatPos")); - assertEquals(348573.345f, results.getFloat("testAddMeasurementFloatPos")); - assertTrue(results.containsKey("testAddMeasurementFloatNeg")); - assertEquals(-19354.093f, results.getFloat("testAddMeasurementFloatNeg")); - } - - @SmallTest - public void testAddMeasurementString() throws Exception { - MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter(); - mPerfCollector.setPerformanceResultsWriter(writer); - mPerfCollector.startTiming("testAddMeasurementString"); - mPerfCollector.addMeasurement("testAddMeasurementStringNull", null); - mPerfCollector.addMeasurement("testAddMeasurementStringEmpty", ""); - mPerfCollector.addMeasurement("testAddMeasurementStringNonEmpty", "Hello World"); - mPerfCollector.stopTiming(""); - - assertEquals("testAddMeasurementString", writer.timingLabel); - Bundle results = writer.timingResults; - assertEquals(4, results.size()); - assertTrue(results.containsKey("testAddMeasurementStringNull")); - assertNull(results.getString("testAddMeasurementStringNull")); - assertTrue(results.containsKey("testAddMeasurementStringEmpty")); - assertEquals("", results.getString("testAddMeasurementStringEmpty")); - assertTrue(results.containsKey("testAddMeasurementStringNonEmpty")); - assertEquals("Hello World", results.getString("testAddMeasurementStringNonEmpty")); - } - - @MediumTest - public void testSimpleSequence() throws Exception { - MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter(); - mPerfCollector.setPerformanceResultsWriter(writer); - mPerfCollector.beginSnapshot("testSimpleSequence"); - mPerfCollector.startTiming("testSimpleSequenceTiming"); - workForRandomTinyPeriod(); - mPerfCollector.addIteration("iteration1"); - workForRandomTinyPeriod(); - mPerfCollector.addIteration("iteration2"); - workForRandomTinyPeriod(); - mPerfCollector.addIteration("iteration3"); - workForRandomTinyPeriod(); - mPerfCollector.addIteration("iteration4"); - workForRandomShortPeriod(); - Bundle timing = mPerfCollector.stopTiming("iteration5"); - workForRandomLongPeriod(); - Bundle snapshot1 = mPerfCollector.endSnapshot(); - Bundle snapshot2 = writer.snapshotResults; - - assertEqualsBundle(snapshot1, snapshot2); - verifySnapshotBundle(snapshot1); - - ArrayList labels = new ArrayList(); - labels.add("iteration1"); - labels.add("iteration2"); - labels.add("iteration3"); - labels.add("iteration4"); - labels.add("iteration5"); - verifyTimingBundle(timing, labels); - } - - @MediumTest - public void testLongSequence() throws Exception { - MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter(); - mPerfCollector.setPerformanceResultsWriter(writer); - mPerfCollector.beginSnapshot("testLongSequence"); - mPerfCollector.startTiming("testLongSequenceTiming1"); - workForRandomTinyPeriod(); - mPerfCollector.addIteration("iteration1"); - workForRandomTinyPeriod(); - mPerfCollector.addIteration("iteration2"); - workForRandomShortPeriod(); - Bundle timing1 = mPerfCollector.stopTiming("iteration3"); - workForRandomLongPeriod(); - - mPerfCollector.startTiming("testLongSequenceTiming2"); - workForRandomTinyPeriod(); - mPerfCollector.addIteration("iteration4"); - workForRandomTinyPeriod(); - mPerfCollector.addIteration("iteration5"); - workForRandomShortPeriod(); - Bundle timing2 = mPerfCollector.stopTiming("iteration6"); - workForRandomLongPeriod(); - - mPerfCollector.startTiming("testLongSequenceTiming3"); - workForRandomTinyPeriod(); - mPerfCollector.addIteration("iteration7"); - workForRandomTinyPeriod(); - mPerfCollector.addIteration("iteration8"); - workForRandomShortPeriod(); - Bundle timing3 = mPerfCollector.stopTiming("iteration9"); - workForRandomLongPeriod(); - - mPerfCollector.startTiming("testLongSequenceTiming4"); - workForRandomTinyPeriod(); - mPerfCollector.addIteration("iteration10"); - workForRandomTinyPeriod(); - mPerfCollector.addIteration("iteration11"); - workForRandomShortPeriod(); - Bundle timing4 = mPerfCollector.stopTiming("iteration12"); - workForRandomLongPeriod(); - - mPerfCollector.startTiming("testLongSequenceTiming5"); - workForRandomTinyPeriod(); - mPerfCollector.addIteration("iteration13"); - workForRandomTinyPeriod(); - mPerfCollector.addIteration("iteration14"); - workForRandomShortPeriod(); - Bundle timing5 = mPerfCollector.stopTiming("iteration15"); - workForRandomLongPeriod(); - Bundle snapshot1 = mPerfCollector.endSnapshot(); - Bundle snapshot2 = writer.snapshotResults; - - assertEqualsBundle(snapshot1, snapshot2); - verifySnapshotBundle(snapshot1); - - ArrayList labels1 = new ArrayList(); - labels1.add("iteration1"); - labels1.add("iteration2"); - labels1.add("iteration3"); - verifyTimingBundle(timing1, labels1); - ArrayList labels2 = new ArrayList(); - labels2.add("iteration4"); - labels2.add("iteration5"); - labels2.add("iteration6"); - verifyTimingBundle(timing2, labels2); - ArrayList labels3 = new ArrayList(); - labels3.add("iteration7"); - labels3.add("iteration8"); - labels3.add("iteration9"); - verifyTimingBundle(timing3, labels3); - ArrayList labels4 = new ArrayList(); - labels4.add("iteration10"); - labels4.add("iteration11"); - labels4.add("iteration12"); - verifyTimingBundle(timing4, labels4); - ArrayList labels5 = new ArrayList(); - labels5.add("iteration13"); - labels5.add("iteration14"); - labels5.add("iteration15"); - verifyTimingBundle(timing5, labels5); - } - - /* - * Verify that snapshotting and timing do not interfere w/ each other, - * by staggering calls to snapshot and timing functions. - */ - @MediumTest - public void testOutOfOrderSequence() { - MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter(); - mPerfCollector.setPerformanceResultsWriter(writer); - mPerfCollector.startTiming("testOutOfOrderSequenceTiming"); - workForRandomShortPeriod(); - mPerfCollector.beginSnapshot("testOutOfOrderSequenceSnapshot"); - workForRandomShortPeriod(); - Bundle timing1 = mPerfCollector.stopTiming("timing1"); - workForRandomShortPeriod(); - Bundle snapshot1 = mPerfCollector.endSnapshot(); - - Bundle timing2 = writer.timingResults; - Bundle snapshot2 = writer.snapshotResults; - - assertEqualsBundle(snapshot1, snapshot2); - verifySnapshotBundle(snapshot1); - - assertEqualsBundle(timing1, timing2); - ArrayList labels = new ArrayList(); - labels.add("timing1"); - verifyTimingBundle(timing1, labels); - } - - private void workForRandomPeriod(int minDuration, int maxDuration) { - Random random = new Random(); - int period = minDuration + random.nextInt(maxDuration - minDuration); - long start = Process.getElapsedCpuTime(); - // Generate positive amount of work, so cpu time is measurable in - // milliseconds - while (Process.getElapsedCpuTime() - start < period) { - for (int i = 0, temp = 0; i < 50; i++ ) { - temp += i; - } - } - } - - private void workForRandomTinyPeriod() { - workForRandomPeriod(2, 5); - } - - private void workForRandomShortPeriod() { - workForRandomPeriod(10, 25); - } - - private void workForRandomLongPeriod() { - workForRandomPeriod(50, 100); - } - - private void verifySnapshotBundle(Bundle snapshot) { - assertTrue("At least 26 metrics collected", 26 <= snapshot.size()); - - assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_CPU_TIME)); - assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_CPU_TIME) > 0); - assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_EXECUTION_TIME)); - assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_EXECUTION_TIME) > 0); - - assertTrue(snapshot.containsKey( - PerformanceCollector.METRIC_KEY_PRE_RECEIVED_TRANSACTIONS)); - assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_PRE_SENT_TRANSACTIONS)); - assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_RECEIVED_TRANSACTIONS)); - assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_SENT_TRANSACTIONS)); - assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_GC_INVOCATION_COUNT)); - - assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_JAVA_ALLOCATED)); - assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_JAVA_ALLOCATED) > 0); - assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_JAVA_FREE)); - assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_JAVA_FREE) > 0); - assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_JAVA_PRIVATE_DIRTY)); - assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_JAVA_PRIVATE_DIRTY) > 0); - assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_JAVA_PSS)); - assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_JAVA_PSS) > 0); - assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_JAVA_SHARED_DIRTY)); - assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_JAVA_SHARED_DIRTY) > 0); - assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_JAVA_SIZE)); - assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_JAVA_SIZE) > 0); - assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_NATIVE_ALLOCATED)); - assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_NATIVE_ALLOCATED) > 0); - assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_NATIVE_FREE)); - assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_NATIVE_FREE) > 0); - assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_NATIVE_PRIVATE_DIRTY)); - assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_NATIVE_PRIVATE_DIRTY) > 0); - assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_NATIVE_PSS)); - assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_NATIVE_PSS) > 0); - assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_NATIVE_SHARED_DIRTY)); - assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_NATIVE_SHARED_DIRTY) > 0); - assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_NATIVE_SIZE)); - assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_NATIVE_SIZE) > 0); - assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_GLOBAL_ALLOC_COUNT)); - assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_GLOBAL_ALLOC_COUNT) > 0); - assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_GLOBAL_ALLOC_SIZE)); - assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_GLOBAL_ALLOC_SIZE) > 0); - assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_GLOBAL_FREED_COUNT)); - assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_GLOBAL_FREED_COUNT) > 0); - assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_GLOBAL_FREED_SIZE)); - assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_GLOBAL_FREED_SIZE) > 0); - assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_OTHER_PRIVATE_DIRTY)); - assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_OTHER_PRIVATE_DIRTY) > 0); - assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_OTHER_PSS)); - assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_OTHER_PSS) > 0); - assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_OTHER_SHARED_DIRTY)); - assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_OTHER_SHARED_DIRTY) > 0); - } - - private void verifyIterationBundle(Bundle iteration, String label) { - assertEquals(3, iteration.size()); - assertTrue(iteration.containsKey(PerformanceCollector.METRIC_KEY_LABEL)); - assertEquals(label, iteration.getString(PerformanceCollector.METRIC_KEY_LABEL)); - assertTrue(iteration.containsKey(PerformanceCollector.METRIC_KEY_CPU_TIME)); - assertTrue(iteration.getLong(PerformanceCollector.METRIC_KEY_CPU_TIME) > 0); - assertTrue(iteration.containsKey(PerformanceCollector.METRIC_KEY_EXECUTION_TIME)); - assertTrue(iteration.getLong(PerformanceCollector.METRIC_KEY_EXECUTION_TIME) > 0); - } - - private void verifyTimingBundle(Bundle timing, ArrayList labels) { - assertEquals(1, timing.size()); - assertTrue(timing.containsKey(PerformanceCollector.METRIC_KEY_ITERATIONS)); - ArrayList iterations = timing.getParcelableArrayList( - PerformanceCollector.METRIC_KEY_ITERATIONS); - assertNotNull(iterations); - assertEquals(labels.size(), iterations.size()); - for (int i = 0; i < labels.size(); i ++) { - Bundle iteration = (Bundle)iterations.get(i); - verifyIterationBundle(iteration, labels.get(i)); - } - } - - private void assertEqualsBundle(Bundle b1, Bundle b2) { - assertEquals(b1.keySet(), b2.keySet()); - for (String key : b1.keySet()) { - assertEquals(b1.get(key), b2.get(key)); - } - } - - private Object readPrivateField(String fieldName, Object object) throws Exception { - Field f = object.getClass().getDeclaredField(fieldName); - f.setAccessible(true); - return f.get(object); - } - - private class MockPerformanceResultsWriter implements PerformanceResultsWriter { - - public String snapshotLabel; - public Bundle snapshotResults = new Bundle(); - public String timingLabel; - public Bundle timingResults = new Bundle(); - - public void writeBeginSnapshot(String label) { - snapshotLabel = label; - } - - public void writeEndSnapshot(Bundle results) { - snapshotResults.putAll(results); - } - - public void writeStartTiming(String label) { - timingLabel = label; - } - - public void writeStopTiming(Bundle results) { - timingResults.putAll(results); - } - - public void writeMeasurement(String label, long value) { - timingResults.putLong(label, value); - } - - public void writeMeasurement(String label, float value) { - timingResults.putFloat(label, value); - } - - public void writeMeasurement(String label, String value) { - timingResults.putString(label, value); - } - } -} diff --git a/src/main/java/android/os/PersistableBundle.java b/src/main/java/android/os/PersistableBundle.java deleted file mode 100644 index 3a44428..0000000 --- a/src/main/java/android/os/PersistableBundle.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.util.ArrayMap; -import com.android.internal.util.XmlUtils; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlSerializer; - -import java.io.IOException; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - -/** - * A mapping from String values to various types that can be saved to persistent and later - * restored. - * - */ -public final class PersistableBundle extends BaseBundle implements Cloneable, Parcelable, - XmlUtils.WriteMapCallback { - private static final String TAG_PERSISTABLEMAP = "pbundle_as_map"; - public static final PersistableBundle EMPTY; - static final Parcel EMPTY_PARCEL; - - static { - EMPTY = new PersistableBundle(); - EMPTY.mMap = ArrayMap.EMPTY; - EMPTY_PARCEL = BaseBundle.EMPTY_PARCEL; - } - - /** - * Constructs a new, empty PersistableBundle. - */ - public PersistableBundle() { - super(); - } - - /** - * Constructs a new, empty PersistableBundle sized to hold the given number of - * elements. The PersistableBundle will grow as needed. - * - * @param capacity the initial capacity of the PersistableBundle - */ - public PersistableBundle(int capacity) { - super(capacity); - } - - /** - * Constructs a PersistableBundle containing a copy of the mappings from the given - * PersistableBundle. - * - * @param b a PersistableBundle to be copied. - */ - public PersistableBundle(PersistableBundle b) { - super(b); - } - - /** - * Constructs a PersistableBundle containing the mappings passed in. - * - * @param map a Map containing only those items that can be persisted. - * @throws IllegalArgumentException if any element of #map cannot be persisted. - */ - private PersistableBundle(Map map) { - super(); - - // First stuff everything in. - putAll(map); - - // Now verify each item throwing an exception if there is a violation. - Set keys = map.keySet(); - Iterator iterator = keys.iterator(); - while (iterator.hasNext()) { - String key = iterator.next(); - Object value = map.get(key); - if (value instanceof Map) { - // Fix up any Maps by replacing them with PersistableBundles. - putPersistableBundle(key, new PersistableBundle((Map) value)); - } else if (!(value instanceof Integer) && !(value instanceof Long) && - !(value instanceof Double) && !(value instanceof String) && - !(value instanceof int[]) && !(value instanceof long[]) && - !(value instanceof double[]) && !(value instanceof String[]) && - !(value instanceof PersistableBundle) && (value != null) && - !(value instanceof Boolean) && !(value instanceof boolean[])) { - throw new IllegalArgumentException("Bad value in PersistableBundle key=" + key + - " value=" + value); - } - } - } - - /* package */ PersistableBundle(Parcel parcelledData, int length) { - super(parcelledData, length); - } - - /** - * Make a PersistableBundle for a single key/value pair. - * - * @hide - */ - public static PersistableBundle forPair(String key, String value) { - PersistableBundle b = new PersistableBundle(1); - b.putString(key, value); - return b; - } - - /** - * Clones the current PersistableBundle. The internal map is cloned, but the keys and - * values to which it refers are copied by reference. - */ - @Override - public Object clone() { - return new PersistableBundle(this); - } - - /** - * Inserts a PersistableBundle value into the mapping of this Bundle, replacing - * any existing value for the given key. Either key or value may be null. - * - * @param key a String, or null - * @param value a Bundle object, or null - */ - public void putPersistableBundle(String key, PersistableBundle value) { - unparcel(); - mMap.put(key, value); - } - - /** - * Returns the value associated with the given key, or null if - * no mapping of the desired type exists for the given key or a null - * value is explicitly associated with the key. - * - * @param key a String, or null - * @return a Bundle value, or null - */ - public PersistableBundle getPersistableBundle(String key) { - unparcel(); - Object o = mMap.get(key); - if (o == null) { - return null; - } - try { - return (PersistableBundle) o; - } catch (ClassCastException e) { - typeWarning(key, o, "Bundle", e); - return null; - } - } - - public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { - @Override - public PersistableBundle createFromParcel(Parcel in) { - return in.readPersistableBundle(); - } - - @Override - public PersistableBundle[] newArray(int size) { - return new PersistableBundle[size]; - } - }; - - /** @hide */ - @Override - public void writeUnknownObject(Object v, String name, XmlSerializer out) - throws XmlPullParserException, IOException { - if (v instanceof PersistableBundle) { - out.startTag(null, TAG_PERSISTABLEMAP); - out.attribute(null, "name", name); - ((PersistableBundle) v).saveToXml(out); - out.endTag(null, TAG_PERSISTABLEMAP); - } else { - throw new XmlPullParserException("Unknown Object o=" + v); - } - } - - /** @hide */ - public void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException { - unparcel(); - XmlUtils.writeMapXml(mMap, out, this); - } - - /** @hide */ - static class MyReadMapCallback implements XmlUtils.ReadMapCallback { - @Override - public Object readThisUnknownObjectXml(XmlPullParser in, String tag) - throws XmlPullParserException, IOException { - if (TAG_PERSISTABLEMAP.equals(tag)) { - return restoreFromXml(in); - } - throw new XmlPullParserException("Unknown tag=" + tag); - } - } - - /** - * Report the nature of this Parcelable's contents - */ - @Override - public int describeContents() { - return 0; - } - - /** - * Writes the PersistableBundle contents to a Parcel, typically in order for - * it to be passed through an IBinder connection. - * @param parcel The parcel to copy this bundle to. - */ - @Override - public void writeToParcel(Parcel parcel, int flags) { - final boolean oldAllowFds = parcel.pushAllowFds(false); - try { - writeToParcelInner(parcel, flags); - } finally { - parcel.restoreAllowFds(oldAllowFds); - } - } - - /** @hide */ - public static PersistableBundle restoreFromXml(XmlPullParser in) throws IOException, - XmlPullParserException { - final int outerDepth = in.getDepth(); - final String startTag = in.getName(); - final String[] tagName = new String[1]; - int event; - while (((event = in.next()) != XmlPullParser.END_DOCUMENT) && - (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) { - if (event == XmlPullParser.START_TAG) { - return new PersistableBundle((Map) - XmlUtils.readThisMapXml(in, startTag, tagName, new MyReadMapCallback())); - } - } - return EMPTY; - } - - @Override - synchronized public String toString() { - if (mParcelledData != null) { - if (mParcelledData == EMPTY_PARCEL) { - return "PersistableBundle[EMPTY_PARCEL]"; - } else { - return "PersistableBundle[mParcelledData.dataSize=" + - mParcelledData.dataSize() + "]"; - } - } - return "PersistableBundle[" + mMap.toString() + "]"; - } - -} diff --git a/src/main/java/android/os/PowerManager.java b/src/main/java/android/os/PowerManager.java deleted file mode 100644 index 8307d9b..0000000 --- a/src/main/java/android/os/PowerManager.java +++ /dev/null @@ -1,1101 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.annotation.SdkConstant; -import android.annotation.SystemApi; -import android.content.Context; -import android.util.Log; - -/** - * This class gives you control of the power state of the device. - * - *

    - * Device battery life will be significantly affected by the use of this API. - * Do not acquire {@link WakeLock}s unless you really need them, use the minimum levels - * possible, and be sure to release them as soon as possible. - *

    - * You can obtain an instance of this class by calling - * {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}. - *

    - * The primary API you'll use is {@link #newWakeLock(int, String) newWakeLock()}. - * This will create a {@link PowerManager.WakeLock} object. You can then use methods - * on the wake lock object to control the power state of the device. - *

    - * In practice it's quite simple: - * {@samplecode - * PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); - * PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "My Tag"); - * wl.acquire(); - * ..screen will stay on during this section.. - * wl.release(); - * } - *

    - * The following wake lock levels are defined, with varying effects on system power. - * These levels are mutually exclusive - you may only specify one of them. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
    Flag ValueCPU Screen Keyboard
    {@link #PARTIAL_WAKE_LOCK}On* Off Off
    {@link #SCREEN_DIM_WAKE_LOCK}On Dim Off
    {@link #SCREEN_BRIGHT_WAKE_LOCK}On Bright Off
    {@link #FULL_WAKE_LOCK}On Bright Bright
    - *

    - * *If you hold a partial wake lock, the CPU will continue to run, regardless of any - * display timeouts or the state of the screen and even after the user presses the power button. - * In all other wake locks, the CPU will run, but the user can still put the device to sleep - * using the power button. - *

    - * In addition, you can add two more flags, which affect behavior of the screen only. - * These flags have no effect when combined with a {@link #PARTIAL_WAKE_LOCK}.

    - * - * - * - * - * - * - * - * - * - * - * - *
    Flag Value Description
    {@link #ACQUIRE_CAUSES_WAKEUP}Normal wake locks don't actually turn on the illumination. Instead, they cause - * the illumination to remain on once it turns on (e.g. from user activity). This flag - * will force the screen and/or keyboard to turn on immediately, when the WakeLock is - * acquired. A typical use would be for notifications which are important for the user to - * see immediately.
    {@link #ON_AFTER_RELEASE}If this flag is set, the user activity timer will be reset when the WakeLock is - * released, causing the illumination to remain on a bit longer. This can be used to - * reduce flicker if you are cycling between wake lock conditions.
    - *

    - * Any application using a WakeLock must request the {@code android.permission.WAKE_LOCK} - * permission in an {@code <uses-permission>} element of the application's manifest. - *

    - */ -public final class PowerManager { - private static final String TAG = "PowerManager"; - - /* NOTE: Wake lock levels were previously defined as a bit field, except that only a few - * combinations were actually supported so the bit field was removed. This explains - * why the numbering scheme is so odd. If adding a new wake lock level, any unused - * value can be used. - */ - - /** - * Wake lock level: Ensures that the CPU is running; the screen and keyboard - * backlight will be allowed to go off. - *

    - * If the user presses the power button, then the screen will be turned off - * but the CPU will be kept on until all partial wake locks have been released. - *

    - */ - public static final int PARTIAL_WAKE_LOCK = 0x00000001; - - /** - * Wake lock level: Ensures that the screen is on (but may be dimmed); - * the keyboard backlight will be allowed to go off. - *

    - * If the user presses the power button, then the {@link #SCREEN_DIM_WAKE_LOCK} will be - * implicitly released by the system, causing both the screen and the CPU to be turned off. - * Contrast with {@link #PARTIAL_WAKE_LOCK}. - *

    - * - * @deprecated Most applications should use - * {@link android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON} instead - * of this type of wake lock, as it will be correctly managed by the platform - * as the user moves between applications and doesn't require a special permission. - */ - @Deprecated - public static final int SCREEN_DIM_WAKE_LOCK = 0x00000006; - - /** - * Wake lock level: Ensures that the screen is on at full brightness; - * the keyboard backlight will be allowed to go off. - *

    - * If the user presses the power button, then the {@link #SCREEN_BRIGHT_WAKE_LOCK} will be - * implicitly released by the system, causing both the screen and the CPU to be turned off. - * Contrast with {@link #PARTIAL_WAKE_LOCK}. - *

    - * - * @deprecated Most applications should use - * {@link android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON} instead - * of this type of wake lock, as it will be correctly managed by the platform - * as the user moves between applications and doesn't require a special permission. - */ - @Deprecated - public static final int SCREEN_BRIGHT_WAKE_LOCK = 0x0000000a; - - /** - * Wake lock level: Ensures that the screen and keyboard backlight are on at - * full brightness. - *

    - * If the user presses the power button, then the {@link #FULL_WAKE_LOCK} will be - * implicitly released by the system, causing both the screen and the CPU to be turned off. - * Contrast with {@link #PARTIAL_WAKE_LOCK}. - *

    - * - * @deprecated Most applications should use - * {@link android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON} instead - * of this type of wake lock, as it will be correctly managed by the platform - * as the user moves between applications and doesn't require a special permission. - */ - @Deprecated - public static final int FULL_WAKE_LOCK = 0x0000001a; - - /** - * Wake lock level: Turns the screen off when the proximity sensor activates. - *

    - * If the proximity sensor detects that an object is nearby, the screen turns off - * immediately. Shortly after the object moves away, the screen turns on again. - *

    - * A proximity wake lock does not prevent the device from falling asleep - * unlike {@link #FULL_WAKE_LOCK}, {@link #SCREEN_BRIGHT_WAKE_LOCK} and - * {@link #SCREEN_DIM_WAKE_LOCK}. If there is no user activity and no other - * wake locks are held, then the device will fall asleep (and lock) as usual. - * However, the device will not fall asleep while the screen has been turned off - * by the proximity sensor because it effectively counts as ongoing user activity. - *

    - * Since not all devices have proximity sensors, use {@link #isWakeLockLevelSupported} - * to determine whether this wake lock level is supported. - *

    - * Cannot be used with {@link #ACQUIRE_CAUSES_WAKEUP}. - *

    - */ - public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 0x00000020; - - /** - * Wake lock level: Put the screen in a low power state and allow the CPU to suspend - * if no other wake locks are held. - *

    - * This is used by the dream manager to implement doze mode. It currently - * has no effect unless the power manager is in the dozing state. - *

    - * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission. - *

    - * - * {@hide} - */ - public static final int DOZE_WAKE_LOCK = 0x00000040; - - /** - * Mask for the wake lock level component of a combined wake lock level and flags integer. - * - * @hide - */ - public static final int WAKE_LOCK_LEVEL_MASK = 0x0000ffff; - - /** - * Wake lock flag: Turn the screen on when the wake lock is acquired. - *

    - * Normally wake locks don't actually wake the device, they just cause - * the screen to remain on once it's already on. Think of the video player - * application as the normal behavior. Notifications that pop up and want - * the device to be on are the exception; use this flag to be like them. - *

    - * Cannot be used with {@link #PARTIAL_WAKE_LOCK}. - *

    - */ - public static final int ACQUIRE_CAUSES_WAKEUP = 0x10000000; - - /** - * Wake lock flag: When this wake lock is released, poke the user activity timer - * so the screen stays on for a little longer. - *

    - * Will not turn the screen on if it is not already on. - * See {@link #ACQUIRE_CAUSES_WAKEUP} if you want that. - *

    - * Cannot be used with {@link #PARTIAL_WAKE_LOCK}. - *

    - */ - public static final int ON_AFTER_RELEASE = 0x20000000; - - /** - * Wake lock flag: This wake lock is not important for logging events. If a later - * wake lock is acquired that is important, it will be considered the one to log. - * @hide - */ - public static final int UNIMPORTANT_FOR_LOGGING = 0x40000000; - - /** - * Flag for {@link WakeLock#release WakeLock.release(int)}: Defer releasing a - * {@link #PROXIMITY_SCREEN_OFF_WAKE_LOCK} wake lock until the proximity sensor - * indicates that an object is not in close proximity. - */ - public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; - - /** - * Brightness value for fully on. - * @hide - */ - public static final int BRIGHTNESS_ON = 255; - - /** - * Brightness value for fully off. - * @hide - */ - public static final int BRIGHTNESS_OFF = 0; - - /** - * Brightness value for default policy handling by the system. - * @hide - */ - public static final int BRIGHTNESS_DEFAULT = -1; - - // Note: Be sure to update android.os.BatteryStats and PowerManager.h - // if adding or modifying user activity event constants. - - /** - * User activity event type: Unspecified event type. - * @hide - */ - @SystemApi - public static final int USER_ACTIVITY_EVENT_OTHER = 0; - - /** - * User activity event type: Button or key pressed or released. - * @hide - */ - @SystemApi - public static final int USER_ACTIVITY_EVENT_BUTTON = 1; - - /** - * User activity event type: Touch down, move or up. - * @hide - */ - @SystemApi - public static final int USER_ACTIVITY_EVENT_TOUCH = 2; - - /** - * User activity flag: If already dimmed, extend the dim timeout - * but do not brighten. This flag is useful for keeping the screen on - * a little longer without causing a visible change such as when - * the power key is pressed. - * @hide - */ - @SystemApi - public static final int USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS = 1 << 0; - - /** - * User activity flag: Note the user activity as usual but do not - * reset the user activity timeout. This flag is useful for applying - * user activity power hints when interacting with the device indirectly - * on a secondary screen while allowing the primary screen to go to sleep. - * @hide - */ - @SystemApi - public static final int USER_ACTIVITY_FLAG_INDIRECT = 1 << 1; - - /** - * Go to sleep reason code: Going to sleep due by application request. - * @hide - */ - public static final int GO_TO_SLEEP_REASON_APPLICATION = 0; - - /** - * Go to sleep reason code: Going to sleep due by request of the - * device administration policy. - * @hide - */ - public static final int GO_TO_SLEEP_REASON_DEVICE_ADMIN = 1; - - /** - * Go to sleep reason code: Going to sleep due to a screen timeout. - * @hide - */ - public static final int GO_TO_SLEEP_REASON_TIMEOUT = 2; - - /** - * Go to sleep reason code: Going to sleep due to the lid switch being closed. - * @hide - */ - public static final int GO_TO_SLEEP_REASON_LID_SWITCH = 3; - - /** - * Go to sleep reason code: Going to sleep due to the power button being pressed. - * @hide - */ - public static final int GO_TO_SLEEP_REASON_POWER_BUTTON = 4; - - /** - * Go to sleep reason code: Going to sleep due to HDMI. - * @hide - */ - public static final int GO_TO_SLEEP_REASON_HDMI = 5; - - /** - * Go to sleep flag: Skip dozing state and directly go to full sleep. - * @hide - */ - public static final int GO_TO_SLEEP_FLAG_NO_DOZE = 1 << 0; - - /** - * The value to pass as the 'reason' argument to reboot() to - * reboot into recovery mode (for applying system updates, doing - * factory resets, etc.). - *

    - * Requires the {@link android.Manifest.permission#RECOVERY} - * permission (in addition to - * {@link android.Manifest.permission#REBOOT}). - *

    - * @hide - */ - public static final String REBOOT_RECOVERY = "recovery"; - - final Context mContext; - final IPowerManager mService; - final Handler mHandler; - - /** - * {@hide} - */ - public PowerManager(Context context, IPowerManager service, Handler handler) { - mContext = context; - mService = service; - mHandler = handler; - } - - /** - * Gets the minimum supported screen brightness setting. - * The screen may be allowed to become dimmer than this value but - * this is the minimum value that can be set by the user. - * @hide - */ - public int getMinimumScreenBrightnessSetting() { - return mContext.getResources().getInteger( - com.android.internal.R.integer.config_screenBrightnessSettingMinimum); - } - - /** - * Gets the maximum supported screen brightness setting. - * The screen may be allowed to become dimmer than this value but - * this is the maximum value that can be set by the user. - * @hide - */ - public int getMaximumScreenBrightnessSetting() { - return mContext.getResources().getInteger( - com.android.internal.R.integer.config_screenBrightnessSettingMaximum); - } - - /** - * Gets the default screen brightness setting. - * @hide - */ - public int getDefaultScreenBrightnessSetting() { - return mContext.getResources().getInteger( - com.android.internal.R.integer.config_screenBrightnessSettingDefault); - } - - /** - * Returns true if the twilight service should be used to adjust screen brightness - * policy. This setting is experimental and disabled by default. - * @hide - */ - public static boolean useTwilightAdjustmentFeature() { - return SystemProperties.getBoolean("persist.power.usetwilightadj", false); - } - - /** - * Creates a new wake lock with the specified level and flags. - *

    - * The {@code levelAndFlags} parameter specifies a wake lock level and optional flags - * combined using the logical OR operator. - *

    - * The wake lock levels are: {@link #PARTIAL_WAKE_LOCK}, - * {@link #FULL_WAKE_LOCK}, {@link #SCREEN_DIM_WAKE_LOCK} - * and {@link #SCREEN_BRIGHT_WAKE_LOCK}. Exactly one wake lock level must be - * specified as part of the {@code levelAndFlags} parameter. - *

    - * The wake lock flags are: {@link #ACQUIRE_CAUSES_WAKEUP} - * and {@link #ON_AFTER_RELEASE}. Multiple flags can be combined as part of the - * {@code levelAndFlags} parameters. - *

    - * Call {@link WakeLock#acquire() acquire()} on the object to acquire the - * wake lock, and {@link WakeLock#release release()} when you are done. - *

    - * {@samplecode - * PowerManager pm = (PowerManager)mContext.getSystemService( - * Context.POWER_SERVICE); - * PowerManager.WakeLock wl = pm.newWakeLock( - * PowerManager.SCREEN_DIM_WAKE_LOCK - * | PowerManager.ON_AFTER_RELEASE, - * TAG); - * wl.acquire(); - * // ... do work... - * wl.release(); - * } - *

    - * Although a wake lock can be created without special permissions, - * the {@link android.Manifest.permission#WAKE_LOCK} permission is - * required to actually acquire or release the wake lock that is returned. - *

    - * If using this to keep the screen on, you should strongly consider using - * {@link android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON} instead. - * This window flag will be correctly managed by the platform - * as the user moves between applications and doesn't require a special permission. - *

    - * - * @param levelAndFlags Combination of wake lock level and flag values defining - * the requested behavior of the WakeLock. - * @param tag Your class name (or other tag) for debugging purposes. - * - * @see WakeLock#acquire() - * @see WakeLock#release() - * @see #PARTIAL_WAKE_LOCK - * @see #FULL_WAKE_LOCK - * @see #SCREEN_DIM_WAKE_LOCK - * @see #SCREEN_BRIGHT_WAKE_LOCK - * @see #PROXIMITY_SCREEN_OFF_WAKE_LOCK - * @see #ACQUIRE_CAUSES_WAKEUP - * @see #ON_AFTER_RELEASE - */ - public WakeLock newWakeLock(int levelAndFlags, String tag) { - validateWakeLockParameters(levelAndFlags, tag); - return new WakeLock(levelAndFlags, tag, mContext.getOpPackageName()); - } - - /** @hide */ - public static void validateWakeLockParameters(int levelAndFlags, String tag) { - switch (levelAndFlags & WAKE_LOCK_LEVEL_MASK) { - case PARTIAL_WAKE_LOCK: - case SCREEN_DIM_WAKE_LOCK: - case SCREEN_BRIGHT_WAKE_LOCK: - case FULL_WAKE_LOCK: - case PROXIMITY_SCREEN_OFF_WAKE_LOCK: - case DOZE_WAKE_LOCK: - break; - default: - throw new IllegalArgumentException("Must specify a valid wake lock level."); - } - if (tag == null) { - throw new IllegalArgumentException("The tag must not be null."); - } - } - - /** - * Notifies the power manager that user activity happened. - *

    - * Resets the auto-off timer and brightens the screen if the device - * is not asleep. This is what happens normally when a key or the touch - * screen is pressed or when some other user activity occurs. - * This method does not wake up the device if it has been put to sleep. - *

    - * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission. - *

    - * - * @param when The time of the user activity, in the {@link SystemClock#uptimeMillis()} - * time base. This timestamp is used to correctly order the user activity request with - * other power management functions. It should be set - * to the timestamp of the input event that caused the user activity. - * @param noChangeLights If true, does not cause the keyboard backlight to turn on - * because of this event. This is set when the power key is pressed. - * We want the device to stay on while the button is down, but we're about - * to turn off the screen so we don't want the keyboard backlight to turn on again. - * Otherwise the lights flash on and then off and it looks weird. - * - * @see #wakeUp - * @see #goToSleep - * - * @removed Requires signature or system permission. - * @deprecated Use {@link #userActivity(long, int, int)}. - */ - @Deprecated - public void userActivity(long when, boolean noChangeLights) { - userActivity(when, USER_ACTIVITY_EVENT_OTHER, - noChangeLights ? USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS : 0); - } - - /** - * Notifies the power manager that user activity happened. - *

    - * Resets the auto-off timer and brightens the screen if the device - * is not asleep. This is what happens normally when a key or the touch - * screen is pressed or when some other user activity occurs. - * This method does not wake up the device if it has been put to sleep. - *

    - * Requires the {@link android.Manifest.permission#DEVICE_POWER} or - * {@link android.Manifest.permission#USER_ACTIVITY} permission. - *

    - * - * @param when The time of the user activity, in the {@link SystemClock#uptimeMillis()} - * time base. This timestamp is used to correctly order the user activity request with - * other power management functions. It should be set - * to the timestamp of the input event that caused the user activity. - * @param event The user activity event. - * @param flags Optional user activity flags. - * - * @see #wakeUp - * @see #goToSleep - * - * @hide Requires signature or system permission. - */ - @SystemApi - public void userActivity(long when, int event, int flags) { - try { - mService.userActivity(when, event, flags); - } catch (RemoteException e) { - } - } - - /** - * Forces the device to go to sleep. - *

    - * Overrides all the wake locks that are held. - * This is what happens when the power key is pressed to turn off the screen. - *

    - * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission. - *

    - * - * @param time The time when the request to go to sleep was issued, in the - * {@link SystemClock#uptimeMillis()} time base. This timestamp is used to correctly - * order the go to sleep request with other power management functions. It should be set - * to the timestamp of the input event that caused the request to go to sleep. - * - * @see #userActivity - * @see #wakeUp - * - * @removed Requires signature permission. - */ - public void goToSleep(long time) { - goToSleep(time, GO_TO_SLEEP_REASON_APPLICATION, 0); - } - - /** - * Forces the device to go to sleep. - *

    - * Overrides all the wake locks that are held. - * This is what happens when the power key is pressed to turn off the screen. - *

    - * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission. - *

    - * - * @param time The time when the request to go to sleep was issued, in the - * {@link SystemClock#uptimeMillis()} time base. This timestamp is used to correctly - * order the go to sleep request with other power management functions. It should be set - * to the timestamp of the input event that caused the request to go to sleep. - * @param reason The reason the device is going to sleep. - * @param flags Optional flags to apply when going to sleep. - * - * @see #userActivity - * @see #wakeUp - * - * @hide Requires signature permission. - */ - public void goToSleep(long time, int reason, int flags) { - try { - mService.goToSleep(time, reason, flags); - } catch (RemoteException e) { - } - } - - /** - * Forces the device to wake up from sleep. - *

    - * If the device is currently asleep, wakes it up, otherwise does nothing. - * This is what happens when the power key is pressed to turn on the screen. - *

    - * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission. - *

    - * - * @param time The time when the request to wake up was issued, in the - * {@link SystemClock#uptimeMillis()} time base. This timestamp is used to correctly - * order the wake up request with other power management functions. It should be set - * to the timestamp of the input event that caused the request to wake up. - * - * @see #userActivity - * @see #goToSleep - * - * @removed Requires signature permission. - */ - public void wakeUp(long time) { - try { - mService.wakeUp(time); - } catch (RemoteException e) { - } - } - - /** - * Forces the device to start napping. - *

    - * If the device is currently awake, starts dreaming, otherwise does nothing. - * When the dream ends or if the dream cannot be started, the device will - * either wake up or go to sleep depending on whether there has been recent - * user activity. - *

    - * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission. - *

    - * - * @param time The time when the request to nap was issued, in the - * {@link SystemClock#uptimeMillis()} time base. This timestamp is used to correctly - * order the nap request with other power management functions. It should be set - * to the timestamp of the input event that caused the request to nap. - * - * @see #wakeUp - * @see #goToSleep - * - * @hide Requires signature permission. - */ - public void nap(long time) { - try { - mService.nap(time); - } catch (RemoteException e) { - } - } - - /** - * Boosts the brightness of the screen to maximum for a predetermined - * period of time. This is used to make the screen more readable in bright - * daylight for a short duration. - *

    - * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission. - *

    - * - * @param time The time when the request to boost was issued, in the - * {@link SystemClock#uptimeMillis()} time base. This timestamp is used to correctly - * order the boost request with other power management functions. It should be set - * to the timestamp of the input event that caused the request to boost. - * - * @hide Requires signature permission. - */ - public void boostScreenBrightness(long time) { - try { - mService.boostScreenBrightness(time); - } catch (RemoteException e) { - } - } - - /** - * Sets the brightness of the backlights (screen, keyboard, button). - *

    - * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission. - *

    - * - * @param brightness The brightness value from 0 to 255. - * - * @hide Requires signature permission. - */ - public void setBacklightBrightness(int brightness) { - try { - mService.setTemporaryScreenBrightnessSettingOverride(brightness); - } catch (RemoteException e) { - } - } - - /** - * Returns true if the specified wake lock level is supported. - * - * @param level The wake lock level to check. - * @return True if the specified wake lock level is supported. - */ - public boolean isWakeLockLevelSupported(int level) { - try { - return mService.isWakeLockLevelSupported(level); - } catch (RemoteException e) { - return false; - } - } - - /** - * Returns true if the device is in an interactive state. - *

    - * For historical reasons, the name of this method refers to the power state of - * the screen but it actually describes the overall interactive state of - * the device. This method has been replaced by {@link #isInteractive}. - *

    - * The value returned by this method only indicates whether the device is - * in an interactive state which may have nothing to do with the screen being - * on or off. To determine the actual state of the screen, - * use {@link android.view.Display#getState}. - *

    - * - * @return True if the device is in an interactive state. - * - * @deprecated Use {@link #isInteractive} instead. - */ - @Deprecated - public boolean isScreenOn() { - return isInteractive(); - } - - /** - * Returns true if the device is in an interactive state. - *

    - * When this method returns true, the device is awake and ready to interact - * with the user (although this is not a guarantee that the user is actively - * interacting with the device just this moment). The main screen is usually - * turned on while in this state. Certain features, such as the proximity - * sensor, may temporarily turn off the screen while still leaving the device in an - * interactive state. Note in particular that the device is still considered - * to be interactive while dreaming (since dreams can be interactive) but not - * when it is dozing or asleep. - *

    - * When this method returns false, the device is dozing or asleep and must - * be awoken before it will become ready to interact with the user again. The - * main screen is usually turned off while in this state. Certain features, - * such as "ambient mode" may cause the main screen to remain on (albeit in a - * low power state) to display system-provided content while the device dozes. - *

    - * The system will send a {@link android.content.Intent#ACTION_SCREEN_ON screen on} - * or {@link android.content.Intent#ACTION_SCREEN_OFF screen off} broadcast - * whenever the interactive state of the device changes. For historical reasons, - * the names of these broadcasts refer to the power state of the screen - * but they are actually sent in response to changes in the overall interactive - * state of the device, as described by this method. - *

    - * Services may use the non-interactive state as a hint to conserve power - * since the user is not present. - *

    - * - * @return True if the device is in an interactive state. - * - * @see android.content.Intent#ACTION_SCREEN_ON - * @see android.content.Intent#ACTION_SCREEN_OFF - */ - public boolean isInteractive() { - try { - return mService.isInteractive(); - } catch (RemoteException e) { - return false; - } - } - - /** - * Reboot the device. Will not return if the reboot is successful. - *

    - * Requires the {@link android.Manifest.permission#REBOOT} permission. - *

    - * - * @param reason code to pass to the kernel (e.g., "recovery") to - * request special boot modes, or null. - */ - public void reboot(String reason) { - try { - mService.reboot(false, reason, true); - } catch (RemoteException e) { - } - } - - /** - * Returns true if the device is currently in power save mode. When in this mode, - * applications should reduce their functionality in order to conserve battery as - * much as possible. You can monitor for changes to this state with - * {@link #ACTION_POWER_SAVE_MODE_CHANGED}. - * - * @return Returns true if currently in low power mode, else false. - */ - public boolean isPowerSaveMode() { - try { - return mService.isPowerSaveMode(); - } catch (RemoteException e) { - return false; - } - } - - /** - * Set the current power save mode. - * - * @return True if the set was allowed. - * - * @see #isPowerSaveMode() - * - * @hide - */ - public boolean setPowerSaveMode(boolean mode) { - try { - return mService.setPowerSaveMode(mode); - } catch (RemoteException e) { - return false; - } - } - - /** - * Intent that is broadcast when the state of {@link #isPowerSaveMode()} changes. - * This broadcast is only sent to registered receivers. - */ - @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_POWER_SAVE_MODE_CHANGED - = "android.os.action.POWER_SAVE_MODE_CHANGED"; - - /** - * Intent that is broadcast when the state of {@link #isPowerSaveMode()} is about to change. - * This broadcast is only sent to registered receivers. - * - * @hide - */ - @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_POWER_SAVE_MODE_CHANGING - = "android.os.action.POWER_SAVE_MODE_CHANGING"; - - /** @hide */ - public static final String EXTRA_POWER_SAVE_MODE = "mode"; - - /** - * A wake lock is a mechanism to indicate that your application needs - * to have the device stay on. - *

    - * Any application using a WakeLock must request the {@code android.permission.WAKE_LOCK} - * permission in an {@code <uses-permission>} element of the application's manifest. - * Obtain a wake lock by calling {@link PowerManager#newWakeLock(int, String)}. - *

    - * Call {@link #acquire()} to acquire the wake lock and force the device to stay - * on at the level that was requested when the wake lock was created. - *

    - * Call {@link #release()} when you are done and don't need the lock anymore. - * It is very important to do this as soon as possible to avoid running down the - * device's battery excessively. - *

    - */ - public final class WakeLock { - private int mFlags; - private String mTag; - private final String mPackageName; - private final IBinder mToken; - private int mCount; - private boolean mRefCounted = true; - private boolean mHeld; - private WorkSource mWorkSource; - private String mHistoryTag; - private final String mTraceName; - - private final Runnable mReleaser = new Runnable() { - public void run() { - release(); - } - }; - - WakeLock(int flags, String tag, String packageName) { - mFlags = flags; - mTag = tag; - mPackageName = packageName; - mToken = new Binder(); - mTraceName = "WakeLock (" + mTag + ")"; - } - - @Override - protected void finalize() throws Throwable { - synchronized (mToken) { - if (mHeld) { - Log.wtf(TAG, "WakeLock finalized while still held: " + mTag); - Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, mTraceName, 0); - try { - mService.releaseWakeLock(mToken, 0); - } catch (RemoteException e) { - } - } - } - } - - /** - * Sets whether this WakeLock is reference counted. - *

    - * Wake locks are reference counted by default. If a wake lock is - * reference counted, then each call to {@link #acquire()} must be - * balanced by an equal number of calls to {@link #release()}. If a wake - * lock is not reference counted, then one call to {@link #release()} is - * sufficient to undo the effect of all previous calls to {@link #acquire()}. - *

    - * - * @param value True to make the wake lock reference counted, false to - * make the wake lock non-reference counted. - */ - public void setReferenceCounted(boolean value) { - synchronized (mToken) { - mRefCounted = value; - } - } - - /** - * Acquires the wake lock. - *

    - * Ensures that the device is on at the level requested when - * the wake lock was created. - *

    - */ - public void acquire() { - synchronized (mToken) { - acquireLocked(); - } - } - - /** - * Acquires the wake lock with a timeout. - *

    - * Ensures that the device is on at the level requested when - * the wake lock was created. The lock will be released after the given timeout - * expires. - *

    - * - * @param timeout The timeout after which to release the wake lock, in milliseconds. - */ - public void acquire(long timeout) { - synchronized (mToken) { - acquireLocked(); - mHandler.postDelayed(mReleaser, timeout); - } - } - - private void acquireLocked() { - if (!mRefCounted || mCount++ == 0) { - // Do this even if the wake lock is already thought to be held (mHeld == true) - // because non-reference counted wake locks are not always properly released. - // For example, the keyguard's wake lock might be forcibly released by the - // power manager without the keyguard knowing. A subsequent call to acquire - // should immediately acquire the wake lock once again despite never having - // been explicitly released by the keyguard. - mHandler.removeCallbacks(mReleaser); - Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, mTraceName, 0); - try { - mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource, - mHistoryTag); - } catch (RemoteException e) { - } - mHeld = true; - } - } - - /** - * Releases the wake lock. - *

    - * This method releases your claim to the CPU or screen being on. - * The screen may turn off shortly after you release the wake lock, or it may - * not if there are other wake locks still held. - *

    - */ - public void release() { - release(0); - } - - /** - * Releases the wake lock with flags to modify the release behavior. - *

    - * This method releases your claim to the CPU or screen being on. - * The screen may turn off shortly after you release the wake lock, or it may - * not if there are other wake locks still held. - *

    - * - * @param flags Combination of flag values to modify the release behavior. - * Currently only {@link #RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY} is supported. - * Passing 0 is equivalent to calling {@link #release()}. - */ - public void release(int flags) { - synchronized (mToken) { - if (!mRefCounted || --mCount == 0) { - mHandler.removeCallbacks(mReleaser); - if (mHeld) { - Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, mTraceName, 0); - try { - mService.releaseWakeLock(mToken, flags); - } catch (RemoteException e) { - } - mHeld = false; - } - } - if (mCount < 0) { - throw new RuntimeException("WakeLock under-locked " + mTag); - } - } - } - - /** - * Returns true if the wake lock has been acquired but not yet released. - * - * @return True if the wake lock is held. - */ - public boolean isHeld() { - synchronized (mToken) { - return mHeld; - } - } - - /** - * Sets the work source associated with the wake lock. - *

    - * The work source is used to determine on behalf of which application - * the wake lock is being held. This is useful in the case where a - * service is performing work on behalf of an application so that the - * cost of that work can be accounted to the application. - *

    - * - * @param ws The work source, or null if none. - */ - public void setWorkSource(WorkSource ws) { - synchronized (mToken) { - if (ws != null && ws.size() == 0) { - ws = null; - } - - final boolean changed; - if (ws == null) { - changed = mWorkSource != null; - mWorkSource = null; - } else if (mWorkSource == null) { - changed = true; - mWorkSource = new WorkSource(ws); - } else { - changed = mWorkSource.diff(ws); - if (changed) { - mWorkSource.set(ws); - } - } - - if (changed && mHeld) { - try { - mService.updateWakeLockWorkSource(mToken, mWorkSource, mHistoryTag); - } catch (RemoteException e) { - } - } - } - } - - /** @hide */ - public void setTag(String tag) { - mTag = tag; - } - - /** @hide */ - public void setHistoryTag(String tag) { - mHistoryTag = tag; - } - - /** @hide */ - public void setUnimportantForLogging(boolean state) { - if (state) mFlags |= UNIMPORTANT_FOR_LOGGING; - else mFlags &= ~UNIMPORTANT_FOR_LOGGING; - } - - @Override - public String toString() { - synchronized (mToken) { - return "WakeLock{" - + Integer.toHexString(System.identityHashCode(this)) - + " held=" + mHeld + ", refCount=" + mCount + "}"; - } - } - } -} diff --git a/src/main/java/android/os/PowerManagerInternal.java b/src/main/java/android/os/PowerManagerInternal.java deleted file mode 100644 index 6f31768..0000000 --- a/src/main/java/android/os/PowerManagerInternal.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.view.Display; - -/** - * Power manager local system service interface. - * - * @hide Only for use within the system server. - */ -public abstract class PowerManagerInternal { - /** - * Wakefulness: The device is asleep. It can only be awoken by a call to wakeUp(). - * The screen should be off or in the process of being turned off by the display controller. - * The device typically passes through the dozing state first. - */ - public static final int WAKEFULNESS_ASLEEP = 0; - - /** - * Wakefulness: The device is fully awake. It can be put to sleep by a call to goToSleep(). - * When the user activity timeout expires, the device may start dreaming or go to sleep. - */ - public static final int WAKEFULNESS_AWAKE = 1; - - /** - * Wakefulness: The device is dreaming. It can be awoken by a call to wakeUp(), - * which ends the dream. The device goes to sleep when goToSleep() is called, when - * the dream ends or when unplugged. - * User activity may brighten the screen but does not end the dream. - */ - public static final int WAKEFULNESS_DREAMING = 2; - - /** - * Wakefulness: The device is dozing. It is almost asleep but is allowing a special - * low-power "doze" dream to run which keeps the display on but lets the application - * processor be suspended. It can be awoken by a call to wakeUp() which ends the dream. - * The device fully goes to sleep if the dream cannot be started or ends on its own. - */ - public static final int WAKEFULNESS_DOZING = 3; - - public static String wakefulnessToString(int wakefulness) { - switch (wakefulness) { - case WAKEFULNESS_ASLEEP: - return "Asleep"; - case WAKEFULNESS_AWAKE: - return "Awake"; - case WAKEFULNESS_DREAMING: - return "Dreaming"; - case WAKEFULNESS_DOZING: - return "Dozing"; - default: - return Integer.toString(wakefulness); - } - } - - /** - * Returns true if the wakefulness state represents an interactive state - * as defined by {@link android.os.PowerManager#isInteractive}. - */ - public static boolean isInteractive(int wakefulness) { - return wakefulness == WAKEFULNESS_AWAKE || wakefulness == WAKEFULNESS_DREAMING; - } - - /** - * Used by the window manager to override the screen brightness based on the - * current foreground activity. - * - * This method must only be called by the window manager. - * - * @param brightness The overridden brightness, or -1 to disable the override. - */ - public abstract void setScreenBrightnessOverrideFromWindowManager(int brightness); - - /** - * Used by the window manager to override the button brightness based on the - * current foreground activity. - * - * This method must only be called by the window manager. - * - * @param brightness The overridden brightness, or -1 to disable the override. - */ - public abstract void setButtonBrightnessOverrideFromWindowManager(int brightness); - - /** - * Used by the window manager to override the user activity timeout based on the - * current foreground activity. It can only be used to make the timeout shorter - * than usual, not longer. - * - * This method must only be called by the window manager. - * - * @param timeoutMillis The overridden timeout, or -1 to disable the override. - */ - public abstract void setUserActivityTimeoutOverrideFromWindowManager(long timeoutMillis); - - /** - * Used by device administration to set the maximum screen off timeout. - * - * This method must only be called by the device administration policy manager. - */ - public abstract void setMaximumScreenOffTimeoutFromDeviceAdmin(int timeMs); - - /** - * Used by the dream manager to override certain properties while dozing. - * - * @param screenState The overridden screen state, or {@link Display.STATE_UNKNOWN} - * to disable the override. - * @param screenBrightness The overridden screen brightness, or - * {@link PowerManager#BRIGHTNESS_DEFAULT} to disable the override. - */ - public abstract void setDozeOverrideFromDreamManager( - int screenState, int screenBrightness); - - public abstract boolean getLowPowerModeEnabled(); - - public abstract void registerLowPowerModeObserver(LowPowerModeListener listener); - - public interface LowPowerModeListener { - public void onLowPowerModeChanged(boolean enabled); - } -} diff --git a/src/main/java/android/os/PowerManagerTest.java b/src/main/java/android/os/PowerManagerTest.java deleted file mode 100644 index 9893c16..0000000 --- a/src/main/java/android/os/PowerManagerTest.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.content.Context; -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; - -public class PowerManagerTest extends AndroidTestCase { - - private PowerManager mPm; - - /** - * Setup any common data for the upcoming tests. - */ - @Override - public void setUp() throws Exception { - super.setUp(); - mPm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); - } - - /** - * Confirm that the setup is good. - * - * @throws Exception - */ - @SmallTest - public void testPreconditions() throws Exception { - assertNotNull(mPm); - } - - /** - * Confirm that we can create functional wakelocks. - * - * @throws Exception - */ - @SmallTest - public void testNewWakeLock() throws Exception { - PowerManager.WakeLock wl = mPm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "FULL_WAKE_LOCK"); - doTestWakeLock(wl); - - wl = mPm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "SCREEN_BRIGHT_WAKE_LOCK"); - doTestWakeLock(wl); - - wl = mPm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "SCREEN_DIM_WAKE_LOCK"); - doTestWakeLock(wl); - - wl = mPm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "PARTIAL_WAKE_LOCK"); - doTestWakeLock(wl); - - doTestSetBacklightBrightness(); - - // TODO: Some sort of functional test (maybe not in the unit test here?) - // that confirms that things are really happening e.g. screen power, keyboard power. -} - - /** - * Confirm that we can't create dysfunctional wakelocks. - * - * @throws Exception - */ - @SmallTest - public void testBadNewWakeLock() throws Exception { - - final int badFlags = PowerManager.SCREEN_BRIGHT_WAKE_LOCK - | PowerManager.SCREEN_DIM_WAKE_LOCK; - // wrap in try because we want the error here - try { - PowerManager.WakeLock wl = mPm.newWakeLock(badFlags, "foo"); - } catch (IllegalArgumentException e) { - return; - } - fail("Bad WakeLock flag was not caught."); - } - - /** - * Apply a few tests to a wakelock to make sure it's healthy. - * - * @param wl The wakelock to be tested. - */ - private void doTestWakeLock(PowerManager.WakeLock wl) { - // First try simple acquire/release - wl.acquire(); - assertTrue(wl.isHeld()); - wl.release(); - assertFalse(wl.isHeld()); - - // Try ref-counted acquire/release - wl.setReferenceCounted(true); - wl.acquire(); - assertTrue(wl.isHeld()); - wl.acquire(); - assertTrue(wl.isHeld()); - wl.release(); - assertTrue(wl.isHeld()); - wl.release(); - assertFalse(wl.isHeld()); - - // Try non-ref-counted - wl.setReferenceCounted(false); - wl.acquire(); - assertTrue(wl.isHeld()); - wl.acquire(); - assertTrue(wl.isHeld()); - wl.release(); - assertFalse(wl.isHeld()); - - // TODO: Threaded test (needs handler) to make sure timed wakelocks work too - } - - - /** - * Test that calling {@link android.os.IHardwareService#setBacklights(int)} requires - * permissions. - *

    Tests permission: - * {@link android.Manifest.permission#DEVICE_POWER} - */ - private void doTestSetBacklightBrightness() { - try { - mPm.setBacklightBrightness(0); - fail("setBacklights did not throw SecurityException as expected"); - } catch (SecurityException e) { - // expected - } - } - -} diff --git a/src/main/java/android/os/Process.java b/src/main/java/android/os/Process.java deleted file mode 100644 index 21a9904..0000000 --- a/src/main/java/android/os/Process.java +++ /dev/null @@ -1,1144 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.net.LocalSocket; -import android.net.LocalSocketAddress; -import android.system.Os; -import android.util.Log; -import com.android.internal.os.Zygote; -import java.io.BufferedWriter; -import java.io.DataInputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/*package*/ class ZygoteStartFailedEx extends Exception { - ZygoteStartFailedEx(String s) { - super(s); - } - - ZygoteStartFailedEx(Throwable cause) { - super(cause); - } - - ZygoteStartFailedEx(String s, Throwable cause) { - super(s, cause); - } -} - -/** - * Tools for managing OS processes. - */ -public class Process { - private static final String LOG_TAG = "Process"; - - /** - * @hide for internal use only. - */ - public static final String ZYGOTE_SOCKET = "zygote"; - - /** - * @hide for internal use only. - */ - public static final String SECONDARY_ZYGOTE_SOCKET = "zygote_secondary"; - - /** - * Defines the root UID. - * @hide - */ - public static final int ROOT_UID = 0; - - /** - * Defines the UID/GID under which system code runs. - */ - public static final int SYSTEM_UID = 1000; - - /** - * Defines the UID/GID under which the telephony code runs. - */ - public static final int PHONE_UID = 1001; - - /** - * Defines the UID/GID for the user shell. - * @hide - */ - public static final int SHELL_UID = 2000; - - /** - * Defines the UID/GID for the log group. - * @hide - */ - public static final int LOG_UID = 1007; - - /** - * Defines the UID/GID for the WIFI supplicant process. - * @hide - */ - public static final int WIFI_UID = 1010; - - /** - * Defines the UID/GID for the mediaserver process. - * @hide - */ - public static final int MEDIA_UID = 1013; - - /** - * Defines the UID/GID for the DRM process. - * @hide - */ - public static final int DRM_UID = 1019; - - /** - * Defines the UID/GID for the group that controls VPN services. - * @hide - */ - public static final int VPN_UID = 1016; - - /** - * Defines the UID/GID for the NFC service process. - * @hide - */ - public static final int NFC_UID = 1027; - - /** - * Defines the UID/GID for the Bluetooth service process. - * @hide - */ - public static final int BLUETOOTH_UID = 1002; - - /** - * Defines the GID for the group that allows write access to the internal media storage. - * @hide - */ - public static final int MEDIA_RW_GID = 1023; - - /** - * Access to installed package details - * @hide - */ - public static final int PACKAGE_INFO_GID = 1032; - - /** - * Defines the UID/GID for the shared RELRO file updater process. - * @hide - */ - public static final int SHARED_RELRO_UID = 1037; - - /** - * Defines the start of a range of UIDs (and GIDs), going from this - * number to {@link #LAST_APPLICATION_UID} that are reserved for assigning - * to applications. - */ - public static final int FIRST_APPLICATION_UID = 10000; - - /** - * Last of application-specific UIDs starting at - * {@link #FIRST_APPLICATION_UID}. - */ - public static final int LAST_APPLICATION_UID = 19999; - - /** - * First uid used for fully isolated sandboxed processes (with no permissions of their own) - * @hide - */ - public static final int FIRST_ISOLATED_UID = 99000; - - /** - * Last uid used for fully isolated sandboxed processes (with no permissions of their own) - * @hide - */ - public static final int LAST_ISOLATED_UID = 99999; - - /** - * Defines the gid shared by all applications running under the same profile. - * @hide - */ - public static final int SHARED_USER_GID = 9997; - - /** - * First gid for applications to share resources. Used when forward-locking - * is enabled but all UserHandles need to be able to read the resources. - * @hide - */ - public static final int FIRST_SHARED_APPLICATION_GID = 50000; - - /** - * Last gid for applications to share resources. Used when forward-locking - * is enabled but all UserHandles need to be able to read the resources. - * @hide - */ - public static final int LAST_SHARED_APPLICATION_GID = 59999; - - /** - * Standard priority of application threads. - * Use with {@link #setThreadPriority(int)} and - * {@link #setThreadPriority(int, int)}, not with the normal - * {@link java.lang.Thread} class. - */ - public static final int THREAD_PRIORITY_DEFAULT = 0; - - /* - * *************************************** - * ** Keep in sync with utils/threads.h ** - * *************************************** - */ - - /** - * Lowest available thread priority. Only for those who really, really - * don't want to run if anything else is happening. - * Use with {@link #setThreadPriority(int)} and - * {@link #setThreadPriority(int, int)}, not with the normal - * {@link java.lang.Thread} class. - */ - public static final int THREAD_PRIORITY_LOWEST = 19; - - /** - * Standard priority background threads. This gives your thread a slightly - * lower than normal priority, so that it will have less chance of impacting - * the responsiveness of the user interface. - * Use with {@link #setThreadPriority(int)} and - * {@link #setThreadPriority(int, int)}, not with the normal - * {@link java.lang.Thread} class. - */ - public static final int THREAD_PRIORITY_BACKGROUND = 10; - - /** - * Standard priority of threads that are currently running a user interface - * that the user is interacting with. Applications can not normally - * change to this priority; the system will automatically adjust your - * application threads as the user moves through the UI. - * Use with {@link #setThreadPriority(int)} and - * {@link #setThreadPriority(int, int)}, not with the normal - * {@link java.lang.Thread} class. - */ - public static final int THREAD_PRIORITY_FOREGROUND = -2; - - /** - * Standard priority of system display threads, involved in updating - * the user interface. Applications can not - * normally change to this priority. - * Use with {@link #setThreadPriority(int)} and - * {@link #setThreadPriority(int, int)}, not with the normal - * {@link java.lang.Thread} class. - */ - public static final int THREAD_PRIORITY_DISPLAY = -4; - - /** - * Standard priority of the most important display threads, for compositing - * the screen and retrieving input events. Applications can not normally - * change to this priority. - * Use with {@link #setThreadPriority(int)} and - * {@link #setThreadPriority(int, int)}, not with the normal - * {@link java.lang.Thread} class. - */ - public static final int THREAD_PRIORITY_URGENT_DISPLAY = -8; - - /** - * Standard priority of audio threads. Applications can not normally - * change to this priority. - * Use with {@link #setThreadPriority(int)} and - * {@link #setThreadPriority(int, int)}, not with the normal - * {@link java.lang.Thread} class. - */ - public static final int THREAD_PRIORITY_AUDIO = -16; - - /** - * Standard priority of the most important audio threads. - * Applications can not normally change to this priority. - * Use with {@link #setThreadPriority(int)} and - * {@link #setThreadPriority(int, int)}, not with the normal - * {@link java.lang.Thread} class. - */ - public static final int THREAD_PRIORITY_URGENT_AUDIO = -19; - - /** - * Minimum increment to make a priority more favorable. - */ - public static final int THREAD_PRIORITY_MORE_FAVORABLE = -1; - - /** - * Minimum increment to make a priority less favorable. - */ - public static final int THREAD_PRIORITY_LESS_FAVORABLE = +1; - - /** - * Default scheduling policy - * @hide - */ - public static final int SCHED_OTHER = 0; - - /** - * First-In First-Out scheduling policy - * @hide - */ - public static final int SCHED_FIFO = 1; - - /** - * Round-Robin scheduling policy - * @hide - */ - public static final int SCHED_RR = 2; - - /** - * Batch scheduling policy - * @hide - */ - public static final int SCHED_BATCH = 3; - - /** - * Idle scheduling policy - * @hide - */ - public static final int SCHED_IDLE = 5; - - // Keep in sync with SP_* constants of enum type SchedPolicy - // declared in system/core/include/cutils/sched_policy.h, - // except THREAD_GROUP_DEFAULT does not correspond to any SP_* value. - - /** - * Default thread group - - * has meaning with setProcessGroup() only, cannot be used with setThreadGroup(). - * When used with setProcessGroup(), the group of each thread in the process - * is conditionally changed based on that thread's current priority, as follows: - * threads with priority numerically less than THREAD_PRIORITY_BACKGROUND - * are moved to foreground thread group. All other threads are left unchanged. - * @hide - */ - public static final int THREAD_GROUP_DEFAULT = -1; - - /** - * Background thread group - All threads in - * this group are scheduled with a reduced share of the CPU. - * Value is same as constant SP_BACKGROUND of enum SchedPolicy. - * FIXME rename to THREAD_GROUP_BACKGROUND. - * @hide - */ - public static final int THREAD_GROUP_BG_NONINTERACTIVE = 0; - - /** - * Foreground thread group - All threads in - * this group are scheduled with a normal share of the CPU. - * Value is same as constant SP_FOREGROUND of enum SchedPolicy. - * Not used at this level. - * @hide - **/ - private static final int THREAD_GROUP_FOREGROUND = 1; - - /** - * System thread group. - * @hide - **/ - public static final int THREAD_GROUP_SYSTEM = 2; - - /** - * Application audio thread group. - * @hide - **/ - public static final int THREAD_GROUP_AUDIO_APP = 3; - - /** - * System audio thread group. - * @hide - **/ - public static final int THREAD_GROUP_AUDIO_SYS = 4; - - public static final int SIGNAL_QUIT = 3; - public static final int SIGNAL_KILL = 9; - public static final int SIGNAL_USR1 = 10; - - /** - * State for communicating with the zygote process. - * - * @hide for internal use only. - */ - public static class ZygoteState { - final LocalSocket socket; - final DataInputStream inputStream; - final BufferedWriter writer; - final List abiList; - - boolean mClosed; - - private ZygoteState(LocalSocket socket, DataInputStream inputStream, - BufferedWriter writer, List abiList) { - this.socket = socket; - this.inputStream = inputStream; - this.writer = writer; - this.abiList = abiList; - } - - public static ZygoteState connect(String socketAddress) throws IOException { - DataInputStream zygoteInputStream = null; - BufferedWriter zygoteWriter = null; - final LocalSocket zygoteSocket = new LocalSocket(); - - try { - zygoteSocket.connect(new LocalSocketAddress(socketAddress, - LocalSocketAddress.Namespace.RESERVED)); - - zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream()); - - zygoteWriter = new BufferedWriter(new OutputStreamWriter( - zygoteSocket.getOutputStream()), 256); - } catch (IOException ex) { - try { - zygoteSocket.close(); - } catch (IOException ignore) { - } - - throw ex; - } - - String abiListString = getAbiList(zygoteWriter, zygoteInputStream); - Log.i("Zygote", "Process: zygote socket opened, supported ABIS: " + abiListString); - - return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter, - Arrays.asList(abiListString.split(","))); - } - - boolean matches(String abi) { - return abiList.contains(abi); - } - - public void close() { - try { - socket.close(); - } catch (IOException ex) { - Log.e(LOG_TAG,"I/O exception on routine close", ex); - } - - mClosed = true; - } - - boolean isClosed() { - return mClosed; - } - } - - /** - * The state of the connection to the primary zygote. - */ - static ZygoteState primaryZygoteState; - - /** - * The state of the connection to the secondary zygote. - */ - static ZygoteState secondaryZygoteState; - - /** - * Start a new process. - * - *

    If processes are enabled, a new process is created and the - * static main() function of a processClass is executed there. - * The process will continue running after this function returns. - * - *

    If processes are not enabled, a new thread in the caller's - * process is created and main() of processClass called there. - * - *

    The niceName parameter, if not an empty string, is a custom name to - * give to the process instead of using processClass. This allows you to - * make easily identifyable processes even if you are using the same base - * processClass to start them. - * - * @param processClass The class to use as the process's main entry - * point. - * @param niceName A more readable name to use for the process. - * @param uid The user-id under which the process will run. - * @param gid The group-id under which the process will run. - * @param gids Additional group-ids associated with the process. - * @param debugFlags Additional flags. - * @param targetSdkVersion The target SDK version for the app. - * @param seInfo null-ok SELinux information for the new process. - * @param abi non-null the ABI this app should be started with. - * @param instructionSet null-ok the instruction set to use. - * @param appDataDir null-ok the data directory of the app. - * @param zygoteArgs Additional arguments to supply to the zygote process. - * - * @return An object that describes the result of the attempt to start the process. - * @throws RuntimeException on fatal start failure - * - * {@hide} - */ - public static final ProcessStartResult start(final String processClass, - final String niceName, - int uid, int gid, int[] gids, - int debugFlags, int mountExternal, - int targetSdkVersion, - String seInfo, - String abi, - String instructionSet, - String appDataDir, - String[] zygoteArgs) { - try { - return startViaZygote(processClass, niceName, uid, gid, gids, - debugFlags, mountExternal, targetSdkVersion, seInfo, - abi, instructionSet, appDataDir, zygoteArgs); - } catch (ZygoteStartFailedEx ex) { - Log.e(LOG_TAG, - "Starting VM process through Zygote failed"); - throw new RuntimeException( - "Starting VM process through Zygote failed", ex); - } - } - - /** retry interval for opening a zygote socket */ - static final int ZYGOTE_RETRY_MILLIS = 500; - - /** - * Queries the zygote for the list of ABIS it supports. - * - * @throws ZygoteStartFailedEx if the query failed. - */ - private static String getAbiList(BufferedWriter writer, DataInputStream inputStream) - throws IOException { - // Each query starts with the argument count (1 in this case) - writer.write("1"); - // ... followed by a new-line. - writer.newLine(); - // ... followed by our only argument. - writer.write("--query-abi-list"); - writer.newLine(); - writer.flush(); - - // The response is a length prefixed stream of ASCII bytes. - int numBytes = inputStream.readInt(); - byte[] bytes = new byte[numBytes]; - inputStream.readFully(bytes); - - return new String(bytes, StandardCharsets.US_ASCII); - } - - /** - * Sends an argument list to the zygote process, which starts a new child - * and returns the child's pid. Please note: the present implementation - * replaces newlines in the argument list with spaces. - * - * @throws ZygoteStartFailedEx if process start failed for any reason - */ - private static ProcessStartResult zygoteSendArgsAndGetResult( - ZygoteState zygoteState, ArrayList args) - throws ZygoteStartFailedEx { - try { - /** - * See com.android.internal.os.ZygoteInit.readArgumentList() - * Presently the wire format to the zygote process is: - * a) a count of arguments (argc, in essence) - * b) a number of newline-separated argument strings equal to count - * - * After the zygote process reads these it will write the pid of - * the child or -1 on failure, followed by boolean to - * indicate whether a wrapper process was used. - */ - final BufferedWriter writer = zygoteState.writer; - final DataInputStream inputStream = zygoteState.inputStream; - - writer.write(Integer.toString(args.size())); - writer.newLine(); - - int sz = args.size(); - for (int i = 0; i < sz; i++) { - String arg = args.get(i); - if (arg.indexOf('\n') >= 0) { - throw new ZygoteStartFailedEx( - "embedded newlines not allowed"); - } - writer.write(arg); - writer.newLine(); - } - - writer.flush(); - - // Should there be a timeout on this? - ProcessStartResult result = new ProcessStartResult(); - result.pid = inputStream.readInt(); - if (result.pid < 0) { - throw new ZygoteStartFailedEx("fork() failed"); - } - result.usingWrapper = inputStream.readBoolean(); - return result; - } catch (IOException ex) { - zygoteState.close(); - throw new ZygoteStartFailedEx(ex); - } - } - - /** - * Starts a new process via the zygote mechanism. - * - * @param processClass Class name whose static main() to run - * @param niceName 'nice' process name to appear in ps - * @param uid a POSIX uid that the new process should setuid() to - * @param gid a POSIX gid that the new process shuold setgid() to - * @param gids null-ok; a list of supplementary group IDs that the - * new process should setgroup() to. - * @param debugFlags Additional flags. - * @param targetSdkVersion The target SDK version for the app. - * @param seInfo null-ok SELinux information for the new process. - * @param abi the ABI the process should use. - * @param instructionSet null-ok the instruction set to use. - * @param appDataDir null-ok the data directory of the app. - * @param extraArgs Additional arguments to supply to the zygote process. - * @return An object that describes the result of the attempt to start the process. - * @throws ZygoteStartFailedEx if process start failed for any reason - */ - private static ProcessStartResult startViaZygote(final String processClass, - final String niceName, - final int uid, final int gid, - final int[] gids, - int debugFlags, int mountExternal, - int targetSdkVersion, - String seInfo, - String abi, - String instructionSet, - String appDataDir, - String[] extraArgs) - throws ZygoteStartFailedEx { - synchronized(Process.class) { - ArrayList argsForZygote = new ArrayList(); - - // --runtime-init, --setuid=, --setgid=, - // and --setgroups= must go first - argsForZygote.add("--runtime-init"); - argsForZygote.add("--setuid=" + uid); - argsForZygote.add("--setgid=" + gid); - if ((debugFlags & Zygote.DEBUG_ENABLE_JNI_LOGGING) != 0) { - argsForZygote.add("--enable-jni-logging"); - } - if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0) { - argsForZygote.add("--enable-safemode"); - } - if ((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) != 0) { - argsForZygote.add("--enable-debugger"); - } - if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) { - argsForZygote.add("--enable-checkjni"); - } - if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) { - argsForZygote.add("--enable-assert"); - } - if (mountExternal == Zygote.MOUNT_EXTERNAL_MULTIUSER) { - argsForZygote.add("--mount-external-multiuser"); - } else if (mountExternal == Zygote.MOUNT_EXTERNAL_MULTIUSER_ALL) { - argsForZygote.add("--mount-external-multiuser-all"); - } - argsForZygote.add("--target-sdk-version=" + targetSdkVersion); - - //TODO optionally enable debuger - //argsForZygote.add("--enable-debugger"); - - // --setgroups is a comma-separated list - if (gids != null && gids.length > 0) { - StringBuilder sb = new StringBuilder(); - sb.append("--setgroups="); - - int sz = gids.length; - for (int i = 0; i < sz; i++) { - if (i != 0) { - sb.append(','); - } - sb.append(gids[i]); - } - - argsForZygote.add(sb.toString()); - } - - if (niceName != null) { - argsForZygote.add("--nice-name=" + niceName); - } - - if (seInfo != null) { - argsForZygote.add("--seinfo=" + seInfo); - } - - if (instructionSet != null) { - argsForZygote.add("--instruction-set=" + instructionSet); - } - - if (appDataDir != null) { - argsForZygote.add("--app-data-dir=" + appDataDir); - } - - argsForZygote.add(processClass); - - if (extraArgs != null) { - for (String arg : extraArgs) { - argsForZygote.add(arg); - } - } - - return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote); - } - } - - /** - * Tries to establish a connection to the zygote that handles a given {@code abi}. Might block and retry if the - * zygote is unresponsive. This method is a no-op if a connection is already open. - * - * @hide - */ - public static void establishZygoteConnectionForAbi(String abi) { - try { - openZygoteSocketIfNeeded(abi); - } catch (ZygoteStartFailedEx ex) { - throw new RuntimeException("Unable to connect to zygote for abi: " + abi, ex); - } - } - - /** - * Tries to open socket to Zygote process if not already open. If - * already open, does nothing. May block and retry. - */ - private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx { - if (primaryZygoteState == null || primaryZygoteState.isClosed()) { - try { - primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET); - } catch (IOException ioe) { - throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe); - } - } - - if (primaryZygoteState.matches(abi)) { - return primaryZygoteState; - } - - // The primary zygote didn't match. Try the secondary. - if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) { - try { - secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET); - } catch (IOException ioe) { - throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe); - } - } - - if (secondaryZygoteState.matches(abi)) { - return secondaryZygoteState; - } - - throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi); - } - - /** - * Returns elapsed milliseconds of the time this process has run. - * @return Returns the number of milliseconds this process has return. - */ - public static final native long getElapsedCpuTime(); - - /** - * Returns the identifier of this process, which can be used with - * {@link #killProcess} and {@link #sendSignal}. - */ - public static final int myPid() { - return Os.getpid(); - } - - /** - * Returns the identifier of this process' parent. - * @hide - */ - public static final int myPpid() { - return Os.getppid(); - } - - /** - * Returns the identifier of the calling thread, which be used with - * {@link #setThreadPriority(int, int)}. - */ - public static final int myTid() { - return Os.gettid(); - } - - /** - * Returns the identifier of this process's uid. This is the kernel uid - * that the process is running under, which is the identity of its - * app-specific sandbox. It is different from {@link #myUserHandle} in that - * a uid identifies a specific app sandbox in a specific user. - */ - public static final int myUid() { - return Os.getuid(); - } - - /** - * Returns this process's user handle. This is the - * user the process is running under. It is distinct from - * {@link #myUid()} in that a particular user will have multiple - * distinct apps running under it each with their own uid. - */ - public static final UserHandle myUserHandle() { - return new UserHandle(UserHandle.getUserId(myUid())); - } - - /** - * Returns whether the current process is in an isolated sandbox. - * @hide - */ - public static final boolean isIsolated() { - int uid = UserHandle.getAppId(myUid()); - return uid >= FIRST_ISOLATED_UID && uid <= LAST_ISOLATED_UID; - } - - /** - * Returns the UID assigned to a particular user name, or -1 if there is - * none. If the given string consists of only numbers, it is converted - * directly to a uid. - */ - public static final native int getUidForName(String name); - - /** - * Returns the GID assigned to a particular user name, or -1 if there is - * none. If the given string consists of only numbers, it is converted - * directly to a gid. - */ - public static final native int getGidForName(String name); - - /** - * Returns a uid for a currently running process. - * @param pid the process id - * @return the uid of the process, or -1 if the process is not running. - * @hide pending API council review - */ - public static final int getUidForPid(int pid) { - String[] procStatusLabels = { "Uid:" }; - long[] procStatusValues = new long[1]; - procStatusValues[0] = -1; - Process.readProcLines("/proc/" + pid + "/status", procStatusLabels, procStatusValues); - return (int) procStatusValues[0]; - } - - /** - * Returns the parent process id for a currently running process. - * @param pid the process id - * @return the parent process id of the process, or -1 if the process is not running. - * @hide - */ - public static final int getParentPid(int pid) { - String[] procStatusLabels = { "PPid:" }; - long[] procStatusValues = new long[1]; - procStatusValues[0] = -1; - Process.readProcLines("/proc/" + pid + "/status", procStatusLabels, procStatusValues); - return (int) procStatusValues[0]; - } - - /** - * Returns the thread group leader id for a currently running thread. - * @param tid the thread id - * @return the thread group leader id of the thread, or -1 if the thread is not running. - * This is same as what getpid(2) would return if called by tid. - * @hide - */ - public static final int getThreadGroupLeader(int tid) { - String[] procStatusLabels = { "Tgid:" }; - long[] procStatusValues = new long[1]; - procStatusValues[0] = -1; - Process.readProcLines("/proc/" + tid + "/status", procStatusLabels, procStatusValues); - return (int) procStatusValues[0]; - } - - /** - * Set the priority of a thread, based on Linux priorities. - * - * @param tid The identifier of the thread/process to change. - * @param priority A Linux priority level, from -20 for highest scheduling - * priority to 19 for lowest scheduling priority. - * - * @throws IllegalArgumentException Throws IllegalArgumentException if - * tid does not exist. - * @throws SecurityException Throws SecurityException if your process does - * not have permission to modify the given thread, or to use the given - * priority. - */ - public static final native void setThreadPriority(int tid, int priority) - throws IllegalArgumentException, SecurityException; - - /** - * Call with 'false' to cause future calls to {@link #setThreadPriority(int)} to - * throw an exception if passed a background-level thread priority. This is only - * effective if the JNI layer is built with GUARD_THREAD_PRIORITY defined to 1. - * - * @hide - */ - public static final native void setCanSelfBackground(boolean backgroundOk); - - /** - * Sets the scheduling group for a thread. - * @hide - * @param tid The identifier of the thread to change. - * @param group The target group for this thread from THREAD_GROUP_*. - * - * @throws IllegalArgumentException Throws IllegalArgumentException if - * tid does not exist. - * @throws SecurityException Throws SecurityException if your process does - * not have permission to modify the given thread, or to use the given - * priority. - * If the thread is a thread group leader, that is it's gettid() == getpid(), - * then the other threads in the same thread group are _not_ affected. - */ - public static final native void setThreadGroup(int tid, int group) - throws IllegalArgumentException, SecurityException; - - /** - * Sets the scheduling group for a process and all child threads - * @hide - * @param pid The identifier of the process to change. - * @param group The target group for this process from THREAD_GROUP_*. - * - * @throws IllegalArgumentException Throws IllegalArgumentException if - * tid does not exist. - * @throws SecurityException Throws SecurityException if your process does - * not have permission to modify the given thread, or to use the given - * priority. - * - * group == THREAD_GROUP_DEFAULT means to move all non-background priority - * threads to the foreground scheduling group, but to leave background - * priority threads alone. group == THREAD_GROUP_BG_NONINTERACTIVE moves all - * threads, regardless of priority, to the background scheduling group. - * group == THREAD_GROUP_FOREGROUND is not allowed. - */ - public static final native void setProcessGroup(int pid, int group) - throws IllegalArgumentException, SecurityException; - - /** - * Return the scheduling group of requested process. - * - * @hide - */ - public static final native int getProcessGroup(int pid) - throws IllegalArgumentException, SecurityException; - - /** - * Set the priority of the calling thread, based on Linux priorities. See - * {@link #setThreadPriority(int, int)} for more information. - * - * @param priority A Linux priority level, from -20 for highest scheduling - * priority to 19 for lowest scheduling priority. - * - * @throws IllegalArgumentException Throws IllegalArgumentException if - * tid does not exist. - * @throws SecurityException Throws SecurityException if your process does - * not have permission to modify the given thread, or to use the given - * priority. - * - * @see #setThreadPriority(int, int) - */ - public static final native void setThreadPriority(int priority) - throws IllegalArgumentException, SecurityException; - - /** - * Return the current priority of a thread, based on Linux priorities. - * - * @param tid The identifier of the thread/process to change. - * - * @return Returns the current priority, as a Linux priority level, - * from -20 for highest scheduling priority to 19 for lowest scheduling - * priority. - * - * @throws IllegalArgumentException Throws IllegalArgumentException if - * tid does not exist. - */ - public static final native int getThreadPriority(int tid) - throws IllegalArgumentException; - - /** - * Set the scheduling policy and priority of a thread, based on Linux. - * - * @param tid The identifier of the thread/process to change. - * @param policy A Linux scheduling policy such as SCHED_OTHER etc. - * @param priority A Linux priority level in a range appropriate for the given policy. - * - * @throws IllegalArgumentException Throws IllegalArgumentException if - * tid does not exist, or if priority is out of range for the policy. - * @throws SecurityException Throws SecurityException if your process does - * not have permission to modify the given thread, or to use the given - * scheduling policy or priority. - * - * {@hide} - */ - public static final native void setThreadScheduler(int tid, int policy, int priority) - throws IllegalArgumentException; - - /** - * Determine whether the current environment supports multiple processes. - * - * @return Returns true if the system can run in multiple processes, else - * false if everything is running in a single process. - * - * @deprecated This method always returns true. Do not use. - */ - @Deprecated - public static final boolean supportsProcesses() { - return true; - } - - /** - * Adjust the swappiness level for a process. - * - * @param pid The process identifier to set. - * @param is_increased Whether swappiness should be increased or default. - * - * @return Returns true if the underlying system supports this - * feature, else false. - * - * {@hide} - */ - public static final native boolean setSwappiness(int pid, boolean is_increased); - - /** - * Change this process's argv[0] parameter. This can be useful to show - * more descriptive information in things like the 'ps' command. - * - * @param text The new name of this process. - * - * {@hide} - */ - public static final native void setArgV0(String text); - - /** - * Kill the process with the given PID. - * Note that, though this API allows us to request to - * kill any process based on its PID, the kernel will - * still impose standard restrictions on which PIDs you - * are actually able to kill. Typically this means only - * the process running the caller's packages/application - * and any additional processes created by that app; packages - * sharing a common UID will also be able to kill each - * other's processes. - */ - public static final void killProcess(int pid) { - sendSignal(pid, SIGNAL_KILL); - } - - /** @hide */ - public static final native int setUid(int uid); - - /** @hide */ - public static final native int setGid(int uid); - - /** - * Send a signal to the given process. - * - * @param pid The pid of the target process. - * @param signal The signal to send. - */ - public static final native void sendSignal(int pid, int signal); - - /** - * @hide - * Private impl for avoiding a log message... DO NOT USE without doing - * your own log, or the Android Illuminati will find you some night and - * beat you up. - */ - public static final void killProcessQuiet(int pid) { - sendSignalQuiet(pid, SIGNAL_KILL); - } - - /** - * @hide - * Private impl for avoiding a log message... DO NOT USE without doing - * your own log, or the Android Illuminati will find you some night and - * beat you up. - */ - public static final native void sendSignalQuiet(int pid, int signal); - - /** @hide */ - public static final native long getFreeMemory(); - - /** @hide */ - public static final native long getTotalMemory(); - - /** @hide */ - public static final native void readProcLines(String path, - String[] reqFields, long[] outSizes); - - /** @hide */ - public static final native int[] getPids(String path, int[] lastArray); - - /** @hide */ - public static final int PROC_TERM_MASK = 0xff; - /** @hide */ - public static final int PROC_ZERO_TERM = 0; - /** @hide */ - public static final int PROC_SPACE_TERM = (int)' '; - /** @hide */ - public static final int PROC_TAB_TERM = (int)'\t'; - /** @hide */ - public static final int PROC_COMBINE = 0x100; - /** @hide */ - public static final int PROC_PARENS = 0x200; - /** @hide */ - public static final int PROC_QUOTES = 0x400; - /** @hide */ - public static final int PROC_OUT_STRING = 0x1000; - /** @hide */ - public static final int PROC_OUT_LONG = 0x2000; - /** @hide */ - public static final int PROC_OUT_FLOAT = 0x4000; - - /** @hide */ - public static final native boolean readProcFile(String file, int[] format, - String[] outStrings, long[] outLongs, float[] outFloats); - - /** @hide */ - public static final native boolean parseProcLine(byte[] buffer, int startIndex, - int endIndex, int[] format, String[] outStrings, long[] outLongs, float[] outFloats); - - /** @hide */ - public static final native int[] getPidsForCommands(String[] cmds); - - /** - * Gets the total Pss value for a given process, in bytes. - * - * @param pid the process to the Pss for - * @return the total Pss value for the given process in bytes, - * or -1 if the value cannot be determined - * @hide - */ - public static final native long getPss(int pid); - - /** - * Specifies the outcome of having started a process. - * @hide - */ - public static final class ProcessStartResult { - /** - * The PID of the newly started process. - * Always >= 0. (If the start failed, an exception will have been thrown instead.) - */ - public int pid; - - /** - * True if the process was started with a wrapper attached. - */ - public boolean usingWrapper; - } - - /** - * Kill all processes in a process group started for the given - * pid. - * @hide - */ - public static final native int killProcessGroup(int uid, int pid); - - /** - * Remove all process groups. Expected to be called when ActivityManager - * is restarted. - * @hide - */ - public static final native void removeAllProcessGroups(); -} diff --git a/src/main/java/android/os/ProcessTest.java b/src/main/java/android/os/ProcessTest.java deleted file mode 100644 index 1f5b7c8..0000000 --- a/src/main/java/android/os/ProcessTest.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package android.os; - -import android.os.Process; -import android.os.UserHandle; -import android.test.suitebuilder.annotation.MediumTest; -import android.test.suitebuilder.annotation.SmallTest; - -import junit.framework.TestCase; - - -public class ProcessTest extends TestCase { - - @MediumTest - public void testProcessGetUidFromName() throws Exception { - assertEquals(android.os.Process.SYSTEM_UID, Process.getUidForName("system")); - assertEquals(Process.BLUETOOTH_UID, Process.getUidForName("bluetooth")); - assertEquals(Process.FIRST_APPLICATION_UID, Process.getUidForName("u0_a0")); - assertEquals(UserHandle.getUid(1, Process.SYSTEM_UID), Process.getUidForName("u1_system")); - assertEquals(UserHandle.getUid(2, Process.FIRST_ISOLATED_UID), - Process.getUidForName("u2_i0")); - assertEquals(UserHandle.getUid(3, Process.FIRST_APPLICATION_UID + 100), - Process.getUidForName("u3_a100")); - } - - @MediumTest - public void testProcessGetUidFromNameFailure() throws Exception { - // Failure cases - assertEquals(-1, Process.getUidForName("u2a_foo")); - assertEquals(-1, Process.getUidForName("u1_abcdef")); - assertEquals(-1, Process.getUidForName("u23")); - assertEquals(-1, Process.getUidForName("u2_i34a")); - assertEquals(-1, Process.getUidForName("akjhwiuefhiuhsf")); - assertEquals(-1, Process.getUidForName("u5_radio5")); - assertEquals(-1, Process.getUidForName("u2jhsajhfkjhsafkhskafhkashfkjashfkjhaskjfdhakj3")); - } - -} diff --git a/src/main/java/android/os/RecoverySystem.java b/src/main/java/android/os/RecoverySystem.java deleted file mode 100644 index b879c83..0000000 --- a/src/main/java/android/os/RecoverySystem.java +++ /dev/null @@ -1,517 +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.os; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.os.UserManager; -import android.text.TextUtils; -import android.util.Log; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.RandomAccessFile; -import java.security.GeneralSecurityException; -import java.security.PublicKey; -import java.security.Signature; -import java.security.SignatureException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -import org.apache.harmony.security.asn1.BerInputStream; -import org.apache.harmony.security.pkcs7.ContentInfo; -import org.apache.harmony.security.pkcs7.SignedData; -import org.apache.harmony.security.pkcs7.SignerInfo; -import org.apache.harmony.security.x509.Certificate; - -/** - * RecoverySystem contains methods for interacting with the Android - * recovery system (the separate partition that can be used to install - * system updates, wipe user data, etc.) - */ -public class RecoverySystem { - private static final String TAG = "RecoverySystem"; - - /** - * Default location of zip file containing public keys (X509 - * certs) authorized to sign OTA updates. - */ - private static final File DEFAULT_KEYSTORE = - new File("/system/etc/security/otacerts.zip"); - - /** Send progress to listeners no more often than this (in ms). */ - private static final long PUBLISH_PROGRESS_INTERVAL_MS = 500; - - /** Used to communicate with recovery. See bootable/recovery/recovery.c. */ - private static File RECOVERY_DIR = new File("/cache/recovery"); - private static File COMMAND_FILE = new File(RECOVERY_DIR, "command"); - private static File LOG_FILE = new File(RECOVERY_DIR, "log"); - private static String LAST_PREFIX = "last_"; - - // Length limits for reading files. - private static int LOG_FILE_MAX_LENGTH = 64 * 1024; - - /** - * Interface definition for a callback to be invoked regularly as - * verification proceeds. - */ - public interface ProgressListener { - /** - * Called periodically as the verification progresses. - * - * @param progress the approximate percentage of the - * verification that has been completed, ranging from 0 - * to 100 (inclusive). - */ - public void onProgress(int progress); - } - - /** @return the set of certs that can be used to sign an OTA package. */ - private static HashSet getTrustedCerts(File keystore) - throws IOException, GeneralSecurityException { - HashSet trusted = new HashSet(); - if (keystore == null) { - keystore = DEFAULT_KEYSTORE; - } - ZipFile zip = new ZipFile(keystore); - try { - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - Enumeration entries = zip.entries(); - while (entries.hasMoreElements()) { - ZipEntry entry = entries.nextElement(); - InputStream is = zip.getInputStream(entry); - try { - trusted.add((X509Certificate) cf.generateCertificate(is)); - } finally { - is.close(); - } - } - } finally { - zip.close(); - } - return trusted; - } - - /** - * Verify the cryptographic signature of a system update package - * before installing it. Note that the package is also verified - * separately by the installer once the device is rebooted into - * the recovery system. This function will return only if the - * package was successfully verified; otherwise it will throw an - * exception. - * - * Verification of a package can take significant time, so this - * function should not be called from a UI thread. Interrupting - * the thread while this function is in progress will result in a - * SecurityException being thrown (and the thread's interrupt flag - * will be cleared). - * - * @param packageFile the package to be verified - * @param listener an object to receive periodic progress - * updates as verification proceeds. May be null. - * @param deviceCertsZipFile the zip file of certificates whose - * public keys we will accept. Verification succeeds if the - * package is signed by the private key corresponding to any - * public key in this file. May be null to use the system default - * file (currently "/system/etc/security/otacerts.zip"). - * - * @throws IOException if there were any errors reading the - * package or certs files. - * @throws GeneralSecurityException if verification failed - */ - public static void verifyPackage(File packageFile, - ProgressListener listener, - File deviceCertsZipFile) - throws IOException, GeneralSecurityException { - long fileLen = packageFile.length(); - - RandomAccessFile raf = new RandomAccessFile(packageFile, "r"); - try { - int lastPercent = 0; - long lastPublishTime = System.currentTimeMillis(); - if (listener != null) { - listener.onProgress(lastPercent); - } - - raf.seek(fileLen - 6); - byte[] footer = new byte[6]; - raf.readFully(footer); - - if (footer[2] != (byte)0xff || footer[3] != (byte)0xff) { - throw new SignatureException("no signature in file (no footer)"); - } - - int commentSize = (footer[4] & 0xff) | ((footer[5] & 0xff) << 8); - int signatureStart = (footer[0] & 0xff) | ((footer[1] & 0xff) << 8); - - byte[] eocd = new byte[commentSize + 22]; - raf.seek(fileLen - (commentSize + 22)); - raf.readFully(eocd); - - // Check that we have found the start of the - // end-of-central-directory record. - if (eocd[0] != (byte)0x50 || eocd[1] != (byte)0x4b || - eocd[2] != (byte)0x05 || eocd[3] != (byte)0x06) { - throw new SignatureException("no signature in file (bad footer)"); - } - - for (int i = 4; i < eocd.length-3; ++i) { - if (eocd[i ] == (byte)0x50 && eocd[i+1] == (byte)0x4b && - eocd[i+2] == (byte)0x05 && eocd[i+3] == (byte)0x06) { - throw new SignatureException("EOCD marker found after start of EOCD"); - } - } - - // The following code is largely copied from - // JarUtils.verifySignature(). We could just *call* that - // method here if that function didn't read the entire - // input (ie, the whole OTA package) into memory just to - // compute its message digest. - - BerInputStream bis = new BerInputStream( - new ByteArrayInputStream(eocd, commentSize+22-signatureStart, signatureStart)); - ContentInfo info = (ContentInfo)ContentInfo.ASN1.decode(bis); - SignedData signedData = info.getSignedData(); - if (signedData == null) { - throw new IOException("signedData is null"); - } - List encCerts = signedData.getCertificates(); - if (encCerts.isEmpty()) { - throw new IOException("encCerts is empty"); - } - // Take the first certificate from the signature (packages - // should contain only one). - Iterator it = encCerts.iterator(); - X509Certificate cert = null; - if (it.hasNext()) { - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - InputStream is = new ByteArrayInputStream(it.next().getEncoded()); - cert = (X509Certificate) cf.generateCertificate(is); - } else { - throw new SignatureException("signature contains no certificates"); - } - - List sigInfos = signedData.getSignerInfos(); - SignerInfo sigInfo; - if (!sigInfos.isEmpty()) { - sigInfo = (SignerInfo)sigInfos.get(0); - } else { - throw new IOException("no signer infos!"); - } - - // Check that the public key of the certificate contained - // in the package equals one of our trusted public keys. - - HashSet trusted = getTrustedCerts( - deviceCertsZipFile == null ? DEFAULT_KEYSTORE : deviceCertsZipFile); - - PublicKey signatureKey = cert.getPublicKey(); - boolean verified = false; - for (X509Certificate c : trusted) { - if (c.getPublicKey().equals(signatureKey)) { - verified = true; - break; - } - } - if (!verified) { - throw new SignatureException("signature doesn't match any trusted key"); - } - - // The signature cert matches a trusted key. Now verify that - // the digest in the cert matches the actual file data. - - // The verifier in recovery only handles SHA1withRSA and - // SHA256withRSA signatures. SignApk chooses which to use - // based on the signature algorithm of the cert: - // - // "SHA256withRSA" cert -> "SHA256withRSA" signature - // "SHA1withRSA" cert -> "SHA1withRSA" signature - // "MD5withRSA" cert -> "SHA1withRSA" signature (for backwards compatibility) - // any other cert -> SignApk fails - // - // Here we ignore whatever the cert says, and instead use - // whatever algorithm is used by the signature. - - String da = sigInfo.getDigestAlgorithm(); - String dea = sigInfo.getDigestEncryptionAlgorithm(); - String alg = null; - if (da == null || dea == null) { - // fall back to the cert algorithm if the sig one - // doesn't look right. - alg = cert.getSigAlgName(); - } else { - alg = da + "with" + dea; - } - Signature sig = Signature.getInstance(alg); - sig.initVerify(cert); - - // The signature covers all of the OTA package except the - // archive comment and its 2-byte length. - long toRead = fileLen - commentSize - 2; - long soFar = 0; - raf.seek(0); - byte[] buffer = new byte[4096]; - boolean interrupted = false; - while (soFar < toRead) { - interrupted = Thread.interrupted(); - if (interrupted) break; - int size = buffer.length; - if (soFar + size > toRead) { - size = (int)(toRead - soFar); - } - int read = raf.read(buffer, 0, size); - sig.update(buffer, 0, read); - soFar += read; - - if (listener != null) { - long now = System.currentTimeMillis(); - int p = (int)(soFar * 100 / toRead); - if (p > lastPercent && - now - lastPublishTime > PUBLISH_PROGRESS_INTERVAL_MS) { - lastPercent = p; - lastPublishTime = now; - listener.onProgress(lastPercent); - } - } - } - if (listener != null) { - listener.onProgress(100); - } - - if (interrupted) { - throw new SignatureException("verification was interrupted"); - } - - if (!sig.verify(sigInfo.getEncryptedDigest())) { - throw new SignatureException("signature digest verification failed"); - } - } finally { - raf.close(); - } - } - - /** - * Reboots the device in order to install the given update - * package. - * Requires the {@link android.Manifest.permission#REBOOT} permission. - * - * @param context the Context to use - * @param packageFile the update package to install. Must be on - * a partition mountable by recovery. (The set of partitions - * known to recovery may vary from device to device. Generally, - * /cache and /data are safe.) - * - * @throws IOException if writing the recovery command file - * fails, or if the reboot itself fails. - */ - public static void installPackage(Context context, File packageFile) - throws IOException { - String filename = packageFile.getCanonicalPath(); - Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!"); - - final String filenameArg = "--update_package=" + filename; - final String localeArg = "--locale=" + Locale.getDefault().toString(); - bootCommand(context, filenameArg, localeArg); - } - - /** - * Reboots the device and wipes the user data and cache - * partitions. This is sometimes called a "factory reset", which - * is something of a misnomer because the system partition is not - * restored to its factory state. Requires the - * {@link android.Manifest.permission#REBOOT} permission. - * - * @param context the Context to use - * - * @throws IOException if writing the recovery command file - * fails, or if the reboot itself fails. - * @throws SecurityException if the current user is not allowed to wipe data. - */ - public static void rebootWipeUserData(Context context) throws IOException { - rebootWipeUserData(context, false, context.getPackageName()); - } - - /** {@hide} */ - public static void rebootWipeUserData(Context context, String reason) throws IOException { - rebootWipeUserData(context, false, reason); - } - - /** {@hide} */ - public static void rebootWipeUserData(Context context, boolean shutdown) - throws IOException { - rebootWipeUserData(context, shutdown, context.getPackageName()); - } - - /** - * Reboots the device and wipes the user data and cache - * partitions. This is sometimes called a "factory reset", which - * is something of a misnomer because the system partition is not - * restored to its factory state. Requires the - * {@link android.Manifest.permission#REBOOT} permission. - * - * @param context the Context to use - * @param shutdown if true, the device will be powered down after - * the wipe completes, rather than being rebooted - * back to the regular system. - * - * @throws IOException if writing the recovery command file - * fails, or if the reboot itself fails. - * @throws SecurityException if the current user is not allowed to wipe data. - * - * @hide - */ - public static void rebootWipeUserData(Context context, boolean shutdown, String reason) - throws IOException { - UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); - if (um.hasUserRestriction(UserManager.DISALLOW_FACTORY_RESET)) { - throw new SecurityException("Wiping data is not allowed for this user."); - } - final ConditionVariable condition = new ConditionVariable(); - - Intent intent = new Intent("android.intent.action.MASTER_CLEAR_NOTIFICATION"); - intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); - context.sendOrderedBroadcastAsUser(intent, UserHandle.OWNER, - android.Manifest.permission.MASTER_CLEAR, - new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - condition.open(); - } - }, null, 0, null, null); - - // Block until the ordered broadcast has completed. - condition.block(); - - String shutdownArg = null; - if (shutdown) { - shutdownArg = "--shutdown_after"; - } - - String reasonArg = null; - if (!TextUtils.isEmpty(reason)) { - reasonArg = "--reason=" + sanitizeArg(reason); - } - - final String localeArg = "--locale=" + Locale.getDefault().toString(); - bootCommand(context, shutdownArg, "--wipe_data", reasonArg, localeArg); - } - - /** - * Reboot into the recovery system to wipe the /cache partition. - * @throws IOException if something goes wrong. - */ - public static void rebootWipeCache(Context context) throws IOException { - rebootWipeCache(context, context.getPackageName()); - } - - /** {@hide} */ - public static void rebootWipeCache(Context context, String reason) throws IOException { - String reasonArg = null; - if (!TextUtils.isEmpty(reason)) { - reasonArg = "--reason=" + sanitizeArg(reason); - } - - final String localeArg = "--locale=" + Locale.getDefault().toString(); - bootCommand(context, "--wipe_cache", reasonArg, localeArg); - } - - /** - * Reboot into the recovery system with the supplied argument. - * @param args to pass to the recovery utility. - * @throws IOException if something goes wrong. - */ - private static void bootCommand(Context context, String... args) throws IOException { - RECOVERY_DIR.mkdirs(); // In case we need it - COMMAND_FILE.delete(); // In case it's not writable - LOG_FILE.delete(); - - FileWriter command = new FileWriter(COMMAND_FILE); - try { - for (String arg : args) { - if (!TextUtils.isEmpty(arg)) { - command.write(arg); - command.write("\n"); - } - } - } finally { - command.close(); - } - - // Having written the command file, go ahead and reboot - PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); - pm.reboot(PowerManager.REBOOT_RECOVERY); - - throw new IOException("Reboot failed (no permissions?)"); - } - - /** - * Called after booting to process and remove recovery-related files. - * @return the log file from recovery, or null if none was found. - * - * @hide - */ - public static String handleAftermath() { - // Record the tail of the LOG_FILE - String log = null; - try { - log = FileUtils.readTextFile(LOG_FILE, -LOG_FILE_MAX_LENGTH, "...\n"); - } catch (FileNotFoundException e) { - Log.i(TAG, "No recovery log file"); - } catch (IOException e) { - Log.e(TAG, "Error reading recovery log", e); - } - - // Delete everything in RECOVERY_DIR except those beginning - // with LAST_PREFIX - String[] names = RECOVERY_DIR.list(); - for (int i = 0; names != null && i < names.length; i++) { - if (names[i].startsWith(LAST_PREFIX)) continue; - File f = new File(RECOVERY_DIR, names[i]); - if (!f.delete()) { - Log.e(TAG, "Can't delete: " + f); - } else { - Log.i(TAG, "Deleted: " + f); - } - } - - return log; - } - - /** - * Internally, recovery treats each line of the command file as a separate - * argv, so we only need to protect against newlines and nulls. - */ - private static String sanitizeArg(String arg) { - arg = arg.replace('\0', '?'); - arg = arg.replace('\n', '?'); - return arg; - } - - private void RecoverySystem() { } // Do not instantiate -} diff --git a/src/main/java/android/os/Registrant.java b/src/main/java/android/os/Registrant.java deleted file mode 100644 index 705cc5d..0000000 --- a/src/main/java/android/os/Registrant.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.os.Handler; -import android.os.Message; - -import java.lang.ref.WeakReference; - -/** @hide */ -public class Registrant -{ - public - Registrant(Handler h, int what, Object obj) - { - refH = new WeakReference(h); - this.what = what; - userObj = obj; - } - - public void - clear() - { - refH = null; - userObj = null; - } - - public void - notifyRegistrant() - { - internalNotifyRegistrant (null, null); - } - - public void - notifyResult(Object result) - { - internalNotifyRegistrant (result, null); - } - - public void - notifyException(Throwable exception) - { - internalNotifyRegistrant (null, exception); - } - - /** - * This makes a copy of @param ar - */ - public void - notifyRegistrant(AsyncResult ar) - { - internalNotifyRegistrant (ar.result, ar.exception); - } - - /*package*/ void - internalNotifyRegistrant (Object result, Throwable exception) - { - Handler h = getHandler(); - - if (h == null) { - clear(); - } else { - Message msg = Message.obtain(); - - msg.what = what; - - msg.obj = new AsyncResult(userObj, result, exception); - - h.sendMessage(msg); - } - } - - /** - * NOTE: May return null if weak reference has been collected - */ - - public Message - messageForRegistrant() - { - Handler h = getHandler(); - - if (h == null) { - clear(); - - return null; - } else { - Message msg = h.obtainMessage(); - - msg.what = what; - msg.obj = userObj; - - return msg; - } - } - - public Handler - getHandler() - { - if (refH == null) - return null; - - return (Handler) refH.get(); - } - - WeakReference refH; - int what; - Object userObj; -} - diff --git a/src/main/java/android/os/RegistrantList.java b/src/main/java/android/os/RegistrantList.java deleted file mode 100644 index 9ab61f5..0000000 --- a/src/main/java/android/os/RegistrantList.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.os.Handler; - -import java.util.ArrayList; - -/** @hide */ -public class RegistrantList -{ - ArrayList registrants = new ArrayList(); // of Registrant - - public synchronized void - add(Handler h, int what, Object obj) - { - add(new Registrant(h, what, obj)); - } - - public synchronized void - addUnique(Handler h, int what, Object obj) - { - // if the handler is already in the registrant list, remove it - remove(h); - add(new Registrant(h, what, obj)); - } - - public synchronized void - add(Registrant r) - { - removeCleared(); - registrants.add(r); - } - - public synchronized void - removeCleared() - { - for (int i = registrants.size() - 1; i >= 0 ; i--) { - Registrant r = (Registrant) registrants.get(i); - - if (r.refH == null) { - registrants.remove(i); - } - } - } - - public synchronized int - size() - { - return registrants.size(); - } - - public synchronized Object - get(int index) - { - return registrants.get(index); - } - - private synchronized void - internalNotifyRegistrants (Object result, Throwable exception) - { - for (int i = 0, s = registrants.size(); i < s ; i++) { - Registrant r = (Registrant) registrants.get(i); - r.internalNotifyRegistrant(result, exception); - } - } - - public /*synchronized*/ void - notifyRegistrants() - { - internalNotifyRegistrants(null, null); - } - - public /*synchronized*/ void - notifyException(Throwable exception) - { - internalNotifyRegistrants (null, exception); - } - - public /*synchronized*/ void - notifyResult(Object result) - { - internalNotifyRegistrants (result, null); - } - - - public /*synchronized*/ void - notifyRegistrants(AsyncResult ar) - { - internalNotifyRegistrants(ar.result, ar.exception); - } - - public synchronized void - remove(Handler h) - { - for (int i = 0, s = registrants.size() ; i < s ; i++) { - Registrant r = (Registrant) registrants.get(i); - Handler rh; - - rh = r.getHandler(); - - /* Clean up both the requested registrant and - * any now-collected registrants - */ - if (rh == null || rh == h) { - r.clear(); - } - } - - removeCleared(); - } -} diff --git a/src/main/java/android/os/RemoteCallback.java b/src/main/java/android/os/RemoteCallback.java deleted file mode 100644 index ca95bdf..0000000 --- a/src/main/java/android/os/RemoteCallback.java +++ /dev/null @@ -1,107 +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.os; - -/** - * TODO: Make this a public API? Let's see how it goes with a few use - * cases first. - * @hide - */ -public abstract class RemoteCallback implements Parcelable { - final Handler mHandler; - final IRemoteCallback mTarget; - - class DeliverResult implements Runnable { - final Bundle mResult; - - DeliverResult(Bundle result) { - mResult = result; - } - - public void run() { - onResult(mResult); - } - } - - class LocalCallback extends IRemoteCallback.Stub { - public void sendResult(Bundle bundle) { - mHandler.post(new DeliverResult(bundle)); - } - } - - static class RemoteCallbackProxy extends RemoteCallback { - RemoteCallbackProxy(IRemoteCallback target) { - super(target); - } - - protected void onResult(Bundle bundle) { - } - } - - public RemoteCallback(Handler handler) { - mHandler = handler; - mTarget = new LocalCallback(); - } - - RemoteCallback(IRemoteCallback target) { - mHandler = null; - mTarget = target; - } - - public void sendResult(Bundle bundle) throws RemoteException { - mTarget.sendResult(bundle); - } - - protected abstract void onResult(Bundle bundle); - - public boolean equals(Object otherObj) { - if (otherObj == null) { - return false; - } - try { - return mTarget.asBinder().equals(((RemoteCallback)otherObj) - .mTarget.asBinder()); - } catch (ClassCastException e) { - } - return false; - } - - public int hashCode() { - return mTarget.asBinder().hashCode(); - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel out, int flags) { - out.writeStrongBinder(mTarget.asBinder()); - } - - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - public RemoteCallback createFromParcel(Parcel in) { - IBinder target = in.readStrongBinder(); - return target != null ? new RemoteCallbackProxy( - IRemoteCallback.Stub.asInterface(target)) : null; - } - - public RemoteCallback[] newArray(int size) { - return new RemoteCallback[size]; - } - }; -} diff --git a/src/main/java/android/os/RemoteCallbackList.java b/src/main/java/android/os/RemoteCallbackList.java deleted file mode 100644 index d2a9cdc..0000000 --- a/src/main/java/android/os/RemoteCallbackList.java +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.util.ArrayMap; - -/** - * Takes care of the grunt work of maintaining a list of remote interfaces, - * typically for the use of performing callbacks from a - * {@link android.app.Service} to its clients. In particular, this: - * - *

      - *
    • Keeps track of a set of registered {@link IInterface} callbacks, - * taking care to identify them through their underlying unique {@link IBinder} - * (by calling {@link IInterface#asBinder IInterface.asBinder()}. - *
    • Attaches a {@link IBinder.DeathRecipient IBinder.DeathRecipient} to - * each registered interface, so that it can be cleaned out of the list if its - * process goes away. - *
    • Performs locking of the underlying list of interfaces to deal with - * multithreaded incoming calls, and a thread-safe way to iterate over a - * snapshot of the list without holding its lock. - *
    - * - *

    To use this class, simply create a single instance along with your - * service, and call its {@link #register} and {@link #unregister} methods - * as client register and unregister with your service. To call back on to - * the registered clients, use {@link #beginBroadcast}, - * {@link #getBroadcastItem}, and {@link #finishBroadcast}. - * - *

    If a registered callback's process goes away, this class will take - * care of automatically removing it from the list. If you want to do - * additional work in this situation, you can create a subclass that - * implements the {@link #onCallbackDied} method. - */ -public class RemoteCallbackList { - /*package*/ ArrayMap mCallbacks - = new ArrayMap(); - private Object[] mActiveBroadcast; - private int mBroadcastCount = -1; - private boolean mKilled = false; - - private final class Callback implements IBinder.DeathRecipient { - final E mCallback; - final Object mCookie; - - Callback(E callback, Object cookie) { - mCallback = callback; - mCookie = cookie; - } - - public void binderDied() { - synchronized (mCallbacks) { - mCallbacks.remove(mCallback.asBinder()); - } - onCallbackDied(mCallback, mCookie); - } - } - - /** - * Simple version of {@link RemoteCallbackList#register(E, Object)} - * that does not take a cookie object. - */ - public boolean register(E callback) { - return register(callback, null); - } - - /** - * Add a new callback to the list. This callback will remain in the list - * until a corresponding call to {@link #unregister} or its hosting process - * goes away. If the callback was already registered (determined by - * checking to see if the {@link IInterface#asBinder callback.asBinder()} - * object is already in the list), then it will be left as-is. - * Registrations are not counted; a single call to {@link #unregister} - * will remove a callback after any number calls to register it. - * - * @param callback The callback interface to be added to the list. Must - * not be null -- passing null here will cause a NullPointerException. - * Most services will want to check for null before calling this with - * an object given from a client, so that clients can't crash the - * service with bad data. - * - * @param cookie Optional additional data to be associated with this - * callback. - * - * @return Returns true if the callback was successfully added to the list. - * Returns false if it was not added, either because {@link #kill} had - * previously been called or the callback's process has gone away. - * - * @see #unregister - * @see #kill - * @see #onCallbackDied - */ - public boolean register(E callback, Object cookie) { - synchronized (mCallbacks) { - if (mKilled) { - return false; - } - IBinder binder = callback.asBinder(); - try { - Callback cb = new Callback(callback, cookie); - binder.linkToDeath(cb, 0); - mCallbacks.put(binder, cb); - return true; - } catch (RemoteException e) { - return false; - } - } - } - - /** - * Remove from the list a callback that was previously added with - * {@link #register}. This uses the - * {@link IInterface#asBinder callback.asBinder()} object to correctly - * find the previous registration. - * Registrations are not counted; a single unregister call will remove - * a callback after any number calls to {@link #register} for it. - * - * @param callback The callback to be removed from the list. Passing - * null here will cause a NullPointerException, so you will generally want - * to check for null before calling. - * - * @return Returns true if the callback was found and unregistered. Returns - * false if the given callback was not found on the list. - * - * @see #register - */ - public boolean unregister(E callback) { - synchronized (mCallbacks) { - Callback cb = mCallbacks.remove(callback.asBinder()); - if (cb != null) { - cb.mCallback.asBinder().unlinkToDeath(cb, 0); - return true; - } - return false; - } - } - - /** - * Disable this callback list. All registered callbacks are unregistered, - * and the list is disabled so that future calls to {@link #register} will - * fail. This should be used when a Service is stopping, to prevent clients - * from registering callbacks after it is stopped. - * - * @see #register - */ - public void kill() { - synchronized (mCallbacks) { - for (int cbi=mCallbacks.size()-1; cbi>=0; cbi--) { - Callback cb = mCallbacks.valueAt(cbi); - cb.mCallback.asBinder().unlinkToDeath(cb, 0); - } - mCallbacks.clear(); - mKilled = true; - } - } - - /** - * Old version of {@link #onCallbackDied(E, Object)} that - * does not provide a cookie. - */ - public void onCallbackDied(E callback) { - } - - /** - * Called when the process hosting a callback in the list has gone away. - * The default implementation calls {@link #onCallbackDied(E)} - * for backwards compatibility. - * - * @param callback The callback whose process has died. Note that, since - * its process has died, you can not make any calls on to this interface. - * You can, however, retrieve its IBinder and compare it with another - * IBinder to see if it is the same object. - * @param cookie The cookie object original provided to - * {@link #register(E, Object)}. - * - * @see #register - */ - public void onCallbackDied(E callback, Object cookie) { - onCallbackDied(callback); - } - - /** - * Prepare to start making calls to the currently registered callbacks. - * This creates a copy of the callback list, which you can retrieve items - * from using {@link #getBroadcastItem}. Note that only one broadcast can - * be active at a time, so you must be sure to always call this from the - * same thread (usually by scheduling with {@link Handler}) or - * do your own synchronization. You must call {@link #finishBroadcast} - * when done. - * - *

    A typical loop delivering a broadcast looks like this: - * - *

    -     * int i = callbacks.beginBroadcast();
    -     * while (i > 0) {
    -     *     i--;
    -     *     try {
    -     *         callbacks.getBroadcastItem(i).somethingHappened();
    -     *     } catch (RemoteException e) {
    -     *         // The RemoteCallbackList will take care of removing
    -     *         // the dead object for us.
    -     *     }
    -     * }
    -     * callbacks.finishBroadcast();
    - * - * @return Returns the number of callbacks in the broadcast, to be used - * with {@link #getBroadcastItem} to determine the range of indices you - * can supply. - * - * @see #getBroadcastItem - * @see #finishBroadcast - */ - public int beginBroadcast() { - synchronized (mCallbacks) { - if (mBroadcastCount > 0) { - throw new IllegalStateException( - "beginBroadcast() called while already in a broadcast"); - } - - final int N = mBroadcastCount = mCallbacks.size(); - if (N <= 0) { - return 0; - } - Object[] active = mActiveBroadcast; - if (active == null || active.length < N) { - mActiveBroadcast = active = new Object[N]; - } - for (int i=0; ionly be called after - * the broadcast is started, and its data is no longer valid after - * calling {@link #finishBroadcast}. - * - *

    Note that it is possible for the process of one of the returned - * callbacks to go away before you call it, so you will need to catch - * {@link RemoteException} when calling on to the returned object. - * The callback list itself, however, will take care of unregistering - * these objects once it detects that it is no longer valid, so you can - * handle such an exception by simply ignoring it. - * - * @param index Which of the registered callbacks you would like to - * retrieve. Ranges from 0 to 1-{@link #beginBroadcast}. - * - * @return Returns the callback interface that you can call. This will - * always be non-null. - * - * @see #beginBroadcast - */ - public E getBroadcastItem(int index) { - return ((Callback)mActiveBroadcast[index]).mCallback; - } - - /** - * Retrieve the cookie associated with the item - * returned by {@link #getBroadcastItem(int)}. - * - * @see #getBroadcastItem - */ - public Object getBroadcastCookie(int index) { - return ((Callback)mActiveBroadcast[index]).mCookie; - } - - /** - * Clean up the state of a broadcast previously initiated by calling - * {@link #beginBroadcast}. This must always be called when you are done - * with a broadcast. - * - * @see #beginBroadcast - */ - public void finishBroadcast() { - if (mBroadcastCount < 0) { - throw new IllegalStateException( - "finishBroadcast() called outside of a broadcast"); - } - - Object[] active = mActiveBroadcast; - if (active != null) { - final int N = mBroadcastCount; - for (int i=0; i - * This function is useful to decide whether to schedule a broadcast if this - * requires doing some work which otherwise would not be performed. - *

    - * - * @return The size. - */ - public int getRegisteredCallbackCount() { - synchronized (mCallbacks) { - if (mKilled) { - return 0; - } - return mCallbacks.size(); - } - } -} diff --git a/src/main/java/android/os/RemoteException.java b/src/main/java/android/os/RemoteException.java deleted file mode 100644 index 98d7523..0000000 --- a/src/main/java/android/os/RemoteException.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; -import android.util.AndroidException; - -/** - * Parent exception for all Binder remote-invocation errors - */ -public class RemoteException extends AndroidException { - public RemoteException() { - super(); - } - - public RemoteException(String message) { - super(message); - } - - /** {@hide} */ - public RuntimeException rethrowAsRuntimeException() { - throw new RuntimeException(this); - } -} diff --git a/src/main/java/android/os/RemoteMailException.java b/src/main/java/android/os/RemoteMailException.java deleted file mode 100644 index 1ac96d1..0000000 --- a/src/main/java/android/os/RemoteMailException.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -/** @hide */ -public class RemoteMailException extends Exception -{ - public RemoteMailException() - { - } - - public RemoteMailException(String s) - { - super(s); - } -} - diff --git a/src/main/java/android/os/ResultReceiver.java b/src/main/java/android/os/ResultReceiver.java deleted file mode 100644 index 34a66b6..0000000 --- a/src/main/java/android/os/ResultReceiver.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import com.android.internal.os.IResultReceiver; - -/** - * Generic interface for receiving a callback result from someone. Use this - * by creating a subclass and implement {@link #onReceiveResult}, which you can - * then pass to others and send through IPC, and receive results they - * supply with {@link #send}. - * - *

    Note: the implementation underneath is just a simple wrapper around - * a {@link Binder} that is used to perform the communication. This means - * semantically you should treat it as such: this class does not impact process - * lifecycle management (you must be using some higher-level component to tell - * the system that your process needs to continue running), the connection will - * break if your process goes away for any reason, etc.

    - */ -public class ResultReceiver implements Parcelable { - final boolean mLocal; - final Handler mHandler; - - IResultReceiver mReceiver; - - class MyRunnable implements Runnable { - final int mResultCode; - final Bundle mResultData; - - MyRunnable(int resultCode, Bundle resultData) { - mResultCode = resultCode; - mResultData = resultData; - } - - public void run() { - onReceiveResult(mResultCode, mResultData); - } - } - - class MyResultReceiver extends IResultReceiver.Stub { - public void send(int resultCode, Bundle resultData) { - if (mHandler != null) { - mHandler.post(new MyRunnable(resultCode, resultData)); - } else { - onReceiveResult(resultCode, resultData); - } - } - } - - /** - * Create a new ResultReceive to receive results. Your - * {@link #onReceiveResult} method will be called from the thread running - * handler if given, or from an arbitrary thread if null. - */ - public ResultReceiver(Handler handler) { - mLocal = true; - mHandler = handler; - } - - /** - * Deliver a result to this receiver. Will call {@link #onReceiveResult}, - * always asynchronously if the receiver has supplied a Handler in which - * to dispatch the result. - * @param resultCode Arbitrary result code to deliver, as defined by you. - * @param resultData Any additional data provided by you. - */ - public void send(int resultCode, Bundle resultData) { - if (mLocal) { - if (mHandler != null) { - mHandler.post(new MyRunnable(resultCode, resultData)); - } else { - onReceiveResult(resultCode, resultData); - } - return; - } - - if (mReceiver != null) { - try { - mReceiver.send(resultCode, resultData); - } catch (RemoteException e) { - } - } - } - - /** - * Override to receive results delivered to this object. - * - * @param resultCode Arbitrary result code delivered by the sender, as - * defined by the sender. - * @param resultData Any additional data provided by the sender. - */ - protected void onReceiveResult(int resultCode, Bundle resultData) { - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel out, int flags) { - synchronized (this) { - if (mReceiver == null) { - mReceiver = new MyResultReceiver(); - } - out.writeStrongBinder(mReceiver.asBinder()); - } - } - - ResultReceiver(Parcel in) { - mLocal = false; - mHandler = null; - mReceiver = IResultReceiver.Stub.asInterface(in.readStrongBinder()); - } - - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - public ResultReceiver createFromParcel(Parcel in) { - return new ResultReceiver(in); - } - public ResultReceiver[] newArray(int size) { - return new ResultReceiver[size]; - } - }; -} diff --git a/src/main/java/android/os/SELinux.java b/src/main/java/android/os/SELinux.java deleted file mode 100644 index 84aa427..0000000 --- a/src/main/java/android/os/SELinux.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.util.Slog; - -import java.io.IOException; -import java.io.File; -import java.io.FileDescriptor; - -/** - * This class provides access to the centralized jni bindings for - * SELinux interaction. - * {@hide} - */ -public class SELinux { - private static final String TAG = "SELinux"; - - /** Keep in sync with ./external/libselinux/include/selinux/android.h */ - private static final int SELINUX_ANDROID_RESTORECON_NOCHANGE = 1; - private static final int SELINUX_ANDROID_RESTORECON_VERBOSE = 2; - private static final int SELINUX_ANDROID_RESTORECON_RECURSE = 4; - private static final int SELINUX_ANDROID_RESTORECON_FORCE = 8; - private static final int SELINUX_ANDROID_RESTORECON_DATADATA = 16; - - /** - * Determine whether SELinux is disabled or enabled. - * @return a boolean indicating whether SELinux is enabled. - */ - public static final native boolean isSELinuxEnabled(); - - /** - * Determine whether SELinux is permissive or enforcing. - * @return a boolean indicating whether SELinux is enforcing. - */ - public static final native boolean isSELinuxEnforced(); - - /** - * Set whether SELinux is permissive or enforcing. - * @param value representing whether to set SELinux to enforcing - * @return a boolean representing whether the desired mode was set - */ - public static final native boolean setSELinuxEnforce(boolean value); - - /** - * Sets the security context for newly created file objects. - * @param context a security context given as a String. - * @return a boolean indicating whether the operation succeeded. - */ - public static final native boolean setFSCreateContext(String context); - - /** - * Change the security context of an existing file object. - * @param path representing the path of file object to relabel. - * @param context new security context given as a String. - * @return a boolean indicating whether the operation succeeded. - */ - public static final native boolean setFileContext(String path, String context); - - /** - * Get the security context of a file object. - * @param path the pathname of the file object. - * @return a security context given as a String. - */ - public static final native String getFileContext(String path); - - /** - * Get the security context of a peer socket. - * @param fd FileDescriptor class of the peer socket. - * @return a String representing the peer socket security context. - */ - public static final native String getPeerContext(FileDescriptor fd); - - /** - * Gets the security context of the current process. - * @return a String representing the security context of the current process. - */ - public static final native String getContext(); - - /** - * Gets the security context of a given process id. - * @param pid an int representing the process id to check. - * @return a String representing the security context of the given pid. - */ - public static final native String getPidContext(int pid); - - /** - * Gets a list of the SELinux boolean names. - * @return an array of strings containing the SELinux boolean names. - */ - public static final native String[] getBooleanNames(); - - /** - * Gets the value for the given SELinux boolean name. - * @param name The name of the SELinux boolean. - * @return a boolean indicating whether the SELinux boolean is set. - */ - public static final native boolean getBooleanValue(String name); - - /** - * Sets the value for the given SELinux boolean name. - * @param name The name of the SELinux boolean. - * @param value The new value of the SELinux boolean. - * @return a boolean indicating whether or not the operation succeeded. - */ - public static final native boolean setBooleanValue(String name, boolean value); - - /** - * Check permissions between two security contexts. - * @param scon The source or subject security context. - * @param tcon The target or object security context. - * @param tclass The object security class name. - * @param perm The permission name. - * @return a boolean indicating whether permission was granted. - */ - public static final native boolean checkSELinuxAccess(String scon, String tcon, String tclass, String perm); - - /** - * Restores a file to its default SELinux security context. - * If the system is not compiled with SELinux, then {@code true} - * is automatically returned. - * If SELinux is compiled in, but disabled, then {@code true} is - * returned. - * - * @param pathname The pathname of the file to be relabeled. - * @return a boolean indicating whether the relabeling succeeded. - * @exception NullPointerException if the pathname is a null object. - */ - public static boolean restorecon(String pathname) throws NullPointerException { - if (pathname == null) { throw new NullPointerException(); } - return native_restorecon(pathname, 0); - } - - /** - * Restores a file to its default SELinux security context. - * If the system is not compiled with SELinux, then {@code true} - * is automatically returned. - * If SELinux is compiled in, but disabled, then {@code true} is - * returned. - * - * @param pathname The pathname of the file to be relabeled. - * @return a boolean indicating whether the relabeling succeeded. - */ - private static native boolean native_restorecon(String pathname, int flags); - - /** - * Restores a file to its default SELinux security context. - * If the system is not compiled with SELinux, then {@code true} - * is automatically returned. - * If SELinux is compiled in, but disabled, then {@code true} is - * returned. - * - * @param file The File object representing the path to be relabeled. - * @return a boolean indicating whether the relabeling succeeded. - * @exception NullPointerException if the file is a null object. - */ - public static boolean restorecon(File file) throws NullPointerException { - try { - return native_restorecon(file.getCanonicalPath(), 0); - } catch (IOException e) { - Slog.e(TAG, "Error getting canonical path. Restorecon failed for " + - file.getPath(), e); - return false; - } - } - - /** - * Recursively restores all files under the given path to their default - * SELinux security context. If the system is not compiled with SELinux, - * then {@code true} is automatically returned. If SELinux is compiled in, - * but disabled, then {@code true} is returned. - * - * @return a boolean indicating whether the relabeling succeeded. - */ - public static boolean restoreconRecursive(File file) { - try { - return native_restorecon(file.getCanonicalPath(), SELINUX_ANDROID_RESTORECON_RECURSE); - } catch (IOException e) { - Slog.e(TAG, "Error getting canonical path. Restorecon failed for " + - file.getPath(), e); - return false; - } - } -} diff --git a/src/main/java/android/os/SELinuxTest.java b/src/main/java/android/os/SELinuxTest.java deleted file mode 100644 index 9b63a6b..0000000 --- a/src/main/java/android/os/SELinuxTest.java +++ /dev/null @@ -1,45 +0,0 @@ -package android.os; - -import android.os.Process; -import android.os.SELinux; -import android.test.AndroidTestCase; -import static junit.framework.Assert.assertEquals; - -public class SELinuxTest extends AndroidTestCase { - - public void testgetFileCon() { - if(SELinux.isSELinuxEnabled() == false) - return; - - String ctx = SELinux.getFileContext("/system/bin/toolbox"); - assertEquals(ctx, "u:object_r:system_file:s0"); - } - - public void testgetCon() { - if(SELinux.isSELinuxEnabled() == false) - return; - - String mycon = SELinux.getContext(); - assertEquals(mycon, "u:r:untrusted_app:s0:c33"); - } - - public void testgetPidCon() { - if(SELinux.isSELinuxEnabled() == false) - return; - - String mycon = SELinux.getPidContext(Process.myPid()); - assertEquals(mycon, "u:r:untrusted_app:s0:c33"); - } - - public void testcheckSELinuxAccess() { - if(SELinux.isSELinuxEnabled() == false) - return; - - String mycon = SELinux.getContext(); - boolean ret; - ret = SELinux.checkSELinuxAccess(mycon, mycon, "process", "fork"); - assertEquals(ret,"true"); - ret = SELinux.checkSELinuxAccess(mycon, mycon, "memprotect", "mmap_zero"); - assertEquals(ret,"true"); - } -} diff --git a/src/main/java/android/os/ServiceManager.java b/src/main/java/android/os/ServiceManager.java deleted file mode 100644 index 6a68ee2..0000000 --- a/src/main/java/android/os/ServiceManager.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import java.util.Map; - -public final class ServiceManager { - - /** - * Returns a reference to a service with the given name. - * - * @param name the name of the service to get - * @return a reference to the service, or null if the service doesn't exist - */ - public static IBinder getService(String name) { - return null; - } - - /** - * Place a new @a service called @a name into the service - * manager. - * - * @param name the name of the new service - * @param service the service object - */ - public static void addService(String name, IBinder service) { - // pass - } - - /** - * Retrieve an existing service called @a name from the - * service manager. Non-blocking. - */ - public static IBinder checkService(String name) { - return null; - } - - /** - * Return a list of all currently running services. - */ - public static String[] listServices() throws RemoteException { - // actual implementation returns null sometimes, so it's ok - // to return null instead of an empty list. - return null; - } - - /** - * This is only intended to be called when the process is first being brought - * up and bound by the activity manager. There is only one thread in the process - * at that time, so no locking is done. - * - * @param cache the cache of service references - * @hide - */ - public static void initServiceCache(Map cache) { - // pass - } -} diff --git a/src/main/java/android/os/ServiceManagerNative.java b/src/main/java/android/os/ServiceManagerNative.java deleted file mode 100644 index be24426..0000000 --- a/src/main/java/android/os/ServiceManagerNative.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import java.util.ArrayList; - - -/** - * Native implementation of the service manager. Most clients will only - * care about getDefault() and possibly asInterface(). - * @hide - */ -public abstract class ServiceManagerNative extends Binder implements IServiceManager -{ - /** - * Cast a Binder object into a service manager interface, generating - * a proxy if needed. - */ - static public IServiceManager asInterface(IBinder obj) - { - if (obj == null) { - return null; - } - IServiceManager in = - (IServiceManager)obj.queryLocalInterface(descriptor); - if (in != null) { - return in; - } - - return new ServiceManagerProxy(obj); - } - - public ServiceManagerNative() - { - attachInterface(this, descriptor); - } - - public boolean onTransact(int code, Parcel data, Parcel reply, int flags) - { - try { - switch (code) { - case IServiceManager.GET_SERVICE_TRANSACTION: { - data.enforceInterface(IServiceManager.descriptor); - String name = data.readString(); - IBinder service = getService(name); - reply.writeStrongBinder(service); - return true; - } - - case IServiceManager.CHECK_SERVICE_TRANSACTION: { - data.enforceInterface(IServiceManager.descriptor); - String name = data.readString(); - IBinder service = checkService(name); - reply.writeStrongBinder(service); - return true; - } - - case IServiceManager.ADD_SERVICE_TRANSACTION: { - data.enforceInterface(IServiceManager.descriptor); - String name = data.readString(); - IBinder service = data.readStrongBinder(); - boolean allowIsolated = data.readInt() != 0; - addService(name, service, allowIsolated); - return true; - } - - case IServiceManager.LIST_SERVICES_TRANSACTION: { - data.enforceInterface(IServiceManager.descriptor); - String[] list = listServices(); - reply.writeStringArray(list); - return true; - } - - case IServiceManager.SET_PERMISSION_CONTROLLER_TRANSACTION: { - data.enforceInterface(IServiceManager.descriptor); - IPermissionController controller - = IPermissionController.Stub.asInterface( - data.readStrongBinder()); - setPermissionController(controller); - return true; - } - } - } catch (RemoteException e) { - } - - return false; - } - - public IBinder asBinder() - { - return this; - } -} - -class ServiceManagerProxy implements IServiceManager { - public ServiceManagerProxy(IBinder remote) { - mRemote = remote; - } - - public IBinder asBinder() { - return mRemote; - } - - public IBinder getService(String name) throws RemoteException { - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - data.writeInterfaceToken(IServiceManager.descriptor); - data.writeString(name); - mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0); - IBinder binder = reply.readStrongBinder(); - reply.recycle(); - data.recycle(); - return binder; - } - - public IBinder checkService(String name) throws RemoteException { - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - data.writeInterfaceToken(IServiceManager.descriptor); - data.writeString(name); - mRemote.transact(CHECK_SERVICE_TRANSACTION, data, reply, 0); - IBinder binder = reply.readStrongBinder(); - reply.recycle(); - data.recycle(); - return binder; - } - - public void addService(String name, IBinder service, boolean allowIsolated) - throws RemoteException { - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - data.writeInterfaceToken(IServiceManager.descriptor); - data.writeString(name); - data.writeStrongBinder(service); - data.writeInt(allowIsolated ? 1 : 0); - mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0); - reply.recycle(); - data.recycle(); - } - - public String[] listServices() throws RemoteException { - ArrayList services = new ArrayList(); - int n = 0; - while (true) { - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - data.writeInterfaceToken(IServiceManager.descriptor); - data.writeInt(n); - n++; - try { - boolean res = mRemote.transact(LIST_SERVICES_TRANSACTION, data, reply, 0); - if (!res) { - break; - } - } catch (RuntimeException e) { - // The result code that is returned by the C++ code can - // cause the call to throw an exception back instead of - // returning a nice result... so eat it here and go on. - break; - } - services.add(reply.readString()); - reply.recycle(); - data.recycle(); - } - String[] array = new String[services.size()]; - services.toArray(array); - return array; - } - - public void setPermissionController(IPermissionController controller) - throws RemoteException { - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - data.writeInterfaceToken(IServiceManager.descriptor); - data.writeStrongBinder(controller.asBinder()); - mRemote.transact(SET_PERMISSION_CONTROLLER_TRANSACTION, data, reply, 0); - reply.recycle(); - data.recycle(); - } - - private IBinder mRemote; -} diff --git a/src/main/java/android/os/SparseRectFArrayTest.java b/src/main/java/android/os/SparseRectFArrayTest.java deleted file mode 100644 index 47b0d2a..0000000 --- a/src/main/java/android/os/SparseRectFArrayTest.java +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.graphics.RectF; -import android.test.InstrumentationTestCase; -import android.test.suitebuilder.annotation.SmallTest; -import android.view.inputmethod.SparseRectFArray; -import android.view.inputmethod.SparseRectFArray.SparseRectFArrayBuilder; - -import java.util.Objects; - -public class SparseRectFArrayTest extends InstrumentationTestCase { - // A test data for {@link SparseRectFArray}. null represents the gap of indices. - private static final RectF[] MANY_RECTS = new RectF[] { - null, - new RectF(102.0f, 202.0f, 302.0f, 402.0f), - new RectF(103.0f, 203.0f, 303.0f, 403.0f), - new RectF(104.0f, 204.0f, 304.0f, 404.0f), - new RectF(105.0f, 205.0f, 305.0f, 405.0f), - new RectF(106.0f, 206.0f, 306.0f, 406.0f), - null, - new RectF(108.0f, 208.0f, 308.0f, 408.0f), - new RectF(109.0f, 209.0f, 309.0f, 409.0f), - new RectF(110.0f, 210.0f, 310.0f, 410.0f), - new RectF(111.0f, 211.0f, 311.0f, 411.0f), - new RectF(112.0f, 212.0f, 312.0f, 412.0f), - new RectF(113.0f, 213.0f, 313.0f, 413.0f), - new RectF(114.0f, 214.0f, 314.0f, 414.0f), - new RectF(115.0f, 215.0f, 315.0f, 415.0f), - new RectF(116.0f, 216.0f, 316.0f, 416.0f), - new RectF(117.0f, 217.0f, 317.0f, 417.0f), - null, - null, - new RectF(118.0f, 218.0f, 318.0f, 418.0f), - }; - - @SmallTest - public void testBuilder() throws Exception { - final RectF TEMP_RECT = new RectF(10.0f, 20.0f, 30.0f, 40.0f); - final int TEMP_FLAGS = 0x1234; - - final SparseRectFArrayBuilder builder = new SparseRectFArrayBuilder(); - builder.append(100, TEMP_RECT.left, TEMP_RECT.top, TEMP_RECT.right, TEMP_RECT.bottom, - TEMP_FLAGS); - assertNull(builder.build().get(-1)); - assertNull(builder.build().get(0)); - assertNull(builder.build().get(99)); - assertEquals(0, builder.build().getFlags(99, 0 /* valueIfKeyNotFound */)); - assertEquals(1, builder.build().getFlags(99, 1 /* valueIfKeyNotFound */)); - assertEquals(TEMP_RECT, builder.build().get(100)); - assertEquals(TEMP_FLAGS, builder.build().getFlags(100, 0 /* valueIfKeyNotFound */)); - assertEquals(TEMP_FLAGS, builder.build().getFlags(100, 1 /* valueIfKeyNotFound */)); - assertNull(builder.build().get(101)); - assertEquals(0, builder.build().getFlags(101, 0 /* valueIfKeyNotFound */)); - assertEquals(1, builder.build().getFlags(101, 1 /* valueIfKeyNotFound */)); - - // Test if {@link SparseRectFArrayBuilder#reset} resets its internal state. - builder.reset(); - assertNull(builder.build().get(100)); - - builder.reset(); - for (int i = 0; i < MANY_RECTS.length; i++) { - final RectF rect = MANY_RECTS[i]; - if (rect != null) { - builder.append(i, rect.left, rect.top, rect.right, rect.bottom, i); - } - } - final SparseRectFArray array = builder.build(); - for (int i = 0; i < MANY_RECTS.length; i++) { - final RectF expectedRect = MANY_RECTS[i]; - assertEquals(expectedRect, array.get(i)); - if (expectedRect != null) { - assertEquals(i, array.getFlags(i, 0x1234 /* valueIfKeyNotFound */)); - assertEquals(i, array.getFlags(i, 0x4321 /* valueIfKeyNotFound */)); - } else { - assertEquals(0x1234, array.getFlags(i, 0x1234 /* valueIfKeyNotFound */)); - assertEquals(0x4321, array.getFlags(i, 0x4321 /* valueIfKeyNotFound */)); - } - } - - // Make sure the builder reproduces an equivalent object. - final SparseRectFArray array2 = builder.build(); - for (int i = 0; i < MANY_RECTS.length; i++) { - final RectF expectedRect = MANY_RECTS[i]; - assertEquals(expectedRect, array2.get(i)); - if (expectedRect != null) { - assertEquals(i, array2.getFlags(i, 0x1234 /* valueIfKeyNotFound */)); - assertEquals(i, array2.getFlags(i, 0x4321 /* valueIfKeyNotFound */)); - } else { - assertEquals(0x1234, array2.getFlags(i, 0x1234 /* valueIfKeyNotFound */)); - assertEquals(0x4321, array2.getFlags(i, 0x4321 /* valueIfKeyNotFound */)); - } - } - assertEqualRects(array, array2); - - // Make sure the instance can be marshaled via {@link Parcel}. - final SparseRectFArray array3 = cloneViaParcel(array); - for (int i = 0; i < MANY_RECTS.length; i++) { - final RectF expectedRect = MANY_RECTS[i]; - assertEquals(expectedRect, array3.get(i)); - if (expectedRect != null) { - assertEquals(i, array3.getFlags(i, 0x1234 /* valueIfKeyNotFound */)); - assertEquals(i, array3.getFlags(i, 0x4321 /* valueIfKeyNotFound */)); - } else { - assertEquals(0x1234, array3.getFlags(i, 0x1234 /* valueIfKeyNotFound */)); - assertEquals(0x4321, array3.getFlags(i, 0x4321 /* valueIfKeyNotFound */)); - } - } - assertEqualRects(array, array3); - - // Make sure the builder can be reset. - builder.reset(); - assertNull(builder.build().get(0)); - } - - @SmallTest - public void testEquality() throws Exception { - // Empty array should be equal. - assertEqualRects(new SparseRectFArrayBuilder().build(), - new SparseRectFArrayBuilder().build()); - - assertEqualRects( - new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f, 1).build(), - new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f, 1).build()); - assertEqualRects( - new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0).build(), - new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0).build()); - assertNotEqualRects( - new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0).build(), - new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f, 1).build()); - assertNotEqualRects( - new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f, 1).build(), - new SparseRectFArrayBuilder().append(100, 2.0f, 2.0f, 3.0f, 4.0f, 1).build()); - assertNotEqualRects( - new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f, 1).build(), - new SparseRectFArrayBuilder().append(101, 1.0f, 2.0f, 3.0f, 4.0f, 1).build()); - - assertEqualRects( - new SparseRectFArrayBuilder() - .append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0) - .append(101, 0.0f, 0.0f, 0.0f, 0.0f, 0).build(), - new SparseRectFArrayBuilder() - .append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0) - .append(101, 0.0f, 0.0f, 0.0f, 0.0f, 0).build()); - assertNotEqualRects( - new SparseRectFArrayBuilder() - .append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0).build(), - new SparseRectFArrayBuilder() - .append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0) - .append(101, 0.0f, 0.0f, 0.0f, 0.0f, 0).build()); - assertNotEqualRects( - new SparseRectFArrayBuilder() - .append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0) - .append(101, 0.0f, 0.0f, 0.0f, 0.0f, 0).build(), - new SparseRectFArrayBuilder() - .append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0).build()); - assertNotEqualRects( - new SparseRectFArrayBuilder() - .append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0) - .append(101, 0.0f, 0.0f, 0.0f, 0.0f, 0).build(), - new SparseRectFArrayBuilder() - .append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0) - .append(101, 1.0f, 0.0f, 0.0f, 0.0f, 0).build()); - assertNotEqualRects( - new SparseRectFArrayBuilder() - .append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0) - .append(101, 1.0f, 0.0f, 0.0f, 0.0f, 0).build(), - new SparseRectFArrayBuilder() - .append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0) - .append(101, 0.0f, 0.0f, 0.0f, 0.0f, 0).build()); - assertNotEqualRects( - new SparseRectFArrayBuilder() - .append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0) - .append(101, 0.0f, 0.0f, 0.0f, 0.0f, 0).build(), - new SparseRectFArrayBuilder() - .append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0) - .append(102, 0.0f, 0.0f, 0.0f, 0.0f, 0).build()); - - assertEqualRects( - new SparseRectFArrayBuilder() - .append(1, 1.0f, 2.0f, 3.0f, 4.0f, 0) - .append(1000, 0.0f, 0.0f, 0.0f, 0.0f, 0) - .append(100000000, 0.0f, 0.0f, 0.0f, 0.0f, 0) - .build(), - new SparseRectFArrayBuilder() - .append(1, 1.0f, 2.0f, 3.0f, 4.0f, 0) - .append(1000, 0.0f, 0.0f, 0.0f, 0.0f, 0) - .append(100000000, 0.0f, 0.0f, 0.0f, 0.0f, 0) - .build()); - - assertNotEqualRects( - new SparseRectFArrayBuilder() - .append(1, 1.0f, 2.0f, 3.0f, 4.0f, 0) - .append(1000, 0.0f, 0.0f, 0.0f, 0.0f, 0) - .append(100000000, 0.0f, 0.0f, 0.0f, 0.0f, 0) - .build(), - new SparseRectFArrayBuilder() - .append(1, 1.0f, 2.0f, 3.0f, 4.0f, 0) - .build()); - assertNotEqualRects( - new SparseRectFArrayBuilder() - .append(1, 1.0f, 2.0f, 3.0f, 4.0f, 0) - .append(1000, 0.0f, 0.0f, 0.0f, 0.0f, 0) - .append(100000000, 0.0f, 0.0f, 0.0f, 0.0f, 0) - .build(), - new SparseRectFArrayBuilder() - .append(1, 1.0f, 2.0f, 3.0f, 4.0f, 0) - .append(1000, 1.0f, 0.0f, 0.0f, 0.0f, 0) - .append(100000000, 0.0f, 0.0f, 0.0f, 0.0f, 0) - .build()); - } - - @SmallTest - public void testBuilderAppend() throws Exception { - // Key should be appended in ascending order. - try { - new SparseRectFArrayBuilder() - .append(10, 0.0f, 0.0f, 0.0f, 0.0f, 0) - .append(0, 1.0f, 2.0f, 3.0f, 4.0f, 0); - } catch (IllegalArgumentException ex) { - assertTrue(true); - } - - try { - new SparseRectFArrayBuilder() - .append(10, 0.0f, 0.0f, 0.0f, 0.0f, 0) - .append(10, 1.0f, 2.0f, 3.0f, 4.0f, 0); - } catch (IllegalArgumentException ex) { - assertTrue(true); - } - } - - private static void assertEqualRects(SparseRectFArray a, SparseRectFArray b) { - assertEquals(a, b); - if (a != null && b != null) { - assertEquals(a.hashCode(), b.hashCode()); - } - } - - private static void assertNotEqualRects(SparseRectFArray a, SparseRectFArray b) { - assertFalse(Objects.equals(a, b)); - } - - private static SparseRectFArray cloneViaParcel(final SparseRectFArray src) { - Parcel parcel = null; - try { - parcel = Parcel.obtain(); - src.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - return new SparseRectFArray(parcel); - } finally { - if (parcel != null) { - parcel.recycle(); - } - } - } -} diff --git a/src/main/java/android/os/StatFs.java b/src/main/java/android/os/StatFs.java deleted file mode 100644 index 13e9a15..0000000 --- a/src/main/java/android/os/StatFs.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.system.ErrnoException; -import android.system.Os; -import android.system.StructStatVfs; - -/** - * Retrieve overall information about the space on a filesystem. This is a - * wrapper for Unix statvfs(). - */ -public class StatFs { - private StructStatVfs mStat; - - /** - * Construct a new StatFs for looking at the stats of the filesystem at - * {@code path}. Upon construction, the stat of the file system will be - * performed, and the values retrieved available from the methods on this - * class. - * - * @param path path in the desired file system to stat. - */ - public StatFs(String path) { - mStat = doStat(path); - } - - private static StructStatVfs doStat(String path) { - try { - return Os.statvfs(path); - } catch (ErrnoException e) { - throw new IllegalArgumentException("Invalid path: " + path, e); - } - } - - /** - * Perform a restat of the file system referenced by this object. This is - * the same as re-constructing the object with the same file system path, - * and the new stat values are available upon return. - */ - public void restat(String path) { - mStat = doStat(path); - } - - /** - * @deprecated Use {@link #getBlockSizeLong()} instead. - */ - @Deprecated - public int getBlockSize() { - return (int) mStat.f_bsize; - } - - /** - * The size, in bytes, of a block on the file system. This corresponds to - * the Unix {@code statvfs.f_bsize} field. - */ - public long getBlockSizeLong() { - return mStat.f_bsize; - } - - /** - * @deprecated Use {@link #getBlockCountLong()} instead. - */ - @Deprecated - public int getBlockCount() { - return (int) mStat.f_blocks; - } - - /** - * The total number of blocks on the file system. This corresponds to the - * Unix {@code statvfs.f_blocks} field. - */ - public long getBlockCountLong() { - return mStat.f_blocks; - } - - /** - * @deprecated Use {@link #getFreeBlocksLong()} instead. - */ - @Deprecated - public int getFreeBlocks() { - return (int) mStat.f_bfree; - } - - /** - * The total number of blocks that are free on the file system, including - * reserved blocks (that are not available to normal applications). This - * corresponds to the Unix {@code statvfs.f_bfree} field. Most applications - * will want to use {@link #getAvailableBlocks()} instead. - */ - public long getFreeBlocksLong() { - return mStat.f_bfree; - } - - /** - * The number of bytes that are free on the file system, including reserved - * blocks (that are not available to normal applications). Most applications - * will want to use {@link #getAvailableBytes()} instead. - */ - public long getFreeBytes() { - return mStat.f_bfree * mStat.f_bsize; - } - - /** - * @deprecated Use {@link #getAvailableBlocksLong()} instead. - */ - @Deprecated - public int getAvailableBlocks() { - return (int) mStat.f_bavail; - } - - /** - * The number of blocks that are free on the file system and available to - * applications. This corresponds to the Unix {@code statvfs.f_bavail} field. - */ - public long getAvailableBlocksLong() { - return mStat.f_bavail; - } - - /** - * The number of bytes that are free on the file system and available to - * applications. - */ - public long getAvailableBytes() { - return mStat.f_bavail * mStat.f_bsize; - } - - /** - * The total number of bytes supported by the file system. - */ - public long getTotalBytes() { - return mStat.f_blocks * mStat.f_bsize; - } -} diff --git a/src/main/java/android/os/StrictMode.java b/src/main/java/android/os/StrictMode.java deleted file mode 100644 index 6db5f67..0000000 --- a/src/main/java/android/os/StrictMode.java +++ /dev/null @@ -1,2328 +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.os; - -import android.animation.ValueAnimator; -import android.app.ActivityManagerNative; -import android.app.ActivityThread; -import android.app.ApplicationErrorReport; -import android.app.IActivityManager; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.util.ArrayMap; -import android.util.Log; -import android.util.Printer; -import android.util.Singleton; -import android.util.Slog; -import android.view.IWindowManager; - -import com.android.internal.os.RuntimeInit; - -import com.android.internal.util.FastPrintWriter; -import dalvik.system.BlockGuard; -import dalvik.system.CloseGuard; -import dalvik.system.VMDebug; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; - -/** - *

    StrictMode is a developer tool which detects things you might be - * doing by accident and brings them to your attention so you can fix - * them. - * - *

    StrictMode is most commonly used to catch accidental disk or - * network access on the application's main thread, where UI - * operations are received and animations take place. Keeping disk - * and network operations off the main thread makes for much smoother, - * more responsive applications. By keeping your application's main thread - * responsive, you also prevent - * ANR dialogs - * from being shown to users. - * - *

    Note that even though an Android device's disk is - * often on flash memory, many devices run a filesystem on top of that - * memory with very limited concurrency. It's often the case that - * almost all disk accesses are fast, but may in individual cases be - * dramatically slower when certain I/O is happening in the background - * from other processes. If possible, it's best to assume that such - * things are not fast.

    - * - *

    Example code to enable from early in your - * {@link android.app.Application}, {@link android.app.Activity}, or - * other application component's - * {@link android.app.Application#onCreate} method: - * - *

    - * public void onCreate() {
    - *     if (DEVELOPER_MODE) {
    - *         StrictMode.setThreadPolicy(new {@link ThreadPolicy.Builder StrictMode.ThreadPolicy.Builder}()
    - *                 .detectDiskReads()
    - *                 .detectDiskWrites()
    - *                 .detectNetwork()   // or .detectAll() for all detectable problems
    - *                 .penaltyLog()
    - *                 .build());
    - *         StrictMode.setVmPolicy(new {@link VmPolicy.Builder StrictMode.VmPolicy.Builder}()
    - *                 .detectLeakedSqlLiteObjects()
    - *                 .detectLeakedClosableObjects()
    - *                 .penaltyLog()
    - *                 .penaltyDeath()
    - *                 .build());
    - *     }
    - *     super.onCreate();
    - * }
    - * 
    - * - *

    You can decide what should happen when a violation is detected. - * For example, using {@link ThreadPolicy.Builder#penaltyLog} you can - * watch the output of adb logcat while you use your - * application to see the violations as they happen. - * - *

    If you find violations that you feel are problematic, there are - * a variety of tools to help solve them: threads, {@link android.os.Handler}, - * {@link android.os.AsyncTask}, {@link android.app.IntentService}, etc. - * But don't feel compelled to fix everything that StrictMode finds. In particular, - * many cases of disk access are often necessary during the normal activity lifecycle. Use - * StrictMode to find things you did by accident. Network requests on the UI thread - * are almost always a problem, though. - * - *

    StrictMode is not a security mechanism and is not - * guaranteed to find all disk or network accesses. While it does - * propagate its state across process boundaries when doing - * {@link android.os.Binder} calls, it's still ultimately a best - * effort mechanism. Notably, disk or network access from JNI calls - * won't necessarily trigger it. Future versions of Android may catch - * more (or fewer) operations, so you should never leave StrictMode - * enabled in applications distributed on Google Play. - */ -public final class StrictMode { - private static final String TAG = "StrictMode"; - private static final boolean LOG_V = Log.isLoggable(TAG, Log.VERBOSE); - - private static final boolean IS_USER_BUILD = "user".equals(Build.TYPE); - private static final boolean IS_ENG_BUILD = "eng".equals(Build.TYPE); - - /** - * Boolean system property to disable strict mode checks outright. - * Set this to 'true' to force disable; 'false' has no effect on other - * enable/disable policy. - * @hide - */ - public static final String DISABLE_PROPERTY = "persist.sys.strictmode.disable"; - - /** - * The boolean system property to control screen flashes on violations. - * - * @hide - */ - public static final String VISUAL_PROPERTY = "persist.sys.strictmode.visual"; - - // Only log a duplicate stack trace to the logs every second. - private static final long MIN_LOG_INTERVAL_MS = 1000; - - // Only show an annoying dialog at most every 30 seconds - private static final long MIN_DIALOG_INTERVAL_MS = 30000; - - // How many Span tags (e.g. animations) to report. - private static final int MAX_SPAN_TAGS = 20; - - // How many offending stacks to keep track of (and time) per loop - // of the Looper. - private static final int MAX_OFFENSES_PER_LOOP = 10; - - // Thread-policy: - - /** - * @hide - */ - public static final int DETECT_DISK_WRITE = 0x01; // for ThreadPolicy - - /** - * @hide - */ - public static final int DETECT_DISK_READ = 0x02; // for ThreadPolicy - - /** - * @hide - */ - public static final int DETECT_NETWORK = 0x04; // for ThreadPolicy - - /** - * For StrictMode.noteSlowCall() - * - * @hide - */ - public static final int DETECT_CUSTOM = 0x08; // for ThreadPolicy - - private static final int ALL_THREAD_DETECT_BITS = - DETECT_DISK_WRITE | DETECT_DISK_READ | DETECT_NETWORK | DETECT_CUSTOM; - - // Process-policy: - - /** - * Note, a "VM_" bit, not thread. - * @hide - */ - public static final int DETECT_VM_CURSOR_LEAKS = 0x200; // for VmPolicy - - /** - * Note, a "VM_" bit, not thread. - * @hide - */ - public static final int DETECT_VM_CLOSABLE_LEAKS = 0x400; // for VmPolicy - - /** - * Note, a "VM_" bit, not thread. - * @hide - */ - public static final int DETECT_VM_ACTIVITY_LEAKS = 0x800; // for VmPolicy - - /** - * @hide - */ - private static final int DETECT_VM_INSTANCE_LEAKS = 0x1000; // for VmPolicy - - /** - * @hide - */ - public static final int DETECT_VM_REGISTRATION_LEAKS = 0x2000; // for VmPolicy - - /** - * @hide - */ - private static final int DETECT_VM_FILE_URI_EXPOSURE = 0x4000; // for VmPolicy - - private static final int ALL_VM_DETECT_BITS = - DETECT_VM_CURSOR_LEAKS | DETECT_VM_CLOSABLE_LEAKS | - DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_INSTANCE_LEAKS | - DETECT_VM_REGISTRATION_LEAKS | DETECT_VM_FILE_URI_EXPOSURE; - - /** - * @hide - */ - public static final int PENALTY_LOG = 0x10; // normal android.util.Log - - // Used for both process and thread policy: - - /** - * @hide - */ - public static final int PENALTY_DIALOG = 0x20; - - /** - * Death on any detected violation. - * - * @hide - */ - public static final int PENALTY_DEATH = 0x40; - - /** - * Death just for detected network usage. - * - * @hide - */ - public static final int PENALTY_DEATH_ON_NETWORK = 0x200; - - /** - * Flash the screen during violations. - * - * @hide - */ - public static final int PENALTY_FLASH = 0x800; - - /** - * @hide - */ - public static final int PENALTY_DROPBOX = 0x80; - - /** - * Non-public penalty mode which overrides all the other penalty - * bits and signals that we're in a Binder call and we should - * ignore the other penalty bits and instead serialize back all - * our offending stack traces to the caller to ultimately handle - * in the originating process. - * - * This must be kept in sync with the constant in libs/binder/Parcel.cpp - * - * @hide - */ - public static final int PENALTY_GATHER = 0x100; - - /** - * Mask of all the penalty bits valid for thread policies. - */ - private static final int THREAD_PENALTY_MASK = - PENALTY_LOG | PENALTY_DIALOG | PENALTY_DEATH | PENALTY_DROPBOX | PENALTY_GATHER | - PENALTY_DEATH_ON_NETWORK | PENALTY_FLASH; - - - /** - * Mask of all the penalty bits valid for VM policies. - */ - private static final int VM_PENALTY_MASK = - PENALTY_LOG | PENALTY_DEATH | PENALTY_DROPBOX; - - - // TODO: wrap in some ImmutableHashMap thing. - // Note: must be before static initialization of sVmPolicy. - private static final HashMap EMPTY_CLASS_LIMIT_MAP = new HashMap(); - - /** - * The current VmPolicy in effect. - * - * TODO: these are redundant (mask is in VmPolicy). Should remove sVmPolicyMask. - */ - private static volatile int sVmPolicyMask = 0; - private static volatile VmPolicy sVmPolicy = VmPolicy.LAX; - - /** - * The number of threads trying to do an async dropbox write. - * Just to limit ourselves out of paranoia. - */ - private static final AtomicInteger sDropboxCallsInFlight = new AtomicInteger(0); - - private StrictMode() {} - - /** - * {@link StrictMode} policy applied to a certain thread. - * - *

    The policy is enabled by {@link #setThreadPolicy}. The current policy - * can be retrieved with {@link #getThreadPolicy}. - * - *

    Note that multiple penalties may be provided and they're run - * in order from least to most severe (logging before process - * death, for example). There's currently no mechanism to choose - * different penalties for different detected actions. - */ - public static final class ThreadPolicy { - /** - * The default, lax policy which doesn't catch anything. - */ - public static final ThreadPolicy LAX = new ThreadPolicy(0); - - final int mask; - - private ThreadPolicy(int mask) { - this.mask = mask; - } - - @Override - public String toString() { - return "[StrictMode.ThreadPolicy; mask=" + mask + "]"; - } - - /** - * Creates {@link ThreadPolicy} instances. Methods whose names start - * with {@code detect} specify what problems we should look - * for. Methods whose names start with {@code penalty} specify what - * we should do when we detect a problem. - * - *

    You can call as many {@code detect} and {@code penalty} - * methods as you like. Currently order is insignificant: all - * penalties apply to all detected problems. - * - *

    For example, detect everything and log anything that's found: - *

    -         * StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
    -         *     .detectAll()
    -         *     .penaltyLog()
    -         *     .build();
    -         * StrictMode.setThreadPolicy(policy);
    -         * 
    - */ - public static final class Builder { - private int mMask = 0; - - /** - * Create a Builder that detects nothing and has no - * violations. (but note that {@link #build} will default - * to enabling {@link #penaltyLog} if no other penalties - * are specified) - */ - public Builder() { - mMask = 0; - } - - /** - * Initialize a Builder from an existing ThreadPolicy. - */ - public Builder(ThreadPolicy policy) { - mMask = policy.mask; - } - - /** - * Detect everything that's potentially suspect. - * - *

    As of the Gingerbread release this includes network and - * disk operations but will likely expand in future releases. - */ - public Builder detectAll() { - return enable(ALL_THREAD_DETECT_BITS); - } - - /** - * Disable the detection of everything. - */ - public Builder permitAll() { - return disable(ALL_THREAD_DETECT_BITS); - } - - /** - * Enable detection of network operations. - */ - public Builder detectNetwork() { - return enable(DETECT_NETWORK); - } - - /** - * Disable detection of network operations. - */ - public Builder permitNetwork() { - return disable(DETECT_NETWORK); - } - - /** - * Enable detection of disk reads. - */ - public Builder detectDiskReads() { - return enable(DETECT_DISK_READ); - } - - /** - * Disable detection of disk reads. - */ - public Builder permitDiskReads() { - return disable(DETECT_DISK_READ); - } - - /** - * Enable detection of slow calls. - */ - public Builder detectCustomSlowCalls() { - return enable(DETECT_CUSTOM); - } - - /** - * Disable detection of slow calls. - */ - public Builder permitCustomSlowCalls() { - return disable(DETECT_CUSTOM); - } - - /** - * Enable detection of disk writes. - */ - public Builder detectDiskWrites() { - return enable(DETECT_DISK_WRITE); - } - - /** - * Disable detection of disk writes. - */ - public Builder permitDiskWrites() { - return disable(DETECT_DISK_WRITE); - } - - /** - * Show an annoying dialog to the developer on detected - * violations, rate-limited to be only a little annoying. - */ - public Builder penaltyDialog() { - return enable(PENALTY_DIALOG); - } - - /** - * Crash the whole process on violation. This penalty runs at - * the end of all enabled penalties so you'll still get - * see logging or other violations before the process dies. - * - *

    Unlike {@link #penaltyDeathOnNetwork}, this applies - * to disk reads, disk writes, and network usage if their - * corresponding detect flags are set. - */ - public Builder penaltyDeath() { - return enable(PENALTY_DEATH); - } - - /** - * Crash the whole process on any network usage. Unlike - * {@link #penaltyDeath}, this penalty runs - * before anything else. You must still have - * called {@link #detectNetwork} to enable this. - * - *

    In the Honeycomb or later SDKs, this is on by default. - */ - public Builder penaltyDeathOnNetwork() { - return enable(PENALTY_DEATH_ON_NETWORK); - } - - /** - * Flash the screen during a violation. - */ - public Builder penaltyFlashScreen() { - return enable(PENALTY_FLASH); - } - - /** - * Log detected violations to the system log. - */ - public Builder penaltyLog() { - return enable(PENALTY_LOG); - } - - /** - * Enable detected violations log a stacktrace and timing data - * to the {@link android.os.DropBoxManager DropBox} on policy - * violation. Intended mostly for platform integrators doing - * beta user field data collection. - */ - public Builder penaltyDropBox() { - return enable(PENALTY_DROPBOX); - } - - private Builder enable(int bit) { - mMask |= bit; - return this; - } - - private Builder disable(int bit) { - mMask &= ~bit; - return this; - } - - /** - * Construct the ThreadPolicy instance. - * - *

    Note: if no penalties are enabled before calling - * build, {@link #penaltyLog} is implicitly - * set. - */ - public ThreadPolicy build() { - // If there are detection bits set but no violation bits - // set, enable simple logging. - if (mMask != 0 && - (mMask & (PENALTY_DEATH | PENALTY_LOG | - PENALTY_DROPBOX | PENALTY_DIALOG)) == 0) { - penaltyLog(); - } - return new ThreadPolicy(mMask); - } - } - } - - /** - * {@link StrictMode} policy applied to all threads in the virtual machine's process. - * - *

    The policy is enabled by {@link #setVmPolicy}. - */ - public static final class VmPolicy { - /** - * The default, lax policy which doesn't catch anything. - */ - public static final VmPolicy LAX = new VmPolicy(0, EMPTY_CLASS_LIMIT_MAP); - - final int mask; - - // Map from class to max number of allowed instances in memory. - final HashMap classInstanceLimit; - - private VmPolicy(int mask, HashMap classInstanceLimit) { - if (classInstanceLimit == null) { - throw new NullPointerException("classInstanceLimit == null"); - } - this.mask = mask; - this.classInstanceLimit = classInstanceLimit; - } - - @Override - public String toString() { - return "[StrictMode.VmPolicy; mask=" + mask + "]"; - } - - /** - * Creates {@link VmPolicy} instances. Methods whose names start - * with {@code detect} specify what problems we should look - * for. Methods whose names start with {@code penalty} specify what - * we should do when we detect a problem. - * - *

    You can call as many {@code detect} and {@code penalty} - * methods as you like. Currently order is insignificant: all - * penalties apply to all detected problems. - * - *

    For example, detect everything and log anything that's found: - *

    -         * StrictMode.VmPolicy policy = new StrictMode.VmPolicy.Builder()
    -         *     .detectAll()
    -         *     .penaltyLog()
    -         *     .build();
    -         * StrictMode.setVmPolicy(policy);
    -         * 
    - */ - public static final class Builder { - private int mMask; - - private HashMap mClassInstanceLimit; // null until needed - private boolean mClassInstanceLimitNeedCow = false; // need copy-on-write - - public Builder() { - mMask = 0; - } - - /** - * Build upon an existing VmPolicy. - */ - public Builder(VmPolicy base) { - mMask = base.mask; - mClassInstanceLimitNeedCow = true; - mClassInstanceLimit = base.classInstanceLimit; - } - - /** - * Set an upper bound on how many instances of a class can be in memory - * at once. Helps to prevent object leaks. - */ - public Builder setClassInstanceLimit(Class klass, int instanceLimit) { - if (klass == null) { - throw new NullPointerException("klass == null"); - } - if (mClassInstanceLimitNeedCow) { - if (mClassInstanceLimit.containsKey(klass) && - mClassInstanceLimit.get(klass) == instanceLimit) { - // no-op; don't break COW - return this; - } - mClassInstanceLimitNeedCow = false; - mClassInstanceLimit = (HashMap) mClassInstanceLimit.clone(); - } else if (mClassInstanceLimit == null) { - mClassInstanceLimit = new HashMap(); - } - mMask |= DETECT_VM_INSTANCE_LEAKS; - mClassInstanceLimit.put(klass, instanceLimit); - return this; - } - - /** - * Detect leaks of {@link android.app.Activity} subclasses. - */ - public Builder detectActivityLeaks() { - return enable(DETECT_VM_ACTIVITY_LEAKS); - } - - /** - * Detect everything that's potentially suspect. - * - *

    In the Honeycomb release this includes leaks of - * SQLite cursors, Activities, and other closable objects - * but will likely expand in future releases. - */ - public Builder detectAll() { - return enable(DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_CURSOR_LEAKS - | DETECT_VM_CLOSABLE_LEAKS | DETECT_VM_REGISTRATION_LEAKS - | DETECT_VM_FILE_URI_EXPOSURE); - } - - /** - * Detect when an - * {@link android.database.sqlite.SQLiteCursor} or other - * SQLite object is finalized without having been closed. - * - *

    You always want to explicitly close your SQLite - * cursors to avoid unnecessary database contention and - * temporary memory leaks. - */ - public Builder detectLeakedSqlLiteObjects() { - return enable(DETECT_VM_CURSOR_LEAKS); - } - - /** - * Detect when an {@link java.io.Closeable} or other - * object with a explict termination method is finalized - * without having been closed. - * - *

    You always want to explicitly close such objects to - * avoid unnecessary resources leaks. - */ - public Builder detectLeakedClosableObjects() { - return enable(DETECT_VM_CLOSABLE_LEAKS); - } - - /** - * Detect when a {@link BroadcastReceiver} or - * {@link ServiceConnection} is leaked during {@link Context} - * teardown. - */ - public Builder detectLeakedRegistrationObjects() { - return enable(DETECT_VM_REGISTRATION_LEAKS); - } - - /** - * Detect when a {@code file://} {@link android.net.Uri} is exposed beyond this - * app. The receiving app may not have access to the sent path. - * Instead, when sharing files between apps, {@code content://} - * should be used with permission grants. - */ - public Builder detectFileUriExposure() { - return enable(DETECT_VM_FILE_URI_EXPOSURE); - } - - /** - * Crashes the whole process on violation. This penalty runs at - * the end of all enabled penalties so yo you'll still get - * your logging or other violations before the process dies. - */ - public Builder penaltyDeath() { - return enable(PENALTY_DEATH); - } - - /** - * Log detected violations to the system log. - */ - public Builder penaltyLog() { - return enable(PENALTY_LOG); - } - - /** - * Enable detected violations log a stacktrace and timing data - * to the {@link android.os.DropBoxManager DropBox} on policy - * violation. Intended mostly for platform integrators doing - * beta user field data collection. - */ - public Builder penaltyDropBox() { - return enable(PENALTY_DROPBOX); - } - - private Builder enable(int bit) { - mMask |= bit; - return this; - } - - /** - * Construct the VmPolicy instance. - * - *

    Note: if no penalties are enabled before calling - * build, {@link #penaltyLog} is implicitly - * set. - */ - public VmPolicy build() { - // If there are detection bits set but no violation bits - // set, enable simple logging. - if (mMask != 0 && - (mMask & (PENALTY_DEATH | PENALTY_LOG | - PENALTY_DROPBOX | PENALTY_DIALOG)) == 0) { - penaltyLog(); - } - return new VmPolicy(mMask, - mClassInstanceLimit != null ? mClassInstanceLimit : EMPTY_CLASS_LIMIT_MAP); - } - } - } - - /** - * Log of strict mode violation stack traces that have occurred - * during a Binder call, to be serialized back later to the caller - * via Parcel.writeNoException() (amusingly) where the caller can - * choose how to react. - */ - private static final ThreadLocal> gatheredViolations = - new ThreadLocal>() { - @Override protected ArrayList initialValue() { - // Starts null to avoid unnecessary allocations when - // checking whether there are any violations or not in - // hasGatheredViolations() below. - return null; - } - }; - - /** - * Sets the policy for what actions on the current thread should - * be detected, as well as the penalty if such actions occur. - * - *

    Internally this sets a thread-local variable which is - * propagated across cross-process IPC calls, meaning you can - * catch violations when a system service or another process - * accesses the disk or network on your behalf. - * - * @param policy the policy to put into place - */ - public static void setThreadPolicy(final ThreadPolicy policy) { - setThreadPolicyMask(policy.mask); - } - - private static void setThreadPolicyMask(final int policyMask) { - // In addition to the Java-level thread-local in Dalvik's - // BlockGuard, we also need to keep a native thread-local in - // Binder in order to propagate the value across Binder calls, - // even across native-only processes. The two are kept in - // sync via the callback to onStrictModePolicyChange, below. - setBlockGuardPolicy(policyMask); - - // And set the Android native version... - Binder.setThreadStrictModePolicy(policyMask); - } - - // Sets the policy in Dalvik/libcore (BlockGuard) - private static void setBlockGuardPolicy(final int policyMask) { - if (policyMask == 0) { - BlockGuard.setThreadPolicy(BlockGuard.LAX_POLICY); - return; - } - final BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); - final AndroidBlockGuardPolicy androidPolicy; - if (policy instanceof AndroidBlockGuardPolicy) { - androidPolicy = (AndroidBlockGuardPolicy) policy; - } else { - androidPolicy = threadAndroidPolicy.get(); - BlockGuard.setThreadPolicy(androidPolicy); - } - androidPolicy.setPolicyMask(policyMask); - } - - // Sets up CloseGuard in Dalvik/libcore - private static void setCloseGuardEnabled(boolean enabled) { - if (!(CloseGuard.getReporter() instanceof AndroidCloseGuardReporter)) { - CloseGuard.setReporter(new AndroidCloseGuardReporter()); - } - CloseGuard.setEnabled(enabled); - } - - /** - * @hide - */ - public static class StrictModeViolation extends BlockGuard.BlockGuardPolicyException { - public StrictModeViolation(int policyState, int policyViolated, String message) { - super(policyState, policyViolated, message); - } - } - - /** - * @hide - */ - public static class StrictModeNetworkViolation extends StrictModeViolation { - public StrictModeNetworkViolation(int policyMask) { - super(policyMask, DETECT_NETWORK, null); - } - } - - /** - * @hide - */ - private static class StrictModeDiskReadViolation extends StrictModeViolation { - public StrictModeDiskReadViolation(int policyMask) { - super(policyMask, DETECT_DISK_READ, null); - } - } - - /** - * @hide - */ - private static class StrictModeDiskWriteViolation extends StrictModeViolation { - public StrictModeDiskWriteViolation(int policyMask) { - super(policyMask, DETECT_DISK_WRITE, null); - } - } - - /** - * @hide - */ - private static class StrictModeCustomViolation extends StrictModeViolation { - public StrictModeCustomViolation(int policyMask, String name) { - super(policyMask, DETECT_CUSTOM, name); - } - } - - /** - * Returns the bitmask of the current thread's policy. - * - * @return the bitmask of all the DETECT_* and PENALTY_* bits currently enabled - * - * @hide - */ - public static int getThreadPolicyMask() { - return BlockGuard.getThreadPolicy().getPolicyMask(); - } - - /** - * Returns the current thread's policy. - */ - public static ThreadPolicy getThreadPolicy() { - // TODO: this was a last minute Gingerbread API change (to - // introduce VmPolicy cleanly) but this isn't particularly - // optimal for users who might call this method often. This - // should be in a thread-local and not allocate on each call. - return new ThreadPolicy(getThreadPolicyMask()); - } - - /** - * A convenience wrapper that takes the current - * {@link ThreadPolicy} from {@link #getThreadPolicy}, modifies it - * to permit both disk reads & writes, and sets the new policy - * with {@link #setThreadPolicy}, returning the old policy so you - * can restore it at the end of a block. - * - * @return the old policy, to be passed to {@link #setThreadPolicy} to - * restore the policy at the end of a block - */ - public static ThreadPolicy allowThreadDiskWrites() { - int oldPolicyMask = getThreadPolicyMask(); - int newPolicyMask = oldPolicyMask & ~(DETECT_DISK_WRITE | DETECT_DISK_READ); - if (newPolicyMask != oldPolicyMask) { - setThreadPolicyMask(newPolicyMask); - } - return new ThreadPolicy(oldPolicyMask); - } - - /** - * A convenience wrapper that takes the current - * {@link ThreadPolicy} from {@link #getThreadPolicy}, modifies it - * to permit disk reads, and sets the new policy - * with {@link #setThreadPolicy}, returning the old policy so you - * can restore it at the end of a block. - * - * @return the old policy, to be passed to setThreadPolicy to - * restore the policy. - */ - public static ThreadPolicy allowThreadDiskReads() { - int oldPolicyMask = getThreadPolicyMask(); - int newPolicyMask = oldPolicyMask & ~(DETECT_DISK_READ); - if (newPolicyMask != oldPolicyMask) { - setThreadPolicyMask(newPolicyMask); - } - return new ThreadPolicy(oldPolicyMask); - } - - // We don't want to flash the screen red in the system server - // process, nor do we want to modify all the call sites of - // conditionallyEnableDebugLogging() in the system server, - // so instead we use this to determine if we are the system server. - private static boolean amTheSystemServerProcess() { - // Fast path. Most apps don't have the system server's UID. - if (Process.myUid() != Process.SYSTEM_UID) { - return false; - } - - // The settings app, though, has the system server's UID so - // look up our stack to see if we came from the system server. - Throwable stack = new Throwable(); - stack.fillInStackTrace(); - for (StackTraceElement ste : stack.getStackTrace()) { - String clsName = ste.getClassName(); - if (clsName != null && clsName.startsWith("com.android.server.")) { - return true; - } - } - return false; - } - - /** - * Enable DropBox logging for debug phone builds. - * - * @hide - */ - public static boolean conditionallyEnableDebugLogging() { - boolean doFlashes = SystemProperties.getBoolean(VISUAL_PROPERTY, false) - && !amTheSystemServerProcess(); - final boolean suppress = SystemProperties.getBoolean(DISABLE_PROPERTY, false); - - // For debug builds, log event loop stalls to dropbox for analysis. - // Similar logic also appears in ActivityThread.java for system apps. - if (!doFlashes && (IS_USER_BUILD || suppress)) { - setCloseGuardEnabled(false); - return false; - } - - // Eng builds have flashes on all the time. The suppression property - // overrides this, so we force the behavior only after the short-circuit - // check above. - if (IS_ENG_BUILD) { - doFlashes = true; - } - - // Thread policy controls BlockGuard. - int threadPolicyMask = StrictMode.DETECT_DISK_WRITE | - StrictMode.DETECT_DISK_READ | - StrictMode.DETECT_NETWORK; - - if (!IS_USER_BUILD) { - threadPolicyMask |= StrictMode.PENALTY_DROPBOX; - } - if (doFlashes) { - threadPolicyMask |= StrictMode.PENALTY_FLASH; - } - - StrictMode.setThreadPolicyMask(threadPolicyMask); - - // VM Policy controls CloseGuard, detection of Activity leaks, - // and instance counting. - if (IS_USER_BUILD) { - setCloseGuardEnabled(false); - } else { - VmPolicy.Builder policyBuilder = new VmPolicy.Builder().detectAll().penaltyDropBox(); - if (IS_ENG_BUILD) { - policyBuilder.penaltyLog(); - } - setVmPolicy(policyBuilder.build()); - setCloseGuardEnabled(vmClosableObjectLeaksEnabled()); - } - return true; - } - - /** - * Used by the framework to make network usage on the main - * thread a fatal error. - * - * @hide - */ - public static void enableDeathOnNetwork() { - int oldPolicy = getThreadPolicyMask(); - int newPolicy = oldPolicy | DETECT_NETWORK | PENALTY_DEATH_ON_NETWORK; - setThreadPolicyMask(newPolicy); - } - - /** - * Parses the BlockGuard policy mask out from the Exception's - * getMessage() String value. Kinda gross, but least - * invasive. :/ - * - * Input is of the following forms: - * "policy=137 violation=64" - * "policy=137 violation=64 msg=Arbitrary text" - * - * Returns 0 on failure, which is a valid policy, but not a - * valid policy during a violation (else there must've been - * some policy in effect to violate). - */ - private static int parsePolicyFromMessage(String message) { - if (message == null || !message.startsWith("policy=")) { - return 0; - } - int spaceIndex = message.indexOf(' '); - if (spaceIndex == -1) { - return 0; - } - String policyString = message.substring(7, spaceIndex); - try { - return Integer.valueOf(policyString).intValue(); - } catch (NumberFormatException e) { - return 0; - } - } - - /** - * Like parsePolicyFromMessage(), but returns the violation. - */ - private static int parseViolationFromMessage(String message) { - if (message == null) { - return 0; - } - int violationIndex = message.indexOf("violation="); - if (violationIndex == -1) { - return 0; - } - int numberStartIndex = violationIndex + "violation=".length(); - int numberEndIndex = message.indexOf(' ', numberStartIndex); - if (numberEndIndex == -1) { - numberEndIndex = message.length(); - } - String violationString = message.substring(numberStartIndex, numberEndIndex); - try { - return Integer.valueOf(violationString).intValue(); - } catch (NumberFormatException e) { - return 0; - } - } - - private static final ThreadLocal> violationsBeingTimed = - new ThreadLocal>() { - @Override protected ArrayList initialValue() { - return new ArrayList(); - } - }; - - // Note: only access this once verifying the thread has a Looper. - private static final ThreadLocal threadHandler = new ThreadLocal() { - @Override protected Handler initialValue() { - return new Handler(); - } - }; - - private static final ThreadLocal - threadAndroidPolicy = new ThreadLocal() { - @Override - protected AndroidBlockGuardPolicy initialValue() { - return new AndroidBlockGuardPolicy(0); - } - }; - - private static boolean tooManyViolationsThisLoop() { - return violationsBeingTimed.get().size() >= MAX_OFFENSES_PER_LOOP; - } - - private static class AndroidBlockGuardPolicy implements BlockGuard.Policy { - private int mPolicyMask; - - // Map from violation stacktrace hashcode -> uptimeMillis of - // last violation. No locking needed, as this is only - // accessed by the same thread. - private ArrayMap mLastViolationTime; - - public AndroidBlockGuardPolicy(final int policyMask) { - mPolicyMask = policyMask; - } - - @Override - public String toString() { - return "AndroidBlockGuardPolicy; mPolicyMask=" + mPolicyMask; - } - - // Part of BlockGuard.Policy interface: - public int getPolicyMask() { - return mPolicyMask; - } - - // Part of BlockGuard.Policy interface: - public void onWriteToDisk() { - if ((mPolicyMask & DETECT_DISK_WRITE) == 0) { - return; - } - if (tooManyViolationsThisLoop()) { - return; - } - BlockGuard.BlockGuardPolicyException e = new StrictModeDiskWriteViolation(mPolicyMask); - e.fillInStackTrace(); - startHandlingViolationException(e); - } - - // Not part of BlockGuard.Policy; just part of StrictMode: - void onCustomSlowCall(String name) { - if ((mPolicyMask & DETECT_CUSTOM) == 0) { - return; - } - if (tooManyViolationsThisLoop()) { - return; - } - BlockGuard.BlockGuardPolicyException e = new StrictModeCustomViolation(mPolicyMask, name); - e.fillInStackTrace(); - startHandlingViolationException(e); - } - - // Part of BlockGuard.Policy interface: - public void onReadFromDisk() { - if ((mPolicyMask & DETECT_DISK_READ) == 0) { - return; - } - if (tooManyViolationsThisLoop()) { - return; - } - BlockGuard.BlockGuardPolicyException e = new StrictModeDiskReadViolation(mPolicyMask); - e.fillInStackTrace(); - startHandlingViolationException(e); - } - - // Part of BlockGuard.Policy interface: - public void onNetwork() { - if ((mPolicyMask & DETECT_NETWORK) == 0) { - return; - } - if ((mPolicyMask & PENALTY_DEATH_ON_NETWORK) != 0) { - throw new NetworkOnMainThreadException(); - } - if (tooManyViolationsThisLoop()) { - return; - } - BlockGuard.BlockGuardPolicyException e = new StrictModeNetworkViolation(mPolicyMask); - e.fillInStackTrace(); - startHandlingViolationException(e); - } - - public void setPolicyMask(int policyMask) { - mPolicyMask = policyMask; - } - - // Start handling a violation that just started and hasn't - // actually run yet (e.g. no disk write or network operation - // has yet occurred). This sees if we're in an event loop - // thread and, if so, uses it to roughly measure how long the - // violation took. - void startHandlingViolationException(BlockGuard.BlockGuardPolicyException e) { - final ViolationInfo info = new ViolationInfo(e, e.getPolicy()); - info.violationUptimeMillis = SystemClock.uptimeMillis(); - handleViolationWithTimingAttempt(info); - } - - // Attempts to fill in the provided ViolationInfo's - // durationMillis field if this thread has a Looper we can use - // to measure with. We measure from the time of violation - // until the time the looper is idle again (right before - // the next epoll_wait) - void handleViolationWithTimingAttempt(final ViolationInfo info) { - Looper looper = Looper.myLooper(); - - // Without a Looper, we're unable to time how long the - // violation takes place. This case should be rare, as - // most users will care about timing violations that - // happen on their main UI thread. Note that this case is - // also hit when a violation takes place in a Binder - // thread, in "gather" mode. In this case, the duration - // of the violation is computed by the ultimate caller and - // its Looper, if any. - // - // Also, as a special short-cut case when the only penalty - // bit is death, we die immediately, rather than timing - // the violation's duration. This makes it convenient to - // use in unit tests too, rather than waiting on a Looper. - // - // TODO: if in gather mode, ignore Looper.myLooper() and always - // go into this immediate mode? - if (looper == null || - (info.policy & THREAD_PENALTY_MASK) == PENALTY_DEATH) { - info.durationMillis = -1; // unknown (redundant, already set) - handleViolation(info); - return; - } - - final ArrayList records = violationsBeingTimed.get(); - if (records.size() >= MAX_OFFENSES_PER_LOOP) { - // Not worth measuring. Too many offenses in one loop. - return; - } - records.add(info); - if (records.size() > 1) { - // There's already been a violation this loop, so we've already - // registered an idle handler to process the list of violations - // at the end of this Looper's loop. - return; - } - - final IWindowManager windowManager = (info.policy & PENALTY_FLASH) != 0 ? - sWindowManager.get() : null; - if (windowManager != null) { - try { - windowManager.showStrictModeViolation(true); - } catch (RemoteException unused) { - } - } - - // We post a runnable to a Handler (== delay 0 ms) for - // measuring the end time of a violation instead of using - // an IdleHandler (as was previously used) because an - // IdleHandler may not run for quite a long period of time - // if an ongoing animation is happening and continually - // posting ASAP (0 ms) animation steps. Animations are - // throttled back to 60fps via SurfaceFlinger/View - // invalidates, _not_ by posting frame updates every 16 - // milliseconds. - threadHandler.get().postAtFrontOfQueue(new Runnable() { - public void run() { - long loopFinishTime = SystemClock.uptimeMillis(); - - // Note: we do this early, before handling the - // violation below, as handling the violation - // may include PENALTY_DEATH and we don't want - // to keep the red border on. - if (windowManager != null) { - try { - windowManager.showStrictModeViolation(false); - } catch (RemoteException unused) { - } - } - - for (int n = 0; n < records.size(); ++n) { - ViolationInfo v = records.get(n); - v.violationNumThisLoop = n + 1; - v.durationMillis = - (int) (loopFinishTime - v.violationUptimeMillis); - handleViolation(v); - } - records.clear(); - } - }); - } - - // Note: It's possible (even quite likely) that the - // thread-local policy mask has changed from the time the - // violation fired and now (after the violating code ran) due - // to people who push/pop temporary policy in regions of code, - // hence the policy being passed around. - void handleViolation(final ViolationInfo info) { - if (info == null || info.crashInfo == null || info.crashInfo.stackTrace == null) { - Log.wtf(TAG, "unexpected null stacktrace"); - return; - } - - if (LOG_V) Log.d(TAG, "handleViolation; policy=" + info.policy); - - if ((info.policy & PENALTY_GATHER) != 0) { - ArrayList violations = gatheredViolations.get(); - if (violations == null) { - violations = new ArrayList(1); - gatheredViolations.set(violations); - } else if (violations.size() >= 5) { - // Too many. In a loop or something? Don't gather them all. - return; - } - for (ViolationInfo previous : violations) { - if (info.crashInfo.stackTrace.equals(previous.crashInfo.stackTrace)) { - // Duplicate. Don't log. - return; - } - } - violations.add(info); - return; - } - - // Not perfect, but fast and good enough for dup suppression. - Integer crashFingerprint = info.hashCode(); - long lastViolationTime = 0; - if (mLastViolationTime != null) { - Long vtime = mLastViolationTime.get(crashFingerprint); - if (vtime != null) { - lastViolationTime = vtime; - } - } else { - mLastViolationTime = new ArrayMap(1); - } - long now = SystemClock.uptimeMillis(); - mLastViolationTime.put(crashFingerprint, now); - long timeSinceLastViolationMillis = lastViolationTime == 0 ? - Long.MAX_VALUE : (now - lastViolationTime); - - if ((info.policy & PENALTY_LOG) != 0 && - timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) { - if (info.durationMillis != -1) { - Log.d(TAG, "StrictMode policy violation; ~duration=" + - info.durationMillis + " ms: " + info.crashInfo.stackTrace); - } else { - Log.d(TAG, "StrictMode policy violation: " + info.crashInfo.stackTrace); - } - } - - // The violationMaskSubset, passed to ActivityManager, is a - // subset of the original StrictMode policy bitmask, with - // only the bit violated and penalty bits to be executed - // by the ActivityManagerService remaining set. - int violationMaskSubset = 0; - - if ((info.policy & PENALTY_DIALOG) != 0 && - timeSinceLastViolationMillis > MIN_DIALOG_INTERVAL_MS) { - violationMaskSubset |= PENALTY_DIALOG; - } - - if ((info.policy & PENALTY_DROPBOX) != 0 && lastViolationTime == 0) { - violationMaskSubset |= PENALTY_DROPBOX; - } - - if (violationMaskSubset != 0) { - int violationBit = parseViolationFromMessage(info.crashInfo.exceptionMessage); - violationMaskSubset |= violationBit; - final int savedPolicyMask = getThreadPolicyMask(); - - final boolean justDropBox = (info.policy & THREAD_PENALTY_MASK) == PENALTY_DROPBOX; - if (justDropBox) { - // If all we're going to ask the activity manager - // to do is dropbox it (the common case during - // platform development), we can avoid doing this - // call synchronously which Binder data suggests - // isn't always super fast, despite the implementation - // in the ActivityManager trying to be mostly async. - dropboxViolationAsync(violationMaskSubset, info); - return; - } - - // Normal synchronous call to the ActivityManager. - try { - // First, remove any policy before we call into the Activity Manager, - // otherwise we'll infinite recurse as we try to log policy violations - // to disk, thus violating policy, thus requiring logging, etc... - // We restore the current policy below, in the finally block. - setThreadPolicyMask(0); - - ActivityManagerNative.getDefault().handleApplicationStrictModeViolation( - RuntimeInit.getApplicationObject(), - violationMaskSubset, - info); - } catch (RemoteException e) { - Log.e(TAG, "RemoteException trying to handle StrictMode violation", e); - } finally { - // Restore the policy. - setThreadPolicyMask(savedPolicyMask); - } - } - - if ((info.policy & PENALTY_DEATH) != 0) { - executeDeathPenalty(info); - } - } - } - - private static void executeDeathPenalty(ViolationInfo info) { - int violationBit = parseViolationFromMessage(info.crashInfo.exceptionMessage); - throw new StrictModeViolation(info.policy, violationBit, null); - } - - /** - * In the common case, as set by conditionallyEnableDebugLogging, - * we're just dropboxing any violations but not showing a dialog, - * not loggging, and not killing the process. In these cases we - * don't need to do a synchronous call to the ActivityManager. - * This is used by both per-thread and vm-wide violations when - * applicable. - */ - private static void dropboxViolationAsync( - final int violationMaskSubset, final ViolationInfo info) { - int outstanding = sDropboxCallsInFlight.incrementAndGet(); - if (outstanding > 20) { - // What's going on? Let's not make make the situation - // worse and just not log. - sDropboxCallsInFlight.decrementAndGet(); - return; - } - - if (LOG_V) Log.d(TAG, "Dropboxing async; in-flight=" + outstanding); - - new Thread("callActivityManagerForStrictModeDropbox") { - public void run() { - Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); - try { - IActivityManager am = ActivityManagerNative.getDefault(); - if (am == null) { - Log.d(TAG, "No activity manager; failed to Dropbox violation."); - } else { - am.handleApplicationStrictModeViolation( - RuntimeInit.getApplicationObject(), - violationMaskSubset, - info); - } - } catch (RemoteException e) { - Log.e(TAG, "RemoteException handling StrictMode violation", e); - } - int outstanding = sDropboxCallsInFlight.decrementAndGet(); - if (LOG_V) Log.d(TAG, "Dropbox complete; in-flight=" + outstanding); - } - }.start(); - } - - private static class AndroidCloseGuardReporter implements CloseGuard.Reporter { - public void report (String message, Throwable allocationSite) { - onVmPolicyViolation(message, allocationSite); - } - } - - /** - * Called from Parcel.writeNoException() - */ - /* package */ static boolean hasGatheredViolations() { - return gatheredViolations.get() != null; - } - - /** - * Called from Parcel.writeException(), so we drop this memory and - * don't incorrectly attribute it to the wrong caller on the next - * Binder call on this thread. - */ - /* package */ static void clearGatheredViolations() { - gatheredViolations.set(null); - } - - /** - * @hide - */ - public static void conditionallyCheckInstanceCounts() { - VmPolicy policy = getVmPolicy(); - if (policy.classInstanceLimit.size() == 0) { - return; - } - - System.gc(); - System.runFinalization(); - System.gc(); - - // Note: classInstanceLimit is immutable, so this is lock-free - for (Map.Entry entry : policy.classInstanceLimit.entrySet()) { - Class klass = entry.getKey(); - int limit = entry.getValue(); - long instances = VMDebug.countInstancesOfClass(klass, false); - if (instances <= limit) { - continue; - } - Throwable tr = new InstanceCountViolation(klass, instances, limit); - onVmPolicyViolation(tr.getMessage(), tr); - } - } - - private static long sLastInstanceCountCheckMillis = 0; - private static boolean sIsIdlerRegistered = false; // guarded by StrictMode.class - private static final MessageQueue.IdleHandler sProcessIdleHandler = - new MessageQueue.IdleHandler() { - public boolean queueIdle() { - long now = SystemClock.uptimeMillis(); - if (now - sLastInstanceCountCheckMillis > 30 * 1000) { - sLastInstanceCountCheckMillis = now; - conditionallyCheckInstanceCounts(); - } - return true; - } - }; - - /** - * Sets the policy for what actions in the VM process (on any - * thread) should be detected, as well as the penalty if such - * actions occur. - * - * @param policy the policy to put into place - */ - public static void setVmPolicy(final VmPolicy policy) { - synchronized (StrictMode.class) { - sVmPolicy = policy; - sVmPolicyMask = policy.mask; - setCloseGuardEnabled(vmClosableObjectLeaksEnabled()); - - Looper looper = Looper.getMainLooper(); - if (looper != null) { - MessageQueue mq = looper.mQueue; - if (policy.classInstanceLimit.size() == 0 || - (sVmPolicyMask & VM_PENALTY_MASK) == 0) { - mq.removeIdleHandler(sProcessIdleHandler); - sIsIdlerRegistered = false; - } else if (!sIsIdlerRegistered) { - mq.addIdleHandler(sProcessIdleHandler); - sIsIdlerRegistered = true; - } - } - } - } - - /** - * Gets the current VM policy. - */ - public static VmPolicy getVmPolicy() { - synchronized (StrictMode.class) { - return sVmPolicy; - } - } - - /** - * Enable the recommended StrictMode defaults, with violations just being logged. - * - *

    This catches disk and network access on the main thread, as - * well as leaked SQLite cursors and unclosed resources. This is - * simply a wrapper around {@link #setVmPolicy} and {@link - * #setThreadPolicy}. - */ - public static void enableDefaults() { - StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() - .detectAll() - .penaltyLog() - .build()); - StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() - .detectAll() - .penaltyLog() - .build()); - } - - /** - * @hide - */ - public static boolean vmSqliteObjectLeaksEnabled() { - return (sVmPolicyMask & DETECT_VM_CURSOR_LEAKS) != 0; - } - - /** - * @hide - */ - public static boolean vmClosableObjectLeaksEnabled() { - return (sVmPolicyMask & DETECT_VM_CLOSABLE_LEAKS) != 0; - } - - /** - * @hide - */ - public static boolean vmRegistrationLeaksEnabled() { - return (sVmPolicyMask & DETECT_VM_REGISTRATION_LEAKS) != 0; - } - - /** - * @hide - */ - public static boolean vmFileUriExposureEnabled() { - return (sVmPolicyMask & DETECT_VM_FILE_URI_EXPOSURE) != 0; - } - - /** - * @hide - */ - public static void onSqliteObjectLeaked(String message, Throwable originStack) { - onVmPolicyViolation(message, originStack); - } - - /** - * @hide - */ - public static void onWebViewMethodCalledOnWrongThread(Throwable originStack) { - onVmPolicyViolation(null, originStack); - } - - /** - * @hide - */ - public static void onIntentReceiverLeaked(Throwable originStack) { - onVmPolicyViolation(null, originStack); - } - - /** - * @hide - */ - public static void onServiceConnectionLeaked(Throwable originStack) { - onVmPolicyViolation(null, originStack); - } - - /** - * @hide - */ - public static void onFileUriExposed(String location) { - final String message = "file:// Uri exposed through " + location; - onVmPolicyViolation(message, new Throwable(message)); - } - - // Map from VM violation fingerprint to uptime millis. - private static final HashMap sLastVmViolationTime = new HashMap(); - - /** - * @hide - */ - public static void onVmPolicyViolation(String message, Throwable originStack) { - final boolean penaltyDropbox = (sVmPolicyMask & PENALTY_DROPBOX) != 0; - final boolean penaltyDeath = (sVmPolicyMask & PENALTY_DEATH) != 0; - final boolean penaltyLog = (sVmPolicyMask & PENALTY_LOG) != 0; - final ViolationInfo info = new ViolationInfo(originStack, sVmPolicyMask); - - // Erase stuff not relevant for process-wide violations - info.numAnimationsRunning = 0; - info.tags = null; - info.broadcastIntentAction = null; - - final Integer fingerprint = info.hashCode(); - final long now = SystemClock.uptimeMillis(); - long lastViolationTime = 0; - long timeSinceLastViolationMillis = Long.MAX_VALUE; - synchronized (sLastVmViolationTime) { - if (sLastVmViolationTime.containsKey(fingerprint)) { - lastViolationTime = sLastVmViolationTime.get(fingerprint); - timeSinceLastViolationMillis = now - lastViolationTime; - } - if (timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) { - sLastVmViolationTime.put(fingerprint, now); - } - } - - if (penaltyLog && timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) { - Log.e(TAG, message, originStack); - } - - int violationMaskSubset = PENALTY_DROPBOX | (ALL_VM_DETECT_BITS & sVmPolicyMask); - - if (penaltyDropbox && !penaltyDeath) { - // Common case for userdebug/eng builds. If no death and - // just dropboxing, we can do the ActivityManager call - // asynchronously. - dropboxViolationAsync(violationMaskSubset, info); - return; - } - - if (penaltyDropbox && lastViolationTime == 0) { - // The violationMask, passed to ActivityManager, is a - // subset of the original StrictMode policy bitmask, with - // only the bit violated and penalty bits to be executed - // by the ActivityManagerService remaining set. - final int savedPolicyMask = getThreadPolicyMask(); - try { - // First, remove any policy before we call into the Activity Manager, - // otherwise we'll infinite recurse as we try to log policy violations - // to disk, thus violating policy, thus requiring logging, etc... - // We restore the current policy below, in the finally block. - setThreadPolicyMask(0); - - ActivityManagerNative.getDefault().handleApplicationStrictModeViolation( - RuntimeInit.getApplicationObject(), - violationMaskSubset, - info); - } catch (RemoteException e) { - Log.e(TAG, "RemoteException trying to handle StrictMode violation", e); - } finally { - // Restore the policy. - setThreadPolicyMask(savedPolicyMask); - } - } - - if (penaltyDeath) { - System.err.println("StrictMode VmPolicy violation with POLICY_DEATH; shutting down."); - Process.killProcess(Process.myPid()); - System.exit(10); - } - } - - /** - * Called from Parcel.writeNoException() - */ - /* package */ static void writeGatheredViolationsToParcel(Parcel p) { - ArrayList violations = gatheredViolations.get(); - if (violations == null) { - p.writeInt(0); - } else { - p.writeInt(violations.size()); - for (int i = 0; i < violations.size(); ++i) { - int start = p.dataPosition(); - violations.get(i).writeToParcel(p, 0 /* unused flags? */); - int size = p.dataPosition()-start; - if (size > 10*1024) { - Slog.d(TAG, "Wrote violation #" + i + " of " + violations.size() + ": " - + (p.dataPosition()-start) + " bytes"); - } - } - if (LOG_V) Log.d(TAG, "wrote violations to response parcel; num=" + violations.size()); - violations.clear(); // somewhat redundant, as we're about to null the threadlocal - } - gatheredViolations.set(null); - } - - private static class LogStackTrace extends Exception {} - - /** - * Called from Parcel.readException() when the exception is EX_STRICT_MODE_VIOLATIONS, - * we here read back all the encoded violations. - */ - /* package */ static void readAndHandleBinderCallViolations(Parcel p) { - // Our own stack trace to append - StringWriter sw = new StringWriter(); - PrintWriter pw = new FastPrintWriter(sw, false, 256); - new LogStackTrace().printStackTrace(pw); - pw.flush(); - String ourStack = sw.toString(); - - int policyMask = getThreadPolicyMask(); - boolean currentlyGathering = (policyMask & PENALTY_GATHER) != 0; - - int numViolations = p.readInt(); - for (int i = 0; i < numViolations; ++i) { - if (LOG_V) Log.d(TAG, "strict mode violation stacks read from binder call. i=" + i); - ViolationInfo info = new ViolationInfo(p, !currentlyGathering); - if (info.crashInfo.stackTrace != null && info.crashInfo.stackTrace.length() > 10000) { - String front = info.crashInfo.stackTrace.substring(256); - // 10000 characters is way too large for this to be any sane kind of - // strict mode collection of stacks. We've had a problem where we leave - // strict mode violations associated with the thread, and it keeps tacking - // more and more stacks on to the violations. Looks like we're in this casse, - // so we'll report it and bail on all of the current strict mode violations - // we currently are maintaining for this thread. - // First, drain the remaining violations from the parcel. - while (i < numViolations) { - info = new ViolationInfo(p, !currentlyGathering); - i++; - } - // Next clear out all gathered violations. - clearGatheredViolations(); - // Now report the problem. - Slog.wtfStack(TAG, "Stack is too large: numViolations=" + numViolations - + " policy=#" + Integer.toHexString(policyMask) - + " front=" + front); - return; - } - info.crashInfo.stackTrace += "# via Binder call with stack:\n" + ourStack; - BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); - if (policy instanceof AndroidBlockGuardPolicy) { - ((AndroidBlockGuardPolicy) policy).handleViolationWithTimingAttempt(info); - } - } - } - - /** - * Called from android_util_Binder.cpp's - * android_os_Parcel_enforceInterface when an incoming Binder call - * requires changing the StrictMode policy mask. The role of this - * function is to ask Binder for its current (native) thread-local - * policy value and synchronize it to libcore's (Java) - * thread-local policy value. - */ - private static void onBinderStrictModePolicyChange(int newPolicy) { - setBlockGuardPolicy(newPolicy); - } - - /** - * A tracked, critical time span. (e.g. during an animation.) - * - * The object itself is a linked list node, to avoid any allocations - * during rapid span entries and exits. - * - * @hide - */ - public static class Span { - private String mName; - private long mCreateMillis; - private Span mNext; - private Span mPrev; // not used when in freeList, only active - private final ThreadSpanState mContainerState; - - Span(ThreadSpanState threadState) { - mContainerState = threadState; - } - - // Empty constructor for the NO_OP_SPAN - protected Span() { - mContainerState = null; - } - - /** - * To be called when the critical span is complete (i.e. the - * animation is done animating). This can be called on any - * thread (even a different one from where the animation was - * taking place), but that's only a defensive implementation - * measure. It really makes no sense for you to call this on - * thread other than that where you created it. - * - * @hide - */ - public void finish() { - ThreadSpanState state = mContainerState; - synchronized (state) { - if (mName == null) { - // Duplicate finish call. Ignore. - return; - } - - // Remove ourselves from the active list. - if (mPrev != null) { - mPrev.mNext = mNext; - } - if (mNext != null) { - mNext.mPrev = mPrev; - } - if (state.mActiveHead == this) { - state.mActiveHead = mNext; - } - - state.mActiveSize--; - - if (LOG_V) Log.d(TAG, "Span finished=" + mName + "; size=" + state.mActiveSize); - - this.mCreateMillis = -1; - this.mName = null; - this.mPrev = null; - this.mNext = null; - - // Add ourselves to the freeList, if it's not already - // too big. - if (state.mFreeListSize < 5) { - this.mNext = state.mFreeListHead; - state.mFreeListHead = this; - state.mFreeListSize++; - } - } - } - } - - // The no-op span that's used in user builds. - private static final Span NO_OP_SPAN = new Span() { - public void finish() { - // Do nothing. - } - }; - - /** - * Linked lists of active spans and a freelist. - * - * Locking notes: there's one of these structures per thread and - * all members of this structure (as well as the Span nodes under - * it) are guarded by the ThreadSpanState object instance. While - * in theory there'd be no locking required because it's all local - * per-thread, the finish() method above is defensive against - * people calling it on a different thread from where they created - * the Span, hence the locking. - */ - private static class ThreadSpanState { - public Span mActiveHead; // doubly-linked list. - public int mActiveSize; - public Span mFreeListHead; // singly-linked list. only changes at head. - public int mFreeListSize; - } - - private static final ThreadLocal sThisThreadSpanState = - new ThreadLocal() { - @Override protected ThreadSpanState initialValue() { - return new ThreadSpanState(); - } - }; - - private static Singleton sWindowManager = new Singleton() { - protected IWindowManager create() { - return IWindowManager.Stub.asInterface(ServiceManager.getService("window")); - } - }; - - /** - * Enter a named critical span (e.g. an animation) - * - *

    The name is an arbitary label (or tag) that will be applied - * to any strictmode violation that happens while this span is - * active. You must call finish() on the span when done. - * - *

    This will never return null, but on devices without debugging - * enabled, this may return a dummy object on which the finish() - * method is a no-op. - * - *

    TODO: add CloseGuard to this, verifying callers call finish. - * - * @hide - */ - public static Span enterCriticalSpan(String name) { - if (IS_USER_BUILD) { - return NO_OP_SPAN; - } - if (name == null || name.isEmpty()) { - throw new IllegalArgumentException("name must be non-null and non-empty"); - } - ThreadSpanState state = sThisThreadSpanState.get(); - Span span = null; - synchronized (state) { - if (state.mFreeListHead != null) { - span = state.mFreeListHead; - state.mFreeListHead = span.mNext; - state.mFreeListSize--; - } else { - // Shouldn't have to do this often. - span = new Span(state); - } - span.mName = name; - span.mCreateMillis = SystemClock.uptimeMillis(); - span.mNext = state.mActiveHead; - span.mPrev = null; - state.mActiveHead = span; - state.mActiveSize++; - if (span.mNext != null) { - span.mNext.mPrev = span; - } - if (LOG_V) Log.d(TAG, "Span enter=" + name + "; size=" + state.mActiveSize); - } - return span; - } - - /** - * For code to note that it's slow. This is a no-op unless the - * current thread's {@link android.os.StrictMode.ThreadPolicy} has - * {@link android.os.StrictMode.ThreadPolicy.Builder#detectCustomSlowCalls} - * enabled. - * - * @param name a short string for the exception stack trace that's - * built if when this fires. - */ - public static void noteSlowCall(String name) { - BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); - if (!(policy instanceof AndroidBlockGuardPolicy)) { - // StrictMode not enabled. - return; - } - ((AndroidBlockGuardPolicy) policy).onCustomSlowCall(name); - } - - /** - * @hide - */ - public static void noteDiskRead() { - BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); - if (!(policy instanceof AndroidBlockGuardPolicy)) { - // StrictMode not enabled. - return; - } - ((AndroidBlockGuardPolicy) policy).onReadFromDisk(); - } - - /** - * @hide - */ - public static void noteDiskWrite() { - BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); - if (!(policy instanceof AndroidBlockGuardPolicy)) { - // StrictMode not enabled. - return; - } - ((AndroidBlockGuardPolicy) policy).onWriteToDisk(); - } - - // Guarded by StrictMode.class - private static final HashMap sExpectedActivityInstanceCount = - new HashMap(); - - /** - * Returns an object that is used to track instances of activites. - * The activity should store a reference to the tracker object in one of its fields. - * @hide - */ - public static Object trackActivity(Object instance) { - return new InstanceTracker(instance); - } - - /** - * @hide - */ - public static void incrementExpectedActivityCount(Class klass) { - if (klass == null) { - return; - } - - synchronized (StrictMode.class) { - if ((sVmPolicy.mask & DETECT_VM_ACTIVITY_LEAKS) == 0) { - return; - } - - Integer expected = sExpectedActivityInstanceCount.get(klass); - Integer newExpected = expected == null ? 1 : expected + 1; - sExpectedActivityInstanceCount.put(klass, newExpected); - } - } - - /** - * @hide - */ - public static void decrementExpectedActivityCount(Class klass) { - if (klass == null) { - return; - } - - final int limit; - synchronized (StrictMode.class) { - if ((sVmPolicy.mask & DETECT_VM_ACTIVITY_LEAKS) == 0) { - return; - } - - Integer expected = sExpectedActivityInstanceCount.get(klass); - int newExpected = (expected == null || expected == 0) ? 0 : expected - 1; - if (newExpected == 0) { - sExpectedActivityInstanceCount.remove(klass); - } else { - sExpectedActivityInstanceCount.put(klass, newExpected); - } - - // Note: adding 1 here to give some breathing room during - // orientation changes. (shouldn't be necessary, though?) - limit = newExpected + 1; - } - - // Quick check. - int actual = InstanceTracker.getInstanceCount(klass); - if (actual <= limit) { - return; - } - - // Do a GC and explicit count to double-check. - // This is the work that we are trying to avoid by tracking the object instances - // explicity. Running an explicit GC can be expensive (80ms) and so can walking - // the heap to count instance (30ms). This extra work can make the system feel - // noticeably less responsive during orientation changes when activities are - // being restarted. Granted, it is only a problem when StrictMode is enabled - // but it is annoying. - - System.gc(); - System.runFinalization(); - System.gc(); - - long instances = VMDebug.countInstancesOfClass(klass, false); - if (instances > limit) { - Throwable tr = new InstanceCountViolation(klass, instances, limit); - onVmPolicyViolation(tr.getMessage(), tr); - } - } - - /** - * Parcelable that gets sent in Binder call headers back to callers - * to report violations that happened during a cross-process call. - * - * @hide - */ - public static class ViolationInfo { - /** - * Stack and other stuff info. - */ - public final ApplicationErrorReport.CrashInfo crashInfo; - - /** - * The strict mode policy mask at the time of violation. - */ - public final int policy; - - /** - * The wall time duration of the violation, when known. -1 when - * not known. - */ - public int durationMillis = -1; - - /** - * The number of animations currently running. - */ - public int numAnimationsRunning = 0; - - /** - * List of tags from active Span instances during this - * violation, or null for none. - */ - public String[] tags; - - /** - * Which violation number this was (1-based) since the last Looper loop, - * from the perspective of the root caller (if it crossed any processes - * via Binder calls). The value is 0 if the root caller wasn't on a Looper - * thread. - */ - public int violationNumThisLoop; - - /** - * The time (in terms of SystemClock.uptimeMillis()) that the - * violation occurred. - */ - public long violationUptimeMillis; - - /** - * The action of the Intent being broadcast to somebody's onReceive - * on this thread right now, or null. - */ - public String broadcastIntentAction; - - /** - * If this is a instance count violation, the number of instances in memory, - * else -1. - */ - public long numInstances = -1; - - /** - * Create an uninitialized instance of ViolationInfo - */ - public ViolationInfo() { - crashInfo = null; - policy = 0; - } - - /** - * Create an instance of ViolationInfo initialized from an exception. - */ - public ViolationInfo(Throwable tr, int policy) { - crashInfo = new ApplicationErrorReport.CrashInfo(tr); - violationUptimeMillis = SystemClock.uptimeMillis(); - this.policy = policy; - this.numAnimationsRunning = ValueAnimator.getCurrentAnimationsCount(); - Intent broadcastIntent = ActivityThread.getIntentBeingBroadcast(); - if (broadcastIntent != null) { - broadcastIntentAction = broadcastIntent.getAction(); - } - ThreadSpanState state = sThisThreadSpanState.get(); - if (tr instanceof InstanceCountViolation) { - this.numInstances = ((InstanceCountViolation) tr).mInstances; - } - synchronized (state) { - int spanActiveCount = state.mActiveSize; - if (spanActiveCount > MAX_SPAN_TAGS) { - spanActiveCount = MAX_SPAN_TAGS; - } - if (spanActiveCount != 0) { - this.tags = new String[spanActiveCount]; - Span iter = state.mActiveHead; - int index = 0; - while (iter != null && index < spanActiveCount) { - this.tags[index] = iter.mName; - index++; - iter = iter.mNext; - } - } - } - } - - @Override - public int hashCode() { - int result = 17; - result = 37 * result + crashInfo.stackTrace.hashCode(); - if (numAnimationsRunning != 0) { - result *= 37; - } - if (broadcastIntentAction != null) { - result = 37 * result + broadcastIntentAction.hashCode(); - } - if (tags != null) { - for (String tag : tags) { - result = 37 * result + tag.hashCode(); - } - } - return result; - } - - /** - * Create an instance of ViolationInfo initialized from a Parcel. - */ - public ViolationInfo(Parcel in) { - this(in, false); - } - - /** - * Create an instance of ViolationInfo initialized from a Parcel. - * - * @param unsetGatheringBit if true, the caller is the root caller - * and the gathering penalty should be removed. - */ - public ViolationInfo(Parcel in, boolean unsetGatheringBit) { - crashInfo = new ApplicationErrorReport.CrashInfo(in); - int rawPolicy = in.readInt(); - if (unsetGatheringBit) { - policy = rawPolicy & ~PENALTY_GATHER; - } else { - policy = rawPolicy; - } - durationMillis = in.readInt(); - violationNumThisLoop = in.readInt(); - numAnimationsRunning = in.readInt(); - violationUptimeMillis = in.readLong(); - numInstances = in.readLong(); - broadcastIntentAction = in.readString(); - tags = in.readStringArray(); - } - - /** - * Save a ViolationInfo instance to a parcel. - */ - public void writeToParcel(Parcel dest, int flags) { - crashInfo.writeToParcel(dest, flags); - int start = dest.dataPosition(); - dest.writeInt(policy); - dest.writeInt(durationMillis); - dest.writeInt(violationNumThisLoop); - dest.writeInt(numAnimationsRunning); - dest.writeLong(violationUptimeMillis); - dest.writeLong(numInstances); - dest.writeString(broadcastIntentAction); - dest.writeStringArray(tags); - int total = dest.dataPosition()-start; - if (total > 10*1024) { - Slog.d(TAG, "VIO: policy=" + policy + " dur=" + durationMillis - + " numLoop=" + violationNumThisLoop - + " anim=" + numAnimationsRunning - + " uptime=" + violationUptimeMillis - + " numInst=" + numInstances); - Slog.d(TAG, "VIO: action=" + broadcastIntentAction); - Slog.d(TAG, "VIO: tags=" + Arrays.toString(tags)); - Slog.d(TAG, "VIO: TOTAL BYTES WRITTEN: " + (dest.dataPosition()-start)); - } - } - - - /** - * Dump a ViolationInfo instance to a Printer. - */ - public void dump(Printer pw, String prefix) { - crashInfo.dump(pw, prefix); - pw.println(prefix + "policy: " + policy); - if (durationMillis != -1) { - pw.println(prefix + "durationMillis: " + durationMillis); - } - if (numInstances != -1) { - pw.println(prefix + "numInstances: " + numInstances); - } - if (violationNumThisLoop != 0) { - pw.println(prefix + "violationNumThisLoop: " + violationNumThisLoop); - } - if (numAnimationsRunning != 0) { - pw.println(prefix + "numAnimationsRunning: " + numAnimationsRunning); - } - pw.println(prefix + "violationUptimeMillis: " + violationUptimeMillis); - if (broadcastIntentAction != null) { - pw.println(prefix + "broadcastIntentAction: " + broadcastIntentAction); - } - if (tags != null) { - int index = 0; - for (String tag : tags) { - pw.println(prefix + "tag[" + (index++) + "]: " + tag); - } - } - } - - } - - // Dummy throwable, for now, since we don't know when or where the - // leaked instances came from. We might in the future, but for - // now we suppress the stack trace because it's useless and/or - // misleading. - private static class InstanceCountViolation extends Throwable { - final Class mClass; - final long mInstances; - final int mLimit; - - private static final StackTraceElement[] FAKE_STACK = { - new StackTraceElement("android.os.StrictMode", "setClassInstanceLimit", - "StrictMode.java", 1) - }; - - public InstanceCountViolation(Class klass, long instances, int limit) { - super(klass.toString() + "; instances=" + instances + "; limit=" + limit); - setStackTrace(FAKE_STACK); - mClass = klass; - mInstances = instances; - mLimit = limit; - } - } - - private static final class InstanceTracker { - private static final HashMap, Integer> sInstanceCounts = - new HashMap, Integer>(); - - private final Class mKlass; - - public InstanceTracker(Object instance) { - mKlass = instance.getClass(); - - synchronized (sInstanceCounts) { - final Integer value = sInstanceCounts.get(mKlass); - final int newValue = value != null ? value + 1 : 1; - sInstanceCounts.put(mKlass, newValue); - } - } - - @Override - protected void finalize() throws Throwable { - try { - synchronized (sInstanceCounts) { - final Integer value = sInstanceCounts.get(mKlass); - if (value != null) { - final int newValue = value - 1; - if (newValue > 0) { - sInstanceCounts.put(mKlass, newValue); - } else { - sInstanceCounts.remove(mKlass); - } - } - } - } finally { - super.finalize(); - } - } - - public static int getInstanceCount(Class klass) { - synchronized (sInstanceCounts) { - final Integer value = sInstanceCounts.get(klass); - return value != null ? value : 0; - } - } - } -} diff --git a/src/main/java/android/os/StrictModeBenchmark.java b/src/main/java/android/os/StrictModeBenchmark.java deleted file mode 100644 index 41af382..0000000 --- a/src/main/java/android/os/StrictModeBenchmark.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.os.StrictMode.ThreadPolicy; - -import com.google.caliper.SimpleBenchmark; - -public class StrictModeBenchmark extends SimpleBenchmark { - - private ThreadPolicy mOff = new ThreadPolicy.Builder().build(); - private ThreadPolicy mOn = new ThreadPolicy.Builder().detectAll().build(); - - public void timeToggleThreadPolicy(int reps) { - for (int i = 0; i < reps; i++) { - StrictMode.setThreadPolicy(mOn); - StrictMode.setThreadPolicy(mOff); - } - } -} diff --git a/src/main/java/android/os/SystemClock.java b/src/main/java/android/os/SystemClock.java deleted file mode 100644 index 672df6d..0000000 --- a/src/main/java/android/os/SystemClock.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.app.IAlarmManager; -import android.content.Context; -import android.util.Slog; - -/** - * Core timekeeping facilities. - * - *

    Three different clocks are available, and they should not be confused: - * - *

      - *
    • {@link System#currentTimeMillis System.currentTimeMillis()} - * is the standard "wall" clock (time and date) expressing milliseconds - * since the epoch. The wall clock can be set by the user or the phone - * network (see {@link #setCurrentTimeMillis}), so the time may jump - * backwards or forwards unpredictably. This clock should only be used - * when correspondence with real-world dates and times is important, such - * as in a calendar or alarm clock application. Interval or elapsed - * time measurements should use a different clock. If you are using - * System.currentTimeMillis(), consider listening to the - * {@link android.content.Intent#ACTION_TIME_TICK ACTION_TIME_TICK}, - * {@link android.content.Intent#ACTION_TIME_CHANGED ACTION_TIME_CHANGED} - * and {@link android.content.Intent#ACTION_TIMEZONE_CHANGED - * ACTION_TIMEZONE_CHANGED} {@link android.content.Intent Intent} - * broadcasts to find out when the time changes. - * - *

    • {@link #uptimeMillis} is counted in milliseconds since the - * system was booted. This clock stops when the system enters deep - * sleep (CPU off, display dark, device waiting for external input), - * but is not affected by clock scaling, idle, or other power saving - * mechanisms. This is the basis for most interval timing - * such as {@link Thread#sleep(long) Thread.sleep(millls)}, - * {@link Object#wait(long) Object.wait(millis)}, and - * {@link System#nanoTime System.nanoTime()}. This clock is guaranteed - * to be monotonic, and is suitable for interval timing when the - * interval does not span device sleep. Most methods that accept a - * timestamp value currently expect the {@link #uptimeMillis} clock. - * - *

    • {@link #elapsedRealtime} and {@link #elapsedRealtimeNanos} - * return the time since the system was booted, and include deep sleep. - * This clock is guaranteed to be monotonic, and continues to tick even - * when the CPU is in power saving modes, so is the recommend basis - * for general purpose interval timing. - * - *

    - * - * There are several mechanisms for controlling the timing of events: - * - *
      - *
    • Standard functions like {@link Thread#sleep(long) - * Thread.sleep(millis)} and {@link Object#wait(long) Object.wait(millis)} - * are always available. These functions use the {@link #uptimeMillis} - * clock; if the device enters sleep, the remainder of the time will be - * postponed until the device wakes up. These synchronous functions may - * be interrupted with {@link Thread#interrupt Thread.interrupt()}, and - * you must handle {@link InterruptedException}. - * - *

    • {@link #sleep SystemClock.sleep(millis)} is a utility function - * very similar to {@link Thread#sleep(long) Thread.sleep(millis)}, but it - * ignores {@link InterruptedException}. Use this function for delays if - * you do not use {@link Thread#interrupt Thread.interrupt()}, as it will - * preserve the interrupted state of the thread. - * - *

    • The {@link android.os.Handler} class can schedule asynchronous - * callbacks at an absolute or relative time. Handler objects also use the - * {@link #uptimeMillis} clock, and require an {@link android.os.Looper - * event loop} (normally present in any GUI application). - * - *

    • The {@link android.app.AlarmManager} can trigger one-time or - * recurring events which occur even when the device is in deep sleep - * or your application is not running. Events may be scheduled with your - * choice of {@link java.lang.System#currentTimeMillis} (RTC) or - * {@link #elapsedRealtime} (ELAPSED_REALTIME), and cause an - * {@link android.content.Intent} broadcast when they occur. - *

    - */ -public final class SystemClock { - private static final String TAG = "SystemClock"; - - /** - * This class is uninstantiable. - */ - private SystemClock() { - // This space intentionally left blank. - } - - /** - * Waits a given number of milliseconds (of uptimeMillis) before returning. - * Similar to {@link java.lang.Thread#sleep(long)}, but does not throw - * {@link InterruptedException}; {@link Thread#interrupt()} events are - * deferred until the next interruptible operation. Does not return until - * at least the specified number of milliseconds has elapsed. - * - * @param ms to sleep before returning, in milliseconds of uptime. - */ - public static void sleep(long ms) - { - long start = uptimeMillis(); - long duration = ms; - boolean interrupted = false; - do { - try { - Thread.sleep(duration); - } - catch (InterruptedException e) { - interrupted = true; - } - duration = start + ms - uptimeMillis(); - } while (duration > 0); - - if (interrupted) { - // Important: we don't want to quietly eat an interrupt() event, - // so we make sure to re-interrupt the thread so that the next - // call to Thread.sleep() or Object.wait() will be interrupted. - Thread.currentThread().interrupt(); - } - } - - /** - * Sets the current wall time, in milliseconds. Requires the calling - * process to have appropriate permissions. - * - * @return if the clock was successfully set to the specified time. - */ - public static boolean setCurrentTimeMillis(long millis) { - IBinder b = ServiceManager.getService(Context.ALARM_SERVICE); - IAlarmManager mgr = IAlarmManager.Stub.asInterface(b); - if (mgr == null) { - return false; - } - - try { - return mgr.setTime(millis); - } catch (RemoteException e) { - Slog.e(TAG, "Unable to set RTC", e); - } catch (SecurityException e) { - Slog.e(TAG, "Unable to set RTC", e); - } - - return false; - } - - /** - * Returns milliseconds since boot, not counting time spent in deep sleep. - * - * @return milliseconds of non-sleep uptime since boot. - */ - native public static long uptimeMillis(); - - /** - * Returns milliseconds since boot, including time spent in sleep. - * - * @return elapsed milliseconds since boot. - */ - native public static long elapsedRealtime(); - - /** - * Returns nanoseconds since boot, including time spent in sleep. - * - * @return elapsed nanoseconds since boot. - */ - public static native long elapsedRealtimeNanos(); - - /** - * Returns milliseconds running in the current thread. - * - * @return elapsed milliseconds in the thread - */ - public static native long currentThreadTimeMillis(); - - /** - * Returns microseconds running in the current thread. - * - * @return elapsed microseconds in the thread - * - * @hide - */ - public static native long currentThreadTimeMicro(); - - /** - * Returns current wall time in microseconds. - * - * @return elapsed microseconds in wall time - * - * @hide - */ - public static native long currentTimeMicro(); -} diff --git a/src/main/java/android/os/SystemClock_Delegate.java b/src/main/java/android/os/SystemClock_Delegate.java deleted file mode 100644 index 5f0d98b..0000000 --- a/src/main/java/android/os/SystemClock_Delegate.java +++ /dev/null @@ -1,101 +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.os; - -import com.android.layoutlib.bridge.impl.DelegateManager; -import com.android.tools.layoutlib.annotations.LayoutlibDelegate; - -/** - * Delegate implementing the native methods of android.os.SystemClock - * - * Through the layoutlib_create tool, the original native methods of SystemClock have been replaced - * by calls to methods of the same name in this delegate class. - * - * Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager} - * around to map int to instance of the delegate. - * - */ -public class SystemClock_Delegate { - private static long sBootTime = System.currentTimeMillis(); - private static long sBootTimeNano = System.nanoTime(); - - /** - * Returns milliseconds since boot, not counting time spent in deep sleep. - * Note: This value may get reset occasionally (before it would - * otherwise wrap around). - * - * @return milliseconds of non-sleep uptime since boot. - */ - @LayoutlibDelegate - /*package*/ static long uptimeMillis() { - return System.currentTimeMillis() - sBootTime; - } - - /** - * Returns milliseconds since boot, including time spent in sleep. - * - * @return elapsed milliseconds since boot. - */ - @LayoutlibDelegate - /*package*/ static long elapsedRealtime() { - return System.currentTimeMillis() - sBootTime; - } - - /** - * Returns nanoseconds since boot, including time spent in sleep. - * - * @return elapsed nanoseconds since boot. - */ - @LayoutlibDelegate - /*package*/ static long elapsedRealtimeNanos() { - return System.nanoTime() - sBootTimeNano; - } - - /** - * Returns milliseconds running in the current thread. - * - * @return elapsed milliseconds in the thread - */ - @LayoutlibDelegate - /*package*/ static long currentThreadTimeMillis() { - return System.currentTimeMillis(); - } - - /** - * Returns microseconds running in the current thread. - * - * @return elapsed microseconds in the thread - * - * @hide - */ - @LayoutlibDelegate - /*package*/ static long currentThreadTimeMicro() { - return System.currentTimeMillis() * 1000; - } - - /** - * Returns current wall time in microseconds. - * - * @return elapsed microseconds in wall time - * - * @hide - */ - @LayoutlibDelegate - /*package*/ static long currentTimeMicro() { - return elapsedRealtime() * 1000; - } -} diff --git a/src/main/java/android/os/SystemProperties.java b/src/main/java/android/os/SystemProperties.java deleted file mode 100644 index 1479035..0000000 --- a/src/main/java/android/os/SystemProperties.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import java.util.ArrayList; - - -/** - * Gives access to the system properties store. The system properties - * store contains a list of string key-value pairs. - * - * {@hide} - */ -public class SystemProperties -{ - public static final int PROP_NAME_MAX = 31; - public static final int PROP_VALUE_MAX = 91; - - private static final ArrayList sChangeCallbacks = new ArrayList(); - - private static native String native_get(String key); - private static native String native_get(String key, String def); - private static native int native_get_int(String key, int def); - private static native long native_get_long(String key, long def); - private static native boolean native_get_boolean(String key, boolean def); - private static native void native_set(String key, String def); - private static native void native_add_change_callback(); - - /** - * Get the value for the given key. - * @return an empty string if the key isn't found - * @throws IllegalArgumentException if the key exceeds 32 characters - */ - public static String get(String key) { - if (key.length() > PROP_NAME_MAX) { - throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX); - } - return native_get(key); - } - - /** - * Get the value for the given key. - * @return if the key isn't found, return def if it isn't null, or an empty string otherwise - * @throws IllegalArgumentException if the key exceeds 32 characters - */ - public static String get(String key, String def) { - if (key.length() > PROP_NAME_MAX) { - throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX); - } - return native_get(key, def); - } - - /** - * Get the value for the given key, and return as an integer. - * @param key the key to lookup - * @param def a default value to return - * @return the key parsed as an integer, or def if the key isn't found or - * cannot be parsed - * @throws IllegalArgumentException if the key exceeds 32 characters - */ - public static int getInt(String key, int def) { - if (key.length() > PROP_NAME_MAX) { - throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX); - } - return native_get_int(key, def); - } - - /** - * Get the value for the given key, and return as a long. - * @param key the key to lookup - * @param def a default value to return - * @return the key parsed as a long, or def if the key isn't found or - * cannot be parsed - * @throws IllegalArgumentException if the key exceeds 32 characters - */ - public static long getLong(String key, long def) { - if (key.length() > PROP_NAME_MAX) { - throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX); - } - return native_get_long(key, def); - } - - /** - * Get the value for the given key, returned as a boolean. - * Values 'n', 'no', '0', 'false' or 'off' are considered false. - * Values 'y', 'yes', '1', 'true' or 'on' are considered true. - * (case sensitive). - * If the key does not exist, or has any other value, then the default - * result is returned. - * @param key the key to lookup - * @param def a default value to return - * @return the key parsed as a boolean, or def if the key isn't found or is - * not able to be parsed as a boolean. - * @throws IllegalArgumentException if the key exceeds 32 characters - */ - public static boolean getBoolean(String key, boolean def) { - if (key.length() > PROP_NAME_MAX) { - throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX); - } - return native_get_boolean(key, def); - } - - /** - * Set the value for the given key. - * @throws IllegalArgumentException if the key exceeds 32 characters - * @throws IllegalArgumentException if the value exceeds 92 characters - */ - public static void set(String key, String val) { - if (key.length() > PROP_NAME_MAX) { - throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX); - } - if (val != null && val.length() > PROP_VALUE_MAX) { - throw new IllegalArgumentException("val.length > " + - PROP_VALUE_MAX); - } - native_set(key, val); - } - - public static void addChangeCallback(Runnable callback) { - synchronized (sChangeCallbacks) { - if (sChangeCallbacks.size() == 0) { - native_add_change_callback(); - } - sChangeCallbacks.add(callback); - } - } - - static void callChangeCallbacks() { - synchronized (sChangeCallbacks) { - //Log.i("foo", "Calling " + sChangeCallbacks.size() + " change callbacks!"); - if (sChangeCallbacks.size() == 0) { - return; - } - ArrayList callbacks = new ArrayList(sChangeCallbacks); - for (int i=0; i properties = Bridge.getPlatformProperties(); - String value = properties.get(key); - if (value != null) { - return value; - } - - return def; - } - @LayoutlibDelegate - /*package*/ static int native_get_int(String key, int def) { - Map properties = Bridge.getPlatformProperties(); - String value = properties.get(key); - if (value != null) { - return Integer.decode(value); - } - - return def; - } - - @LayoutlibDelegate - /*package*/ static long native_get_long(String key, long def) { - Map properties = Bridge.getPlatformProperties(); - String value = properties.get(key); - if (value != null) { - return Long.decode(value); - } - - return def; - } - - /** - * Values 'n', 'no', '0', 'false' or 'off' are considered false. - * Values 'y', 'yes', '1', 'true' or 'on' are considered true. - */ - @LayoutlibDelegate - /*package*/ static boolean native_get_boolean(String key, boolean def) { - Map properties = Bridge.getPlatformProperties(); - String value = properties.get(key); - - if ("n".equals(value) || "no".equals(value) || "0".equals(value) || "false".equals(value) - || "off".equals(value)) { - return false; - } - //noinspection SimplifiableIfStatement - if ("y".equals(value) || "yes".equals(value) || "1".equals(value) || "true".equals(value) - || "on".equals(value)) { - return true; - } - - return def; - } - - @LayoutlibDelegate - /*package*/ static void native_set(String key, String def) { - Map properties = Bridge.getPlatformProperties(); - properties.put(key, def); - } - - @LayoutlibDelegate - /*package*/ static void native_add_change_callback() { - // pass. - } -} diff --git a/src/main/java/android/os/SystemService.java b/src/main/java/android/os/SystemService.java deleted file mode 100644 index 41e7546..0000000 --- a/src/main/java/android/os/SystemService.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import com.google.android.collect.Maps; - -import java.util.HashMap; -import java.util.concurrent.TimeoutException; - -/** - * Controls and utilities for low-level {@code init} services. - * - * @hide - */ -public class SystemService { - - private static HashMap sStates = Maps.newHashMap(); - - /** - * State of a known {@code init} service. - */ - public enum State { - RUNNING("running"), - STOPPING("stopping"), - STOPPED("stopped"), - RESTARTING("restarting"); - - State(String state) { - sStates.put(state, this); - } - } - - private static Object sPropertyLock = new Object(); - - static { - SystemProperties.addChangeCallback(new Runnable() { - @Override - public void run() { - synchronized (sPropertyLock) { - sPropertyLock.notifyAll(); - } - } - }); - } - - /** Request that the init daemon start a named service. */ - public static void start(String name) { - SystemProperties.set("ctl.start", name); - } - - /** Request that the init daemon stop a named service. */ - public static void stop(String name) { - SystemProperties.set("ctl.stop", name); - } - - /** Request that the init daemon restart a named service. */ - public static void restart(String name) { - SystemProperties.set("ctl.restart", name); - } - - /** - * Return current state of given service. - */ - public static State getState(String service) { - final String rawState = SystemProperties.get("init.svc." + service); - final State state = sStates.get(rawState); - if (state != null) { - return state; - } else { - return State.STOPPED; - } - } - - /** - * Check if given service is {@link State#STOPPED}. - */ - public static boolean isStopped(String service) { - return State.STOPPED.equals(getState(service)); - } - - /** - * Check if given service is {@link State#RUNNING}. - */ - public static boolean isRunning(String service) { - return State.RUNNING.equals(getState(service)); - } - - /** - * Wait until given service has entered specific state. - */ - public static void waitForState(String service, State state, long timeoutMillis) - throws TimeoutException { - final long endMillis = SystemClock.elapsedRealtime() + timeoutMillis; - while (true) { - synchronized (sPropertyLock) { - final State currentState = getState(service); - if (state.equals(currentState)) { - return; - } - - if (SystemClock.elapsedRealtime() >= endMillis) { - throw new TimeoutException("Service " + service + " currently " + currentState - + "; waited " + timeoutMillis + "ms for " + state); - } - - try { - sPropertyLock.wait(timeoutMillis); - } catch (InterruptedException e) { - } - } - } - } - - /** - * Wait until any of given services enters {@link State#STOPPED}. - */ - public static void waitForAnyStopped(String... services) { - while (true) { - synchronized (sPropertyLock) { - for (String service : services) { - if (State.STOPPED.equals(getState(service))) { - return; - } - } - - try { - sPropertyLock.wait(); - } catch (InterruptedException e) { - } - } - } - } -} diff --git a/src/main/java/android/os/SystemVibrator.java b/src/main/java/android/os/SystemVibrator.java deleted file mode 100644 index c488811..0000000 --- a/src/main/java/android/os/SystemVibrator.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.content.Context; -import android.media.AudioAttributes; -import android.util.Log; - -/** - * Vibrator implementation that controls the main system vibrator. - * - * @hide - */ -public class SystemVibrator extends Vibrator { - private static final String TAG = "Vibrator"; - - private final IVibratorService mService; - private final Binder mToken = new Binder(); - - public SystemVibrator() { - mService = IVibratorService.Stub.asInterface( - ServiceManager.getService("vibrator")); - } - - public SystemVibrator(Context context) { - super(context); - mService = IVibratorService.Stub.asInterface( - ServiceManager.getService("vibrator")); - } - - @Override - public boolean hasVibrator() { - if (mService == null) { - Log.w(TAG, "Failed to vibrate; no vibrator service."); - return false; - } - try { - return mService.hasVibrator(); - } catch (RemoteException e) { - } - return false; - } - - /** - * @hide - */ - @Override - public void vibrate(int uid, String opPkg, long milliseconds, AudioAttributes attributes) { - if (mService == null) { - Log.w(TAG, "Failed to vibrate; no vibrator service."); - return; - } - try { - mService.vibrate(uid, opPkg, milliseconds, usageForAttributes(attributes), mToken); - } catch (RemoteException e) { - Log.w(TAG, "Failed to vibrate.", e); - } - } - - /** - * @hide - */ - @Override - public void vibrate(int uid, String opPkg, long[] pattern, int repeat, - AudioAttributes attributes) { - if (mService == null) { - Log.w(TAG, "Failed to vibrate; no vibrator service."); - return; - } - // catch this here because the server will do nothing. pattern may - // not be null, let that be checked, because the server will drop it - // anyway - if (repeat < pattern.length) { - try { - mService.vibratePattern(uid, opPkg, pattern, repeat, usageForAttributes(attributes), - mToken); - } catch (RemoteException e) { - Log.w(TAG, "Failed to vibrate.", e); - } - } else { - throw new ArrayIndexOutOfBoundsException(); - } - } - - private static int usageForAttributes(AudioAttributes attributes) { - return attributes != null ? attributes.getUsage() : AudioAttributes.USAGE_UNKNOWN; - } - - @Override - public void cancel() { - if (mService == null) { - return; - } - try { - mService.cancelVibrate(mToken); - } catch (RemoteException e) { - Log.w(TAG, "Failed to cancel vibration.", e); - } - } -} diff --git a/src/main/java/android/os/TestHandlerThread.java b/src/main/java/android/os/TestHandlerThread.java deleted file mode 100644 index 7e84af3..0000000 --- a/src/main/java/android/os/TestHandlerThread.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.os.MessageQueue.IdleHandler; - -abstract class TestHandlerThread { - private boolean mDone = false; - private boolean mSuccess = false; - private RuntimeException mFailure = null; - private Looper mLooper; - - public abstract void go(); - - public TestHandlerThread() { - } - - public void doTest(long timeout) { - (new LooperThread()).start(); - - synchronized (this) { - long now = System.currentTimeMillis(); - long endTime = now + timeout; - while (!mDone && now < endTime) { - try { - wait(endTime-now); - } - catch (InterruptedException e) { - } - now = System.currentTimeMillis(); - } - } - - mLooper.quit(); - - if (!mDone) { - throw new RuntimeException("test timed out"); - } - if (!mSuccess) { - throw mFailure; - } - } - - public Looper getLooper() { - return mLooper; - } - - public void success() { - synchronized (this) { - mSuccess = true; - quit(); - } - } - - public void failure(RuntimeException failure) { - synchronized (this) { - mSuccess = false; - mFailure = failure; - quit(); - } - } - - class LooperThread extends Thread { - public void run() { - Looper.prepare(); - mLooper = Looper.myLooper(); - go(); - Looper.loop(); - - synchronized (TestHandlerThread.this) { - mDone = true; - if (!mSuccess && mFailure == null) { - mFailure = new RuntimeException("no failure exception set"); - } - TestHandlerThread.this.notifyAll(); - } - } - - } - - private void quit() { - synchronized (this) { - mDone = true; - notifyAll(); - } - } -} diff --git a/src/main/java/android/os/TokenWatcher.java b/src/main/java/android/os/TokenWatcher.java deleted file mode 100644 index 9b3a2d6..0000000 --- a/src/main/java/android/os/TokenWatcher.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.WeakHashMap; -import java.util.Set; -import android.util.Log; - -/** - * Helper class that helps you use IBinder objects as reference counted - * tokens. IBinders make good tokens because we find out when they are - * removed - * - */ -public abstract class TokenWatcher -{ - /** - * Construct the TokenWatcher - * - * @param h A handler to call {@link #acquired} and {@link #released} - * on. If you don't care, just call it like this, although your thread - * will have to be a Looper thread. - * new TokenWatcher(new Handler()) - * @param tag A debugging tag for this TokenWatcher - */ - public TokenWatcher(Handler h, String tag) - { - mHandler = h; - mTag = tag != null ? tag : "TokenWatcher"; - } - - /** - * Called when the number of active tokens goes from 0 to 1. - */ - public abstract void acquired(); - - /** - * Called when the number of active tokens goes from 1 to 0. - */ - public abstract void released(); - - /** - * Record that this token has been acquired. When acquire is called, and - * the current count is 0, the acquired method is called on the given - * handler. - * - * @param token An IBinder object. If this token has already been acquired, - * no action is taken. - * @param tag A string used by the {@link #dump} method for debugging, - * to see who has references. - */ - public void acquire(IBinder token, String tag) - { - synchronized (mTokens) { - // explicitly checked to avoid bogus sendNotification calls because - // of the WeakHashMap and the GC - int oldSize = mTokens.size(); - - Death d = new Death(token, tag); - try { - token.linkToDeath(d, 0); - } catch (RemoteException e) { - return; - } - mTokens.put(token, d); - - if (oldSize == 0 && !mAcquired) { - sendNotificationLocked(true); - mAcquired = true; - } - } - } - - public void cleanup(IBinder token, boolean unlink) - { - synchronized (mTokens) { - Death d = mTokens.remove(token); - if (unlink && d != null) { - d.token.unlinkToDeath(d, 0); - d.token = null; - } - - if (mTokens.size() == 0 && mAcquired) { - sendNotificationLocked(false); - mAcquired = false; - } - } - } - - public void release(IBinder token) - { - cleanup(token, true); - } - - public boolean isAcquired() - { - synchronized (mTokens) { - return mAcquired; - } - } - - public void dump() - { - ArrayList a = dumpInternal(); - for (String s : a) { - Log.i(mTag, s); - } - } - - public void dump(PrintWriter pw) { - ArrayList a = dumpInternal(); - for (String s : a) { - pw.println(s); - } - } - - private ArrayList dumpInternal() { - ArrayList a = new ArrayList(); - synchronized (mTokens) { - Set keys = mTokens.keySet(); - a.add("Token count: " + mTokens.size()); - int i = 0; - for (IBinder b: keys) { - a.add("[" + i + "] " + mTokens.get(b).tag + " - " + b); - i++; - } - } - return a; - } - - private Runnable mNotificationTask = new Runnable() { - public void run() - { - int value; - synchronized (mTokens) { - value = mNotificationQueue; - mNotificationQueue = -1; - } - if (value == 1) { - acquired(); - } - else if (value == 0) { - released(); - } - } - }; - - private void sendNotificationLocked(boolean on) - { - int value = on ? 1 : 0; - if (mNotificationQueue == -1) { - // empty - mNotificationQueue = value; - mHandler.post(mNotificationTask); - } - else if (mNotificationQueue != value) { - // it's a pair, so cancel it - mNotificationQueue = -1; - mHandler.removeCallbacks(mNotificationTask); - } - // else, same so do nothing -- maybe we should warn? - } - - private class Death implements IBinder.DeathRecipient - { - IBinder token; - String tag; - - Death(IBinder token, String tag) - { - this.token = token; - this.tag = tag; - } - - public void binderDied() - { - cleanup(token, false); - } - - protected void finalize() throws Throwable - { - try { - if (token != null) { - Log.w(mTag, "cleaning up leaked reference: " + tag); - release(token); - } - } - finally { - super.finalize(); - } - } - } - - private WeakHashMap mTokens = new WeakHashMap(); - private Handler mHandler; - private String mTag; - private int mNotificationQueue = -1; - private volatile boolean mAcquired = false; -} diff --git a/src/main/java/android/os/Trace.java b/src/main/java/android/os/Trace.java deleted file mode 100644 index 31b5849..0000000 --- a/src/main/java/android/os/Trace.java +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -/** - * Writes trace events to the system trace buffer. These trace events can be - * collected and visualized using the Systrace tool. - * - *

    This tracing mechanism is independent of the method tracing mechanism - * offered by {@link Debug#startMethodTracing}. In particular, it enables - * tracing of events that occur across multiple processes. - *

    For information about using the Systrace tool, read Analyzing Display and Performance - * with Systrace. - */ -public final class Trace { - /* - * Writes trace events to the kernel trace buffer. These trace events can be - * collected using the "atrace" program for offline analysis. - */ - - private static final String TAG = "Trace"; - - // These tags must be kept in sync with system/core/include/cutils/trace.h. - // They should also be added to frameworks/native/cmds/atrace/atrace.cpp. - /** @hide */ - public static final long TRACE_TAG_NEVER = 0; - /** @hide */ - public static final long TRACE_TAG_ALWAYS = 1L << 0; - /** @hide */ - public static final long TRACE_TAG_GRAPHICS = 1L << 1; - /** @hide */ - public static final long TRACE_TAG_INPUT = 1L << 2; - /** @hide */ - public static final long TRACE_TAG_VIEW = 1L << 3; - /** @hide */ - public static final long TRACE_TAG_WEBVIEW = 1L << 4; - /** @hide */ - public static final long TRACE_TAG_WINDOW_MANAGER = 1L << 5; - /** @hide */ - public static final long TRACE_TAG_ACTIVITY_MANAGER = 1L << 6; - /** @hide */ - public static final long TRACE_TAG_SYNC_MANAGER = 1L << 7; - /** @hide */ - public static final long TRACE_TAG_AUDIO = 1L << 8; - /** @hide */ - public static final long TRACE_TAG_VIDEO = 1L << 9; - /** @hide */ - public static final long TRACE_TAG_CAMERA = 1L << 10; - /** @hide */ - public static final long TRACE_TAG_HAL = 1L << 11; - /** @hide */ - public static final long TRACE_TAG_APP = 1L << 12; - /** @hide */ - public static final long TRACE_TAG_RESOURCES = 1L << 13; - /** @hide */ - public static final long TRACE_TAG_DALVIK = 1L << 14; - /** @hide */ - public static final long TRACE_TAG_RS = 1L << 15; - /** @hide */ - public static final long TRACE_TAG_BIONIC = 1L << 16; - /** @hide */ - public static final long TRACE_TAG_POWER = 1L << 17; - - private static final long TRACE_TAG_NOT_READY = 1L << 63; - private static final int MAX_SECTION_NAME_LEN = 127; - - // Must be volatile to avoid word tearing. - private static volatile long sEnabledTags = TRACE_TAG_NOT_READY; - - private static native long nativeGetEnabledTags(); - private static native void nativeTraceCounter(long tag, String name, int value); - private static native void nativeTraceBegin(long tag, String name); - private static native void nativeTraceEnd(long tag); - private static native void nativeAsyncTraceBegin(long tag, String name, int cookie); - private static native void nativeAsyncTraceEnd(long tag, String name, int cookie); - private static native void nativeSetAppTracingAllowed(boolean allowed); - private static native void nativeSetTracingEnabled(boolean allowed); - - static { - // We configure two separate change callbacks, one in Trace.cpp and one here. The - // native callback reads the tags from the system property, and this callback - // reads the value that the native code retrieved. It's essential that the native - // callback executes first. - // - // The system provides ordering through a priority level. Callbacks made through - // SystemProperties.addChangeCallback currently have a negative priority, while - // our native code is using a priority of zero. - SystemProperties.addChangeCallback(new Runnable() { - @Override public void run() { - cacheEnabledTags(); - } - }); - } - - private Trace() { - } - - /** - * Caches a copy of the enabled-tag bits. The "master" copy is held by the native code, - * and comes from the PROPERTY_TRACE_TAG_ENABLEFLAGS property. - *

    - * If the native code hasn't yet read the property, we will cause it to do one-time - * initialization. We don't want to do this during class init, because this class is - * preloaded, so all apps would be stuck with whatever the zygote saw. (The zygote - * doesn't see the system-property update broadcasts.) - *

    - * We want to defer initialization until the first use by an app, post-zygote. - *

    - * We're okay if multiple threads call here simultaneously -- the native state is - * synchronized, and sEnabledTags is volatile (prevents word tearing). - */ - private static long cacheEnabledTags() { - long tags = nativeGetEnabledTags(); - sEnabledTags = tags; - return tags; - } - - /** - * Returns true if a trace tag is enabled. - * - * @param traceTag The trace tag to check. - * @return True if the trace tag is valid. - * - * @hide - */ - public static boolean isTagEnabled(long traceTag) { - long tags = sEnabledTags; - if (tags == TRACE_TAG_NOT_READY) { - tags = cacheEnabledTags(); - } - return (tags & traceTag) != 0; - } - - /** - * Writes trace message to indicate the value of a given counter. - * - * @param traceTag The trace tag. - * @param counterName The counter name to appear in the trace. - * @param counterValue The counter value. - * - * @hide - */ - public static void traceCounter(long traceTag, String counterName, int counterValue) { - if (isTagEnabled(traceTag)) { - nativeTraceCounter(traceTag, counterName, counterValue); - } - } - - /** - * Set whether application tracing is allowed for this process. This is intended to be set - * once at application start-up time based on whether the application is debuggable. - * - * @hide - */ - public static void setAppTracingAllowed(boolean allowed) { - nativeSetAppTracingAllowed(allowed); - - // Setting whether app tracing is allowed may change the tags, so we update the cached - // tags here. - cacheEnabledTags(); - } - - /** - * Set whether tracing is enabled in this process. Tracing is disabled shortly after Zygote - * initializes and re-enabled after processes fork from Zygote. This is done because Zygote - * has no way to be notified about changes to the tracing tags, and if Zygote ever reads and - * caches the tracing tags, forked processes will inherit those stale tags. - * - * @hide - */ - public static void setTracingEnabled(boolean enabled) { - nativeSetTracingEnabled(enabled); - - // Setting whether tracing is enabled may change the tags, so we update the cached tags - // here. - cacheEnabledTags(); - } - - /** - * Writes a trace message to indicate that a given section of code has - * begun. Must be followed by a call to {@link #traceEnd} using the same - * tag. - * - * @param traceTag The trace tag. - * @param methodName The method name to appear in the trace. - * - * @hide - */ - public static void traceBegin(long traceTag, String methodName) { - if (isTagEnabled(traceTag)) { - nativeTraceBegin(traceTag, methodName); - } - } - - /** - * Writes a trace message to indicate that the current method has ended. - * Must be called exactly once for each call to {@link #traceBegin} using the same tag. - * - * @param traceTag The trace tag. - * - * @hide - */ - public static void traceEnd(long traceTag) { - if (isTagEnabled(traceTag)) { - nativeTraceEnd(traceTag); - } - } - - /** - * Writes a trace message to indicate that a given section of code has - * begun. Must be followed by a call to {@link #asyncTraceEnd} using the same - * tag. Unlike {@link #traceBegin(long, String)} and {@link #traceEnd(long)}, - * asynchronous events do not need to be nested. The name and cookie used to - * begin an event must be used to end it. - * - * @param traceTag The trace tag. - * @param methodName The method name to appear in the trace. - * @param cookie Unique identifier for distinguishing simultaneous events - * - * @hide - */ - public static void asyncTraceBegin(long traceTag, String methodName, int cookie) { - if (isTagEnabled(traceTag)) { - nativeAsyncTraceBegin(traceTag, methodName, cookie); - } - } - - /** - * Writes a trace message to indicate that the current method has ended. - * Must be called exactly once for each call to {@link #asyncTraceBegin(long, String, int)} - * using the same tag, name and cookie. - * - * @param traceTag The trace tag. - * @param methodName The method name to appear in the trace. - * @param cookie Unique identifier for distinguishing simultaneous events - * - * @hide - */ - public static void asyncTraceEnd(long traceTag, String methodName, int cookie) { - if (isTagEnabled(traceTag)) { - nativeAsyncTraceEnd(traceTag, methodName, cookie); - } - } - - /** - * Writes a trace message to indicate that a given section of code has begun. This call must - * be followed by a corresponding call to {@link #endSection()} on the same thread. - * - *

    At this time the vertical bar character '|', newline character '\n', and - * null character '\0' are used internally by the tracing mechanism. If sectionName contains - * these characters they will be replaced with a space character in the trace. - * - * @param sectionName The name of the code section to appear in the trace. This may be at - * most 127 Unicode code units long. - */ - public static void beginSection(String sectionName) { - if (isTagEnabled(TRACE_TAG_APP)) { - if (sectionName.length() > MAX_SECTION_NAME_LEN) { - throw new IllegalArgumentException("sectionName is too long"); - } - nativeTraceBegin(TRACE_TAG_APP, sectionName); - } - } - - /** - * Writes a trace message to indicate that a given section of code has ended. This call must - * be preceeded by a corresponding call to {@link #beginSection(String)}. Calling this method - * will mark the end of the most recently begun section of code, so care must be taken to - * ensure that beginSection / endSection pairs are properly nested and called from the same - * thread. - */ - public static void endSection() { - if (isTagEnabled(TRACE_TAG_APP)) { - nativeTraceEnd(TRACE_TAG_APP); - } - } -} diff --git a/src/main/java/android/os/TraceTest.java b/src/main/java/android/os/TraceTest.java deleted file mode 100644 index 7a788ee..0000000 --- a/src/main/java/android/os/TraceTest.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.os.Debug; -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.LargeTest; -import android.test.suitebuilder.annotation.SmallTest; -import android.test.suitebuilder.annotation.Suppress; -import android.util.Log; - -/** - * This class is used to test the native tracing support. Run this test - * while tracing on the emulator and then run traceview to view the trace. - */ -public class TraceTest extends AndroidTestCase -{ - private static final String TAG = "TraceTest"; - private int eMethodCalls = 0; - private int fMethodCalls = 0; - private int gMethodCalls = 0; - - @SmallTest - public void testNativeTracingFromJava() - { - long start = System.currentTimeMillis(); - Debug.startNativeTracing(); - //nativeMethod(); - int count = 0; - for (int ii = 0; ii < 20; ii++) { - count = eMethod(); - } - Debug.stopNativeTracing(); - long end = System.currentTimeMillis(); - long elapsed = end - start; - Log.i(TAG, "elapsed millis: " + elapsed); - Log.i(TAG, "eMethod calls: " + eMethodCalls - + " fMethod calls: " + fMethodCalls - + " gMethod calls: " + gMethodCalls); - } - - // This should not run in the automated suite. - @Suppress - public void disableTestNativeTracingFromC() - { - long start = System.currentTimeMillis(); - nativeMethodAndStartTracing(); - long end = System.currentTimeMillis(); - long elapsed = end - start; - Log.i(TAG, "elapsed millis: " + elapsed); - } - - native void nativeMethod(); - native void nativeMethodAndStartTracing(); - - @LargeTest - public void testMethodTracing() - { - long start = System.currentTimeMillis(); - Debug.startMethodTracing("traceTest"); - topMethod(); - Debug.stopMethodTracing(); - long end = System.currentTimeMillis(); - long elapsed = end - start; - Log.i(TAG, "elapsed millis: " + elapsed); - } - - private void topMethod() { - aMethod(); - bMethod(); - cMethod(); - dMethod(5); - - Thread t1 = new aThread(); - t1.start(); - Thread t2 = new aThread(); - t2.start(); - Thread t3 = new aThread(); - t3.start(); - try { - t1.join(); - t2.join(); - t3.join(); - } catch (InterruptedException e) { - } - } - - private class aThread extends Thread { - @Override - public void run() { - aMethod(); - bMethod(); - cMethod(); - } - } - - /** Calls other methods to make some interesting trace data. - * - * @return a meaningless value - */ - private int aMethod() { - int count = 0; - for (int ii = 0; ii < 6; ii++) { - count += bMethod(); - } - for (int ii = 0; ii < 5; ii++) { - count += cMethod(); - } - for (int ii = 0; ii < 4; ii++) { - count += dMethod(ii); - } - return count; - } - - /** Calls another method to make some interesting trace data. - * - * @return a meaningless value - */ - private int bMethod() { - int count = 0; - for (int ii = 0; ii < 4; ii++) { - count += cMethod(); - } - return count; - } - - /** Executes a simple loop to make some interesting trace data. - * - * @return a meaningless value - */ - private int cMethod() { - int count = 0; - for (int ii = 0; ii < 1000; ii++) { - count += ii; - } - return count; - } - - /** Calls itself recursively to make some interesting trace data. - * - * @return a meaningless value - */ - private int dMethod(int level) { - int count = 0; - if (level > 0) { - count = dMethod(level - 1); - } - for (int ii = 0; ii < 100; ii++) { - count += ii; - } - if (level == 0) { - return count; - } - return dMethod(level - 1); - } - - public int eMethod() { - eMethodCalls += 1; - int count = fMethod(); - count += gMethod(3); - return count; - } - - public int fMethod() { - fMethodCalls += 1; - int count = 0; - for (int ii = 0; ii < 10; ii++) { - count += ii; - } - return count; - } - - public int gMethod(int level) { - gMethodCalls += 1; - int count = level; - if (level > 1) - count += gMethod(level - 1); - return count; - } - - /* - * This causes the native shared library to be loaded when the - * class is first used. The library is only loaded once, even if - * multiple classes include this line. - * - * The library must be in java.library.path, which is derived from - * LD_LIBRARY_PATH. The actual library name searched for will be - * "libtrace_test.so" under Linux, but may be different on other - * platforms. - */ - static { - Log.i(TAG, "Loading trace_test native library..."); - try { - System.loadLibrary("trace_test"); - Log.i(TAG, "Successfully loaded trace_test native library"); - } - catch (UnsatisfiedLinkError ule) { - Log.w(TAG, "Could not load trace_test native library"); - } - } -} diff --git a/src/main/java/android/os/TransactionTooLargeException.java b/src/main/java/android/os/TransactionTooLargeException.java deleted file mode 100644 index 25f09e8..0000000 --- a/src/main/java/android/os/TransactionTooLargeException.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; -import android.os.RemoteException; - -/** - * The Binder transaction failed because it was too large. - *

    - * During a remote procedure call, the arguments and the return value of the call - * are transferred as {@link Parcel} objects stored in the Binder transaction buffer. - * If the arguments or the return value are too large to fit in the transaction buffer, - * then the call will fail and {@link TransactionTooLargeException} will be thrown. - *

    - * The Binder transaction buffer has a limited fixed size, currently 1Mb, which - * is shared by all transactions in progress for the process. Consequently this - * exception can be thrown when there are many transactions in progress even when - * most of the individual transactions are of moderate size. - *

    - * There are two possible outcomes when a remote procedure call throws - * {@link TransactionTooLargeException}. Either the client was unable to send - * its request to the service (most likely if the arguments were too large to fit in - * the transaction buffer), or the service was unable to send its response back - * to the client (most likely if the return value was too large to fit - * in the transaction buffer). It is not possible to tell which of these outcomes - * actually occurred. The client should assume that a partial failure occurred. - *

    - * The key to avoiding {@link TransactionTooLargeException} is to keep all - * transactions relatively small. Try to minimize the amount of memory needed to create - * a {@link Parcel} for the arguments and the return value of the remote procedure call. - * Avoid transferring huge arrays of strings or large bitmaps. - * If possible, try to break up big requests into smaller pieces. - *

    - * If you are implementing a service, it may help to impose size or complexity - * contraints on the queries that clients can perform. For example, if the result set - * could become large, then don't allow the client to request more than a few records - * at a time. Alternately, instead of returning all of the available data all at once, - * return the essential information first and make the client ask for additional information - * later as needed. - *

    - */ -public class TransactionTooLargeException extends RemoteException { - public TransactionTooLargeException() { - super(); - } -} diff --git a/src/main/java/android/os/UEventObserver.java b/src/main/java/android/os/UEventObserver.java deleted file mode 100644 index 9dbfd50..0000000 --- a/src/main/java/android/os/UEventObserver.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.util.Log; - -import java.util.ArrayList; -import java.util.HashMap; - -/** - * UEventObserver is an abstract class that receives UEvent's from the kernel.

    - * - * Subclass UEventObserver, implementing onUEvent(UEvent event), then call - * startObserving() with a match string. The UEvent thread will then call your - * onUEvent() method when a UEvent occurs that contains your match string.

    - * - * Call stopObserving() to stop receiving UEvent's.

    - * - * There is only one UEvent thread per process, even if that process has - * multiple UEventObserver subclass instances. The UEvent thread starts when - * the startObserving() is called for the first time in that process. Once - * started the UEvent thread will not stop (although it can stop notifying - * UEventObserver's via stopObserving()).

    - * - * @hide -*/ -public abstract class UEventObserver { - private static final String TAG = "UEventObserver"; - private static final boolean DEBUG = false; - - private static UEventThread sThread; - - private static native void nativeSetup(); - private static native String nativeWaitForNextEvent(); - private static native void nativeAddMatch(String match); - private static native void nativeRemoveMatch(String match); - - public UEventObserver() { - } - - @Override - protected void finalize() throws Throwable { - try { - stopObserving(); - } finally { - super.finalize(); - } - } - - private static UEventThread getThread() { - synchronized (UEventObserver.class) { - if (sThread == null) { - sThread = new UEventThread(); - sThread.start(); - } - return sThread; - } - } - - private static UEventThread peekThread() { - synchronized (UEventObserver.class) { - return sThread; - } - } - - /** - * Begin observation of UEvent's.

    - * This method will cause the UEvent thread to start if this is the first - * invocation of startObserving in this process.

    - * Once called, the UEvent thread will call onUEvent() when an incoming - * UEvent matches the specified string.

    - * This method can be called multiple times to register multiple matches. - * Only one call to stopObserving is required even with multiple registered - * matches. - * - * @param match A substring of the UEvent to match. Try to be as specific - * as possible to avoid incurring unintended additional cost from processing - * irrelevant messages. Netlink messages can be moderately high bandwidth and - * are expensive to parse. For example, some devices may send one netlink message - * for each vsync period. - */ - public final void startObserving(String match) { - if (match == null || match.isEmpty()) { - throw new IllegalArgumentException("match substring must be non-empty"); - } - - final UEventThread t = getThread(); - t.addObserver(match, this); - } - - /** - * End observation of UEvent's.

    - * This process's UEvent thread will never call onUEvent() on this - * UEventObserver after this call. Repeated calls have no effect. - */ - public final void stopObserving() { - final UEventThread t = getThread(); - if (t != null) { - t.removeObserver(this); - } - } - - /** - * Subclasses of UEventObserver should override this method to handle - * UEvents. - */ - public abstract void onUEvent(UEvent event); - - /** - * Representation of a UEvent. - */ - public static final class UEvent { - // collection of key=value pairs parsed from the uevent message - private final HashMap mMap = new HashMap(); - - public UEvent(String message) { - int offset = 0; - int length = message.length(); - - while (offset < length) { - int equals = message.indexOf('=', offset); - int at = message.indexOf('\0', offset); - if (at < 0) break; - - if (equals > offset && equals < at) { - // key is before the equals sign, and value is after - mMap.put(message.substring(offset, equals), - message.substring(equals + 1, at)); - } - - offset = at + 1; - } - } - - public String get(String key) { - return mMap.get(key); - } - - public String get(String key, String defaultValue) { - String result = mMap.get(key); - return (result == null ? defaultValue : result); - } - - public String toString() { - return mMap.toString(); - } - } - - private static final class UEventThread extends Thread { - /** Many to many mapping of string match to observer. - * Multimap would be better, but not available in android, so use - * an ArrayList where even elements are the String match and odd - * elements the corresponding UEventObserver observer */ - private final ArrayList mKeysAndObservers = new ArrayList(); - - private final ArrayList mTempObserversToSignal = - new ArrayList(); - - public UEventThread() { - super("UEventObserver"); - } - - @Override - public void run() { - nativeSetup(); - - while (true) { - String message = nativeWaitForNextEvent(); - if (message != null) { - if (DEBUG) { - Log.d(TAG, message); - } - sendEvent(message); - } - } - } - - private void sendEvent(String message) { - synchronized (mKeysAndObservers) { - final int N = mKeysAndObservers.size(); - for (int i = 0; i < N; i += 2) { - final String key = (String)mKeysAndObservers.get(i); - if (message.contains(key)) { - final UEventObserver observer = - (UEventObserver)mKeysAndObservers.get(i + 1); - mTempObserversToSignal.add(observer); - } - } - } - - if (!mTempObserversToSignal.isEmpty()) { - final UEvent event = new UEvent(message); - final int N = mTempObserversToSignal.size(); - for (int i = 0; i < N; i++) { - final UEventObserver observer = mTempObserversToSignal.get(i); - observer.onUEvent(event); - } - mTempObserversToSignal.clear(); - } - } - - public void addObserver(String match, UEventObserver observer) { - synchronized (mKeysAndObservers) { - mKeysAndObservers.add(match); - mKeysAndObservers.add(observer); - nativeAddMatch(match); - } - } - - /** Removes every key/value pair where value=observer from mObservers */ - public void removeObserver(UEventObserver observer) { - synchronized (mKeysAndObservers) { - for (int i = 0; i < mKeysAndObservers.size(); ) { - if (mKeysAndObservers.get(i + 1) == observer) { - mKeysAndObservers.remove(i + 1); - final String match = (String)mKeysAndObservers.remove(i); - nativeRemoveMatch(match); - } else { - i += 2; - } - } - } - } - } -} diff --git a/src/main/java/android/os/UpdateLock.java b/src/main/java/android/os/UpdateLock.java deleted file mode 100644 index 4060326..0000000 --- a/src/main/java/android/os/UpdateLock.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.content.Context; -import android.util.Log; - -/** - * Advisory wakelock-like mechanism by which processes that should not be interrupted for - * OTA/update purposes can so advise the OS. This is particularly relevant for headless - * or kiosk-like operation. - * - * @hide - */ -public class UpdateLock { - private static final boolean DEBUG = false; - private static final String TAG = "UpdateLock"; - - private static IUpdateLock sService; - private static void checkService() { - if (sService == null) { - sService = IUpdateLock.Stub.asInterface( - ServiceManager.getService(Context.UPDATE_LOCK_SERVICE)); - } - } - - IBinder mToken; - int mCount = 0; - boolean mRefCounted = true; - boolean mHeld = false; - final String mTag; - - /** - * Broadcast Intent action sent when the global update lock state changes, - * i.e. when the first locker acquires an update lock, or when the last - * locker releases theirs. The broadcast is sticky but is sent only to - * registered receivers. - */ - public static final String UPDATE_LOCK_CHANGED = "android.os.UpdateLock.UPDATE_LOCK_CHANGED"; - - /** - * Boolean Intent extra on the UPDATE_LOCK_CHANGED sticky broadcast, indicating - * whether now is an appropriate time to interrupt device activity with an - * update operation. True means that updates are okay right now; false indicates - * that perhaps later would be a better time. - */ - public static final String NOW_IS_CONVENIENT = "nowisconvenient"; - - /** - * Long Intent extra on the UPDATE_LOCK_CHANGED sticky broadcast, marking the - * wall-clock time [in UTC] at which the broadcast was sent. Note that this is - * in the System.currentTimeMillis() time base, which may be non-monotonic especially - * around reboots. - */ - public static final String TIMESTAMP = "timestamp"; - - /** - * Construct an UpdateLock instance. - * @param tag An arbitrary string used to identify this lock instance in dump output. - */ - public UpdateLock(String tag) { - mTag = tag; - mToken = new Binder(); - } - - /** - * Change the refcount behavior of this update lock. - */ - public void setReferenceCounted(boolean isRefCounted) { - if (DEBUG) { - Log.v(TAG, "setting refcounted=" + isRefCounted + " : " + this); - } - mRefCounted = isRefCounted; - } - - /** - * Is this lock currently held? - */ - public boolean isHeld() { - synchronized (mToken) { - return mHeld; - } - } - - /** - * Acquire an update lock. - */ - public void acquire() { - if (DEBUG) { - Log.v(TAG, "acquire() : " + this, new RuntimeException("here")); - } - checkService(); - synchronized (mToken) { - acquireLocked(); - } - } - - private void acquireLocked() { - if (!mRefCounted || mCount++ == 0) { - if (sService != null) { - try { - sService.acquireUpdateLock(mToken, mTag); - } catch (RemoteException e) { - Log.e(TAG, "Unable to contact service to acquire"); - } - } - mHeld = true; - } - } - - /** - * Release this update lock. - */ - public void release() { - if (DEBUG) Log.v(TAG, "release() : " + this, new RuntimeException("here")); - checkService(); - synchronized (mToken) { - releaseLocked(); - } - } - - private void releaseLocked() { - if (!mRefCounted || --mCount == 0) { - if (sService != null) { - try { - sService.releaseUpdateLock(mToken); - } catch (RemoteException e) { - Log.e(TAG, "Unable to contact service to release"); - } - } - mHeld = false; - } - if (mCount < 0) { - throw new RuntimeException("UpdateLock under-locked"); - } - } - - @Override - protected void finalize() throws Throwable { - synchronized (mToken) { - // if mHeld is true, sService must be non-null - if (mHeld) { - Log.wtf(TAG, "UpdateLock finalized while still held"); - try { - sService.releaseUpdateLock(mToken); - } catch (RemoteException e) { - Log.e(TAG, "Unable to contact service to release"); - } - } - } - } -} diff --git a/src/main/java/android/os/UserHandle.java b/src/main/java/android/os/UserHandle.java deleted file mode 100644 index 74e064e..0000000 --- a/src/main/java/android/os/UserHandle.java +++ /dev/null @@ -1,353 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.annotation.SystemApi; -import android.util.SparseArray; - -import java.io.PrintWriter; -import java.util.HashMap; - -/** - * Representation of a user on the device. - */ -public final class UserHandle implements Parcelable { - /** - * @hide Range of uids allocated for a user. - */ - public static final int PER_USER_RANGE = 100000; - - /** @hide A user id to indicate all users on the device */ - public static final int USER_ALL = -1; - - /** @hide A user handle to indicate all users on the device */ - public static final UserHandle ALL = new UserHandle(USER_ALL); - - /** @hide A user id to indicate the currently active user */ - public static final int USER_CURRENT = -2; - - /** @hide A user handle to indicate the current user of the device */ - public static final UserHandle CURRENT = new UserHandle(USER_CURRENT); - - /** @hide A user id to indicate that we would like to send to the current - * user, but if this is calling from a user process then we will send it - * to the caller's user instead of failing with a security exception */ - public static final int USER_CURRENT_OR_SELF = -3; - - /** @hide A user handle to indicate that we would like to send to the current - * user, but if this is calling from a user process then we will send it - * to the caller's user instead of failing with a security exception */ - public static final UserHandle CURRENT_OR_SELF = new UserHandle(USER_CURRENT_OR_SELF); - - /** @hide An undefined user id */ - public static final int USER_NULL = -10000; - - /** @hide A user id constant to indicate the "owner" user of the device */ - public static final int USER_OWNER = 0; - - /** @hide A user handle to indicate the primary/owner user of the device */ - public static final UserHandle OWNER = new UserHandle(USER_OWNER); - - /** - * @hide Enable multi-user related side effects. Set this to false if - * there are problems with single user use-cases. - */ - public static final boolean MU_ENABLED = true; - - final int mHandle; - - private static final SparseArray userHandles = new SparseArray(); - - /** - * Checks to see if the user id is the same for the two uids, i.e., they belong to the same - * user. - * @hide - */ - public static final boolean isSameUser(int uid1, int uid2) { - return getUserId(uid1) == getUserId(uid2); - } - - /** - * Checks to see if both uids are referring to the same app id, ignoring the user id part of the - * uids. - * @param uid1 uid to compare - * @param uid2 other uid to compare - * @return whether the appId is the same for both uids - * @hide - */ - public static final boolean isSameApp(int uid1, int uid2) { - return getAppId(uid1) == getAppId(uid2); - } - - /** @hide */ - public static final boolean isIsolated(int uid) { - if (uid > 0) { - final int appId = getAppId(uid); - return appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID; - } else { - return false; - } - } - - /** @hide */ - public static boolean isApp(int uid) { - if (uid > 0) { - final int appId = getAppId(uid); - return appId >= Process.FIRST_APPLICATION_UID && appId <= Process.LAST_APPLICATION_UID; - } else { - return false; - } - } - - /** - * Returns the user id for a given uid. - * @hide - */ - public static final int getUserId(int uid) { - if (MU_ENABLED) { - return uid / PER_USER_RANGE; - } else { - return 0; - } - } - - /** @hide */ - public static final int getCallingUserId() { - return getUserId(Binder.getCallingUid()); - } - - /** @hide */ - public static final UserHandle getCallingUserHandle() { - int userId = getUserId(Binder.getCallingUid()); - UserHandle userHandle = userHandles.get(userId); - // Intentionally not synchronized to save time - if (userHandle == null) { - userHandle = new UserHandle(userId); - userHandles.put(userId, userHandle); - } - return userHandle; - } - - /** - * Returns the uid that is composed from the userId and the appId. - * @hide - */ - public static final int getUid(int userId, int appId) { - if (MU_ENABLED) { - return userId * PER_USER_RANGE + (appId % PER_USER_RANGE); - } else { - return appId; - } - } - - /** - * Returns the app id (or base uid) for a given uid, stripping out the user id from it. - * @hide - */ - public static final int getAppId(int uid) { - return uid % PER_USER_RANGE; - } - - /** - * Returns the gid shared between all apps with this userId. - * @hide - */ - public static final int getUserGid(int userId) { - return getUid(userId, Process.SHARED_USER_GID); - } - - /** - * Returns the shared app gid for a given uid or appId. - * @hide - */ - public static final int getSharedAppGid(int id) { - return Process.FIRST_SHARED_APPLICATION_GID + (id % PER_USER_RANGE) - - Process.FIRST_APPLICATION_UID; - } - - /** - * Generate a text representation of the uid, breaking out its individual - * components -- user, app, isolated, etc. - * @hide - */ - public static void formatUid(StringBuilder sb, int uid) { - if (uid < Process.FIRST_APPLICATION_UID) { - sb.append(uid); - } else { - sb.append('u'); - sb.append(getUserId(uid)); - final int appId = getAppId(uid); - if (appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID) { - sb.append('i'); - sb.append(appId - Process.FIRST_ISOLATED_UID); - } else if (appId >= Process.FIRST_APPLICATION_UID) { - sb.append('a'); - sb.append(appId - Process.FIRST_APPLICATION_UID); - } else { - sb.append('s'); - sb.append(appId); - } - } - } - - /** - * Generate a text representation of the uid, breaking out its individual - * components -- user, app, isolated, etc. - * @hide - */ - public static void formatUid(PrintWriter pw, int uid) { - if (uid < Process.FIRST_APPLICATION_UID) { - pw.print(uid); - } else { - pw.print('u'); - pw.print(getUserId(uid)); - final int appId = getAppId(uid); - if (appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID) { - pw.print('i'); - pw.print(appId - Process.FIRST_ISOLATED_UID); - } else if (appId >= Process.FIRST_APPLICATION_UID) { - pw.print('a'); - pw.print(appId - Process.FIRST_APPLICATION_UID); - } else { - pw.print('s'); - pw.print(appId); - } - } - } - - /** - * Returns the user id of the current process - * @return user id of the current process - * @hide - */ - @SystemApi - public static final int myUserId() { - return getUserId(Process.myUid()); - } - - /** - * Returns true if this UserHandle refers to the owner user; false otherwise. - * @return true if this UserHandle refers to the owner user; false otherwise. - * @hide - */ - @SystemApi - public final boolean isOwner() { - return this.equals(OWNER); - } - - /** @hide */ - public UserHandle(int h) { - mHandle = h; - } - - /** - * Returns the userId stored in this UserHandle. - * @hide - */ - @SystemApi - public int getIdentifier() { - return mHandle; - } - - @Override - public String toString() { - return "UserHandle{" + mHandle + "}"; - } - - @Override - public boolean equals(Object obj) { - try { - if (obj != null) { - UserHandle other = (UserHandle)obj; - return mHandle == other.mHandle; - } - } catch (ClassCastException e) { - } - return false; - } - - @Override - public int hashCode() { - return mHandle; - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel out, int flags) { - out.writeInt(mHandle); - } - - /** - * Write a UserHandle to a Parcel, handling null pointers. Must be - * read with {@link #readFromParcel(Parcel)}. - * - * @param h The UserHandle to be written. - * @param out The Parcel in which the UserHandle will be placed. - * - * @see #readFromParcel(Parcel) - */ - public static void writeToParcel(UserHandle h, Parcel out) { - if (h != null) { - h.writeToParcel(out, 0); - } else { - out.writeInt(USER_NULL); - } - } - - /** - * Read a UserHandle from a Parcel that was previously written - * with {@link #writeToParcel(UserHandle, Parcel)}, returning either - * a null or new object as appropriate. - * - * @param in The Parcel from which to read the UserHandle - * @return Returns a new UserHandle matching the previously written - * object, or null if a null had been written. - * - * @see #writeToParcel(UserHandle, Parcel) - */ - public static UserHandle readFromParcel(Parcel in) { - int h = in.readInt(); - return h != USER_NULL ? new UserHandle(h) : null; - } - - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - public UserHandle createFromParcel(Parcel in) { - return new UserHandle(in); - } - - public UserHandle[] newArray(int size) { - return new UserHandle[size]; - } - }; - - /** - * Instantiate a new UserHandle from the data in a Parcel that was - * previously written with {@link #writeToParcel(Parcel, int)}. Note that you - * must not use this with data written by - * {@link #writeToParcel(UserHandle, Parcel)} since it is not possible - * to handle a null UserHandle here. - * - * @param in The Parcel containing the previously written UserHandle, - * positioned at the location in the buffer where it was written. - */ - public UserHandle(Parcel in) { - mHandle = in.readInt(); - } -} diff --git a/src/main/java/android/os/UserManager.java b/src/main/java/android/os/UserManager.java deleted file mode 100644 index d124a49..0000000 --- a/src/main/java/android/os/UserManager.java +++ /dev/null @@ -1,1289 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.os; - -import android.annotation.SystemApi; -import android.app.ActivityManager; -import android.app.ActivityManagerNative; -import android.content.Context; -import android.content.pm.UserInfo; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.provider.Settings; -import android.util.Log; -import android.view.WindowManager.LayoutParams; - -import com.android.internal.R; - -import java.util.ArrayList; -import java.util.List; - -/** - * Manages users and user details on a multi-user system. - */ -public class UserManager { - - private static String TAG = "UserManager"; - private final IUserManager mService; - private final Context mContext; - - /** - * Specifies if a user is disallowed from adding and removing accounts. - * The default value is false. - * - *

    Key for user restrictions. - *

    Type: Boolean - * @see #setUserRestrictions(Bundle) - * @see #getUserRestrictions() - */ - public static final String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts"; - - /** - * Specifies if a user is disallowed from changing Wi-Fi - * access points. The default value is false. - *

    This restriction has no effect in a managed profile. - * - *

    Key for user restrictions. - *

    Type: Boolean - * @see #setUserRestrictions(Bundle) - * @see #getUserRestrictions() - */ - public static final String DISALLOW_CONFIG_WIFI = "no_config_wifi"; - - /** - * Specifies if a user is disallowed from installing applications. - * The default value is false. - * - *

    Key for user restrictions. - *

    Type: Boolean - * @see #setUserRestrictions(Bundle) - * @see #getUserRestrictions() - */ - public static final String DISALLOW_INSTALL_APPS = "no_install_apps"; - - /** - * Specifies if a user is disallowed from uninstalling applications. - * The default value is false. - * - *

    Key for user restrictions. - *

    Type: Boolean - * @see #setUserRestrictions(Bundle) - * @see #getUserRestrictions() - */ - public static final String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps"; - - /** - * Specifies if a user is disallowed from turning on location sharing. - * The default value is false. - *

    In a managed profile, location sharing always reflects the primary user's setting, but - * can be overridden and forced off by setting this restriction to true in the managed profile. - * - *

    Key for user restrictions. - *

    Type: Boolean - * @see #setUserRestrictions(Bundle) - * @see #getUserRestrictions() - */ - public static final String DISALLOW_SHARE_LOCATION = "no_share_location"; - - /** - * Specifies if a user is disallowed from enabling the - * "Unknown Sources" setting, that allows installation of apps from unknown sources. - * The default value is false. - * - *

    Key for user restrictions. - *

    Type: Boolean - * @see #setUserRestrictions(Bundle) - * @see #getUserRestrictions() - */ - public static final String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources"; - - /** - * Specifies if a user is disallowed from configuring bluetooth. - * The default value is false. - *

    This restriction has no effect in a managed profile. - * - *

    Key for user restrictions. - *

    Type: Boolean - * @see #setUserRestrictions(Bundle) - * @see #getUserRestrictions() - */ - public static final String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth"; - - /** - * Specifies if a user is disallowed from transferring files over - * USB. This can only be set by device owners and profile owners on the primary user. - * The default value is false. - * - *

    Key for user restrictions. - *

    Type: Boolean - * @see #setUserRestrictions(Bundle) - * @see #getUserRestrictions() - */ - public static final String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer"; - - /** - * Specifies if a user is disallowed from configuring user - * credentials. The default value is false. - * - *

    Key for user restrictions. - *

    Type: Boolean - * @see #setUserRestrictions(Bundle) - * @see #getUserRestrictions() - */ - public static final String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials"; - - /** - * When set on the primary user this specifies if the user can remove other users. - * When set on a secondary user, this specifies if the user can remove itself. - * This restriction has no effect on managed profiles. - * The default value is false. - * - *

    Key for user restrictions. - *

    Type: Boolean - * @see #setUserRestrictions(Bundle) - * @see #getUserRestrictions() - */ - public static final String DISALLOW_REMOVE_USER = "no_remove_user"; - - /** - * Specifies if a user is disallowed from enabling or - * accessing debugging features. The default value is false. - * - *

    Key for user restrictions. - *

    Type: Boolean - * @see #setUserRestrictions(Bundle) - * @see #getUserRestrictions() - */ - public static final String DISALLOW_DEBUGGING_FEATURES = "no_debugging_features"; - - /** - * Specifies if a user is disallowed from configuring VPN. - * The default value is false. - * This restriction has no effect in a managed profile. - * - *

    Key for user restrictions. - *

    Type: Boolean - * @see #setUserRestrictions(Bundle) - * @see #getUserRestrictions() - */ - public static final String DISALLOW_CONFIG_VPN = "no_config_vpn"; - - /** - * Specifies if a user is disallowed from configuring Tethering - * & portable hotspots. This can only be set by device owners and profile owners on the - * primary user. The default value is false. - * - *

    Key for user restrictions. - *

    Type: Boolean - * @see #setUserRestrictions(Bundle) - * @see #getUserRestrictions() - */ - public static final String DISALLOW_CONFIG_TETHERING = "no_config_tethering"; - - /** - * Specifies if a user is disallowed from factory resetting - * from Settings. This can only be set by device owners and profile owners on the primary user. - * The default value is false. - *

    This restriction has no effect on secondary users and managed profiles since only the - * primary user can factory reset the device. - * - *

    Key for user restrictions. - *

    Type: Boolean - * @see #setUserRestrictions(Bundle) - * @see #getUserRestrictions() - */ - public static final String DISALLOW_FACTORY_RESET = "no_factory_reset"; - - /** - * Specifies if a user is disallowed from adding new users and - * profiles. This can only be set by device owners and profile owners on the primary user. - * The default value is false. - *

    This restriction has no effect on secondary users and managed profiles since only the - * primary user can add other users. - * - *

    Key for user restrictions. - *

    Type: Boolean - * @see #setUserRestrictions(Bundle) - * @see #getUserRestrictions() - */ - public static final String DISALLOW_ADD_USER = "no_add_user"; - - /** - * Specifies if a user is disallowed from disabling application - * verification. The default value is false. - * - *

    Key for user restrictions. - *

    Type: Boolean - * @see #setUserRestrictions(Bundle) - * @see #getUserRestrictions() - */ - public static final String ENSURE_VERIFY_APPS = "ensure_verify_apps"; - - /** - * Specifies if a user is disallowed from configuring cell - * broadcasts. This can only be set by device owners and profile owners on the primary user. - * The default value is false. - *

    This restriction has no effect on secondary users and managed profiles since only the - * primary user can configure cell broadcasts. - * - *

    Key for user restrictions. - *

    Type: Boolean - * @see #setUserRestrictions(Bundle) - * @see #getUserRestrictions() - */ - public static final String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts"; - - /** - * Specifies if a user is disallowed from configuring mobile - * networks. This can only be set by device owners and profile owners on the primary user. - * The default value is false. - *

    This restriction has no effect on secondary users and managed profiles since only the - * primary user can configure mobile networks. - * - *

    Key for user restrictions. - *

    Type: Boolean - * @see #setUserRestrictions(Bundle) - * @see #getUserRestrictions() - */ - public static final String DISALLOW_CONFIG_MOBILE_NETWORKS = "no_config_mobile_networks"; - - /** - * Specifies if a user is disallowed from modifying - * applications in Settings or launchers. The following actions will not be allowed when this - * restriction is enabled: - *

  • uninstalling apps
  • - *
  • disabling apps
  • - *
  • clearing app caches
  • - *
  • clearing app data
  • - *
  • force stopping apps
  • - *
  • clearing app defaults
  • - *

    - * The default value is false. - * - *

    Key for user restrictions. - *

    Type: Boolean - * @see #setUserRestrictions(Bundle) - * @see #getUserRestrictions() - */ - public static final String DISALLOW_APPS_CONTROL = "no_control_apps"; - - /** - * Specifies if a user is disallowed from mounting - * physical external media. This can only be set by device owners and profile owners on the - * primary user. The default value is false. - * - *

    Key for user restrictions. - *

    Type: Boolean - * @see #setUserRestrictions(Bundle) - * @see #getUserRestrictions() - */ - public static final String DISALLOW_MOUNT_PHYSICAL_MEDIA = "no_physical_media"; - - /** - * Specifies if a user is disallowed from adjusting microphone - * volume. If set, the microphone will be muted. This can only be set by device owners - * and profile owners on the primary user. The default value is false. - * - *

    Key for user restrictions. - *

    Type: Boolean - * @see #setUserRestrictions(Bundle) - * @see #getUserRestrictions() - */ - public static final String DISALLOW_UNMUTE_MICROPHONE = "no_unmute_microphone"; - - /** - * Specifies if a user is disallowed from adjusting the master - * volume. If set, the master volume will be muted. This can only be set by device owners - * and profile owners on the primary user. The default value is false. - * - *

    Key for user restrictions. - *

    Type: Boolean - * @see #setUserRestrictions(Bundle) - * @see #getUserRestrictions() - */ - public static final String DISALLOW_ADJUST_VOLUME = "no_adjust_volume"; - - /** - * Specifies that the user is not allowed to make outgoing - * phone calls. Emergency calls are still permitted. - * The default value is false. - *

    This restriction has no effect on managed profiles since call intents are normally - * forwarded to the primary user. - * - *

    Key for user restrictions. - *

    Type: Boolean - * @see #setUserRestrictions(Bundle) - * @see #getUserRestrictions() - */ - public static final String DISALLOW_OUTGOING_CALLS = "no_outgoing_calls"; - - /** - * Specifies that the user is not allowed to send or receive - * SMS messages. The default value is false. - * - *

    Key for user restrictions. - *

    Type: Boolean - * @see #setUserRestrictions(Bundle) - * @see #getUserRestrictions() - */ - public static final String DISALLOW_SMS = "no_sms"; - - /** - * Specifies that windows besides app windows should not be - * created. This will block the creation of the following types of windows. - *

  • {@link LayoutParams#TYPE_TOAST}
  • - *
  • {@link LayoutParams#TYPE_PHONE}
  • - *
  • {@link LayoutParams#TYPE_PRIORITY_PHONE}
  • - *
  • {@link LayoutParams#TYPE_SYSTEM_ALERT}
  • - *
  • {@link LayoutParams#TYPE_SYSTEM_ERROR}
  • - *
  • {@link LayoutParams#TYPE_SYSTEM_OVERLAY}
  • - * - *

    This can only be set by device owners and profile owners on the primary user. - * The default value is false. - * - *

    Key for user restrictions. - *

    Type: Boolean - * @see #setUserRestrictions(Bundle) - * @see #getUserRestrictions() - */ - public static final String DISALLOW_CREATE_WINDOWS = "no_create_windows"; - - /** - * Specifies if what is copied in the clipboard of this profile can - * be pasted in related profiles. Does not restrict if the clipboard of related profiles can be - * pasted in this profile. - * The default value is false. - * - *

    Key for user restrictions. - *

    Type: Boolean - * @see #setUserRestrictions(Bundle) - * @see #getUserRestrictions() - */ - public static final String DISALLOW_CROSS_PROFILE_COPY_PASTE = "no_cross_profile_copy_paste"; - - /** - * Specifies if the user is not allowed to use NFC to beam out data from apps. - * The default value is false. - * - *

    Key for user restrictions. - *

    Type: Boolean - * @see #setUserRestrictions(Bundle) - * @see #getUserRestrictions() - */ - public static final String DISALLOW_OUTGOING_BEAM = "no_outgoing_beam"; - - /** - * Application restriction key that is used to indicate the pending arrival - * of real restrictions for the app. - * - *

    - * Applications that support restrictions should check for the presence of this key. - * A true value indicates that restrictions may be applied in the near - * future but are not available yet. It is the responsibility of any - * management application that sets this flag to update it when the final - * restrictions are enforced. - * - *

    Key for application restrictions. - *

    Type: Boolean - * @see android.app.admin.DevicePolicyManager#setApplicationRestrictions( - * android.content.ComponentName, String, Bundle) - * @see android.app.admin.DevicePolicyManager#getApplicationRestrictions( - * android.content.ComponentName, String) - */ - public static final String KEY_RESTRICTIONS_PENDING = "restrictions_pending"; - - /** @hide */ - public static final int PIN_VERIFICATION_FAILED_INCORRECT = -3; - /** @hide */ - public static final int PIN_VERIFICATION_FAILED_NOT_SET = -2; - /** @hide */ - public static final int PIN_VERIFICATION_SUCCESS = -1; - - private static UserManager sInstance = null; - - /** @hide */ - public synchronized static UserManager get(Context context) { - if (sInstance == null) { - sInstance = (UserManager) context.getSystemService(Context.USER_SERVICE); - } - return sInstance; - } - - /** @hide */ - public UserManager(Context context, IUserManager service) { - mService = service; - mContext = context; - } - - /** - * Returns whether the system supports multiple users. - * @return true if multiple users can be created by user, false if it is a single user device. - * @hide - */ - public static boolean supportsMultipleUsers() { - return getMaxSupportedUsers() > 1 - && SystemProperties.getBoolean("fw.show_multiuserui", - Resources.getSystem().getBoolean(R.bool.config_enableMultiUserUI)); - } - - /** - * Returns the user handle for the user that the calling process is running on. - * - * @return the user handle of the user making this call. - * @hide - */ - public int getUserHandle() { - return UserHandle.myUserId(); - } - - /** - * Returns the user name of the user making this call. This call is only - * available to applications on the system image; it requires the - * MANAGE_USERS permission. - * @return the user name - */ - public String getUserName() { - try { - return mService.getUserInfo(getUserHandle()).name; - } catch (RemoteException re) { - Log.w(TAG, "Could not get user name", re); - return ""; - } - } - - /** - * Used to determine whether the user making this call is subject to - * teleportations. - * - *

    As of {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this method can - * now automatically identify goats using advanced goat recognition technology.

    - * - * @return Returns true if the user making this call is a goat. - */ - public boolean isUserAGoat() { - return mContext.getPackageManager() - .isPackageAvailable("com.coffeestainstudios.goatsimulator"); - } - - /** - * Used to check if the user making this call is linked to another user. Linked users may have - * a reduced number of available apps, app restrictions and account restrictions. - * @return whether the user making this call is a linked user - * @hide - */ - public boolean isLinkedUser() { - try { - return mService.isRestricted(); - } catch (RemoteException re) { - Log.w(TAG, "Could not check if user is limited ", re); - return false; - } - } - - /** - * Checks if the calling app is running as a guest user. - * @return whether the caller is a guest user. - * @hide - */ - public boolean isGuestUser() { - UserInfo user = getUserInfo(UserHandle.myUserId()); - return user != null ? user.isGuest() : false; - } - - /** - * Checks if the calling app is running in a managed profile. - * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. - * - * @return whether the caller is in a managed profile. - * @hide - */ - @SystemApi - public boolean isManagedProfile() { - UserInfo user = getUserInfo(UserHandle.myUserId()); - return user != null ? user.isManagedProfile() : false; - } - - /** - * Return whether the given user is actively running. This means that - * the user is in the "started" state, not "stopped" -- it is currently - * allowed to run code through scheduled alarms, receiving broadcasts, - * etc. A started user may be either the current foreground user or a - * background user; the result here does not distinguish between the two. - * @param user The user to retrieve the running state for. - */ - public boolean isUserRunning(UserHandle user) { - try { - return ActivityManagerNative.getDefault().isUserRunning( - user.getIdentifier(), false); - } catch (RemoteException e) { - return false; - } - } - - /** - * Return whether the given user is actively running or stopping. - * This is like {@link #isUserRunning(UserHandle)}, but will also return - * true if the user had been running but is in the process of being stopped - * (but is not yet fully stopped, and still running some code). - * @param user The user to retrieve the running state for. - */ - public boolean isUserRunningOrStopping(UserHandle user) { - try { - return ActivityManagerNative.getDefault().isUserRunning( - user.getIdentifier(), true); - } catch (RemoteException e) { - return false; - } - } - - /** - * Returns the UserInfo object describing a specific user. - * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. - * @param userHandle the user handle of the user whose information is being requested. - * @return the UserInfo object for a specific user. - * @hide - */ - public UserInfo getUserInfo(int userHandle) { - try { - return mService.getUserInfo(userHandle); - } catch (RemoteException re) { - Log.w(TAG, "Could not get user info", re); - return null; - } - } - - /** - * Returns the user-wide restrictions imposed on this user. - * @return a Bundle containing all the restrictions. - */ - public Bundle getUserRestrictions() { - return getUserRestrictions(Process.myUserHandle()); - } - - /** - * Returns the user-wide restrictions imposed on the user specified by userHandle. - * @param userHandle the UserHandle of the user for whom to retrieve the restrictions. - * @return a Bundle containing all the restrictions. - */ - public Bundle getUserRestrictions(UserHandle userHandle) { - try { - return mService.getUserRestrictions(userHandle.getIdentifier()); - } catch (RemoteException re) { - Log.w(TAG, "Could not get user restrictions", re); - return Bundle.EMPTY; - } - } - - /** - * Sets all the user-wide restrictions for this user. - * Requires the MANAGE_USERS permission. - * @param restrictions the Bundle containing all the restrictions. - * @deprecated use {@link android.app.admin.DevicePolicyManager#addUserRestriction( - * android.content.ComponentName, String)} or - * {@link android.app.admin.DevicePolicyManager#clearUserRestriction( - * android.content.ComponentName, String)} instead. - */ - @Deprecated - public void setUserRestrictions(Bundle restrictions) { - setUserRestrictions(restrictions, Process.myUserHandle()); - } - - /** - * Sets all the user-wide restrictions for the specified user. - * Requires the MANAGE_USERS permission. - * @param restrictions the Bundle containing all the restrictions. - * @param userHandle the UserHandle of the user for whom to set the restrictions. - * @deprecated use {@link android.app.admin.DevicePolicyManager#addUserRestriction( - * android.content.ComponentName, String)} or - * {@link android.app.admin.DevicePolicyManager#clearUserRestriction( - * android.content.ComponentName, String)} instead. - */ - @Deprecated - public void setUserRestrictions(Bundle restrictions, UserHandle userHandle) { - try { - mService.setUserRestrictions(restrictions, userHandle.getIdentifier()); - } catch (RemoteException re) { - Log.w(TAG, "Could not set user restrictions", re); - } - } - - /** - * Sets the value of a specific restriction. - * Requires the MANAGE_USERS permission. - * @param key the key of the restriction - * @param value the value for the restriction - * @deprecated use {@link android.app.admin.DevicePolicyManager#addUserRestriction( - * android.content.ComponentName, String)} or - * {@link android.app.admin.DevicePolicyManager#clearUserRestriction( - * android.content.ComponentName, String)} instead. - */ - @Deprecated - public void setUserRestriction(String key, boolean value) { - Bundle bundle = getUserRestrictions(); - bundle.putBoolean(key, value); - setUserRestrictions(bundle); - } - - /** - * @hide - * Sets the value of a specific restriction on a specific user. - * Requires the MANAGE_USERS permission. - * @param key the key of the restriction - * @param value the value for the restriction - * @param userHandle the user whose restriction is to be changed. - * @deprecated use {@link android.app.admin.DevicePolicyManager#addUserRestriction( - * android.content.ComponentName, String)} or - * {@link android.app.admin.DevicePolicyManager#clearUserRestriction( - * android.content.ComponentName, String)} instead. - */ - @Deprecated - public void setUserRestriction(String key, boolean value, UserHandle userHandle) { - Bundle bundle = getUserRestrictions(userHandle); - bundle.putBoolean(key, value); - setUserRestrictions(bundle, userHandle); - } - - /** - * Returns whether the current user has been disallowed from performing certain actions - * or setting certain settings. - * - * @param restrictionKey The string key representing the restriction. - * @return {@code true} if the current user has the given restriction, {@code false} otherwise. - */ - public boolean hasUserRestriction(String restrictionKey) { - return hasUserRestriction(restrictionKey, Process.myUserHandle()); - } - - /** - * @hide - * Returns whether the given user has been disallowed from performing certain actions - * or setting certain settings. - * @param restrictionKey the string key representing the restriction - * @param userHandle the UserHandle of the user for whom to retrieve the restrictions. - */ - public boolean hasUserRestriction(String restrictionKey, UserHandle userHandle) { - try { - return mService.hasUserRestriction(restrictionKey, - userHandle.getIdentifier()); - } catch (RemoteException re) { - Log.w(TAG, "Could not check user restrictions", re); - return false; - } - } - - /** - * Return the serial number for a user. This is a device-unique - * number assigned to that user; if the user is deleted and then a new - * user created, the new users will not be given the same serial number. - * @param user The user whose serial number is to be retrieved. - * @return The serial number of the given user; returns -1 if the - * given UserHandle does not exist. - * @see #getUserForSerialNumber(long) - */ - public long getSerialNumberForUser(UserHandle user) { - return getUserSerialNumber(user.getIdentifier()); - } - - /** - * Return the user associated with a serial number previously - * returned by {@link #getSerialNumberForUser(UserHandle)}. - * @param serialNumber The serial number of the user that is being - * retrieved. - * @return Return the user associated with the serial number, or null - * if there is not one. - * @see #getSerialNumberForUser(UserHandle) - */ - public UserHandle getUserForSerialNumber(long serialNumber) { - int ident = getUserHandle((int)serialNumber); - return ident >= 0 ? new UserHandle(ident) : null; - } - - /** - * Creates a user with the specified name and options. - * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. - * - * @param name the user's name - * @param flags flags that identify the type of user and other properties. - * @see UserInfo - * - * @return the UserInfo object for the created user, or null if the user could not be created. - * @hide - */ - public UserInfo createUser(String name, int flags) { - try { - return mService.createUser(name, flags); - } catch (RemoteException re) { - Log.w(TAG, "Could not create a user", re); - return null; - } - } - - /** - * Creates a guest user and configures it. - * @param context an application context - * @param name the name to set for the user - * @hide - */ - public UserInfo createGuest(Context context, String name) { - UserInfo guest = createUser(name, UserInfo.FLAG_GUEST); - if (guest != null) { - Settings.Secure.putStringForUser(context.getContentResolver(), - Settings.Secure.SKIP_FIRST_USE_HINTS, "1", guest.id); - try { - Bundle guestRestrictions = mService.getDefaultGuestRestrictions(); - guestRestrictions.putBoolean(DISALLOW_SMS, true); - guestRestrictions.putBoolean(DISALLOW_INSTALL_UNKNOWN_SOURCES, true); - mService.setUserRestrictions(guestRestrictions, guest.id); - } catch (RemoteException re) { - Log.w(TAG, "Could not update guest restrictions"); - } - } - return guest; - } - - /** - * Creates a secondary user with the specified name and options and configures it with default - * restrictions. - * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. - * - * @param name the user's name - * @param flags flags that identify the type of user and other properties. - * @see UserInfo - * - * @return the UserInfo object for the created user, or null if the user could not be created. - * @hide - */ - public UserInfo createSecondaryUser(String name, int flags) { - try { - UserInfo user = mService.createUser(name, flags); - if (user == null) { - return null; - } - Bundle userRestrictions = mService.getUserRestrictions(user.id); - addDefaultUserRestrictions(userRestrictions); - mService.setUserRestrictions(userRestrictions, user.id); - return user; - } catch (RemoteException re) { - Log.w(TAG, "Could not create a user", re); - return null; - } - } - - private static void addDefaultUserRestrictions(Bundle restrictions) { - restrictions.putBoolean(DISALLOW_OUTGOING_CALLS, true); - restrictions.putBoolean(DISALLOW_SMS, true); - } - - /** - * Creates a user with the specified name and options as a profile of another user. - * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. - * - * @param name the user's name - * @param flags flags that identify the type of user and other properties. - * @see UserInfo - * @param userHandle new user will be a profile of this use. - * - * @return the UserInfo object for the created user, or null if the user could not be created. - * @hide - */ - public UserInfo createProfileForUser(String name, int flags, int userHandle) { - try { - return mService.createProfileForUser(name, flags, userHandle); - } catch (RemoteException re) { - Log.w(TAG, "Could not create a user", re); - return null; - } - } - - /** - * @hide - * Marks the guest user for deletion to allow a new guest to be created before deleting - * the current user who is a guest. - * @param userHandle - * @return - */ - public boolean markGuestForDeletion(int userHandle) { - try { - return mService.markGuestForDeletion(userHandle); - } catch (RemoteException re) { - Log.w(TAG, "Could not mark guest for deletion", re); - return false; - } - } - - /** - * Sets the user as enabled, if such an user exists. - * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. - * Note that the default is true, it's only that managed profiles might not be enabled. - * - * @param userHandle the id of the profile to enable - * @hide - */ - public void setUserEnabled(int userHandle) { - try { - mService.setUserEnabled(userHandle); - } catch (RemoteException e) { - Log.w(TAG, "Could not enable the profile", e); - } - } - - /** - * Return the number of users currently created on the device. - */ - public int getUserCount() { - List users = getUsers(); - return users != null ? users.size() : 1; - } - - /** - * Returns information for all users on this device. - * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. - * @return the list of users that were created. - * @hide - */ - public List getUsers() { - try { - return mService.getUsers(false); - } catch (RemoteException re) { - Log.w(TAG, "Could not get user list", re); - return null; - } - } - - /** - * Checks whether it's possible to add more users. Caller must hold the MANAGE_USERS - * permission. - * - * @return true if more users can be added, false if limit has been reached. - * @hide - */ - public boolean canAddMoreUsers() { - final List users = getUsers(true); - final int totalUserCount = users.size(); - int aliveUserCount = 0; - for (int i = 0; i < totalUserCount; i++) { - UserInfo user = users.get(i); - if (!user.isGuest()) { - aliveUserCount++; - } - } - return aliveUserCount < getMaxSupportedUsers(); - } - - /** - * Returns list of the profiles of userHandle including - * userHandle itself. - * Note that this returns both enabled and not enabled profiles. See - * {@link #getUserProfiles()} if you need only the enabled ones. - * - * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. - * @param userHandle profiles of this user will be returned. - * @return the list of profiles. - * @hide - */ - public List getProfiles(int userHandle) { - try { - return mService.getProfiles(userHandle, false /* enabledOnly */); - } catch (RemoteException re) { - Log.w(TAG, "Could not get user list", re); - return null; - } - } - - /** - * Returns a list of UserHandles for profiles associated with the user that the calling process - * is running on, including the user itself. - * - * @return A non-empty list of UserHandles associated with the calling user. - */ - public List getUserProfiles() { - ArrayList profiles = new ArrayList(); - List users = new ArrayList(); - try { - users = mService.getProfiles(UserHandle.myUserId(), true /* enabledOnly */); - } catch (RemoteException re) { - Log.w(TAG, "Could not get user list", re); - return null; - } - for (UserInfo info : users) { - UserHandle userHandle = new UserHandle(info.id); - profiles.add(userHandle); - } - return profiles; - } - - /** - * Returns the parent of the profile which this method is called from - * or null if called from a user that is not a profile. - * - * @hide - */ - public UserInfo getProfileParent(int userHandle) { - try { - return mService.getProfileParent(userHandle); - } catch (RemoteException re) { - Log.w(TAG, "Could not get profile parent", re); - return null; - } - } - - /** - * If the target user is a managed profile of the calling user or the caller - * is itself a managed profile, then this returns a badged copy of the given - * icon to be able to distinguish it from the original icon. For badging an - * arbitrary drawable use {@link #getBadgedDrawableForUser( - * android.graphics.drawable.Drawable, UserHandle, android.graphics.Rect, int)}. - *

    - * If the original drawable is a BitmapDrawable and the backing bitmap is - * mutable as per {@link android.graphics.Bitmap#isMutable()}, the bading - * is performed in place and the original drawable is returned. - *

    - * - * @param icon The icon to badge. - * @param user The target user. - * @return A drawable that combines the original icon and a badge as - * determined by the system. - * @removed - */ - public Drawable getBadgedIconForUser(Drawable icon, UserHandle user) { - return mContext.getPackageManager().getUserBadgedIcon(icon, user); - } - - /** - * If the target user is a managed profile of the calling user or the caller - * is itself a managed profile, then this returns a badged copy of the given - * drawable allowing the user to distinguish it from the original drawable. - * The caller can specify the location in the bounds of the drawable to be - * badged where the badge should be applied as well as the density of the - * badge to be used. - *

    - * If the original drawable is a BitmapDrawable and the backing bitmap is - * mutable as per {@link android.graphics.Bitmap#isMutable()}, the bading - * is performed in place and the original drawable is returned. - *

    - * - * @param badgedDrawable The drawable to badge. - * @param user The target user. - * @param badgeLocation Where in the bounds of the badged drawable to place - * the badge. If not provided, the badge is applied on top of the entire - * drawable being badged. - * @param badgeDensity The optional desired density for the badge as per - * {@link android.util.DisplayMetrics#densityDpi}. If not provided, - * the density of the display is used. - * @return A drawable that combines the original drawable and a badge as - * determined by the system. - * @removed - */ - public Drawable getBadgedDrawableForUser(Drawable badgedDrawable, UserHandle user, - Rect badgeLocation, int badgeDensity) { - return mContext.getPackageManager().getUserBadgedDrawableForDensity(badgedDrawable, user, - badgeLocation, badgeDensity); - } - - /** - * If the target user is a managed profile of the calling user or the caller - * is itself a managed profile, then this returns a copy of the label with - * badging for accessibility services like talkback. E.g. passing in "Email" - * and it might return "Work Email" for Email in the work profile. - * - * @param label The label to change. - * @param user The target user. - * @return A label that combines the original label and a badge as - * determined by the system. - * @removed - */ - public CharSequence getBadgedLabelForUser(CharSequence label, UserHandle user) { - return mContext.getPackageManager().getUserBadgedLabel(label, user); - } - - /** - * Returns information for all users on this device. Requires - * {@link android.Manifest.permission#MANAGE_USERS} permission. - * - * @param excludeDying specify if the list should exclude users being - * removed. - * @return the list of users that were created. - * @hide - */ - public List getUsers(boolean excludeDying) { - try { - return mService.getUsers(excludeDying); - } catch (RemoteException re) { - Log.w(TAG, "Could not get user list", re); - return null; - } - } - - /** - * Removes a user and all associated data. - * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. - * @param userHandle the integer handle of the user, where 0 is the primary user. - * @hide - */ - public boolean removeUser(int userHandle) { - try { - return mService.removeUser(userHandle); - } catch (RemoteException re) { - Log.w(TAG, "Could not remove user ", re); - return false; - } - } - - /** - * Updates the user's name. - * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. - * - * @param userHandle the user's integer handle - * @param name the new name for the user - * @hide - */ - public void setUserName(int userHandle, String name) { - try { - mService.setUserName(userHandle, name); - } catch (RemoteException re) { - Log.w(TAG, "Could not set the user name ", re); - } - } - - /** - * Sets the user's photo. - * @param userHandle the user for whom to change the photo. - * @param icon the bitmap to set as the photo. - * @hide - */ - public void setUserIcon(int userHandle, Bitmap icon) { - try { - mService.setUserIcon(userHandle, icon); - } catch (RemoteException re) { - Log.w(TAG, "Could not set the user icon ", re); - } - } - - /** - * Returns a file descriptor for the user's photo. PNG data can be read from this file. - * @param userHandle the user whose photo we want to read. - * @return a {@link Bitmap} of the user's photo, or null if there's no photo. - * @see com.android.internal.util.UserIcons#getDefaultUserIcon for a default. - * @hide - */ - public Bitmap getUserIcon(int userHandle) { - try { - return mService.getUserIcon(userHandle); - } catch (RemoteException re) { - Log.w(TAG, "Could not get the user icon ", re); - return null; - } - } - - /** - * Returns the maximum number of users that can be created on this device. A return value - * of 1 means that it is a single user device. - * @hide - * @return a value greater than or equal to 1 - */ - public static int getMaxSupportedUsers() { - // Don't allow multiple users on certain builds - if (android.os.Build.ID.startsWith("JVP")) return 1; - // Svelte devices don't get multi-user. - if (ActivityManager.isLowRamDeviceStatic()) return 1; - return SystemProperties.getInt("fw.max_users", - Resources.getSystem().getInteger(R.integer.config_multiuserMaximumUsers)); - } - - /** - * Returns true if the user switcher should be shown, this will be if there - * are multiple users that aren't managed profiles. - * @hide - * @return true if user switcher should be shown. - */ - public boolean isUserSwitcherEnabled() { - List users = getUsers(true); - if (users == null) { - return false; - } - int switchableUserCount = 0; - for (UserInfo user : users) { - if (user.supportsSwitchTo()) { - ++switchableUserCount; - } - } - final boolean guestEnabled = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.GUEST_USER_ENABLED, 0) == 1; - return switchableUserCount > 1 || guestEnabled; - } - - /** - * Returns a serial number on this device for a given userHandle. User handles can be recycled - * when deleting and creating users, but serial numbers are not reused until the device is wiped. - * @param userHandle - * @return a serial number associated with that user, or -1 if the userHandle is not valid. - * @hide - */ - public int getUserSerialNumber(int userHandle) { - try { - return mService.getUserSerialNumber(userHandle); - } catch (RemoteException re) { - Log.w(TAG, "Could not get serial number for user " + userHandle); - } - return -1; - } - - /** - * Returns a userHandle on this device for a given user serial number. User handles can be - * recycled when deleting and creating users, but serial numbers are not reused until the device - * is wiped. - * @param userSerialNumber - * @return the userHandle associated with that user serial number, or -1 if the serial number - * is not valid. - * @hide - */ - public int getUserHandle(int userSerialNumber) { - try { - return mService.getUserHandle(userSerialNumber); - } catch (RemoteException re) { - Log.w(TAG, "Could not get userHandle for user " + userSerialNumber); - } - return -1; - } - - /** - * Returns a Bundle containing any saved application restrictions for this user, for the - * given package name. Only an application with this package name can call this method. - * @param packageName the package name of the calling application - * @return a Bundle with the restrictions as key/value pairs, or null if there are no - * saved restrictions. The values can be of type Boolean, String or String[], depending - * on the restriction type, as defined by the application. - */ - public Bundle getApplicationRestrictions(String packageName) { - try { - return mService.getApplicationRestrictions(packageName); - } catch (RemoteException re) { - Log.w(TAG, "Could not get application restrictions for package " + packageName); - } - return null; - } - - /** - * @hide - */ - public Bundle getApplicationRestrictions(String packageName, UserHandle user) { - try { - return mService.getApplicationRestrictionsForUser(packageName, user.getIdentifier()); - } catch (RemoteException re) { - Log.w(TAG, "Could not get application restrictions for user " + user.getIdentifier()); - } - return null; - } - - /** - * @hide - */ - public void setApplicationRestrictions(String packageName, Bundle restrictions, - UserHandle user) { - try { - mService.setApplicationRestrictions(packageName, restrictions, user.getIdentifier()); - } catch (RemoteException re) { - Log.w(TAG, "Could not set application restrictions for user " + user.getIdentifier()); - } - } - - /** - * Sets a new challenge PIN for restrictions. This is only for use by pre-installed - * apps and requires the MANAGE_USERS permission. - * @param newPin the PIN to use for challenge dialogs. - * @return Returns true if the challenge PIN was set successfully. - */ - public boolean setRestrictionsChallenge(String newPin) { - try { - return mService.setRestrictionsChallenge(newPin); - } catch (RemoteException re) { - Log.w(TAG, "Could not change restrictions pin"); - } - return false; - } - - /** - * @hide - * @param pin The PIN to verify, or null to get the number of milliseconds to wait for before - * allowing the user to enter the PIN. - * @return Returns a positive number (including zero) for how many milliseconds before - * you can accept another PIN, when the input is null or the input doesn't match the saved PIN. - * Returns {@link #PIN_VERIFICATION_SUCCESS} if the input matches the saved PIN. Returns - * {@link #PIN_VERIFICATION_FAILED_NOT_SET} if there is no PIN set. - */ - public int checkRestrictionsChallenge(String pin) { - try { - return mService.checkRestrictionsChallenge(pin); - } catch (RemoteException re) { - Log.w(TAG, "Could not check restrictions pin"); - } - return PIN_VERIFICATION_FAILED_INCORRECT; - } - - /** - * @hide - * Checks whether the user has restrictions that are PIN-protected. An application that - * participates in restrictions can check if the owner has requested a PIN challenge for - * any restricted operations. If there is a PIN in effect, the application should launch - * the PIN challenge activity {@link android.content.Intent#ACTION_RESTRICTIONS_CHALLENGE}. - * @see android.content.Intent#ACTION_RESTRICTIONS_CHALLENGE - * @return whether a restrictions PIN is in effect. - */ - public boolean hasRestrictionsChallenge() { - try { - return mService.hasRestrictionsChallenge(); - } catch (RemoteException re) { - Log.w(TAG, "Could not change restrictions pin"); - } - return false; - } - - /** @hide */ - public void removeRestrictions() { - try { - mService.removeRestrictions(); - } catch (RemoteException re) { - Log.w(TAG, "Could not change restrictions pin"); - } - } - - /** - * @hide - * Set restrictions that should apply to any future guest user that's created. - */ - public void setDefaultGuestRestrictions(Bundle restrictions) { - try { - mService.setDefaultGuestRestrictions(restrictions); - } catch (RemoteException re) { - Log.w(TAG, "Could not set guest restrictions"); - } - } - - /** - * @hide - * Gets the default guest restrictions. - */ - public Bundle getDefaultGuestRestrictions() { - try { - return mService.getDefaultGuestRestrictions(); - } catch (RemoteException re) { - Log.w(TAG, "Could not set guest restrictions"); - } - return new Bundle(); - } -} diff --git a/src/main/java/android/os/Vibrator.java b/src/main/java/android/os/Vibrator.java deleted file mode 100644 index f9b7666..0000000 --- a/src/main/java/android/os/Vibrator.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.app.ActivityThread; -import android.content.Context; -import android.media.AudioAttributes; - -/** - * Class that operates the vibrator on the device. - *

    - * If your process exits, any vibration you started will stop. - *

    - * - * To obtain an instance of the system vibrator, call - * {@link Context#getSystemService} with {@link Context#VIBRATOR_SERVICE} as the argument. - */ -public abstract class Vibrator { - - private final String mPackageName; - - /** - * @hide to prevent subclassing from outside of the framework - */ - public Vibrator() { - mPackageName = ActivityThread.currentPackageName(); - } - - /** - * @hide to prevent subclassing from outside of the framework - */ - protected Vibrator(Context context) { - mPackageName = context.getOpPackageName(); - } - - /** - * Check whether the hardware has a vibrator. - * - * @return True if the hardware has a vibrator, else false. - */ - public abstract boolean hasVibrator(); - - /** - * Vibrate constantly for the specified period of time. - *

    This method requires the caller to hold the permission - * {@link android.Manifest.permission#VIBRATE}. - * - * @param milliseconds The number of milliseconds to vibrate. - */ - public void vibrate(long milliseconds) { - vibrate(milliseconds, null); - } - - /** - * Vibrate constantly for the specified period of time. - *

    This method requires the caller to hold the permission - * {@link android.Manifest.permission#VIBRATE}. - * - * @param milliseconds The number of milliseconds to vibrate. - * @param attributes {@link AudioAttributes} corresponding to the vibration. For example, - * specify {@link AudioAttributes#USAGE_ALARM} for alarm vibrations or - * {@link AudioAttributes#USAGE_NOTIFICATION_RINGTONE} for - * vibrations associated with incoming calls. - */ - public void vibrate(long milliseconds, AudioAttributes attributes) { - vibrate(Process.myUid(), mPackageName, milliseconds, attributes); - } - - /** - * Vibrate with a given pattern. - * - *

    - * Pass in an array of ints that are the durations for which to turn on or off - * the vibrator in milliseconds. The first value indicates the number of milliseconds - * to wait before turning the vibrator on. The next value indicates the number of milliseconds - * for which to keep the vibrator on before turning it off. Subsequent values alternate - * between durations in milliseconds to turn the vibrator off or to turn the vibrator on. - *

    - * To cause the pattern to repeat, pass the index into the pattern array at which - * to start the repeat, or -1 to disable repeating. - *

    - *

    This method requires the caller to hold the permission - * {@link android.Manifest.permission#VIBRATE}. - * - * @param pattern an array of longs of times for which to turn the vibrator on or off. - * @param repeat the index into pattern at which to repeat, or -1 if - * you don't want to repeat. - */ - public void vibrate(long[] pattern, int repeat) { - vibrate(pattern, repeat, null); - } - - /** - * Vibrate with a given pattern. - * - *

    - * Pass in an array of ints that are the durations for which to turn on or off - * the vibrator in milliseconds. The first value indicates the number of milliseconds - * to wait before turning the vibrator on. The next value indicates the number of milliseconds - * for which to keep the vibrator on before turning it off. Subsequent values alternate - * between durations in milliseconds to turn the vibrator off or to turn the vibrator on. - *

    - * To cause the pattern to repeat, pass the index into the pattern array at which - * to start the repeat, or -1 to disable repeating. - *

    - *

    This method requires the caller to hold the permission - * {@link android.Manifest.permission#VIBRATE}. - * - * @param pattern an array of longs of times for which to turn the vibrator on or off. - * @param repeat the index into pattern at which to repeat, or -1 if - * you don't want to repeat. - * @param attributes {@link AudioAttributes} corresponding to the vibration. For example, - * specify {@link AudioAttributes#USAGE_ALARM} for alarm vibrations or - * {@link AudioAttributes#USAGE_NOTIFICATION_RINGTONE} for - * vibrations associated with incoming calls. - */ - public void vibrate(long[] pattern, int repeat, AudioAttributes attributes) { - vibrate(Process.myUid(), mPackageName, pattern, repeat, attributes); - } - - /** - * @hide - * Like {@link #vibrate(long, AudioAttributes)}, but allowing the caller to specify that - * the vibration is owned by someone else. - */ - public abstract void vibrate(int uid, String opPkg, long milliseconds, - AudioAttributes attributes); - - /** - * @hide - * Like {@link #vibrate(long[], int, AudioAttributes)}, but allowing the caller to specify that - * the vibration is owned by someone else. - */ - public abstract void vibrate(int uid, String opPkg, long[] pattern, int repeat, - AudioAttributes attributes); - - /** - * Turn the vibrator off. - *

    This method requires the caller to hold the permission - * {@link android.Manifest.permission#VIBRATE}. - */ - public abstract void cancel(); -} diff --git a/src/main/java/android/os/WorkSource.java b/src/main/java/android/os/WorkSource.java deleted file mode 100644 index f8da87a..0000000 --- a/src/main/java/android/os/WorkSource.java +++ /dev/null @@ -1,704 +0,0 @@ -package android.os; - -import android.util.Log; - -import java.util.Arrays; - -/** - * Describes the source of some work that may be done by someone else. - * Currently the public representation of what a work source is is not - * defined; this is an opaque container. - */ -public class WorkSource implements Parcelable { - static final String TAG = "WorkSource"; - static final boolean DEBUG = false; - - int mNum; - int[] mUids; - String[] mNames; - - /** - * Internal statics to avoid object allocations in some operations. - * The WorkSource object itself is not thread safe, but we need to - * hold sTmpWorkSource lock while working with these statics. - */ - static final WorkSource sTmpWorkSource = new WorkSource(0); - /** - * For returning newbie work from a modification operation. - */ - static WorkSource sNewbWork; - /** - * For returning gone work form a modification operation. - */ - static WorkSource sGoneWork; - - /** - * Create an empty work source. - */ - public WorkSource() { - mNum = 0; - } - - /** - * Create a new WorkSource that is a copy of an existing one. - * If orig is null, an empty WorkSource is created. - */ - public WorkSource(WorkSource orig) { - if (orig == null) { - mNum = 0; - return; - } - mNum = orig.mNum; - if (orig.mUids != null) { - mUids = orig.mUids.clone(); - mNames = orig.mNames != null ? orig.mNames.clone() : null; - } else { - mUids = null; - mNames = null; - } - } - - /** @hide */ - public WorkSource(int uid) { - mNum = 1; - mUids = new int[] { uid, 0 }; - mNames = null; - } - - /** @hide */ - public WorkSource(int uid, String name) { - if (name == null) { - throw new NullPointerException("Name can't be null"); - } - mNum = 1; - mUids = new int[] { uid, 0 }; - mNames = new String[] { name, null }; - } - - WorkSource(Parcel in) { - mNum = in.readInt(); - mUids = in.createIntArray(); - mNames = in.createStringArray(); - } - - /** @hide */ - public int size() { - return mNum; - } - - /** @hide */ - public int get(int index) { - return mUids[index]; - } - - /** @hide */ - public String getName(int index) { - return mNames != null ? mNames[index] : null; - } - - /** - * Clear names from this WorkSource. Uids are left intact. - * - *

    Useful when combining with another WorkSource that doesn't have names. - * @hide - */ - public void clearNames() { - if (mNames != null) { - mNames = null; - // Clear out any duplicate uids now that we don't have names to disambiguate them. - int destIndex = 1; - int newNum = mNum; - for (int sourceIndex = 1; sourceIndex < mNum; sourceIndex++) { - if (mUids[sourceIndex] == mUids[sourceIndex - 1]) { - newNum--; - } else { - mUids[destIndex] = mUids[sourceIndex]; - destIndex++; - } - } - mNum = newNum; - } - } - - /** - * Clear this WorkSource to be empty. - */ - public void clear() { - mNum = 0; - } - - @Override - public boolean equals(Object o) { - return o instanceof WorkSource && !diff((WorkSource)o); - } - - @Override - public int hashCode() { - int result = 0; - for (int i = 0; i < mNum; i++) { - result = ((result << 4) | (result >>> 28)) ^ mUids[i]; - } - if (mNames != null) { - for (int i = 0; i < mNum; i++) { - result = ((result << 4) | (result >>> 28)) ^ mNames[i].hashCode(); - } - } - return result; - } - - /** - * Compare this WorkSource with another. - * @param other The WorkSource to compare against. - * @return If there is a difference, true is returned. - */ - public boolean diff(WorkSource other) { - int N = mNum; - if (N != other.mNum) { - return true; - } - final int[] uids1 = mUids; - final int[] uids2 = other.mUids; - final String[] names1 = mNames; - final String[] names2 = other.mNames; - for (int i=0; iother is null, the current work source - * will be made empty. - */ - public void set(WorkSource other) { - if (other == null) { - mNum = 0; - return; - } - mNum = other.mNum; - if (other.mUids != null) { - if (mUids != null && mUids.length >= mNum) { - System.arraycopy(other.mUids, 0, mUids, 0, mNum); - } else { - mUids = other.mUids.clone(); - } - if (other.mNames != null) { - if (mNames != null && mNames.length >= mNum) { - System.arraycopy(other.mNames, 0, mNames, 0, mNum); - } else { - mNames = other.mNames.clone(); - } - } else { - mNames = null; - } - } else { - mUids = null; - mNames = null; - } - } - - /** @hide */ - public void set(int uid) { - mNum = 1; - if (mUids == null) mUids = new int[2]; - mUids[0] = uid; - mNames = null; - } - - /** @hide */ - public void set(int uid, String name) { - if (name == null) { - throw new NullPointerException("Name can't be null"); - } - mNum = 1; - if (mUids == null) { - mUids = new int[2]; - mNames = new String[2]; - } - mUids[0] = uid; - mNames[0] = name; - } - - /** @hide */ - public WorkSource[] setReturningDiffs(WorkSource other) { - synchronized (sTmpWorkSource) { - sNewbWork = null; - sGoneWork = null; - updateLocked(other, true, true); - if (sNewbWork != null || sGoneWork != null) { - WorkSource[] diffs = new WorkSource[2]; - diffs[0] = sNewbWork; - diffs[1] = sGoneWork; - return diffs; - } - return null; - } - } - - /** - * Merge the contents of other WorkSource in to this one. - * - * @param other The other WorkSource whose contents are to be merged. - * @return Returns true if any new sources were added. - */ - public boolean add(WorkSource other) { - synchronized (sTmpWorkSource) { - return updateLocked(other, false, false); - } - } - - /** @hide */ - public WorkSource addReturningNewbs(WorkSource other) { - synchronized (sTmpWorkSource) { - sNewbWork = null; - updateLocked(other, false, true); - return sNewbWork; - } - } - - /** @hide */ - public boolean add(int uid) { - if (mNum <= 0) { - mNames = null; - insert(0, uid); - return true; - } - if (mNames != null) { - throw new IllegalArgumentException("Adding without name to named " + this); - } - int i = Arrays.binarySearch(mUids, 0, mNum, uid); - if (DEBUG) Log.d(TAG, "Adding uid " + uid + " to " + this + ": binsearch res = " + i); - if (i >= 0) { - return false; - } - insert(-i-1, uid); - return true; - } - - /** @hide */ - public boolean add(int uid, String name) { - if (mNum <= 0) { - insert(0, uid, name); - return true; - } - if (mNames == null) { - throw new IllegalArgumentException("Adding name to unnamed " + this); - } - int i; - for (i=0; i uid) { - break; - } - if (mUids[i] == uid) { - int diff = mNames[i].compareTo(name); - if (diff > 0) { - break; - } - if (diff == 0) { - return false; - } - } - } - insert(i, uid, name); - return true; - } - - /** @hide */ - public WorkSource addReturningNewbs(int uid) { - synchronized (sTmpWorkSource) { - sNewbWork = null; - sTmpWorkSource.mUids[0] = uid; - updateLocked(sTmpWorkSource, false, true); - return sNewbWork; - } - } - - public boolean remove(WorkSource other) { - if (mNum <= 0 || other.mNum <= 0) { - return false; - } - if (mNames == null && other.mNames == null) { - return removeUids(other); - } else { - if (mNames == null) { - throw new IllegalArgumentException("Other " + other + " has names, but target " - + this + " does not"); - } - if (other.mNames == null) { - throw new IllegalArgumentException("Target " + this + " has names, but other " - + other + " does not"); - } - return removeUidsAndNames(other); - } - } - - /** @hide */ - public WorkSource stripNames() { - if (mNum <= 0) { - return new WorkSource(); - } - WorkSource result = new WorkSource(); - int lastUid = -1; - for (int i=0; i uids1[i1]) { - if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + " N1=" + N1 + ": skip i1"); - i1++; - } else { - if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + " N1=" + N1 + ": skip i2"); - i2++; - } - } - - mNum = N1; - - return changed; - } - - private boolean removeUidsAndNames(WorkSource other) { - int N1 = mNum; - final int[] uids1 = mUids; - final String[] names1 = mNames; - final int N2 = other.mNum; - final int[] uids2 = other.mUids; - final String[] names2 = other.mNames; - boolean changed = false; - int i1 = 0, i2 = 0; - if (DEBUG) Log.d(TAG, "Remove " + other + " from " + this); - while (i1 < N1 && i2 < N2) { - if (DEBUG) Log.d(TAG, "Step: target @ " + i1 + " of " + N1 + ", other @ " + i2 - + " of " + N2 + ": " + uids1[i1] + " " + names1[i1]); - if (uids2[i2] == uids1[i1] && names2[i2].equals(names1[i1])) { - if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + " N1=" + N1 - + ": remove " + uids1[i1] + " " + names1[i1]); - N1--; - changed = true; - if (i1 < N1) { - System.arraycopy(uids1, i1+1, uids1, i1, N1-i1); - System.arraycopy(names1, i1+1, names1, i1, N1-i1); - } - i2++; - } else if (uids2[i2] > uids1[i1] - || (uids2[i2] == uids1[i1] && names2[i2].compareTo(names1[i1]) > 0)) { - if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + " N1=" + N1 + ": skip i1"); - i1++; - } else { - if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + " N1=" + N1 + ": skip i2"); - i2++; - } - } - - mNum = N1; - - return changed; - } - - private boolean updateLocked(WorkSource other, boolean set, boolean returnNewbs) { - if (mNames == null && other.mNames == null) { - return updateUidsLocked(other, set, returnNewbs); - } else { - if (mNum > 0 && mNames == null) { - throw new IllegalArgumentException("Other " + other + " has names, but target " - + this + " does not"); - } - if (other.mNum > 0 && other.mNames == null) { - throw new IllegalArgumentException("Target " + this + " has names, but other " - + other + " does not"); - } - return updateUidsAndNamesLocked(other, set, returnNewbs); - } - } - - private static WorkSource addWork(WorkSource cur, int newUid) { - if (cur == null) { - return new WorkSource(newUid); - } - cur.insert(cur.mNum, newUid); - return cur; - } - - private boolean updateUidsLocked(WorkSource other, boolean set, boolean returnNewbs) { - int N1 = mNum; - int[] uids1 = mUids; - final int N2 = other.mNum; - final int[] uids2 = other.mUids; - boolean changed = false; - int i1 = 0, i2 = 0; - if (DEBUG) Log.d(TAG, "Update " + this + " with " + other + " set=" + set - + " returnNewbs=" + returnNewbs); - while (i1 < N1 || i2 < N2) { - if (DEBUG) Log.d(TAG, "Step: target @ " + i1 + " of " + N1 + ", other @ " + i2 - + " of " + N2); - if (i1 >= N1 || (i2 < N2 && uids2[i2] < uids1[i1])) { - // Need to insert a new uid. - if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + " N1=" + N1 - + ": insert " + uids2[i2]); - changed = true; - if (uids1 == null) { - uids1 = new int[4]; - uids1[0] = uids2[i2]; - } else if (N1 >= uids1.length) { - int[] newuids = new int[(uids1.length*3)/2]; - if (i1 > 0) System.arraycopy(uids1, 0, newuids, 0, i1); - if (i1 < N1) System.arraycopy(uids1, i1, newuids, i1+1, N1-i1); - uids1 = newuids; - uids1[i1] = uids2[i2]; - } else { - if (i1 < N1) System.arraycopy(uids1, i1, uids1, i1+1, N1-i1); - uids1[i1] = uids2[i2]; - } - if (returnNewbs) { - sNewbWork = addWork(sNewbWork, uids2[i2]); - } - N1++; - i1++; - i2++; - } else { - if (!set) { - // Skip uids that already exist or are not in 'other'. - if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + " N1=" + N1 + ": skip"); - if (i2 < N2 && uids2[i2] == uids1[i1]) { - i2++; - } - i1++; - } else { - // Remove any uids that don't exist in 'other'. - int start = i1; - while (i1 < N1 && (i2 >= N2 || uids2[i2] > uids1[i1])) { - if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + ": remove " + uids1[i1]); - sGoneWork = addWork(sGoneWork, uids1[i1]); - i1++; - } - if (start < i1) { - System.arraycopy(uids1, i1, uids1, start, N1-i1); - N1 -= i1-start; - i1 = start; - } - // If there is a matching uid, skip it. - if (i1 < N1 && i2 < N2 && uids2[i2] == uids1[i1]) { - if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + " N1=" + N1 + ": skip"); - i1++; - i2++; - } - } - } - } - - mNum = N1; - mUids = uids1; - - return changed; - } - - /** - * Returns 0 if equal, negative if 'this' is before 'other', positive if 'this' is after 'other'. - */ - private int compare(WorkSource other, int i1, int i2) { - final int diff = mUids[i1] - other.mUids[i2]; - if (diff != 0) { - return diff; - } - return mNames[i1].compareTo(other.mNames[i2]); - } - - private static WorkSource addWork(WorkSource cur, int newUid, String newName) { - if (cur == null) { - return new WorkSource(newUid, newName); - } - cur.insert(cur.mNum, newUid, newName); - return cur; - } - - private boolean updateUidsAndNamesLocked(WorkSource other, boolean set, boolean returnNewbs) { - final int N2 = other.mNum; - final int[] uids2 = other.mUids; - String[] names2 = other.mNames; - boolean changed = false; - int i1 = 0, i2 = 0; - if (DEBUG) Log.d(TAG, "Update " + this + " with " + other + " set=" + set - + " returnNewbs=" + returnNewbs); - while (i1 < mNum || i2 < N2) { - if (DEBUG) Log.d(TAG, "Step: target @ " + i1 + " of " + mNum + ", other @ " + i2 - + " of " + N2); - int diff = -1; - if (i1 >= mNum || (i2 < N2 && (diff=compare(other, i1, i2)) > 0)) { - // Need to insert a new uid. - changed = true; - if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + " N1=" + mNum - + ": insert " + uids2[i2] + " " + names2[i2]); - insert(i1, uids2[i2], names2[i2]); - if (returnNewbs) { - sNewbWork = addWork(sNewbWork, uids2[i2], names2[i2]); - } - i1++; - i2++; - } else { - if (!set) { - if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + " N1=" + mNum + ": skip"); - if (i2 < N2 && diff == 0) { - i2++; - } - i1++; - } else { - // Remove any uids that don't exist in 'other'. - int start = i1; - while (diff < 0) { - if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + ": remove " + mUids[i1] - + " " + mNames[i1]); - sGoneWork = addWork(sGoneWork, mUids[i1], mNames[i1]); - i1++; - if (i1 >= mNum) { - break; - } - diff = i2 < N2 ? compare(other, i1, i2) : -1; - } - if (start < i1) { - System.arraycopy(mUids, i1, mUids, start, mNum-i1); - System.arraycopy(mNames, i1, mNames, start, mNum-i1); - mNum -= i1-start; - i1 = start; - } - // If there is a matching uid, skip it. - if (i1 < mNum && diff == 0) { - if (DEBUG) Log.d(TAG, "i1=" + i1 + " i2=" + i2 + " N1=" + mNum + ": skip"); - i1++; - i2++; - } - } - } - } - - return changed; - } - - private void insert(int index, int uid) { - if (DEBUG) Log.d(TAG, "Insert in " + this + " @ " + index + " uid " + uid); - if (mUids == null) { - mUids = new int[4]; - mUids[0] = uid; - mNum = 1; - } else if (mNum >= mUids.length) { - int[] newuids = new int[(mNum*3)/2]; - if (index > 0) { - System.arraycopy(mUids, 0, newuids, 0, index); - } - if (index < mNum) { - System.arraycopy(mUids, index, newuids, index+1, mNum-index); - } - mUids = newuids; - mUids[index] = uid; - mNum++; - } else { - if (index < mNum) { - System.arraycopy(mUids, index, mUids, index+1, mNum-index); - } - mUids[index] = uid; - mNum++; - } - } - - private void insert(int index, int uid, String name) { - if (mUids == null) { - mUids = new int[4]; - mUids[0] = uid; - mNames = new String[4]; - mNames[0] = name; - mNum = 1; - } else if (mNum >= mUids.length) { - int[] newuids = new int[(mNum*3)/2]; - String[] newnames = new String[(mNum*3)/2]; - if (index > 0) { - System.arraycopy(mUids, 0, newuids, 0, index); - System.arraycopy(mNames, 0, newnames, 0, index); - } - if (index < mNum) { - System.arraycopy(mUids, index, newuids, index+1, mNum-index); - System.arraycopy(mNames, index, newnames, index+1, mNum-index); - } - mUids = newuids; - mNames = newnames; - mUids[index] = uid; - mNames[index] = name; - mNum++; - } else { - if (index < mNum) { - System.arraycopy(mUids, index, mUids, index+1, mNum-index); - System.arraycopy(mNames, index, mNames, index+1, mNum-index); - } - mUids[index] = uid; - mNames[index] = name; - mNum++; - } - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mNum); - dest.writeIntArray(mUids); - dest.writeStringArray(mNames); - } - - @Override - public String toString() { - StringBuilder result = new StringBuilder(); - result.append("WorkSource{"); - for (int i = 0; i < mNum; i++) { - if (i != 0) { - result.append(", "); - } - result.append(mUids[i]); - if (mNames != null) { - result.append(" "); - result.append(mNames[i]); - } - } - result.append("}"); - return result.toString(); - } - - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - public WorkSource createFromParcel(Parcel in) { - return new WorkSource(in); - } - public WorkSource[] newArray(int size) { - return new WorkSource[size]; - } - }; -} diff --git a/src/main/java/android/os/storage/AsecTests.java b/src/main/java/android/os/storage/AsecTests.java deleted file mode 100644 index 4f724fe..0000000 --- a/src/main/java/android/os/storage/AsecTests.java +++ /dev/null @@ -1,756 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os.storage; - -import android.content.Context; -import android.os.Environment; -import android.os.IBinder; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.test.AndroidTestCase; -import android.util.Log; - -import java.io.File; -import java.io.FileOutputStream; - -public class AsecTests extends AndroidTestCase { - private static final String SECURE_CONTAINER_PREFIX = "com.android.unittests.AsecTests."; - private static final boolean localLOGV = true; - public static final String TAG="AsecTests"; - - private static final String FS_FAT = "fat"; - private static final String FS_EXT4 = "ext4"; - - @Override - protected void setUp() throws Exception { - super.setUp(); - if (localLOGV) Log.i(TAG, "Cleaning out old test containers"); - cleanupContainers(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - if (localLOGV) Log.i(TAG, "Cleaning out old test containers"); - cleanupContainers(); - } - - private void cleanupContainers() throws RemoteException { - IMountService ms = getMs(); - String[] containers = ms.getSecureContainerList(); - - for (int i = 0; i < containers.length; i++) { - if (containers[i].startsWith(SECURE_CONTAINER_PREFIX)) { - if (localLOGV) - Log.i(TAG, "Cleaning: " + containers[i]); - ms.destroySecureContainer(containers[i], true); - } - } - } - - private boolean containerExists(String localId) throws RemoteException { - IMountService ms = getMs(); - String[] containers = ms.getSecureContainerList(); - String fullId = SECURE_CONTAINER_PREFIX + localId; - - for (int i = 0; i < containers.length; i++) { - if (containers[i].equals(fullId)) { - return true; - } - } - return false; - } - - private int createContainer(String localId, int size, String key, String filesystem, - boolean isExternal) throws Exception { - assertTrue("Media should be mounted", isMediaMounted()); - String fullId = SECURE_CONTAINER_PREFIX + localId; - - IMountService ms = getMs(); - return ms.createSecureContainer(fullId, size, filesystem, key, android.os.Process.myUid(), - isExternal); - } - - private int mountContainer(String localId, String key) throws Exception { - assertTrue("Media should be mounted", isMediaMounted()); - String fullId = SECURE_CONTAINER_PREFIX + localId; - - IMountService ms = getMs(); - return ms.mountSecureContainer(fullId, key, android.os.Process.myUid(), true); - } - - private int renameContainer(String localId1, String localId2) throws Exception { - assertTrue("Media should be mounted", isMediaMounted()); - String fullId1 = SECURE_CONTAINER_PREFIX + localId1; - String fullId2 = SECURE_CONTAINER_PREFIX + localId2; - - IMountService ms = getMs(); - return ms.renameSecureContainer(fullId1, fullId2); - } - - private int unmountContainer(String localId, boolean force) throws Exception { - assertTrue("Media should be mounted", isMediaMounted()); - String fullId = SECURE_CONTAINER_PREFIX + localId; - - IMountService ms = getMs(); - return ms.unmountSecureContainer(fullId, force); - } - - private int destroyContainer(String localId, boolean force) throws Exception { - assertTrue("Media should be mounted", isMediaMounted()); - String fullId = SECURE_CONTAINER_PREFIX + localId; - - IMountService ms = getMs(); - return ms.destroySecureContainer(fullId, force); - } - - private boolean isContainerMounted(String localId) throws Exception { - assertTrue("Media should be mounted", isMediaMounted()); - String fullId = SECURE_CONTAINER_PREFIX + localId; - - IMountService ms = getMs(); - return ms.isSecureContainerMounted(fullId); - } - - private IMountService getMs() { - IBinder service = ServiceManager.getService("mount"); - if (service != null) { - return IMountService.Stub.asInterface(service); - } else { - Log.e(TAG, "Can't get mount service"); - } - return null; - } - - private boolean isMediaMounted() throws Exception { - String mPath = Environment.getExternalStorageDirectory().toString(); - String state = getMs().getVolumeState(mPath); - return Environment.MEDIA_MOUNTED.equals(state); - } - - - /* - * CREATE - */ - - public void test_Fat_External_Create_Success() throws Exception { - if (Environment.isExternalStorageEmulated()) { - return; - } - - assertEquals(StorageResultCode.OperationSucceeded, - createContainer("testCreateContainer", 4, "none", FS_FAT, true)); - assertTrue(containerExists("testCreateContainer")); - } - - public void test_Ext4_External_Create_Success() throws Exception { - if (Environment.isExternalStorageEmulated()) { - return; - } - - assertEquals(StorageResultCode.OperationSucceeded, - createContainer("testCreateContainer", 4, "none", FS_EXT4, true)); - assertTrue(containerExists("testCreateContainer")); - } - - public void test_Fat_Internal_Create_Success() throws Exception { - assertEquals(StorageResultCode.OperationSucceeded, - createContainer("testCreateContainer", 4, "none", FS_FAT, false)); - assertTrue(containerExists("testCreateContainer")); - } - - public void test_Ext4_Internal_Create_Success() throws Exception { - assertEquals(StorageResultCode.OperationSucceeded, - createContainer("testCreateContainer", 4, "none", FS_EXT4, false)); - assertTrue(containerExists("testCreateContainer")); - } - - - /* - * CREATE MIN SIZE - */ - - public void test_Fat_External_CreateMinSize_Success() throws Exception { - if (Environment.isExternalStorageEmulated()) { - return; - } - - assertEquals(StorageResultCode.OperationSucceeded, - createContainer("testCreateContainer", 1, "none", FS_FAT, true)); - assertTrue(containerExists("testCreateContainer")); - } - - public void test_Ext4_External_CreateMinSize_Success() throws Exception { - if (Environment.isExternalStorageEmulated()) { - return; - } - - assertEquals(StorageResultCode.OperationSucceeded, - createContainer("testCreateContainer", 1, "none", FS_EXT4, true)); - assertTrue(containerExists("testCreateContainer")); - } - - public void test_Fat_Internal_CreateMinSize_Success() throws Exception { - assertEquals(StorageResultCode.OperationSucceeded, - createContainer("testCreateContainer", 1, "none", FS_FAT, false)); - assertTrue(containerExists("testCreateContainer")); - } - - public void test_Ext4_Internal_CreateMinSize_Success() throws Exception { - assertEquals(StorageResultCode.OperationSucceeded, - createContainer("testCreateContainer", 1, "none", FS_EXT4, false)); - assertTrue(containerExists("testCreateContainer")); - } - - - /* - * CREATE ZERO SIZE - FAIL CASE - */ - - public void test_Fat_External_CreateZeroSize_Failure() throws Exception { - if (Environment.isExternalStorageEmulated()) { - return; - } - - assertEquals(StorageResultCode.OperationFailedInternalError, - createContainer("testCreateZeroContainer", 0, "none", FS_FAT, true)); - } - - public void test_Ext4_External_CreateZeroSize_Failure() throws Exception { - if (Environment.isExternalStorageEmulated()) { - return; - } - - assertEquals(StorageResultCode.OperationFailedInternalError, - createContainer("testCreateZeroContainer", 0, "none", FS_EXT4, true)); - } - - public void test_Fat_Internal_CreateZeroSize_Failure() throws Exception { - assertEquals(StorageResultCode.OperationFailedInternalError, - createContainer("testCreateZeroContainer", 0, "none", FS_FAT, false)); - } - - public void test_Ext4_Internal_CreateZeroSize_Failure() throws Exception { - assertEquals(StorageResultCode.OperationFailedInternalError, - createContainer("testCreateZeroContainer", 0, "none", FS_EXT4, false)); - } - - - /* - * CREATE DUPLICATE - FAIL CASE - */ - - public void test_Fat_External_CreateDuplicate_Failure() throws Exception { - if (Environment.isExternalStorageEmulated()) { - return; - } - - assertEquals(StorageResultCode.OperationSucceeded, - createContainer("testCreateDupContainer", 4, "none", FS_FAT, true)); - - assertEquals(StorageResultCode.OperationFailedInternalError, - createContainer("testCreateDupContainer", 4, "none", FS_FAT, true)); - } - - public void test_Ext4_External_CreateDuplicate_Failure() throws Exception { - if (Environment.isExternalStorageEmulated()) { - return; - } - - assertEquals(StorageResultCode.OperationSucceeded, - createContainer("testCreateDupContainer", 4, "none", FS_EXT4, true)); - - assertEquals(StorageResultCode.OperationFailedInternalError, - createContainer("testCreateDupContainer", 4, "none", FS_EXT4, true)); - } - - public void test_Fat_Internal_CreateDuplicate_Failure() throws Exception { - assertEquals(StorageResultCode.OperationSucceeded, - createContainer("testCreateDupContainer", 4, "none", FS_FAT, false)); - - assertEquals(StorageResultCode.OperationFailedInternalError, - createContainer("testCreateDupContainer", 4, "none", FS_FAT, false)); - } - - public void test_Ext4_Internal_CreateDuplicate_Failure() throws Exception { - assertEquals(StorageResultCode.OperationSucceeded, - createContainer("testCreateDupContainer", 4, "none", FS_EXT4, false)); - - assertEquals(StorageResultCode.OperationFailedInternalError, - createContainer("testCreateDupContainer", 4, "none", FS_EXT4, false)); - } - - - /* - * DESTROY - */ - - public void test_Fat_External_Destroy_Success() throws Exception { - if (Environment.isExternalStorageEmulated()) { - return; - } - - assertEquals(StorageResultCode.OperationSucceeded, - createContainer("testDestroyContainer", 4, "none", FS_FAT, true)); - assertEquals(StorageResultCode.OperationSucceeded, - destroyContainer("testDestroyContainer", false)); - } - - public void test_Ext4_External_Destroy_Success() throws Exception { - if (Environment.isExternalStorageEmulated()) { - return; - } - - assertEquals(StorageResultCode.OperationSucceeded, - createContainer("testDestroyContainer", 4, "none", FS_EXT4, true)); - assertEquals(StorageResultCode.OperationSucceeded, - destroyContainer("testDestroyContainer", false)); - } - - public void test_Fat_Internal_Destroy_Success() throws Exception { - assertEquals(StorageResultCode.OperationSucceeded, - createContainer("testDestroyContainer", 4, "none", FS_FAT, false)); - assertEquals(StorageResultCode.OperationSucceeded, - destroyContainer("testDestroyContainer", false)); - } - - public void test_Ext4_Internal_Destroy_Success() throws Exception { - assertEquals(StorageResultCode.OperationSucceeded, - createContainer("testDestroyContainer", 4, "none", FS_EXT4, false)); - assertEquals(StorageResultCode.OperationSucceeded, - destroyContainer("testDestroyContainer", false)); - } - - - /* - * MOUNT - */ - - public void test_Fat_External_Mount() throws Exception { - if (Environment.isExternalStorageEmulated()) { - return; - } - - assertEquals(StorageResultCode.OperationSucceeded, - createContainer("testMountContainer", 4, "none", FS_FAT, true)); - - assertEquals(StorageResultCode.OperationSucceeded, - unmountContainer("testMountContainer", false)); - - assertEquals(StorageResultCode.OperationSucceeded, - mountContainer("testMountContainer", "none")); - } - - - /* - * MOUNT BAD KEY - FAIL CASE - */ - - public void test_Fat_External_MountBadKey_Failure() throws Exception { - if (Environment.isExternalStorageEmulated()) { - return; - } - - assertEquals(StorageResultCode.OperationSucceeded, - createContainer("testMountBadKey", 4, "00000000000000000000000000000000", FS_FAT, - true)); - - assertEquals(StorageResultCode.OperationSucceeded, - unmountContainer("testMountBadKey", false)); - - assertEquals(StorageResultCode.OperationFailedInternalError, - mountContainer("testMountContainer", "000000000000000000000000000000001")); - - assertEquals(StorageResultCode.OperationFailedInternalError, - mountContainer("testMountContainer", "none")); - } - - - public void test_Fat_External_UnmountBusy_Success() throws Exception { - if (Environment.isExternalStorageEmulated()) { - return; - } - - IMountService ms = getMs(); - assertEquals(StorageResultCode.OperationSucceeded, - createContainer("testUnmountBusyContainer", 4, "none", FS_FAT, true)); - - String path = ms.getSecureContainerPath(SECURE_CONTAINER_PREFIX - + "testUnmountBusyContainer"); - - File f = new File(path, "reference"); - FileOutputStream fos = new FileOutputStream(f); - - assertEquals(StorageResultCode.OperationFailedStorageBusy, - unmountContainer("testUnmountBusyContainer", false)); - - fos.close(); - assertEquals(StorageResultCode.OperationSucceeded, - unmountContainer("testUnmountBusyContainer", false)); - } - - public void test_Fat_External_DestroyBusy() throws Exception { - if (Environment.isExternalStorageEmulated()) { - return; - } - - IMountService ms = getMs(); - - assertEquals(StorageResultCode.OperationSucceeded, - createContainer("testDestroyBusyContainer", 4, "none", FS_FAT, true)); - - String path = ms.getSecureContainerPath(SECURE_CONTAINER_PREFIX - + "testDestroyBusyContainer"); - - File f = new File(path, "reference"); - FileOutputStream fos = new FileOutputStream(f); - - assertEquals(StorageResultCode.OperationFailedStorageBusy, - destroyContainer("testDestroyBusyContainer", false)); - - fos.close(); - assertEquals(StorageResultCode.OperationSucceeded, - destroyContainer("testDestroyBusyContainer", false)); - } - - public void test_Fat_External_Rename_Success() throws Exception { - if (Environment.isExternalStorageEmulated()) { - return; - } - - assertEquals(StorageResultCode.OperationSucceeded, - createContainer("testRenameContainer.1", 4, "none", FS_FAT, true)); - - assertEquals(StorageResultCode.OperationSucceeded, - unmountContainer("testRenameContainer.1", false)); - - assertEquals(StorageResultCode.OperationSucceeded, - renameContainer("testRenameContainer.1", "testRenameContainer.2")); - - assertFalse(containerExists("testRenameContainer.1")); - assertTrue(containerExists("testRenameContainer.2")); - } - - public void test_Fat_External_RenameSrcMounted_Failure() throws Exception { - if (Environment.isExternalStorageEmulated()) { - return; - } - - assertEquals(StorageResultCode.OperationSucceeded, - createContainer("testRenameContainer.1", 4, "none", FS_FAT, true)); - - assertEquals(StorageResultCode.OperationFailedStorageMounted, - renameContainer("testRenameContainer.1", "testRenameContainer.2")); - } - - public void test_Fat_External_RenameDstMounted_Failure() throws Exception { - if (Environment.isExternalStorageEmulated()) { - return; - } - - assertEquals(StorageResultCode.OperationSucceeded, - createContainer("testRenameContainer.1", 4, "none", FS_FAT, true)); - - assertEquals(StorageResultCode.OperationSucceeded, - unmountContainer("testRenameContainer.1", false)); - - assertEquals(StorageResultCode.OperationSucceeded, - createContainer("testRenameContainer.2", 4, "none", FS_FAT, true)); - - assertEquals(StorageResultCode.OperationFailedStorageMounted, - renameContainer("testRenameContainer.1", "testRenameContainer.2")); - } - - public void test_Fat_External_Size_Success() throws Exception { - if (Environment.isExternalStorageEmulated()) { - return; - } - - IMountService ms = getMs(); - assertEquals(StorageResultCode.OperationSucceeded, - createContainer("testContainerSize", 1, "none", FS_FAT, true)); - String path = ms.getSecureContainerPath(SECURE_CONTAINER_PREFIX + "testContainerSize"); - - byte[] buf = new byte[4096]; - File f = new File(path, "reference"); - FileOutputStream fos = new FileOutputStream(f); - for (int i = 0; i < (1024 * 1024); i += buf.length) { - fos.write(buf); - } - fos.close(); - } - - public void testGetSecureContainerPath_NonExistPath_Failure() throws Exception { - IMountService ms = getMs(); - assertNull("Getting the path for an invalid container should return null", - ms.getSecureContainerPath("jparks.broke.it")); - } - - /*------------ Tests for unmounting volume ---*/ - public final long MAX_WAIT_TIME=120*1000; - public final long WAIT_TIME_INCR=20*1000; - - boolean getMediaState() throws Exception { - String mPath = Environment.getExternalStorageDirectory().toString(); - String state = getMs().getVolumeState(mPath); - return Environment.MEDIA_MOUNTED.equals(state); - } - - boolean mountMedia() throws Exception { - if (Environment.isExternalStorageEmulated()) { - return true; - } - - if (getMediaState()) { - return true; - } - - String mPath = Environment.getExternalStorageDirectory().toString(); - int ret = getMs().mountVolume(mPath); - return ret == StorageResultCode.OperationSucceeded; - } - - class StorageListener extends StorageEventListener { - String oldState; - String newState; - String path; - private boolean doneFlag = false; - - public void action() { - synchronized (this) { - doneFlag = true; - notifyAll(); - } - } - - public boolean isDone() { - return doneFlag; - } - - @Override - public void onStorageStateChanged(String path, String oldState, String newState) { - if (localLOGV) Log.i(TAG, "Storage state changed from " + oldState + " to " + newState); - this.oldState = oldState; - this.newState = newState; - this.path = path; - action(); - } - } - - private void unmountMedia() throws Exception { - if (Environment.isExternalStorageEmulated()) { - return; - } - - if (!getMediaState()) { - return; - } - - String path = Environment.getExternalStorageDirectory().toString(); - StorageListener observer = new StorageListener(); - StorageManager sm = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE); - sm.registerListener(observer); - try { - // Wait on observer - synchronized(observer) { - getMs().unmountVolume(path, false, false); - long waitTime = 0; - while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) { - observer.wait(WAIT_TIME_INCR); - waitTime += WAIT_TIME_INCR; - } - if(!observer.isDone()) { - fail("Timed out waiting for packageInstalled callback"); - } - } - } finally { - sm.unregisterListener(observer); - } - } - - public void testUnmount() throws Exception { - boolean oldStatus = getMediaState(); - Log.i(TAG, "oldStatus="+oldStatus); - try { - // Mount media firsts - if (!getMediaState()) { - mountMedia(); - } - unmountMedia(); - } finally { - // Restore old status - boolean currStatus = getMediaState(); - if (oldStatus != currStatus) { - if (oldStatus) { - // Mount media - mountMedia(); - } else { - unmountMedia(); - } - } - } - } - - class MultipleStorageLis extends StorageListener { - int count = 0; - public void onStorageStateChanged(String path, String oldState, String newState) { - count++; - super.action(); - } - } - /* - * This test invokes unmount multiple time and expects the call back - * to be invoked just once. - */ - public void testUnmountMultiple() throws Exception { - if (Environment.isExternalStorageEmulated()) { - return; - } - - boolean oldStatus = getMediaState(); - StorageManager sm = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE); - MultipleStorageLis observer = new MultipleStorageLis(); - try { - // Mount media firsts - if (!getMediaState()) { - mountMedia(); - } - String path = Environment.getExternalStorageDirectory().toString(); - sm.registerListener(observer); - // Wait on observer - synchronized(observer) { - for (int i = 0; i < 5; i++) { - getMs().unmountVolume(path, false, false); - } - long waitTime = 0; - while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) { - observer.wait(WAIT_TIME_INCR); - waitTime += WAIT_TIME_INCR; - } - if(!observer.isDone()) { - fail("Timed out waiting for packageInstalled callback"); - } - } - assertEquals(observer.count, 1); - } finally { - sm.unregisterListener(observer); - // Restore old status - boolean currStatus = getMediaState(); - if (oldStatus != currStatus) { - if (oldStatus) { - // Mount media - mountMedia(); - } else { - unmountMedia(); - } - } - } - } - - class ShutdownObserver extends IMountShutdownObserver.Stub{ - private boolean doneFlag = false; - int statusCode; - - public void action() { - synchronized (this) { - doneFlag = true; - notifyAll(); - } - } - - public boolean isDone() { - return doneFlag; - } - public void onShutDownComplete(int statusCode) throws RemoteException { - this.statusCode = statusCode; - action(); - } - - } - - void invokeShutdown() throws Exception { - IMountService ms = getMs(); - ShutdownObserver observer = new ShutdownObserver(); - synchronized (observer) { - ms.shutdown(observer); - } - } - - public void testShutdown() throws Exception { - if (Environment.isExternalStorageEmulated()) { - return; - } - - boolean oldStatus = getMediaState(); - try { - // Mount media firsts - if (!getMediaState()) { - mountMedia(); - } - invokeShutdown(); - } finally { - // Restore old status - boolean currStatus = getMediaState(); - if (oldStatus != currStatus) { - if (oldStatus) { - // Mount media - mountMedia(); - } else { - unmountMedia(); - } - } - } - } - - /* - * This test invokes unmount multiple time and expects the call back - * to be invoked just once. - */ - public void testShutdownMultiple() throws Exception { - if (Environment.isExternalStorageEmulated()) { - return; - } - - boolean oldStatus = getMediaState(); - try { - // Mount media firsts - if (!getMediaState()) { - mountMedia(); - } - IMountService ms = getMs(); - ShutdownObserver observer = new ShutdownObserver(); - synchronized (observer) { - ms.shutdown(observer); - for (int i = 0; i < 4; i++) { - ms.shutdown(null); - } - } - } finally { - // Restore old status - boolean currStatus = getMediaState(); - if (oldStatus != currStatus) { - if (oldStatus) { - // Mount media - mountMedia(); - } else { - unmountMedia(); - } - } - } - } - -} diff --git a/src/main/java/android/os/storage/IMountService.java b/src/main/java/android/os/storage/IMountService.java deleted file mode 100644 index 116110e..0000000 --- a/src/main/java/android/os/storage/IMountService.java +++ /dev/null @@ -1,1683 +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.os.storage; - -import android.os.Binder; -import android.os.IBinder; -import android.os.IInterface; -import android.os.Parcel; -import android.os.RemoteException; - -/** - * WARNING! Update IMountService.h and IMountService.cpp if you change this - * file. In particular, the ordering of the methods below must match the - * _TRANSACTION enum in IMountService.cpp - * - * @hide - Applications should use android.os.storage.StorageManager to access - * storage functions. - */ -public interface IMountService extends IInterface { - /** Local-side IPC implementation stub class. */ - public static abstract class Stub extends Binder implements IMountService { - private static class Proxy implements IMountService { - private final IBinder mRemote; - - Proxy(IBinder remote) { - mRemote = remote; - } - - public IBinder asBinder() { - return mRemote; - } - - public String getInterfaceDescriptor() { - return DESCRIPTOR; - } - - /** - * Registers an IMountServiceListener for receiving async - * notifications. - */ - public void registerListener(IMountServiceListener listener) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeStrongBinder((listener != null ? listener.asBinder() : null)); - mRemote.transact(Stub.TRANSACTION_registerListener, _data, _reply, 0); - _reply.readException(); - } finally { - _reply.recycle(); - _data.recycle(); - } - } - - /** - * Unregisters an IMountServiceListener - */ - public void unregisterListener(IMountServiceListener listener) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeStrongBinder((listener != null ? listener.asBinder() : null)); - mRemote.transact(Stub.TRANSACTION_unregisterListener, _data, _reply, 0); - _reply.readException(); - } finally { - _reply.recycle(); - _data.recycle(); - } - } - - /** - * Returns true if a USB mass storage host is connected - */ - public boolean isUsbMassStorageConnected() throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - boolean _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - mRemote.transact(Stub.TRANSACTION_isUsbMassStorageConnected, _data, _reply, 0); - _reply.readException(); - _result = 0 != _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - /** - * Enables / disables USB mass storage. The caller should check - * actual status of enabling/disabling USB mass storage via - * StorageEventListener. - */ - public void setUsbMassStorageEnabled(boolean enable) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeInt((enable ? 1 : 0)); - mRemote.transact(Stub.TRANSACTION_setUsbMassStorageEnabled, _data, _reply, 0); - _reply.readException(); - } finally { - _reply.recycle(); - _data.recycle(); - } - } - - /** - * Returns true if a USB mass storage host is enabled (media is - * shared) - */ - public boolean isUsbMassStorageEnabled() throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - boolean _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - mRemote.transact(Stub.TRANSACTION_isUsbMassStorageEnabled, _data, _reply, 0); - _reply.readException(); - _result = 0 != _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - /** - * Mount external storage at given mount point. Returns an int - * consistent with MountServiceResultCode - */ - public int mountVolume(String mountPoint) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(mountPoint); - mRemote.transact(Stub.TRANSACTION_mountVolume, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - /** - * Safely unmount external storage at given mount point. The unmount - * is an asynchronous operation. Applications should register - * StorageEventListener for storage related status changes. - */ - public void unmountVolume(String mountPoint, boolean force, boolean removeEncryption) - throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(mountPoint); - _data.writeInt((force ? 1 : 0)); - _data.writeInt((removeEncryption ? 1 : 0)); - mRemote.transact(Stub.TRANSACTION_unmountVolume, _data, _reply, 0); - _reply.readException(); - } finally { - _reply.recycle(); - _data.recycle(); - } - } - - /** - * Format external storage given a mount point. Returns an int - * consistent with MountServiceResultCode - */ - public int formatVolume(String mountPoint) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(mountPoint); - mRemote.transact(Stub.TRANSACTION_formatVolume, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - /** - * Returns an array of pids with open files on the specified path. - */ - public int[] getStorageUsers(String path) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int[] _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(path); - mRemote.transact(Stub.TRANSACTION_getStorageUsers, _data, _reply, 0); - _reply.readException(); - _result = _reply.createIntArray(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - /** - * Gets the state of a volume via its mountpoint. - */ - public String getVolumeState(String mountPoint) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - String _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(mountPoint); - mRemote.transact(Stub.TRANSACTION_getVolumeState, _data, _reply, 0); - _reply.readException(); - _result = _reply.readString(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - /* - * Creates a secure container with the specified parameters. Returns - * an int consistent with MountServiceResultCode - */ - public int createSecureContainer(String id, int sizeMb, String fstype, String key, - int ownerUid, boolean external) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(id); - _data.writeInt(sizeMb); - _data.writeString(fstype); - _data.writeString(key); - _data.writeInt(ownerUid); - _data.writeInt(external ? 1 : 0); - mRemote.transact(Stub.TRANSACTION_createSecureContainer, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - /* - * Destroy a secure container, and free up all resources associated - * with it. NOTE: Ensure all references are released prior to - * deleting. Returns an int consistent with MountServiceResultCode - */ - public int destroySecureContainer(String id, boolean force) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(id); - _data.writeInt((force ? 1 : 0)); - mRemote.transact(Stub.TRANSACTION_destroySecureContainer, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - /* - * Finalize a container which has just been created and populated. - * After finalization, the container is immutable. Returns an int - * consistent with MountServiceResultCode - */ - public int finalizeSecureContainer(String id) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(id); - mRemote.transact(Stub.TRANSACTION_finalizeSecureContainer, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - /* - * Mount a secure container with the specified key and owner UID. - * Returns an int consistent with MountServiceResultCode - */ - public int mountSecureContainer(String id, String key, int ownerUid, boolean readOnly) - throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(id); - _data.writeString(key); - _data.writeInt(ownerUid); - _data.writeInt(readOnly ? 1 : 0); - mRemote.transact(Stub.TRANSACTION_mountSecureContainer, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - /* - * Unount a secure container. Returns an int consistent with - * MountServiceResultCode - */ - public int unmountSecureContainer(String id, boolean force) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(id); - _data.writeInt((force ? 1 : 0)); - mRemote.transact(Stub.TRANSACTION_unmountSecureContainer, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - /* - * Returns true if the specified container is mounted - */ - public boolean isSecureContainerMounted(String id) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - boolean _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(id); - mRemote.transact(Stub.TRANSACTION_isSecureContainerMounted, _data, _reply, 0); - _reply.readException(); - _result = 0 != _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - /* - * Rename an unmounted secure container. Returns an int consistent - * with MountServiceResultCode - */ - public int renameSecureContainer(String oldId, String newId) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(oldId); - _data.writeString(newId); - mRemote.transact(Stub.TRANSACTION_renameSecureContainer, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - /* - * Returns the filesystem path of a mounted secure container. - */ - public String getSecureContainerPath(String id) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - String _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(id); - mRemote.transact(Stub.TRANSACTION_getSecureContainerPath, _data, _reply, 0); - _reply.readException(); - _result = _reply.readString(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - /** - * Gets an Array of currently known secure container IDs - */ - public String[] getSecureContainerList() throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - String[] _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - mRemote.transact(Stub.TRANSACTION_getSecureContainerList, _data, _reply, 0); - _reply.readException(); - _result = _reply.createStringArray(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - /** - * Shuts down the MountService and gracefully unmounts all external - * media. Invokes call back once the shutdown is complete. - */ - public void shutdown(IMountShutdownObserver observer) - throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeStrongBinder((observer != null ? observer.asBinder() : null)); - mRemote.transact(Stub.TRANSACTION_shutdown, _data, _reply, 0); - _reply.readException(); - } finally { - _reply.recycle(); - _data.recycle(); - } - } - - /** - * Call into MountService by PackageManager to notify that its done - * processing the media status update request. - */ - public void finishMediaUpdate() throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - try { - _data.writeInterfaceToken(DESCRIPTOR); - mRemote.transact(Stub.TRANSACTION_finishMediaUpdate, _data, _reply, 0); - _reply.readException(); - } finally { - _reply.recycle(); - _data.recycle(); - } - } - - /** - * Mounts an Opaque Binary Blob (OBB) with the specified decryption - * key and only allows the calling process's UID access to the - * contents. MountService will call back to the supplied - * IObbActionListener to inform it of the terminal state of the - * call. - */ - public void mountObb(String rawPath, String canonicalPath, String key, - IObbActionListener token, int nonce) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(rawPath); - _data.writeString(canonicalPath); - _data.writeString(key); - _data.writeStrongBinder((token != null ? token.asBinder() : null)); - _data.writeInt(nonce); - mRemote.transact(Stub.TRANSACTION_mountObb, _data, _reply, 0); - _reply.readException(); - } finally { - _reply.recycle(); - _data.recycle(); - } - } - - /** - * Unmounts an Opaque Binary Blob (OBB). When the force flag is - * specified, any program using it will be forcibly killed to - * unmount the image. MountService will call back to the supplied - * IObbActionListener to inform it of the terminal state of the - * call. - */ - public void unmountObb( - String rawPath, boolean force, IObbActionListener token, int nonce) - throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(rawPath); - _data.writeInt((force ? 1 : 0)); - _data.writeStrongBinder((token != null ? token.asBinder() : null)); - _data.writeInt(nonce); - mRemote.transact(Stub.TRANSACTION_unmountObb, _data, _reply, 0); - _reply.readException(); - } finally { - _reply.recycle(); - _data.recycle(); - } - } - - /** - * Checks whether the specified Opaque Binary Blob (OBB) is mounted - * somewhere. - */ - public boolean isObbMounted(String rawPath) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - boolean _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(rawPath); - mRemote.transact(Stub.TRANSACTION_isObbMounted, _data, _reply, 0); - _reply.readException(); - _result = 0 != _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - /** - * Gets the path to the mounted Opaque Binary Blob (OBB). - */ - public String getMountedObbPath(String rawPath) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - String _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(rawPath); - mRemote.transact(Stub.TRANSACTION_getMountedObbPath, _data, _reply, 0); - _reply.readException(); - _result = _reply.readString(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - /** - * Returns whether the external storage is emulated. - */ - public boolean isExternalStorageEmulated() throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - boolean _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - mRemote.transact(Stub.TRANSACTION_isExternalStorageEmulated, _data, _reply, 0); - _reply.readException(); - _result = 0 != _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - public int getEncryptionState() throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - mRemote.transact(Stub.TRANSACTION_getEncryptionState, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - public int decryptStorage(String password) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(password); - mRemote.transact(Stub.TRANSACTION_decryptStorage, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - public int encryptStorage(int type, String password) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeInt(type); - _data.writeString(password); - mRemote.transact(Stub.TRANSACTION_encryptStorage, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - public int changeEncryptionPassword(int type, String password) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeInt(type); - _data.writeString(password); - mRemote.transact(Stub.TRANSACTION_changeEncryptionPassword, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - @Override - public int verifyEncryptionPassword(String password) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(password); - mRemote.transact(Stub.TRANSACTION_verifyEncryptionPassword, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - public int getPasswordType() throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - mRemote.transact(Stub.TRANSACTION_getPasswordType, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - public String getPassword() throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - String _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - mRemote.transact(Stub.TRANSACTION_getPassword, _data, _reply, 0); - _reply.readException(); - _result = _reply.readString(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - public void clearPassword() throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - try { - _data.writeInterfaceToken(DESCRIPTOR); - mRemote.transact(Stub.TRANSACTION_clearPassword, _data, _reply, IBinder.FLAG_ONEWAY); - _reply.readException(); - } finally { - _reply.recycle(); - _data.recycle(); - } - } - - public void setField(String field, String data) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(field); - _data.writeString(data); - mRemote.transact(Stub.TRANSACTION_setField, _data, _reply, IBinder.FLAG_ONEWAY); - _reply.readException(); - } finally { - _reply.recycle(); - _data.recycle(); - } - } - - public String getField(String field) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - String _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(field); - mRemote.transact(Stub.TRANSACTION_getField, _data, _reply, 0); - _reply.readException(); - _result = _reply.readString(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - public StorageVolume[] getVolumeList() throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - StorageVolume[] _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - mRemote.transact(Stub.TRANSACTION_getVolumeList, _data, _reply, 0); - _reply.readException(); - _result = _reply.createTypedArray(StorageVolume.CREATOR); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - /* - * Returns the filesystem path of a mounted secure container. - */ - public String getSecureContainerFilesystemPath(String id) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - String _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(id); - mRemote.transact(Stub.TRANSACTION_getSecureContainerFilesystemPath, _data, _reply, 0); - _reply.readException(); - _result = _reply.readString(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - /** - * Fix permissions in a container which has just been created and - * populated. Returns an int consistent with MountServiceResultCode - */ - public int fixPermissionsSecureContainer(String id, int gid, String filename) - throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(id); - _data.writeInt(gid); - _data.writeString(filename); - mRemote.transact(Stub.TRANSACTION_fixPermissionsSecureContainer, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - @Override - public int mkdirs(String callingPkg, String path) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(callingPkg); - _data.writeString(path); - mRemote.transact(Stub.TRANSACTION_mkdirs, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - @Override - public int resizeSecureContainer(String id, int sizeMb, String key) - throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(id); - _data.writeInt(sizeMb); - _data.writeString(key); - mRemote.transact(Stub.TRANSACTION_resizeSecureContainer, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - @Override - public long lastMaintenance() throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - long _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - mRemote.transact(Stub.TRANSACTION_lastMaintenance, _data, _reply, 0); - _reply.readException(); - _result = _reply.readLong(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - @Override - public void runMaintenance() throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - try { - _data.writeInterfaceToken(DESCRIPTOR); - mRemote.transact(Stub.TRANSACTION_runMaintenance, _data, _reply, 0); - _reply.readException(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return; - } - } - - private static final String DESCRIPTOR = "IMountService"; - - static final int TRANSACTION_registerListener = IBinder.FIRST_CALL_TRANSACTION + 0; - - static final int TRANSACTION_unregisterListener = IBinder.FIRST_CALL_TRANSACTION + 1; - - static final int TRANSACTION_isUsbMassStorageConnected = IBinder.FIRST_CALL_TRANSACTION + 2; - - static final int TRANSACTION_setUsbMassStorageEnabled = IBinder.FIRST_CALL_TRANSACTION + 3; - - static final int TRANSACTION_isUsbMassStorageEnabled = IBinder.FIRST_CALL_TRANSACTION + 4; - - static final int TRANSACTION_mountVolume = IBinder.FIRST_CALL_TRANSACTION + 5; - - static final int TRANSACTION_unmountVolume = IBinder.FIRST_CALL_TRANSACTION + 6; - - static final int TRANSACTION_formatVolume = IBinder.FIRST_CALL_TRANSACTION + 7; - - static final int TRANSACTION_getStorageUsers = IBinder.FIRST_CALL_TRANSACTION + 8; - - static final int TRANSACTION_getVolumeState = IBinder.FIRST_CALL_TRANSACTION + 9; - - static final int TRANSACTION_createSecureContainer = IBinder.FIRST_CALL_TRANSACTION + 10; - - static final int TRANSACTION_finalizeSecureContainer = IBinder.FIRST_CALL_TRANSACTION + 11; - - static final int TRANSACTION_destroySecureContainer = IBinder.FIRST_CALL_TRANSACTION + 12; - - static final int TRANSACTION_mountSecureContainer = IBinder.FIRST_CALL_TRANSACTION + 13; - - static final int TRANSACTION_unmountSecureContainer = IBinder.FIRST_CALL_TRANSACTION + 14; - - static final int TRANSACTION_isSecureContainerMounted = IBinder.FIRST_CALL_TRANSACTION + 15; - - static final int TRANSACTION_renameSecureContainer = IBinder.FIRST_CALL_TRANSACTION + 16; - - static final int TRANSACTION_getSecureContainerPath = IBinder.FIRST_CALL_TRANSACTION + 17; - - static final int TRANSACTION_getSecureContainerList = IBinder.FIRST_CALL_TRANSACTION + 18; - - static final int TRANSACTION_shutdown = IBinder.FIRST_CALL_TRANSACTION + 19; - - static final int TRANSACTION_finishMediaUpdate = IBinder.FIRST_CALL_TRANSACTION + 20; - - static final int TRANSACTION_mountObb = IBinder.FIRST_CALL_TRANSACTION + 21; - - static final int TRANSACTION_unmountObb = IBinder.FIRST_CALL_TRANSACTION + 22; - - static final int TRANSACTION_isObbMounted = IBinder.FIRST_CALL_TRANSACTION + 23; - - static final int TRANSACTION_getMountedObbPath = IBinder.FIRST_CALL_TRANSACTION + 24; - - static final int TRANSACTION_isExternalStorageEmulated = IBinder.FIRST_CALL_TRANSACTION + 25; - - static final int TRANSACTION_decryptStorage = IBinder.FIRST_CALL_TRANSACTION + 26; - - static final int TRANSACTION_encryptStorage = IBinder.FIRST_CALL_TRANSACTION + 27; - - static final int TRANSACTION_changeEncryptionPassword = IBinder.FIRST_CALL_TRANSACTION + 28; - - static final int TRANSACTION_getVolumeList = IBinder.FIRST_CALL_TRANSACTION + 29; - - static final int TRANSACTION_getSecureContainerFilesystemPath = IBinder.FIRST_CALL_TRANSACTION + 30; - - static final int TRANSACTION_getEncryptionState = IBinder.FIRST_CALL_TRANSACTION + 31; - - static final int TRANSACTION_verifyEncryptionPassword = IBinder.FIRST_CALL_TRANSACTION + 32; - - static final int TRANSACTION_fixPermissionsSecureContainer = IBinder.FIRST_CALL_TRANSACTION + 33; - - static final int TRANSACTION_mkdirs = IBinder.FIRST_CALL_TRANSACTION + 34; - - static final int TRANSACTION_getPasswordType = IBinder.FIRST_CALL_TRANSACTION + 35; - - static final int TRANSACTION_getPassword = IBinder.FIRST_CALL_TRANSACTION + 36; - - static final int TRANSACTION_clearPassword = IBinder.FIRST_CALL_TRANSACTION + 37; - - static final int TRANSACTION_setField = IBinder.FIRST_CALL_TRANSACTION + 38; - - static final int TRANSACTION_getField = IBinder.FIRST_CALL_TRANSACTION + 39; - - static final int TRANSACTION_resizeSecureContainer = IBinder.FIRST_CALL_TRANSACTION + 40; - - static final int TRANSACTION_lastMaintenance = IBinder.FIRST_CALL_TRANSACTION + 41; - - static final int TRANSACTION_runMaintenance = IBinder.FIRST_CALL_TRANSACTION + 42; - - /** - * Cast an IBinder object into an IMountService interface, generating a - * proxy if needed. - */ - public static IMountService asInterface(IBinder obj) { - if (obj == null) { - return null; - } - IInterface iin = obj.queryLocalInterface(DESCRIPTOR); - if (iin != null && iin instanceof IMountService) { - return (IMountService) iin; - } - return new IMountService.Stub.Proxy(obj); - } - - /** Construct the stub at attach it to the interface. */ - public Stub() { - attachInterface(this, DESCRIPTOR); - } - - public IBinder asBinder() { - return this; - } - - @Override - public boolean onTransact(int code, Parcel data, Parcel reply, - int flags) throws RemoteException { - switch (code) { - case INTERFACE_TRANSACTION: { - reply.writeString(DESCRIPTOR); - return true; - } - case TRANSACTION_registerListener: { - data.enforceInterface(DESCRIPTOR); - IMountServiceListener listener; - listener = IMountServiceListener.Stub.asInterface(data.readStrongBinder()); - registerListener(listener); - reply.writeNoException(); - return true; - } - case TRANSACTION_unregisterListener: { - data.enforceInterface(DESCRIPTOR); - IMountServiceListener listener; - listener = IMountServiceListener.Stub.asInterface(data.readStrongBinder()); - unregisterListener(listener); - reply.writeNoException(); - return true; - } - case TRANSACTION_isUsbMassStorageConnected: { - data.enforceInterface(DESCRIPTOR); - boolean result = isUsbMassStorageConnected(); - reply.writeNoException(); - reply.writeInt((result ? 1 : 0)); - return true; - } - case TRANSACTION_setUsbMassStorageEnabled: { - data.enforceInterface(DESCRIPTOR); - boolean enable; - enable = 0 != data.readInt(); - setUsbMassStorageEnabled(enable); - reply.writeNoException(); - return true; - } - case TRANSACTION_isUsbMassStorageEnabled: { - data.enforceInterface(DESCRIPTOR); - boolean result = isUsbMassStorageEnabled(); - reply.writeNoException(); - reply.writeInt((result ? 1 : 0)); - return true; - } - case TRANSACTION_mountVolume: { - data.enforceInterface(DESCRIPTOR); - String mountPoint; - mountPoint = data.readString(); - int resultCode = mountVolume(mountPoint); - reply.writeNoException(); - reply.writeInt(resultCode); - return true; - } - case TRANSACTION_unmountVolume: { - data.enforceInterface(DESCRIPTOR); - String mountPoint; - mountPoint = data.readString(); - boolean force = 0 != data.readInt(); - boolean removeEncrypt = 0 != data.readInt(); - unmountVolume(mountPoint, force, removeEncrypt); - reply.writeNoException(); - return true; - } - case TRANSACTION_formatVolume: { - data.enforceInterface(DESCRIPTOR); - String mountPoint; - mountPoint = data.readString(); - int result = formatVolume(mountPoint); - reply.writeNoException(); - reply.writeInt(result); - return true; - } - case TRANSACTION_getStorageUsers: { - data.enforceInterface(DESCRIPTOR); - String path; - path = data.readString(); - int[] pids = getStorageUsers(path); - reply.writeNoException(); - reply.writeIntArray(pids); - return true; - } - case TRANSACTION_getVolumeState: { - data.enforceInterface(DESCRIPTOR); - String mountPoint; - mountPoint = data.readString(); - String state = getVolumeState(mountPoint); - reply.writeNoException(); - reply.writeString(state); - return true; - } - case TRANSACTION_createSecureContainer: { - data.enforceInterface(DESCRIPTOR); - String id; - id = data.readString(); - int sizeMb; - sizeMb = data.readInt(); - String fstype; - fstype = data.readString(); - String key; - key = data.readString(); - int ownerUid; - ownerUid = data.readInt(); - boolean external; - external = 0 != data.readInt(); - int resultCode = createSecureContainer(id, sizeMb, fstype, key, ownerUid, - external); - reply.writeNoException(); - reply.writeInt(resultCode); - return true; - } - case TRANSACTION_finalizeSecureContainer: { - data.enforceInterface(DESCRIPTOR); - String id; - id = data.readString(); - int resultCode = finalizeSecureContainer(id); - reply.writeNoException(); - reply.writeInt(resultCode); - return true; - } - case TRANSACTION_destroySecureContainer: { - data.enforceInterface(DESCRIPTOR); - String id; - id = data.readString(); - boolean force; - force = 0 != data.readInt(); - int resultCode = destroySecureContainer(id, force); - reply.writeNoException(); - reply.writeInt(resultCode); - return true; - } - case TRANSACTION_mountSecureContainer: { - data.enforceInterface(DESCRIPTOR); - String id; - id = data.readString(); - String key; - key = data.readString(); - int ownerUid; - ownerUid = data.readInt(); - boolean readOnly; - readOnly = data.readInt() != 0; - int resultCode = mountSecureContainer(id, key, ownerUid, readOnly); - reply.writeNoException(); - reply.writeInt(resultCode); - return true; - } - case TRANSACTION_unmountSecureContainer: { - data.enforceInterface(DESCRIPTOR); - String id; - id = data.readString(); - boolean force; - force = 0 != data.readInt(); - int resultCode = unmountSecureContainer(id, force); - reply.writeNoException(); - reply.writeInt(resultCode); - return true; - } - case TRANSACTION_isSecureContainerMounted: { - data.enforceInterface(DESCRIPTOR); - String id; - id = data.readString(); - boolean status = isSecureContainerMounted(id); - reply.writeNoException(); - reply.writeInt((status ? 1 : 0)); - return true; - } - case TRANSACTION_renameSecureContainer: { - data.enforceInterface(DESCRIPTOR); - String oldId; - oldId = data.readString(); - String newId; - newId = data.readString(); - int resultCode = renameSecureContainer(oldId, newId); - reply.writeNoException(); - reply.writeInt(resultCode); - return true; - } - case TRANSACTION_getSecureContainerPath: { - data.enforceInterface(DESCRIPTOR); - String id; - id = data.readString(); - String path = getSecureContainerPath(id); - reply.writeNoException(); - reply.writeString(path); - return true; - } - case TRANSACTION_getSecureContainerList: { - data.enforceInterface(DESCRIPTOR); - String[] ids = getSecureContainerList(); - reply.writeNoException(); - reply.writeStringArray(ids); - return true; - } - case TRANSACTION_shutdown: { - data.enforceInterface(DESCRIPTOR); - IMountShutdownObserver observer; - observer = IMountShutdownObserver.Stub.asInterface(data - .readStrongBinder()); - shutdown(observer); - reply.writeNoException(); - return true; - } - case TRANSACTION_finishMediaUpdate: { - data.enforceInterface(DESCRIPTOR); - finishMediaUpdate(); - reply.writeNoException(); - return true; - } - case TRANSACTION_mountObb: { - data.enforceInterface(DESCRIPTOR); - final String rawPath = data.readString(); - final String canonicalPath = data.readString(); - final String key = data.readString(); - IObbActionListener observer; - observer = IObbActionListener.Stub.asInterface(data.readStrongBinder()); - int nonce; - nonce = data.readInt(); - mountObb(rawPath, canonicalPath, key, observer, nonce); - reply.writeNoException(); - return true; - } - case TRANSACTION_unmountObb: { - data.enforceInterface(DESCRIPTOR); - String filename; - filename = data.readString(); - boolean force; - force = 0 != data.readInt(); - IObbActionListener observer; - observer = IObbActionListener.Stub.asInterface(data.readStrongBinder()); - int nonce; - nonce = data.readInt(); - unmountObb(filename, force, observer, nonce); - reply.writeNoException(); - return true; - } - case TRANSACTION_isObbMounted: { - data.enforceInterface(DESCRIPTOR); - String filename; - filename = data.readString(); - boolean status = isObbMounted(filename); - reply.writeNoException(); - reply.writeInt((status ? 1 : 0)); - return true; - } - case TRANSACTION_getMountedObbPath: { - data.enforceInterface(DESCRIPTOR); - String filename; - filename = data.readString(); - String mountedPath = getMountedObbPath(filename); - reply.writeNoException(); - reply.writeString(mountedPath); - return true; - } - case TRANSACTION_isExternalStorageEmulated: { - data.enforceInterface(DESCRIPTOR); - boolean emulated = isExternalStorageEmulated(); - reply.writeNoException(); - reply.writeInt(emulated ? 1 : 0); - return true; - } - case TRANSACTION_decryptStorage: { - data.enforceInterface(DESCRIPTOR); - String password = data.readString(); - int result = decryptStorage(password); - reply.writeNoException(); - reply.writeInt(result); - return true; - } - case TRANSACTION_encryptStorage: { - data.enforceInterface(DESCRIPTOR); - int type = data.readInt(); - String password = data.readString(); - int result = encryptStorage(type, password); - reply.writeNoException(); - reply.writeInt(result); - return true; - } - case TRANSACTION_changeEncryptionPassword: { - data.enforceInterface(DESCRIPTOR); - int type = data.readInt(); - String password = data.readString(); - int result = changeEncryptionPassword(type, password); - reply.writeNoException(); - reply.writeInt(result); - return true; - } - case TRANSACTION_getVolumeList: { - data.enforceInterface(DESCRIPTOR); - StorageVolume[] result = getVolumeList(); - reply.writeNoException(); - reply.writeTypedArray(result, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); - return true; - } - case TRANSACTION_getSecureContainerFilesystemPath: { - data.enforceInterface(DESCRIPTOR); - String id; - id = data.readString(); - String path = getSecureContainerFilesystemPath(id); - reply.writeNoException(); - reply.writeString(path); - return true; - } - case TRANSACTION_getEncryptionState: { - data.enforceInterface(DESCRIPTOR); - int result = getEncryptionState(); - reply.writeNoException(); - reply.writeInt(result); - return true; - } - case TRANSACTION_fixPermissionsSecureContainer: { - data.enforceInterface(DESCRIPTOR); - String id; - id = data.readString(); - int gid; - gid = data.readInt(); - String filename; - filename = data.readString(); - int resultCode = fixPermissionsSecureContainer(id, gid, filename); - reply.writeNoException(); - reply.writeInt(resultCode); - return true; - } - case TRANSACTION_mkdirs: { - data.enforceInterface(DESCRIPTOR); - String callingPkg = data.readString(); - String path = data.readString(); - int result = mkdirs(callingPkg, path); - reply.writeNoException(); - reply.writeInt(result); - return true; - } - case TRANSACTION_getPasswordType: { - data.enforceInterface(DESCRIPTOR); - int result = getPasswordType(); - reply.writeNoException(); - reply.writeInt(result); - return true; - } - case TRANSACTION_getPassword: { - data.enforceInterface(DESCRIPTOR); - String result = getPassword(); - reply.writeNoException(); - reply.writeString(result); - return true; - } - case TRANSACTION_clearPassword: { - data.enforceInterface(DESCRIPTOR); - clearPassword(); - reply.writeNoException(); - return true; - } - case TRANSACTION_setField: { - data.enforceInterface(DESCRIPTOR); - String field = data.readString(); - String contents = data.readString(); - setField(field, contents); - reply.writeNoException(); - return true; - } - case TRANSACTION_getField: { - data.enforceInterface(DESCRIPTOR); - String field = data.readString(); - String contents = getField(field); - reply.writeNoException(); - reply.writeString(contents); - return true; - } - case TRANSACTION_resizeSecureContainer: { - data.enforceInterface(DESCRIPTOR); - String id; - id = data.readString(); - int sizeMb; - sizeMb = data.readInt(); - String key; - key = data.readString(); - int resultCode = resizeSecureContainer(id, sizeMb, key); - reply.writeNoException(); - reply.writeInt(resultCode); - return true; - } - case TRANSACTION_lastMaintenance: { - data.enforceInterface(DESCRIPTOR); - long lastMaintenance = lastMaintenance(); - reply.writeNoException(); - reply.writeLong(lastMaintenance); - return true; - } - case TRANSACTION_runMaintenance: { - data.enforceInterface(DESCRIPTOR); - runMaintenance(); - reply.writeNoException(); - return true; - } - } - return super.onTransact(code, data, reply, flags); - } - } - - /* - * Creates a secure container with the specified parameters. Returns an int - * consistent with MountServiceResultCode - */ - public int createSecureContainer(String id, int sizeMb, String fstype, String key, - int ownerUid, boolean external) throws RemoteException; - - /* - * Destroy a secure container, and free up all resources associated with it. - * NOTE: Ensure all references are released prior to deleting. Returns an - * int consistent with MountServiceResultCode - */ - public int destroySecureContainer(String id, boolean force) throws RemoteException; - - /* - * Finalize a container which has just been created and populated. After - * finalization, the container is immutable. Returns an int consistent with - * MountServiceResultCode - */ - public int finalizeSecureContainer(String id) throws RemoteException; - - /** - * Call into MountService by PackageManager to notify that its done - * processing the media status update request. - */ - public void finishMediaUpdate() throws RemoteException; - - /** - * Format external storage given a mount point. Returns an int consistent - * with MountServiceResultCode - */ - public int formatVolume(String mountPoint) throws RemoteException; - - /** - * Gets the path to the mounted Opaque Binary Blob (OBB). - */ - public String getMountedObbPath(String rawPath) throws RemoteException; - - /** - * Gets an Array of currently known secure container IDs - */ - public String[] getSecureContainerList() throws RemoteException; - - /* - * Returns the filesystem path of a mounted secure container. - */ - public String getSecureContainerPath(String id) throws RemoteException; - - /** - * Returns an array of pids with open files on the specified path. - */ - public int[] getStorageUsers(String path) throws RemoteException; - - /** - * Gets the state of a volume via its mountpoint. - */ - public String getVolumeState(String mountPoint) throws RemoteException; - - /** - * Checks whether the specified Opaque Binary Blob (OBB) is mounted - * somewhere. - */ - public boolean isObbMounted(String rawPath) throws RemoteException; - - /* - * Returns true if the specified container is mounted - */ - public boolean isSecureContainerMounted(String id) throws RemoteException; - - /** - * Returns true if a USB mass storage host is connected - */ - public boolean isUsbMassStorageConnected() throws RemoteException; - - /** - * Returns true if a USB mass storage host is enabled (media is shared) - */ - public boolean isUsbMassStorageEnabled() throws RemoteException; - - /** - * Mounts an Opaque Binary Blob (OBB) with the specified decryption key and - * only allows the calling process's UID access to the contents. - * MountService will call back to the supplied IObbActionListener to inform - * it of the terminal state of the call. - */ - public void mountObb(String rawPath, String canonicalPath, String key, - IObbActionListener token, int nonce) throws RemoteException; - - /* - * Mount a secure container with the specified key and owner UID. Returns an - * int consistent with MountServiceResultCode - */ - public int mountSecureContainer(String id, String key, int ownerUid, boolean readOnly) - throws RemoteException; - - /** - * Mount external storage at given mount point. Returns an int consistent - * with MountServiceResultCode - */ - public int mountVolume(String mountPoint) throws RemoteException; - - /** - * Registers an IMountServiceListener for receiving async notifications. - */ - public void registerListener(IMountServiceListener listener) throws RemoteException; - - /* - * Rename an unmounted secure container. Returns an int consistent with - * MountServiceResultCode - */ - public int renameSecureContainer(String oldId, String newId) throws RemoteException; - - /** - * Enables / disables USB mass storage. The caller should check actual - * status of enabling/disabling USB mass storage via StorageEventListener. - */ - public void setUsbMassStorageEnabled(boolean enable) throws RemoteException; - - /** - * Shuts down the MountService and gracefully unmounts all external media. - * Invokes call back once the shutdown is complete. - */ - public void shutdown(IMountShutdownObserver observer) throws RemoteException; - - /** - * Unmounts an Opaque Binary Blob (OBB). When the force flag is specified, - * any program using it will be forcibly killed to unmount the image. - * MountService will call back to the supplied IObbActionListener to inform - * it of the terminal state of the call. - */ - public void unmountObb(String rawPath, boolean force, IObbActionListener token, int nonce) - throws RemoteException; - - /* - * Unount a secure container. Returns an int consistent with - * MountServiceResultCode - */ - public int unmountSecureContainer(String id, boolean force) throws RemoteException; - - /** - * Safely unmount external storage at given mount point. The unmount is an - * asynchronous operation. Applications should register StorageEventListener - * for storage related status changes. - * @param mountPoint the mount point - * @param force whether or not to forcefully unmount it (e.g. even if programs are using this - * data currently) - * @param removeEncryption whether or not encryption mapping should be removed from the volume. - * This value implies {@code force}. - */ - public void unmountVolume(String mountPoint, boolean force, boolean removeEncryption) - throws RemoteException; - - /** - * Unregisters an IMountServiceListener - */ - public void unregisterListener(IMountServiceListener listener) throws RemoteException; - - /** - * Returns whether or not the external storage is emulated. - */ - public boolean isExternalStorageEmulated() throws RemoteException; - - /** The volume is not encrypted. */ - static final int ENCRYPTION_STATE_NONE = 1; - /** The volume has been encrypted succesfully. */ - static final int ENCRYPTION_STATE_OK = 0; - /** The volume is in a bad state.*/ - static final int ENCRYPTION_STATE_ERROR_UNKNOWN = -1; - /** Encryption is incomplete */ - static final int ENCRYPTION_STATE_ERROR_INCOMPLETE = -2; - /** Encryption is incomplete and irrecoverable */ - static final int ENCRYPTION_STATE_ERROR_INCONSISTENT = -3; - /** Underlying data is corrupt */ - static final int ENCRYPTION_STATE_ERROR_CORRUPT = -4; - - /** - * Determines the encryption state of the volume. - * @return a numerical value. See {@code ENCRYPTION_STATE_*} for possible values. - */ - public int getEncryptionState() throws RemoteException; - - /** - * Decrypts any encrypted volumes. - */ - public int decryptStorage(String password) throws RemoteException; - - /** - * Encrypts storage. - */ - public int encryptStorage(int type, String password) throws RemoteException; - - /** - * Changes the encryption password. - */ - public int changeEncryptionPassword(int type, String password) - throws RemoteException; - - /** - * Verify the encryption password against the stored volume. This method - * may only be called by the system process. - */ - public int verifyEncryptionPassword(String password) throws RemoteException; - - /** - * Returns list of all mountable volumes. - */ - public StorageVolume[] getVolumeList() throws RemoteException; - - /** - * Gets the path on the filesystem for the ASEC container itself. - * - * @param cid ASEC container ID - * @return path to filesystem or {@code null} if it's not found - * @throws RemoteException - */ - public String getSecureContainerFilesystemPath(String cid) throws RemoteException; - - /* - * Fix permissions in a container which has just been created and populated. - * Returns an int consistent with MountServiceResultCode - */ - public int fixPermissionsSecureContainer(String id, int gid, String filename) - throws RemoteException; - - /** - * Ensure that all directories along given path exist, creating parent - * directories as needed. Validates that given path is absolute and that it - * contains no relative "." or ".." paths or symlinks. Also ensures that - * path belongs to a volume managed by vold, and that path is either - * external storage data or OBB directory belonging to calling app. - */ - public int mkdirs(String callingPkg, String path) throws RemoteException; - - /** - * Determines the type of the encryption password - * @return PasswordType - */ - public int getPasswordType() throws RemoteException; - - /** - * Get password from vold - * @return password or empty string - */ - public String getPassword() throws RemoteException; - - /** - * Securely clear password from vold - */ - public void clearPassword() throws RemoteException; - - /** - * Set a field in the crypto header. - * @param field field to set - * @param contents contents to set in field - */ - public void setField(String field, String contents) throws RemoteException; - - /** - * Gets a field from the crypto header. - * @param field field to get - * @return contents of field - */ - public String getField(String field) throws RemoteException; - - public int resizeSecureContainer(String id, int sizeMb, String key) throws RemoteException; - - /** - * Report the time of the last maintenance operation such as fstrim. - * @return Timestamp of the last maintenance operation, in the - * System.currentTimeMillis() time base - * @throws RemoteException - */ - public long lastMaintenance() throws RemoteException; - - /** - * Kick off an immediate maintenance operation - * @throws RemoteException - */ - public void runMaintenance() throws RemoteException; -} diff --git a/src/main/java/android/os/storage/IMountServiceListener.java b/src/main/java/android/os/storage/IMountServiceListener.java deleted file mode 100644 index d5c5fa5..0000000 --- a/src/main/java/android/os/storage/IMountServiceListener.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os.storage; - -import android.os.Binder; -import android.os.IBinder; -import android.os.IInterface; -import android.os.Parcel; -import android.os.RemoteException; - -/** - * Callback class for receiving events from MountService. - * - * @hide - Applications should use IStorageEventListener for storage event - * callbacks. - */ -public interface IMountServiceListener extends IInterface { - /** Local-side IPC implementation stub class. */ - public static abstract class Stub extends Binder implements IMountServiceListener { - private static final String DESCRIPTOR = "IMountServiceListener"; - - /** Construct the stub at attach it to the interface. */ - public Stub() { - this.attachInterface(this, DESCRIPTOR); - } - - /** - * Cast an IBinder object into an IMountServiceListener interface, - * generating a proxy if needed. - */ - public static IMountServiceListener asInterface(IBinder obj) { - if ((obj == null)) { - return null; - } - IInterface iin = (IInterface) obj.queryLocalInterface(DESCRIPTOR); - if (((iin != null) && (iin instanceof IMountServiceListener))) { - return ((IMountServiceListener) iin); - } - return new IMountServiceListener.Stub.Proxy(obj); - } - - public IBinder asBinder() { - return this; - } - - @Override - public boolean onTransact(int code, Parcel data, Parcel reply, int flags) - throws RemoteException { - switch (code) { - case INTERFACE_TRANSACTION: { - reply.writeString(DESCRIPTOR); - return true; - } - case TRANSACTION_onUsbMassStorageConnectionChanged: { - data.enforceInterface(DESCRIPTOR); - boolean connected; - connected = (0 != data.readInt()); - this.onUsbMassStorageConnectionChanged(connected); - reply.writeNoException(); - return true; - } - case TRANSACTION_onStorageStateChanged: { - data.enforceInterface(DESCRIPTOR); - String path; - path = data.readString(); - String oldState; - oldState = data.readString(); - String newState; - newState = data.readString(); - this.onStorageStateChanged(path, oldState, newState); - reply.writeNoException(); - return true; - } - } - return super.onTransact(code, data, reply, flags); - } - - private static class Proxy implements IMountServiceListener { - private IBinder mRemote; - - Proxy(IBinder remote) { - mRemote = remote; - } - - public IBinder asBinder() { - return mRemote; - } - - public String getInterfaceDescriptor() { - return DESCRIPTOR; - } - - /** - * Detection state of USB Mass Storage has changed - * - * @param available true if a UMS host is connected. - */ - public void onUsbMassStorageConnectionChanged(boolean connected) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeInt(((connected) ? (1) : (0))); - mRemote.transact(Stub.TRANSACTION_onUsbMassStorageConnectionChanged, _data, - _reply, 0); - _reply.readException(); - } finally { - _reply.recycle(); - _data.recycle(); - } - } - - /** - * Storage state has changed. - * - * @param path The volume mount path. - * @param oldState The old state of the volume. - * @param newState The new state of the volume. Note: State is one - * of the values returned by - * Environment.getExternalStorageState() - */ - public void onStorageStateChanged(String path, String oldState, String newState) - throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(path); - _data.writeString(oldState); - _data.writeString(newState); - mRemote.transact(Stub.TRANSACTION_onStorageStateChanged, _data, _reply, 0); - _reply.readException(); - } finally { - _reply.recycle(); - _data.recycle(); - } - } - } - - static final int TRANSACTION_onUsbMassStorageConnectionChanged = (IBinder.FIRST_CALL_TRANSACTION + 0); - - static final int TRANSACTION_onStorageStateChanged = (IBinder.FIRST_CALL_TRANSACTION + 1); - } - - /** - * Detection state of USB Mass Storage has changed - * - * @param available true if a UMS host is connected. - */ - public void onUsbMassStorageConnectionChanged(boolean connected) throws RemoteException; - - /** - * Storage state has changed. - * - * @param path The volume mount path. - * @param oldState The old state of the volume. - * @param newState The new state of the volume. Note: State is one of the - * values returned by Environment.getExternalStorageState() - */ - public void onStorageStateChanged(String path, String oldState, String newState) - throws RemoteException; -} diff --git a/src/main/java/android/os/storage/IMountShutdownObserver.java b/src/main/java/android/os/storage/IMountShutdownObserver.java deleted file mode 100644 index d946e1a..0000000 --- a/src/main/java/android/os/storage/IMountShutdownObserver.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os.storage; - -import android.os.Binder; -import android.os.IBinder; -import android.os.IInterface; -import android.os.Parcel; -import android.os.RemoteException; - -/** - * Callback class for receiving events related to shutdown. - * - * @hide - For internal consumption only. - */ -public interface IMountShutdownObserver extends IInterface { - /** Local-side IPC implementation stub class. */ - public static abstract class Stub extends Binder implements IMountShutdownObserver { - private static final java.lang.String DESCRIPTOR = "IMountShutdownObserver"; - - /** Construct the stub at attach it to the interface. */ - public Stub() { - this.attachInterface(this, DESCRIPTOR); - } - - /** - * Cast an IBinder object into an IMountShutdownObserver interface, - * generating a proxy if needed. - */ - public static IMountShutdownObserver asInterface(IBinder obj) { - if ((obj == null)) { - return null; - } - IInterface iin = (IInterface) obj.queryLocalInterface(DESCRIPTOR); - if (((iin != null) && (iin instanceof IMountShutdownObserver))) { - return ((IMountShutdownObserver) iin); - } - return new IMountShutdownObserver.Stub.Proxy(obj); - } - - public IBinder asBinder() { - return this; - } - - @Override - public boolean onTransact(int code, Parcel data, Parcel reply, int flags) - throws RemoteException { - switch (code) { - case INTERFACE_TRANSACTION: { - reply.writeString(DESCRIPTOR); - return true; - } - case TRANSACTION_onShutDownComplete: { - data.enforceInterface(DESCRIPTOR); - int statusCode; - statusCode = data.readInt(); - this.onShutDownComplete(statusCode); - reply.writeNoException(); - return true; - } - } - return super.onTransact(code, data, reply, flags); - } - - private static class Proxy implements IMountShutdownObserver { - private IBinder mRemote; - - Proxy(IBinder remote) { - mRemote = remote; - } - - public IBinder asBinder() { - return mRemote; - } - - public java.lang.String getInterfaceDescriptor() { - return DESCRIPTOR; - } - - /** - * This method is called when the shutdown of MountService - * completed. - * - * @param statusCode indicates success or failure of the shutdown. - */ - public void onShutDownComplete(int statusCode) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeInt(statusCode); - mRemote.transact(Stub.TRANSACTION_onShutDownComplete, _data, _reply, 0); - _reply.readException(); - } finally { - _reply.recycle(); - _data.recycle(); - } - } - } - - static final int TRANSACTION_onShutDownComplete = (IBinder.FIRST_CALL_TRANSACTION + 0); - } - - /** - * This method is called when the shutdown of MountService completed. - * - * @param statusCode indicates success or failure of the shutdown. - */ - public void onShutDownComplete(int statusCode) throws RemoteException; -} diff --git a/src/main/java/android/os/storage/IObbActionListener.java b/src/main/java/android/os/storage/IObbActionListener.java deleted file mode 100644 index 35da4b0..0000000 --- a/src/main/java/android/os/storage/IObbActionListener.java +++ /dev/null @@ -1,136 +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.os.storage; - -import android.os.Binder; -import android.os.IBinder; -import android.os.IInterface; -import android.os.Parcel; -import android.os.RemoteException; - -/** - * Callback class for receiving events from MountService about Opaque Binary - * Blobs (OBBs). - * - * @hide - Applications should use StorageManager to interact with OBBs. - */ -public interface IObbActionListener extends IInterface { - /** Local-side IPC implementation stub class. */ - public static abstract class Stub extends Binder implements IObbActionListener { - private static final String DESCRIPTOR = "IObbActionListener"; - - /** Construct the stub at attach it to the interface. */ - public Stub() { - this.attachInterface(this, DESCRIPTOR); - } - - /** - * Cast an IBinder object into an IObbActionListener interface, - * generating a proxy if needed. - */ - public static IObbActionListener asInterface(IBinder obj) { - if ((obj == null)) { - return null; - } - IInterface iin = (IInterface) obj.queryLocalInterface(DESCRIPTOR); - if (((iin != null) && (iin instanceof IObbActionListener))) { - return ((IObbActionListener) iin); - } - return new IObbActionListener.Stub.Proxy(obj); - } - - public IBinder asBinder() { - return this; - } - - @Override - public boolean onTransact(int code, Parcel data, Parcel reply, int flags) - throws RemoteException { - switch (code) { - case INTERFACE_TRANSACTION: { - reply.writeString(DESCRIPTOR); - return true; - } - case TRANSACTION_onObbResult: { - data.enforceInterface(DESCRIPTOR); - String filename; - filename = data.readString(); - int nonce; - nonce = data.readInt(); - int status; - status = data.readInt(); - this.onObbResult(filename, nonce, status); - reply.writeNoException(); - return true; - } - } - return super.onTransact(code, data, reply, flags); - } - - private static class Proxy implements IObbActionListener { - private IBinder mRemote; - - Proxy(IBinder remote) { - mRemote = remote; - } - - public IBinder asBinder() { - return mRemote; - } - - public String getInterfaceDescriptor() { - return DESCRIPTOR; - } - - /** - * Return from an OBB action result. - * - * @param filename the path to the OBB the operation was performed - * on - * @param returnCode status of the operation - */ - public void onObbResult(String filename, int nonce, int status) - throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(filename); - _data.writeInt(nonce); - _data.writeInt(status); - mRemote.transact(Stub.TRANSACTION_onObbResult, _data, _reply, - android.os.IBinder.FLAG_ONEWAY); - _reply.readException(); - } finally { - _reply.recycle(); - _data.recycle(); - } - } - } - - static final int TRANSACTION_onObbResult = (IBinder.FIRST_CALL_TRANSACTION + 0); - } - - /** - * Return from an OBB action result. - * - * @param filename the path to the OBB the operation was performed on - * @param nonce identifier that is meaningful to the receiver - * @param status status code as defined in {@link OnObbStateChangeListener} - */ - public void onObbResult(String filename, int nonce, int status) throws RemoteException; -} diff --git a/src/main/java/android/os/storage/MountServiceListener.java b/src/main/java/android/os/storage/MountServiceListener.java deleted file mode 100644 index bebb3f6..0000000 --- a/src/main/java/android/os/storage/MountServiceListener.java +++ /dev/null @@ -1,44 +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.os.storage; - -/** - * Callback class for receiving progress reports during a restore operation. These - * methods will all be called on your application's main thread. - * @hide - */ -public abstract class MountServiceListener { - /** - * USB Mass storage connection state has changed. - * - * @param connected True if UMS is connected. - */ - void onUsbMassStorageConnectionChanged(boolean connected) { - } - - /** - * Storage state has changed. - * - * @param path The volume mount path. - * @param oldState The old state of the volume. - * @param newState The new state of the volume. - * - * @Note: State is one of the values returned by Environment.getExternalStorageState() - */ - void onStorageStateChange(String path, String oldState, String newState) { - } -} diff --git a/src/main/java/android/os/storage/OnObbStateChangeListener.java b/src/main/java/android/os/storage/OnObbStateChangeListener.java deleted file mode 100644 index 1fb1782..0000000 --- a/src/main/java/android/os/storage/OnObbStateChangeListener.java +++ /dev/null @@ -1,85 +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.os.storage; - -/** - * Used for receiving notifications from {@link StorageManager} about OBB file - * states. - */ -public abstract class OnObbStateChangeListener { - - /** - * The OBB container is now mounted and ready for use. Returned in status - * messages from calls made via {@link StorageManager} - */ - public static final int MOUNTED = 1; - - /** - * The OBB container is now unmounted and not usable. Returned in status - * messages from calls made via {@link StorageManager} - */ - public static final int UNMOUNTED = 2; - - /** - * There was an internal system error encountered while trying to mount the - * OBB. Returned in status messages from calls made via - * {@link StorageManager} - */ - public static final int ERROR_INTERNAL = 20; - - /** - * The OBB could not be mounted by the system. Returned in status messages - * from calls made via {@link StorageManager} - */ - public static final int ERROR_COULD_NOT_MOUNT = 21; - - /** - * The OBB could not be unmounted. This most likely indicates that a file is - * in use on the OBB. Returned in status messages from calls made via - * {@link StorageManager} - */ - public static final int ERROR_COULD_NOT_UNMOUNT = 22; - - /** - * A call was made to unmount the OBB when it was not mounted. Returned in - * status messages from calls made via {@link StorageManager} - */ - public static final int ERROR_NOT_MOUNTED = 23; - - /** - * The OBB has already been mounted. Returned in status messages from calls - * made via {@link StorageManager} - */ - public static final int ERROR_ALREADY_MOUNTED = 24; - - /** - * The current application does not have permission to use this OBB. This - * could be because the OBB indicates it's owned by a different package or - * some other error. Returned in status messages from calls made via - * {@link StorageManager} - */ - public static final int ERROR_PERMISSION_DENIED = 25; - - /** - * Called when an OBB has changed states. - * - * @param path path to the OBB file the state change has happened on - * @param state the current state of the OBB - */ - public void onObbStateChange(String path, int state) { - } -} diff --git a/src/main/java/android/os/storage/StorageEventListener.java b/src/main/java/android/os/storage/StorageEventListener.java deleted file mode 100644 index 6c73d04..0000000 --- a/src/main/java/android/os/storage/StorageEventListener.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os.storage; - -/** - * Used for receiving notifications from the StorageManager - * - * @hide - */ -public abstract class StorageEventListener { - /** - * Called when the detection state of a USB Mass Storage host has changed. - * @param connected true if the USB mass storage is connected. - */ - public void onUsbMassStorageConnectionChanged(boolean connected) { - } - - /** - * Called when storage has changed state - * @param path the filesystem path for the storage - * @param oldState the old state as returned by {@link android.os.Environment#getExternalStorageState()}. - * @param newState the old state as returned by {@link android.os.Environment#getExternalStorageState()}. - */ - public void onStorageStateChanged(String path, String oldState, String newState) { - } -} diff --git a/src/main/java/android/os/storage/StorageListener.java b/src/main/java/android/os/storage/StorageListener.java deleted file mode 100644 index 6a26b88..0000000 --- a/src/main/java/android/os/storage/StorageListener.java +++ /dev/null @@ -1,48 +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.os.storage; - -import android.util.Log; - -public class StorageListener extends StorageEventListener { - private static final boolean localLOGV = true; - - public static final String TAG = "StorageListener"; - - private String mTargetState; - private boolean doneFlag = false; - - public StorageListener(String targetState) { - mTargetState = targetState; - } - - @Override - public void onStorageStateChanged(String path, String oldState, String newState) { - if (localLOGV) Log.i(TAG, "Storage state changed from " + oldState + " to " + newState); - - synchronized (this) { - if (mTargetState.equals(newState)) { - doneFlag = true; - notifyAll(); - } - } - } - - public boolean isDone() { - return doneFlag; - } -} diff --git a/src/main/java/android/os/storage/StorageManager.java b/src/main/java/android/os/storage/StorageManager.java deleted file mode 100644 index 2785ee8..0000000 --- a/src/main/java/android/os/storage/StorageManager.java +++ /dev/null @@ -1,676 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os.storage; - -import static android.net.TrafficStats.MB_IN_BYTES; - -import android.content.ContentResolver; -import android.content.Context; -import android.os.Environment; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.os.Parcelable; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.provider.Settings; -import android.util.Log; -import android.util.SparseArray; - -import com.android.internal.util.Preconditions; - -import java.io.File; -import java.io.IOException; -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * StorageManager is the interface to the systems storage service. The storage - * manager handles storage-related items such as Opaque Binary Blobs (OBBs). - *

    - * OBBs contain a filesystem that maybe be encrypted on disk and mounted - * on-demand from an application. OBBs are a good way of providing large amounts - * of binary assets without packaging them into APKs as they may be multiple - * gigabytes in size. However, due to their size, they're most likely stored in - * a shared storage pool accessible from all programs. The system does not - * guarantee the security of the OBB file itself: if any program modifies the - * OBB, there is no guarantee that a read from that OBB will produce the - * expected output. - *

    - * Get an instance of this class by calling - * {@link android.content.Context#getSystemService(java.lang.String)} with an - * argument of {@link android.content.Context#STORAGE_SERVICE}. - */ -public class StorageManager { - private static final String TAG = "StorageManager"; - - private final ContentResolver mResolver; - - /* - * Our internal MountService binder reference - */ - private final IMountService mMountService; - - /* - * The looper target for callbacks - */ - private final Looper mTgtLooper; - - /* - * Target listener for binder callbacks - */ - private MountServiceBinderListener mBinderListener; - - /* - * List of our listeners - */ - private List mListeners = new ArrayList(); - - /* - * Next available nonce - */ - final private AtomicInteger mNextNonce = new AtomicInteger(0); - - private class MountServiceBinderListener extends IMountServiceListener.Stub { - public void onUsbMassStorageConnectionChanged(boolean available) { - final int size = mListeners.size(); - for (int i = 0; i < size; i++) { - mListeners.get(i).sendShareAvailabilityChanged(available); - } - } - - public void onStorageStateChanged(String path, String oldState, String newState) { - final int size = mListeners.size(); - for (int i = 0; i < size; i++) { - mListeners.get(i).sendStorageStateChanged(path, oldState, newState); - } - } - } - - /** - * Binder listener for OBB action results. - */ - private final ObbActionListener mObbActionListener = new ObbActionListener(); - - private class ObbActionListener extends IObbActionListener.Stub { - @SuppressWarnings("hiding") - private SparseArray mListeners = new SparseArray(); - - @Override - public void onObbResult(String filename, int nonce, int status) { - final ObbListenerDelegate delegate; - synchronized (mListeners) { - delegate = mListeners.get(nonce); - if (delegate != null) { - mListeners.remove(nonce); - } - } - - if (delegate != null) { - delegate.sendObbStateChanged(filename, status); - } - } - - public int addListener(OnObbStateChangeListener listener) { - final ObbListenerDelegate delegate = new ObbListenerDelegate(listener); - - synchronized (mListeners) { - mListeners.put(delegate.nonce, delegate); - } - - return delegate.nonce; - } - } - - private int getNextNonce() { - return mNextNonce.getAndIncrement(); - } - - /** - * Private class containing sender and receiver code for StorageEvents. - */ - private class ObbListenerDelegate { - private final WeakReference mObbEventListenerRef; - private final Handler mHandler; - - private final int nonce; - - ObbListenerDelegate(OnObbStateChangeListener listener) { - nonce = getNextNonce(); - mObbEventListenerRef = new WeakReference(listener); - mHandler = new Handler(mTgtLooper) { - @Override - public void handleMessage(Message msg) { - final OnObbStateChangeListener changeListener = getListener(); - if (changeListener == null) { - return; - } - - StorageEvent e = (StorageEvent) msg.obj; - - if (msg.what == StorageEvent.EVENT_OBB_STATE_CHANGED) { - ObbStateChangedStorageEvent ev = (ObbStateChangedStorageEvent) e; - changeListener.onObbStateChange(ev.path, ev.state); - } else { - Log.e(TAG, "Unsupported event " + msg.what); - } - } - }; - } - - OnObbStateChangeListener getListener() { - if (mObbEventListenerRef == null) { - return null; - } - return mObbEventListenerRef.get(); - } - - void sendObbStateChanged(String path, int state) { - ObbStateChangedStorageEvent e = new ObbStateChangedStorageEvent(path, state); - mHandler.sendMessage(e.getMessage()); - } - } - - /** - * Message sent during an OBB status change event. - */ - private class ObbStateChangedStorageEvent extends StorageEvent { - public final String path; - - public final int state; - - public ObbStateChangedStorageEvent(String path, int state) { - super(EVENT_OBB_STATE_CHANGED); - this.path = path; - this.state = state; - } - } - - /** - * Private base class for messages sent between the callback thread - * and the target looper handler. - */ - private class StorageEvent { - static final int EVENT_UMS_CONNECTION_CHANGED = 1; - static final int EVENT_STORAGE_STATE_CHANGED = 2; - static final int EVENT_OBB_STATE_CHANGED = 3; - - private Message mMessage; - - public StorageEvent(int what) { - mMessage = Message.obtain(); - mMessage.what = what; - mMessage.obj = this; - } - - public Message getMessage() { - return mMessage; - } - } - - /** - * Message sent on a USB mass storage connection change. - */ - private class UmsConnectionChangedStorageEvent extends StorageEvent { - public boolean available; - - public UmsConnectionChangedStorageEvent(boolean a) { - super(EVENT_UMS_CONNECTION_CHANGED); - available = a; - } - } - - /** - * Message sent on volume state change. - */ - private class StorageStateChangedStorageEvent extends StorageEvent { - public String path; - public String oldState; - public String newState; - - public StorageStateChangedStorageEvent(String p, String oldS, String newS) { - super(EVENT_STORAGE_STATE_CHANGED); - path = p; - oldState = oldS; - newState = newS; - } - } - - /** - * Private class containing sender and receiver code for StorageEvents. - */ - private class ListenerDelegate { - final StorageEventListener mStorageEventListener; - private final Handler mHandler; - - ListenerDelegate(StorageEventListener listener) { - mStorageEventListener = listener; - mHandler = new Handler(mTgtLooper) { - @Override - public void handleMessage(Message msg) { - StorageEvent e = (StorageEvent) msg.obj; - - if (msg.what == StorageEvent.EVENT_UMS_CONNECTION_CHANGED) { - UmsConnectionChangedStorageEvent ev = (UmsConnectionChangedStorageEvent) e; - mStorageEventListener.onUsbMassStorageConnectionChanged(ev.available); - } else if (msg.what == StorageEvent.EVENT_STORAGE_STATE_CHANGED) { - StorageStateChangedStorageEvent ev = (StorageStateChangedStorageEvent) e; - mStorageEventListener.onStorageStateChanged(ev.path, ev.oldState, ev.newState); - } else { - Log.e(TAG, "Unsupported event " + msg.what); - } - } - }; - } - - StorageEventListener getListener() { - return mStorageEventListener; - } - - void sendShareAvailabilityChanged(boolean available) { - UmsConnectionChangedStorageEvent e = new UmsConnectionChangedStorageEvent(available); - mHandler.sendMessage(e.getMessage()); - } - - void sendStorageStateChanged(String path, String oldState, String newState) { - StorageStateChangedStorageEvent e = new StorageStateChangedStorageEvent(path, oldState, newState); - mHandler.sendMessage(e.getMessage()); - } - } - - /** {@hide} */ - public static StorageManager from(Context context) { - return (StorageManager) context.getSystemService(Context.STORAGE_SERVICE); - } - - /** - * Constructs a StorageManager object through which an application can - * can communicate with the systems mount service. - * - * @param tgtLooper The {@link android.os.Looper} which events will be received on. - * - *

    Applications can get instance of this class by calling - * {@link android.content.Context#getSystemService(java.lang.String)} with an argument - * of {@link android.content.Context#STORAGE_SERVICE}. - * - * @hide - */ - public StorageManager(ContentResolver resolver, Looper tgtLooper) throws RemoteException { - mResolver = resolver; - mTgtLooper = tgtLooper; - mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount")); - if (mMountService == null) { - Log.e(TAG, "Unable to connect to mount service! - is it running yet?"); - return; - } - } - - /** - * Registers a {@link android.os.storage.StorageEventListener StorageEventListener}. - * - * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object. - * - * @hide - */ - public void registerListener(StorageEventListener listener) { - if (listener == null) { - return; - } - - synchronized (mListeners) { - if (mBinderListener == null ) { - try { - mBinderListener = new MountServiceBinderListener(); - mMountService.registerListener(mBinderListener); - } catch (RemoteException rex) { - Log.e(TAG, "Register mBinderListener failed"); - return; - } - } - mListeners.add(new ListenerDelegate(listener)); - } - } - - /** - * Unregisters a {@link android.os.storage.StorageEventListener StorageEventListener}. - * - * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object. - * - * @hide - */ - public void unregisterListener(StorageEventListener listener) { - if (listener == null) { - return; - } - - synchronized (mListeners) { - final int size = mListeners.size(); - for (int i=0 ; ikey is - * specified, it is supplied to the mounting process to be used in any - * encryption used in the OBB. - *

    - * The OBB will remain mounted for as long as the StorageManager reference - * is held by the application. As soon as this reference is lost, the OBBs - * in use will be unmounted. The {@link OnObbStateChangeListener} registered - * with this call will receive the success or failure of this operation. - *

    - * Note: you can only mount OBB files for which the OBB tag on the - * file matches a package ID that is owned by the calling program's UID. - * That is, shared UID applications can attempt to mount any other - * application's OBB that shares its UID. - * - * @param rawPath the path to the OBB file - * @param key secret used to encrypt the OBB; may be null if no - * encryption was used on the OBB. - * @param listener will receive the success or failure of the operation - * @return whether the mount call was successfully queued or not - */ - public boolean mountObb(String rawPath, String key, OnObbStateChangeListener listener) { - Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); - Preconditions.checkNotNull(listener, "listener cannot be null"); - - try { - final String canonicalPath = new File(rawPath).getCanonicalPath(); - final int nonce = mObbActionListener.addListener(listener); - mMountService.mountObb(rawPath, canonicalPath, key, mObbActionListener, nonce); - return true; - } catch (IOException e) { - throw new IllegalArgumentException("Failed to resolve path: " + rawPath, e); - } catch (RemoteException e) { - Log.e(TAG, "Failed to mount OBB", e); - } - - return false; - } - - /** - * Unmount an Opaque Binary Blob (OBB) file asynchronously. If the - * force flag is true, it will kill any application needed to - * unmount the given OBB (even the calling application). - *

    - * The {@link OnObbStateChangeListener} registered with this call will - * receive the success or failure of this operation. - *

    - * Note: you can only mount OBB files for which the OBB tag on the - * file matches a package ID that is owned by the calling program's UID. - * That is, shared UID applications can obtain access to any other - * application's OBB that shares its UID. - *

    - * - * @param rawPath path to the OBB file - * @param force whether to kill any programs using this in order to unmount - * it - * @param listener will receive the success or failure of the operation - * @return whether the unmount call was successfully queued or not - */ - public boolean unmountObb(String rawPath, boolean force, OnObbStateChangeListener listener) { - Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); - Preconditions.checkNotNull(listener, "listener cannot be null"); - - try { - final int nonce = mObbActionListener.addListener(listener); - mMountService.unmountObb(rawPath, force, mObbActionListener, nonce); - return true; - } catch (RemoteException e) { - Log.e(TAG, "Failed to mount OBB", e); - } - - return false; - } - - /** - * Check whether an Opaque Binary Blob (OBB) is mounted or not. - * - * @param rawPath path to OBB image - * @return true if OBB is mounted; false if not mounted or on error - */ - public boolean isObbMounted(String rawPath) { - Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); - - try { - return mMountService.isObbMounted(rawPath); - } catch (RemoteException e) { - Log.e(TAG, "Failed to check if OBB is mounted", e); - } - - return false; - } - - /** - * Check the mounted path of an Opaque Binary Blob (OBB) file. This will - * give you the path to where you can obtain access to the internals of the - * OBB. - * - * @param rawPath path to OBB image - * @return absolute path to mounted OBB image data or null if - * not mounted or exception encountered trying to read status - */ - public String getMountedObbPath(String rawPath) { - Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); - - try { - return mMountService.getMountedObbPath(rawPath); - } catch (RemoteException e) { - Log.e(TAG, "Failed to find mounted path for OBB", e); - } - - return null; - } - - /** - * Gets the state of a volume via its mountpoint. - * @hide - */ - public String getVolumeState(String mountPoint) { - if (mMountService == null) return Environment.MEDIA_REMOVED; - try { - return mMountService.getVolumeState(mountPoint); - } catch (RemoteException e) { - Log.e(TAG, "Failed to get volume state", e); - return null; - } - } - - /** - * Returns list of all mountable volumes. - * @hide - */ - public StorageVolume[] getVolumeList() { - if (mMountService == null) return new StorageVolume[0]; - try { - Parcelable[] list = mMountService.getVolumeList(); - if (list == null) return new StorageVolume[0]; - int length = list.length; - StorageVolume[] result = new StorageVolume[length]; - for (int i = 0; i < length; i++) { - result[i] = (StorageVolume)list[i]; - } - return result; - } catch (RemoteException e) { - Log.e(TAG, "Failed to get volume list", e); - return null; - } - } - - /** - * Returns list of paths for all mountable volumes. - * @hide - */ - public String[] getVolumePaths() { - StorageVolume[] volumes = getVolumeList(); - if (volumes == null) return null; - int count = volumes.length; - String[] paths = new String[count]; - for (int i = 0; i < count; i++) { - paths[i] = volumes[i].getPath(); - } - return paths; - } - - /** {@hide} */ - public StorageVolume getPrimaryVolume() { - return getPrimaryVolume(getVolumeList()); - } - - /** {@hide} */ - public static StorageVolume getPrimaryVolume(StorageVolume[] volumes) { - for (StorageVolume volume : volumes) { - if (volume.isPrimary()) { - return volume; - } - } - Log.w(TAG, "No primary storage defined"); - return null; - } - - private static final int DEFAULT_THRESHOLD_PERCENTAGE = 10; - private static final long DEFAULT_THRESHOLD_MAX_BYTES = 500 * MB_IN_BYTES; - private static final long DEFAULT_FULL_THRESHOLD_BYTES = MB_IN_BYTES; - - /** - * Return the number of available bytes until the given path is considered - * running low on storage. - * - * @hide - */ - public long getStorageBytesUntilLow(File path) { - return path.getUsableSpace() - getStorageFullBytes(path); - } - - /** - * Return the number of available bytes at which the given path is - * considered running low on storage. - * - * @hide - */ - public long getStorageLowBytes(File path) { - final long lowPercent = Settings.Global.getInt(mResolver, - Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE, DEFAULT_THRESHOLD_PERCENTAGE); - final long lowBytes = (path.getTotalSpace() * lowPercent) / 100; - - final long maxLowBytes = Settings.Global.getLong(mResolver, - Settings.Global.SYS_STORAGE_THRESHOLD_MAX_BYTES, DEFAULT_THRESHOLD_MAX_BYTES); - - return Math.min(lowBytes, maxLowBytes); - } - - /** - * Return the number of available bytes at which the given path is - * considered full. - * - * @hide - */ - public long getStorageFullBytes(File path) { - return Settings.Global.getLong(mResolver, Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES, - DEFAULT_FULL_THRESHOLD_BYTES); - } - - /// Consts to match the password types in cryptfs.h - /** @hide */ - public static final int CRYPT_TYPE_PASSWORD = 0; - /** @hide */ - public static final int CRYPT_TYPE_DEFAULT = 1; - /** @hide */ - public static final int CRYPT_TYPE_PATTERN = 2; - /** @hide */ - public static final int CRYPT_TYPE_PIN = 3; - - // Constants for the data available via MountService.getField. - /** @hide */ - public static final String SYSTEM_LOCALE_KEY = "SystemLocale"; - /** @hide */ - public static final String OWNER_INFO_KEY = "OwnerInfo"; - /** @hide */ - public static final String PATTERN_VISIBLE_KEY = "PatternVisible"; -} diff --git a/src/main/java/android/os/storage/StorageManagerBaseTest.java b/src/main/java/android/os/storage/StorageManagerBaseTest.java deleted file mode 100644 index 90cb9a5..0000000 --- a/src/main/java/android/os/storage/StorageManagerBaseTest.java +++ /dev/null @@ -1,644 +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.os.storage; - -import android.content.Context; -import android.content.res.Resources; -import android.content.res.Resources.NotFoundException; -import android.os.Environment; -import android.os.SystemClock; -import android.test.InstrumentationTestCase; -import android.util.Log; -import android.os.Environment; -import android.os.FileUtils; -import android.os.storage.OnObbStateChangeListener; -import android.os.storage.StorageManager; - -import java.io.BufferedReader; -import java.io.DataInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.InputStream; -import java.io.IOException; -import java.io.StringReader; - -public class StorageManagerBaseTest extends InstrumentationTestCase { - - protected Context mContext = null; - protected StorageManager mSm = null; - private static String LOG_TAG = "StorageManagerBaseTest"; - protected static final long MAX_WAIT_TIME = 120*1000; - protected static final long WAIT_TIME_INCR = 5*1000; - protected static String OBB_FILE_1 = "obb_file1.obb"; - protected static String OBB_FILE_1_CONTENTS_1 = "OneToOneThousandInts.bin"; - protected static String OBB_FILE_2 = "obb_file2.obb"; - protected static String OBB_FILE_3 = "obb_file3.obb"; - protected static String OBB_FILE_1_PASSWORD = "password1"; - protected static String OBB_FILE_1_ENCRYPTED = "obb_enc_file100_orig1.obb"; - protected static String OBB_FILE_2_UNSIGNED = "obb_file2_nosign.obb"; - protected static String OBB_FILE_3_PASSWORD = "password3"; - protected static String OBB_FILE_3_ENCRYPTED = "obb_enc_file100_orig3.obb"; - protected static String OBB_FILE_3_BAD_PACKAGENAME = "obb_file3_bad_packagename.obb"; - - protected static boolean FORCE = true; - protected static boolean DONT_FORCE = false; - - private static final String SAMPLE1_TEXT = "This is sample text.\n\nTesting 1 2 3."; - - private static final String SAMPLE2_TEXT = - "We the people of the United States, in order to form a more perfect union,\n" - + "establish justice, insure domestic tranquility, provide for the common\n" - + "defense, promote the general welfare, and secure the blessings of liberty\n" - + "to ourselves and our posterity, do ordain and establish this Constitution\n" - + "for the United States of America.\n\n"; - - class MountingObbThread extends Thread { - boolean mStop = false; - volatile boolean mFileOpenOnObb = false; - private String mObbFilePath = null; - private String mPathToContentsFile = null; - private String mOfficialObbFilePath = null; - - /** - * Constructor - * - * @param obbFilePath path to the OBB image file - * @param pathToContentsFile path to a file on the mounted OBB volume to open after the OBB - * has been mounted - */ - public MountingObbThread (String obbFilePath, String pathToContentsFile) { - assertTrue("obbFilePath cannot be null!", obbFilePath != null); - mObbFilePath = obbFilePath; - assertTrue("path to contents file cannot be null!", pathToContentsFile != null); - mPathToContentsFile = pathToContentsFile; - } - - /** - * Runs the thread - * - * Mounts OBB_FILE_1, and tries to open a file on the mounted OBB (specified in the - * constructor). Once it's open, it waits until someone calls its doStop(), after which it - * closes the opened file. - */ - public void run() { - // the official OBB file path and the mount-request file path should be the same, but - // let's distinguish the two as they may make for some interesting tests later - mOfficialObbFilePath = mountObb(mObbFilePath); - assertEquals("Expected and actual OBB file paths differ!", mObbFilePath, - mOfficialObbFilePath); - - // open a file on OBB 1... - DataInputStream inputFile = openFileOnMountedObb(mOfficialObbFilePath, - mPathToContentsFile); - assertTrue("Failed to open file!", inputFile != null); - - synchronized (this) { - mFileOpenOnObb = true; - notifyAll(); - } - - while (!mStop) { - try { - Thread.sleep(WAIT_TIME_INCR); - } catch (InterruptedException e) { - // nothing special to be done for interruptions - } - } - try { - inputFile.close(); - } catch (IOException e) { - fail("Failed to close file on OBB due to error: " + e.toString()); - } - } - - /** - * Tells whether a file has yet been successfully opened on the OBB or not - * - * @return true if the specified file on the OBB was opened; false otherwise - */ - public boolean isFileOpenOnObb() { - return mFileOpenOnObb; - } - - /** - * Returns the official path of the OBB file that was mounted - * - * This is not the mount path, but the normalized path to the actual OBB file - * - * @return a {@link String} representation of the path to the OBB file that was mounted - */ - public String officialObbFilePath() { - return mOfficialObbFilePath; - } - - /** - * Requests the thread to stop running - * - * Closes the opened file and returns - */ - public void doStop() { - mStop = true; - } - } - - public class ObbListener extends OnObbStateChangeListener { - private String LOG_TAG = "StorageManagerBaseTest.ObbListener"; - - String mOfficialPath = null; - boolean mDone = false; - int mState = -1; - - /** - * {@inheritDoc} - */ - @Override - public void onObbStateChange(String path, int state) { - Log.i(LOG_TAG, "Storage state changing to: " + state); - - synchronized (this) { - Log.i(LOG_TAG, "OfficialPath is now: " + path); - mState = state; - mOfficialPath = path; - mDone = true; - notifyAll(); - } - } - - /** - * Tells whether we are done or not (system told us the OBB has changed state) - * - * @return true if the system has told us this OBB's state has changed, false otherwise - */ - public boolean isDone() { - return mDone; - } - - /** - * The last state of the OBB, according to the system - * - * @return A {@link String} representation of the state of the OBB - */ - public int state() { - return mState; - } - - /** - * The normalized, official path to the OBB file (according to the system) - * - * @return A {@link String} representation of the official path to the OBB file - */ - public String officialPath() { - return mOfficialPath; - } - } - - /** - * {@inheritDoc} - */ - @Override - public void setUp() throws Exception { - mContext = getInstrumentation().getContext(); - mSm = (StorageManager)mContext.getSystemService(android.content.Context.STORAGE_SERVICE); - - } - - /** - * Helper to copy a raw resource file to an actual specified file - * - * @param rawResId The raw resource ID of the OBB resource file - * @param outFile A File representing the file we want to copy the OBB to - * @throws NotFoundException If the resource file could not be found - */ - private void copyRawToFile(int rawResId, File outFile) throws NotFoundException { - Resources res = mContext.getResources(); - InputStream is = null; - try { - is = res.openRawResource(rawResId); - } catch (NotFoundException e) { - Log.i(LOG_TAG, "Failed to load resource with id: " + rawResId); - throw e; - } - FileUtils.setPermissions(outFile.getPath(), FileUtils.S_IRWXU | FileUtils.S_IRWXG - | FileUtils.S_IRWXO, -1, -1); - assertTrue(FileUtils.copyToFile(is, outFile)); - FileUtils.setPermissions(outFile.getPath(), FileUtils.S_IRWXU | FileUtils.S_IRWXG - | FileUtils.S_IRWXO, -1, -1); - } - - /** - * Creates an OBB file (with the given name), into the app's standard files directory - * - * @param name The name of the OBB file we want to create/write to - * @param rawResId The raw resource ID of the OBB file in the package - * @return A {@link File} representing the file to write to - */ - protected File createObbFile(String name, int rawResId) { - File outFile = null; - try { - final File filesDir = mContext.getFilesDir(); - outFile = new File(filesDir, name); - copyRawToFile(rawResId, outFile); - } catch (NotFoundException e) { - if (outFile != null) { - outFile.delete(); - } - } - return outFile; - } - - /** - * Mounts an OBB file and opens a file located on it - * - * @param obbPath Path to OBB image - * @param fileName The full name and path to the file on the OBB to open once the OBB is mounted - * @return The {@link DataInputStream} representing the opened file, if successful in opening - * the file, or null of unsuccessful. - */ - protected DataInputStream openFileOnMountedObb(String obbPath, String fileName) { - - // get mSm obb mount path - assertTrue("Cannot open file when OBB is not mounted!", mSm.isObbMounted(obbPath)); - - String path = mSm.getMountedObbPath(obbPath); - assertTrue("Path should not be null!", path != null); - - File inFile = new File(path, fileName); - DataInputStream inStream = null; - try { - inStream = new DataInputStream(new FileInputStream(inFile)); - Log.i(LOG_TAG, "Opened file: " + fileName + " for read at path: " + path); - } catch (FileNotFoundException e) { - Log.e(LOG_TAG, e.toString()); - return null; - } catch (SecurityException e) { - Log.e(LOG_TAG, e.toString()); - return null; - } - return inStream; - } - - /** - * Mounts an OBB file - * - * @param obbFilePath The full path to the OBB file to mount - * @param key (optional) The key to use to unencrypt the OBB; pass null for no encryption - * @param expectedState The expected state resulting from trying to mount the OBB - * @return A {@link String} representing the normalized path to OBB file that was mounted - */ - protected String mountObb(String obbFilePath, String key, int expectedState) { - return doMountObb(obbFilePath, key, expectedState); - } - - /** - * Mounts an OBB file with default options (no encryption, mounting succeeds) - * - * @param obbFilePath The full path to the OBB file to mount - * @return A {@link String} representing the normalized path to OBB file that was mounted - */ - protected String mountObb(String obbFilePath) { - return doMountObb(obbFilePath, null, OnObbStateChangeListener.MOUNTED); - } - - /** - * Synchronously waits for an OBB listener to be signaled of a state change, but does not throw - * - * @param obbListener The listener for the OBB file - * @return true if the listener was signaled of a state change by the system, else returns - * false if we time out. - */ - protected boolean doWaitForObbStateChange(ObbListener obbListener) { - synchronized(obbListener) { - long waitTimeMillis = 0; - while (!obbListener.isDone()) { - try { - Log.i(LOG_TAG, "Waiting for listener..."); - obbListener.wait(WAIT_TIME_INCR); - Log.i(LOG_TAG, "Awoke from waiting for listener..."); - waitTimeMillis += WAIT_TIME_INCR; - if (waitTimeMillis > MAX_WAIT_TIME) { - fail("Timed out waiting for OBB state to change!"); - } - } catch (InterruptedException e) { - Log.i(LOG_TAG, e.toString()); - } - } - return obbListener.isDone(); - } - } - - /** - * Synchronously waits for an OBB listener to be signaled of a state change - * - * @param obbListener The listener for the OBB file - * @return true if the listener was signaled of a state change by the system; else a fail() - * is triggered if we timed out - */ - protected String doMountObb_noThrow(String obbFilePath, String key, int expectedState) { - Log.i(LOG_TAG, "doMountObb() on " + obbFilePath + " using key: " + key); - assertTrue ("Null path was passed in for OBB file!", obbFilePath != null); - assertTrue ("Null path was passed in for OBB file!", obbFilePath != null); - - ObbListener obbListener = new ObbListener(); - boolean success = mSm.mountObb(obbFilePath, key, obbListener); - success &= obbFilePath.equals(doWaitForObbStateChange(obbListener)); - success &= (expectedState == obbListener.state()); - - if (OnObbStateChangeListener.MOUNTED == expectedState) { - success &= obbFilePath.equals(obbListener.officialPath()); - success &= mSm.isObbMounted(obbListener.officialPath()); - } else { - success &= !mSm.isObbMounted(obbListener.officialPath()); - } - - if (success) { - return obbListener.officialPath(); - } else { - return null; - } - } - - /** - * Mounts an OBB file without throwing and synchronously waits for it to finish mounting - * - * @param obbFilePath The full path to the OBB file to mount - * @param key (optional) The key to use to unencrypt the OBB; pass null for no encryption - * @param expectedState The expected state resulting from trying to mount the OBB - * @return A {@link String} representing the actual normalized path to OBB file that was - * mounted, or null if the mounting failed - */ - protected String doMountObb(String obbFilePath, String key, int expectedState) { - Log.i(LOG_TAG, "doMountObb() on " + obbFilePath + " using key: " + key); - assertTrue ("Null path was passed in for OBB file!", obbFilePath != null); - - ObbListener obbListener = new ObbListener(); - assertTrue("mountObb call failed", mSm.mountObb(obbFilePath, key, obbListener)); - assertTrue("Failed to get OBB mount status change for file: " + obbFilePath, - doWaitForObbStateChange(obbListener)); - assertEquals("OBB mount state not what was expected!", expectedState, obbListener.state()); - - if (OnObbStateChangeListener.MOUNTED == expectedState) { - assertEquals(obbFilePath, obbListener.officialPath()); - assertTrue("Obb should be mounted, but SM reports it is not!", - mSm.isObbMounted(obbListener.officialPath())); - } else if (OnObbStateChangeListener.UNMOUNTED == expectedState) { - assertFalse("Obb should not be mounted, but SM reports it is!", - mSm.isObbMounted(obbListener.officialPath())); - } - - assertEquals("Mount state is not what was expected!", expectedState, obbListener.state()); - return obbListener.officialPath(); - } - - /** - * Unmounts an OBB file without throwing, and synchronously waits for it to finish unmounting - * - * @param obbFilePath The full path to the OBB file to mount - * @param force true if we shuold force the unmount, false otherwise - * @return true if the unmount was successful, false otherwise - */ - protected boolean unmountObb_noThrow(String obbFilePath, boolean force) { - Log.i(LOG_TAG, "doUnmountObb_noThrow() on " + obbFilePath); - assertTrue ("Null path was passed in for OBB file!", obbFilePath != null); - boolean success = true; - - ObbListener obbListener = new ObbListener(); - assertTrue("unmountObb call failed", mSm.unmountObb(obbFilePath, force, obbListener)); - - boolean stateChanged = doWaitForObbStateChange(obbListener); - if (force) { - success &= stateChanged; - success &= (OnObbStateChangeListener.UNMOUNTED == obbListener.state()); - success &= !mSm.isObbMounted(obbFilePath); - } - return success; - } - - /** - * Unmounts an OBB file and synchronously waits for it to finish unmounting - * - * @param obbFilePath The full path to the OBB file to mount - * @param force true if we shuold force the unmount, false otherwise - */ - protected void unmountObb(String obbFilePath, boolean force) { - Log.i(LOG_TAG, "doUnmountObb() on " + obbFilePath); - assertTrue ("Null path was passed in for OBB file!", obbFilePath != null); - - ObbListener obbListener = new ObbListener(); - assertTrue("unmountObb call failed", mSm.unmountObb(obbFilePath, force, obbListener)); - - boolean stateChanged = doWaitForObbStateChange(obbListener); - if (force) { - assertTrue("Timed out waiting to unmount OBB file " + obbFilePath, stateChanged); - assertEquals("OBB failed to unmount", OnObbStateChangeListener.UNMOUNTED, - obbListener.state()); - assertFalse("Obb should NOT be mounted, but SM reports it is!", mSm.isObbMounted( - obbFilePath)); - } - } - - /** - * Helper to validate the contents of an "int" file in an OBB. - * - * The format of the files are sequential int's, in the range of: [start..end) - * - * @param path The full path to the file (path to OBB) - * @param filename The filename containing the ints to validate - * @param start The first int expected to be found in the file - * @param end The last int + 1 expected to be found in the file - */ - protected void doValidateIntContents(String path, String filename, int start, int end) { - File inFile = new File(path, filename); - DataInputStream inStream = null; - Log.i(LOG_TAG, "Validating file " + filename + " at " + path); - try { - inStream = new DataInputStream(new FileInputStream(inFile)); - - for (int i = start; i < end; ++i) { - if (inStream.readInt() != i) { - fail("Unexpected value read in OBB file"); - } - } - if (inStream != null) { - inStream.close(); - } - Log.i(LOG_TAG, "Successfully validated file " + filename); - } catch (FileNotFoundException e) { - fail("File " + inFile + " not found: " + e.toString()); - } catch (IOException e) { - fail("IOError with file " + inFile + ":" + e.toString()); - } - } - - /** - * Helper to validate the contents of a text file in an OBB - * - * @param path The full path to the file (path to OBB) - * @param filename The filename containing the ints to validate - * @param contents A {@link String} containing the expected contents of the file - */ - protected void doValidateTextContents(String path, String filename, String contents) { - File inFile = new File(path, filename); - BufferedReader fileReader = null; - BufferedReader textReader = null; - Log.i(LOG_TAG, "Validating file " + filename + " at " + path); - try { - fileReader = new BufferedReader(new FileReader(inFile)); - textReader = new BufferedReader(new StringReader(contents)); - String actual = null; - String expected = null; - while ((actual = fileReader.readLine()) != null) { - expected = textReader.readLine(); - if (!actual.equals(expected)) { - fail("File " + filename + " in OBB " + path + " does not match expected value"); - } - } - fileReader.close(); - textReader.close(); - Log.i(LOG_TAG, "File " + filename + " successfully verified."); - } catch (IOException e) { - fail("IOError with file " + inFile + ":" + e.toString()); - } - } - - /** - * Helper to validate the contents of a "long" file on our OBBs - * - * The format of the files are sequential 0's of type long - * - * @param path The full path to the file (path to OBB) - * @param filename The filename containing the ints to validate - * @param size The number of zero's expected in the file - * @param checkContents If true, the contents of the file are actually verified; if false, - * we simply verify that the file can be opened - */ - protected void doValidateZeroLongFile(String path, String filename, long size, - boolean checkContents) { - File inFile = new File(path, filename); - DataInputStream inStream = null; - Log.i(LOG_TAG, "Validating file " + filename + " at " + path); - try { - inStream = new DataInputStream(new FileInputStream(inFile)); - - if (checkContents) { - for (long i = 0; i < size; ++i) { - if (inStream.readLong() != 0) { - fail("Unexpected value read in OBB file" + filename); - } - } - } - - if (inStream != null) { - inStream.close(); - } - Log.i(LOG_TAG, "File " + filename + " successfully verified for " + size + " zeros"); - } catch (IOException e) { - fail("IOError with file " + inFile + ":" + e.toString()); - } - } - - /** - * Helper to synchronously wait until we can get a path for a given OBB file - * - * @param filePath The full normalized path to the OBB file - * @return The mounted path of the OBB, used to access contents in it - */ - protected String doWaitForPath(String filePath) { - String path = null; - - long waitTimeMillis = 0; - assertTrue("OBB " + filePath + " is not currently mounted!", mSm.isObbMounted(filePath)); - while (path == null) { - try { - Thread.sleep(WAIT_TIME_INCR); - waitTimeMillis += WAIT_TIME_INCR; - if (waitTimeMillis > MAX_WAIT_TIME) { - fail("Timed out waiting to get path of OBB file " + filePath); - } - } catch (InterruptedException e) { - // do nothing - } - path = mSm.getMountedObbPath(filePath); - } - Log.i(LOG_TAG, "Got OBB path: " + path); - return path; - } - - /** - * Verifies the pre-defined contents of our first OBB (OBB_FILE_1) - * - * The OBB contains 4 files and no subdirectories - * - * @param filePath The normalized path to the already-mounted OBB file - */ - protected void verifyObb1Contents(String filePath) { - String path = null; - path = doWaitForPath(filePath); - - // Validate contents of 2 files in this obb - doValidateIntContents(path, "OneToOneThousandInts.bin", 0, 1000); - doValidateIntContents(path, "SevenHundredInts.bin", 0, 700); - doValidateZeroLongFile(path, "FiveLongs.bin", 5, true); - } - - /** - * Verifies the pre-defined contents of our second OBB (OBB_FILE_2) - * - * The OBB contains 2 files and no subdirectories - * - * @param filePath The normalized path to the already-mounted OBB file - */ - protected void verifyObb2Contents(String filename) { - String path = null; - path = doWaitForPath(filename); - - // Validate contents of file - doValidateTextContents(path, "sample.txt", SAMPLE1_TEXT); - doValidateTextContents(path, "sample2.txt", SAMPLE2_TEXT); - } - - /** - * Verifies the pre-defined contents of our third OBB (OBB_FILE_3) - * - * The OBB contains nested files and subdirectories - * - * @param filePath The normalized path to the already-mounted OBB file - */ - protected void verifyObb3Contents(String filename) { - String path = null; - path = doWaitForPath(filename); - - // Validate contents of file - doValidateIntContents(path, "OneToOneThousandInts.bin", 0, 1000); - doValidateZeroLongFile(path, "TwoHundredLongs", 200, true); - - // validate subdirectory 1 - doValidateZeroLongFile(path + File.separator + "subdir1", "FiftyLongs", 50, true); - - // validate subdirectory subdir2/ - doValidateIntContents(path + File.separator + "subdir2", "OneToOneThousandInts", 0, 1000); - - // validate subdirectory subdir2/subdir2a/ - doValidateZeroLongFile(path + File.separator + "subdir2" + File.separator + "subdir2a", - "TwoHundredLongs", 200, true); - - // validate subdirectory subdir2/subdir2a/subdir2a1/ - doValidateIntContents(path + File.separator + "subdir2" + File.separator + "subdir2a" - + File.separator + "subdir2a1", "OneToOneThousandInts", 0, 1000); - } -} \ No newline at end of file diff --git a/src/main/java/android/os/storage/StorageManagerIntegrationTest.java b/src/main/java/android/os/storage/StorageManagerIntegrationTest.java deleted file mode 100644 index 71772d9..0000000 --- a/src/main/java/android/os/storage/StorageManagerIntegrationTest.java +++ /dev/null @@ -1,244 +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.os.storage; - -import android.content.Context; -import android.os.Environment; -import android.test.InstrumentationTestCase; -import android.test.suitebuilder.annotation.LargeTest; -import android.util.Log; - -import com.android.frameworks.coretests.R; - -import java.io.DataInputStream; -import java.io.IOException; -import java.io.File; -import java.io.FileInputStream; - -import junit.framework.AssertionFailedError; - -public class StorageManagerIntegrationTest extends StorageManagerBaseTest { - - private static String LOG_TAG = "StorageManagerBaseTest.StorageManagerIntegrationTest"; - protected File mFile = null; - - /** - * {@inheritDoc} - */ - @Override - public void setUp() throws Exception { - super.setUp(); - mContext = getInstrumentation().getContext(); - mFile = null; - } - - /** - * {@inheritDoc} - */ - @Override - protected void tearDown() throws Exception { - if (mFile != null) { - mFile.delete(); - mFile = null; - } - super.tearDown(); - } - - /** - * Tests mounting a single OBB file and verifies its contents. - */ - @LargeTest - public void testMountSingleObb() { - mFile = createObbFile(OBB_FILE_1, R.raw.obb_file1); - String filePath = mFile.getAbsolutePath(); - mountObb(filePath); - verifyObb1Contents(filePath); - unmountObb(filePath, DONT_FORCE); - } - - /** - * Tests mounting several OBB files and verifies its contents. - */ - @LargeTest - public void testMountMultipleObb() { - File file1 = null; - File file2 = null; - File file3 = null; - try { - file1 = createObbFile(OBB_FILE_1, R.raw.obb_file1); - String filePath1 = file1.getAbsolutePath(); - mountObb(filePath1); - verifyObb1Contents(filePath1); - - file2 = createObbFile(OBB_FILE_2, R.raw.obb_file2); - String filePath2 = file2.getAbsolutePath(); - mountObb(filePath2); - verifyObb2Contents(filePath2); - - file3 = createObbFile(OBB_FILE_3, R.raw.obb_file3); - String filePath3 = file3.getAbsolutePath(); - mountObb(filePath3); - verifyObb3Contents(filePath3); - - unmountObb(filePath1, DONT_FORCE); - unmountObb(filePath2, DONT_FORCE); - unmountObb(filePath3, DONT_FORCE); - } finally { - if (file1 != null) { - file1.delete(); - } - if (file2 != null) { - file2.delete(); - } - if (file3 != null) { - file3.delete(); - } - } - } - - /** - * Tests mounting a single encrypted OBB file and verifies its contents. - */ - @LargeTest - public void testMountSingleEncryptedObb() { - mFile = createObbFile(OBB_FILE_3_ENCRYPTED, R.raw.obb_enc_file100_orig3); - String filePath = mFile.getAbsolutePath(); - mountObb(filePath, OBB_FILE_3_PASSWORD, OnObbStateChangeListener.MOUNTED); - verifyObb3Contents(filePath); - unmountObb(filePath, DONT_FORCE); - } - - /** - * Tests mounting a single encrypted OBB file using an invalid password. - */ - @LargeTest - public void testMountSingleEncryptedObbInvalidPassword() { - mFile = createObbFile("bad password@$%#@^*(!&)", R.raw.obb_enc_file100_orig3); - String filePath = mFile.getAbsolutePath(); - mountObb(filePath, OBB_FILE_3_PASSWORD, OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT); - unmountObb(filePath, DONT_FORCE); - } - - /** - * Tests simultaneously mounting 2 encrypted OBBs with different keys and verifies contents. - */ - @LargeTest - public void testMountTwoEncryptedObb() { - File file3 = null; - File file1 = null; - try { - file3 = createObbFile(OBB_FILE_3_ENCRYPTED, R.raw.obb_enc_file100_orig3); - String filePath3 = file3.getAbsolutePath(); - mountObb(filePath3, OBB_FILE_3_PASSWORD, OnObbStateChangeListener.MOUNTED); - verifyObb3Contents(filePath3); - - file1 = createObbFile(OBB_FILE_1_ENCRYPTED, R.raw.obb_enc_file100_orig1); - String filePath1 = file1.getAbsolutePath(); - mountObb(filePath1, OBB_FILE_1_PASSWORD, OnObbStateChangeListener.MOUNTED); - verifyObb1Contents(filePath1); - - unmountObb(filePath3, DONT_FORCE); - unmountObb(filePath1, DONT_FORCE); - } finally { - if (file3 != null) { - file3.delete(); - } - if (file1 != null) { - file1.delete(); - } - } - } - - /** - * Tests that we can not force unmount when a file is currently open on the OBB. - */ - @LargeTest - public void testUnmount_DontForce() { - mFile = createObbFile(OBB_FILE_1, R.raw.obb_file1); - String obbFilePath = mFile.getAbsolutePath(); - - MountingObbThread mountingThread = new MountingObbThread(obbFilePath, - OBB_FILE_1_CONTENTS_1); - - try { - mountingThread.start(); - - long waitTime = 0; - while (!mountingThread.isFileOpenOnObb()) { - synchronized (mountingThread) { - Log.i(LOG_TAG, "Waiting for file to be opened on OBB..."); - mountingThread.wait(WAIT_TIME_INCR); - waitTime += WAIT_TIME_INCR; - if (waitTime > MAX_WAIT_TIME) { - fail("Timed out waiting for file file to be opened on OBB!"); - } - } - } - - unmountObb(obbFilePath, DONT_FORCE); - - // verify still mounted - assertTrue("mounted path should not be null!", obbFilePath != null); - assertTrue("mounted path should still be mounted!", mSm.isObbMounted(obbFilePath)); - - // close the opened file - mountingThread.doStop(); - - // try unmounting again (should succeed this time) - unmountObb(obbFilePath, DONT_FORCE); - assertFalse("mounted path should no longer be mounted!", - mSm.isObbMounted(obbFilePath)); - } catch (InterruptedException e) { - fail("Timed out waiting for file on OBB to be opened..."); - } - } - - /** - * Tests mounting a single OBB that isn't signed. - */ - @LargeTest - public void testMountUnsignedObb() { - mFile = createObbFile(OBB_FILE_2_UNSIGNED, R.raw.obb_file2_nosign); - String filePath = mFile.getAbsolutePath(); - mountObb(filePath, OBB_FILE_2_UNSIGNED, OnObbStateChangeListener.ERROR_INTERNAL); - } - - /** - * Tests mounting a single OBB that is signed with a different package. - */ - @LargeTest - public void testMountBadPackageNameObb() { - mFile = createObbFile(OBB_FILE_3_BAD_PACKAGENAME, R.raw.obb_file3_bad_packagename); - String filePath = mFile.getAbsolutePath(); - mountObb(filePath, OBB_FILE_3_BAD_PACKAGENAME, - OnObbStateChangeListener.ERROR_PERMISSION_DENIED); - } - - /** - * Tests remounting a single OBB that has already been mounted. - */ - @LargeTest - public void testRemountObb() { - mFile = createObbFile(OBB_FILE_1, R.raw.obb_file1); - String filePath = mFile.getAbsolutePath(); - mountObb(filePath); - verifyObb1Contents(filePath); - mountObb(filePath, null, OnObbStateChangeListener.ERROR_ALREADY_MOUNTED); - verifyObb1Contents(filePath); - unmountObb(filePath, DONT_FORCE); - } -} \ No newline at end of file diff --git a/src/main/java/android/os/storage/StorageResultCode.java b/src/main/java/android/os/storage/StorageResultCode.java deleted file mode 100644 index 8e7db31..0000000 --- a/src/main/java/android/os/storage/StorageResultCode.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os.storage; - -/** - * Class that provides access to constants returned from StorageManager - * and lower level MountService APIs. - * - * @hide - */ -public class StorageResultCode -{ - /** - * Operation succeeded. - * @see android.os.storage.StorageManager - */ - public static final int OperationSucceeded = 0; - - /** - * Operation failed: Internal error. - * @see android.os.storage.StorageManager - */ - public static final int OperationFailedInternalError = -1; - - /** - * Operation failed: Missing media. - * @see android.os.storage.StorageManager - */ - public static final int OperationFailedNoMedia = -2; - - /** - * Operation failed: Media is blank. - * @see android.os.storage.StorageManager - */ - public static final int OperationFailedMediaBlank = -3; - - /** - * Operation failed: Media is corrupt. - * @see android.os.storage.StorageManager - */ - public static final int OperationFailedMediaCorrupt = -4; - - /** - * Operation failed: Storage not mounted. - * @see android.os.storage.StorageManager - */ - public static final int OperationFailedStorageNotMounted = -5; - - /** - * Operation failed: Storage is mounted. - * @see android.os.storage.StorageManager - */ - public static final int OperationFailedStorageMounted = -6; - - /** - * Operation failed: Storage is busy. - * @see android.os.storage.StorageManager - */ - public static final int OperationFailedStorageBusy = -7; - -} diff --git a/src/main/java/android/os/storage/StorageVolume.java b/src/main/java/android/os/storage/StorageVolume.java deleted file mode 100644 index 06565f1..0000000 --- a/src/main/java/android/os/storage/StorageVolume.java +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os.storage; - -import android.content.Context; -import android.os.Parcel; -import android.os.Parcelable; -import android.os.UserHandle; - -import com.android.internal.util.IndentingPrintWriter; - -import java.io.CharArrayWriter; -import java.io.File; - -/** - * Description of a storage volume and its capabilities, including the - * filesystem path where it may be mounted. - * - * @hide - */ -public class StorageVolume implements Parcelable { - - // TODO: switch to more durable token - private int mStorageId; - - private final File mPath; - private final int mDescriptionId; - private final boolean mPrimary; - private final boolean mRemovable; - private final boolean mEmulated; - private final int mMtpReserveSpace; - private final boolean mAllowMassStorage; - /** Maximum file size for the storage, or zero for no limit */ - private final long mMaxFileSize; - /** When set, indicates exclusive ownership of this volume */ - private final UserHandle mOwner; - - private String mUuid; - private String mUserLabel; - private String mState; - - // StorageVolume extra for ACTION_MEDIA_REMOVED, ACTION_MEDIA_UNMOUNTED, ACTION_MEDIA_CHECKING, - // ACTION_MEDIA_NOFS, ACTION_MEDIA_MOUNTED, ACTION_MEDIA_SHARED, ACTION_MEDIA_UNSHARED, - // ACTION_MEDIA_BAD_REMOVAL, ACTION_MEDIA_UNMOUNTABLE and ACTION_MEDIA_EJECT broadcasts. - public static final String EXTRA_STORAGE_VOLUME = "storage_volume"; - - public StorageVolume(File path, int descriptionId, boolean primary, boolean removable, - boolean emulated, int mtpReserveSpace, boolean allowMassStorage, long maxFileSize, - UserHandle owner) { - mPath = path; - mDescriptionId = descriptionId; - mPrimary = primary; - mRemovable = removable; - mEmulated = emulated; - mMtpReserveSpace = mtpReserveSpace; - mAllowMassStorage = allowMassStorage; - mMaxFileSize = maxFileSize; - mOwner = owner; - } - - private StorageVolume(Parcel in) { - mStorageId = in.readInt(); - mPath = new File(in.readString()); - mDescriptionId = in.readInt(); - mPrimary = in.readInt() != 0; - mRemovable = in.readInt() != 0; - mEmulated = in.readInt() != 0; - mMtpReserveSpace = in.readInt(); - mAllowMassStorage = in.readInt() != 0; - mMaxFileSize = in.readLong(); - mOwner = in.readParcelable(null); - mUuid = in.readString(); - mUserLabel = in.readString(); - mState = in.readString(); - } - - public static StorageVolume fromTemplate(StorageVolume template, File path, UserHandle owner) { - return new StorageVolume(path, template.mDescriptionId, template.mPrimary, - template.mRemovable, template.mEmulated, template.mMtpReserveSpace, - template.mAllowMassStorage, template.mMaxFileSize, owner); - } - - /** - * Returns the mount path for the volume. - * - * @return the mount path - */ - public String getPath() { - return mPath.toString(); - } - - public File getPathFile() { - return mPath; - } - - /** - * Returns a user visible description of the volume. - * - * @return the volume description - */ - public String getDescription(Context context) { - return context.getResources().getString(mDescriptionId); - } - - public int getDescriptionId() { - return mDescriptionId; - } - - public boolean isPrimary() { - return mPrimary; - } - - /** - * Returns true if the volume is removable. - * - * @return is removable - */ - public boolean isRemovable() { - return mRemovable; - } - - /** - * Returns true if the volume is emulated. - * - * @return is removable - */ - public boolean isEmulated() { - return mEmulated; - } - - /** - * Returns the MTP storage ID for the volume. - * this is also used for the storage_id column in the media provider. - * - * @return MTP storage ID - */ - public int getStorageId() { - return mStorageId; - } - - /** - * Do not call this unless you are MountService - */ - public void setStorageId(int index) { - // storage ID is 0x00010001 for primary storage, - // then 0x00020001, 0x00030001, etc. for secondary storages - mStorageId = ((index + 1) << 16) + 1; - } - - /** - * Number of megabytes of space to leave unallocated by MTP. - * MTP will subtract this value from the free space it reports back - * to the host via GetStorageInfo, and will not allow new files to - * be added via MTP if there is less than this amount left free in the storage. - * If MTP has dedicated storage this value should be zero, but if MTP is - * sharing storage with the rest of the system, set this to a positive value - * to ensure that MTP activity does not result in the storage being - * too close to full. - * - * @return MTP reserve space - */ - public int getMtpReserveSpace() { - return mMtpReserveSpace; - } - - /** - * Returns true if this volume can be shared via USB mass storage. - * - * @return whether mass storage is allowed - */ - public boolean allowMassStorage() { - return mAllowMassStorage; - } - - /** - * Returns maximum file size for the volume, or zero if it is unbounded. - * - * @return maximum file size - */ - public long getMaxFileSize() { - return mMaxFileSize; - } - - public UserHandle getOwner() { - return mOwner; - } - - public void setUuid(String uuid) { - mUuid = uuid; - } - - public String getUuid() { - return mUuid; - } - - /** - * Parse and return volume UUID as FAT volume ID, or return -1 if unable to - * parse or UUID is unknown. - */ - public int getFatVolumeId() { - if (mUuid == null || mUuid.length() != 9) { - return -1; - } - try { - return (int)Long.parseLong(mUuid.replace("-", ""), 16); - } catch (NumberFormatException e) { - return -1; - } - } - - public void setUserLabel(String userLabel) { - mUserLabel = userLabel; - } - - public String getUserLabel() { - return mUserLabel; - } - - public void setState(String state) { - mState = state; - } - - public String getState() { - return mState; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof StorageVolume && mPath != null) { - StorageVolume volume = (StorageVolume)obj; - return (mPath.equals(volume.mPath)); - } - return false; - } - - @Override - public int hashCode() { - return mPath.hashCode(); - } - - @Override - public String toString() { - final CharArrayWriter writer = new CharArrayWriter(); - dump(new IndentingPrintWriter(writer, " ", 80)); - return writer.toString(); - } - - public void dump(IndentingPrintWriter pw) { - pw.println("StorageVolume:"); - pw.increaseIndent(); - pw.printPair("mStorageId", mStorageId); - pw.printPair("mPath", mPath); - pw.printPair("mDescriptionId", mDescriptionId); - pw.printPair("mPrimary", mPrimary); - pw.printPair("mRemovable", mRemovable); - pw.printPair("mEmulated", mEmulated); - pw.printPair("mMtpReserveSpace", mMtpReserveSpace); - pw.printPair("mAllowMassStorage", mAllowMassStorage); - pw.printPair("mMaxFileSize", mMaxFileSize); - pw.printPair("mOwner", mOwner); - pw.printPair("mUuid", mUuid); - pw.printPair("mUserLabel", mUserLabel); - pw.printPair("mState", mState); - pw.decreaseIndent(); - } - - public static final Creator CREATOR = new Creator() { - @Override - public StorageVolume createFromParcel(Parcel in) { - return new StorageVolume(in); - } - - @Override - public StorageVolume[] newArray(int size) { - return new StorageVolume[size]; - } - }; - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel parcel, int flags) { - parcel.writeInt(mStorageId); - parcel.writeString(mPath.toString()); - parcel.writeInt(mDescriptionId); - parcel.writeInt(mPrimary ? 1 : 0); - parcel.writeInt(mRemovable ? 1 : 0); - parcel.writeInt(mEmulated ? 1 : 0); - parcel.writeInt(mMtpReserveSpace); - parcel.writeInt(mAllowMassStorage ? 1 : 0); - parcel.writeLong(mMaxFileSize); - parcel.writeParcelable(mOwner, flags); - parcel.writeString(mUuid); - parcel.writeString(mUserLabel); - parcel.writeString(mState); - } -} diff --git a/src/main/java/android/util/AndroidException.java b/src/main/java/android/util/AndroidException.java deleted file mode 100644 index dfe00c9..0000000 --- a/src/main/java/android/util/AndroidException.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -/** - * Base class for all checked exceptions thrown by the Android frameworks. - */ -public class AndroidException extends Exception { - public AndroidException() { - } - - public AndroidException(String name) { - super(name); - } - - public AndroidException(String name, Throwable cause) { - super(name, cause); - } - - public AndroidException(Exception cause) { - super(cause); - } -}; - diff --git a/src/main/java/android/util/AndroidRuntimeException.java b/src/main/java/android/util/AndroidRuntimeException.java deleted file mode 100644 index 2b824bf..0000000 --- a/src/main/java/android/util/AndroidRuntimeException.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -/** - * Base class for all unchecked exceptions thrown by the Android frameworks. - */ -public class AndroidRuntimeException extends RuntimeException { - public AndroidRuntimeException() { - } - - public AndroidRuntimeException(String name) { - super(name); - } - - public AndroidRuntimeException(String name, Throwable cause) { - super(name, cause); - } - - public AndroidRuntimeException(Exception cause) { - super(cause); - } -}; - diff --git a/src/main/java/android/util/ArrayMap.java b/src/main/java/android/util/ArrayMap.java deleted file mode 100644 index 6ed3885..0000000 --- a/src/main/java/android/util/ArrayMap.java +++ /dev/null @@ -1,882 +0,0 @@ -/* - * Copyright (C) 2013 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.util; - -import libcore.util.EmptyArray; - -import java.util.Collection; -import java.util.Map; -import java.util.Set; - -/** - * ArrayMap is a generic key->value mapping data structure that is - * designed to be more memory efficient than a traditional {@link java.util.HashMap}. - * It keeps its mappings in an array data structure -- an integer array of hash - * codes for each item, and an Object array of the key/value pairs. This allows it to - * avoid having to create an extra object for every entry put in to the map, and it - * also tries to control the growth of the size of these arrays more aggressively - * (since growing them only requires copying the entries in the array, not rebuilding - * a hash map). - * - *

    Note that this implementation is not intended to be appropriate for data structures - * that may contain large numbers of items. It is generally slower than a traditional - * HashMap, since lookups require a binary search and adds and removes require inserting - * and deleting entries in the array. For containers holding up to hundreds of items, - * the performance difference is not significant, less than 50%.

    - * - *

    Because this container is intended to better balance memory use, unlike most other - * standard Java containers it will shrink its array as items are removed from it. Currently - * you have no control over this shrinking -- if you set a capacity and then remove an - * item, it may reduce the capacity to better match the current size. In the future an - * explicit call to set the capacity should turn off this aggressive shrinking behavior.

    - */ -public final class ArrayMap implements Map { - private static final boolean DEBUG = false; - private static final String TAG = "ArrayMap"; - - /** - * The minimum amount by which the capacity of a ArrayMap will increase. - * This is tuned to be relatively space-efficient. - */ - private static final int BASE_SIZE = 4; - - /** - * Maximum number of entries to have in array caches. - */ - private static final int CACHE_SIZE = 10; - - /** - * @hide Special immutable empty ArrayMap. - */ - public static final ArrayMap EMPTY = new ArrayMap(true); - - /** - * Caches of small array objects to avoid spamming garbage. The cache - * Object[] variable is a pointer to a linked list of array objects. - * The first entry in the array is a pointer to the next array in the - * list; the second entry is a pointer to the int[] hash code array for it. - */ - static Object[] mBaseCache; - static int mBaseCacheSize; - static Object[] mTwiceBaseCache; - static int mTwiceBaseCacheSize; - - /** - * Special hash array value that indicates the container is immutable. - */ - static final int[] EMPTY_IMMUTABLE_INTS = new int[0]; - - int[] mHashes; - Object[] mArray; - int mSize; - MapCollections mCollections; - - int indexOf(Object key, int hash) { - final int N = mSize; - - // Important fast case: if nothing is in here, nothing to look for. - if (N == 0) { - return ~0; - } - - int index = ContainerHelpers.binarySearch(mHashes, N, hash); - - // If the hash code wasn't found, then we have no entry for this key. - if (index < 0) { - return index; - } - - // If the key at the returned index matches, that's what we want. - if (key.equals(mArray[index<<1])) { - return index; - } - - // Search for a matching key after the index. - int end; - for (end = index + 1; end < N && mHashes[end] == hash; end++) { - if (key.equals(mArray[end << 1])) return end; - } - - // Search for a matching key before the index. - for (int i = index - 1; i >= 0 && mHashes[i] == hash; i--) { - if (key.equals(mArray[i << 1])) return i; - } - - // Key not found -- return negative value indicating where a - // new entry for this key should go. We use the end of the - // hash chain to reduce the number of array entries that will - // need to be copied when inserting. - return ~end; - } - - int indexOfNull() { - final int N = mSize; - - // Important fast case: if nothing is in here, nothing to look for. - if (N == 0) { - return ~0; - } - - int index = ContainerHelpers.binarySearch(mHashes, N, 0); - - // If the hash code wasn't found, then we have no entry for this key. - if (index < 0) { - return index; - } - - // If the key at the returned index matches, that's what we want. - if (null == mArray[index<<1]) { - return index; - } - - // Search for a matching key after the index. - int end; - for (end = index + 1; end < N && mHashes[end] == 0; end++) { - if (null == mArray[end << 1]) return end; - } - - // Search for a matching key before the index. - for (int i = index - 1; i >= 0 && mHashes[i] == 0; i--) { - if (null == mArray[i << 1]) return i; - } - - // Key not found -- return negative value indicating where a - // new entry for this key should go. We use the end of the - // hash chain to reduce the number of array entries that will - // need to be copied when inserting. - return ~end; - } - - private void allocArrays(final int size) { - if (mHashes == EMPTY_IMMUTABLE_INTS) { - throw new UnsupportedOperationException("ArrayMap is immutable"); - } - if (size == (BASE_SIZE*2)) { - synchronized (ArrayMap.class) { - if (mTwiceBaseCache != null) { - final Object[] array = mTwiceBaseCache; - mArray = array; - mTwiceBaseCache = (Object[])array[0]; - mHashes = (int[])array[1]; - array[0] = array[1] = null; - mTwiceBaseCacheSize--; - if (DEBUG) Log.d(TAG, "Retrieving 2x cache " + mHashes - + " now have " + mTwiceBaseCacheSize + " entries"); - return; - } - } - } else if (size == BASE_SIZE) { - synchronized (ArrayMap.class) { - if (mBaseCache != null) { - final Object[] array = mBaseCache; - mArray = array; - mBaseCache = (Object[])array[0]; - mHashes = (int[])array[1]; - array[0] = array[1] = null; - mBaseCacheSize--; - if (DEBUG) Log.d(TAG, "Retrieving 1x cache " + mHashes - + " now have " + mBaseCacheSize + " entries"); - return; - } - } - } - - mHashes = new int[size]; - mArray = new Object[size<<1]; - } - - private static void freeArrays(final int[] hashes, final Object[] array, final int size) { - if (hashes.length == (BASE_SIZE*2)) { - synchronized (ArrayMap.class) { - if (mTwiceBaseCacheSize < CACHE_SIZE) { - array[0] = mTwiceBaseCache; - array[1] = hashes; - for (int i=(size<<1)-1; i>=2; i--) { - array[i] = null; - } - mTwiceBaseCache = array; - mTwiceBaseCacheSize++; - if (DEBUG) Log.d(TAG, "Storing 2x cache " + array - + " now have " + mTwiceBaseCacheSize + " entries"); - } - } - } else if (hashes.length == BASE_SIZE) { - synchronized (ArrayMap.class) { - if (mBaseCacheSize < CACHE_SIZE) { - array[0] = mBaseCache; - array[1] = hashes; - for (int i=(size<<1)-1; i>=2; i--) { - array[i] = null; - } - mBaseCache = array; - mBaseCacheSize++; - if (DEBUG) Log.d(TAG, "Storing 1x cache " + array - + " now have " + mBaseCacheSize + " entries"); - } - } - } - } - - /** - * Create a new empty ArrayMap. The default capacity of an array map is 0, and - * will grow once items are added to it. - */ - public ArrayMap() { - mHashes = EmptyArray.INT; - mArray = EmptyArray.OBJECT; - mSize = 0; - } - - /** - * Create a new ArrayMap with a given initial capacity. - */ - public ArrayMap(int capacity) { - if (capacity == 0) { - mHashes = EmptyArray.INT; - mArray = EmptyArray.OBJECT; - } else { - allocArrays(capacity); - } - mSize = 0; - } - - private ArrayMap(boolean immutable) { - // If this is immutable, use the sentinal EMPTY_IMMUTABLE_INTS - // instance instead of the usual EmptyArray.INT. The reference - // is checked later to see if the array is allowed to grow. - mHashes = immutable ? EMPTY_IMMUTABLE_INTS : EmptyArray.INT; - mArray = EmptyArray.OBJECT; - mSize = 0; - } - - /** - * Create a new ArrayMap with the mappings from the given ArrayMap. - */ - public ArrayMap(ArrayMap map) { - this(); - if (map != null) { - putAll(map); - } - } - - /** - * Make the array map empty. All storage is released. - */ - @Override - public void clear() { - if (mSize > 0) { - freeArrays(mHashes, mArray, mSize); - mHashes = EmptyArray.INT; - mArray = EmptyArray.OBJECT; - mSize = 0; - } - } - - /** - * @hide - * Like {@link #clear}, but doesn't reduce the capacity of the ArrayMap. - */ - public void erase() { - if (mSize > 0) { - final int N = mSize<<1; - final Object[] array = mArray; - for (int i=0; iminimumCapacity - * items. - */ - public void ensureCapacity(int minimumCapacity) { - if (mHashes.length < minimumCapacity) { - final int[] ohashes = mHashes; - final Object[] oarray = mArray; - allocArrays(minimumCapacity); - if (mSize > 0) { - System.arraycopy(ohashes, 0, mHashes, 0, mSize); - System.arraycopy(oarray, 0, mArray, 0, mSize<<1); - } - freeArrays(ohashes, oarray, mSize); - } - } - - /** - * Check whether a key exists in the array. - * - * @param key The key to search for. - * @return Returns true if the key exists, else false. - */ - @Override - public boolean containsKey(Object key) { - return indexOfKey(key) >= 0; - } - - /** - * Returns the index of a key in the set. - * - * @param key The key to search for. - * @return Returns the index of the key if it exists, else a negative integer. - */ - public int indexOfKey(Object key) { - return key == null ? indexOfNull() : indexOf(key, key.hashCode()); - } - - int indexOfValue(Object value) { - final int N = mSize*2; - final Object[] array = mArray; - if (value == null) { - for (int i=1; i>1; - } - } - } else { - for (int i=1; i>1; - } - } - } - return -1; - } - - /** - * Check whether a value exists in the array. This requires a linear search - * through the entire array. - * - * @param value The value to search for. - * @return Returns true if the value exists, else false. - */ - @Override - public boolean containsValue(Object value) { - return indexOfValue(value) >= 0; - } - - /** - * Retrieve a value from the array. - * @param key The key of the value to retrieve. - * @return Returns the value associated with the given key, - * or null if there is no such key. - */ - @Override - public V get(Object key) { - final int index = indexOfKey(key); - return index >= 0 ? (V)mArray[(index<<1)+1] : null; - } - - /** - * Return the key at the given index in the array. - * @param index The desired index, must be between 0 and {@link #size()}-1. - * @return Returns the key stored at the given index. - */ - public K keyAt(int index) { - return (K)mArray[index << 1]; - } - - /** - * Return the value at the given index in the array. - * @param index The desired index, must be between 0 and {@link #size()}-1. - * @return Returns the value stored at the given index. - */ - public V valueAt(int index) { - return (V)mArray[(index << 1) + 1]; - } - - /** - * Set the value at a given index in the array. - * @param index The desired index, must be between 0 and {@link #size()}-1. - * @param value The new value to store at this index. - * @return Returns the previous value at the given index. - */ - public V setValueAt(int index, V value) { - index = (index << 1) + 1; - V old = (V)mArray[index]; - mArray[index] = value; - return old; - } - - /** - * Return true if the array map contains no items. - */ - @Override - public boolean isEmpty() { - return mSize <= 0; - } - - /** - * Add a new value to the array map. - * @param key The key under which to store the value. If - * this key already exists in the array, its value will be replaced. - * @param value The value to store for the given key. - * @return Returns the old value that was stored for the given key, or null if there - * was no such key. - */ - @Override - public V put(K key, V value) { - final int hash; - int index; - if (key == null) { - hash = 0; - index = indexOfNull(); - } else { - hash = key.hashCode(); - index = indexOf(key, hash); - } - if (index >= 0) { - index = (index<<1) + 1; - final V old = (V)mArray[index]; - mArray[index] = value; - return old; - } - - index = ~index; - if (mSize >= mHashes.length) { - final int n = mSize >= (BASE_SIZE*2) ? (mSize+(mSize>>1)) - : (mSize >= BASE_SIZE ? (BASE_SIZE*2) : BASE_SIZE); - - if (DEBUG) Log.d(TAG, "put: grow from " + mHashes.length + " to " + n); - - final int[] ohashes = mHashes; - final Object[] oarray = mArray; - allocArrays(n); - - if (mHashes.length > 0) { - if (DEBUG) Log.d(TAG, "put: copy 0-" + mSize + " to 0"); - System.arraycopy(ohashes, 0, mHashes, 0, ohashes.length); - System.arraycopy(oarray, 0, mArray, 0, oarray.length); - } - - freeArrays(ohashes, oarray, mSize); - } - - if (index < mSize) { - if (DEBUG) Log.d(TAG, "put: move " + index + "-" + (mSize-index) - + " to " + (index+1)); - System.arraycopy(mHashes, index, mHashes, index + 1, mSize - index); - System.arraycopy(mArray, index << 1, mArray, (index + 1) << 1, (mSize - index) << 1); - } - - mHashes[index] = hash; - mArray[index<<1] = key; - mArray[(index<<1)+1] = value; - mSize++; - return null; - } - - /** - * Special fast path for appending items to the end of the array without validation. - * The array must already be large enough to contain the item. - * @hide - */ - public void append(K key, V value) { - int index = mSize; - final int hash = key == null ? 0 : key.hashCode(); - if (index >= mHashes.length) { - throw new IllegalStateException("Array is full"); - } - if (index > 0 && mHashes[index-1] > hash) { - RuntimeException e = new RuntimeException("here"); - e.fillInStackTrace(); - Log.w(TAG, "New hash " + hash - + " is before end of array hash " + mHashes[index-1] - + " at index " + index + " key " + key, e); - put(key, value); - return; - } - mSize = index+1; - mHashes[index] = hash; - index <<= 1; - mArray[index] = key; - mArray[index+1] = value; - } - - /** - * The use of the {@link #append} function can result in invalid array maps, in particular - * an array map where the same key appears multiple times. This function verifies that - * the array map is valid, throwing IllegalArgumentException if a problem is found. The - * main use for this method is validating an array map after unpacking from an IPC, to - * protect against malicious callers. - * @hide - */ - public void validate() { - final int N = mSize; - if (N <= 1) { - // There can't be dups. - return; - } - int basehash = mHashes[0]; - int basei = 0; - for (int i=1; i=basei; j--) { - final Object prev = mArray[j<<1]; - if (cur == prev) { - throw new IllegalArgumentException("Duplicate key in ArrayMap: " + cur); - } - if (cur != null && prev != null && cur.equals(prev)) { - throw new IllegalArgumentException("Duplicate key in ArrayMap: " + cur); - } - } - } - } - - /** - * Perform a {@link #put(Object, Object)} of all key/value pairs in array - * @param array The array whose contents are to be retrieved. - */ - public void putAll(ArrayMap array) { - final int N = array.mSize; - ensureCapacity(mSize + N); - if (mSize == 0) { - if (N > 0) { - System.arraycopy(array.mHashes, 0, mHashes, 0, N); - System.arraycopy(array.mArray, 0, mArray, 0, N<<1); - mSize = N; - } - } else { - for (int i=0; i= 0) { - return removeAt(index); - } - - return null; - } - - /** - * Remove the key/value mapping at the given index. - * @param index The desired index, must be between 0 and {@link #size()}-1. - * @return Returns the value that was stored at this index. - */ - public V removeAt(int index) { - final Object old = mArray[(index << 1) + 1]; - if (mSize <= 1) { - // Now empty. - if (DEBUG) Log.d(TAG, "remove: shrink from " + mHashes.length + " to 0"); - freeArrays(mHashes, mArray, mSize); - mHashes = EmptyArray.INT; - mArray = EmptyArray.OBJECT; - mSize = 0; - } else { - if (mHashes.length > (BASE_SIZE*2) && mSize < mHashes.length/3) { - // Shrunk enough to reduce size of arrays. We don't allow it to - // shrink smaller than (BASE_SIZE*2) to avoid flapping between - // that and BASE_SIZE. - final int n = mSize > (BASE_SIZE*2) ? (mSize + (mSize>>1)) : (BASE_SIZE*2); - - if (DEBUG) Log.d(TAG, "remove: shrink from " + mHashes.length + " to " + n); - - final int[] ohashes = mHashes; - final Object[] oarray = mArray; - allocArrays(n); - - mSize--; - if (index > 0) { - if (DEBUG) Log.d(TAG, "remove: copy from 0-" + index + " to 0"); - System.arraycopy(ohashes, 0, mHashes, 0, index); - System.arraycopy(oarray, 0, mArray, 0, index << 1); - } - if (index < mSize) { - if (DEBUG) Log.d(TAG, "remove: copy from " + (index+1) + "-" + mSize - + " to " + index); - System.arraycopy(ohashes, index + 1, mHashes, index, mSize - index); - System.arraycopy(oarray, (index + 1) << 1, mArray, index << 1, - (mSize - index) << 1); - } - } else { - mSize--; - if (index < mSize) { - if (DEBUG) Log.d(TAG, "remove: move " + (index+1) + "-" + mSize - + " to " + index); - System.arraycopy(mHashes, index + 1, mHashes, index, mSize - index); - System.arraycopy(mArray, (index + 1) << 1, mArray, index << 1, - (mSize - index) << 1); - } - mArray[mSize << 1] = null; - mArray[(mSize << 1) + 1] = null; - } - } - return (V)old; - } - - /** - * Return the number of items in this array map. - */ - @Override - public int size() { - return mSize; - } - - /** - * {@inheritDoc} - * - *

    This implementation returns false if the object is not a map, or - * if the maps have different sizes. Otherwise, for each key in this map, - * values of both maps are compared. If the values for any key are not - * equal, the method returns false, otherwise it returns true. - */ - @Override - public boolean equals(Object object) { - if (this == object) { - return true; - } - if (object instanceof Map) { - Map map = (Map) object; - if (size() != map.size()) { - return false; - } - - try { - for (int i=0; iThis implementation composes a string by iterating over its mappings. If - * this map contains itself as a key or a value, the string "(this Map)" - * will appear in its place. - */ - @Override - public String toString() { - if (isEmpty()) { - return "{}"; - } - - StringBuilder buffer = new StringBuilder(mSize * 28); - buffer.append('{'); - for (int i=0; i 0) { - buffer.append(", "); - } - Object key = keyAt(i); - if (key != this) { - buffer.append(key); - } else { - buffer.append("(this Map)"); - } - buffer.append('='); - Object value = valueAt(i); - if (value != this) { - buffer.append(value); - } else { - buffer.append("(this Map)"); - } - } - buffer.append('}'); - return buffer.toString(); - } - - // ------------------------------------------------------------------------ - // Interop with traditional Java containers. Not as efficient as using - // specialized collection APIs. - // ------------------------------------------------------------------------ - - private MapCollections getCollection() { - if (mCollections == null) { - mCollections = new MapCollections() { - @Override - protected int colGetSize() { - return mSize; - } - - @Override - protected Object colGetEntry(int index, int offset) { - return mArray[(index<<1) + offset]; - } - - @Override - protected int colIndexOfKey(Object key) { - return indexOfKey(key); - } - - @Override - protected int colIndexOfValue(Object value) { - return indexOfValue(value); - } - - @Override - protected Map colGetMap() { - return ArrayMap.this; - } - - @Override - protected void colPut(K key, V value) { - put(key, value); - } - - @Override - protected V colSetValue(int index, V value) { - return setValueAt(index, value); - } - - @Override - protected void colRemoveAt(int index) { - removeAt(index); - } - - @Override - protected void colClear() { - clear(); - } - }; - } - return mCollections; - } - - /** - * Determine if the array map contains all of the keys in the given collection. - * @param collection The collection whose contents are to be checked against. - * @return Returns true if this array map contains a key for every entry - * in collection, else returns false. - */ - public boolean containsAll(Collection collection) { - return MapCollections.containsAllHelper(this, collection); - } - - /** - * Perform a {@link #put(Object, Object)} of all key/value pairs in map - * @param map The map whose contents are to be retrieved. - */ - @Override - public void putAll(Map map) { - ensureCapacity(mSize + map.size()); - for (Map.Entry entry : map.entrySet()) { - put(entry.getKey(), entry.getValue()); - } - } - - /** - * Remove all keys in the array map that exist in the given collection. - * @param collection The collection whose contents are to be used to remove keys. - * @return Returns true if any keys were removed from the array map, else false. - */ - public boolean removeAll(Collection collection) { - return MapCollections.removeAllHelper(this, collection); - } - - /** - * Remove all keys in the array map that do not exist in the given collection. - * @param collection The collection whose contents are to be used to determine which - * keys to keep. - * @return Returns true if any keys were removed from the array map, else false. - */ - public boolean retainAll(Collection collection) { - return MapCollections.retainAllHelper(this, collection); - } - - /** - * Return a {@link java.util.Set} for iterating over and interacting with all mappings - * in the array map. - * - *

    Note: this is a very inefficient way to access the array contents, it - * requires generating a number of temporary objects.

    - * - *

    Note:

    the semantics of this - * Set are subtly different than that of a {@link java.util.HashMap}: most important, - * the {@link java.util.Map.Entry Map.Entry} object returned by its iterator is a single - * object that exists for the entire iterator, so you can not hold on to it - * after calling {@link java.util.Iterator#next() Iterator.next}.

    - */ - @Override - public Set> entrySet() { - return getCollection().getEntrySet(); - } - - /** - * Return a {@link java.util.Set} for iterating over and interacting with all keys - * in the array map. - * - *

    Note: this is a fairly inefficient way to access the array contents, it - * requires generating a number of temporary objects.

    - */ - @Override - public Set keySet() { - return getCollection().getKeySet(); - } - - /** - * Return a {@link java.util.Collection} for iterating over and interacting with all values - * in the array map. - * - *

    Note: this is a fairly inefficient way to access the array contents, it - * requires generating a number of temporary objects.

    - */ - @Override - public Collection values() { - return getCollection().getValues(); - } -} diff --git a/src/main/java/android/util/ArraySet.java b/src/main/java/android/util/ArraySet.java deleted file mode 100644 index 68f725e..0000000 --- a/src/main/java/android/util/ArraySet.java +++ /dev/null @@ -1,689 +0,0 @@ -/* - * Copyright (C) 2013 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.util; - -import libcore.util.EmptyArray; - -import java.lang.reflect.Array; -import java.util.Collection; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - -/** - * ArraySet is a generic set data structure that is designed to be more memory efficient than a - * traditional {@link java.util.HashSet}. The design is very similar to - * {@link ArrayMap}, with all of the caveats described there. This implementation is - * separate from ArrayMap, however, so the Object array contains only one item for each - * entry in the set (instead of a pair for a mapping). - * - *

    Note that this implementation is not intended to be appropriate for data structures - * that may contain large numbers of items. It is generally slower than a traditional - * HashSet, since lookups require a binary search and adds and removes require inserting - * and deleting entries in the array. For containers holding up to hundreds of items, - * the performance difference is not significant, less than 50%.

    - * - *

    Because this container is intended to better balance memory use, unlike most other - * standard Java containers it will shrink its array as items are removed from it. Currently - * you have no control over this shrinking -- if you set a capacity and then remove an - * item, it may reduce the capacity to better match the current size. In the future an - * explicit call to set the capacity should turn off this aggressive shrinking behavior.

    - * - * @hide - */ -public final class ArraySet implements Collection, Set { - private static final boolean DEBUG = false; - private static final String TAG = "ArraySet"; - - /** - * The minimum amount by which the capacity of a ArraySet will increase. - * This is tuned to be relatively space-efficient. - */ - private static final int BASE_SIZE = 4; - - /** - * Maximum number of entries to have in array caches. - */ - private static final int CACHE_SIZE = 10; - - /** - * Caches of small array objects to avoid spamming garbage. The cache - * Object[] variable is a pointer to a linked list of array objects. - * The first entry in the array is a pointer to the next array in the - * list; the second entry is a pointer to the int[] hash code array for it. - */ - static Object[] mBaseCache; - static int mBaseCacheSize; - static Object[] mTwiceBaseCache; - static int mTwiceBaseCacheSize; - - int[] mHashes; - Object[] mArray; - int mSize; - MapCollections mCollections; - - private int indexOf(Object key, int hash) { - final int N = mSize; - - // Important fast case: if nothing is in here, nothing to look for. - if (N == 0) { - return ~0; - } - - int index = ContainerHelpers.binarySearch(mHashes, N, hash); - - // If the hash code wasn't found, then we have no entry for this key. - if (index < 0) { - return index; - } - - // If the key at the returned index matches, that's what we want. - if (key.equals(mArray[index])) { - return index; - } - - // Search for a matching key after the index. - int end; - for (end = index + 1; end < N && mHashes[end] == hash; end++) { - if (key.equals(mArray[end])) return end; - } - - // Search for a matching key before the index. - for (int i = index - 1; i >= 0 && mHashes[i] == hash; i--) { - if (key.equals(mArray[i])) return i; - } - - // Key not found -- return negative value indicating where a - // new entry for this key should go. We use the end of the - // hash chain to reduce the number of array entries that will - // need to be copied when inserting. - return ~end; - } - - private int indexOfNull() { - final int N = mSize; - - // Important fast case: if nothing is in here, nothing to look for. - if (N == 0) { - return ~0; - } - - int index = ContainerHelpers.binarySearch(mHashes, N, 0); - - // If the hash code wasn't found, then we have no entry for this key. - if (index < 0) { - return index; - } - - // If the key at the returned index matches, that's what we want. - if (null == mArray[index]) { - return index; - } - - // Search for a matching key after the index. - int end; - for (end = index + 1; end < N && mHashes[end] == 0; end++) { - if (null == mArray[end]) return end; - } - - // Search for a matching key before the index. - for (int i = index - 1; i >= 0 && mHashes[i] == 0; i--) { - if (null == mArray[i]) return i; - } - - // Key not found -- return negative value indicating where a - // new entry for this key should go. We use the end of the - // hash chain to reduce the number of array entries that will - // need to be copied when inserting. - return ~end; - } - - private void allocArrays(final int size) { - if (size == (BASE_SIZE*2)) { - synchronized (ArraySet.class) { - if (mTwiceBaseCache != null) { - final Object[] array = mTwiceBaseCache; - mArray = array; - mTwiceBaseCache = (Object[])array[0]; - mHashes = (int[])array[1]; - array[0] = array[1] = null; - mTwiceBaseCacheSize--; - if (DEBUG) Log.d(TAG, "Retrieving 2x cache " + mHashes - + " now have " + mTwiceBaseCacheSize + " entries"); - return; - } - } - } else if (size == BASE_SIZE) { - synchronized (ArraySet.class) { - if (mBaseCache != null) { - final Object[] array = mBaseCache; - mArray = array; - mBaseCache = (Object[])array[0]; - mHashes = (int[])array[1]; - array[0] = array[1] = null; - mBaseCacheSize--; - if (DEBUG) Log.d(TAG, "Retrieving 1x cache " + mHashes - + " now have " + mBaseCacheSize + " entries"); - return; - } - } - } - - mHashes = new int[size]; - mArray = new Object[size]; - } - - private static void freeArrays(final int[] hashes, final Object[] array, final int size) { - if (hashes.length == (BASE_SIZE*2)) { - synchronized (ArraySet.class) { - if (mTwiceBaseCacheSize < CACHE_SIZE) { - array[0] = mTwiceBaseCache; - array[1] = hashes; - for (int i=size-1; i>=2; i--) { - array[i] = null; - } - mTwiceBaseCache = array; - mTwiceBaseCacheSize++; - if (DEBUG) Log.d(TAG, "Storing 2x cache " + array - + " now have " + mTwiceBaseCacheSize + " entries"); - } - } - } else if (hashes.length == BASE_SIZE) { - synchronized (ArraySet.class) { - if (mBaseCacheSize < CACHE_SIZE) { - array[0] = mBaseCache; - array[1] = hashes; - for (int i=size-1; i>=2; i--) { - array[i] = null; - } - mBaseCache = array; - mBaseCacheSize++; - if (DEBUG) Log.d(TAG, "Storing 1x cache " + array - + " now have " + mBaseCacheSize + " entries"); - } - } - } - } - - /** - * Create a new empty ArraySet. The default capacity of an array map is 0, and - * will grow once items are added to it. - */ - public ArraySet() { - mHashes = EmptyArray.INT; - mArray = EmptyArray.OBJECT; - mSize = 0; - } - - /** - * Create a new ArraySet with a given initial capacity. - */ - public ArraySet(int capacity) { - if (capacity == 0) { - mHashes = EmptyArray.INT; - mArray = EmptyArray.OBJECT; - } else { - allocArrays(capacity); - } - mSize = 0; - } - - /** - * Create a new ArraySet with the mappings from the given ArraySet. - */ - public ArraySet(ArraySet set) { - this(); - if (set != null) { - addAll(set); - } - } - - /** {@hide} */ - public ArraySet(Collection set) { - this(); - if (set != null) { - addAll(set); - } - } - - /** - * Make the array map empty. All storage is released. - */ - @Override - public void clear() { - if (mSize != 0) { - freeArrays(mHashes, mArray, mSize); - mHashes = EmptyArray.INT; - mArray = EmptyArray.OBJECT; - mSize = 0; - } - } - - /** - * Ensure the array map can hold at least minimumCapacity - * items. - */ - public void ensureCapacity(int minimumCapacity) { - if (mHashes.length < minimumCapacity) { - final int[] ohashes = mHashes; - final Object[] oarray = mArray; - allocArrays(minimumCapacity); - if (mSize > 0) { - System.arraycopy(ohashes, 0, mHashes, 0, mSize); - System.arraycopy(oarray, 0, mArray, 0, mSize); - } - freeArrays(ohashes, oarray, mSize); - } - } - - /** - * Check whether a value exists in the set. - * - * @param key The value to search for. - * @return Returns true if the value exists, else false. - */ - @Override - public boolean contains(Object key) { - return indexOf(key) >= 0; - } - - /** - * Returns the index of a value in the set. - * - * @param key The value to search for. - * @return Returns the index of the value if it exists, else a negative integer. - */ - public int indexOf(Object key) { - return key == null ? indexOfNull() : indexOf(key, key.hashCode()); - } - - /** - * Return the value at the given index in the array. - * @param index The desired index, must be between 0 and {@link #size()}-1. - * @return Returns the value stored at the given index. - */ - public E valueAt(int index) { - return (E)mArray[index]; - } - - /** - * Return true if the array map contains no items. - */ - @Override - public boolean isEmpty() { - return mSize <= 0; - } - - /** - * Adds the specified object to this set. The set is not modified if it - * already contains the object. - * - * @param value the object to add. - * @return {@code true} if this set is modified, {@code false} otherwise. - * @throws ClassCastException - * when the class of the object is inappropriate for this set. - */ - @Override - public boolean add(E value) { - final int hash; - int index; - if (value == null) { - hash = 0; - index = indexOfNull(); - } else { - hash = value.hashCode(); - index = indexOf(value, hash); - } - if (index >= 0) { - return false; - } - - index = ~index; - if (mSize >= mHashes.length) { - final int n = mSize >= (BASE_SIZE*2) ? (mSize+(mSize>>1)) - : (mSize >= BASE_SIZE ? (BASE_SIZE*2) : BASE_SIZE); - - if (DEBUG) Log.d(TAG, "add: grow from " + mHashes.length + " to " + n); - - final int[] ohashes = mHashes; - final Object[] oarray = mArray; - allocArrays(n); - - if (mHashes.length > 0) { - if (DEBUG) Log.d(TAG, "add: copy 0-" + mSize + " to 0"); - System.arraycopy(ohashes, 0, mHashes, 0, ohashes.length); - System.arraycopy(oarray, 0, mArray, 0, oarray.length); - } - - freeArrays(ohashes, oarray, mSize); - } - - if (index < mSize) { - if (DEBUG) Log.d(TAG, "add: move " + index + "-" + (mSize-index) - + " to " + (index+1)); - System.arraycopy(mHashes, index, mHashes, index + 1, mSize - index); - System.arraycopy(mArray, index, mArray, index + 1, mSize - index); - } - - mHashes[index] = hash; - mArray[index] = value; - mSize++; - return true; - } - - /** - * Perform a {@link #add(Object)} of all values in array - * @param array The array whose contents are to be retrieved. - */ - public void addAll(ArraySet array) { - final int N = array.mSize; - ensureCapacity(mSize + N); - if (mSize == 0) { - if (N > 0) { - System.arraycopy(array.mHashes, 0, mHashes, 0, N); - System.arraycopy(array.mArray, 0, mArray, 0, N); - mSize = N; - } - } else { - for (int i=0; i= 0) { - removeAt(index); - return true; - } - return false; - } - - /** - * Remove the key/value mapping at the given index. - * @param index The desired index, must be between 0 and {@link #size()}-1. - * @return Returns the value that was stored at this index. - */ - public E removeAt(int index) { - final Object old = mArray[index]; - if (mSize <= 1) { - // Now empty. - if (DEBUG) Log.d(TAG, "remove: shrink from " + mHashes.length + " to 0"); - freeArrays(mHashes, mArray, mSize); - mHashes = EmptyArray.INT; - mArray = EmptyArray.OBJECT; - mSize = 0; - } else { - if (mHashes.length > (BASE_SIZE*2) && mSize < mHashes.length/3) { - // Shrunk enough to reduce size of arrays. We don't allow it to - // shrink smaller than (BASE_SIZE*2) to avoid flapping between - // that and BASE_SIZE. - final int n = mSize > (BASE_SIZE*2) ? (mSize + (mSize>>1)) : (BASE_SIZE*2); - - if (DEBUG) Log.d(TAG, "remove: shrink from " + mHashes.length + " to " + n); - - final int[] ohashes = mHashes; - final Object[] oarray = mArray; - allocArrays(n); - - mSize--; - if (index > 0) { - if (DEBUG) Log.d(TAG, "remove: copy from 0-" + index + " to 0"); - System.arraycopy(ohashes, 0, mHashes, 0, index); - System.arraycopy(oarray, 0, mArray, 0, index); - } - if (index < mSize) { - if (DEBUG) Log.d(TAG, "remove: copy from " + (index+1) + "-" + mSize - + " to " + index); - System.arraycopy(ohashes, index + 1, mHashes, index, mSize - index); - System.arraycopy(oarray, index + 1, mArray, index, mSize - index); - } - } else { - mSize--; - if (index < mSize) { - if (DEBUG) Log.d(TAG, "remove: move " + (index+1) + "-" + mSize - + " to " + index); - System.arraycopy(mHashes, index + 1, mHashes, index, mSize - index); - System.arraycopy(mArray, index + 1, mArray, index, mSize - index); - } - mArray[mSize] = null; - } - } - return (E)old; - } - - /** - * Return the number of items in this array map. - */ - @Override - public int size() { - return mSize; - } - - @Override - public Object[] toArray() { - Object[] result = new Object[mSize]; - System.arraycopy(mArray, 0, result, 0, mSize); - return result; - } - - @Override - public T[] toArray(T[] array) { - if (array.length < mSize) { - @SuppressWarnings("unchecked") T[] newArray - = (T[]) Array.newInstance(array.getClass().getComponentType(), mSize); - array = newArray; - } - System.arraycopy(mArray, 0, array, 0, mSize); - if (array.length > mSize) { - array[mSize] = null; - } - return array; - } - - /** - * {@inheritDoc} - * - *

    This implementation returns false if the object is not a set, or - * if the sets have different sizes. Otherwise, for each value in this - * set, it checks to make sure the value also exists in the other set. - * If any value doesn't exist, the method returns false; otherwise, it - * returns true. - */ - @Override - public boolean equals(Object object) { - if (this == object) { - return true; - } - if (object instanceof Set) { - Set set = (Set) object; - if (size() != set.size()) { - return false; - } - - try { - for (int i=0; iThis implementation composes a string by iterating over its values. If - * this set contains itself as a value, the string "(this Set)" - * will appear in its place. - */ - @Override - public String toString() { - if (isEmpty()) { - return "{}"; - } - - StringBuilder buffer = new StringBuilder(mSize * 14); - buffer.append('{'); - for (int i=0; i 0) { - buffer.append(", "); - } - Object value = valueAt(i); - if (value != this) { - buffer.append(value); - } else { - buffer.append("(this Set)"); - } - } - buffer.append('}'); - return buffer.toString(); - } - - // ------------------------------------------------------------------------ - // Interop with traditional Java containers. Not as efficient as using - // specialized collection APIs. - // ------------------------------------------------------------------------ - - private MapCollections getCollection() { - if (mCollections == null) { - mCollections = new MapCollections() { - @Override - protected int colGetSize() { - return mSize; - } - - @Override - protected Object colGetEntry(int index, int offset) { - return mArray[index]; - } - - @Override - protected int colIndexOfKey(Object key) { - return indexOf(key); - } - - @Override - protected int colIndexOfValue(Object value) { - return indexOf(value); - } - - @Override - protected Map colGetMap() { - throw new UnsupportedOperationException("not a map"); - } - - @Override - protected void colPut(E key, E value) { - add(key); - } - - @Override - protected E colSetValue(int index, E value) { - throw new UnsupportedOperationException("not a map"); - } - - @Override - protected void colRemoveAt(int index) { - removeAt(index); - } - - @Override - protected void colClear() { - clear(); - } - }; - } - return mCollections; - } - - @Override - public Iterator iterator() { - return getCollection().getKeySet().iterator(); - } - - @Override - public boolean containsAll(Collection collection) { - Iterator it = collection.iterator(); - while (it.hasNext()) { - if (!contains(it.next())) { - return false; - } - } - return true; - } - - @Override - public boolean addAll(Collection collection) { - ensureCapacity(mSize + collection.size()); - boolean added = false; - for (E value : collection) { - added |= add(value); - } - return added; - } - - @Override - public boolean removeAll(Collection collection) { - boolean removed = false; - for (Object value : collection) { - removed |= remove(value); - } - return removed; - } - - @Override - public boolean retainAll(Collection collection) { - boolean removed = false; - for (int i=mSize-1; i>=0; i--) { - if (!collection.contains(mArray[i])) { - removeAt(i); - removed = true; - } - } - return removed; - } -} diff --git a/src/main/java/android/util/AtomicFile.java b/src/main/java/android/util/AtomicFile.java deleted file mode 100644 index a6466fc..0000000 --- a/src/main/java/android/util/AtomicFile.java +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import android.os.FileUtils; -import android.util.Log; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; - -/** - * Helper class for performing atomic operations on a file by creating a - * backup file until a write has successfully completed. If you need this - * on older versions of the platform you can use - * {@link android.support.v4.util.AtomicFile} in the v4 support library. - *

    - * Atomic file guarantees file integrity by ensuring that a file has - * been completely written and sync'd to disk before removing its backup. - * As long as the backup file exists, the original file is considered - * to be invalid (left over from a previous attempt to write the file). - *

    - * Atomic file does not confer any file locking semantics. - * Do not use this class when the file may be accessed or modified concurrently - * by multiple threads or processes. The caller is responsible for ensuring - * appropriate mutual exclusion invariants whenever it accesses the file. - *

    - */ -public class AtomicFile { - private final File mBaseName; - private final File mBackupName; - - /** - * Create a new AtomicFile for a file located at the given File path. - * The secondary backup file will be the same file path with ".bak" appended. - */ - public AtomicFile(File baseName) { - mBaseName = baseName; - mBackupName = new File(baseName.getPath() + ".bak"); - } - - /** - * Return the path to the base file. You should not generally use this, - * as the data at that path may not be valid. - */ - public File getBaseFile() { - return mBaseName; - } - - /** - * Delete the atomic file. This deletes both the base and backup files. - */ - public void delete() { - mBaseName.delete(); - mBackupName.delete(); - } - - /** - * Start a new write operation on the file. This returns a FileOutputStream - * to which you can write the new file data. The existing file is replaced - * with the new data. You must not directly close the given - * FileOutputStream; instead call either {@link #finishWrite(FileOutputStream)} - * or {@link #failWrite(FileOutputStream)}. - * - *

    Note that if another thread is currently performing - * a write, this will simply replace whatever that thread is writing - * with the new file being written by this thread, and when the other - * thread finishes the write the new write operation will no longer be - * safe (or will be lost). You must do your own threading protection for - * access to AtomicFile. - */ - public FileOutputStream startWrite() throws IOException { - // Rename the current file so it may be used as a backup during the next read - if (mBaseName.exists()) { - if (!mBackupName.exists()) { - if (!mBaseName.renameTo(mBackupName)) { - Log.w("AtomicFile", "Couldn't rename file " + mBaseName - + " to backup file " + mBackupName); - } - } else { - mBaseName.delete(); - } - } - FileOutputStream str = null; - try { - str = new FileOutputStream(mBaseName); - } catch (FileNotFoundException e) { - File parent = mBaseName.getParentFile(); - if (!parent.mkdir()) { - throw new IOException("Couldn't create directory " + mBaseName); - } - FileUtils.setPermissions( - parent.getPath(), - FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH, - -1, -1); - try { - str = new FileOutputStream(mBaseName); - } catch (FileNotFoundException e2) { - throw new IOException("Couldn't create " + mBaseName); - } - } - return str; - } - - /** - * Call when you have successfully finished writing to the stream - * returned by {@link #startWrite()}. This will close, sync, and - * commit the new data. The next attempt to read the atomic file - * will return the new file stream. - */ - public void finishWrite(FileOutputStream str) { - if (str != null) { - FileUtils.sync(str); - try { - str.close(); - mBackupName.delete(); - } catch (IOException e) { - Log.w("AtomicFile", "finishWrite: Got exception:", e); - } - } - } - - /** - * Call when you have failed for some reason at writing to the stream - * returned by {@link #startWrite()}. This will close the current - * write stream, and roll back to the previous state of the file. - */ - public void failWrite(FileOutputStream str) { - if (str != null) { - FileUtils.sync(str); - try { - str.close(); - mBaseName.delete(); - mBackupName.renameTo(mBaseName); - } catch (IOException e) { - Log.w("AtomicFile", "failWrite: Got exception:", e); - } - } - } - - /** @hide - * @deprecated This is not safe. - */ - @Deprecated public void truncate() throws IOException { - try { - FileOutputStream fos = new FileOutputStream(mBaseName); - FileUtils.sync(fos); - fos.close(); - } catch (FileNotFoundException e) { - throw new IOException("Couldn't append " + mBaseName); - } catch (IOException e) { - } - } - - /** @hide - * @deprecated This is not safe. - */ - @Deprecated public FileOutputStream openAppend() throws IOException { - try { - return new FileOutputStream(mBaseName, true); - } catch (FileNotFoundException e) { - throw new IOException("Couldn't append " + mBaseName); - } - } - - /** - * Open the atomic file for reading. If there previously was an - * incomplete write, this will roll back to the last good data before - * opening for read. You should call close() on the FileInputStream when - * you are done reading from it. - * - *

    Note that if another thread is currently performing - * a write, this will incorrectly consider it to be in the state of a bad - * write and roll back, causing the new data currently being written to - * be dropped. You must do your own threading protection for access to - * AtomicFile. - */ - public FileInputStream openRead() throws FileNotFoundException { - if (mBackupName.exists()) { - mBaseName.delete(); - mBackupName.renameTo(mBaseName); - } - return new FileInputStream(mBaseName); - } - - /** - * Gets the last modified time of the atomic file. - * {@hide} - * - * @return last modified time in milliseconds since epoch. - * @throws IOException - */ - public long getLastModifiedTime() throws IOException { - if (mBackupName.exists()) { - return mBackupName.lastModified(); - } - return mBaseName.lastModified(); - } - - /** - * A convenience for {@link #openRead()} that also reads all of the - * file contents into a byte array which is returned. - */ - public byte[] readFully() throws IOException { - FileInputStream stream = openRead(); - try { - int pos = 0; - int avail = stream.available(); - byte[] data = new byte[avail]; - while (true) { - int amt = stream.read(data, pos, data.length-pos); - //Log.i("foo", "Read " + amt + " bytes at " + pos - // + " of avail " + data.length); - if (amt <= 0) { - //Log.i("foo", "**** FINISHED READING: pos=" + pos - // + " len=" + data.length); - return data; - } - pos += amt; - avail = stream.available(); - if (avail > data.length-pos) { - byte[] newData = new byte[pos+avail]; - System.arraycopy(data, 0, newData, 0, pos); - data = newData; - } - } - } finally { - stream.close(); - } - } -} diff --git a/src/main/java/android/util/AttributeSet.java b/src/main/java/android/util/AttributeSet.java deleted file mode 100644 index 74942ba..0000000 --- a/src/main/java/android/util/AttributeSet.java +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - - -/** - * A collection of attributes, as found associated with a tag in an XML - * document. Often you will not want to use this interface directly, instead - * passing it to {@link android.content.res.Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int) - * Resources.Theme.obtainStyledAttributes()} - * which will take care of parsing the attributes for you. In particular, - * the Resources API will convert resource references (attribute values such as - * "@string/my_label" in the original XML) to the desired type - * for you; if you use AttributeSet directly then you will need to manually - * check for resource references - * (with {@link #getAttributeResourceValue(int, int)}) and do the resource - * lookup yourself if needed. Direct use of AttributeSet also prevents the - * application of themes and styles when retrieving attribute values. - * - *

    This interface provides an efficient mechanism for retrieving - * data from compiled XML files, which can be retrieved for a particular - * XmlPullParser through {@link Xml#asAttributeSet - * Xml.asAttributeSet()}. Normally this will return an implementation - * of the interface that works on top of a generic XmlPullParser, however it - * is more useful in conjunction with compiled XML resources: - * - *

    - * XmlPullParser parser = resources.getXml(myResouce);
    - * AttributeSet attributes = Xml.asAttributeSet(parser);
    - * - *

    The implementation returned here, unlike using - * the implementation on top of a generic XmlPullParser, - * is highly optimized by retrieving pre-computed information that was - * generated by aapt when compiling your resources. For example, - * the {@link #getAttributeFloatValue(int, float)} method returns a floating - * point number previous stored in the compiled resource instead of parsing - * at runtime the string originally in the XML file. - * - *

    This interface also provides additional information contained in the - * compiled XML resource that is not available in a normal XML file, such - * as {@link #getAttributeNameResource(int)} which returns the resource - * identifier associated with a particular XML attribute name. - */ -public interface AttributeSet { - /** - * Returns the number of attributes available in the set. - * - * @return A positive integer, or 0 if the set is empty. - */ - public int getAttributeCount(); - - /** - * Returns the name of the specified attribute. - * - * @param index Index of the desired attribute, 0...count-1. - * - * @return A String containing the name of the attribute, or null if the - * attribute cannot be found. - */ - public String getAttributeName(int index); - - /** - * Returns the value of the specified attribute as a string representation. - * - * @param index Index of the desired attribute, 0...count-1. - * - * @return A String containing the value of the attribute, or null if the - * attribute cannot be found. - */ - public String getAttributeValue(int index); - - /** - * Returns the value of the specified attribute as a string representation. - * The lookup is performed using the attribute name. - * - * @param namespace The namespace of the attribute to get the value from. - * @param name The name of the attribute to get the value from. - * - * @return A String containing the value of the attribute, or null if the - * attribute cannot be found. - */ - public String getAttributeValue(String namespace, String name); - - /** - * Returns a description of the current position of the attribute set. - * For instance, if the attribute set is loaded from an XML document, - * the position description could indicate the current line number. - * - * @return A string representation of the current position in the set, - * may be null. - */ - public String getPositionDescription(); - - /** - * Return the resource ID associated with the given attribute name. This - * will be the identifier for an attribute resource, which can be used by - * styles. Returns 0 if there is no resource associated with this - * attribute. - * - *

    Note that this is different than {@link #getAttributeResourceValue} - * in that it returns a resource identifier for the attribute name; the - * other method returns this attribute's value as a resource identifier. - * - * @param index Index of the desired attribute, 0...count-1. - * - * @return The resource identifier, 0 if none. - */ - public int getAttributeNameResource(int index); - - /** - * Return the index of the value of 'attribute' in the list 'options'. - * - * @param namespace Namespace of attribute to retrieve. - * @param attribute Name of attribute to retrieve. - * @param options List of strings whose values we are checking against. - * @param defaultValue Value returned if attribute doesn't exist or no - * match is found. - * - * @return Index in to 'options' or defaultValue. - */ - public int getAttributeListValue(String namespace, String attribute, - String[] options, int defaultValue); - - /** - * Return the boolean value of 'attribute'. - * - * @param namespace Namespace of attribute to retrieve. - * @param attribute The attribute to retrieve. - * @param defaultValue What to return if the attribute isn't found. - * - * @return Resulting value. - */ - public boolean getAttributeBooleanValue(String namespace, String attribute, - boolean defaultValue); - - /** - * Return the value of 'attribute' as a resource identifier. - * - *

    Note that this is different than {@link #getAttributeNameResource} - * in that it returns the value contained in this attribute as a - * resource identifier (i.e., a value originally of the form - * "@package:type/resource"); the other method returns a resource - * identifier that identifies the name of the attribute. - * - * @param namespace Namespace of attribute to retrieve. - * @param attribute The attribute to retrieve. - * @param defaultValue What to return if the attribute isn't found. - * - * @return Resulting value. - */ - public int getAttributeResourceValue(String namespace, String attribute, - int defaultValue); - - /** - * Return the integer value of 'attribute'. - * - * @param namespace Namespace of attribute to retrieve. - * @param attribute The attribute to retrieve. - * @param defaultValue What to return if the attribute isn't found. - * - * @return Resulting value. - */ - public int getAttributeIntValue(String namespace, String attribute, - int defaultValue); - - /** - * Return the boolean value of 'attribute' that is formatted as an - * unsigned value. In particular, the formats 0xn...n and #n...n are - * handled. - * - * @param namespace Namespace of attribute to retrieve. - * @param attribute The attribute to retrieve. - * @param defaultValue What to return if the attribute isn't found. - * - * @return Resulting value. - */ - public int getAttributeUnsignedIntValue(String namespace, String attribute, - int defaultValue); - - /** - * Return the float value of 'attribute'. - * - * @param namespace Namespace of attribute to retrieve. - * @param attribute The attribute to retrieve. - * @param defaultValue What to return if the attribute isn't found. - * - * @return Resulting value. - */ - public float getAttributeFloatValue(String namespace, String attribute, - float defaultValue); - - /** - * Return the index of the value of attribute at 'index' in the list - * 'options'. - * - * @param index Index of the desired attribute, 0...count-1. - * @param options List of strings whose values we are checking against. - * @param defaultValue Value returned if attribute doesn't exist or no - * match is found. - * - * @return Index in to 'options' or defaultValue. - */ - public int getAttributeListValue(int index, String[] options, int defaultValue); - - /** - * Return the boolean value of attribute at 'index'. - * - * @param index Index of the desired attribute, 0...count-1. - * @param defaultValue What to return if the attribute isn't found. - * - * @return Resulting value. - */ - public boolean getAttributeBooleanValue(int index, boolean defaultValue); - - /** - * Return the value of attribute at 'index' as a resource identifier. - * - *

    Note that this is different than {@link #getAttributeNameResource} - * in that it returns the value contained in this attribute as a - * resource identifier (i.e., a value originally of the form - * "@package:type/resource"); the other method returns a resource - * identifier that identifies the name of the attribute. - * - * @param index Index of the desired attribute, 0...count-1. - * @param defaultValue What to return if the attribute isn't found. - * - * @return Resulting value. - */ - public int getAttributeResourceValue(int index, int defaultValue); - - /** - * Return the integer value of attribute at 'index'. - * - * @param index Index of the desired attribute, 0...count-1. - * @param defaultValue What to return if the attribute isn't found. - * - * @return Resulting value. - */ - public int getAttributeIntValue(int index, int defaultValue); - - /** - * Return the integer value of attribute at 'index' that is formatted as an - * unsigned value. In particular, the formats 0xn...n and #n...n are - * handled. - * - * @param index Index of the desired attribute, 0...count-1. - * @param defaultValue What to return if the attribute isn't found. - * - * @return Resulting value. - */ - public int getAttributeUnsignedIntValue(int index, int defaultValue); - - /** - * Return the float value of attribute at 'index'. - * - * @param index Index of the desired attribute, 0...count-1. - * @param defaultValue What to return if the attribute isn't found. - * - * @return Resulting value. - */ - public float getAttributeFloatValue(int index, float defaultValue); - - /** - * Return the value of the "id" attribute or null if there is not one. - * Equivalent to getAttributeValue(null, "id"). - * - * @return The id attribute's value or null. - */ - public String getIdAttribute(); - - /** - * Return the value of the "class" attribute or null if there is not one. - * Equivalent to getAttributeValue(null, "class"). - * - * @return The class attribute's value or null. - */ - public String getClassAttribute(); - - /** - * Return the integer value of the "id" attribute or defaultValue if there - * is none. - * Equivalent to getAttributeResourceValue(null, "id", defaultValue); - * - * @param defaultValue What to return if the "id" attribute isn't found. - * @return int Resulting value. - */ - public int getIdAttributeResourceValue(int defaultValue); - - /** - - * Return the value of the "style" attribute or 0 if there is not one. - * Equivalent to getAttributeResourceValue(null, "style"). - * - * @return The style attribute's resource identifier or 0. - */ - public int getStyleAttribute(); -} diff --git a/src/main/java/android/util/Base64.java b/src/main/java/android/util/Base64.java deleted file mode 100644 index 1f2a5a7..0000000 --- a/src/main/java/android/util/Base64.java +++ /dev/null @@ -1,741 +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.util; - -import java.io.UnsupportedEncodingException; - -/** - * Utilities for encoding and decoding the Base64 representation of - * binary data. See RFCs 2045 and 3548. - */ -public class Base64 { - /** - * Default values for encoder/decoder flags. - */ - public static final int DEFAULT = 0; - - /** - * Encoder flag bit to omit the padding '=' characters at the end - * of the output (if any). - */ - public static final int NO_PADDING = 1; - - /** - * Encoder flag bit to omit all line terminators (i.e., the output - * will be on one long line). - */ - public static final int NO_WRAP = 2; - - /** - * Encoder flag bit to indicate lines should be terminated with a - * CRLF pair instead of just an LF. Has no effect if {@code - * NO_WRAP} is specified as well. - */ - public static final int CRLF = 4; - - /** - * Encoder/decoder flag bit to indicate using the "URL and - * filename safe" variant of Base64 (see RFC 3548 section 4) where - * {@code -} and {@code _} are used in place of {@code +} and - * {@code /}. - */ - public static final int URL_SAFE = 8; - - /** - * Flag to pass to {@link Base64OutputStream} to indicate that it - * should not close the output stream it is wrapping when it - * itself is closed. - */ - public static final int NO_CLOSE = 16; - - // -------------------------------------------------------- - // shared code - // -------------------------------------------------------- - - /* package */ static abstract class Coder { - public byte[] output; - public int op; - - /** - * Encode/decode another block of input data. this.output is - * provided by the caller, and must be big enough to hold all - * the coded data. On exit, this.opwill be set to the length - * of the coded data. - * - * @param finish true if this is the final call to process for - * this object. Will finalize the coder state and - * include any final bytes in the output. - * - * @return true if the input so far is good; false if some - * error has been detected in the input stream.. - */ - public abstract boolean process(byte[] input, int offset, int len, boolean finish); - - /** - * @return the maximum number of bytes a call to process() - * could produce for the given number of input bytes. This may - * be an overestimate. - */ - public abstract int maxOutputSize(int len); - } - - // -------------------------------------------------------- - // decoding - // -------------------------------------------------------- - - /** - * Decode the Base64-encoded data in input and return the data in - * a new byte array. - * - *

    The padding '=' characters at the end are considered optional, but - * if any are present, there must be the correct number of them. - * - * @param str the input String to decode, which is converted to - * bytes using the default charset - * @param flags controls certain features of the decoded output. - * Pass {@code DEFAULT} to decode standard Base64. - * - * @throws IllegalArgumentException if the input contains - * incorrect padding - */ - public static byte[] decode(String str, int flags) { - return decode(str.getBytes(), flags); - } - - /** - * Decode the Base64-encoded data in input and return the data in - * a new byte array. - * - *

    The padding '=' characters at the end are considered optional, but - * if any are present, there must be the correct number of them. - * - * @param input the input array to decode - * @param flags controls certain features of the decoded output. - * Pass {@code DEFAULT} to decode standard Base64. - * - * @throws IllegalArgumentException if the input contains - * incorrect padding - */ - public static byte[] decode(byte[] input, int flags) { - return decode(input, 0, input.length, flags); - } - - /** - * Decode the Base64-encoded data in input and return the data in - * a new byte array. - * - *

    The padding '=' characters at the end are considered optional, but - * if any are present, there must be the correct number of them. - * - * @param input the data to decode - * @param offset the position within the input array at which to start - * @param len the number of bytes of input to decode - * @param flags controls certain features of the decoded output. - * Pass {@code DEFAULT} to decode standard Base64. - * - * @throws IllegalArgumentException if the input contains - * incorrect padding - */ - public static byte[] decode(byte[] input, int offset, int len, int flags) { - // Allocate space for the most data the input could represent. - // (It could contain less if it contains whitespace, etc.) - Decoder decoder = new Decoder(flags, new byte[len*3/4]); - - if (!decoder.process(input, offset, len, true)) { - throw new IllegalArgumentException("bad base-64"); - } - - // Maybe we got lucky and allocated exactly enough output space. - if (decoder.op == decoder.output.length) { - return decoder.output; - } - - // Need to shorten the array, so allocate a new one of the - // right size and copy. - byte[] temp = new byte[decoder.op]; - System.arraycopy(decoder.output, 0, temp, 0, decoder.op); - return temp; - } - - /* package */ static class Decoder extends Coder { - /** - * Lookup table for turning bytes into their position in the - * Base64 alphabet. - */ - private static final int DECODE[] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1, - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, - -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - }; - - /** - * Decode lookup table for the "web safe" variant (RFC 3548 - * sec. 4) where - and _ replace + and /. - */ - private static final int DECODE_WEBSAFE[] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1, - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, - -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - }; - - /** Non-data values in the DECODE arrays. */ - private static final int SKIP = -1; - private static final int EQUALS = -2; - - /** - * States 0-3 are reading through the next input tuple. - * State 4 is having read one '=' and expecting exactly - * one more. - * State 5 is expecting no more data or padding characters - * in the input. - * State 6 is the error state; an error has been detected - * in the input and no future input can "fix" it. - */ - private int state; // state number (0 to 6) - private int value; - - final private int[] alphabet; - - public Decoder(int flags, byte[] output) { - this.output = output; - - alphabet = ((flags & URL_SAFE) == 0) ? DECODE : DECODE_WEBSAFE; - state = 0; - value = 0; - } - - /** - * @return an overestimate for the number of bytes {@code - * len} bytes could decode to. - */ - public int maxOutputSize(int len) { - return len * 3/4 + 10; - } - - /** - * Decode another block of input data. - * - * @return true if the state machine is still healthy. false if - * bad base-64 data has been detected in the input stream. - */ - public boolean process(byte[] input, int offset, int len, boolean finish) { - if (this.state == 6) return false; - - int p = offset; - len += offset; - - // Using local variables makes the decoder about 12% - // faster than if we manipulate the member variables in - // the loop. (Even alphabet makes a measurable - // difference, which is somewhat surprising to me since - // the member variable is final.) - int state = this.state; - int value = this.value; - int op = 0; - final byte[] output = this.output; - final int[] alphabet = this.alphabet; - - while (p < len) { - // Try the fast path: we're starting a new tuple and the - // next four bytes of the input stream are all data - // bytes. This corresponds to going through states - // 0-1-2-3-0. We expect to use this method for most of - // the data. - // - // If any of the next four bytes of input are non-data - // (whitespace, etc.), value will end up negative. (All - // the non-data values in decode are small negative - // numbers, so shifting any of them up and or'ing them - // together will result in a value with its top bit set.) - // - // You can remove this whole block and the output should - // be the same, just slower. - if (state == 0) { - while (p+4 <= len && - (value = ((alphabet[input[p] & 0xff] << 18) | - (alphabet[input[p+1] & 0xff] << 12) | - (alphabet[input[p+2] & 0xff] << 6) | - (alphabet[input[p+3] & 0xff]))) >= 0) { - output[op+2] = (byte) value; - output[op+1] = (byte) (value >> 8); - output[op] = (byte) (value >> 16); - op += 3; - p += 4; - } - if (p >= len) break; - } - - // The fast path isn't available -- either we've read a - // partial tuple, or the next four input bytes aren't all - // data, or whatever. Fall back to the slower state - // machine implementation. - - int d = alphabet[input[p++] & 0xff]; - - switch (state) { - case 0: - if (d >= 0) { - value = d; - ++state; - } else if (d != SKIP) { - this.state = 6; - return false; - } - break; - - case 1: - if (d >= 0) { - value = (value << 6) | d; - ++state; - } else if (d != SKIP) { - this.state = 6; - return false; - } - break; - - case 2: - if (d >= 0) { - value = (value << 6) | d; - ++state; - } else if (d == EQUALS) { - // Emit the last (partial) output tuple; - // expect exactly one more padding character. - output[op++] = (byte) (value >> 4); - state = 4; - } else if (d != SKIP) { - this.state = 6; - return false; - } - break; - - case 3: - if (d >= 0) { - // Emit the output triple and return to state 0. - value = (value << 6) | d; - output[op+2] = (byte) value; - output[op+1] = (byte) (value >> 8); - output[op] = (byte) (value >> 16); - op += 3; - state = 0; - } else if (d == EQUALS) { - // Emit the last (partial) output tuple; - // expect no further data or padding characters. - output[op+1] = (byte) (value >> 2); - output[op] = (byte) (value >> 10); - op += 2; - state = 5; - } else if (d != SKIP) { - this.state = 6; - return false; - } - break; - - case 4: - if (d == EQUALS) { - ++state; - } else if (d != SKIP) { - this.state = 6; - return false; - } - break; - - case 5: - if (d != SKIP) { - this.state = 6; - return false; - } - break; - } - } - - if (!finish) { - // We're out of input, but a future call could provide - // more. - this.state = state; - this.value = value; - this.op = op; - return true; - } - - // Done reading input. Now figure out where we are left in - // the state machine and finish up. - - switch (state) { - case 0: - // Output length is a multiple of three. Fine. - break; - case 1: - // Read one extra input byte, which isn't enough to - // make another output byte. Illegal. - this.state = 6; - return false; - case 2: - // Read two extra input bytes, enough to emit 1 more - // output byte. Fine. - output[op++] = (byte) (value >> 4); - break; - case 3: - // Read three extra input bytes, enough to emit 2 more - // output bytes. Fine. - output[op++] = (byte) (value >> 10); - output[op++] = (byte) (value >> 2); - break; - case 4: - // Read one padding '=' when we expected 2. Illegal. - this.state = 6; - return false; - case 5: - // Read all the padding '='s we expected and no more. - // Fine. - break; - } - - this.state = state; - this.op = op; - return true; - } - } - - // -------------------------------------------------------- - // encoding - // -------------------------------------------------------- - - /** - * Base64-encode the given data and return a newly allocated - * String with the result. - * - * @param input the data to encode - * @param flags controls certain features of the encoded output. - * Passing {@code DEFAULT} results in output that - * adheres to RFC 2045. - */ - public static String encodeToString(byte[] input, int flags) { - try { - return new String(encode(input, flags), "US-ASCII"); - } catch (UnsupportedEncodingException e) { - // US-ASCII is guaranteed to be available. - throw new AssertionError(e); - } - } - - /** - * Base64-encode the given data and return a newly allocated - * String with the result. - * - * @param input the data to encode - * @param offset the position within the input array at which to - * start - * @param len the number of bytes of input to encode - * @param flags controls certain features of the encoded output. - * Passing {@code DEFAULT} results in output that - * adheres to RFC 2045. - */ - public static String encodeToString(byte[] input, int offset, int len, int flags) { - try { - return new String(encode(input, offset, len, flags), "US-ASCII"); - } catch (UnsupportedEncodingException e) { - // US-ASCII is guaranteed to be available. - throw new AssertionError(e); - } - } - - /** - * Base64-encode the given data and return a newly allocated - * byte[] with the result. - * - * @param input the data to encode - * @param flags controls certain features of the encoded output. - * Passing {@code DEFAULT} results in output that - * adheres to RFC 2045. - */ - public static byte[] encode(byte[] input, int flags) { - return encode(input, 0, input.length, flags); - } - - /** - * Base64-encode the given data and return a newly allocated - * byte[] with the result. - * - * @param input the data to encode - * @param offset the position within the input array at which to - * start - * @param len the number of bytes of input to encode - * @param flags controls certain features of the encoded output. - * Passing {@code DEFAULT} results in output that - * adheres to RFC 2045. - */ - public static byte[] encode(byte[] input, int offset, int len, int flags) { - Encoder encoder = new Encoder(flags, null); - - // Compute the exact length of the array we will produce. - int output_len = len / 3 * 4; - - // Account for the tail of the data and the padding bytes, if any. - if (encoder.do_padding) { - if (len % 3 > 0) { - output_len += 4; - } - } else { - switch (len % 3) { - case 0: break; - case 1: output_len += 2; break; - case 2: output_len += 3; break; - } - } - - // Account for the newlines, if any. - if (encoder.do_newline && len > 0) { - output_len += (((len-1) / (3 * Encoder.LINE_GROUPS)) + 1) * - (encoder.do_cr ? 2 : 1); - } - - encoder.output = new byte[output_len]; - encoder.process(input, offset, len, true); - - assert encoder.op == output_len; - - return encoder.output; - } - - /* package */ static class Encoder extends Coder { - /** - * Emit a new line every this many output tuples. Corresponds to - * a 76-character line length (the maximum allowable according to - * RFC 2045). - */ - public static final int LINE_GROUPS = 19; - - /** - * Lookup table for turning Base64 alphabet positions (6 bits) - * into output bytes. - */ - private static final byte ENCODE[] = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', - 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', - 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', - }; - - /** - * Lookup table for turning Base64 alphabet positions (6 bits) - * into output bytes. - */ - private static final byte ENCODE_WEBSAFE[] = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', - 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', - 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_', - }; - - final private byte[] tail; - /* package */ int tailLen; - private int count; - - final public boolean do_padding; - final public boolean do_newline; - final public boolean do_cr; - final private byte[] alphabet; - - public Encoder(int flags, byte[] output) { - this.output = output; - - do_padding = (flags & NO_PADDING) == 0; - do_newline = (flags & NO_WRAP) == 0; - do_cr = (flags & CRLF) != 0; - alphabet = ((flags & URL_SAFE) == 0) ? ENCODE : ENCODE_WEBSAFE; - - tail = new byte[2]; - tailLen = 0; - - count = do_newline ? LINE_GROUPS : -1; - } - - /** - * @return an overestimate for the number of bytes {@code - * len} bytes could encode to. - */ - public int maxOutputSize(int len) { - return len * 8/5 + 10; - } - - public boolean process(byte[] input, int offset, int len, boolean finish) { - // Using local variables makes the encoder about 9% faster. - final byte[] alphabet = this.alphabet; - final byte[] output = this.output; - int op = 0; - int count = this.count; - - int p = offset; - len += offset; - int v = -1; - - // First we need to concatenate the tail of the previous call - // with any input bytes available now and see if we can empty - // the tail. - - switch (tailLen) { - case 0: - // There was no tail. - break; - - case 1: - if (p+2 <= len) { - // A 1-byte tail with at least 2 bytes of - // input available now. - v = ((tail[0] & 0xff) << 16) | - ((input[p++] & 0xff) << 8) | - (input[p++] & 0xff); - tailLen = 0; - }; - break; - - case 2: - if (p+1 <= len) { - // A 2-byte tail with at least 1 byte of input. - v = ((tail[0] & 0xff) << 16) | - ((tail[1] & 0xff) << 8) | - (input[p++] & 0xff); - tailLen = 0; - } - break; - } - - if (v != -1) { - output[op++] = alphabet[(v >> 18) & 0x3f]; - output[op++] = alphabet[(v >> 12) & 0x3f]; - output[op++] = alphabet[(v >> 6) & 0x3f]; - output[op++] = alphabet[v & 0x3f]; - if (--count == 0) { - if (do_cr) output[op++] = '\r'; - output[op++] = '\n'; - count = LINE_GROUPS; - } - } - - // At this point either there is no tail, or there are fewer - // than 3 bytes of input available. - - // The main loop, turning 3 input bytes into 4 output bytes on - // each iteration. - while (p+3 <= len) { - v = ((input[p] & 0xff) << 16) | - ((input[p+1] & 0xff) << 8) | - (input[p+2] & 0xff); - output[op] = alphabet[(v >> 18) & 0x3f]; - output[op+1] = alphabet[(v >> 12) & 0x3f]; - output[op+2] = alphabet[(v >> 6) & 0x3f]; - output[op+3] = alphabet[v & 0x3f]; - p += 3; - op += 4; - if (--count == 0) { - if (do_cr) output[op++] = '\r'; - output[op++] = '\n'; - count = LINE_GROUPS; - } - } - - if (finish) { - // Finish up the tail of the input. Note that we need to - // consume any bytes in tail before any bytes - // remaining in input; there should be at most two bytes - // total. - - if (p-tailLen == len-1) { - int t = 0; - v = ((tailLen > 0 ? tail[t++] : input[p++]) & 0xff) << 4; - tailLen -= t; - output[op++] = alphabet[(v >> 6) & 0x3f]; - output[op++] = alphabet[v & 0x3f]; - if (do_padding) { - output[op++] = '='; - output[op++] = '='; - } - if (do_newline) { - if (do_cr) output[op++] = '\r'; - output[op++] = '\n'; - } - } else if (p-tailLen == len-2) { - int t = 0; - v = (((tailLen > 1 ? tail[t++] : input[p++]) & 0xff) << 10) | - (((tailLen > 0 ? tail[t++] : input[p++]) & 0xff) << 2); - tailLen -= t; - output[op++] = alphabet[(v >> 12) & 0x3f]; - output[op++] = alphabet[(v >> 6) & 0x3f]; - output[op++] = alphabet[v & 0x3f]; - if (do_padding) { - output[op++] = '='; - } - if (do_newline) { - if (do_cr) output[op++] = '\r'; - output[op++] = '\n'; - } - } else if (do_newline && op > 0 && count != LINE_GROUPS) { - if (do_cr) output[op++] = '\r'; - output[op++] = '\n'; - } - - assert tailLen == 0; - assert p == len; - } else { - // Save the leftovers in tail to be consumed on the next - // call to encodeInternal. - - if (p == len-1) { - tail[tailLen++] = input[p]; - } else if (p == len-2) { - tail[tailLen++] = input[p]; - tail[tailLen++] = input[p+1]; - } - } - - this.op = op; - this.count = count; - - return true; - } - } - - private Base64() { } // don't instantiate -} diff --git a/src/main/java/android/util/Base64DataException.java b/src/main/java/android/util/Base64DataException.java deleted file mode 100644 index de12ee1..0000000 --- a/src/main/java/android/util/Base64DataException.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2011 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.util; - -import java.io.IOException; - -/** - * This exception is thrown by {@link Base64InputStream} or {@link Base64OutputStream} - * when an error is detected in the data being decoded. This allows problems with the base64 data - * to be disambiguated from errors in the underlying streams (e.g. actual connection errors.) - */ -public class Base64DataException extends IOException { - public Base64DataException(String detailMessage) { - super(detailMessage); - } -} diff --git a/src/main/java/android/util/Base64InputStream.java b/src/main/java/android/util/Base64InputStream.java deleted file mode 100644 index 9eba5b5..0000000 --- a/src/main/java/android/util/Base64InputStream.java +++ /dev/null @@ -1,153 +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.util; - -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; - -/** - * An InputStream that does Base64 decoding on the data read through - * it. - */ -public class Base64InputStream extends FilterInputStream { - private final Base64.Coder coder; - - private static byte[] EMPTY = new byte[0]; - - private static final int BUFFER_SIZE = 2048; - private boolean eof; - private byte[] inputBuffer; - private int outputStart; - private int outputEnd; - - /** - * An InputStream that performs Base64 decoding on the data read - * from the wrapped stream. - * - * @param in the InputStream to read the source data from - * @param flags bit flags for controlling the decoder; see the - * constants in {@link Base64} - */ - public Base64InputStream(InputStream in, int flags) { - this(in, flags, false); - } - - /** - * Performs Base64 encoding or decoding on the data read from the - * wrapped InputStream. - * - * @param in the InputStream to read the source data from - * @param flags bit flags for controlling the decoder; see the - * constants in {@link Base64} - * @param encode true to encode, false to decode - * - * @hide - */ - public Base64InputStream(InputStream in, int flags, boolean encode) { - super(in); - eof = false; - inputBuffer = new byte[BUFFER_SIZE]; - if (encode) { - coder = new Base64.Encoder(flags, null); - } else { - coder = new Base64.Decoder(flags, null); - } - coder.output = new byte[coder.maxOutputSize(BUFFER_SIZE)]; - outputStart = 0; - outputEnd = 0; - } - - public boolean markSupported() { - return false; - } - - public void mark(int readlimit) { - throw new UnsupportedOperationException(); - } - - public void reset() { - throw new UnsupportedOperationException(); - } - - public void close() throws IOException { - in.close(); - inputBuffer = null; - } - - public int available() { - return outputEnd - outputStart; - } - - public long skip(long n) throws IOException { - if (outputStart >= outputEnd) { - refill(); - } - if (outputStart >= outputEnd) { - return 0; - } - long bytes = Math.min(n, outputEnd-outputStart); - outputStart += bytes; - return bytes; - } - - public int read() throws IOException { - if (outputStart >= outputEnd) { - refill(); - } - if (outputStart >= outputEnd) { - return -1; - } else { - return coder.output[outputStart++] & 0xff; - } - } - - public int read(byte[] b, int off, int len) throws IOException { - if (outputStart >= outputEnd) { - refill(); - } - if (outputStart >= outputEnd) { - return -1; - } - int bytes = Math.min(len, outputEnd-outputStart); - System.arraycopy(coder.output, outputStart, b, off, bytes); - outputStart += bytes; - return bytes; - } - - /** - * Read data from the input stream into inputBuffer, then - * decode/encode it into the empty coder.output, and reset the - * outputStart and outputEnd pointers. - */ - private void refill() throws IOException { - if (eof) return; - int bytesRead = in.read(inputBuffer); - boolean success; - if (bytesRead == -1) { - eof = true; - success = coder.process(EMPTY, 0, 0, true); - } else { - success = coder.process(inputBuffer, 0, bytesRead, false); - } - if (!success) { - throw new Base64DataException("bad base-64"); - } - outputEnd = coder.op; - outputStart = 0; - } -} diff --git a/src/main/java/android/util/Base64OutputStream.java b/src/main/java/android/util/Base64OutputStream.java deleted file mode 100644 index 4535d1c..0000000 --- a/src/main/java/android/util/Base64OutputStream.java +++ /dev/null @@ -1,155 +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.util; - -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -/** - * An OutputStream that does Base64 encoding on the data written to - * it, writing the resulting data to another OutputStream. - */ -public class Base64OutputStream extends FilterOutputStream { - private final Base64.Coder coder; - private final int flags; - - private byte[] buffer = null; - private int bpos = 0; - - private static byte[] EMPTY = new byte[0]; - - /** - * Performs Base64 encoding on the data written to the stream, - * writing the encoded data to another OutputStream. - * - * @param out the OutputStream to write the encoded data to - * @param flags bit flags for controlling the encoder; see the - * constants in {@link Base64} - */ - public Base64OutputStream(OutputStream out, int flags) { - this(out, flags, true); - } - - /** - * Performs Base64 encoding or decoding on the data written to the - * stream, writing the encoded/decoded data to another - * OutputStream. - * - * @param out the OutputStream to write the encoded data to - * @param flags bit flags for controlling the encoder; see the - * constants in {@link Base64} - * @param encode true to encode, false to decode - * - * @hide - */ - public Base64OutputStream(OutputStream out, int flags, boolean encode) { - super(out); - this.flags = flags; - if (encode) { - coder = new Base64.Encoder(flags, null); - } else { - coder = new Base64.Decoder(flags, null); - } - } - - public void write(int b) throws IOException { - // To avoid invoking the encoder/decoder routines for single - // bytes, we buffer up calls to write(int) in an internal - // byte array to transform them into writes of decently-sized - // arrays. - - if (buffer == null) { - buffer = new byte[1024]; - } - if (bpos >= buffer.length) { - // internal buffer full; write it out. - internalWrite(buffer, 0, bpos, false); - bpos = 0; - } - buffer[bpos++] = (byte) b; - } - - /** - * Flush any buffered data from calls to write(int). Needed - * before doing a write(byte[], int, int) or a close(). - */ - private void flushBuffer() throws IOException { - if (bpos > 0) { - internalWrite(buffer, 0, bpos, false); - bpos = 0; - } - } - - public void write(byte[] b, int off, int len) throws IOException { - if (len <= 0) return; - flushBuffer(); - internalWrite(b, off, len, false); - } - - public void close() throws IOException { - IOException thrown = null; - try { - flushBuffer(); - internalWrite(EMPTY, 0, 0, true); - } catch (IOException e) { - thrown = e; - } - - try { - if ((flags & Base64.NO_CLOSE) == 0) { - out.close(); - } else { - out.flush(); - } - } catch (IOException e) { - if (thrown != null) { - thrown = e; - } - } - - if (thrown != null) { - throw thrown; - } - } - - /** - * Write the given bytes to the encoder/decoder. - * - * @param finish true if this is the last batch of input, to cause - * encoder/decoder state to be finalized. - */ - private void internalWrite(byte[] b, int off, int len, boolean finish) throws IOException { - coder.output = embiggen(coder.output, coder.maxOutputSize(len)); - if (!coder.process(b, off, len, finish)) { - throw new Base64DataException("bad base-64"); - } - out.write(coder.output, 0, coder.op); - } - - /** - * If b.length is at least len, return b. Otherwise return a new - * byte array of length len. - */ - private byte[] embiggen(byte[] b, int len) { - if (b == null || b.length < len) { - return new byte[len]; - } else { - return b; - } - } -} diff --git a/src/main/java/android/util/Base64Test.java b/src/main/java/android/util/Base64Test.java deleted file mode 100644 index 53368d4..0000000 --- a/src/main/java/android/util/Base64Test.java +++ /dev/null @@ -1,531 +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.util; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; -import junit.framework.TestCase; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.util.Random; - -public class Base64Test extends TestCase { - private static final String TAG = "Base64Test"; - - /** Decodes a string, returning a string. */ - private String decodeString(String in) throws Exception { - byte[] out = Base64.decode(in, 0); - return new String(out); - } - - /** - * Encodes the string 'in' using 'flags'. Asserts that decoding - * gives the same string. Returns the encoded string. - */ - private String encodeToString(String in, int flags) throws Exception { - String b64 = Base64.encodeToString(in.getBytes(), flags); - String dec = decodeString(b64); - assertEquals(in, dec); - return b64; - } - - /** Assert that decoding 'in' throws IllegalArgumentException. */ - private void assertBad(String in) throws Exception { - try { - byte[] out = Base64.decode(in, 0); - fail("should have failed to decode"); - } catch (IllegalArgumentException e) { - } - } - - /** Assert that actual equals the first len bytes of expected. */ - private void assertEquals(byte[] expected, int len, byte[] actual) { - assertEquals(len, actual.length); - for (int i = 0; i < len; ++i) { - assertEquals(expected[i], actual[i]); - } - } - - /** Assert that actual equals the first len bytes of expected. */ - private void assertEquals(byte[] expected, int len, byte[] actual, int alen) { - assertEquals(len, alen); - for (int i = 0; i < len; ++i) { - assertEquals(expected[i], actual[i]); - } - } - - /** Assert that actual equals the first len bytes of expected. */ - private void assertEquals(byte[] expected, byte[] actual) { - assertEquals(expected.length, actual.length); - for (int i = 0; i < expected.length; ++i) { - assertEquals(expected[i], actual[i]); - } - } - - public void testDecodeExtraChars() throws Exception { - // padding 0 - assertEquals("hello, world", decodeString("aGVsbG8sIHdvcmxk")); - assertBad("aGVsbG8sIHdvcmxk="); - assertBad("aGVsbG8sIHdvcmxk=="); - assertBad("aGVsbG8sIHdvcmxk ="); - assertBad("aGVsbG8sIHdvcmxk = = "); - assertEquals("hello, world", decodeString(" aGVs bG8s IHdv cmxk ")); - assertEquals("hello, world", decodeString(" aGV sbG8 sIHd vcmx k ")); - assertEquals("hello, world", decodeString(" aG VsbG 8sIH dvcm xk ")); - assertEquals("hello, world", decodeString(" a GVsb G8sI Hdvc mxk ")); - assertEquals("hello, world", decodeString(" a G V s b G 8 s I H d v c m x k ")); - assertEquals("hello, world", decodeString("_a*G_V*s_b*G_8*s_I*H_d*v_c*m_x*k_")); - assertEquals("hello, world", decodeString("aGVsbG8sIHdvcmxk")); - - // padding 1 - assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPyE=")); - assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPyE")); - assertBad("aGVsbG8sIHdvcmxkPyE=="); - assertBad("aGVsbG8sIHdvcmxkPyE =="); - assertBad("aGVsbG8sIHdvcmxkPyE = = "); - assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E=")); - assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E")); - assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E =")); - assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E ")); - assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E = ")); - assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E ")); - - // padding 2 - assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkLg==")); - assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkLg")); - assertBad("aGVsbG8sIHdvcmxkLg="); - assertBad("aGVsbG8sIHdvcmxkLg ="); - assertBad("aGVsbG8sIHdvcmxkLg = "); - assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g==")); - assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g")); - assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g ==")); - assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g ")); - assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g = = ")); - assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g ")); - } - - private static final byte[] BYTES = { (byte) 0xff, (byte) 0xee, (byte) 0xdd, - (byte) 0xcc, (byte) 0xbb, (byte) 0xaa, - (byte) 0x99, (byte) 0x88, (byte) 0x77 }; - - public void testBinaryDecode() throws Exception { - assertEquals(BYTES, 0, Base64.decode("", 0)); - assertEquals(BYTES, 1, Base64.decode("/w==", 0)); - assertEquals(BYTES, 2, Base64.decode("/+4=", 0)); - assertEquals(BYTES, 3, Base64.decode("/+7d", 0)); - assertEquals(BYTES, 4, Base64.decode("/+7dzA==", 0)); - assertEquals(BYTES, 5, Base64.decode("/+7dzLs=", 0)); - assertEquals(BYTES, 6, Base64.decode("/+7dzLuq", 0)); - assertEquals(BYTES, 7, Base64.decode("/+7dzLuqmQ==", 0)); - assertEquals(BYTES, 8, Base64.decode("/+7dzLuqmYg=", 0)); - } - - public void testWebSafe() throws Exception { - assertEquals(BYTES, 0, Base64.decode("", Base64.URL_SAFE)); - assertEquals(BYTES, 1, Base64.decode("_w==", Base64.URL_SAFE)); - assertEquals(BYTES, 2, Base64.decode("_-4=", Base64.URL_SAFE)); - assertEquals(BYTES, 3, Base64.decode("_-7d", Base64.URL_SAFE)); - assertEquals(BYTES, 4, Base64.decode("_-7dzA==", Base64.URL_SAFE)); - assertEquals(BYTES, 5, Base64.decode("_-7dzLs=", Base64.URL_SAFE)); - assertEquals(BYTES, 6, Base64.decode("_-7dzLuq", Base64.URL_SAFE)); - assertEquals(BYTES, 7, Base64.decode("_-7dzLuqmQ==", Base64.URL_SAFE)); - assertEquals(BYTES, 8, Base64.decode("_-7dzLuqmYg=", Base64.URL_SAFE)); - - assertEquals("", Base64.encodeToString(BYTES, 0, 0, Base64.URL_SAFE)); - assertEquals("_w==\n", Base64.encodeToString(BYTES, 0, 1, Base64.URL_SAFE)); - assertEquals("_-4=\n", Base64.encodeToString(BYTES, 0, 2, Base64.URL_SAFE)); - assertEquals("_-7d\n", Base64.encodeToString(BYTES, 0, 3, Base64.URL_SAFE)); - assertEquals("_-7dzA==\n", Base64.encodeToString(BYTES, 0, 4, Base64.URL_SAFE)); - assertEquals("_-7dzLs=\n", Base64.encodeToString(BYTES, 0, 5, Base64.URL_SAFE)); - assertEquals("_-7dzLuq\n", Base64.encodeToString(BYTES, 0, 6, Base64.URL_SAFE)); - assertEquals("_-7dzLuqmQ==\n", Base64.encodeToString(BYTES, 0, 7, Base64.URL_SAFE)); - assertEquals("_-7dzLuqmYg=\n", Base64.encodeToString(BYTES, 0, 8, Base64.URL_SAFE)); - } - - public void testFlags() throws Exception { - assertEquals("YQ==\n", encodeToString("a", 0)); - assertEquals("YQ==", encodeToString("a", Base64.NO_WRAP)); - assertEquals("YQ\n", encodeToString("a", Base64.NO_PADDING)); - assertEquals("YQ", encodeToString("a", Base64.NO_PADDING | Base64.NO_WRAP)); - assertEquals("YQ==\r\n", encodeToString("a", Base64.CRLF)); - assertEquals("YQ\r\n", encodeToString("a", Base64.CRLF | Base64.NO_PADDING)); - - assertEquals("YWI=\n", encodeToString("ab", 0)); - assertEquals("YWI=", encodeToString("ab", Base64.NO_WRAP)); - assertEquals("YWI\n", encodeToString("ab", Base64.NO_PADDING)); - assertEquals("YWI", encodeToString("ab", Base64.NO_PADDING | Base64.NO_WRAP)); - assertEquals("YWI=\r\n", encodeToString("ab", Base64.CRLF)); - assertEquals("YWI\r\n", encodeToString("ab", Base64.CRLF | Base64.NO_PADDING)); - - assertEquals("YWJj\n", encodeToString("abc", 0)); - assertEquals("YWJj", encodeToString("abc", Base64.NO_WRAP)); - assertEquals("YWJj\n", encodeToString("abc", Base64.NO_PADDING)); - assertEquals("YWJj", encodeToString("abc", Base64.NO_PADDING | Base64.NO_WRAP)); - assertEquals("YWJj\r\n", encodeToString("abc", Base64.CRLF)); - assertEquals("YWJj\r\n", encodeToString("abc", Base64.CRLF | Base64.NO_PADDING)); - - assertEquals("YWJjZA==\n", encodeToString("abcd", 0)); - assertEquals("YWJjZA==", encodeToString("abcd", Base64.NO_WRAP)); - assertEquals("YWJjZA\n", encodeToString("abcd", Base64.NO_PADDING)); - assertEquals("YWJjZA", encodeToString("abcd", Base64.NO_PADDING | Base64.NO_WRAP)); - assertEquals("YWJjZA==\r\n", encodeToString("abcd", Base64.CRLF)); - assertEquals("YWJjZA\r\n", encodeToString("abcd", Base64.CRLF | Base64.NO_PADDING)); - } - - public void testLineLength() throws Exception { - String in_56 = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd"; - String in_57 = in_56 + "e"; - String in_58 = in_56 + "ef"; - String in_59 = in_56 + "efg"; - String in_60 = in_56 + "efgh"; - String in_61 = in_56 + "efghi"; - - String prefix = "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5emFi"; - String out_56 = prefix + "Y2Q=\n"; - String out_57 = prefix + "Y2Rl\n"; - String out_58 = prefix + "Y2Rl\nZg==\n"; - String out_59 = prefix + "Y2Rl\nZmc=\n"; - String out_60 = prefix + "Y2Rl\nZmdo\n"; - String out_61 = prefix + "Y2Rl\nZmdoaQ==\n"; - - // no newline for an empty input array. - assertEquals("", encodeToString("", 0)); - - assertEquals(out_56, encodeToString(in_56, 0)); - assertEquals(out_57, encodeToString(in_57, 0)); - assertEquals(out_58, encodeToString(in_58, 0)); - assertEquals(out_59, encodeToString(in_59, 0)); - assertEquals(out_60, encodeToString(in_60, 0)); - assertEquals(out_61, encodeToString(in_61, 0)); - - assertEquals(out_56.replaceAll("=", ""), encodeToString(in_56, Base64.NO_PADDING)); - assertEquals(out_57.replaceAll("=", ""), encodeToString(in_57, Base64.NO_PADDING)); - assertEquals(out_58.replaceAll("=", ""), encodeToString(in_58, Base64.NO_PADDING)); - assertEquals(out_59.replaceAll("=", ""), encodeToString(in_59, Base64.NO_PADDING)); - assertEquals(out_60.replaceAll("=", ""), encodeToString(in_60, Base64.NO_PADDING)); - assertEquals(out_61.replaceAll("=", ""), encodeToString(in_61, Base64.NO_PADDING)); - - assertEquals(out_56.replaceAll("\n", ""), encodeToString(in_56, Base64.NO_WRAP)); - assertEquals(out_57.replaceAll("\n", ""), encodeToString(in_57, Base64.NO_WRAP)); - assertEquals(out_58.replaceAll("\n", ""), encodeToString(in_58, Base64.NO_WRAP)); - assertEquals(out_59.replaceAll("\n", ""), encodeToString(in_59, Base64.NO_WRAP)); - assertEquals(out_60.replaceAll("\n", ""), encodeToString(in_60, Base64.NO_WRAP)); - assertEquals(out_61.replaceAll("\n", ""), encodeToString(in_61, Base64.NO_WRAP)); - } - - /** - * Tests that Base64.Encoder.encode() does correct handling of the - * tail for each call. - * - * This test is disabled because while it passes if you can get it - * to run, android's test infrastructure currently doesn't allow - * us to get at package-private members (Base64.Encoder in - * this case). - */ - public void XXXtestEncodeInternal() throws Exception { - byte[] input = { (byte) 0x61, (byte) 0x62, (byte) 0x63 }; - byte[] output = new byte[100]; - - Base64.Encoder encoder = new Base64.Encoder(Base64.NO_PADDING | Base64.NO_WRAP, - output); - - encoder.process(input, 0, 3, false); - assertEquals("YWJj".getBytes(), 4, encoder.output, encoder.op); - assertEquals(0, encoder.tailLen); - - encoder.process(input, 0, 3, false); - assertEquals("YWJj".getBytes(), 4, encoder.output, encoder.op); - assertEquals(0, encoder.tailLen); - - encoder.process(input, 0, 1, false); - assertEquals(0, encoder.op); - assertEquals(1, encoder.tailLen); - - encoder.process(input, 0, 1, false); - assertEquals(0, encoder.op); - assertEquals(2, encoder.tailLen); - - encoder.process(input, 0, 1, false); - assertEquals("YWFh".getBytes(), 4, encoder.output, encoder.op); - assertEquals(0, encoder.tailLen); - - encoder.process(input, 0, 2, false); - assertEquals(0, encoder.op); - assertEquals(2, encoder.tailLen); - - encoder.process(input, 0, 2, false); - assertEquals("YWJh".getBytes(), 4, encoder.output, encoder.op); - assertEquals(1, encoder.tailLen); - - encoder.process(input, 0, 2, false); - assertEquals("YmFi".getBytes(), 4, encoder.output, encoder.op); - assertEquals(0, encoder.tailLen); - - encoder.process(input, 0, 1, true); - assertEquals("YQ".getBytes(), 2, encoder.output, encoder.op); - } - - private static final String lipsum = - "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " + - "Quisque congue eleifend odio, eu ornare nulla facilisis eget. " + - "Integer eget elit diam, sit amet laoreet nibh. Quisque enim " + - "urna, pharetra vitae consequat eget, adipiscing eu ante. " + - "Aliquam venenatis arcu nec nibh imperdiet tempor. In id dui " + - "eget lorem aliquam rutrum vel vitae eros. In placerat ornare " + - "pretium. Curabitur non fringilla mi. Fusce ultricies, turpis " + - "eu ultrices suscipit, ligula nisi consectetur eros, dapibus " + - "aliquet dui sapien a turpis. Donec ultricies varius ligula, " + - "ut hendrerit arcu malesuada at. Praesent sed elit pretium " + - "eros luctus gravida. In ac dolor lorem. Cras condimentum " + - "convallis elementum. Phasellus vel felis in nulla ultrices " + - "venenatis. Nam non tortor non orci convallis convallis. " + - "Nam tristique lacinia hendrerit. Pellentesque habitant morbi " + - "tristique senectus et netus et malesuada fames ac turpis " + - "egestas. Vivamus cursus, nibh eu imperdiet porta, magna " + - "ipsum mollis mauris, sit amet fringilla mi nisl eu mi. " + - "Phasellus posuere, leo at ultricies vehicula, massa risus " + - "volutpat sapien, eu tincidunt diam ipsum eget nulla. Cras " + - "molestie dapibus commodo. Ut vel tellus at massa gravida " + - "semper non sed orci."; - - public void testInputStream() throws Exception { - int[] flagses = { Base64.DEFAULT, - Base64.NO_PADDING, - Base64.NO_WRAP, - Base64.NO_PADDING | Base64.NO_WRAP, - Base64.CRLF, - Base64.URL_SAFE }; - int[] writeLengths = { -10, -5, -1, 0, 1, 1, 2, 2, 3, 10, 100 }; - Random rng = new Random(32176L); - - // Test input needs to be at least 2048 bytes to fill up the - // read buffer of Base64InputStream. - byte[] plain = (lipsum + lipsum + lipsum + lipsum + lipsum).getBytes(); - - for (int flags: flagses) { - byte[] encoded = Base64.encode(plain, flags); - - ByteArrayInputStream bais; - Base64InputStream b64is; - byte[] actual = new byte[plain.length * 2]; - int ap; - int b; - - // ----- test decoding ("encoded" -> "plain") ----- - - // read as much as it will give us in one chunk - bais = new ByteArrayInputStream(encoded); - b64is = new Base64InputStream(bais, flags); - ap = 0; - while ((b = b64is.read(actual, ap, actual.length-ap)) != -1) { - ap += b; - } - assertEquals(actual, ap, plain); - - // read individual bytes - bais = new ByteArrayInputStream(encoded); - b64is = new Base64InputStream(bais, flags); - ap = 0; - while ((b = b64is.read()) != -1) { - actual[ap++] = (byte) b; - } - assertEquals(actual, ap, plain); - - // mix reads of variously-sized arrays with one-byte reads - bais = new ByteArrayInputStream(encoded); - b64is = new Base64InputStream(bais, flags); - ap = 0; - readloop: while (true) { - int l = writeLengths[rng.nextInt(writeLengths.length)]; - if (l >= 0) { - b = b64is.read(actual, ap, l); - if (b == -1) break readloop; - ap += b; - } else { - for (int i = 0; i < -l; ++i) { - if ((b = b64is.read()) == -1) break readloop; - actual[ap++] = (byte) b; - } - } - } - assertEquals(actual, ap, plain); - - // ----- test encoding ("plain" -> "encoded") ----- - - // read as much as it will give us in one chunk - bais = new ByteArrayInputStream(plain); - b64is = new Base64InputStream(bais, flags, true); - ap = 0; - while ((b = b64is.read(actual, ap, actual.length-ap)) != -1) { - ap += b; - } - assertEquals(actual, ap, encoded); - - // read individual bytes - bais = new ByteArrayInputStream(plain); - b64is = new Base64InputStream(bais, flags, true); - ap = 0; - while ((b = b64is.read()) != -1) { - actual[ap++] = (byte) b; - } - assertEquals(actual, ap, encoded); - - // mix reads of variously-sized arrays with one-byte reads - bais = new ByteArrayInputStream(plain); - b64is = new Base64InputStream(bais, flags, true); - ap = 0; - readloop: while (true) { - int l = writeLengths[rng.nextInt(writeLengths.length)]; - if (l >= 0) { - b = b64is.read(actual, ap, l); - if (b == -1) break readloop; - ap += b; - } else { - for (int i = 0; i < -l; ++i) { - if ((b = b64is.read()) == -1) break readloop; - actual[ap++] = (byte) b; - } - } - } - assertEquals(actual, ap, encoded); - } - } - - /** http://b/3026478 */ - public void testSingleByteReads() throws IOException { - InputStream in = new Base64InputStream( - new ByteArrayInputStream("/v8=".getBytes()), Base64.DEFAULT); - assertEquals(254, in.read()); - assertEquals(255, in.read()); - } - - /** - * Tests that Base64OutputStream produces exactly the same results - * as calling Base64.encode/.decode on an in-memory array. - */ - public void testOutputStream() throws Exception { - int[] flagses = { Base64.DEFAULT, - Base64.NO_PADDING, - Base64.NO_WRAP, - Base64.NO_PADDING | Base64.NO_WRAP, - Base64.CRLF, - Base64.URL_SAFE }; - int[] writeLengths = { -10, -5, -1, 0, 1, 1, 2, 2, 3, 10, 100 }; - Random rng = new Random(32176L); - - // Test input needs to be at least 1024 bytes to test filling - // up the write(int) buffer of Base64OutputStream. - byte[] plain = (lipsum + lipsum).getBytes(); - - for (int flags: flagses) { - byte[] encoded = Base64.encode(plain, flags); - - ByteArrayOutputStream baos; - Base64OutputStream b64os; - byte[] actual; - int p; - - // ----- test encoding ("plain" -> "encoded") ----- - - // one large write(byte[]) of the whole input - baos = new ByteArrayOutputStream(); - b64os = new Base64OutputStream(baos, flags); - b64os.write(plain); - b64os.close(); - actual = baos.toByteArray(); - assertEquals(encoded, actual); - - // many calls to write(int) - baos = new ByteArrayOutputStream(); - b64os = new Base64OutputStream(baos, flags); - for (int i = 0; i < plain.length; ++i) { - b64os.write(plain[i]); - } - b64os.close(); - actual = baos.toByteArray(); - assertEquals(encoded, actual); - - // intermixed sequences of write(int) with - // write(byte[],int,int) of various lengths. - baos = new ByteArrayOutputStream(); - b64os = new Base64OutputStream(baos, flags); - p = 0; - while (p < plain.length) { - int l = writeLengths[rng.nextInt(writeLengths.length)]; - l = Math.min(l, plain.length-p); - if (l >= 0) { - b64os.write(plain, p, l); - p += l; - } else { - l = Math.min(-l, plain.length-p); - for (int i = 0; i < l; ++i) { - b64os.write(plain[p+i]); - } - p += l; - } - } - b64os.close(); - actual = baos.toByteArray(); - assertEquals(encoded, actual); - - // ----- test decoding ("encoded" -> "plain") ----- - - // one large write(byte[]) of the whole input - baos = new ByteArrayOutputStream(); - b64os = new Base64OutputStream(baos, flags, false); - b64os.write(encoded); - b64os.close(); - actual = baos.toByteArray(); - assertEquals(plain, actual); - - // many calls to write(int) - baos = new ByteArrayOutputStream(); - b64os = new Base64OutputStream(baos, flags, false); - for (int i = 0; i < encoded.length; ++i) { - b64os.write(encoded[i]); - } - b64os.close(); - actual = baos.toByteArray(); - assertEquals(plain, actual); - - // intermixed sequences of write(int) with - // write(byte[],int,int) of various lengths. - baos = new ByteArrayOutputStream(); - b64os = new Base64OutputStream(baos, flags, false); - p = 0; - while (p < encoded.length) { - int l = writeLengths[rng.nextInt(writeLengths.length)]; - l = Math.min(l, encoded.length-p); - if (l >= 0) { - b64os.write(encoded, p, l); - p += l; - } else { - l = Math.min(-l, encoded.length-p); - for (int i = 0; i < l; ++i) { - b64os.write(encoded[p+i]); - } - p += l; - } - } - b64os.close(); - actual = baos.toByteArray(); - assertEquals(plain, actual); - } - } -} diff --git a/src/main/java/android/util/BridgeXmlPullAttributes.java b/src/main/java/android/util/BridgeXmlPullAttributes.java deleted file mode 100644 index 691339e..0000000 --- a/src/main/java/android/util/BridgeXmlPullAttributes.java +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import com.android.ide.common.rendering.api.RenderResources; -import com.android.ide.common.rendering.api.ResourceValue; -import com.android.internal.util.XmlUtils; -import com.android.layoutlib.bridge.Bridge; -import com.android.layoutlib.bridge.BridgeConstants; -import com.android.layoutlib.bridge.android.BridgeContext; -import com.android.layoutlib.bridge.impl.ResourceHelper; -import com.android.resources.ResourceType; - -import org.xmlpull.v1.XmlPullParser; - -/** - * A correct implementation of the {@link AttributeSet} interface on top of a XmlPullParser - */ -public class BridgeXmlPullAttributes extends XmlPullAttributes { - - private final BridgeContext mContext; - private final boolean mPlatformFile; - - public BridgeXmlPullAttributes(XmlPullParser parser, BridgeContext context, - boolean platformFile) { - super(parser); - mContext = context; - mPlatformFile = platformFile; - } - - /* - * (non-Javadoc) - * @see android.util.XmlPullAttributes#getAttributeNameResource(int) - * - * This methods must return com.android.internal.R.attr. matching - * the name of the attribute. - * It returns 0 if it doesn't find anything. - */ - @Override - public int getAttributeNameResource(int index) { - // get the attribute name. - String name = getAttributeName(index); - - // get the attribute namespace - String ns = mParser.getAttributeNamespace(index); - - if (BridgeConstants.NS_RESOURCES.equals(ns)) { - Integer v = Bridge.getResourceId(ResourceType.ATTR, name); - if (v != null) { - return v.intValue(); - } - - return 0; - } - - // this is not an attribute in the android namespace, we query the customviewloader, if - // the namespaces match. - if (mContext.getProjectCallback().getNamespace().equals(ns)) { - Integer v = mContext.getProjectCallback().getResourceId(ResourceType.ATTR, name); - if (v != null) { - return v.intValue(); - } - } - - return 0; - } - - @Override - public int getAttributeListValue(String namespace, String attribute, - String[] options, int defaultValue) { - String value = getAttributeValue(namespace, attribute); - if (value != null) { - ResourceValue r = getResourceValue(value); - - if (r != null) { - value = r.getValue(); - } - - return XmlUtils.convertValueToList(value, options, defaultValue); - } - - return defaultValue; - } - - @Override - public boolean getAttributeBooleanValue(String namespace, String attribute, - boolean defaultValue) { - String value = getAttributeValue(namespace, attribute); - if (value != null) { - ResourceValue r = getResourceValue(value); - - if (r != null) { - value = r.getValue(); - } - - return XmlUtils.convertValueToBoolean(value, defaultValue); - } - - return defaultValue; - } - - @Override - public int getAttributeResourceValue(String namespace, String attribute, int defaultValue) { - String value = getAttributeValue(namespace, attribute); - - return resolveResourceValue(value, defaultValue); - } - - @Override - public int getAttributeIntValue(String namespace, String attribute, - int defaultValue) { - String value = getAttributeValue(namespace, attribute); - if (value != null) { - ResourceValue r = getResourceValue(value); - - if (r != null) { - value = r.getValue(); - } - - return XmlUtils.convertValueToInt(value, defaultValue); - } - - return defaultValue; - } - - @Override - public int getAttributeUnsignedIntValue(String namespace, String attribute, - int defaultValue) { - String value = getAttributeValue(namespace, attribute); - if (value != null) { - ResourceValue r = getResourceValue(value); - - if (r != null) { - value = r.getValue(); - } - - return XmlUtils.convertValueToUnsignedInt(value, defaultValue); - } - - return defaultValue; - } - - @Override - public float getAttributeFloatValue(String namespace, String attribute, - float defaultValue) { - String s = getAttributeValue(namespace, attribute); - if (s != null) { - ResourceValue r = getResourceValue(s); - - if (r != null) { - s = r.getValue(); - } - - return Float.parseFloat(s); - } - - return defaultValue; - } - - @Override - public int getAttributeListValue(int index, - String[] options, int defaultValue) { - return XmlUtils.convertValueToList( - getAttributeValue(index), options, defaultValue); - } - - @Override - public boolean getAttributeBooleanValue(int index, boolean defaultValue) { - String value = getAttributeValue(index); - if (value != null) { - ResourceValue r = getResourceValue(value); - - if (r != null) { - value = r.getValue(); - } - - return XmlUtils.convertValueToBoolean(value, defaultValue); - } - - return defaultValue; - } - - @Override - public int getAttributeResourceValue(int index, int defaultValue) { - String value = getAttributeValue(index); - - return resolveResourceValue(value, defaultValue); - } - - @Override - public int getAttributeIntValue(int index, int defaultValue) { - String value = getAttributeValue(index); - if (value != null) { - ResourceValue r = getResourceValue(value); - - if (r != null) { - value = r.getValue(); - } - - if (value.charAt(0) == '#') { - return ResourceHelper.getColor(value); - } - return XmlUtils.convertValueToInt(value, defaultValue); - } - - return defaultValue; - } - - @Override - public int getAttributeUnsignedIntValue(int index, int defaultValue) { - String value = getAttributeValue(index); - if (value != null) { - ResourceValue r = getResourceValue(value); - - if (r != null) { - value = r.getValue(); - } - - return XmlUtils.convertValueToUnsignedInt(value, defaultValue); - } - - return defaultValue; - } - - @Override - public float getAttributeFloatValue(int index, float defaultValue) { - String s = getAttributeValue(index); - if (s != null) { - ResourceValue r = getResourceValue(s); - - if (r != null) { - s = r.getValue(); - } - - return Float.parseFloat(s); - } - - return defaultValue; - } - - // -- private helper methods - - /** - * Returns a resolved {@link ResourceValue} from a given value. - */ - private ResourceValue getResourceValue(String value) { - // now look for this particular value - RenderResources resources = mContext.getRenderResources(); - return resources.resolveResValue(resources.findResValue(value, mPlatformFile)); - } - - /** - * Resolves and return a value to its associated integer. - */ - private int resolveResourceValue(String value, int defaultValue) { - ResourceValue resource = getResourceValue(value); - if (resource != null) { - Integer id = null; - if (mPlatformFile || resource.isFramework()) { - id = Bridge.getResourceId(resource.getResourceType(), resource.getName()); - } else { - id = mContext.getProjectCallback().getResourceId( - resource.getResourceType(), resource.getName()); - } - - if (id != null) { - return id; - } - } - - return defaultValue; - } -} diff --git a/src/main/java/android/util/Config.java b/src/main/java/android/util/Config.java deleted file mode 100644 index 70dc9aa..0000000 --- a/src/main/java/android/util/Config.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -/** - * @deprecated This class is not useful, it just returns the same value for - * all constants, and has always done this. Do not use it. - */ -@Deprecated -public final class Config { - /** @hide */ public Config() {} - - /** - * @deprecated Always false. - */ - @Deprecated - public static final boolean DEBUG = false; - - /** - * @deprecated Always true. - */ - @Deprecated - public static final boolean RELEASE = true; - - /** - * @deprecated Always false. - */ - @Deprecated - public static final boolean PROFILE = false; - - /** - * @deprecated Always false. - */ - @Deprecated - public static final boolean LOGV = false; - - /** - * @deprecated Always true. - */ - @Deprecated - public static final boolean LOGD = true; -} diff --git a/src/main/java/android/util/ContainerHelpers.java b/src/main/java/android/util/ContainerHelpers.java deleted file mode 100644 index 4e5fefb..0000000 --- a/src/main/java/android/util/ContainerHelpers.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2013 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.util; - -class ContainerHelpers { - - // This is Arrays.binarySearch(), but doesn't do any argument validation. - static int binarySearch(int[] array, int size, int value) { - int lo = 0; - int hi = size - 1; - - while (lo <= hi) { - final int mid = (lo + hi) >>> 1; - final int midVal = array[mid]; - - if (midVal < value) { - lo = mid + 1; - } else if (midVal > value) { - hi = mid - 1; - } else { - return mid; // value found - } - } - return ~lo; // value not present - } - - static int binarySearch(long[] array, int size, long value) { - int lo = 0; - int hi = size - 1; - - while (lo <= hi) { - final int mid = (lo + hi) >>> 1; - final long midVal = array[mid]; - - if (midVal < value) { - lo = mid + 1; - } else if (midVal > value) { - hi = mid - 1; - } else { - return mid; // value found - } - } - return ~lo; // value not present - } -} diff --git a/src/main/java/android/util/DayOfMonthCursor.java b/src/main/java/android/util/DayOfMonthCursor.java deleted file mode 100644 index 393b98e..0000000 --- a/src/main/java/android/util/DayOfMonthCursor.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -/** - * Helps control and display a month view of a calendar that has a current - * selected day. - *

      - *
    • Keeps track of current month, day, year
    • - *
    • Keeps track of current cursor position (row, column)
    • - *
    • Provides methods to help display the calendar
    • - *
    • Provides methods to move the cursor up / down / left / right.
    • - *
    - * - * This should be used by anyone who presents a month view to users and wishes - * to behave consistently with other widgets and apps; if we ever change our - * mind about when to flip the month, we can change it here only. - * - * @hide - */ -public class DayOfMonthCursor extends MonthDisplayHelper { - - private int mRow; - private int mColumn; - - /** - * @param year The initial year. - * @param month The initial month. - * @param dayOfMonth The initial dayOfMonth. - * @param weekStartDay What dayOfMonth of the week the week should start, - * in terms of {@link java.util.Calendar} constants such as - * {@link java.util.Calendar#SUNDAY}. - */ - public DayOfMonthCursor(int year, int month, int dayOfMonth, int weekStartDay) { - super(year, month, weekStartDay); - mRow = getRowOf(dayOfMonth); - mColumn = getColumnOf(dayOfMonth); - } - - - public int getSelectedRow() { - return mRow; - } - - public int getSelectedColumn() { - return mColumn; - } - - public void setSelectedRowColumn(int row, int col) { - mRow = row; - mColumn = col; - } - - public int getSelectedDayOfMonth() { - return getDayAt(mRow, mColumn); - } - - /** - * @return 0 if the selection is in the current month, otherwise -1 or +1 - * depending on whether the selection is in the first or last row. - */ - public int getSelectedMonthOffset() { - if (isWithinCurrentMonth(mRow, mColumn)) { - return 0; - } - if (mRow == 0) { - return -1; - } - return 1; - } - - public void setSelectedDayOfMonth(int dayOfMonth) { - mRow = getRowOf(dayOfMonth); - mColumn = getColumnOf(dayOfMonth); - } - - public boolean isSelected(int row, int column) { - return (mRow == row) && (mColumn == column); - } - - /** - * Move up one box, potentially flipping to the previous month. - * @return Whether the month was flipped to the previous month - * due to the move. - */ - public boolean up() { - if (isWithinCurrentMonth(mRow - 1, mColumn)) { - // within current month, just move up - mRow--; - return false; - } - // flip back to previous month, same column, first position within month - previousMonth(); - mRow = 5; - while(!isWithinCurrentMonth(mRow, mColumn)) { - mRow--; - } - return true; - } - - /** - * Move down one box, potentially flipping to the next month. - * @return Whether the month was flipped to the next month - * due to the move. - */ - public boolean down() { - if (isWithinCurrentMonth(mRow + 1, mColumn)) { - // within current month, just move down - mRow++; - return false; - } - // flip to next month, same column, first position within month - nextMonth(); - mRow = 0; - while (!isWithinCurrentMonth(mRow, mColumn)) { - mRow++; - } - return true; - } - - /** - * Move left one box, potentially flipping to the previous month. - * @return Whether the month was flipped to the previous month - * due to the move. - */ - public boolean left() { - if (mColumn == 0) { - mRow--; - mColumn = 6; - } else { - mColumn--; - } - - if (isWithinCurrentMonth(mRow, mColumn)) { - return false; - } - - // need to flip to last day of previous month - previousMonth(); - int lastDay = getNumberOfDaysInMonth(); - mRow = getRowOf(lastDay); - mColumn = getColumnOf(lastDay); - return true; - } - - /** - * Move right one box, potentially flipping to the next month. - * @return Whether the month was flipped to the next month - * due to the move. - */ - public boolean right() { - if (mColumn == 6) { - mRow++; - mColumn = 0; - } else { - mColumn++; - } - - if (isWithinCurrentMonth(mRow, mColumn)) { - return false; - } - - // need to flip to first day of next month - nextMonth(); - mRow = 0; - mColumn = 0; - while (!isWithinCurrentMonth(mRow, mColumn)) { - mColumn++; - } - return true; - } - -} diff --git a/src/main/java/android/util/DayOfMonthCursorTest.java b/src/main/java/android/util/DayOfMonthCursorTest.java deleted file mode 100644 index 4c5ad76..0000000 --- a/src/main/java/android/util/DayOfMonthCursorTest.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import junit.framework.TestCase; - -import java.util.Calendar; -import android.test.suitebuilder.annotation.SmallTest; - -/** - * Unit tests for {@link DayOfMonthCursor}. - */ -public class DayOfMonthCursorTest extends TestCase { - - @SmallTest - public void testMonthRows() { - DayOfMonthCursor mc = new DayOfMonthCursor(2007, - Calendar.SEPTEMBER, 11, Calendar.SUNDAY); - - assertArraysEqual(new int[]{26, 27, 28, 29, 30, 31, 1}, - mc.getDigitsForRow(0)); - assertArraysEqual(new int[]{2, 3, 4, 5, 6, 7, 8}, - mc.getDigitsForRow(1)); - assertArraysEqual(new int[]{30, 1, 2, 3, 4, 5, 6}, - mc.getDigitsForRow(5)); - } - - @SmallTest - public void testMoveLeft() { - DayOfMonthCursor mc = new DayOfMonthCursor(2007, - Calendar.SEPTEMBER, 3, Calendar.SUNDAY); - - assertEquals(Calendar.SEPTEMBER, mc.getMonth()); - assertEquals(3, mc.getSelectedDayOfMonth()); - assertEquals(1, mc.getSelectedRow()); - assertEquals(1, mc.getSelectedColumn()); - - // move left, still same row - assertFalse(mc.left()); - assertEquals(2, mc.getSelectedDayOfMonth()); - assertEquals(1, mc.getSelectedRow()); - assertEquals(0, mc.getSelectedColumn()); - - // wrap over to previous column, same month - assertFalse(mc.left()); - assertEquals(1, mc.getSelectedDayOfMonth()); - assertEquals(0, mc.getSelectedRow()); - assertEquals(6, mc.getSelectedColumn()); - - // wrap to previous month - assertTrue(mc.left()); - assertEquals(Calendar.AUGUST, mc.getMonth()); - assertEquals(31, mc.getSelectedDayOfMonth()); - assertEquals(4, mc.getSelectedRow()); - assertEquals(5, mc.getSelectedColumn()); - } - - @SmallTest - public void testMoveRight() { - DayOfMonthCursor mc = new DayOfMonthCursor(2007, - Calendar.SEPTEMBER, 28, Calendar.SUNDAY); - - assertEquals(Calendar.SEPTEMBER, mc.getMonth()); - assertEquals(28, mc.getSelectedDayOfMonth()); - assertEquals(4, mc.getSelectedRow()); - assertEquals(5, mc.getSelectedColumn()); - - // same row - assertFalse(mc.right()); - assertEquals(29, mc.getSelectedDayOfMonth()); - assertEquals(4, mc.getSelectedRow()); - assertEquals(6, mc.getSelectedColumn()); - - // wrap to next column, same month - assertFalse(mc.right()); - assertEquals(30, mc.getSelectedDayOfMonth()); - assertEquals(5, mc.getSelectedRow()); - assertEquals(0, mc.getSelectedColumn()); - - // next month - assertTrue(mc.right()); - assertEquals(Calendar.OCTOBER, mc.getMonth()); - assertEquals(1, mc.getSelectedDayOfMonth()); - assertEquals(0, mc.getSelectedRow()); - assertEquals(1, mc.getSelectedColumn()); - } - - @SmallTest - public void testMoveUp() { - DayOfMonthCursor mc = new DayOfMonthCursor(2007, - Calendar.SEPTEMBER, 13, Calendar.SUNDAY); - - assertEquals(Calendar.SEPTEMBER, mc.getMonth()); - assertEquals(13, mc.getSelectedDayOfMonth()); - assertEquals(2, mc.getSelectedRow()); - assertEquals(4, mc.getSelectedColumn()); - - // up, same month - assertFalse(mc.up()); - assertEquals(6, mc.getSelectedDayOfMonth()); - assertEquals(1, mc.getSelectedRow()); - assertEquals(4, mc.getSelectedColumn()); - - // up, flips back - assertTrue(mc.up()); - assertEquals(Calendar.AUGUST, mc.getMonth()); - assertEquals(30, mc.getSelectedDayOfMonth()); - assertEquals(4, mc.getSelectedRow()); - assertEquals(4, mc.getSelectedColumn()); - } - - @SmallTest - public void testMoveDown() { - DayOfMonthCursor mc = new DayOfMonthCursor(2007, - Calendar.SEPTEMBER, 23, Calendar.SUNDAY); - - assertEquals(Calendar.SEPTEMBER, mc.getMonth()); - assertEquals(23, mc.getSelectedDayOfMonth()); - assertEquals(4, mc.getSelectedRow()); - assertEquals(0, mc.getSelectedColumn()); - - // down, same month - assertFalse(mc.down()); - assertEquals(30, mc.getSelectedDayOfMonth()); - assertEquals(5, mc.getSelectedRow()); - assertEquals(0, mc.getSelectedColumn()); - - // down, next month - assertTrue(mc.down()); - assertEquals(Calendar.OCTOBER, mc.getMonth()); - assertEquals(7, mc.getSelectedDayOfMonth()); - assertEquals(1, mc.getSelectedRow()); - assertEquals(0, mc.getSelectedColumn()); - } - - private void assertArraysEqual(int[] expected, int[] actual) { - assertEquals("array length", expected.length, actual.length); - for (int i = 0; i < expected.length; i++) { - assertEquals("index " + i, - expected[i], actual[i]); - } - } -} diff --git a/src/main/java/android/util/DebugUtils.java b/src/main/java/android/util/DebugUtils.java deleted file mode 100644 index f607207..0000000 --- a/src/main/java/android/util/DebugUtils.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import java.lang.reflect.Method; -import java.lang.reflect.InvocationTargetException; -import java.util.Locale; - -/** - *

    Various utilities for debugging and logging.

    - */ -public class DebugUtils { - /** @hide */ public DebugUtils() {} - - /** - *

    Filters objects against the ANDROID_OBJECT_FILTER - * environment variable. This environment variable can filter objects - * based on their class name and attribute values.

    - * - *

    Here is the syntax for ANDROID_OBJECT_FILTER:

    - * - *

    ClassName@attribute1=value1@attribute2=value2...

    - * - *

    Examples:

    - *
      - *
    • Select TextView instances: TextView
    • - *
    • Select TextView instances of text "Loading" and bottom offset of 22: - * TextView@text=Loading.*@bottom=22
    • - *
    - * - *

    The class name and the values are regular expressions.

    - * - *

    This class is useful for debugging and logging purpose:

    - *
    -     * if (DEBUG) {
    -     *   if (DebugUtils.isObjectSelected(childView) && LOGV_ENABLED) {
    -     *     Log.v(TAG, "Object " + childView + " logged!");
    -     *   }
    -     * }
    -     * 
    - * - *

    NOTE: This method is very expensive as it relies - * heavily on regular expressions and reflection. Calls to this method - * should always be stripped out of the release binaries and avoided - * as much as possible in debug mode.

    - * - * @param object any object to match against the ANDROID_OBJECT_FILTER - * environement variable - * @return true if object is selected by the ANDROID_OBJECT_FILTER - * environment variable, false otherwise - */ - public static boolean isObjectSelected(Object object) { - boolean match = false; - String s = System.getenv("ANDROID_OBJECT_FILTER"); - if (s != null && s.length() > 0) { - String[] selectors = s.split("@"); - // first selector == class name - if (object.getClass().getSimpleName().matches(selectors[0])) { - // check potential attributes - for (int i = 1; i < selectors.length; i++) { - String[] pair = selectors[i].split("="); - Class klass = object.getClass(); - try { - Method declaredMethod = null; - Class parent = klass; - do { - declaredMethod = parent.getDeclaredMethod("get" + - pair[0].substring(0, 1).toUpperCase(Locale.ROOT) + - pair[0].substring(1), - (Class[]) null); - } while ((parent = klass.getSuperclass()) != null && - declaredMethod == null); - - if (declaredMethod != null) { - Object value = declaredMethod - .invoke(object, (Object[])null); - match |= (value != null ? - value.toString() : "null").matches(pair[1]); - } - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } - } - } - } - return match; - } - - /** @hide */ - public static void buildShortClassTag(Object cls, StringBuilder out) { - if (cls == null) { - out.append("null"); - } else { - String simpleName = cls.getClass().getSimpleName(); - if (simpleName == null || simpleName.isEmpty()) { - simpleName = cls.getClass().getName(); - int end = simpleName.lastIndexOf('.'); - if (end > 0) { - simpleName = simpleName.substring(end+1); - } - } - out.append(simpleName); - out.append('{'); - out.append(Integer.toHexString(System.identityHashCode(cls))); - } - } - -} diff --git a/src/main/java/android/util/DisplayMetrics.java b/src/main/java/android/util/DisplayMetrics.java deleted file mode 100644 index d0e5b9e..0000000 --- a/src/main/java/android/util/DisplayMetrics.java +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import android.os.SystemProperties; - - -/** - * A structure describing general information about a display, such as its - * size, density, and font scaling. - *

    To access the DisplayMetrics members, initialize an object like this:

    - *
     DisplayMetrics metrics = new DisplayMetrics();
    - * getWindowManager().getDefaultDisplay().getMetrics(metrics);
    - */ -public class DisplayMetrics { - /** - * Standard quantized DPI for low-density screens. - */ - public static final int DENSITY_LOW = 120; - - /** - * Standard quantized DPI for medium-density screens. - */ - public static final int DENSITY_MEDIUM = 160; - - /** - * This is a secondary density, added for some common screen configurations. - * It is recommended that applications not generally target this as a first - * class density -- that is, don't supply specific graphics for this - * density, instead allow the platform to scale from other densities - * (typically {@link #DENSITY_HIGH}) as - * appropriate. In most cases (such as using bitmaps in - * {@link android.graphics.drawable.Drawable}) the platform - * can perform this scaling at load time, so the only cost is some slight - * startup runtime overhead. - * - *

    This density was original introduced to correspond with a - * 720p TV screen: the density for 1080p televisions is - * {@link #DENSITY_XHIGH}, and the value here provides the same UI - * size for a TV running at 720p. It has also found use in 7" tablets, - * when these devices have 1280x720 displays. - */ - public static final int DENSITY_TV = 213; - - /** - * Standard quantized DPI for high-density screens. - */ - public static final int DENSITY_HIGH = 240; - - /** - * Intermediate density for screens that sit between {@link #DENSITY_HIGH} (240dpi) and - * {@link #DENSITY_XHIGH} (320dpi). This is not a density that applications should target, - * instead relying on the system to scale their {@link #DENSITY_XHIGH} assets for them. - */ - public static final int DENSITY_280 = 280; - - /** - * Standard quantized DPI for extra-high-density screens. - */ - public static final int DENSITY_XHIGH = 320; - - /** - * Intermediate density for screens that sit somewhere between - * {@link #DENSITY_XHIGH} (320 dpi) and {@link #DENSITY_XXHIGH} (480 dpi). - * This is not a density that applications should target, instead relying - * on the system to scale their {@link #DENSITY_XXHIGH} assets for them. - */ - public static final int DENSITY_400 = 400; - - /** - * Standard quantized DPI for extra-extra-high-density screens. - */ - public static final int DENSITY_XXHIGH = 480; - - /** - * Intermediate density for screens that sit somewhere between - * {@link #DENSITY_XXHIGH} (480 dpi) and {@link #DENSITY_XXXHIGH} (640 dpi). - * This is not a density that applications should target, instead relying - * on the system to scale their {@link #DENSITY_XXXHIGH} assets for them. - */ - public static final int DENSITY_560 = 560; - - /** - * Standard quantized DPI for extra-extra-extra-high-density screens. Applications - * should not generally worry about this density; relying on XHIGH graphics - * being scaled up to it should be sufficient for almost all cases. A typical - * use of this density would be 4K television screens -- 3840x2160, which - * is 2x a traditional HD 1920x1080 screen which runs at DENSITY_XHIGH. - */ - public static final int DENSITY_XXXHIGH = 640; - - /** - * The reference density used throughout the system. - */ - public static final int DENSITY_DEFAULT = DENSITY_MEDIUM; - - /** - * Scaling factor to convert a density in DPI units to the density scale. - * @hide - */ - public static final float DENSITY_DEFAULT_SCALE = 1.0f / DENSITY_DEFAULT; - - /** - * The device's density. - * @hide because eventually this should be able to change while - * running, so shouldn't be a constant. - * @deprecated There is no longer a static density; you can find the - * density for a display in {@link #densityDpi}. - */ - @Deprecated - public static int DENSITY_DEVICE = getDeviceDensity(); - - /** - * The absolute width of the display in pixels. - */ - public int widthPixels; - /** - * The absolute height of the display in pixels. - */ - public int heightPixels; - /** - * The logical density of the display. This is a scaling factor for the - * Density Independent Pixel unit, where one DIP is one pixel on an - * approximately 160 dpi screen (for example a 240x320, 1.5"x2" screen), - * providing the baseline of the system's display. Thus on a 160dpi screen - * this density value will be 1; on a 120 dpi screen it would be .75; etc. - * - *

    This value does not exactly follow the real screen size (as given by - * {@link #xdpi} and {@link #ydpi}, but rather is used to scale the size of - * the overall UI in steps based on gross changes in the display dpi. For - * example, a 240x320 screen will have a density of 1 even if its width is - * 1.8", 1.3", etc. However, if the screen resolution is increased to - * 320x480 but the screen size remained 1.5"x2" then the density would be - * increased (probably to 1.5). - * - * @see #DENSITY_DEFAULT - */ - public float density; - /** - * The screen density expressed as dots-per-inch. May be either - * {@link #DENSITY_LOW}, {@link #DENSITY_MEDIUM}, or {@link #DENSITY_HIGH}. - */ - public int densityDpi; - /** - * A scaling factor for fonts displayed on the display. This is the same - * as {@link #density}, except that it may be adjusted in smaller - * increments at runtime based on a user preference for the font size. - */ - public float scaledDensity; - /** - * The exact physical pixels per inch of the screen in the X dimension. - */ - public float xdpi; - /** - * The exact physical pixels per inch of the screen in the Y dimension. - */ - public float ydpi; - - /** - * The reported display width prior to any compatibility mode scaling - * being applied. - * @hide - */ - public int noncompatWidthPixels; - /** - * The reported display height prior to any compatibility mode scaling - * being applied. - * @hide - */ - public int noncompatHeightPixels; - /** - * The reported display density prior to any compatibility mode scaling - * being applied. - * @hide - */ - public float noncompatDensity; - /** - * The reported display density prior to any compatibility mode scaling - * being applied. - * @hide - */ - public int noncompatDensityDpi; - /** - * The reported scaled density prior to any compatibility mode scaling - * being applied. - * @hide - */ - public float noncompatScaledDensity; - /** - * The reported display xdpi prior to any compatibility mode scaling - * being applied. - * @hide - */ - public float noncompatXdpi; - /** - * The reported display ydpi prior to any compatibility mode scaling - * being applied. - * @hide - */ - public float noncompatYdpi; - - public DisplayMetrics() { - } - - public void setTo(DisplayMetrics o) { - widthPixels = o.widthPixels; - heightPixels = o.heightPixels; - density = o.density; - densityDpi = o.densityDpi; - scaledDensity = o.scaledDensity; - xdpi = o.xdpi; - ydpi = o.ydpi; - noncompatWidthPixels = o.noncompatWidthPixels; - noncompatHeightPixels = o.noncompatHeightPixels; - noncompatDensity = o.noncompatDensity; - noncompatDensityDpi = o.noncompatDensityDpi; - noncompatScaledDensity = o.noncompatScaledDensity; - noncompatXdpi = o.noncompatXdpi; - noncompatYdpi = o.noncompatYdpi; - } - - public void setToDefaults() { - widthPixels = 0; - heightPixels = 0; - density = DENSITY_DEVICE / (float) DENSITY_DEFAULT; - densityDpi = DENSITY_DEVICE; - scaledDensity = density; - xdpi = DENSITY_DEVICE; - ydpi = DENSITY_DEVICE; - noncompatWidthPixels = widthPixels; - noncompatHeightPixels = heightPixels; - noncompatDensity = density; - noncompatDensityDpi = densityDpi; - noncompatScaledDensity = scaledDensity; - noncompatXdpi = xdpi; - noncompatYdpi = ydpi; - } - - @Override - public boolean equals(Object o) { - return o instanceof DisplayMetrics && equals((DisplayMetrics)o); - } - - /** - * Returns true if these display metrics equal the other display metrics. - * - * @param other The display metrics with which to compare. - * @return True if the display metrics are equal. - */ - public boolean equals(DisplayMetrics other) { - return equalsPhysical(other) - && scaledDensity == other.scaledDensity - && noncompatScaledDensity == other.noncompatScaledDensity; - } - - /** - * Returns true if the physical aspects of the two display metrics - * are equal. This ignores the scaled density, which is a logical - * attribute based on the current desired font size. - * - * @param other The display metrics with which to compare. - * @return True if the display metrics are equal. - * @hide - */ - public boolean equalsPhysical(DisplayMetrics other) { - return other != null - && widthPixels == other.widthPixels - && heightPixels == other.heightPixels - && density == other.density - && densityDpi == other.densityDpi - && xdpi == other.xdpi - && ydpi == other.ydpi - && noncompatWidthPixels == other.noncompatWidthPixels - && noncompatHeightPixels == other.noncompatHeightPixels - && noncompatDensity == other.noncompatDensity - && noncompatDensityDpi == other.noncompatDensityDpi - && noncompatXdpi == other.noncompatXdpi - && noncompatYdpi == other.noncompatYdpi; - } - - @Override - public int hashCode() { - return widthPixels * heightPixels * densityDpi; - } - - @Override - public String toString() { - return "DisplayMetrics{density=" + density + ", width=" + widthPixels + - ", height=" + heightPixels + ", scaledDensity=" + scaledDensity + - ", xdpi=" + xdpi + ", ydpi=" + ydpi + "}"; - } - - private static int getDeviceDensity() { - // qemu.sf.lcd_density can be used to override ro.sf.lcd_density - // when running in the emulator, allowing for dynamic configurations. - // The reason for this is that ro.sf.lcd_density is write-once and is - // set by the init process when it parses build.prop before anything else. - return SystemProperties.getInt("qemu.sf.lcd_density", - SystemProperties.getInt("ro.sf.lcd_density", DENSITY_DEFAULT)); - } -} diff --git a/src/main/java/android/util/EventLog.java b/src/main/java/android/util/EventLog.java deleted file mode 100644 index aefced8..0000000 --- a/src/main/java/android/util/EventLog.java +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import java.io.BufferedReader; -import java.io.FileReader; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.nio.BufferUnderflowException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Collection; -import java.util.HashMap; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Access to the system diagnostic event record. System diagnostic events are - * used to record certain system-level events (such as garbage collection, - * activity manager state, system watchdogs, and other low level activity), - * which may be automatically collected and analyzed during system development. - * - *

    This is not the main "logcat" debugging log ({@link android.util.Log})! - * These diagnostic events are for system integrators, not application authors. - * - *

    Events use integer tag codes corresponding to /system/etc/event-log-tags. - * They carry a payload of one or more int, long, or String values. The - * event-log-tags file defines the payload contents for each type code. - */ -public class EventLog { - /** @hide */ public EventLog() {} - - private static final String TAG = "EventLog"; - - private static final String TAGS_FILE = "/system/etc/event-log-tags"; - private static final String COMMENT_PATTERN = "^\\s*(#.*)?$"; - private static final String TAG_PATTERN = "^\\s*(\\d+)\\s+(\\w+)\\s*(\\(.*\\))?\\s*$"; - private static HashMap sTagCodes = null; - private static HashMap sTagNames = null; - - /** A previously logged event read from the logs. */ - public static final class Event { - private final ByteBuffer mBuffer; - - // Layout of event log entry received from Android logger. - // see system/core/include/log/logger.h - private static final int LENGTH_OFFSET = 0; - private static final int HEADER_SIZE_OFFSET = 2; - private static final int PROCESS_OFFSET = 4; - private static final int THREAD_OFFSET = 8; - private static final int SECONDS_OFFSET = 12; - private static final int NANOSECONDS_OFFSET = 16; - - // Layout for event log v1 format, v2 and v3 use HEADER_SIZE_OFFSET - private static final int V1_PAYLOAD_START = 20; - private static final int DATA_OFFSET = 4; - - // Value types - private static final byte INT_TYPE = 0; - private static final byte LONG_TYPE = 1; - private static final byte STRING_TYPE = 2; - private static final byte LIST_TYPE = 3; - - /** @param data containing event, read from the system */ - /*package*/ Event(byte[] data) { - mBuffer = ByteBuffer.wrap(data); - mBuffer.order(ByteOrder.nativeOrder()); - } - - /** @return the process ID which wrote the log entry */ - public int getProcessId() { - return mBuffer.getInt(PROCESS_OFFSET); - } - - /** @return the thread ID which wrote the log entry */ - public int getThreadId() { - return mBuffer.getInt(THREAD_OFFSET); - } - - /** @return the wall clock time when the entry was written */ - public long getTimeNanos() { - return mBuffer.getInt(SECONDS_OFFSET) * 1000000000l - + mBuffer.getInt(NANOSECONDS_OFFSET); - } - - /** @return the type tag code of the entry */ - public int getTag() { - int offset = mBuffer.getShort(HEADER_SIZE_OFFSET); - if (offset == 0) { - offset = V1_PAYLOAD_START; - } - return mBuffer.getInt(offset); - } - - /** @return one of Integer, Long, String, null, or Object[] of same. */ - public synchronized Object getData() { - try { - int offset = mBuffer.getShort(HEADER_SIZE_OFFSET); - if (offset == 0) { - offset = V1_PAYLOAD_START; - } - mBuffer.limit(offset + mBuffer.getShort(LENGTH_OFFSET)); - mBuffer.position(offset + DATA_OFFSET); // Just after the tag. - return decodeObject(); - } catch (IllegalArgumentException e) { - Log.wtf(TAG, "Illegal entry payload: tag=" + getTag(), e); - return null; - } catch (BufferUnderflowException e) { - Log.wtf(TAG, "Truncated entry payload: tag=" + getTag(), e); - return null; - } - } - - /** @return the loggable item at the current position in mBuffer. */ - private Object decodeObject() { - byte type = mBuffer.get(); - switch (type) { - case INT_TYPE: - return (Integer) mBuffer.getInt(); - - case LONG_TYPE: - return (Long) mBuffer.getLong(); - - case STRING_TYPE: - try { - int length = mBuffer.getInt(); - int start = mBuffer.position(); - mBuffer.position(start + length); - return new String(mBuffer.array(), start, length, "UTF-8"); - } catch (UnsupportedEncodingException e) { - Log.wtf(TAG, "UTF-8 is not supported", e); - return null; - } - - case LIST_TYPE: - int length = mBuffer.get(); - if (length < 0) length += 256; // treat as signed byte - Object[] array = new Object[length]; - for (int i = 0; i < length; ++i) array[i] = decodeObject(); - return array; - - default: - throw new IllegalArgumentException("Unknown entry type: " + type); - } - } - } - - // We assume that the native methods deal with any concurrency issues. - - /** - * Record an event log message. - * @param tag The event type tag code - * @param value A value to log - * @return The number of bytes written - */ - public static native int writeEvent(int tag, int value); - - /** - * Record an event log message. - * @param tag The event type tag code - * @param value A value to log - * @return The number of bytes written - */ - public static native int writeEvent(int tag, long value); - - /** - * Record an event log message. - * @param tag The event type tag code - * @param str A value to log - * @return The number of bytes written - */ - public static native int writeEvent(int tag, String str); - - /** - * Record an event log message. - * @param tag The event type tag code - * @param list A list of values to log - * @return The number of bytes written - */ - public static native int writeEvent(int tag, Object... list); - - /** - * Read events from the log, filtered by type. - * @param tags to search for - * @param output container to add events into - * @throws IOException if something goes wrong reading events - */ - public static native void readEvents(int[] tags, Collection output) - throws IOException; - - /** - * Get the name associated with an event type tag code. - * @param tag code to look up - * @return the name of the tag, or null if no tag has that number - */ - public static String getTagName(int tag) { - readTagsFile(); - return sTagNames.get(tag); - } - - /** - * Get the event type tag code associated with an event name. - * @param name of event to look up - * @return the tag code, or -1 if no tag has that name - */ - public static int getTagCode(String name) { - readTagsFile(); - Integer code = sTagCodes.get(name); - return code != null ? code : -1; - } - - /** - * Read TAGS_FILE, populating sTagCodes and sTagNames, if not already done. - */ - private static synchronized void readTagsFile() { - if (sTagCodes != null && sTagNames != null) return; - - sTagCodes = new HashMap(); - sTagNames = new HashMap(); - - Pattern comment = Pattern.compile(COMMENT_PATTERN); - Pattern tag = Pattern.compile(TAG_PATTERN); - BufferedReader reader = null; - String line; - - try { - reader = new BufferedReader(new FileReader(TAGS_FILE), 256); - while ((line = reader.readLine()) != null) { - if (comment.matcher(line).matches()) continue; - - Matcher m = tag.matcher(line); - if (!m.matches()) { - Log.wtf(TAG, "Bad entry in " + TAGS_FILE + ": " + line); - continue; - } - - try { - int num = Integer.parseInt(m.group(1)); - String name = m.group(2); - sTagCodes.put(name, num); - sTagNames.put(num, name); - } catch (NumberFormatException e) { - Log.wtf(TAG, "Error in " + TAGS_FILE + ": " + line, e); - } - } - } catch (IOException e) { - Log.wtf(TAG, "Error reading " + TAGS_FILE, e); - // Leave the maps existing but unpopulated - } finally { - try { if (reader != null) reader.close(); } catch (IOException e) {} - } - } -} diff --git a/src/main/java/android/util/EventLogTags.java b/src/main/java/android/util/EventLogTags.java deleted file mode 100644 index f4ce4fd..0000000 --- a/src/main/java/android/util/EventLogTags.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import java.io.BufferedReader; -import java.io.IOException; - -/** - * @deprecated This class is no longer functional. - * Use {@link android.util.EventLog} instead. - */ -@Deprecated -public class EventLogTags { - public static class Description { - public final int mTag; - public final String mName; - - Description(int tag, String name) { - mTag = tag; - mName = name; - } - } - - public EventLogTags() throws IOException {} - - public EventLogTags(BufferedReader input) throws IOException {} - - public Description get(String name) { return null; } - - public Description get(int tag) { return null; } -} diff --git a/src/main/java/android/util/ExceptionUtils.java b/src/main/java/android/util/ExceptionUtils.java deleted file mode 100644 index f5d515d..0000000 --- a/src/main/java/android/util/ExceptionUtils.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2014 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.util; - -import java.io.IOException; - -/** - * Utility methods for proxying richer exceptions across Binder calls. - * - * @hide - */ -public class ExceptionUtils { - // TODO: longer term these should be replaced with first-class - // Parcel.read/writeException() and AIDL support, but for now do this using - // a nasty hack. - - private static final String PREFIX_IO = "\u2603"; - - public static RuntimeException wrap(IOException e) { - throw new IllegalStateException(PREFIX_IO + e.getMessage()); - } - - public static void maybeUnwrapIOException(RuntimeException e) throws IOException { - if ((e instanceof IllegalStateException) && e.getMessage().startsWith(PREFIX_IO)) { - throw new IOException(e.getMessage().substring(PREFIX_IO.length())); - } - } - - public static String getCompleteMessage(String msg, Throwable t) { - final StringBuilder builder = new StringBuilder(); - if (msg != null) { - builder.append(msg).append(": "); - } - builder.append(t.getMessage()); - while ((t = t.getCause()) != null) { - builder.append(": ").append(t.getMessage()); - } - return builder.toString(); - } - - public static String getCompleteMessage(Throwable t) { - return getCompleteMessage(null, t); - } -} diff --git a/src/main/java/android/util/FastImmutableArraySet.java b/src/main/java/android/util/FastImmutableArraySet.java deleted file mode 100644 index 4175c60..0000000 --- a/src/main/java/android/util/FastImmutableArraySet.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2011 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.util; - -import java.util.AbstractSet; -import java.util.Iterator; - -/** - * A fast immutable set wrapper for an array that is optimized for non-concurrent iteration. - * The same iterator instance is reused each time to avoid creating lots of garbage. - * Iterating over an array in this fashion is 2.5x faster than iterating over a {@link HashSet} - * so it is worth copying the contents of the set to an array when iterating over it - * hundreds of times. - * @hide - */ -public final class FastImmutableArraySet extends AbstractSet { - FastIterator mIterator; - T[] mContents; - - public FastImmutableArraySet(T[] contents) { - mContents = contents; - } - - @Override - public Iterator iterator() { - FastIterator it = mIterator; - if (it == null) { - it = new FastIterator(mContents); - mIterator = it; - } else { - it.mIndex = 0; - } - return it; - } - - @Override - public int size() { - return mContents.length; - } - - private static final class FastIterator implements Iterator { - private final T[] mContents; - int mIndex; - - public FastIterator(T[] contents) { - mContents = contents; - } - - @Override - public boolean hasNext() { - return mIndex != mContents.length; - } - - @Override - public T next() { - return mContents[mIndex++]; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - } -} diff --git a/src/main/java/android/util/FloatMath.java b/src/main/java/android/util/FloatMath.java deleted file mode 100644 index bdcf5ca..0000000 --- a/src/main/java/android/util/FloatMath.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -/** - * Math routines similar to those found in {@link java.lang.Math}. On - * versions of Android with a JIT, these are significantly slower than - * the equivalent {@code Math} functions, which should be used in preference - * to these. - * - * @deprecated Use {@link java.lang.Math} instead. - */ -@Deprecated -public class FloatMath { - - /** Prevents instantiation. */ - private FloatMath() {} - - /** - * Returns the float conversion of the most positive (i.e. closest to - * positive infinity) integer value which is less than the argument. - * - * @param value to be converted - * @return the floor of value - */ - public static native float floor(float value); - - /** - * Returns the float conversion of the most negative (i.e. closest to - * negative infinity) integer value which is greater than the argument. - * - * @param value to be converted - * @return the ceiling of value - */ - public static native float ceil(float value); - - /** - * Returns the closest float approximation of the sine of the argument. - * - * @param angle to compute the cosine of, in radians - * @return the sine of angle - */ - public static native float sin(float angle); - - /** - * Returns the closest float approximation of the cosine of the argument. - * - * @param angle to compute the cosine of, in radians - * @return the cosine of angle - */ - public static native float cos(float angle); - - /** - * Returns the closest float approximation of the square root of the - * argument. - * - * @param value to compute sqrt of - * @return the square root of value - */ - public static native float sqrt(float value); - - /** - * Returns the closest float approximation of the raising "e" to the power - * of the argument. - * - * @param value to compute the exponential of - * @return the exponential of value - */ - public static native float exp(float value); - - /** - * Returns the closest float approximation of the result of raising {@code - * x} to the power of {@code y}. - * - * @param x the base of the operation. - * @param y the exponent of the operation. - * @return {@code x} to the power of {@code y}. - */ - public static native float pow(float x, float y); - - /** - * Returns {@code sqrt(}{@code x}{@code 2}{@code +} - * {@code y}{@code 2}{@code )}. - * - * @param x a float number - * @param y a float number - * @return the hypotenuse - */ - public static native float hypot(float x, float y); -} diff --git a/src/main/java/android/util/FloatMathTest.java b/src/main/java/android/util/FloatMathTest.java deleted file mode 100644 index f479e2b..0000000 --- a/src/main/java/android/util/FloatMathTest.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import junit.framework.TestCase; -import android.test.suitebuilder.annotation.SmallTest; - -public class FloatMathTest extends TestCase { - - @SmallTest - public void testSqrt() { - assertEquals(7, FloatMath.sqrt(49), 0); - assertEquals(10, FloatMath.sqrt(100), 0); - assertEquals(0, FloatMath.sqrt(0), 0); - assertEquals(1, FloatMath.sqrt(1), 0); - } - - @SmallTest - public void testFloor() { - assertEquals(78, FloatMath.floor(78.89f), 0); - assertEquals(-79, FloatMath.floor(-78.89f), 0); - } - - @SmallTest - public void testCeil() { - assertEquals(79, FloatMath.ceil(78.89f), 0); - assertEquals(-78, FloatMath.ceil(-78.89f), 0); - } - - @SmallTest - public void testSin() { - assertEquals(0.0, FloatMath.sin(0), 0); - assertEquals(0.8414709848078965f, FloatMath.sin(1), 0); - } - - @SmallTest - public void testCos() { - assertEquals(1.0f, FloatMath.cos(0), 0); - assertEquals(0.5403023058681398f, FloatMath.cos(1), 0); - } -} diff --git a/src/main/java/android/util/FloatMath_Delegate.java b/src/main/java/android/util/FloatMath_Delegate.java deleted file mode 100644 index 8b4c60b..0000000 --- a/src/main/java/android/util/FloatMath_Delegate.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import com.android.layoutlib.bridge.impl.DelegateManager; -import com.android.tools.layoutlib.annotations.LayoutlibDelegate; - -/** - * Delegate implementing the native methods of android.util.FloatMath - * - * Through the layoutlib_create tool, the original native methods of FloatMath have been replaced - * by calls to methods of the same name in this delegate class. - * - * Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager} - * around to map int to instance of the delegate. - * - */ -/*package*/ final class FloatMath_Delegate { - - /** Prevents instantiation. */ - private FloatMath_Delegate() {} - - /** - * Returns the float conversion of the most positive (i.e. closest to - * positive infinity) integer value which is less than the argument. - * - * @param value to be converted - * @return the floor of value - */ - @LayoutlibDelegate - /*package*/ static float floor(float value) { - return (float)Math.floor(value); - } - - /** - * Returns the float conversion of the most negative (i.e. closest to - * negative infinity) integer value which is greater than the argument. - * - * @param value to be converted - * @return the ceiling of value - */ - @LayoutlibDelegate - /*package*/ static float ceil(float value) { - return (float)Math.ceil(value); - } - - /** - * Returns the closest float approximation of the sine of the argument. - * - * @param angle to compute the cosine of, in radians - * @return the sine of angle - */ - @LayoutlibDelegate - /*package*/ static float sin(float angle) { - return (float)Math.sin(angle); - } - - /** - * Returns the closest float approximation of the cosine of the argument. - * - * @param angle to compute the cosine of, in radians - * @return the cosine of angle - */ - @LayoutlibDelegate - /*package*/ static float cos(float angle) { - return (float)Math.cos(angle); - } - - /** - * Returns the closest float approximation of the square root of the - * argument. - * - * @param value to compute sqrt of - * @return the square root of value - */ - @LayoutlibDelegate - /*package*/ static float sqrt(float value) { - return (float)Math.sqrt(value); - } - - /** - * Returns the closest float approximation of the raising "e" to the power - * of the argument. - * - * @param value to compute the exponential of - * @return the exponential of value - */ - @LayoutlibDelegate - /*package*/ static float exp(float value) { - return (float)Math.exp(value); - } - - /** - * Returns the closest float approximation of the result of raising {@code - * x} to the power of {@code y}. - * - * @param x the base of the operation. - * @param y the exponent of the operation. - * @return {@code x} to the power of {@code y}. - */ - @LayoutlibDelegate - /*package*/ static float pow(float x, float y) { - return (float)Math.pow(x, y); - } - - /** - * Returns {@code sqrt(}{@code x}{@code 2}{@code +} - * {@code y}{@code 2}{@code )}. - * - * @param x a float number - * @param y a float number - * @return the hypotenuse - */ - @LayoutlibDelegate - /*package*/ static float hypot(float x, float y) { - return (float)Math.sqrt(x*x + y*y); - } -} diff --git a/src/main/java/android/util/FloatProperty.java b/src/main/java/android/util/FloatProperty.java deleted file mode 100644 index a67b3cb..0000000 --- a/src/main/java/android/util/FloatProperty.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2011 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.util; - -import android.util.Property; - -/** - * An implementation of {@link android.util.Property} to be used specifically with fields of type - * float. This type-specific subclass enables performance benefit by allowing - * calls to a {@link #set(Object, Float) set()} function that takes the primitive - * float type and avoids autoboxing and other overhead associated with the - * Float class. - * - * @param The class on which the Property is declared. - * - * @hide - */ -public abstract class FloatProperty extends Property { - - public FloatProperty(String name) { - super(Float.class, name); - } - - /** - * A type-specific override of the {@link #set(Object, Float)} that is faster when dealing - * with fields of type float. - */ - public abstract void setValue(T object, float value); - - @Override - final public void set(T object, Float value) { - setValue(object, value); - } - -} \ No newline at end of file diff --git a/src/main/java/android/util/GridScenario.java b/src/main/java/android/util/GridScenario.java deleted file mode 100644 index 0f1730e..0000000 --- a/src/main/java/android/util/GridScenario.java +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import android.app.Activity; -import android.os.Bundle; -import android.view.View; -import android.view.ViewGroup; -import android.view.Window; -import android.widget.AbsListView; -import android.widget.AdapterView; -import android.widget.BaseAdapter; -import android.widget.GridView; -import android.widget.ListAdapter; -import android.widget.TextView; - -import com.google.android.collect.Maps; - -import java.util.Map; - -/** - * Utility base class for creating various GridView scenarios. Configurable by the number - * of items, how tall each item should be (in relation to the screen height), and - * what item should start with selection. - */ -public abstract class GridScenario extends Activity { - - private GridView mGridView; - - private int mNumItems; - - private int mStartingSelectionPosition; - private double mItemScreenSizeFactor; - private Map mOverrideItemScreenSizeFactors = Maps.newHashMap(); - - private int mScreenHeight; - - private boolean mStackFromBottom; - - private int mColumnWidth; - - private int mNumColumns; - - private int mStretchMode; - - private int mVerticalSpacing; - - public GridView getGridView() { - return mGridView; - } - - protected int getScreenHeight() { - return mScreenHeight; - } - - /** - * @return The initial number of items in the grid as specified by the scenario. - * This number may change over time. - */ - protected int getInitialNumItems() { - return mNumItems; - } - - /** - * @return The desired height of 1 item, ignoring overrides - */ - public int getDesiredItemHeight() { - return (int) (mScreenHeight * mItemScreenSizeFactor); - } - - /** - * Better way to pass in optional params than a honkin' paramater list :) - */ - public static class Params { - private int mNumItems = 4; - private int mStartingSelectionPosition = -1; - private double mItemScreenSizeFactor = 1 / 5; - - private Map mOverrideItemScreenSizeFactors = Maps.newHashMap(); - - private boolean mStackFromBottom = false; - private boolean mMustFillScreen = true; - - private int mColumnWidth = 0; - private int mNumColumns = GridView.AUTO_FIT; - private int mStretchMode = GridView.STRETCH_COLUMN_WIDTH; - private int mVerticalSpacing = 0; - - /** - * Set the number of items in the grid. - */ - public Params setNumItems(int numItems) { - mNumItems = numItems; - return this; - } - - /** - * Set the position that starts selected. - * - * @param startingSelectionPosition The selected position within the adapter's data set. - * Pass -1 if you do not want to force a selection. - * @return - */ - public Params setStartingSelectionPosition(int startingSelectionPosition) { - mStartingSelectionPosition = startingSelectionPosition; - return this; - } - - /** - * Set the factor that determines how tall each item is in relation to the - * screen height. - */ - public Params setItemScreenSizeFactor(double itemScreenSizeFactor) { - mItemScreenSizeFactor = itemScreenSizeFactor; - return this; - } - - /** - * Override the item screen size factor for a particular item. Useful for - * creating grids with non-uniform item height. - * @param position The position in the grid. - * @param itemScreenSizeFactor The screen size factor to use for the height. - */ - public Params setPositionScreenSizeFactorOverride( - int position, double itemScreenSizeFactor) { - mOverrideItemScreenSizeFactors.put(position, itemScreenSizeFactor); - return this; - } - - /** - * Sets the stacking direction - * @param stackFromBottom - * @return - */ - public Params setStackFromBottom(boolean stackFromBottom) { - mStackFromBottom = stackFromBottom; - return this; - } - - /** - * Sets whether the sum of the height of the grid items must be at least the - * height of the grid view. - */ - public Params setMustFillScreen(boolean fillScreen) { - mMustFillScreen = fillScreen; - return this; - } - - /** - * Sets the individual width of each column. - * - * @param requestedWidth the width in pixels of the column - */ - public Params setColumnWidth(int requestedWidth) { - mColumnWidth = requestedWidth; - return this; - } - - /** - * Sets the number of columns in the grid. - */ - public Params setNumColumns(int numColumns) { - mNumColumns = numColumns; - return this; - } - - /** - * Sets the stretch mode. - */ - public Params setStretchMode(int stretchMode) { - mStretchMode = stretchMode; - return this; - } - - /** - * Sets the spacing between rows in the grid - */ - public Params setVerticalSpacing(int verticalSpacing) { - mVerticalSpacing = verticalSpacing; - return this; - } - } - - /** - * How each scenario customizes its behavior. - * @param params - */ - protected abstract void init(Params params); - - /** - * Override this to provide an different adapter for your scenario - * @return The adapter that this scenario will use - */ - protected ListAdapter createAdapter() { - return new MyAdapter(); - } - - /** - * Override this if you want to know when something has been selected (perhaps - * more importantly, that {@link android.widget.AdapterView.OnItemSelectedListener} has - * been triggered). - */ - @SuppressWarnings({ "UnusedDeclaration" }) - protected void positionSelected(int positon) { - - } - - /** - * Override this if you want to know that nothing is selected. - */ - protected void nothingSelected() { - - } - - @Override - protected void onCreate(Bundle icicle) { - super.onCreate(icicle); - - // turn off title bar - requestWindowFeature(Window.FEATURE_NO_TITLE); - - mScreenHeight = getWindowManager().getDefaultDisplay().getHeight(); - - final Params params = new Params(); - init(params); - - readAndValidateParams(params); - - mGridView = new GridView(this); - mGridView.setLayoutParams(new ViewGroup.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT)); - mGridView.setDrawSelectorOnTop(false); - if (mNumColumns >= GridView.AUTO_FIT) { - mGridView.setNumColumns(mNumColumns); - } - if (mColumnWidth > 0) { - mGridView.setColumnWidth(mColumnWidth); - } - if (mVerticalSpacing > 0) { - mGridView.setVerticalSpacing(mVerticalSpacing); - } - mGridView.setStretchMode(mStretchMode); - mGridView.setAdapter(createAdapter()); - if (mStartingSelectionPosition >= 0) { - mGridView.setSelection(mStartingSelectionPosition); - } - mGridView.setPadding(10, 10, 10, 10); - mGridView.setStackFromBottom(mStackFromBottom); - - mGridView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { - public void onItemSelected(AdapterView parent, View v, int position, long id) { - positionSelected(position); - } - - public void onNothingSelected(AdapterView parent) { - nothingSelected(); - } - }); - - setContentView(mGridView); - } - - - - /** - * Read in and validate all of the params passed in by the scenario. - * @param params - */ - private void readAndValidateParams(Params params) { - if (params.mMustFillScreen ) { - double totalFactor = 0.0; - for (int i = 0; i < params.mNumItems; i++) { - if (params.mOverrideItemScreenSizeFactors.containsKey(i)) { - totalFactor += params.mOverrideItemScreenSizeFactors.get(i); - } else { - totalFactor += params.mItemScreenSizeFactor; - } - } - if (totalFactor < 1.0) { - throw new IllegalArgumentException("grid items must combine to be at least " + - "the height of the screen. this is not the case with " + params.mNumItems - + " items and " + params.mItemScreenSizeFactor + " screen factor and " + - "screen height of " + mScreenHeight); - } - } - - mNumItems = params.mNumItems; - mStartingSelectionPosition = params.mStartingSelectionPosition; - mItemScreenSizeFactor = params.mItemScreenSizeFactor; - - mOverrideItemScreenSizeFactors.putAll(params.mOverrideItemScreenSizeFactors); - - mStackFromBottom = params.mStackFromBottom; - mColumnWidth = params.mColumnWidth; - mNumColumns = params.mNumColumns; - mStretchMode = params.mStretchMode; - mVerticalSpacing = params.mVerticalSpacing; - } - - public final String getValueAtPosition(int position) { - return "postion " + position; - } - - /** - * Create a view for a grid item. Override this to create a custom view beyond - * the simple focusable / unfocusable text view. - * @param position The position. - * @param parent The parent - * @param desiredHeight The height the view should be to respect the desired item - * to screen height ratio. - * @return a view for the grid. - */ - protected View createView(int position, ViewGroup parent, int desiredHeight) { - TextView result = new TextView(parent.getContext()); - result.setHeight(desiredHeight); - result.setText(getValueAtPosition(position)); - final ViewGroup.LayoutParams lp = new AbsListView.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT); - result.setLayoutParams(lp); - result.setId(position); - result.setBackgroundColor(0x55ffffff); - return result; - } - - - - private class MyAdapter extends BaseAdapter { - public int getCount() { - return mNumItems; - } - - public Object getItem(int position) { - return getValueAtPosition(position); - } - - public long getItemId(int position) { - return position; - } - - public View getView(int position, View convertView, ViewGroup parent) { - if (convertView != null) { - ((TextView) convertView).setText(getValueAtPosition(position)); - convertView.setId(position); - return convertView; - } - - int desiredHeight = getDesiredItemHeight(); - if (mOverrideItemScreenSizeFactors.containsKey(position)) { - desiredHeight = (int) (mScreenHeight * mOverrideItemScreenSizeFactors.get(position)); - } - return createView(position, parent, desiredHeight); - } - } -} diff --git a/src/main/java/android/util/IntArray.java b/src/main/java/android/util/IntArray.java deleted file mode 100644 index e8d3947..0000000 --- a/src/main/java/android/util/IntArray.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2014 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.util; - -import com.android.internal.util.ArrayUtils; - -import libcore.util.EmptyArray; - -/** - * Implements a growing array of int primitives. - * - * @hide - */ -public class IntArray implements Cloneable { - private static final int MIN_CAPACITY_INCREMENT = 12; - - private int[] mValues; - private int mSize; - - /** - * Creates an empty IntArray with the default initial capacity. - */ - public IntArray() { - this(10); - } - - /** - * Creates an empty IntArray with the specified initial capacity. - */ - public IntArray(int initialCapacity) { - if (initialCapacity == 0) { - mValues = EmptyArray.INT; - } else { - mValues = ArrayUtils.newUnpaddedIntArray(initialCapacity); - } - mSize = 0; - } - - /** - * Appends the specified value to the end of this array. - */ - public void add(int value) { - add(mSize, value); - } - - /** - * Inserts a value at the specified position in this array. - * - * @throws IndexOutOfBoundsException when index < 0 || index > size() - */ - public void add(int index, int value) { - if (index < 0 || index > mSize) { - throw new IndexOutOfBoundsException(); - } - - ensureCapacity(1); - - if (mSize - index != 0) { - System.arraycopy(mValues, index, mValues, index + 1, mSize - index); - } - - mValues[index] = value; - mSize++; - } - - /** - * Adds the values in the specified array to this array. - */ - public void addAll(IntArray values) { - final int count = values.mSize; - ensureCapacity(count); - - System.arraycopy(values.mValues, 0, mValues, mSize, count); - mSize += count; - } - - /** - * Ensures capacity to append at least count values. - */ - private void ensureCapacity(int count) { - final int currentSize = mSize; - final int minCapacity = currentSize + count; - if (minCapacity >= mValues.length) { - final int targetCap = currentSize + (currentSize < (MIN_CAPACITY_INCREMENT / 2) ? - MIN_CAPACITY_INCREMENT : currentSize >> 1); - final int newCapacity = targetCap > minCapacity ? targetCap : minCapacity; - final int[] newValues = ArrayUtils.newUnpaddedIntArray(newCapacity); - System.arraycopy(mValues, 0, newValues, 0, currentSize); - mValues = newValues; - } - } - - /** - * Removes all values from this array. - */ - public void clear() { - mSize = 0; - } - - @Override - public IntArray clone() throws CloneNotSupportedException { - final IntArray clone = (IntArray) super.clone(); - clone.mValues = mValues.clone(); - return clone; - } - - /** - * Returns the value at the specified position in this array. - */ - public int get(int index) { - if (index >= mSize) { - throw new ArrayIndexOutOfBoundsException(mSize, index); - } - return mValues[index]; - } - - /** - * Returns the index of the first occurrence of the specified value in this - * array, or -1 if this array does not contain the value. - */ - public int indexOf(int value) { - final int n = mSize; - for (int i = 0; i < n; i++) { - if (mValues[i] == value) { - return i; - } - } - return -1; - } - - /** - * Removes the value at the specified index from this array. - */ - public void remove(int index) { - if (index >= mSize) { - throw new ArrayIndexOutOfBoundsException(mSize, index); - } - System.arraycopy(mValues, index + 1, mValues, index, mSize - index - 1); - mSize--; - } - - /** - * Returns the number of values in this array. - */ - public int size() { - return mSize; - } -} diff --git a/src/main/java/android/util/IntProperty.java b/src/main/java/android/util/IntProperty.java deleted file mode 100644 index 17977ca..0000000 --- a/src/main/java/android/util/IntProperty.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2011 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.util; - -import android.util.Property; - -/** - * An implementation of {@link android.util.Property} to be used specifically with fields of type - * int. This type-specific subclass enables performance benefit by allowing - * calls to a {@link #set(Object, Integer) set()} function that takes the primitive - * int type and avoids autoboxing and other overhead associated with the - * Integer class. - * - * @param The class on which the Property is declared. - * - * @hide - */ -public abstract class IntProperty extends Property { - - public IntProperty(String name) { - super(Integer.class, name); - } - - /** - * A type-specific override of the {@link #set(Object, Integer)} that is faster when dealing - * with fields of type int. - */ - public abstract void setValue(T object, int value); - - @Override - final public void set(T object, Integer value) { - setValue(object, value.intValue()); - } - -} \ No newline at end of file diff --git a/src/main/java/android/util/InternalSelectionView.java b/src/main/java/android/util/InternalSelectionView.java deleted file mode 100644 index a0fb0f1..0000000 --- a/src/main/java/android/util/InternalSelectionView.java +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import com.android.frameworks.coretests.R; - -import android.view.View; -import android.view.KeyEvent; -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Paint; -import android.graphics.Canvas; -import android.graphics.Rect; -import android.graphics.Color; -import android.util.AttributeSet; - - - -/** - * A view that has a known number of selectable rows, and maintains a notion of which - * row is selected. The rows take up the - * entire width of the view. The height of the view is divided evenly among - * the rows. - * - * Note: If the height of the view does not divide exactly to the number of rows, - * the last row's height is inflated with the remainder. For example, if the - * view height is 22 and there are two rows, the height of the first row is - * 10 and the second 22. - * - * Notice what this view does to be a good citizen w.r.t its internal selection: - * 1) calls {@link View#requestRectangleOnScreen} each time the selection changes due to - * internal navigation. - * 2) implements {@link View#getFocusedRect} by filling in the rectangle of the currently - * selected row - * 3) overrides {@link View#onFocusChanged} and sets selection appropriately according to - * the previously focused rectangle. - */ -public class InternalSelectionView extends View { - - private Paint mPainter = new Paint(); - private Paint mTextPaint = new Paint(); - private Rect mTempRect = new Rect(); - - private int mNumRows = 5; - private int mSelectedRow = 0; - private final int mEstimatedPixelHeight = 10; - - private Integer mDesiredHeight = null; - private String mLabel = null; - - public InternalSelectionView(Context context, int numRows, String label) { - super(context); - mNumRows = numRows; - mLabel = label; - init(); - } - - public InternalSelectionView(Context context, AttributeSet attrs) { - super(context, attrs); - TypedArray a = - context.obtainStyledAttributes( - attrs, R.styleable.SelectableRowView); - mNumRows = a.getInt(R.styleable.SelectableRowView_numRows, 5); - init(); - } - - private void init() { - setFocusable(true); - mTextPaint.setAntiAlias(true); - mTextPaint.setTextSize(10); - mTextPaint.setColor(Color.WHITE); - } - - public int getNumRows() { - return mNumRows; - } - - public int getSelectedRow() { - return mSelectedRow; - } - - public void setDesiredHeight(int desiredHeight) { - mDesiredHeight = desiredHeight; - } - - public String getLabel() { - return mLabel; - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - setMeasuredDimension( - measureWidth(widthMeasureSpec), - measureHeight(heightMeasureSpec)); - } - - private int measureWidth(int measureSpec) { - int specMode = MeasureSpec.getMode(measureSpec); - int specSize = MeasureSpec.getSize(measureSpec); - - int desiredWidth = 300 + mPaddingLeft + mPaddingRight; - if (specMode == MeasureSpec.EXACTLY) { - // We were told how big to be - return specSize; - } else if (specMode == MeasureSpec.AT_MOST) { - return desiredWidth < specSize ? desiredWidth : specSize; - } else { - return desiredWidth; - } - } - - private int measureHeight(int measureSpec) { - int specMode = MeasureSpec.getMode(measureSpec); - int specSize = MeasureSpec.getSize(measureSpec); - - int desiredHeight = mDesiredHeight != null ? - mDesiredHeight : - mNumRows * mEstimatedPixelHeight + mPaddingTop + mPaddingBottom; - if (specMode == MeasureSpec.EXACTLY) { - // We were told how big to be - return specSize; - } else if (specMode == MeasureSpec.AT_MOST) { - return desiredHeight < specSize ? desiredHeight : specSize; - } else { - return desiredHeight; - } - } - - - @Override - protected void onDraw(Canvas canvas) { - int rectTop = mPaddingTop; - int rectLeft = mPaddingLeft; - int rectRight = getWidth() - mPaddingRight; - for (int i = 0; i < mNumRows; i++) { - - mPainter.setColor(Color.BLACK); - mPainter.setAlpha(0x20); - - int rowHeight = getRowHeight(i); - - // draw background rect - mTempRect.set(rectLeft, rectTop, rectRight, rectTop + rowHeight); - canvas.drawRect(mTempRect, mPainter); - - // draw forground rect - if (i == mSelectedRow && hasFocus()) { - mPainter.setColor(Color.RED); - mPainter.setAlpha(0xF0); - mTextPaint.setAlpha(0xFF); - } else { - mPainter.setColor(Color.BLACK); - mPainter.setAlpha(0x40); - mTextPaint.setAlpha(0xF0); - } - mTempRect.set(rectLeft + 2, rectTop + 2, - rectRight - 2, rectTop + rowHeight - 2); - canvas.drawRect(mTempRect, mPainter); - - // draw text to help when visually inspecting - canvas.drawText( - Integer.toString(i), - rectLeft + 2, - rectTop + 2 - (int) mTextPaint.ascent(), - mTextPaint); - - rectTop += rowHeight; - } - } - - private int getRowHeight(int row) { - final int availableHeight = getHeight() - mPaddingTop - mPaddingBottom; - final int desiredRowHeight = availableHeight / mNumRows; - if (row < mNumRows - 1) { - return desiredRowHeight; - } else { - final int residualHeight = availableHeight % mNumRows; - return desiredRowHeight + residualHeight; - } - } - - public void getRectForRow(Rect rect, int row) { - final int rowHeight = getRowHeight(row); - final int top = mPaddingTop + row * rowHeight; - rect.set(mPaddingLeft, - top, - getWidth() - mPaddingRight, - top + rowHeight); - } - - - void ensureRectVisible() { - getRectForRow(mTempRect, mSelectedRow); - requestRectangleOnScreen(mTempRect); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - switch(event.getKeyCode()) { - case KeyEvent.KEYCODE_DPAD_UP: - if (mSelectedRow > 0) { - mSelectedRow--; - invalidate(); - ensureRectVisible(); - return true; - } - break; - case KeyEvent.KEYCODE_DPAD_DOWN: - if (mSelectedRow < (mNumRows - 1)) { - mSelectedRow++; - invalidate(); - ensureRectVisible(); - return true; - } - break; - } - return false; - } - - - @Override - public void getFocusedRect(Rect r) { - getRectForRow(r, mSelectedRow); - } - - @Override - protected void onFocusChanged(boolean focused, int direction, - Rect previouslyFocusedRect) { - super.onFocusChanged(focused, direction, previouslyFocusedRect); - - if (focused) { - switch (direction) { - case View.FOCUS_DOWN: - mSelectedRow = 0; - break; - case View.FOCUS_UP: - mSelectedRow = mNumRows - 1; - break; - case View.FOCUS_LEFT: // fall through - case View.FOCUS_RIGHT: - // set the row that is closest to the rect - if (previouslyFocusedRect != null) { - int y = previouslyFocusedRect.top - + (previouslyFocusedRect.height() / 2); - int yPerRow = getHeight() / mNumRows; - mSelectedRow = y / yPerRow; - } else { - mSelectedRow = 0; - } - break; - default: - // can't gleam any useful information about what internal - // selection should be... - return; - } - invalidate(); - } - } - - @Override - public String toString() { - if (mLabel != null) { - return mLabel; - } - return super.toString(); - } -} diff --git a/src/main/java/android/util/JsonReader.java b/src/main/java/android/util/JsonReader.java deleted file mode 100644 index 7d1c6c4..0000000 --- a/src/main/java/android/util/JsonReader.java +++ /dev/null @@ -1,1171 +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.util; - -import java.io.Closeable; -import java.io.EOFException; -import java.io.IOException; -import java.io.Reader; -import java.util.ArrayList; -import java.util.List; -import libcore.internal.StringPool; - -/** - * Reads a JSON (RFC 4627) - * encoded value as a stream of tokens. This stream includes both literal - * values (strings, numbers, booleans, and nulls) as well as the begin and - * end delimiters of objects and arrays. The tokens are traversed in - * depth-first order, the same order that they appear in the JSON document. - * Within JSON objects, name/value pairs are represented by a single token. - * - *

    Parsing JSON

    - * To create a recursive descent parser for your own JSON streams, first create - * an entry point method that creates a {@code JsonReader}. - * - *

    Next, create handler methods for each structure in your JSON text. You'll - * need a method for each object type and for each array type. - *

      - *
    • Within array handling methods, first call {@link - * #beginArray} to consume the array's opening bracket. Then create a - * while loop that accumulates values, terminating when {@link #hasNext} - * is false. Finally, read the array's closing bracket by calling {@link - * #endArray}. - *
    • Within object handling methods, first call {@link - * #beginObject} to consume the object's opening brace. Then create a - * while loop that assigns values to local variables based on their name. - * This loop should terminate when {@link #hasNext} is false. Finally, - * read the object's closing brace by calling {@link #endObject}. - *
    - *

    When a nested object or array is encountered, delegate to the - * corresponding handler method. - * - *

    When an unknown name is encountered, strict parsers should fail with an - * exception. Lenient parsers should call {@link #skipValue()} to recursively - * skip the value's nested tokens, which may otherwise conflict. - * - *

    If a value may be null, you should first check using {@link #peek()}. - * Null literals can be consumed using either {@link #nextNull()} or {@link - * #skipValue()}. - * - *

    Example

    - * Suppose we'd like to parse a stream of messages such as the following:
     {@code
    - * [
    - *   {
    - *     "id": 912345678901,
    - *     "text": "How do I read JSON on Android?",
    - *     "geo": null,
    - *     "user": {
    - *       "name": "android_newb",
    - *       "followers_count": 41
    - *      }
    - *   },
    - *   {
    - *     "id": 912345678902,
    - *     "text": "@android_newb just use android.util.JsonReader!",
    - *     "geo": [50.454722, -104.606667],
    - *     "user": {
    - *       "name": "jesse",
    - *       "followers_count": 2
    - *     }
    - *   }
    - * ]}
    - * This code implements the parser for the above structure:
       {@code
    - *
    - *   public List readJsonStream(InputStream in) throws IOException {
    - *     JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8"));
    - *     try {
    - *       return readMessagesArray(reader);
    - *     } finally {
    - *       reader.close();
    - *     }
    - *   }
    - *
    - *   public List readMessagesArray(JsonReader reader) throws IOException {
    - *     List messages = new ArrayList();
    - *
    - *     reader.beginArray();
    - *     while (reader.hasNext()) {
    - *       messages.add(readMessage(reader));
    - *     }
    - *     reader.endArray();
    - *     return messages;
    - *   }
    - *
    - *   public Message readMessage(JsonReader reader) throws IOException {
    - *     long id = -1;
    - *     String text = null;
    - *     User user = null;
    - *     List geo = null;
    - *
    - *     reader.beginObject();
    - *     while (reader.hasNext()) {
    - *       String name = reader.nextName();
    - *       if (name.equals("id")) {
    - *         id = reader.nextLong();
    - *       } else if (name.equals("text")) {
    - *         text = reader.nextString();
    - *       } else if (name.equals("geo") && reader.peek() != JsonToken.NULL) {
    - *         geo = readDoublesArray(reader);
    - *       } else if (name.equals("user")) {
    - *         user = readUser(reader);
    - *       } else {
    - *         reader.skipValue();
    - *       }
    - *     }
    - *     reader.endObject();
    - *     return new Message(id, text, user, geo);
    - *   }
    - *
    - *   public List readDoublesArray(JsonReader reader) throws IOException {
    - *     List doubles = new ArrayList();
    - *
    - *     reader.beginArray();
    - *     while (reader.hasNext()) {
    - *       doubles.add(reader.nextDouble());
    - *     }
    - *     reader.endArray();
    - *     return doubles;
    - *   }
    - *
    - *   public User readUser(JsonReader reader) throws IOException {
    - *     String username = null;
    - *     int followersCount = -1;
    - *
    - *     reader.beginObject();
    - *     while (reader.hasNext()) {
    - *       String name = reader.nextName();
    - *       if (name.equals("name")) {
    - *         username = reader.nextString();
    - *       } else if (name.equals("followers_count")) {
    - *         followersCount = reader.nextInt();
    - *       } else {
    - *         reader.skipValue();
    - *       }
    - *     }
    - *     reader.endObject();
    - *     return new User(username, followersCount);
    - *   }}
    - * - *

    Number Handling

    - * This reader permits numeric values to be read as strings and string values to - * be read as numbers. For example, both elements of the JSON array {@code - * [1, "1"]} may be read using either {@link #nextInt} or {@link #nextString}. - * This behavior is intended to prevent lossy numeric conversions: double is - * JavaScript's only numeric type and very large values like {@code - * 9007199254740993} cannot be represented exactly on that platform. To minimize - * precision loss, extremely large values should be written and read as strings - * in JSON. - * - *

    Each {@code JsonReader} may be used to read a single JSON stream. Instances - * of this class are not thread safe. - */ -public final class JsonReader implements Closeable { - - private static final String TRUE = "true"; - private static final String FALSE = "false"; - - private final StringPool stringPool = new StringPool(); - - /** The input JSON. */ - private final Reader in; - - /** True to accept non-spec compliant JSON */ - private boolean lenient = false; - - /** - * Use a manual buffer to easily read and unread upcoming characters, and - * also so we can create strings without an intermediate StringBuilder. - * We decode literals directly out of this buffer, so it must be at least as - * long as the longest token that can be reported as a number. - */ - private final char[] buffer = new char[1024]; - private int pos = 0; - private int limit = 0; - - /* - * The offset of the first character in the buffer. - */ - private int bufferStartLine = 1; - private int bufferStartColumn = 1; - - private final List stack = new ArrayList(); - { - push(JsonScope.EMPTY_DOCUMENT); - } - - /** - * The type of the next token to be returned by {@link #peek} and {@link - * #advance}. If null, peek() will assign a value. - */ - private JsonToken token; - - /** The text of the next name. */ - private String name; - - /* - * For the next literal value, we may have the text value, or the position - * and length in the buffer. - */ - private String value; - private int valuePos; - private int valueLength; - - /** True if we're currently handling a skipValue() call. */ - private boolean skipping = false; - - /** - * Creates a new instance that reads a JSON-encoded stream from {@code in}. - */ - public JsonReader(Reader in) { - if (in == null) { - throw new NullPointerException("in == null"); - } - this.in = in; - } - - /** - * Configure this parser to be be liberal in what it accepts. By default, - * this parser is strict and only accepts JSON as specified by RFC 4627. Setting the - * parser to lenient causes it to ignore the following syntax errors: - * - *

      - *
    • End of line comments starting with {@code //} or {@code #} and - * ending with a newline character. - *
    • C-style comments starting with {@code /*} and ending with - * {@code *}{@code /}. Such comments may not be nested. - *
    • Names that are unquoted or {@code 'single quoted'}. - *
    • Strings that are unquoted or {@code 'single quoted'}. - *
    • Array elements separated by {@code ;} instead of {@code ,}. - *
    • Unnecessary array separators. These are interpreted as if null - * was the omitted value. - *
    • Names and values separated by {@code =} or {@code =>} instead of - * {@code :}. - *
    • Name/value pairs separated by {@code ;} instead of {@code ,}. - *
    - */ - public void setLenient(boolean lenient) { - this.lenient = lenient; - } - - /** - * Returns true if this parser is liberal in what it accepts. - */ - public boolean isLenient() { - return lenient; - } - - /** - * Consumes the next token from the JSON stream and asserts that it is the - * beginning of a new array. - */ - public void beginArray() throws IOException { - expect(JsonToken.BEGIN_ARRAY); - } - - /** - * Consumes the next token from the JSON stream and asserts that it is the - * end of the current array. - */ - public void endArray() throws IOException { - expect(JsonToken.END_ARRAY); - } - - /** - * Consumes the next token from the JSON stream and asserts that it is the - * beginning of a new object. - */ - public void beginObject() throws IOException { - expect(JsonToken.BEGIN_OBJECT); - } - - /** - * Consumes the next token from the JSON stream and asserts that it is the - * end of the current array. - */ - public void endObject() throws IOException { - expect(JsonToken.END_OBJECT); - } - - /** - * Consumes {@code expected}. - */ - private void expect(JsonToken expected) throws IOException { - peek(); - if (token != expected) { - throw new IllegalStateException("Expected " + expected + " but was " + peek()); - } - advance(); - } - - /** - * Returns true if the current array or object has another element. - */ - public boolean hasNext() throws IOException { - peek(); - return token != JsonToken.END_OBJECT && token != JsonToken.END_ARRAY; - } - - /** - * Returns the type of the next token without consuming it. - */ - public JsonToken peek() throws IOException { - if (token != null) { - return token; - } - - switch (peekStack()) { - case EMPTY_DOCUMENT: - replaceTop(JsonScope.NONEMPTY_DOCUMENT); - JsonToken firstToken = nextValue(); - if (!lenient && token != JsonToken.BEGIN_ARRAY && token != JsonToken.BEGIN_OBJECT) { - throw new IOException( - "Expected JSON document to start with '[' or '{' but was " + token); - } - return firstToken; - case EMPTY_ARRAY: - return nextInArray(true); - case NONEMPTY_ARRAY: - return nextInArray(false); - case EMPTY_OBJECT: - return nextInObject(true); - case DANGLING_NAME: - return objectValue(); - case NONEMPTY_OBJECT: - return nextInObject(false); - case NONEMPTY_DOCUMENT: - try { - JsonToken token = nextValue(); - if (lenient) { - return token; - } - throw syntaxError("Expected EOF"); - } catch (EOFException e) { - return token = JsonToken.END_DOCUMENT; // TODO: avoid throwing here? - } - case CLOSED: - throw new IllegalStateException("JsonReader is closed"); - default: - throw new AssertionError(); - } - } - - /** - * Advances the cursor in the JSON stream to the next token. - */ - private JsonToken advance() throws IOException { - peek(); - - JsonToken result = token; - token = null; - value = null; - name = null; - return result; - } - - /** - * Returns the next token, a {@link JsonToken#NAME property name}, and - * consumes it. - * - * @throws IOException if the next token in the stream is not a property - * name. - */ - public String nextName() throws IOException { - peek(); - if (token != JsonToken.NAME) { - throw new IllegalStateException("Expected a name but was " + peek()); - } - String result = name; - advance(); - return result; - } - - /** - * Returns the {@link JsonToken#STRING string} value of the next token, - * consuming it. If the next token is a number, this method will return its - * string form. - * - * @throws IllegalStateException if the next token is not a string or if - * this reader is closed. - */ - public String nextString() throws IOException { - peek(); - if (token != JsonToken.STRING && token != JsonToken.NUMBER) { - throw new IllegalStateException("Expected a string but was " + peek()); - } - - String result = value; - advance(); - return result; - } - - /** - * Returns the {@link JsonToken#BOOLEAN boolean} value of the next token, - * consuming it. - * - * @throws IllegalStateException if the next token is not a boolean or if - * this reader is closed. - */ - public boolean nextBoolean() throws IOException { - peek(); - if (token != JsonToken.BOOLEAN) { - throw new IllegalStateException("Expected a boolean but was " + token); - } - - boolean result = (value == TRUE); - advance(); - return result; - } - - /** - * Consumes the next token from the JSON stream and asserts that it is a - * literal null. - * - * @throws IllegalStateException if the next token is not null or if this - * reader is closed. - */ - public void nextNull() throws IOException { - peek(); - if (token != JsonToken.NULL) { - throw new IllegalStateException("Expected null but was " + token); - } - - advance(); - } - - /** - * Returns the {@link JsonToken#NUMBER double} value of the next token, - * consuming it. If the next token is a string, this method will attempt to - * parse it as a double using {@link Double#parseDouble(String)}. - * - * @throws IllegalStateException if the next token is not a literal value. - */ - public double nextDouble() throws IOException { - peek(); - if (token != JsonToken.STRING && token != JsonToken.NUMBER) { - throw new IllegalStateException("Expected a double but was " + token); - } - - double result = Double.parseDouble(value); - advance(); - return result; - } - - /** - * Returns the {@link JsonToken#NUMBER long} value of the next token, - * consuming it. If the next token is a string, this method will attempt to - * parse it as a long. If the next token's numeric value cannot be exactly - * represented by a Java {@code long}, this method throws. - * - * @throws IllegalStateException if the next token is not a literal value. - * @throws NumberFormatException if the next literal value cannot be parsed - * as a number, or exactly represented as a long. - */ - public long nextLong() throws IOException { - peek(); - if (token != JsonToken.STRING && token != JsonToken.NUMBER) { - throw new IllegalStateException("Expected a long but was " + token); - } - - long result; - try { - result = Long.parseLong(value); - } catch (NumberFormatException ignored) { - double asDouble = Double.parseDouble(value); // don't catch this NumberFormatException - result = (long) asDouble; - if ((double) result != asDouble) { - throw new NumberFormatException(value); - } - } - - advance(); - return result; - } - - /** - * Returns the {@link JsonToken#NUMBER int} value of the next token, - * consuming it. If the next token is a string, this method will attempt to - * parse it as an int. If the next token's numeric value cannot be exactly - * represented by a Java {@code int}, this method throws. - * - * @throws IllegalStateException if the next token is not a literal value. - * @throws NumberFormatException if the next literal value cannot be parsed - * as a number, or exactly represented as an int. - */ - public int nextInt() throws IOException { - peek(); - if (token != JsonToken.STRING && token != JsonToken.NUMBER) { - throw new IllegalStateException("Expected an int but was " + token); - } - - int result; - try { - result = Integer.parseInt(value); - } catch (NumberFormatException ignored) { - double asDouble = Double.parseDouble(value); // don't catch this NumberFormatException - result = (int) asDouble; - if ((double) result != asDouble) { - throw new NumberFormatException(value); - } - } - - advance(); - return result; - } - - /** - * Closes this JSON reader and the underlying {@link Reader}. - */ - public void close() throws IOException { - value = null; - token = null; - stack.clear(); - stack.add(JsonScope.CLOSED); - in.close(); - } - - /** - * Skips the next value recursively. If it is an object or array, all nested - * elements are skipped. This method is intended for use when the JSON token - * stream contains unrecognized or unhandled values. - */ - public void skipValue() throws IOException { - skipping = true; - try { - if (!hasNext() || peek() == JsonToken.END_DOCUMENT) { - throw new IllegalStateException("No element left to skip"); - } - int count = 0; - do { - JsonToken token = advance(); - if (token == JsonToken.BEGIN_ARRAY || token == JsonToken.BEGIN_OBJECT) { - count++; - } else if (token == JsonToken.END_ARRAY || token == JsonToken.END_OBJECT) { - count--; - } - } while (count != 0); - } finally { - skipping = false; - } - } - - private JsonScope peekStack() { - return stack.get(stack.size() - 1); - } - - private JsonScope pop() { - return stack.remove(stack.size() - 1); - } - - private void push(JsonScope newTop) { - stack.add(newTop); - } - - /** - * Replace the value on the top of the stack with the given value. - */ - private void replaceTop(JsonScope newTop) { - stack.set(stack.size() - 1, newTop); - } - - private JsonToken nextInArray(boolean firstElement) throws IOException { - if (firstElement) { - replaceTop(JsonScope.NONEMPTY_ARRAY); - } else { - /* Look for a comma before each element after the first element. */ - switch (nextNonWhitespace()) { - case ']': - pop(); - return token = JsonToken.END_ARRAY; - case ';': - checkLenient(); // fall-through - case ',': - break; - default: - throw syntaxError("Unterminated array"); - } - } - - switch (nextNonWhitespace()) { - case ']': - if (firstElement) { - pop(); - return token = JsonToken.END_ARRAY; - } - // fall-through to handle ",]" - case ';': - case ',': - /* In lenient mode, a 0-length literal means 'null' */ - checkLenient(); - pos--; - value = "null"; - return token = JsonToken.NULL; - default: - pos--; - return nextValue(); - } - } - - private JsonToken nextInObject(boolean firstElement) throws IOException { - /* - * Read delimiters. Either a comma/semicolon separating this and the - * previous name-value pair, or a close brace to denote the end of the - * object. - */ - if (firstElement) { - /* Peek to see if this is the empty object. */ - switch (nextNonWhitespace()) { - case '}': - pop(); - return token = JsonToken.END_OBJECT; - default: - pos--; - } - } else { - switch (nextNonWhitespace()) { - case '}': - pop(); - return token = JsonToken.END_OBJECT; - case ';': - case ',': - break; - default: - throw syntaxError("Unterminated object"); - } - } - - /* Read the name. */ - int quote = nextNonWhitespace(); - switch (quote) { - case '\'': - checkLenient(); // fall-through - case '"': - name = nextString((char) quote); - break; - default: - checkLenient(); - pos--; - name = nextLiteral(false); - if (name.isEmpty()) { - throw syntaxError("Expected name"); - } - } - - replaceTop(JsonScope.DANGLING_NAME); - return token = JsonToken.NAME; - } - - private JsonToken objectValue() throws IOException { - /* - * Read the name/value separator. Usually a colon ':'. In lenient mode - * we also accept an equals sign '=', or an arrow "=>". - */ - switch (nextNonWhitespace()) { - case ':': - break; - case '=': - checkLenient(); - if ((pos < limit || fillBuffer(1)) && buffer[pos] == '>') { - pos++; - } - break; - default: - throw syntaxError("Expected ':'"); - } - - replaceTop(JsonScope.NONEMPTY_OBJECT); - return nextValue(); - } - - private JsonToken nextValue() throws IOException { - int c = nextNonWhitespace(); - switch (c) { - case '{': - push(JsonScope.EMPTY_OBJECT); - return token = JsonToken.BEGIN_OBJECT; - - case '[': - push(JsonScope.EMPTY_ARRAY); - return token = JsonToken.BEGIN_ARRAY; - - case '\'': - checkLenient(); // fall-through - case '"': - value = nextString((char) c); - return token = JsonToken.STRING; - - default: - pos--; - return readLiteral(); - } - } - - /** - * Returns true once {@code limit - pos >= minimum}. If the data is - * exhausted before that many characters are available, this returns - * false. - */ - private boolean fillBuffer(int minimum) throws IOException { - // Before clobbering the old characters, update where buffer starts - for (int i = 0; i < pos; i++) { - if (buffer[i] == '\n') { - bufferStartLine++; - bufferStartColumn = 1; - } else { - bufferStartColumn++; - } - } - - if (limit != pos) { - limit -= pos; - System.arraycopy(buffer, pos, buffer, 0, limit); - } else { - limit = 0; - } - - pos = 0; - int total; - while ((total = in.read(buffer, limit, buffer.length - limit)) != -1) { - limit += total; - - // if this is the first read, consume an optional byte order mark (BOM) if it exists - if (bufferStartLine == 1 && bufferStartColumn == 1 - && limit > 0 && buffer[0] == '\ufeff') { - pos++; - bufferStartColumn--; - } - - if (limit >= minimum) { - return true; - } - } - return false; - } - - private int getLineNumber() { - int result = bufferStartLine; - for (int i = 0; i < pos; i++) { - if (buffer[i] == '\n') { - result++; - } - } - return result; - } - - private int getColumnNumber() { - int result = bufferStartColumn; - for (int i = 0; i < pos; i++) { - if (buffer[i] == '\n') { - result = 1; - } else { - result++; - } - } - return result; - } - - private int nextNonWhitespace() throws IOException { - while (pos < limit || fillBuffer(1)) { - int c = buffer[pos++]; - switch (c) { - case '\t': - case ' ': - case '\n': - case '\r': - continue; - - case '/': - if (pos == limit && !fillBuffer(1)) { - return c; - } - - checkLenient(); - char peek = buffer[pos]; - switch (peek) { - case '*': - // skip a /* c-style comment */ - pos++; - if (!skipTo("*/")) { - throw syntaxError("Unterminated comment"); - } - pos += 2; - continue; - - case '/': - // skip a // end-of-line comment - pos++; - skipToEndOfLine(); - continue; - - default: - return c; - } - - case '#': - /* - * Skip a # hash end-of-line comment. The JSON RFC doesn't - * specify this behaviour, but it's required to parse - * existing documents. See http://b/2571423. - */ - checkLenient(); - skipToEndOfLine(); - continue; - - default: - return c; - } - } - - throw new EOFException("End of input"); - } - - private void checkLenient() throws IOException { - if (!lenient) { - throw syntaxError("Use JsonReader.setLenient(true) to accept malformed JSON"); - } - } - - /** - * Advances the position until after the next newline character. If the line - * is terminated by "\r\n", the '\n' must be consumed as whitespace by the - * caller. - */ - private void skipToEndOfLine() throws IOException { - while (pos < limit || fillBuffer(1)) { - char c = buffer[pos++]; - if (c == '\r' || c == '\n') { - break; - } - } - } - - private boolean skipTo(String toFind) throws IOException { - outer: - for (; pos + toFind.length() <= limit || fillBuffer(toFind.length()); pos++) { - for (int c = 0; c < toFind.length(); c++) { - if (buffer[pos + c] != toFind.charAt(c)) { - continue outer; - } - } - return true; - } - return false; - } - - /** - * Returns the string up to but not including {@code quote}, unescaping any - * character escape sequences encountered along the way. The opening quote - * should have already been read. This consumes the closing quote, but does - * not include it in the returned string. - * - * @param quote either ' or ". - * @throws NumberFormatException if any unicode escape sequences are - * malformed. - */ - private String nextString(char quote) throws IOException { - StringBuilder builder = null; - do { - /* the index of the first character not yet appended to the builder. */ - int start = pos; - while (pos < limit) { - int c = buffer[pos++]; - - if (c == quote) { - if (skipping) { - return "skipped!"; - } else if (builder == null) { - return stringPool.get(buffer, start, pos - start - 1); - } else { - builder.append(buffer, start, pos - start - 1); - return builder.toString(); - } - - } else if (c == '\\') { - if (builder == null) { - builder = new StringBuilder(); - } - builder.append(buffer, start, pos - start - 1); - builder.append(readEscapeCharacter()); - start = pos; - } - } - - if (builder == null) { - builder = new StringBuilder(); - } - builder.append(buffer, start, pos - start); - } while (fillBuffer(1)); - - throw syntaxError("Unterminated string"); - } - - /** - * Reads the value up to but not including any delimiter characters. This - * does not consume the delimiter character. - * - * @param assignOffsetsOnly true for this method to only set the valuePos - * and valueLength fields and return a null result. This only works if - * the literal is short; a string is returned otherwise. - */ - private String nextLiteral(boolean assignOffsetsOnly) throws IOException { - StringBuilder builder = null; - valuePos = -1; - valueLength = 0; - int i = 0; - - findNonLiteralCharacter: - while (true) { - for (; pos + i < limit; i++) { - switch (buffer[pos + i]) { - case '/': - case '\\': - case ';': - case '#': - case '=': - checkLenient(); // fall-through - case '{': - case '}': - case '[': - case ']': - case ':': - case ',': - case ' ': - case '\t': - case '\f': - case '\r': - case '\n': - break findNonLiteralCharacter; - } - } - - /* - * Attempt to load the entire literal into the buffer at once. If - * we run out of input, add a non-literal character at the end so - * that decoding doesn't need to do bounds checks. - */ - if (i < buffer.length) { - if (fillBuffer(i + 1)) { - continue; - } else { - buffer[limit] = '\0'; - break; - } - } - - // use a StringBuilder when the value is too long. It must be an unquoted string. - if (builder == null) { - builder = new StringBuilder(); - } - builder.append(buffer, pos, i); - valueLength += i; - pos += i; - i = 0; - if (!fillBuffer(1)) { - break; - } - } - - String result; - if (assignOffsetsOnly && builder == null) { - valuePos = pos; - result = null; - } else if (skipping) { - result = "skipped!"; - } else if (builder == null) { - result = stringPool.get(buffer, pos, i); - } else { - builder.append(buffer, pos, i); - result = builder.toString(); - } - valueLength += i; - pos += i; - return result; - } - - @Override public String toString() { - return getClass().getSimpleName() + " near " + getSnippet(); - } - - /** - * Unescapes the character identified by the character or characters that - * immediately follow a backslash. The backslash '\' should have already - * been read. This supports both unicode escapes "u000A" and two-character - * escapes "\n". - * - * @throws NumberFormatException if any unicode escape sequences are - * malformed. - */ - private char readEscapeCharacter() throws IOException { - if (pos == limit && !fillBuffer(1)) { - throw syntaxError("Unterminated escape sequence"); - } - - char escaped = buffer[pos++]; - switch (escaped) { - case 'u': - if (pos + 4 > limit && !fillBuffer(4)) { - throw syntaxError("Unterminated escape sequence"); - } - String hex = stringPool.get(buffer, pos, 4); - pos += 4; - return (char) Integer.parseInt(hex, 16); - - case 't': - return '\t'; - - case 'b': - return '\b'; - - case 'n': - return '\n'; - - case 'r': - return '\r'; - - case 'f': - return '\f'; - - case '\'': - case '"': - case '\\': - default: - return escaped; - } - } - - /** - * Reads a null, boolean, numeric or unquoted string literal value. - */ - private JsonToken readLiteral() throws IOException { - value = nextLiteral(true); - if (valueLength == 0) { - throw syntaxError("Expected literal value"); - } - token = decodeLiteral(); - if (token == JsonToken.STRING) { - checkLenient(); - } - return token; - } - - /** - * Assigns {@code nextToken} based on the value of {@code nextValue}. - */ - private JsonToken decodeLiteral() throws IOException { - if (valuePos == -1) { - // it was too long to fit in the buffer so it can only be a string - return JsonToken.STRING; - } else if (valueLength == 4 - && ('n' == buffer[valuePos ] || 'N' == buffer[valuePos ]) - && ('u' == buffer[valuePos + 1] || 'U' == buffer[valuePos + 1]) - && ('l' == buffer[valuePos + 2] || 'L' == buffer[valuePos + 2]) - && ('l' == buffer[valuePos + 3] || 'L' == buffer[valuePos + 3])) { - value = "null"; - return JsonToken.NULL; - } else if (valueLength == 4 - && ('t' == buffer[valuePos ] || 'T' == buffer[valuePos ]) - && ('r' == buffer[valuePos + 1] || 'R' == buffer[valuePos + 1]) - && ('u' == buffer[valuePos + 2] || 'U' == buffer[valuePos + 2]) - && ('e' == buffer[valuePos + 3] || 'E' == buffer[valuePos + 3])) { - value = TRUE; - return JsonToken.BOOLEAN; - } else if (valueLength == 5 - && ('f' == buffer[valuePos ] || 'F' == buffer[valuePos ]) - && ('a' == buffer[valuePos + 1] || 'A' == buffer[valuePos + 1]) - && ('l' == buffer[valuePos + 2] || 'L' == buffer[valuePos + 2]) - && ('s' == buffer[valuePos + 3] || 'S' == buffer[valuePos + 3]) - && ('e' == buffer[valuePos + 4] || 'E' == buffer[valuePos + 4])) { - value = FALSE; - return JsonToken.BOOLEAN; - } else { - value = stringPool.get(buffer, valuePos, valueLength); - return decodeNumber(buffer, valuePos, valueLength); - } - } - - /** - * Determine whether the characters is a JSON number. Numbers are of the - * form -12.34e+56. Fractional and exponential parts are optional. Leading - * zeroes are not allowed in the value or exponential part, but are allowed - * in the fraction. - */ - private JsonToken decodeNumber(char[] chars, int offset, int length) { - int i = offset; - int c = chars[i]; - - if (c == '-') { - c = chars[++i]; - } - - if (c == '0') { - c = chars[++i]; - } else if (c >= '1' && c <= '9') { - c = chars[++i]; - while (c >= '0' && c <= '9') { - c = chars[++i]; - } - } else { - return JsonToken.STRING; - } - - if (c == '.') { - c = chars[++i]; - while (c >= '0' && c <= '9') { - c = chars[++i]; - } - } - - if (c == 'e' || c == 'E') { - c = chars[++i]; - if (c == '+' || c == '-') { - c = chars[++i]; - } - if (c >= '0' && c <= '9') { - c = chars[++i]; - while (c >= '0' && c <= '9') { - c = chars[++i]; - } - } else { - return JsonToken.STRING; - } - } - - if (i == offset + length) { - return JsonToken.NUMBER; - } else { - return JsonToken.STRING; - } - } - - /** - * Throws a new IO exception with the given message and a context snippet - * with this reader's content. - */ - private IOException syntaxError(String message) throws IOException { - throw new MalformedJsonException(message - + " at line " + getLineNumber() + " column " + getColumnNumber()); - } - - private CharSequence getSnippet() { - StringBuilder snippet = new StringBuilder(); - int beforePos = Math.min(pos, 20); - snippet.append(buffer, pos - beforePos, beforePos); - int afterPos = Math.min(limit - pos, 20); - snippet.append(buffer, pos, afterPos); - return snippet; - } -} diff --git a/src/main/java/android/util/JsonScope.java b/src/main/java/android/util/JsonScope.java deleted file mode 100644 index ca534e9..0000000 --- a/src/main/java/android/util/JsonScope.java +++ /dev/null @@ -1,68 +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.util; - -/** - * Lexical scoping elements within a JSON reader or writer. - */ -enum JsonScope { - - /** - * An array with no elements requires no separators or newlines before - * it is closed. - */ - EMPTY_ARRAY, - - /** - * A array with at least one value requires a comma and newline before - * the next element. - */ - NONEMPTY_ARRAY, - - /** - * An object with no name/value pairs requires no separators or newlines - * before it is closed. - */ - EMPTY_OBJECT, - - /** - * An object whose most recent element is a key. The next element must - * be a value. - */ - DANGLING_NAME, - - /** - * An object with at least one name/value pair requires a comma and - * newline before the next element. - */ - NONEMPTY_OBJECT, - - /** - * No object or array has been started. - */ - EMPTY_DOCUMENT, - - /** - * A document with at an array or object. - */ - NONEMPTY_DOCUMENT, - - /** - * A document that's been closed and cannot be accessed. - */ - CLOSED, -} diff --git a/src/main/java/android/util/JsonToken.java b/src/main/java/android/util/JsonToken.java deleted file mode 100644 index 45bc6ca..0000000 --- a/src/main/java/android/util/JsonToken.java +++ /dev/null @@ -1,82 +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.util; - -/** - * A structure, name or value type in a JSON-encoded string. - */ -public enum JsonToken { - - /** - * The opening of a JSON array. Written using {@link JsonWriter#beginObject} - * and read using {@link JsonReader#beginObject}. - */ - BEGIN_ARRAY, - - /** - * The closing of a JSON array. Written using {@link JsonWriter#endArray} - * and read using {@link JsonReader#endArray}. - */ - END_ARRAY, - - /** - * The opening of a JSON object. Written using {@link JsonWriter#beginObject} - * and read using {@link JsonReader#beginObject}. - */ - BEGIN_OBJECT, - - /** - * The closing of a JSON object. Written using {@link JsonWriter#endObject} - * and read using {@link JsonReader#endObject}. - */ - END_OBJECT, - - /** - * A JSON property name. Within objects, tokens alternate between names and - * their values. Written using {@link JsonWriter#name} and read using {@link - * JsonReader#nextName} - */ - NAME, - - /** - * A JSON string. - */ - STRING, - - /** - * A JSON number represented in this API by a Java {@code double}, {@code - * long}, or {@code int}. - */ - NUMBER, - - /** - * A JSON {@code true} or {@code false}. - */ - BOOLEAN, - - /** - * A JSON {@code null}. - */ - NULL, - - /** - * The end of the JSON stream. This sentinel value is returned by {@link - * JsonReader#peek()} to signal that the JSON-encoded value has no more - * tokens. - */ - END_DOCUMENT -} diff --git a/src/main/java/android/util/JsonWriter.java b/src/main/java/android/util/JsonWriter.java deleted file mode 100644 index c1e6e40..0000000 --- a/src/main/java/android/util/JsonWriter.java +++ /dev/null @@ -1,528 +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.util; - -import java.io.Closeable; -import java.io.IOException; -import java.io.Writer; -import java.util.ArrayList; -import java.util.List; - -/** - * Writes a JSON (RFC 4627) - * encoded value to a stream, one token at a time. The stream includes both - * literal values (strings, numbers, booleans and nulls) as well as the begin - * and end delimiters of objects and arrays. - * - *

    Encoding JSON

    - * To encode your data as JSON, create a new {@code JsonWriter}. Each JSON - * document must contain one top-level array or object. Call methods on the - * writer as you walk the structure's contents, nesting arrays and objects as - * necessary: - *
      - *
    • To write arrays, first call {@link #beginArray()}. - * Write each of the array's elements with the appropriate {@link #value} - * methods or by nesting other arrays and objects. Finally close the array - * using {@link #endArray()}. - *
    • To write objects, first call {@link #beginObject()}. - * Write each of the object's properties by alternating calls to - * {@link #name} with the property's value. Write property values with the - * appropriate {@link #value} method or by nesting other objects or arrays. - * Finally close the object using {@link #endObject()}. - *
    - * - *

    Example

    - * Suppose we'd like to encode a stream of messages such as the following:
     {@code
    - * [
    - *   {
    - *     "id": 912345678901,
    - *     "text": "How do I write JSON on Android?",
    - *     "geo": null,
    - *     "user": {
    - *       "name": "android_newb",
    - *       "followers_count": 41
    - *      }
    - *   },
    - *   {
    - *     "id": 912345678902,
    - *     "text": "@android_newb just use android.util.JsonWriter!",
    - *     "geo": [50.454722, -104.606667],
    - *     "user": {
    - *       "name": "jesse",
    - *       "followers_count": 2
    - *     }
    - *   }
    - * ]}
    - * This code encodes the above structure:
       {@code
    - *   public void writeJsonStream(OutputStream out, List messages) throws IOException {
    - *     JsonWriter writer = new JsonWriter(new OutputStreamWriter(out, "UTF-8"));
    - *     writer.setIndent("  ");
    - *     writeMessagesArray(writer, messages);
    - *     writer.close();
    - *   }
    - *
    - *   public void writeMessagesArray(JsonWriter writer, List messages) throws IOException {
    - *     writer.beginArray();
    - *     for (Message message : messages) {
    - *       writeMessage(writer, message);
    - *     }
    - *     writer.endArray();
    - *   }
    - *
    - *   public void writeMessage(JsonWriter writer, Message message) throws IOException {
    - *     writer.beginObject();
    - *     writer.name("id").value(message.getId());
    - *     writer.name("text").value(message.getText());
    - *     if (message.getGeo() != null) {
    - *       writer.name("geo");
    - *       writeDoublesArray(writer, message.getGeo());
    - *     } else {
    - *       writer.name("geo").nullValue();
    - *     }
    - *     writer.name("user");
    - *     writeUser(writer, message.getUser());
    - *     writer.endObject();
    - *   }
    - *
    - *   public void writeUser(JsonWriter writer, User user) throws IOException {
    - *     writer.beginObject();
    - *     writer.name("name").value(user.getName());
    - *     writer.name("followers_count").value(user.getFollowersCount());
    - *     writer.endObject();
    - *   }
    - *
    - *   public void writeDoublesArray(JsonWriter writer, List doubles) throws IOException {
    - *     writer.beginArray();
    - *     for (Double value : doubles) {
    - *       writer.value(value);
    - *     }
    - *     writer.endArray();
    - *   }}
    - * - *

    Each {@code JsonWriter} may be used to write a single JSON stream. - * Instances of this class are not thread safe. Calls that would result in a - * malformed JSON string will fail with an {@link IllegalStateException}. - */ -public final class JsonWriter implements Closeable { - - /** The output data, containing at most one top-level array or object. */ - private final Writer out; - - private final List stack = new ArrayList(); - { - stack.add(JsonScope.EMPTY_DOCUMENT); - } - - /** - * A string containing a full set of spaces for a single level of - * indentation, or null for no pretty printing. - */ - private String indent; - - /** - * The name/value separator; either ":" or ": ". - */ - private String separator = ":"; - - private boolean lenient; - - /** - * Creates a new instance that writes a JSON-encoded stream to {@code out}. - * For best performance, ensure {@link Writer} is buffered; wrapping in - * {@link java.io.BufferedWriter BufferedWriter} if necessary. - */ - public JsonWriter(Writer out) { - if (out == null) { - throw new NullPointerException("out == null"); - } - this.out = out; - } - - /** - * Sets the indentation string to be repeated for each level of indentation - * in the encoded document. If {@code indent.isEmpty()} the encoded document - * will be compact. Otherwise the encoded document will be more - * human-readable. - * - * @param indent a string containing only whitespace. - */ - public void setIndent(String indent) { - if (indent.isEmpty()) { - this.indent = null; - this.separator = ":"; - } else { - this.indent = indent; - this.separator = ": "; - } - } - - /** - * Configure this writer to relax its syntax rules. By default, this writer - * only emits well-formed JSON as specified by RFC 4627. Setting the writer - * to lenient permits the following: - *

      - *
    • Top-level values of any type. With strict writing, the top-level - * value must be an object or an array. - *
    • Numbers may be {@link Double#isNaN() NaNs} or {@link - * Double#isInfinite() infinities}. - *
    - */ - public void setLenient(boolean lenient) { - this.lenient = lenient; - } - - /** - * Returns true if this writer has relaxed syntax rules. - */ - public boolean isLenient() { - return lenient; - } - - /** - * Begins encoding a new array. Each call to this method must be paired with - * a call to {@link #endArray}. - * - * @return this writer. - */ - public JsonWriter beginArray() throws IOException { - return open(JsonScope.EMPTY_ARRAY, "["); - } - - /** - * Ends encoding the current array. - * - * @return this writer. - */ - public JsonWriter endArray() throws IOException { - return close(JsonScope.EMPTY_ARRAY, JsonScope.NONEMPTY_ARRAY, "]"); - } - - /** - * Begins encoding a new object. Each call to this method must be paired - * with a call to {@link #endObject}. - * - * @return this writer. - */ - public JsonWriter beginObject() throws IOException { - return open(JsonScope.EMPTY_OBJECT, "{"); - } - - /** - * Ends encoding the current object. - * - * @return this writer. - */ - public JsonWriter endObject() throws IOException { - return close(JsonScope.EMPTY_OBJECT, JsonScope.NONEMPTY_OBJECT, "}"); - } - - /** - * Enters a new scope by appending any necessary whitespace and the given - * bracket. - */ - private JsonWriter open(JsonScope empty, String openBracket) throws IOException { - beforeValue(true); - stack.add(empty); - out.write(openBracket); - return this; - } - - /** - * Closes the current scope by appending any necessary whitespace and the - * given bracket. - */ - private JsonWriter close(JsonScope empty, JsonScope nonempty, String closeBracket) - throws IOException { - JsonScope context = peek(); - if (context != nonempty && context != empty) { - throw new IllegalStateException("Nesting problem: " + stack); - } - - stack.remove(stack.size() - 1); - if (context == nonempty) { - newline(); - } - out.write(closeBracket); - return this; - } - - /** - * Returns the value on the top of the stack. - */ - private JsonScope peek() { - return stack.get(stack.size() - 1); - } - - /** - * Replace the value on the top of the stack with the given value. - */ - private void replaceTop(JsonScope topOfStack) { - stack.set(stack.size() - 1, topOfStack); - } - - /** - * Encodes the property name. - * - * @param name the name of the forthcoming value. May not be null. - * @return this writer. - */ - public JsonWriter name(String name) throws IOException { - if (name == null) { - throw new NullPointerException("name == null"); - } - beforeName(); - string(name); - return this; - } - - /** - * Encodes {@code value}. - * - * @param value the literal string value, or null to encode a null literal. - * @return this writer. - */ - public JsonWriter value(String value) throws IOException { - if (value == null) { - return nullValue(); - } - beforeValue(false); - string(value); - return this; - } - - /** - * Encodes {@code null}. - * - * @return this writer. - */ - public JsonWriter nullValue() throws IOException { - beforeValue(false); - out.write("null"); - return this; - } - - /** - * Encodes {@code value}. - * - * @return this writer. - */ - public JsonWriter value(boolean value) throws IOException { - beforeValue(false); - out.write(value ? "true" : "false"); - return this; - } - - /** - * Encodes {@code value}. - * - * @param value a finite value. May not be {@link Double#isNaN() NaNs} or - * {@link Double#isInfinite() infinities} unless this writer is lenient. - * @return this writer. - */ - public JsonWriter value(double value) throws IOException { - if (!lenient && (Double.isNaN(value) || Double.isInfinite(value))) { - throw new IllegalArgumentException("Numeric values must be finite, but was " + value); - } - beforeValue(false); - out.append(Double.toString(value)); - return this; - } - - /** - * Encodes {@code value}. - * - * @return this writer. - */ - public JsonWriter value(long value) throws IOException { - beforeValue(false); - out.write(Long.toString(value)); - return this; - } - - /** - * Encodes {@code value}. - * - * @param value a finite value. May not be {@link Double#isNaN() NaNs} or - * {@link Double#isInfinite() infinities} unless this writer is lenient. - * @return this writer. - */ - public JsonWriter value(Number value) throws IOException { - if (value == null) { - return nullValue(); - } - - String string = value.toString(); - if (!lenient && - (string.equals("-Infinity") || string.equals("Infinity") || string.equals("NaN"))) { - throw new IllegalArgumentException("Numeric values must be finite, but was " + value); - } - beforeValue(false); - out.append(string); - return this; - } - - /** - * Ensures all buffered data is written to the underlying {@link Writer} - * and flushes that writer. - */ - public void flush() throws IOException { - out.flush(); - } - - /** - * Flushes and closes this writer and the underlying {@link Writer}. - * - * @throws IOException if the JSON document is incomplete. - */ - public void close() throws IOException { - out.close(); - - if (peek() != JsonScope.NONEMPTY_DOCUMENT) { - throw new IOException("Incomplete document"); - } - } - - private void string(String value) throws IOException { - out.write("\""); - for (int i = 0, length = value.length(); i < length; i++) { - char c = value.charAt(i); - - /* - * From RFC 4627, "All Unicode characters may be placed within the - * quotation marks except for the characters that must be escaped: - * quotation mark, reverse solidus, and the control characters - * (U+0000 through U+001F)." - * - * We also escape '\u2028' and '\u2029', which JavaScript interprets - * as newline characters. This prevents eval() from failing with a - * syntax error. - * http://code.google.com/p/google-gson/issues/detail?id=341 - */ - switch (c) { - case '"': - case '\\': - out.write('\\'); - out.write(c); - break; - - case '\t': - out.write("\\t"); - break; - - case '\b': - out.write("\\b"); - break; - - case '\n': - out.write("\\n"); - break; - - case '\r': - out.write("\\r"); - break; - - case '\f': - out.write("\\f"); - break; - - case '\u2028': - case '\u2029': - out.write(String.format("\\u%04x", (int) c)); - break; - - default: - if (c <= 0x1F) { - out.write(String.format("\\u%04x", (int) c)); - } else { - out.write(c); - } - break; - } - - } - out.write("\""); - } - - private void newline() throws IOException { - if (indent == null) { - return; - } - - out.write("\n"); - for (int i = 1; i < stack.size(); i++) { - out.write(indent); - } - } - - /** - * Inserts any necessary separators and whitespace before a name. Also - * adjusts the stack to expect the name's value. - */ - private void beforeName() throws IOException { - JsonScope context = peek(); - if (context == JsonScope.NONEMPTY_OBJECT) { // first in object - out.write(','); - } else if (context != JsonScope.EMPTY_OBJECT) { // not in an object! - throw new IllegalStateException("Nesting problem: " + stack); - } - newline(); - replaceTop(JsonScope.DANGLING_NAME); - } - - /** - * Inserts any necessary separators and whitespace before a literal value, - * inline array, or inline object. Also adjusts the stack to expect either a - * closing bracket or another element. - * - * @param root true if the value is a new array or object, the two values - * permitted as top-level elements. - */ - private void beforeValue(boolean root) throws IOException { - switch (peek()) { - case EMPTY_DOCUMENT: // first in document - if (!lenient && !root) { - throw new IllegalStateException( - "JSON must start with an array or an object."); - } - replaceTop(JsonScope.NONEMPTY_DOCUMENT); - break; - - case EMPTY_ARRAY: // first in array - replaceTop(JsonScope.NONEMPTY_ARRAY); - newline(); - break; - - case NONEMPTY_ARRAY: // another in array - out.append(','); - newline(); - break; - - case DANGLING_NAME: // value for name - out.append(separator); - replaceTop(JsonScope.NONEMPTY_OBJECT); - break; - - case NONEMPTY_DOCUMENT: - throw new IllegalStateException( - "JSON must have only one top-level value."); - - default: - throw new IllegalStateException("Nesting problem: " + stack); - } - } -} diff --git a/src/main/java/android/util/KeyUtils.java b/src/main/java/android/util/KeyUtils.java deleted file mode 100644 index b58fda3..0000000 --- a/src/main/java/android/util/KeyUtils.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import android.app.Instrumentation; -import android.os.SystemClock; -import android.test.ActivityInstrumentationTestCase; -import android.test.InstrumentationTestCase; -import android.view.Gravity; -import android.view.KeyCharacterMap; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewConfiguration; -import android.view.ViewGroup; - -/** - * Reusable methods for generating key events. - *

    - * Definitions: - *

  • Tap refers to pushing and releasing a button (down and up event). - *
  • Chord refers to pushing a modifier key, tapping a regular key, and - * releasing the modifier key. - */ -public class KeyUtils { - /** - * Simulates tapping the menu key. - * - * @param test The test case that is being run. - */ - public static void tapMenuKey(ActivityInstrumentationTestCase test) { - final Instrumentation inst = test.getInstrumentation(); - - inst.sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU)); - inst.sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MENU)); - } - - /** - * Simulates chording the menu key. - * - * @param test The test case that is being run. - * @param shortcutKey The shortcut key to tap while chording the menu key. - */ - public static void chordMenuKey(ActivityInstrumentationTestCase test, char shortcutKey) { - final Instrumentation inst = test.getInstrumentation(); - - final KeyEvent pushMenuKey = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU); - final KeyCharacterMap keyCharMap = KeyCharacterMap.load(pushMenuKey.getDeviceId()); - final KeyEvent shortcutKeyEvent = keyCharMap.getEvents(new char[] { shortcutKey })[0]; - final int shortcutKeyCode = shortcutKeyEvent.getKeyCode(); - - inst.sendKeySync(pushMenuKey); - inst.sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, shortcutKeyCode)); - inst.sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, shortcutKeyCode)); - inst.sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MENU)); - } - - /** - * Simulates a long click via the keyboard. - * - * @param test The test case that is being run. - */ - public static void longClick(ActivityInstrumentationTestCase test) { - final Instrumentation inst = test.getInstrumentation(); - - inst.sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER)); - try { - Thread.sleep((long)(ViewConfiguration.getLongPressTimeout() * 1.5f)); - } catch (InterruptedException e) { - e.printStackTrace(); - } - inst.sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER)); - } -} diff --git a/src/main/java/android/util/LayoutDirection.java b/src/main/java/android/util/LayoutDirection.java deleted file mode 100644 index 20af20b..0000000 --- a/src/main/java/android/util/LayoutDirection.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2013 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.util; - -/** - * A class for defining layout directions. A layout direction can be left-to-right (LTR) - * or right-to-left (RTL). It can also be inherited (from a parent) or deduced from the default - * language script of a locale. - */ -public final class LayoutDirection { - - // No instantiation - private LayoutDirection() {} - - /** - * Horizontal layout direction is from Left to Right. - */ - public static final int LTR = 0; - - /** - * Horizontal layout direction is from Right to Left. - */ - public static final int RTL = 1; - - /** - * Horizontal layout direction is inherited. - */ - public static final int INHERIT = 2; - - /** - * Horizontal layout direction is deduced from the default language script for the locale. - */ - public static final int LOCALE = 3; -} diff --git a/src/main/java/android/util/ListItemFactory.java b/src/main/java/android/util/ListItemFactory.java deleted file mode 100644 index 3f48dcc..0000000 --- a/src/main/java/android/util/ListItemFactory.java +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import android.content.Context; -import android.view.Gravity; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AbsListView; -import android.widget.Button; -import android.widget.LinearLayout; -import android.widget.TextView; - -/** - * Reusable methods for creating more complex list items. - */ -public class ListItemFactory { - - /** - * Create a view with a button at the top and bottom, with filler in between. - * The filler is sized to take up any space left over within desiredHeight. - * - * @param position The position within the list. - * @param context The context. - * @param desiredHeight The desired height of the entire view. - * @return The created view. - */ - public static View twoButtonsSeparatedByFiller(int position, Context context, int desiredHeight) { - if (desiredHeight < 90) { - throw new IllegalArgumentException("need at least 90 pixels of height " + - "to create the two buttons and leave 10 pixels for the filler"); - } - - final LinearLayout ll = new LinearLayout(context); - ll.setOrientation(LinearLayout.VERTICAL); - - final LinearLayout.LayoutParams buttonLp = - new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - 50); - - final Button topButton = new Button(context); - topButton.setLayoutParams( - buttonLp); - topButton.setText("top (position " + position + ")"); - ll.addView(topButton); - - final TextView middleFiller = new TextView(context); - middleFiller.setLayoutParams(new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - desiredHeight - 100)); - middleFiller.setText("filler"); - ll.addView(middleFiller); - - final Button bottomButton = new Button(context); - bottomButton.setLayoutParams(buttonLp); - bottomButton.setText("bottom (position " + position + ")"); - ll.addView(bottomButton); - ll.setTag("twoButtons"); - return ll; - } - - public enum Slot { - Left, - Middle, - Right - } - - /** - * Create a horizontal linear layout divided into thirds (with some margins - * separating the thirds), filled with buttons into some slots. - * @param context The context. - * @param desiredHeight The height of the LL. - * @param slots Which slots to fill with buttons. - * @return The linear layout. - */ - public static View horizontalButtonSlots(Context context, int desiredHeight, Slot... slots) { - - final LinearLayout ll = new LinearLayout(context); - ll.setOrientation(LinearLayout.HORIZONTAL); - - final LinearLayout.LayoutParams lp - = new LinearLayout.LayoutParams(0, desiredHeight); - lp.setMargins(10, 0, 10, 0); - lp.weight = 0.33f; - - boolean left = false; - boolean middle = false; - boolean right = false; - for (Slot slot : slots) { - switch (slot) { - case Left: - left = true; - break; - case Middle: - middle = true; - break; - case Right: - right = true; - break; - } - } - - if (left) { - final Button button = new Button(context); - button.setText("left"); - ll.addView(button, lp); - } else { - ll.addView(new View(context), lp); - } - - if (middle) { - final Button button = new Button(context); - button.setText("center"); - ll.addView(button, lp); - } else { - ll.addView(new View(context), lp); - } - - if (right) { - final Button button = new Button(context); - button.setText("right"); - ll.addView(button, lp); - } else { - ll.addView(new View(context), lp); - } - - return ll; - } - - - /** - * Create a button ready to be a list item. - * - * @param position The position within the list. - * @param context The context. - * @param text The text of the button - * @param desiredHeight The desired height of the button - * @return The created view. - */ - public static View button(int position, Context context, String text, int desiredHeight) { - TextView result = new Button(context); - result.setHeight(desiredHeight); - result.setText(text); - final ViewGroup.LayoutParams lp = new AbsListView.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT); - result.setLayoutParams(lp); - result.setId(position); - result.setTag("button"); - return result; - } - - /** - * Convert an existing button view to display the data at a new position. - * - * @param convertView Non-null Button created by {@link #button} - * @param text The text of the button - * @param position The position withion the list - * @return The converted view - */ - public static View convertButton(View convertView, String text, int position) { - if (((String) convertView.getTag()).equals("button")) { - ((Button) convertView).setText(text); - convertView.setId(position); - return convertView; - } else { - return null; - } - } - - /** - * Create a text view ready to be a list item. - * - * @param position The position within the list. - * @param context The context. - * @param text The text to display - * @param desiredHeight The desired height of the text view - * @return The created view. - */ - public static View text(int position, Context context, String text, int desiredHeight) { - TextView result = new TextView(context); - result.setHeight(desiredHeight); - result.setText(text); - final ViewGroup.LayoutParams lp = new AbsListView.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT); - result.setLayoutParams(lp); - result.setId(position); - result.setTag("text"); - return result; - } - - /** - * Convert an existing text view to display the data at a new position. - * - * @param convertView Non-null TextView created by {@link #text} - * @param text The text to display - * @param position The position withion the list - * @return The converted view - */ - public static View convertText(View convertView, String text, int position) { - if(convertView.getTag() != null && ((String) convertView.getTag()).equals("text")) { - ((TextView) convertView).setText(text); - convertView.setId(position); - return convertView; - - } else { - return null; - } - } - - /** - * Create a text view ready to be a list item. - * - * @param position The position within the list. - * @param context The context. - * @param text The text of the button - * @param desiredHeight The desired height of the button - * @return The created view. - */ - public static View doubleText(int position, Context context, String text, int desiredHeight) { - final LinearLayout ll = new LinearLayout(context); - ll.setOrientation(LinearLayout.HORIZONTAL); - - final AbsListView.LayoutParams lp = - new AbsListView.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - desiredHeight); - ll.setLayoutParams(lp); - ll.setId(position); - - TextView t1 = new TextView(context); - t1.setHeight(desiredHeight); - t1.setText(text); - t1.setGravity(Gravity.START | Gravity.CENTER_VERTICAL); - final ViewGroup.LayoutParams lp1 = new LinearLayout.LayoutParams( - 0, - ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f); - ll.addView(t1, lp1); - - TextView t2 = new TextView(context); - t2.setHeight(desiredHeight); - t2.setText(text); - t2.setGravity(Gravity.RIGHT | Gravity.CENTER_VERTICAL); - final ViewGroup.LayoutParams lp2 = new LinearLayout.LayoutParams( - 0, - ViewGroup.LayoutParams.WRAP_CONTENT, - 1.0f); - - ll.addView(t2, lp2); - ll.setTag("double"); - return ll; - } - - - /** - * Convert an existing button view to display the data at a new position. - * - * @param convertView Non-null view created by {@link #doubleText} - * @param text The text of the button - * @param position The position withion the list - * @return The converted view - */ - public static View convertDoubleText(View convertView, String text, int position) { - if (((String) convertView.getTag()).equals("double")) { - TextView t1 = (TextView) ((LinearLayout) convertView).getChildAt(0); - TextView t2 = (TextView) ((LinearLayout) convertView).getChildAt(1); - t1.setText(text); - t2.setText(text); - convertView.setId(position); - return convertView; - } else { - return null; - } - } -} diff --git a/src/main/java/android/util/ListScenario.java b/src/main/java/android/util/ListScenario.java deleted file mode 100644 index fa088a3..0000000 --- a/src/main/java/android/util/ListScenario.java +++ /dev/null @@ -1,662 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import android.app.Activity; -import android.graphics.Rect; -import android.os.Bundle; -import android.view.View; -import android.view.ViewGroup; -import android.view.Window; -import android.widget.AdapterView; -import android.widget.BaseAdapter; -import android.widget.EditText; -import android.widget.LinearLayout; -import android.widget.ListView; -import android.widget.TextView; -import com.google.android.collect.Maps; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * Utility base class for creating various List scenarios. Configurable by the number - * of items, how tall each item should be (in relation to the screen height), and - * what item should start with selection. - */ -public abstract class ListScenario extends Activity { - - private ListView mListView; - private TextView mHeaderTextView; - - private int mNumItems; - protected boolean mItemsFocusable; - - private int mStartingSelectionPosition; - private double mItemScreenSizeFactor; - private Map mOverrideItemScreenSizeFactors = Maps.newHashMap(); - - private int mScreenHeight; - - // whether to include a text view above the list - private boolean mIncludeHeader; - - // separators - private Set mUnselectableItems = new HashSet(); - - private boolean mStackFromBottom; - - private int mClickedPosition = -1; - - private int mLongClickedPosition = -1; - - private int mConvertMisses = 0; - - private int mHeaderViewCount; - private boolean mHeadersFocusable; - - private int mFooterViewCount; - private LinearLayout mLinearLayout; - - public ListView getListView() { - return mListView; - } - - protected int getScreenHeight() { - return mScreenHeight; - } - - /** - * Return whether the item at position is selectable (i.e is a separator). - * (external users can access this info using the adapter) - */ - private boolean isItemAtPositionSelectable(int position) { - return !mUnselectableItems.contains(position); - } - - /** - * Better way to pass in optional params than a honkin' paramater list :) - */ - public static class Params { - private int mNumItems = 4; - private boolean mItemsFocusable = false; - private int mStartingSelectionPosition = 0; - private double mItemScreenSizeFactor = 1 / 5; - private Double mFadingEdgeScreenSizeFactor = null; - - private Map mOverrideItemScreenSizeFactors = Maps.newHashMap(); - - // separators - private List mUnselectableItems = new ArrayList(8); - // whether to include a text view above the list - private boolean mIncludeHeader = false; - private boolean mStackFromBottom = false; - public boolean mMustFillScreen = true; - private int mHeaderViewCount; - private boolean mHeaderFocusable = false; - private int mFooterViewCount; - - private boolean mConnectAdapter = true; - - /** - * Set the number of items in the list. - */ - public Params setNumItems(int numItems) { - mNumItems = numItems; - return this; - } - - /** - * Set whether the items are focusable. - */ - public Params setItemsFocusable(boolean itemsFocusable) { - mItemsFocusable = itemsFocusable; - return this; - } - - /** - * Set the position that starts selected. - * - * @param startingSelectionPosition The selected position within the adapter's data set. - * Pass -1 if you do not want to force a selection. - * @return - */ - public Params setStartingSelectionPosition(int startingSelectionPosition) { - mStartingSelectionPosition = startingSelectionPosition; - return this; - } - - /** - * Set the factor that determines how tall each item is in relation to the - * screen height. - */ - public Params setItemScreenSizeFactor(double itemScreenSizeFactor) { - mItemScreenSizeFactor = itemScreenSizeFactor; - return this; - } - - /** - * Override the item screen size factor for a particular item. Useful for - * creating lists with non-uniform item height. - * @param position The position in the list. - * @param itemScreenSizeFactor The screen size factor to use for the height. - */ - public Params setPositionScreenSizeFactorOverride( - int position, double itemScreenSizeFactor) { - mOverrideItemScreenSizeFactors.put(position, itemScreenSizeFactor); - return this; - } - - /** - * Set a position as unselectable (a.k.a a separator) - * @param position - * @return - */ - public Params setPositionUnselectable(int position) { - mUnselectableItems.add(position); - return this; - } - - /** - * Set positions as unselectable (a.k.a a separator) - */ - public Params setPositionsUnselectable(int ...positions) { - for (int pos : positions) { - setPositionUnselectable(pos); - } - return this; - } - - /** - * Include a header text view above the list. - * @param includeHeader - * @return - */ - public Params includeHeaderAboveList(boolean includeHeader) { - mIncludeHeader = includeHeader; - return this; - } - - /** - * Sets the stacking direction - * @param stackFromBottom - * @return - */ - public Params setStackFromBottom(boolean stackFromBottom) { - mStackFromBottom = stackFromBottom; - return this; - } - - /** - * Sets whether the sum of the height of the list items must be at least the - * height of the list view. - */ - public Params setMustFillScreen(boolean fillScreen) { - mMustFillScreen = fillScreen; - return this; - } - - /** - * Set the factor for the fading edge length. - */ - public Params setFadingEdgeScreenSizeFactor(double fadingEdgeScreenSizeFactor) { - mFadingEdgeScreenSizeFactor = fadingEdgeScreenSizeFactor; - return this; - } - - /** - * Set the number of header views to appear within the list - */ - public Params setHeaderViewCount(int headerViewCount) { - mHeaderViewCount = headerViewCount; - return this; - } - - /** - * Set whether the headers should be focusable. - * @param headerFocusable Whether the headers should be focusable (i.e - * created as edit texts rather than text views). - */ - public Params setHeaderFocusable(boolean headerFocusable) { - mHeaderFocusable = headerFocusable; - return this; - } - - /** - * Set the number of footer views to appear within the list - */ - public Params setFooterViewCount(int footerViewCount) { - mFooterViewCount = footerViewCount; - return this; - } - - /** - * Sets whether the {@link ListScenario} will automatically set the - * adapter on the list view. If this is false, the client MUST set it - * manually (this is useful when adding headers to the list view, which - * must be done before the adapter is set). - */ - public Params setConnectAdapter(boolean connectAdapter) { - mConnectAdapter = connectAdapter; - return this; - } - } - - /** - * How each scenario customizes its behavior. - * @param params - */ - protected abstract void init(Params params); - - /** - * Override this if you want to know when something has been selected (perhaps - * more importantly, that {@link android.widget.AdapterView.OnItemSelectedListener} has - * been triggered). - */ - protected void positionSelected(int positon) { - } - - /** - * Override this if you want to know that nothing is selected. - */ - protected void nothingSelected() { - } - - /** - * Override this if you want to know when something has been clicked (perhaps - * more importantly, that {@link android.widget.AdapterView.OnItemClickListener} has - * been triggered). - */ - protected void positionClicked(int position) { - setClickedPosition(position); - } - - /** - * Override this if you want to know when something has been long clicked (perhaps - * more importantly, that {@link android.widget.AdapterView.OnItemLongClickListener} has - * been triggered). - */ - protected void positionLongClicked(int position) { - setLongClickedPosition(position); - } - - @Override - protected void onCreate(Bundle icicle) { - super.onCreate(icicle); - - // for test stability, turn off title bar - requestWindowFeature(Window.FEATURE_NO_TITLE); - - - mScreenHeight = getWindowManager().getDefaultDisplay().getHeight(); - - final Params params = createParams(); - init(params); - - readAndValidateParams(params); - - - mListView = createListView(); - mListView.setLayoutParams(new ViewGroup.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT)); - mListView.setDrawSelectorOnTop(false); - - for (int i=0; i= 0) { - mListView.setSelection(mStartingSelectionPosition); - } - mListView.setPadding(0, 0, 0, 0); - mListView.setStackFromBottom(mStackFromBottom); - mListView.setDivider(null); - - mListView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { - public void onItemSelected(AdapterView parent, View v, int position, long id) { - positionSelected(position); - } - - public void onNothingSelected(AdapterView parent) { - nothingSelected(); - } - }); - - mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { - public void onItemClick(AdapterView parent, View v, int position, long id) { - positionClicked(position); - } - }); - - // set the fading edge length porportionally to the screen - // height for test stability - if (params.mFadingEdgeScreenSizeFactor != null) { - mListView.setFadingEdgeLength((int) (params.mFadingEdgeScreenSizeFactor * mScreenHeight)); - } else { - mListView.setFadingEdgeLength((int) ((64.0 / 480) * mScreenHeight)); - } - - if (mIncludeHeader) { - mLinearLayout = new LinearLayout(this); - - mHeaderTextView = new TextView(this); - mHeaderTextView.setText("hi"); - mHeaderTextView.setLayoutParams(new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT)); - mLinearLayout.addView(mHeaderTextView); - - mLinearLayout.setOrientation(LinearLayout.VERTICAL); - mLinearLayout.setLayoutParams(new ViewGroup.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT)); - mListView.setLayoutParams((new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - 0, - 1f))); - - mLinearLayout.addView(mListView); - setContentView(mLinearLayout); - } else { - mLinearLayout = new LinearLayout(this); - mLinearLayout.setOrientation(LinearLayout.VERTICAL); - mLinearLayout.setLayoutParams(new ViewGroup.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT)); - mListView.setLayoutParams((new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - 0, - 1f))); - mLinearLayout.addView(mListView); - setContentView(mLinearLayout); - } - } - - /** - * Returns the LinearLayout containing the ListView in this scenario. - * - * @return The LinearLayout in which the ListView is held. - */ - protected LinearLayout getListViewContainer() { - return mLinearLayout; - } - - /** - * Attaches a long press listener. You can find out which views were clicked by calling - * {@link #getLongClickedPosition()}. - */ - public void enableLongPress() { - mListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { - public boolean onItemLongClick(AdapterView parent, View v, int position, long id) { - positionLongClicked(position); - return true; - } - }); - } - - /** - * @return The newly created ListView widget. - */ - protected ListView createListView() { - return new ListView(this); - } - - /** - * @return The newly created Params object. - */ - protected Params createParams() { - return new Params(); - } - - /** - * Sets an adapter on a ListView. - * - * @param listView The ListView to set the adapter on. - */ - protected void setAdapter(ListView listView) { - listView.setAdapter(new MyAdapter()); - } - - /** - * Read in and validate all of the params passed in by the scenario. - * @param params - */ - protected void readAndValidateParams(Params params) { - if (params.mMustFillScreen ) { - double totalFactor = 0.0; - for (int i = 0; i < params.mNumItems; i++) { - if (params.mOverrideItemScreenSizeFactors.containsKey(i)) { - totalFactor += params.mOverrideItemScreenSizeFactors.get(i); - } else { - totalFactor += params.mItemScreenSizeFactor; - } - } - if (totalFactor < 1.0) { - throw new IllegalArgumentException("list items must combine to be at least " + - "the height of the screen. this is not the case with " + params.mNumItems - + " items and " + params.mItemScreenSizeFactor + " screen factor and " + - "screen height of " + mScreenHeight); - } - } - - mNumItems = params.mNumItems; - mItemsFocusable = params.mItemsFocusable; - mStartingSelectionPosition = params.mStartingSelectionPosition; - mItemScreenSizeFactor = params.mItemScreenSizeFactor; - - mOverrideItemScreenSizeFactors.putAll(params.mOverrideItemScreenSizeFactors); - - mUnselectableItems.addAll(params.mUnselectableItems); - mIncludeHeader = params.mIncludeHeader; - mStackFromBottom = params.mStackFromBottom; - mHeaderViewCount = params.mHeaderViewCount; - mHeadersFocusable = params.mHeaderFocusable; - mFooterViewCount = params.mFooterViewCount; - } - - public final String getValueAtPosition(int position) { - return isItemAtPositionSelectable(position) - ? - "position " + position: - "------- " + position; - } - - /** - * @return The height that will be set for a particular position. - */ - public int getHeightForPosition(int position) { - int desiredHeight = (int) (mScreenHeight * mItemScreenSizeFactor); - if (mOverrideItemScreenSizeFactors.containsKey(position)) { - desiredHeight = (int) (mScreenHeight * mOverrideItemScreenSizeFactors.get(position)); - } - return desiredHeight; - } - - - /** - * @return The contents of the header above the list. - * @throws IllegalArgumentException if there is no header. - */ - public final String getHeaderValue() { - if (!mIncludeHeader) { - throw new IllegalArgumentException("no header above list"); - } - return mHeaderTextView.getText().toString(); - } - - /** - * @param value What to put in the header text view - * @throws IllegalArgumentException if there is no header. - */ - protected final void setHeaderValue(String value) { - if (!mIncludeHeader) { - throw new IllegalArgumentException("no header above list"); - } - mHeaderTextView.setText(value); - } - - /** - * Create a view for a list item. Override this to create a custom view beyond - * the simple focusable / unfocusable text view. - * @param position The position. - * @param parent The parent - * @param desiredHeight The height the view should be to respect the desired item - * to screen height ratio. - * @return a view for the list. - */ - protected View createView(int position, ViewGroup parent, int desiredHeight) { - return ListItemFactory.text(position, parent.getContext(), getValueAtPosition(position), - desiredHeight); - } - - /** - * Convert a non-null view. - */ - public View convertView(int position, View convertView, ViewGroup parent) { - return ListItemFactory.convertText(convertView, getValueAtPosition(position), position); - } - - public void setClickedPosition(int clickedPosition) { - mClickedPosition = clickedPosition; - } - - public int getClickedPosition() { - return mClickedPosition; - } - - public void setLongClickedPosition(int longClickedPosition) { - mLongClickedPosition = longClickedPosition; - } - - public int getLongClickedPosition() { - return mLongClickedPosition; - } - - /** - * Have a child of the list view call {@link View#requestRectangleOnScreen(android.graphics.Rect)}. - * @param childIndex The index into the viewgroup children (i.e the children that are - * currently visible). - * @param rect The rectangle, in the child's coordinates. - */ - public void requestRectangleOnScreen(int childIndex, final Rect rect) { - final View child = getListView().getChildAt(childIndex); - - child.post(new Runnable() { - public void run() { - child.requestRectangleOnScreen(rect); - } - }); - } - - /** - * Return an item type for the specified position in the adapter. Override if your - * adapter creates more than one type. - */ - public int getItemViewType(int position) { - return 0; - } - - /** - * Return the number of types created by the adapter. Override if your - * adapter creates more than one type. - */ - public int getViewTypeCount() { - return 1; - } - - /** - * @return The number of times convertView failed - */ - public int getConvertMisses() { - return mConvertMisses; - } - - private class MyAdapter extends BaseAdapter { - - public int getCount() { - return mNumItems; - } - - public Object getItem(int position) { - return getValueAtPosition(position); - } - - public long getItemId(int position) { - return position; - } - - @Override - public boolean areAllItemsEnabled() { - return mUnselectableItems.isEmpty(); - } - - @Override - public boolean isEnabled(int position) { - return isItemAtPositionSelectable(position); - } - - public View getView(int position, View convertView, ViewGroup parent) { - View result = null; - if (position >= mNumItems || position < 0) { - throw new IllegalStateException("position out of range for adapter!"); - } - - if (convertView != null) { - result = convertView(position, convertView, parent); - if (result == null) { - mConvertMisses++; - } - } - - if (result == null) { - int desiredHeight = getHeightForPosition(position); - result = createView(position, parent, desiredHeight); - } - return result; - } - - @Override - public int getItemViewType(int position) { - return ListScenario.this.getItemViewType(position); - } - - @Override - public int getViewTypeCount() { - return ListScenario.this.getViewTypeCount(); - } - - } -} diff --git a/src/main/java/android/util/ListUtil.java b/src/main/java/android/util/ListUtil.java deleted file mode 100644 index 2a7cb96..0000000 --- a/src/main/java/android/util/ListUtil.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import android.app.Instrumentation; -import android.view.KeyEvent; -import android.widget.ListView; - - -/** - * Various useful stuff for instrumentation testing listview. - */ -public class ListUtil { - - - private final ListView mListView; - private final Instrumentation mInstrumentation; - - /** - * @param listView The listview to act on - * @param instrumentation The instrumentation to use. - */ - public ListUtil(ListView listView, Instrumentation instrumentation) { - mListView = listView; - mInstrumentation = instrumentation; - } - - /** - * Set the selected position of the list view. - * @param pos The desired position. - */ - public final void setSelectedPosition(final int pos) { - mListView.post(new Runnable() { - public void run() { - mListView.setSelection(pos); - } - }); - mInstrumentation.waitForIdleSync(); - } - - /** - * Get the top of the list. - */ - public final int getListTop() { - return mListView.getListPaddingTop(); - } - - /** - * Get the bottom of the list. - */ - public final int getListBottom() { - return mListView.getHeight() - mListView.getListPaddingBottom(); - } - - /** - * Arrow (up or down as appropriate) to the desired position in the list. - * @param desiredPos The desired position - * @throws IllegalStateException if the position can't be reached within 20 presses. - */ - public final void arrowScrollToSelectedPosition(int desiredPos) { - if (desiredPos > mListView.getSelectedItemPosition()) { - arrowDownToSelectedPosition(desiredPos); - } else { - arrowUpToSelectedPosition(desiredPos); - } - } - - private void arrowDownToSelectedPosition(int position) { - int maxDowns = 20; - while(mListView.getSelectedItemPosition() < position && --maxDowns > 0) { - mInstrumentation.sendCharacterSync(KeyEvent.KEYCODE_DPAD_DOWN); - } - if (position != mListView.getSelectedItemPosition()) { - throw new IllegalStateException("couldn't get to item after 20 downs"); - } - - } - - private void arrowUpToSelectedPosition(int position) { - int maxUps = 20; - while(mListView.getSelectedItemPosition() > position && --maxUps > 0) { - mInstrumentation.sendCharacterSync(KeyEvent.KEYCODE_DPAD_UP); - } - if (position != mListView.getSelectedItemPosition()) { - throw new IllegalStateException("couldn't get to item after 20 ups"); - } - } - -} diff --git a/src/main/java/android/util/LocalLog.java b/src/main/java/android/util/LocalLog.java deleted file mode 100644 index e49b8c3..0000000 --- a/src/main/java/android/util/LocalLog.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import android.text.format.Time; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.Calendar; -import java.util.Iterator; -import java.util.LinkedList; - -/** - * @hide - */ -public final class LocalLog { - - private LinkedList mLog; - private int mMaxLines; - private long mNow; - - public LocalLog(int maxLines) { - mLog = new LinkedList(); - mMaxLines = maxLines; - } - - public synchronized void log(String msg) { - if (mMaxLines > 0) { - mNow = System.currentTimeMillis(); - StringBuilder sb = new StringBuilder(); - Calendar c = Calendar.getInstance(); - c.setTimeInMillis(mNow); - sb.append(String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c)); - mLog.add(sb.toString() + " - " + msg); - while (mLog.size() > mMaxLines) mLog.remove(); - } - } - - public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - Iterator itr = mLog.listIterator(0); - while (itr.hasNext()) { - pw.println(itr.next()); - } - } -} diff --git a/src/main/java/android/util/Log.java b/src/main/java/android/util/Log.java deleted file mode 100644 index b94e48b..0000000 --- a/src/main/java/android/util/Log.java +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.net.UnknownHostException; - -/** - * Mock Log implementation for testing on non android host. - */ -public final class Log { - - /** - * Priority constant for the println method; use Log.v. - */ - public static final int VERBOSE = 2; - - /** - * Priority constant for the println method; use Log.d. - */ - public static final int DEBUG = 3; - - /** - * Priority constant for the println method; use Log.i. - */ - public static final int INFO = 4; - - /** - * Priority constant for the println method; use Log.w. - */ - public static final int WARN = 5; - - /** - * Priority constant for the println method; use Log.e. - */ - public static final int ERROR = 6; - - /** - * Priority constant for the println method. - */ - public static final int ASSERT = 7; - - private Log() { - } - - /** - * Send a {@link #VERBOSE} log message. - * @param tag Used to identify the source of a log message. It usually identifies - * the class or activity where the log call occurs. - * @param msg The message you would like logged. - */ - public static int v(String tag, String msg) { - return println(LOG_ID_MAIN, VERBOSE, tag, msg); - } - - /** - * Send a {@link #VERBOSE} log message and log the exception. - * @param tag Used to identify the source of a log message. It usually identifies - * the class or activity where the log call occurs. - * @param msg The message you would like logged. - * @param tr An exception to log - */ - public static int v(String tag, String msg, Throwable tr) { - return println(LOG_ID_MAIN, VERBOSE, tag, msg + '\n' + getStackTraceString(tr)); - } - - /** - * Send a {@link #DEBUG} log message. - * @param tag Used to identify the source of a log message. It usually identifies - * the class or activity where the log call occurs. - * @param msg The message you would like logged. - */ - public static int d(String tag, String msg) { - return println(LOG_ID_MAIN, DEBUG, tag, msg); - } - - /** - * Send a {@link #DEBUG} log message and log the exception. - * @param tag Used to identify the source of a log message. It usually identifies - * the class or activity where the log call occurs. - * @param msg The message you would like logged. - * @param tr An exception to log - */ - public static int d(String tag, String msg, Throwable tr) { - return println(LOG_ID_MAIN, DEBUG, tag, msg + '\n' + getStackTraceString(tr)); - } - - /** - * Send an {@link #INFO} log message. - * @param tag Used to identify the source of a log message. It usually identifies - * the class or activity where the log call occurs. - * @param msg The message you would like logged. - */ - public static int i(String tag, String msg) { - return println(LOG_ID_MAIN, INFO, tag, msg); - } - - /** - * Send a {@link #INFO} log message and log the exception. - * @param tag Used to identify the source of a log message. It usually identifies - * the class or activity where the log call occurs. - * @param msg The message you would like logged. - * @param tr An exception to log - */ - public static int i(String tag, String msg, Throwable tr) { - return println(LOG_ID_MAIN, INFO, tag, msg + '\n' + getStackTraceString(tr)); - } - - /** - * Send a {@link #WARN} log message. - * @param tag Used to identify the source of a log message. It usually identifies - * the class or activity where the log call occurs. - * @param msg The message you would like logged. - */ - public static int w(String tag, String msg) { - return println(LOG_ID_MAIN, WARN, tag, msg); - } - - /** - * Send a {@link #WARN} log message and log the exception. - * @param tag Used to identify the source of a log message. It usually identifies - * the class or activity where the log call occurs. - * @param msg The message you would like logged. - * @param tr An exception to log - */ - public static int w(String tag, String msg, Throwable tr) { - return println(LOG_ID_MAIN, WARN, tag, msg + '\n' + getStackTraceString(tr)); - } - - /* - * Send a {@link #WARN} log message and log the exception. - * @param tag Used to identify the source of a log message. It usually identifies - * the class or activity where the log call occurs. - * @param tr An exception to log - */ - public static int w(String tag, Throwable tr) { - return println(LOG_ID_MAIN, WARN, tag, getStackTraceString(tr)); - } - - /** - * Send an {@link #ERROR} log message. - * @param tag Used to identify the source of a log message. It usually identifies - * the class or activity where the log call occurs. - * @param msg The message you would like logged. - */ - public static int e(String tag, String msg) { - return println(LOG_ID_MAIN, ERROR, tag, msg); - } - - /** - * Send a {@link #ERROR} log message and log the exception. - * @param tag Used to identify the source of a log message. It usually identifies - * the class or activity where the log call occurs. - * @param msg The message you would like logged. - * @param tr An exception to log - */ - public static int e(String tag, String msg, Throwable tr) { - return println(LOG_ID_MAIN, ERROR, tag, msg + '\n' + getStackTraceString(tr)); - } - - /** - * Handy function to get a loggable stack trace from a Throwable - * @param tr An exception to log - */ - public static String getStackTraceString(Throwable tr) { - if (tr == null) { - return ""; - } - - // This is to reduce the amount of log spew that apps do in the non-error - // condition of the network being unavailable. - Throwable t = tr; - while (t != null) { - if (t instanceof UnknownHostException) { - return ""; - } - t = t.getCause(); - } - - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - tr.printStackTrace(pw); - pw.flush(); - return sw.toString(); - } - - /** - * Low-level logging call. - * @param priority The priority/type of this log message - * @param tag Used to identify the source of a log message. It usually identifies - * the class or activity where the log call occurs. - * @param msg The message you would like logged. - * @return The number of bytes written. - */ - public static int println(int priority, String tag, String msg) { - return println(LOG_ID_MAIN, priority, tag, msg); - } - - /** @hide */ public static final int LOG_ID_MAIN = 0; - /** @hide */ public static final int LOG_ID_RADIO = 1; - /** @hide */ public static final int LOG_ID_EVENTS = 2; - /** @hide */ public static final int LOG_ID_SYSTEM = 3; - /** @hide */ public static final int LOG_ID_CRASH = 4; - - /** @hide */ @SuppressWarnings("unused") - public static int println(int bufID, - int priority, String tag, String msg) { - return 0; - } -} diff --git a/src/main/java/android/util/LogPrinter.java b/src/main/java/android/util/LogPrinter.java deleted file mode 100644 index 68f64d0..0000000 --- a/src/main/java/android/util/LogPrinter.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -/** - * Implementation of a {@link android.util.Printer} that sends its output - * to the system log. - */ -public class LogPrinter implements Printer { - private final int mPriority; - private final String mTag; - private final int mBuffer; - - /** - * Create a new Printer that sends to the log with the given priority - * and tag. - * - * @param priority The desired log priority: - * {@link android.util.Log#VERBOSE Log.VERBOSE}, - * {@link android.util.Log#DEBUG Log.DEBUG}, - * {@link android.util.Log#INFO Log.INFO}, - * {@link android.util.Log#WARN Log.WARN}, or - * {@link android.util.Log#ERROR Log.ERROR}. - * @param tag A string tag to associate with each printed log statement. - */ - public LogPrinter(int priority, String tag) { - mPriority = priority; - mTag = tag; - mBuffer = Log.LOG_ID_MAIN; - } - - /** - * @hide - * Same as above, but buffer is one of the LOG_ID_ constants from android.util.Log. - */ - public LogPrinter(int priority, String tag, int buffer) { - mPriority = priority; - mTag = tag; - mBuffer = buffer; - } - - public void println(String x) { - Log.println_native(mBuffer, mPriority, mTag, x); - } -} diff --git a/src/main/java/android/util/LogTest.java b/src/main/java/android/util/LogTest.java deleted file mode 100644 index 30c81b0..0000000 --- a/src/main/java/android/util/LogTest.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import junit.framework.Assert; -import junit.framework.TestCase; - -import android.os.SystemProperties; -import android.test.PerformanceTestCase; -import android.test.suitebuilder.annotation.Suppress; -import android.util.Log; - -//This is an empty TestCase. -@Suppress -public class LogTest extends TestCase { - private static final String PROPERTY_TAG = "log.tag.LogTest"; - private static final String LOG_TAG = "LogTest"; - - - // TODO: remove this test once we uncomment out the following test. - public void testLogTestDummy() { - return; - } - - - /* TODO: This test is commented out because we will not be able to set properities. Fix the test. - public void testIsLoggable() { - // First clear any SystemProperty setting for our test key. - SystemProperties.set(PROPERTY_TAG, null); - - String value = SystemProperties.get(PROPERTY_TAG); - Assert.assertTrue(value == null || value.length() == 0); - - // Check to make sure that all levels expect for INFO, WARN, ERROR, and ASSERT are loggable. - Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.VERBOSE)); - Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.DEBUG)); - Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.INFO)); - Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.WARN)); - Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ERROR)); - Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ASSERT)); - - // Set the log level to be VERBOSE for this tag. - SystemProperties.set(PROPERTY_TAG, "VERBOSE"); - - // Test to make sure all log levels >= VERBOSE are loggable. - Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.VERBOSE)); - Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.DEBUG)); - Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.INFO)); - Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.WARN)); - Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ERROR)); - Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ASSERT)); - - // Set the log level to be DEBUG for this tag. - SystemProperties.set(PROPERTY_TAG, "DEBUG"); - - // Test to make sure all log levels >= DEBUG are loggable. - Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.VERBOSE)); - Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.DEBUG)); - Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.INFO)); - Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.WARN)); - Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ERROR)); - Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ASSERT)); - - // Set the log level to be INFO for this tag. - SystemProperties.set(PROPERTY_TAG, "INFO"); - - // Test to make sure all log levels >= INFO are loggable. - Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.VERBOSE)); - Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.DEBUG)); - Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.INFO)); - Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.WARN)); - Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ERROR)); - Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ASSERT)); - - // Set the log level to be WARN for this tag. - SystemProperties.set(PROPERTY_TAG, "WARN"); - - // Test to make sure all log levels >= WARN are loggable. - Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.VERBOSE)); - Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.DEBUG)); - Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.INFO)); - Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.WARN)); - Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ERROR)); - Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ASSERT)); - - // Set the log level to be ERROR for this tag. - SystemProperties.set(PROPERTY_TAG, "ERROR"); - - // Test to make sure all log levels >= ERROR are loggable. - Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.VERBOSE)); - Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.DEBUG)); - Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.INFO)); - Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.WARN)); - Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ERROR)); - Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ASSERT)); - - // Set the log level to be ASSERT for this tag. - SystemProperties.set(PROPERTY_TAG, "ASSERT"); - - // Test to make sure all log levels >= ASSERT are loggable. - Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.VERBOSE)); - Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.DEBUG)); - Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.INFO)); - Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.WARN)); - Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.ERROR)); - Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ASSERT)); - - // Set the log level to be SUPPRESS for this tag. - SystemProperties.set(PROPERTY_TAG, "SUPPRESS"); - - // Test to make sure all log levels >= ASSERT are loggable. - Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.VERBOSE)); - Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.DEBUG)); - Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.INFO)); - Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.WARN)); - Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.ERROR)); - Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.ASSERT)); - } - */ - - public static class PerformanceTest extends TestCase implements PerformanceTestCase { - private static final int ITERATIONS = 1000; - - @Override - public void setUp() { - SystemProperties.set(LOG_TAG, "VERBOSE"); - } - - public boolean isPerformanceOnly() { - return true; - } - - public int startPerformance(PerformanceTestCase.Intermediates intermediates) { - intermediates.setInternalIterations(ITERATIONS * 10); - return 0; - } - - public void testIsLoggable() { - boolean canLog = false; - for (int i = ITERATIONS - 1; i >= 0; i--) { - canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE); - canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE); - canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE); - canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE); - canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE); - canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE); - canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE); - canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE); - canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE); - canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE); - } - } - } -} diff --git a/src/main/java/android/util/LogWriter.java b/src/main/java/android/util/LogWriter.java deleted file mode 100644 index ce30631..0000000 --- a/src/main/java/android/util/LogWriter.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2011 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.util; - -import java.io.Writer; - -/** @hide */ -public class LogWriter extends Writer { - private final int mPriority; - private final String mTag; - private final int mBuffer; - private StringBuilder mBuilder = new StringBuilder(128); - - /** - * Create a new Writer that sends to the log with the given priority - * and tag. - * - * @param priority The desired log priority: - * {@link android.util.Log#VERBOSE Log.VERBOSE}, - * {@link android.util.Log#DEBUG Log.DEBUG}, - * {@link android.util.Log#INFO Log.INFO}, - * {@link android.util.Log#WARN Log.WARN}, or - * {@link android.util.Log#ERROR Log.ERROR}. - * @param tag A string tag to associate with each printed log statement. - */ - public LogWriter(int priority, String tag) { - mPriority = priority; - mTag = tag; - mBuffer = Log.LOG_ID_MAIN; - } - - /** - * @hide - * Same as above, but buffer is one of the LOG_ID_ constants from android.util.Log. - */ - public LogWriter(int priority, String tag, int buffer) { - mPriority = priority; - mTag = tag; - mBuffer = buffer; - } - - @Override public void close() { - flushBuilder(); - } - - @Override public void flush() { - flushBuilder(); - } - - @Override public void write(char[] buf, int offset, int count) { - for(int i = 0; i < count; i++) { - char c = buf[offset + i]; - if ( c == '\n') { - flushBuilder(); - } - else { - mBuilder.append(c); - } - } - } - - private void flushBuilder() { - if (mBuilder.length() > 0) { - Log.println_native(mBuffer, mPriority, mTag, mBuilder.toString()); - mBuilder.delete(0, mBuilder.length()); - } - } -} diff --git a/src/main/java/android/util/Log_Delegate.java b/src/main/java/android/util/Log_Delegate.java deleted file mode 100644 index 7f432ab..0000000 --- a/src/main/java/android/util/Log_Delegate.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2011 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.util; - -import com.android.tools.layoutlib.annotations.LayoutlibDelegate; - -class Log_Delegate { - // to replicate prefix visible when using 'adb logcat' - private static char priorityChar(int priority) { - switch (priority) { - case Log.VERBOSE: - return 'V'; - case Log.DEBUG: - return 'D'; - case Log.INFO: - return 'I'; - case Log.WARN: - return 'W'; - case Log.ERROR: - return 'E'; - case Log.ASSERT: - return 'A'; - default: - return '?'; - } - } - - @LayoutlibDelegate - static int println_native(int bufID, int priority, String tag, String msgs) { - String prefix = priorityChar(priority) + "/" + tag + ": "; - for (String msg: msgs.split("\n")) { - System.out.println(prefix + msg); - } - return 0; - } - -} diff --git a/src/main/java/android/util/LongArray.java b/src/main/java/android/util/LongArray.java deleted file mode 100644 index 54a6882..0000000 --- a/src/main/java/android/util/LongArray.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (C) 2013 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.util; - -import com.android.internal.util.ArrayUtils; -import libcore.util.EmptyArray; - -/** - * Implements a growing array of long primitives. - * - * @hide - */ -public class LongArray implements Cloneable { - private static final int MIN_CAPACITY_INCREMENT = 12; - - private long[] mValues; - private int mSize; - - /** - * Creates an empty LongArray with the default initial capacity. - */ - public LongArray() { - this(10); - } - - /** - * Creates an empty LongArray with the specified initial capacity. - */ - public LongArray(int initialCapacity) { - if (initialCapacity == 0) { - mValues = EmptyArray.LONG; - } else { - mValues = ArrayUtils.newUnpaddedLongArray(initialCapacity); - } - mSize = 0; - } - - /** - * Appends the specified value to the end of this array. - */ - public void add(long value) { - add(mSize, value); - } - - /** - * Inserts a value at the specified position in this array. - * - * @throws IndexOutOfBoundsException when index < 0 || index > size() - */ - public void add(int index, long value) { - if (index < 0 || index > mSize) { - throw new IndexOutOfBoundsException(); - } - - ensureCapacity(1); - - if (mSize - index != 0) { - System.arraycopy(mValues, index, mValues, index + 1, mSize - index); - } - - mValues[index] = value; - mSize++; - } - - /** - * Adds the values in the specified array to this array. - */ - public void addAll(LongArray values) { - final int count = values.mSize; - ensureCapacity(count); - - System.arraycopy(values.mValues, 0, mValues, mSize, count); - mSize += count; - } - - /** - * Ensures capacity to append at least count values. - */ - private void ensureCapacity(int count) { - final int currentSize = mSize; - final int minCapacity = currentSize + count; - if (minCapacity >= mValues.length) { - final int targetCap = currentSize + (currentSize < (MIN_CAPACITY_INCREMENT / 2) ? - MIN_CAPACITY_INCREMENT : currentSize >> 1); - final int newCapacity = targetCap > minCapacity ? targetCap : minCapacity; - final long[] newValues = ArrayUtils.newUnpaddedLongArray(newCapacity); - System.arraycopy(mValues, 0, newValues, 0, currentSize); - mValues = newValues; - } - } - - /** - * Removes all values from this array. - */ - public void clear() { - mSize = 0; - } - - @Override - public LongArray clone() { - LongArray clone = null; - try { - clone = (LongArray) super.clone(); - clone.mValues = mValues.clone(); - } catch (CloneNotSupportedException cnse) { - /* ignore */ - } - return clone; - } - - /** - * Returns the value at the specified position in this array. - */ - public long get(int index) { - if (index >= mSize) { - throw new ArrayIndexOutOfBoundsException(mSize, index); - } - return mValues[index]; - } - - /** - * Returns the index of the first occurrence of the specified value in this - * array, or -1 if this array does not contain the value. - */ - public int indexOf(long value) { - final int n = mSize; - for (int i = 0; i < n; i++) { - if (mValues[i] == value) { - return i; - } - } - return -1; - } - - /** - * Removes the value at the specified index from this array. - */ - public void remove(int index) { - if (index >= mSize) { - throw new ArrayIndexOutOfBoundsException(mSize, index); - } - System.arraycopy(mValues, index + 1, mValues, index, mSize - index - 1); - mSize--; - } - - /** - * Returns the number of values in this array. - */ - public int size() { - return mSize; - } -} diff --git a/src/main/java/android/util/LongSparseArray.java b/src/main/java/android/util/LongSparseArray.java deleted file mode 100644 index 6b45ff4..0000000 --- a/src/main/java/android/util/LongSparseArray.java +++ /dev/null @@ -1,375 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import com.android.internal.util.ArrayUtils; -import com.android.internal.util.GrowingArrayUtils; - -import libcore.util.EmptyArray; - -/** - * SparseArray mapping longs to Objects. Unlike a normal array of Objects, - * there can be gaps in the indices. It is intended to be more memory efficient - * than using a HashMap to map Longs to Objects, both because it avoids - * auto-boxing keys and its data structure doesn't rely on an extra entry object - * for each mapping. - * - *

    Note that this container keeps its mappings in an array data structure, - * using a binary search to find keys. The implementation is not intended to be appropriate for - * data structures - * that may contain large numbers of items. It is generally slower than a traditional - * HashMap, since lookups require a binary search and adds and removes require inserting - * and deleting entries in the array. For containers holding up to hundreds of items, - * the performance difference is not significant, less than 50%.

    - * - *

    To help with performance, the container includes an optimization when removing - * keys: instead of compacting its array immediately, it leaves the removed entry marked - * as deleted. The entry can then be re-used for the same key, or compacted later in - * a single garbage collection step of all removed entries. This garbage collection will - * need to be performed at any time the array needs to be grown or the the map size or - * entry values are retrieved.

    - * - *

    It is possible to iterate over the items in this container using - * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using - * keyAt(int) with ascending values of the index will return the - * keys in ascending order, or the values corresponding to the keys in ascending - * order in the case of valueAt(int).

    - */ -public class LongSparseArray implements Cloneable { - private static final Object DELETED = new Object(); - private boolean mGarbage = false; - - private long[] mKeys; - private Object[] mValues; - private int mSize; - - /** - * Creates a new LongSparseArray containing no mappings. - */ - public LongSparseArray() { - this(10); - } - - /** - * Creates a new LongSparseArray containing no mappings that will not - * require any additional memory allocation to store the specified - * number of mappings. If you supply an initial capacity of 0, the - * sparse array will be initialized with a light-weight representation - * not requiring any additional array allocations. - */ - public LongSparseArray(int initialCapacity) { - if (initialCapacity == 0) { - mKeys = EmptyArray.LONG; - mValues = EmptyArray.OBJECT; - } else { - mKeys = ArrayUtils.newUnpaddedLongArray(initialCapacity); - mValues = ArrayUtils.newUnpaddedObjectArray(initialCapacity); - } - mSize = 0; - } - - @Override - @SuppressWarnings("unchecked") - public LongSparseArray clone() { - LongSparseArray clone = null; - try { - clone = (LongSparseArray) super.clone(); - clone.mKeys = mKeys.clone(); - clone.mValues = mValues.clone(); - } catch (CloneNotSupportedException cnse) { - /* ignore */ - } - return clone; - } - - /** - * Gets the Object mapped from the specified key, or null - * if no such mapping has been made. - */ - public E get(long key) { - return get(key, null); - } - - /** - * Gets the Object mapped from the specified key, or the specified Object - * if no such mapping has been made. - */ - @SuppressWarnings("unchecked") - public E get(long key, E valueIfKeyNotFound) { - int i = ContainerHelpers.binarySearch(mKeys, mSize, key); - - if (i < 0 || mValues[i] == DELETED) { - return valueIfKeyNotFound; - } else { - return (E) mValues[i]; - } - } - - /** - * Removes the mapping from the specified key, if there was any. - */ - public void delete(long key) { - int i = ContainerHelpers.binarySearch(mKeys, mSize, key); - - if (i >= 0) { - if (mValues[i] != DELETED) { - mValues[i] = DELETED; - mGarbage = true; - } - } - } - - /** - * Alias for {@link #delete(long)}. - */ - public void remove(long key) { - delete(key); - } - - /** - * Removes the mapping at the specified index. - */ - public void removeAt(int index) { - if (mValues[index] != DELETED) { - mValues[index] = DELETED; - mGarbage = true; - } - } - - private void gc() { - // Log.e("SparseArray", "gc start with " + mSize); - - int n = mSize; - int o = 0; - long[] keys = mKeys; - Object[] values = mValues; - - for (int i = 0; i < n; i++) { - Object val = values[i]; - - if (val != DELETED) { - if (i != o) { - keys[o] = keys[i]; - values[o] = val; - values[i] = null; - } - - o++; - } - } - - mGarbage = false; - mSize = o; - - // Log.e("SparseArray", "gc end with " + mSize); - } - - /** - * Adds a mapping from the specified key to the specified value, - * replacing the previous mapping from the specified key if there - * was one. - */ - public void put(long key, E value) { - int i = ContainerHelpers.binarySearch(mKeys, mSize, key); - - if (i >= 0) { - mValues[i] = value; - } else { - i = ~i; - - if (i < mSize && mValues[i] == DELETED) { - mKeys[i] = key; - mValues[i] = value; - return; - } - - if (mGarbage && mSize >= mKeys.length) { - gc(); - - // Search again because indices may have changed. - i = ~ContainerHelpers.binarySearch(mKeys, mSize, key); - } - - mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key); - mValues = GrowingArrayUtils.insert(mValues, mSize, i, value); - mSize++; - } - } - - /** - * Returns the number of key-value mappings that this LongSparseArray - * currently stores. - */ - public int size() { - if (mGarbage) { - gc(); - } - - return mSize; - } - - /** - * Given an index in the range 0...size()-1, returns - * the key from the indexth key-value mapping that this - * LongSparseArray stores. - * - *

    The keys corresponding to indices in ascending order are guaranteed to - * be in ascending order, e.g., keyAt(0) will return the - * smallest key and keyAt(size()-1) will return the largest - * key.

    - */ - public long keyAt(int index) { - if (mGarbage) { - gc(); - } - - return mKeys[index]; - } - - /** - * Given an index in the range 0...size()-1, returns - * the value from the indexth key-value mapping that this - * LongSparseArray stores. - * - *

    The values corresponding to indices in ascending order are guaranteed - * to be associated with keys in ascending order, e.g., - * valueAt(0) will return the value associated with the - * smallest key and valueAt(size()-1) will return the value - * associated with the largest key.

    - */ - @SuppressWarnings("unchecked") - public E valueAt(int index) { - if (mGarbage) { - gc(); - } - - return (E) mValues[index]; - } - - /** - * Given an index in the range 0...size()-1, sets a new - * value for the indexth key-value mapping that this - * LongSparseArray stores. - */ - public void setValueAt(int index, E value) { - if (mGarbage) { - gc(); - } - - mValues[index] = value; - } - - /** - * Returns the index for which {@link #keyAt} would return the - * specified key, or a negative number if the specified - * key is not mapped. - */ - public int indexOfKey(long key) { - if (mGarbage) { - gc(); - } - - return ContainerHelpers.binarySearch(mKeys, mSize, key); - } - - /** - * Returns an index for which {@link #valueAt} would return the - * specified key, or a negative number if no keys map to the - * specified value. - * Beware that this is a linear search, unlike lookups by key, - * and that multiple keys can map to the same value and this will - * find only one of them. - */ - public int indexOfValue(E value) { - if (mGarbage) { - gc(); - } - - for (int i = 0; i < mSize; i++) - if (mValues[i] == value) - return i; - - return -1; - } - - /** - * Removes all key-value mappings from this LongSparseArray. - */ - public void clear() { - int n = mSize; - Object[] values = mValues; - - for (int i = 0; i < n; i++) { - values[i] = null; - } - - mSize = 0; - mGarbage = false; - } - - /** - * Puts a key/value pair into the array, optimizing for the case where - * the key is greater than all existing keys in the array. - */ - public void append(long key, E value) { - if (mSize != 0 && key <= mKeys[mSize - 1]) { - put(key, value); - return; - } - - if (mGarbage && mSize >= mKeys.length) { - gc(); - } - - mKeys = GrowingArrayUtils.append(mKeys, mSize, key); - mValues = GrowingArrayUtils.append(mValues, mSize, value); - mSize++; - } - - /** - * {@inheritDoc} - * - *

    This implementation composes a string by iterating over its mappings. If - * this map contains itself as a value, the string "(this Map)" - * will appear in its place. - */ - @Override - public String toString() { - if (size() <= 0) { - return "{}"; - } - - StringBuilder buffer = new StringBuilder(mSize * 28); - buffer.append('{'); - for (int i=0; i 0) { - buffer.append(", "); - } - long key = keyAt(i); - buffer.append(key); - buffer.append('='); - Object value = valueAt(i); - if (value != this) { - buffer.append(value); - } else { - buffer.append("(this Map)"); - } - } - buffer.append('}'); - return buffer.toString(); - } -} diff --git a/src/main/java/android/util/LongSparseLongArray.java b/src/main/java/android/util/LongSparseLongArray.java deleted file mode 100644 index a361457..0000000 --- a/src/main/java/android/util/LongSparseLongArray.java +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import com.android.internal.util.ArrayUtils; -import com.android.internal.util.GrowingArrayUtils; - -import libcore.util.EmptyArray; - -/** - * Map of {@code long} to {@code long}. Unlike a normal array of longs, there - * can be gaps in the indices. It is intended to be more memory efficient than using a - * {@code HashMap}, both because it avoids - * auto-boxing keys and values and its data structure doesn't rely on an extra entry object - * for each mapping. - * - *

    Note that this container keeps its mappings in an array data structure, - * using a binary search to find keys. The implementation is not intended to be appropriate for - * data structures - * that may contain large numbers of items. It is generally slower than a traditional - * HashMap, since lookups require a binary search and adds and removes require inserting - * and deleting entries in the array. For containers holding up to hundreds of items, - * the performance difference is not significant, less than 50%.

    - * - *

    It is possible to iterate over the items in this container using - * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using - * keyAt(int) with ascending values of the index will return the - * keys in ascending order, or the values corresponding to the keys in ascending - * order in the case of valueAt(int).

    - * - * @hide - */ -public class LongSparseLongArray implements Cloneable { - private long[] mKeys; - private long[] mValues; - private int mSize; - - /** - * Creates a new SparseLongArray containing no mappings. - */ - public LongSparseLongArray() { - this(10); - } - - /** - * Creates a new SparseLongArray containing no mappings that will not - * require any additional memory allocation to store the specified - * number of mappings. If you supply an initial capacity of 0, the - * sparse array will be initialized with a light-weight representation - * not requiring any additional array allocations. - */ - public LongSparseLongArray(int initialCapacity) { - if (initialCapacity == 0) { - mKeys = EmptyArray.LONG; - mValues = EmptyArray.LONG; - } else { - mKeys = ArrayUtils.newUnpaddedLongArray(initialCapacity); - mValues = new long[mKeys.length]; - } - mSize = 0; - } - - @Override - public LongSparseLongArray clone() { - LongSparseLongArray clone = null; - try { - clone = (LongSparseLongArray) super.clone(); - clone.mKeys = mKeys.clone(); - clone.mValues = mValues.clone(); - } catch (CloneNotSupportedException cnse) { - /* ignore */ - } - return clone; - } - - /** - * Gets the long mapped from the specified key, or 0 - * if no such mapping has been made. - */ - public long get(long key) { - return get(key, 0); - } - - /** - * Gets the long mapped from the specified key, or the specified value - * if no such mapping has been made. - */ - public long get(long key, long valueIfKeyNotFound) { - int i = ContainerHelpers.binarySearch(mKeys, mSize, key); - - if (i < 0) { - return valueIfKeyNotFound; - } else { - return mValues[i]; - } - } - - /** - * Removes the mapping from the specified key, if there was any. - */ - public void delete(long key) { - int i = ContainerHelpers.binarySearch(mKeys, mSize, key); - - if (i >= 0) { - removeAt(i); - } - } - - /** - * Removes the mapping at the given index. - */ - public void removeAt(int index) { - System.arraycopy(mKeys, index + 1, mKeys, index, mSize - (index + 1)); - System.arraycopy(mValues, index + 1, mValues, index, mSize - (index + 1)); - mSize--; - } - - /** - * Adds a mapping from the specified key to the specified value, - * replacing the previous mapping from the specified key if there - * was one. - */ - public void put(long key, long value) { - int i = ContainerHelpers.binarySearch(mKeys, mSize, key); - - if (i >= 0) { - mValues[i] = value; - } else { - i = ~i; - - mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key); - mValues = GrowingArrayUtils.insert(mValues, mSize, i, value); - mSize++; - } - } - - /** - * Returns the number of key-value mappings that this SparseIntArray - * currently stores. - */ - public int size() { - return mSize; - } - - /** - * Given an index in the range 0...size()-1, returns - * the key from the indexth key-value mapping that this - * SparseLongArray stores. - * - *

    The keys corresponding to indices in ascending order are guaranteed to - * be in ascending order, e.g., keyAt(0) will return the - * smallest key and keyAt(size()-1) will return the largest - * key.

    - */ - public long keyAt(int index) { - return mKeys[index]; - } - - /** - * Given an index in the range 0...size()-1, returns - * the value from the indexth key-value mapping that this - * SparseLongArray stores. - * - *

    The values corresponding to indices in ascending order are guaranteed - * to be associated with keys in ascending order, e.g., - * valueAt(0) will return the value associated with the - * smallest key and valueAt(size()-1) will return the value - * associated with the largest key.

    - */ - public long valueAt(int index) { - return mValues[index]; - } - - /** - * Returns the index for which {@link #keyAt} would return the - * specified key, or a negative number if the specified - * key is not mapped. - */ - public int indexOfKey(long key) { - return ContainerHelpers.binarySearch(mKeys, mSize, key); - } - - /** - * Returns an index for which {@link #valueAt} would return the - * specified key, or a negative number if no keys map to the - * specified value. - * Beware that this is a linear search, unlike lookups by key, - * and that multiple keys can map to the same value and this will - * find only one of them. - */ - public int indexOfValue(long value) { - for (int i = 0; i < mSize; i++) - if (mValues[i] == value) - return i; - - return -1; - } - - /** - * Removes all key-value mappings from this SparseIntArray. - */ - public void clear() { - mSize = 0; - } - - /** - * Puts a key/value pair into the array, optimizing for the case where - * the key is greater than all existing keys in the array. - */ - public void append(long key, long value) { - if (mSize != 0 && key <= mKeys[mSize - 1]) { - put(key, value); - return; - } - - mKeys = GrowingArrayUtils.append(mKeys, mSize, key); - mValues = GrowingArrayUtils.append(mValues, mSize, value); - mSize++; - } - - /** - * {@inheritDoc} - * - *

    This implementation composes a string by iterating over its mappings. - */ - @Override - public String toString() { - if (size() <= 0) { - return "{}"; - } - - StringBuilder buffer = new StringBuilder(mSize * 28); - buffer.append('{'); - for (int i=0; i 0) { - buffer.append(", "); - } - long key = keyAt(i); - buffer.append(key); - buffer.append('='); - long value = valueAt(i); - buffer.append(value); - } - buffer.append('}'); - return buffer.toString(); - } -} diff --git a/src/main/java/android/util/LongSparseLongArrayTest.java b/src/main/java/android/util/LongSparseLongArrayTest.java deleted file mode 100644 index cb468bc..0000000 --- a/src/main/java/android/util/LongSparseLongArrayTest.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import junit.framework.TestCase; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Random; - -/** - * Tests for {@link LongSparseLongArray}. - */ -public class LongSparseLongArrayTest extends TestCase { - private static final String TAG = "LongSparseLongArrayTest"; - - public void testSimplePut() throws Exception { - final LongSparseLongArray array = new LongSparseLongArray(5); - for (int i = 0; i < 48; i++) { - final long value = 1 << i; - array.put(value, value); - } - for (int i = 0; i < 48; i++) { - final long value = 1 << i; - assertEquals(value, array.get(value, -1)); - assertEquals(-1, array.get(-value, -1)); - } - } - - public void testSimplePutBackwards() throws Exception { - final LongSparseLongArray array = new LongSparseLongArray(5); - for (int i = 47; i >= 0; i--) { - final long value = 1 << i; - array.put(value, value); - } - for (int i = 0; i < 48; i++) { - final long value = 1 << i; - assertEquals(value, array.get(value, -1)); - assertEquals(-1, array.get(-value, -1)); - } - } - - public void testMiddleInsert() throws Exception { - final LongSparseLongArray array = new LongSparseLongArray(5); - for (int i = 0; i < 48; i++) { - final long value = 1 << i; - array.put(value, value); - } - final long special = (1 << 24) + 5; - array.put(special, 1024); - for (int i = 0; i < 48; i++) { - final long value = 1 << i; - assertEquals(value, array.get(value, -1)); - assertEquals(-1, array.get(-value, -1)); - } - assertEquals(1024, array.get(special, -1)); - } - - public void testFuzz() throws Exception { - final Random r = new Random(); - - final HashMap map = new HashMap(); - final LongSparseLongArray array = new LongSparseLongArray(r.nextInt(128)); - - for (int i = 0; i < 10240; i++) { - if (r.nextBoolean()) { - final long key = r.nextLong(); - final long value = r.nextLong(); - map.put(key, value); - array.put(key, value); - } - if (r.nextBoolean() && map.size() > 0) { - final int index = r.nextInt(map.size()); - final long key = getKeyAtIndex(map, index); - map.remove(key); - array.delete(key); - } - } - - Log.d(TAG, "verifying a map with " + map.size() + " entries"); - - for (Map.Entry e : map.entrySet()) { - final long key = e.getKey(); - final long value = e.getValue(); - assertEquals(value, array.get(key)); - } - } - - private static E getKeyAtIndex(Map map, int index) { - final Iterator keys = map.keySet().iterator(); - for (int i = 0; i < index; i++) { - keys.next(); - } - return keys.next(); - } -} diff --git a/src/main/java/android/util/LruCache.java b/src/main/java/android/util/LruCache.java deleted file mode 100644 index 5208606..0000000 --- a/src/main/java/android/util/LruCache.java +++ /dev/null @@ -1,391 +0,0 @@ -/* - * Copyright (C) 2011 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.util; - -import java.util.LinkedHashMap; -import java.util.Map; - -/** - * BEGIN LAYOUTLIB CHANGE - * This is a custom version that doesn't use the non standard LinkedHashMap#eldest. - * END LAYOUTLIB CHANGE - * - * A cache that holds strong references to a limited number of values. Each time - * a value is accessed, it is moved to the head of a queue. When a value is - * added to a full cache, the value at the end of that queue is evicted and may - * become eligible for garbage collection. - * - *

    If your cached values hold resources that need to be explicitly released, - * override {@link #entryRemoved}. - * - *

    If a cache miss should be computed on demand for the corresponding keys, - * override {@link #create}. This simplifies the calling code, allowing it to - * assume a value will always be returned, even when there's a cache miss. - * - *

    By default, the cache size is measured in the number of entries. Override - * {@link #sizeOf} to size the cache in different units. For example, this cache - * is limited to 4MiB of bitmaps: - *

       {@code
    - *   int cacheSize = 4 * 1024 * 1024; // 4MiB
    - *   LruCache bitmapCache = new LruCache(cacheSize) {
    - *       protected int sizeOf(String key, Bitmap value) {
    - *           return value.getByteCount();
    - *       }
    - *   }}
    - * - *

    This class is thread-safe. Perform multiple cache operations atomically by - * synchronizing on the cache:

       {@code
    - *   synchronized (cache) {
    - *     if (cache.get(key) == null) {
    - *         cache.put(key, value);
    - *     }
    - *   }}
    - * - *

    This class does not allow null to be used as a key or value. A return - * value of null from {@link #get}, {@link #put} or {@link #remove} is - * unambiguous: the key was not in the cache. - * - *

    This class appeared in Android 3.1 (Honeycomb MR1); it's available as part - * of Android's - * Support Package for earlier releases. - */ -public class LruCache { - private final LinkedHashMap map; - - /** Size of this cache in units. Not necessarily the number of elements. */ - private int size; - private int maxSize; - - private int putCount; - private int createCount; - private int evictionCount; - private int hitCount; - private int missCount; - - /** - * @param maxSize for caches that do not override {@link #sizeOf}, this is - * the maximum number of entries in the cache. For all other caches, - * this is the maximum sum of the sizes of the entries in this cache. - */ - public LruCache(int maxSize) { - if (maxSize <= 0) { - throw new IllegalArgumentException("maxSize <= 0"); - } - this.maxSize = maxSize; - this.map = new LinkedHashMap(0, 0.75f, true); - } - - /** - * Sets the size of the cache. - * @param maxSize The new maximum size. - * - * @hide - */ - public void resize(int maxSize) { - if (maxSize <= 0) { - throw new IllegalArgumentException("maxSize <= 0"); - } - - synchronized (this) { - this.maxSize = maxSize; - } - trimToSize(maxSize); - } - - /** - * Returns the value for {@code key} if it exists in the cache or can be - * created by {@code #create}. If a value was returned, it is moved to the - * head of the queue. This returns null if a value is not cached and cannot - * be created. - */ - public final V get(K key) { - if (key == null) { - throw new NullPointerException("key == null"); - } - - V mapValue; - synchronized (this) { - mapValue = map.get(key); - if (mapValue != null) { - hitCount++; - return mapValue; - } - missCount++; - } - - /* - * Attempt to create a value. This may take a long time, and the map - * may be different when create() returns. If a conflicting value was - * added to the map while create() was working, we leave that value in - * the map and release the created value. - */ - - V createdValue = create(key); - if (createdValue == null) { - return null; - } - - synchronized (this) { - createCount++; - mapValue = map.put(key, createdValue); - - if (mapValue != null) { - // There was a conflict so undo that last put - map.put(key, mapValue); - } else { - size += safeSizeOf(key, createdValue); - } - } - - if (mapValue != null) { - entryRemoved(false, key, createdValue, mapValue); - return mapValue; - } else { - trimToSize(maxSize); - return createdValue; - } - } - - /** - * Caches {@code value} for {@code key}. The value is moved to the head of - * the queue. - * - * @return the previous value mapped by {@code key}. - */ - public final V put(K key, V value) { - if (key == null || value == null) { - throw new NullPointerException("key == null || value == null"); - } - - V previous; - synchronized (this) { - putCount++; - size += safeSizeOf(key, value); - previous = map.put(key, value); - if (previous != null) { - size -= safeSizeOf(key, previous); - } - } - - if (previous != null) { - entryRemoved(false, key, previous, value); - } - - trimToSize(maxSize); - return previous; - } - - /** - * @param maxSize the maximum size of the cache before returning. May be -1 - * to evict even 0-sized elements. - */ - private void trimToSize(int maxSize) { - while (true) { - K key; - V value; - synchronized (this) { - if (size < 0 || (map.isEmpty() && size != 0)) { - throw new IllegalStateException(getClass().getName() - + ".sizeOf() is reporting inconsistent results!"); - } - - if (size <= maxSize) { - break; - } - - // BEGIN LAYOUTLIB CHANGE - // get the last item in the linked list. - // This is not efficient, the goal here is to minimize the changes - // compared to the platform version. - Map.Entry toEvict = null; - for (Map.Entry entry : map.entrySet()) { - toEvict = entry; - } - // END LAYOUTLIB CHANGE - - if (toEvict == null) { - break; - } - - key = toEvict.getKey(); - value = toEvict.getValue(); - map.remove(key); - size -= safeSizeOf(key, value); - evictionCount++; - } - - entryRemoved(true, key, value, null); - } - } - - /** - * Removes the entry for {@code key} if it exists. - * - * @return the previous value mapped by {@code key}. - */ - public final V remove(K key) { - if (key == null) { - throw new NullPointerException("key == null"); - } - - V previous; - synchronized (this) { - previous = map.remove(key); - if (previous != null) { - size -= safeSizeOf(key, previous); - } - } - - if (previous != null) { - entryRemoved(false, key, previous, null); - } - - return previous; - } - - /** - * Called for entries that have been evicted or removed. This method is - * invoked when a value is evicted to make space, removed by a call to - * {@link #remove}, or replaced by a call to {@link #put}. The default - * implementation does nothing. - * - *

    The method is called without synchronization: other threads may - * access the cache while this method is executing. - * - * @param evicted true if the entry is being removed to make space, false - * if the removal was caused by a {@link #put} or {@link #remove}. - * @param newValue the new value for {@code key}, if it exists. If non-null, - * this removal was caused by a {@link #put}. Otherwise it was caused by - * an eviction or a {@link #remove}. - */ - protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {} - - /** - * Called after a cache miss to compute a value for the corresponding key. - * Returns the computed value or null if no value can be computed. The - * default implementation returns null. - * - *

    The method is called without synchronization: other threads may - * access the cache while this method is executing. - * - *

    If a value for {@code key} exists in the cache when this method - * returns, the created value will be released with {@link #entryRemoved} - * and discarded. This can occur when multiple threads request the same key - * at the same time (causing multiple values to be created), or when one - * thread calls {@link #put} while another is creating a value for the same - * key. - */ - protected V create(K key) { - return null; - } - - private int safeSizeOf(K key, V value) { - int result = sizeOf(key, value); - if (result < 0) { - throw new IllegalStateException("Negative size: " + key + "=" + value); - } - return result; - } - - /** - * Returns the size of the entry for {@code key} and {@code value} in - * user-defined units. The default implementation returns 1 so that size - * is the number of entries and max size is the maximum number of entries. - * - *

    An entry's size must not change while it is in the cache. - */ - protected int sizeOf(K key, V value) { - return 1; - } - - /** - * Clear the cache, calling {@link #entryRemoved} on each removed entry. - */ - public final void evictAll() { - trimToSize(-1); // -1 will evict 0-sized elements - } - - /** - * For caches that do not override {@link #sizeOf}, this returns the number - * of entries in the cache. For all other caches, this returns the sum of - * the sizes of the entries in this cache. - */ - public synchronized final int size() { - return size; - } - - /** - * For caches that do not override {@link #sizeOf}, this returns the maximum - * number of entries in the cache. For all other caches, this returns the - * maximum sum of the sizes of the entries in this cache. - */ - public synchronized final int maxSize() { - return maxSize; - } - - /** - * Returns the number of times {@link #get} returned a value that was - * already present in the cache. - */ - public synchronized final int hitCount() { - return hitCount; - } - - /** - * Returns the number of times {@link #get} returned null or required a new - * value to be created. - */ - public synchronized final int missCount() { - return missCount; - } - - /** - * Returns the number of times {@link #create(Object)} returned a value. - */ - public synchronized final int createCount() { - return createCount; - } - - /** - * Returns the number of times {@link #put} was called. - */ - public synchronized final int putCount() { - return putCount; - } - - /** - * Returns the number of values that have been evicted. - */ - public synchronized final int evictionCount() { - return evictionCount; - } - - /** - * Returns a copy of the current contents of the cache, ordered from least - * recently accessed to most recently accessed. - */ - public synchronized final Map snapshot() { - return new LinkedHashMap(map); - } - - @Override public synchronized final String toString() { - int accesses = hitCount + missCount; - int hitPercent = accesses != 0 ? (100 * hitCount / accesses) : 0; - return String.format("LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]", - maxSize, hitCount, missCount, hitPercent); - } -} diff --git a/src/main/java/android/util/LruCacheTest.java b/src/main/java/android/util/LruCacheTest.java deleted file mode 100644 index 5a97158..0000000 --- a/src/main/java/android/util/LruCacheTest.java +++ /dev/null @@ -1,504 +0,0 @@ -/* - * Copyright (C) 2011 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.util; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import junit.framework.TestCase; - -public final class LruCacheTest extends TestCase { - private int expectedCreateCount; - private int expectedPutCount; - private int expectedHitCount; - private int expectedMissCount; - private int expectedEvictionCount; - - public void testStatistics() { - LruCache cache = new LruCache(3); - assertStatistics(cache); - - assertEquals(null, cache.put("a", "A")); - expectedPutCount++; - assertStatistics(cache); - assertHit(cache, "a", "A"); - assertSnapshot(cache, "a", "A"); - - assertEquals(null, cache.put("b", "B")); - expectedPutCount++; - assertStatistics(cache); - assertHit(cache, "a", "A"); - assertHit(cache, "b", "B"); - assertSnapshot(cache, "a", "A", "b", "B"); - - assertEquals(null, cache.put("c", "C")); - expectedPutCount++; - assertStatistics(cache); - assertHit(cache, "a", "A"); - assertHit(cache, "b", "B"); - assertHit(cache, "c", "C"); - assertSnapshot(cache, "a", "A", "b", "B", "c", "C"); - - assertEquals(null, cache.put("d", "D")); - expectedPutCount++; - expectedEvictionCount++; // a should have been evicted - assertStatistics(cache); - assertMiss(cache, "a"); - assertHit(cache, "b", "B"); - assertHit(cache, "c", "C"); - assertHit(cache, "d", "D"); - assertHit(cache, "b", "B"); - assertHit(cache, "c", "C"); - assertSnapshot(cache, "d", "D", "b", "B", "c", "C"); - - assertEquals(null, cache.put("e", "E")); - expectedPutCount++; - expectedEvictionCount++; // d should have been evicted - assertStatistics(cache); - assertMiss(cache, "d"); - assertMiss(cache, "a"); - assertHit(cache, "e", "E"); - assertHit(cache, "b", "B"); - assertHit(cache, "c", "C"); - assertSnapshot(cache, "e", "E", "b", "B", "c", "C"); - } - - public void testStatisticsWithCreate() { - LruCache cache = newCreatingCache(); - assertStatistics(cache); - - assertCreated(cache, "aa", "created-aa"); - assertHit(cache, "aa", "created-aa"); - assertSnapshot(cache, "aa", "created-aa"); - - assertCreated(cache, "bb", "created-bb"); - assertMiss(cache, "c"); - assertSnapshot(cache, "aa", "created-aa", "bb", "created-bb"); - - assertCreated(cache, "cc", "created-cc"); - assertSnapshot(cache, "aa", "created-aa", "bb", "created-bb", "cc", "created-cc"); - - expectedEvictionCount++; // aa will be evicted - assertCreated(cache, "dd", "created-dd"); - assertSnapshot(cache, "bb", "created-bb", "cc", "created-cc", "dd", "created-dd"); - - expectedEvictionCount++; // bb will be evicted - assertCreated(cache, "aa", "created-aa"); - assertSnapshot(cache, "cc", "created-cc", "dd", "created-dd", "aa", "created-aa"); - } - - public void testCreateOnCacheMiss() { - LruCache cache = newCreatingCache(); - String created = cache.get("aa"); - assertEquals("created-aa", created); - } - - public void testNoCreateOnCacheHit() { - LruCache cache = newCreatingCache(); - cache.put("aa", "put-aa"); - assertEquals("put-aa", cache.get("aa")); - } - - public void testConstructorDoesNotAllowZeroCacheSize() { - try { - new LruCache(0); - fail(); - } catch (IllegalArgumentException expected) { - } - } - - public void testCannotPutNullKey() { - LruCache cache = new LruCache(3); - try { - cache.put(null, "A"); - fail(); - } catch (NullPointerException expected) { - } - } - - public void testCannotPutNullValue() { - LruCache cache = new LruCache(3); - try { - cache.put("a", null); - fail(); - } catch (NullPointerException expected) { - } - } - - public void testToString() { - LruCache cache = new LruCache(3); - assertEquals("LruCache[maxSize=3,hits=0,misses=0,hitRate=0%]", cache.toString()); - - cache.put("a", "A"); - cache.put("b", "B"); - cache.put("c", "C"); - cache.put("d", "D"); - - cache.get("a"); // miss - cache.get("b"); // hit - cache.get("c"); // hit - cache.get("d"); // hit - cache.get("e"); // miss - - assertEquals("LruCache[maxSize=3,hits=3,misses=2,hitRate=60%]", cache.toString()); - } - - public void testEvictionWithSingletonCache() { - LruCache cache = new LruCache(1); - cache.put("a", "A"); - cache.put("b", "B"); - assertSnapshot(cache, "b", "B"); - } - - public void testEntryEvictedWhenFull() { - List log = new ArrayList(); - LruCache cache = newRemovalLogCache(log); - - cache.put("a", "A"); - cache.put("b", "B"); - cache.put("c", "C"); - assertEquals(Collections.emptyList(), log); - - cache.put("d", "D"); - assertEquals(Arrays.asList("a=A"), log); - } - - /** - * Replacing the value for a key doesn't cause an eviction but it does bring - * the replaced entry to the front of the queue. - */ - public void testPutCauseEviction() { - List log = new ArrayList(); - LruCache cache = newRemovalLogCache(log); - - cache.put("a", "A"); - cache.put("b", "B"); - cache.put("c", "C"); - cache.put("b", "B2"); - assertEquals(Arrays.asList("b=B>B2"), log); - assertSnapshot(cache, "a", "A", "c", "C", "b", "B2"); - } - - public void testCustomSizesImpactsSize() { - LruCache cache = new LruCache(10) { - @Override protected int sizeOf(String key, String value) { - return key.length() + value.length(); - } - }; - - assertEquals(0, cache.size()); - cache.put("a", "AA"); - assertEquals(3, cache.size()); - cache.put("b", "BBBB"); - assertEquals(8, cache.size()); - cache.put("a", ""); - assertEquals(6, cache.size()); - } - - public void testEvictionWithCustomSizes() { - LruCache cache = new LruCache(4) { - @Override protected int sizeOf(String key, String value) { - return value.length(); - } - }; - - cache.put("a", "AAAA"); - assertSnapshot(cache, "a", "AAAA"); - cache.put("b", "BBBB"); // should evict a - assertSnapshot(cache, "b", "BBBB"); - cache.put("c", "CC"); // should evict b - assertSnapshot(cache, "c", "CC"); - cache.put("d", "DD"); - assertSnapshot(cache, "c", "CC", "d", "DD"); - cache.put("e", "E"); // should evict c - assertSnapshot(cache, "d", "DD", "e", "E"); - cache.put("f", "F"); - assertSnapshot(cache, "d", "DD", "e", "E", "f", "F"); - cache.put("g", "G"); // should evict d - assertSnapshot(cache, "e", "E", "f", "F", "g", "G"); - cache.put("h", "H"); - assertSnapshot(cache, "e", "E", "f", "F", "g", "G", "h", "H"); - cache.put("i", "III"); // should evict e, f, and g - assertSnapshot(cache, "h", "H", "i", "III"); - cache.put("j", "JJJ"); // should evict h and i - assertSnapshot(cache, "j", "JJJ"); - } - - public void testEvictionThrowsWhenSizesAreInconsistent() { - LruCache cache = new LruCache(4) { - @Override protected int sizeOf(String key, int[] value) { - return value[0]; - } - }; - - int[] a = { 4 }; - cache.put("a", a); - - // get the cache size out of sync - a[0] = 1; - assertEquals(4, cache.size()); - - // evict something - try { - cache.put("b", new int[] { 2 }); - fail(); - } catch (IllegalStateException expected) { - } - } - - public void testEvictionThrowsWhenSizesAreNegative() { - LruCache cache = new LruCache(4) { - @Override protected int sizeOf(String key, String value) { - return -1; - } - }; - - try { - cache.put("a", "A"); - fail(); - } catch (IllegalStateException expected) { - } - } - - /** - * Naive caches evict at most one element at a time. This is problematic - * because evicting a small element may be insufficient to make room for a - * large element. - */ - public void testDifferentElementSizes() { - LruCache cache = new LruCache(10) { - @Override protected int sizeOf(String key, String value) { - return value.length(); - } - }; - - cache.put("a", "1"); - cache.put("b", "12345678"); - cache.put("c", "1"); - assertSnapshot(cache, "a", "1", "b", "12345678", "c", "1"); - cache.put("d", "12345678"); // should evict a and b - assertSnapshot(cache, "c", "1", "d", "12345678"); - cache.put("e", "12345678"); // should evict c and d - assertSnapshot(cache, "e", "12345678"); - } - - public void testEvictAll() { - List log = new ArrayList(); - LruCache cache = newRemovalLogCache(log); - cache.put("a", "A"); - cache.put("b", "B"); - cache.put("c", "C"); - cache.evictAll(); - assertEquals(0, cache.size()); - assertEquals(Arrays.asList("a=A", "b=B", "c=C"), log); - } - - public void testEvictAllEvictsSizeZeroElements() { - LruCache cache = new LruCache(10) { - @Override protected int sizeOf(String key, String value) { - return 0; - } - }; - - cache.put("a", "A"); - cache.put("b", "B"); - cache.evictAll(); - assertSnapshot(cache); - } - - public void testRemoveWithCustomSizes() { - LruCache cache = new LruCache(10) { - @Override protected int sizeOf(String key, String value) { - return value.length(); - } - }; - cache.put("a", "123456"); - cache.put("b", "1234"); - cache.remove("a"); - assertEquals(4, cache.size()); - } - - public void testRemoveAbsentElement() { - LruCache cache = new LruCache(10); - cache.put("a", "A"); - cache.put("b", "B"); - assertEquals(null, cache.remove("c")); - assertEquals(2, cache.size()); - } - - public void testRemoveNullThrows() { - LruCache cache = new LruCache(10); - try { - cache.remove(null); - fail(); - } catch (NullPointerException expected) { - } - } - - public void testRemoveCallsEntryRemoved() { - List log = new ArrayList(); - LruCache cache = newRemovalLogCache(log); - cache.put("a", "A"); - cache.remove("a"); - assertEquals(Arrays.asList("a=A>null"), log); - } - - public void testPutCallsEntryRemoved() { - List log = new ArrayList(); - LruCache cache = newRemovalLogCache(log); - cache.put("a", "A"); - cache.put("a", "A2"); - assertEquals(Arrays.asList("a=A>A2"), log); - } - - public void testEntryRemovedIsCalledWithoutSynchronization() { - LruCache cache = new LruCache(3) { - @Override protected void entryRemoved( - boolean evicted, String key, String oldValue, String newValue) { - assertFalse(Thread.holdsLock(this)); - } - }; - - cache.put("a", "A"); - cache.put("a", "A2"); // replaced - cache.put("b", "B"); - cache.put("c", "C"); - cache.put("d", "D"); // single eviction - cache.remove("a"); // removed - cache.evictAll(); // multiple eviction - } - - public void testCreateIsCalledWithoutSynchronization() { - LruCache cache = new LruCache(3) { - @Override protected String create(String key) { - assertFalse(Thread.holdsLock(this)); - return null; - } - }; - - cache.get("a"); - } - - /** - * Test what happens when a value is added to the map while create is - * working. The map value should be returned by get(), and the created value - * should be released with entryRemoved(). - */ - public void testCreateWithConcurrentPut() { - final List log = new ArrayList(); - LruCache cache = new LruCache(3) { - @Override protected String create(String key) { - put(key, "B"); - return "A"; - } - @Override protected void entryRemoved( - boolean evicted, String key, String oldValue, String newValue) { - log.add(key + "=" + oldValue + ">" + newValue); - } - }; - - assertEquals("B", cache.get("a")); - assertEquals(Arrays.asList("a=A>B"), log); - } - - /** - * Test what happens when two creates happen concurrently. The result from - * the first create to return is returned by both gets. The other created - * values should be released with entryRemove(). - */ - public void testCreateWithConcurrentCreate() { - final List log = new ArrayList(); - LruCache cache = new LruCache(3) { - int callCount = 0; - @Override protected Integer create(String key) { - if (callCount++ == 0) { - assertEquals(2, get(key).intValue()); - return 1; - } else { - return 2; - } - } - @Override protected void entryRemoved( - boolean evicted, String key, Integer oldValue, Integer newValue) { - log.add(key + "=" + oldValue + ">" + newValue); - } - }; - - assertEquals(2, cache.get("a").intValue()); - assertEquals(Arrays.asList("a=1>2"), log); - } - - private LruCache newCreatingCache() { - return new LruCache(3) { - @Override protected String create(String key) { - return (key.length() > 1) ? ("created-" + key) : null; - } - }; - } - - private LruCache newRemovalLogCache(final List log) { - return new LruCache(3) { - @Override protected void entryRemoved( - boolean evicted, String key, String oldValue, String newValue) { - String message = evicted - ? (key + "=" + oldValue) - : (key + "=" + oldValue + ">" + newValue); - log.add(message); - } - }; - } - - private void assertHit(LruCache cache, String key, String value) { - assertEquals(value, cache.get(key)); - expectedHitCount++; - assertStatistics(cache); - } - - private void assertMiss(LruCache cache, String key) { - assertEquals(null, cache.get(key)); - expectedMissCount++; - assertStatistics(cache); - } - - private void assertCreated(LruCache cache, String key, String value) { - assertEquals(value, cache.get(key)); - expectedMissCount++; - expectedCreateCount++; - assertStatistics(cache); - } - - private void assertStatistics(LruCache cache) { - assertEquals("create count", expectedCreateCount, cache.createCount()); - assertEquals("put count", expectedPutCount, cache.putCount()); - assertEquals("hit count", expectedHitCount, cache.hitCount()); - assertEquals("miss count", expectedMissCount, cache.missCount()); - assertEquals("eviction count", expectedEvictionCount, cache.evictionCount()); - } - - private void assertSnapshot(LruCache cache, T... keysAndValues) { - List actualKeysAndValues = new ArrayList(); - for (Map.Entry entry : cache.snapshot().entrySet()) { - actualKeysAndValues.add(entry.getKey()); - actualKeysAndValues.add(entry.getValue()); - } - - // assert using lists because order is important for LRUs - assertEquals(Arrays.asList(keysAndValues), actualKeysAndValues); - } -} diff --git a/src/main/java/android/util/MalformedJsonException.java b/src/main/java/android/util/MalformedJsonException.java deleted file mode 100644 index 63c19ff..0000000 --- a/src/main/java/android/util/MalformedJsonException.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2011 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.util; - -import java.io.IOException; - -/** - * Thrown when a reader encounters malformed JSON. Some syntax errors can be - * ignored by calling {@link JsonReader#setLenient(boolean)}. - */ -public final class MalformedJsonException extends IOException { - private static final long serialVersionUID = 1L; - - public MalformedJsonException(String message) { - super(message); - } -} diff --git a/src/main/java/android/util/MapCollections.java b/src/main/java/android/util/MapCollections.java deleted file mode 100644 index 28b788b..0000000 --- a/src/main/java/android/util/MapCollections.java +++ /dev/null @@ -1,559 +0,0 @@ -/* - * Copyright (C) 2013 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.util; - -import libcore.util.Objects; - -import java.lang.reflect.Array; -import java.util.Collection; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - -/** - * Helper for writing standard Java collection interfaces to a data - * structure like {@link ArrayMap}. - * @hide - */ -abstract class MapCollections { - EntrySet mEntrySet; - KeySet mKeySet; - ValuesCollection mValues; - - final class ArrayIterator implements Iterator { - final int mOffset; - int mSize; - int mIndex; - boolean mCanRemove = false; - - ArrayIterator(int offset) { - mOffset = offset; - mSize = colGetSize(); - } - - @Override - public boolean hasNext() { - return mIndex < mSize; - } - - @Override - public T next() { - Object res = colGetEntry(mIndex, mOffset); - mIndex++; - mCanRemove = true; - return (T)res; - } - - @Override - public void remove() { - if (!mCanRemove) { - throw new IllegalStateException(); - } - mIndex--; - mSize--; - mCanRemove = false; - colRemoveAt(mIndex); - } - } - - final class MapIterator implements Iterator>, Map.Entry { - int mEnd; - int mIndex; - boolean mEntryValid = false; - - MapIterator() { - mEnd = colGetSize() - 1; - mIndex = -1; - } - - @Override - public boolean hasNext() { - return mIndex < mEnd; - } - - @Override - public Map.Entry next() { - mIndex++; - mEntryValid = true; - return this; - } - - @Override - public void remove() { - if (!mEntryValid) { - throw new IllegalStateException(); - } - colRemoveAt(mIndex); - mIndex--; - mEnd--; - mEntryValid = false; - } - - @Override - public K getKey() { - if (!mEntryValid) { - throw new IllegalStateException( - "This container does not support retaining Map.Entry objects"); - } - return (K)colGetEntry(mIndex, 0); - } - - @Override - public V getValue() { - if (!mEntryValid) { - throw new IllegalStateException( - "This container does not support retaining Map.Entry objects"); - } - return (V)colGetEntry(mIndex, 1); - } - - @Override - public V setValue(V object) { - if (!mEntryValid) { - throw new IllegalStateException( - "This container does not support retaining Map.Entry objects"); - } - return colSetValue(mIndex, object); - } - - @Override - public final boolean equals(Object o) { - if (!mEntryValid) { - throw new IllegalStateException( - "This container does not support retaining Map.Entry objects"); - } - if (!(o instanceof Map.Entry)) { - return false; - } - Map.Entry e = (Map.Entry) o; - return Objects.equal(e.getKey(), colGetEntry(mIndex, 0)) - && Objects.equal(e.getValue(), colGetEntry(mIndex, 1)); - } - - @Override - public final int hashCode() { - if (!mEntryValid) { - throw new IllegalStateException( - "This container does not support retaining Map.Entry objects"); - } - final Object key = colGetEntry(mIndex, 0); - final Object value = colGetEntry(mIndex, 1); - return (key == null ? 0 : key.hashCode()) ^ - (value == null ? 0 : value.hashCode()); - } - - @Override - public final String toString() { - return getKey() + "=" + getValue(); - } - } - - final class EntrySet implements Set> { - @Override - public boolean add(Map.Entry object) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean addAll(Collection> collection) { - int oldSize = colGetSize(); - for (Map.Entry entry : collection) { - colPut(entry.getKey(), entry.getValue()); - } - return oldSize != colGetSize(); - } - - @Override - public void clear() { - colClear(); - } - - @Override - public boolean contains(Object o) { - if (!(o instanceof Map.Entry)) - return false; - Map.Entry e = (Map.Entry) o; - int index = colIndexOfKey(e.getKey()); - if (index < 0) { - return false; - } - Object foundVal = colGetEntry(index, 1); - return Objects.equal(foundVal, e.getValue()); - } - - @Override - public boolean containsAll(Collection collection) { - Iterator it = collection.iterator(); - while (it.hasNext()) { - if (!contains(it.next())) { - return false; - } - } - return true; - } - - @Override - public boolean isEmpty() { - return colGetSize() == 0; - } - - @Override - public Iterator> iterator() { - return new MapIterator(); - } - - @Override - public boolean remove(Object object) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean removeAll(Collection collection) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean retainAll(Collection collection) { - throw new UnsupportedOperationException(); - } - - @Override - public int size() { - return colGetSize(); - } - - @Override - public Object[] toArray() { - throw new UnsupportedOperationException(); - } - - @Override - public T[] toArray(T[] array) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean equals(Object object) { - return equalsSetHelper(this, object); - } - - @Override - public int hashCode() { - int result = 0; - for (int i=colGetSize()-1; i>=0; i--) { - final Object key = colGetEntry(i, 0); - final Object value = colGetEntry(i, 1); - result += ( (key == null ? 0 : key.hashCode()) ^ - (value == null ? 0 : value.hashCode()) ); - } - return result; - } - }; - - final class KeySet implements Set { - - @Override - public boolean add(K object) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean addAll(Collection collection) { - throw new UnsupportedOperationException(); - } - - @Override - public void clear() { - colClear(); - } - - @Override - public boolean contains(Object object) { - return colIndexOfKey(object) >= 0; - } - - @Override - public boolean containsAll(Collection collection) { - return containsAllHelper(colGetMap(), collection); - } - - @Override - public boolean isEmpty() { - return colGetSize() == 0; - } - - @Override - public Iterator iterator() { - return new ArrayIterator(0); - } - - @Override - public boolean remove(Object object) { - int index = colIndexOfKey(object); - if (index >= 0) { - colRemoveAt(index); - return true; - } - return false; - } - - @Override - public boolean removeAll(Collection collection) { - return removeAllHelper(colGetMap(), collection); - } - - @Override - public boolean retainAll(Collection collection) { - return retainAllHelper(colGetMap(), collection); - } - - @Override - public int size() { - return colGetSize(); - } - - @Override - public Object[] toArray() { - return toArrayHelper(0); - } - - @Override - public T[] toArray(T[] array) { - return toArrayHelper(array, 0); - } - - @Override - public boolean equals(Object object) { - return equalsSetHelper(this, object); - } - - @Override - public int hashCode() { - int result = 0; - for (int i=colGetSize()-1; i>=0; i--) { - Object obj = colGetEntry(i, 0); - result += obj == null ? 0 : obj.hashCode(); - } - return result; - } - }; - - final class ValuesCollection implements Collection { - - @Override - public boolean add(V object) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean addAll(Collection collection) { - throw new UnsupportedOperationException(); - } - - @Override - public void clear() { - colClear(); - } - - @Override - public boolean contains(Object object) { - return colIndexOfValue(object) >= 0; - } - - @Override - public boolean containsAll(Collection collection) { - Iterator it = collection.iterator(); - while (it.hasNext()) { - if (!contains(it.next())) { - return false; - } - } - return true; - } - - @Override - public boolean isEmpty() { - return colGetSize() == 0; - } - - @Override - public Iterator iterator() { - return new ArrayIterator(1); - } - - @Override - public boolean remove(Object object) { - int index = colIndexOfValue(object); - if (index >= 0) { - colRemoveAt(index); - return true; - } - return false; - } - - @Override - public boolean removeAll(Collection collection) { - int N = colGetSize(); - boolean changed = false; - for (int i=0; i collection) { - int N = colGetSize(); - boolean changed = false; - for (int i=0; i T[] toArray(T[] array) { - return toArrayHelper(array, 1); - } - }; - - public static boolean containsAllHelper(Map map, Collection collection) { - Iterator it = collection.iterator(); - while (it.hasNext()) { - if (!map.containsKey(it.next())) { - return false; - } - } - return true; - } - - public static boolean removeAllHelper(Map map, Collection collection) { - int oldSize = map.size(); - Iterator it = collection.iterator(); - while (it.hasNext()) { - map.remove(it.next()); - } - return oldSize != map.size(); - } - - public static boolean retainAllHelper(Map map, Collection collection) { - int oldSize = map.size(); - Iterator it = map.keySet().iterator(); - while (it.hasNext()) { - if (!collection.contains(it.next())) { - it.remove(); - } - } - return oldSize != map.size(); - } - - public Object[] toArrayHelper(int offset) { - final int N = colGetSize(); - Object[] result = new Object[N]; - for (int i=0; i T[] toArrayHelper(T[] array, int offset) { - final int N = colGetSize(); - if (array.length < N) { - @SuppressWarnings("unchecked") T[] newArray - = (T[]) Array.newInstance(array.getClass().getComponentType(), N); - array = newArray; - } - for (int i=0; i N) { - array[N] = null; - } - return array; - } - - public static boolean equalsSetHelper(Set set, Object object) { - if (set == object) { - return true; - } - if (object instanceof Set) { - Set s = (Set) object; - - try { - return set.size() == s.size() && set.containsAll(s); - } catch (NullPointerException ignored) { - return false; - } catch (ClassCastException ignored) { - return false; - } - } - return false; - } - - public Set> getEntrySet() { - if (mEntrySet == null) { - mEntrySet = new EntrySet(); - } - return mEntrySet; - } - - public Set getKeySet() { - if (mKeySet == null) { - mKeySet = new KeySet(); - } - return mKeySet; - } - - public Collection getValues() { - if (mValues == null) { - mValues = new ValuesCollection(); - } - return mValues; - } - - protected abstract int colGetSize(); - protected abstract Object colGetEntry(int index, int offset); - protected abstract int colIndexOfKey(Object key); - protected abstract int colIndexOfValue(Object key); - protected abstract Map colGetMap(); - protected abstract void colPut(K key, V value); - protected abstract V colSetValue(int index, V value); - protected abstract void colRemoveAt(int index); - protected abstract void colClear(); -} diff --git a/src/main/java/android/util/MathUtils.java b/src/main/java/android/util/MathUtils.java deleted file mode 100644 index 13a692e..0000000 --- a/src/main/java/android/util/MathUtils.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import java.util.Random; - -/** - * A class that contains utility methods related to numbers. - * - * @hide Pending API council approval - */ -public final class MathUtils { - private static final Random sRandom = new Random(); - private static final float DEG_TO_RAD = 3.1415926f / 180.0f; - private static final float RAD_TO_DEG = 180.0f / 3.1415926f; - - private MathUtils() { - } - - public static float abs(float v) { - return v > 0 ? v : -v; - } - - public static int constrain(int amount, int low, int high) { - return amount < low ? low : (amount > high ? high : amount); - } - - public static long constrain(long amount, long low, long high) { - return amount < low ? low : (amount > high ? high : amount); - } - - public static float constrain(float amount, float low, float high) { - return amount < low ? low : (amount > high ? high : amount); - } - - public static float log(float a) { - return (float) Math.log(a); - } - - public static float exp(float a) { - return (float) Math.exp(a); - } - - public static float pow(float a, float b) { - return (float) Math.pow(a, b); - } - - public static float max(float a, float b) { - return a > b ? a : b; - } - - public static float max(int a, int b) { - return a > b ? a : b; - } - - public static float max(float a, float b, float c) { - return a > b ? (a > c ? a : c) : (b > c ? b : c); - } - - public static float max(int a, int b, int c) { - return a > b ? (a > c ? a : c) : (b > c ? b : c); - } - - public static float min(float a, float b) { - return a < b ? a : b; - } - - public static float min(int a, int b) { - return a < b ? a : b; - } - - public static float min(float a, float b, float c) { - return a < b ? (a < c ? a : c) : (b < c ? b : c); - } - - public static float min(int a, int b, int c) { - return a < b ? (a < c ? a : c) : (b < c ? b : c); - } - - public static float dist(float x1, float y1, float x2, float y2) { - final float x = (x2 - x1); - final float y = (y2 - y1); - return (float) Math.sqrt(x * x + y * y); - } - - public static float dist(float x1, float y1, float z1, float x2, float y2, float z2) { - final float x = (x2 - x1); - final float y = (y2 - y1); - final float z = (z2 - z1); - return (float) Math.sqrt(x * x + y * y + z * z); - } - - public static float mag(float a, float b) { - return (float) Math.sqrt(a * a + b * b); - } - - public static float mag(float a, float b, float c) { - return (float) Math.sqrt(a * a + b * b + c * c); - } - - public static float sq(float v) { - return v * v; - } - - public static float radians(float degrees) { - return degrees * DEG_TO_RAD; - } - - public static float degrees(float radians) { - return radians * RAD_TO_DEG; - } - - public static float acos(float value) { - return (float) Math.acos(value); - } - - public static float asin(float value) { - return (float) Math.asin(value); - } - - public static float atan(float value) { - return (float) Math.atan(value); - } - - public static float atan2(float a, float b) { - return (float) Math.atan2(a, b); - } - - public static float tan(float angle) { - return (float) Math.tan(angle); - } - - public static float lerp(float start, float stop, float amount) { - return start + (stop - start) * amount; - } - - public static float norm(float start, float stop, float value) { - return (value - start) / (stop - start); - } - - public static float map(float minStart, float minStop, float maxStart, float maxStop, float value) { - return maxStart + (maxStart - maxStop) * ((value - minStart) / (minStop - minStart)); - } - - public static int random(int howbig) { - return (int) (sRandom.nextFloat() * howbig); - } - - public static int random(int howsmall, int howbig) { - if (howsmall >= howbig) return howsmall; - return (int) (sRandom.nextFloat() * (howbig - howsmall) + howsmall); - } - - public static float random(float howbig) { - return sRandom.nextFloat() * howbig; - } - - public static float random(float howsmall, float howbig) { - if (howsmall >= howbig) return howsmall; - return sRandom.nextFloat() * (howbig - howsmall) + howsmall; - } - - public static void randomSeed(long seed) { - sRandom.setSeed(seed); - } -} diff --git a/src/main/java/android/util/MonthDisplayHelper.java b/src/main/java/android/util/MonthDisplayHelper.java deleted file mode 100644 index c3f13fc..0000000 --- a/src/main/java/android/util/MonthDisplayHelper.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import java.util.Calendar; - -/** - * Helps answer common questions that come up when displaying a month in a - * 6 row calendar grid format. - * - * Not thread safe. - */ -public class MonthDisplayHelper { - - // display pref - private final int mWeekStartDay; - - // holds current month, year, helps compute display - private Calendar mCalendar; - - // cached computed stuff that helps with display - private int mNumDaysInMonth; - private int mNumDaysInPrevMonth; - private int mOffset; - - - /** - * @param year The year. - * @param month The month. - * @param weekStartDay What day of the week the week should start. - */ - public MonthDisplayHelper(int year, int month, int weekStartDay) { - - if (weekStartDay < Calendar.SUNDAY || weekStartDay > Calendar.SATURDAY) { - throw new IllegalArgumentException(); - } - mWeekStartDay = weekStartDay; - - mCalendar = Calendar.getInstance(); - mCalendar.set(Calendar.YEAR, year); - mCalendar.set(Calendar.MONTH, month); - mCalendar.set(Calendar.DAY_OF_MONTH, 1); - mCalendar.set(Calendar.HOUR_OF_DAY, 0); - mCalendar.set(Calendar.MINUTE, 0); - mCalendar.set(Calendar.SECOND, 0); - mCalendar.getTimeInMillis(); - - recalculate(); - } - - - public MonthDisplayHelper(int year, int month) { - this(year, month, Calendar.SUNDAY); - } - - - public int getYear() { - return mCalendar.get(Calendar.YEAR); - } - - public int getMonth() { - return mCalendar.get(Calendar.MONTH); - } - - - public int getWeekStartDay() { - return mWeekStartDay; - } - - /** - * @return The first day of the month using a constants such as - * {@link java.util.Calendar#SUNDAY}. - */ - public int getFirstDayOfMonth() { - return mCalendar.get(Calendar.DAY_OF_WEEK); - } - - /** - * @return The number of days in the month. - */ - public int getNumberOfDaysInMonth() { - return mNumDaysInMonth; - } - - - /** - * @return The offset from displaying everything starting on the very first - * box. For example, if the calendar is set to display the first day of - * the week as Sunday, and the month starts on a Wednesday, the offset is 3. - */ - public int getOffset() { - return mOffset; - } - - - /** - * @param row Which row (0-5). - * @return the digits of the month to display in one - * of the 6 rows of a calendar month display. - */ - public int[] getDigitsForRow(int row) { - if (row < 0 || row > 5) { - throw new IllegalArgumentException("row " + row - + " out of range (0-5)"); - } - - int [] result = new int[7]; - for (int column = 0; column < 7; column++) { - result[column] = getDayAt(row, column); - } - - return result; - } - - /** - * @param row The row, 0-5, starting from the top. - * @param column The column, 0-6, starting from the left. - * @return The day at a particular row, column - */ - public int getDayAt(int row, int column) { - - if (row == 0 && column < mOffset) { - return mNumDaysInPrevMonth + column - mOffset + 1; - } - - int day = 7 * row + column - mOffset + 1; - - return (day > mNumDaysInMonth) ? - day - mNumDaysInMonth : day; - } - - /** - * @return Which row day is in. - */ - public int getRowOf(int day) { - return (day + mOffset - 1) / 7; - } - - /** - * @return Which column day is in. - */ - public int getColumnOf(int day) { - return (day + mOffset - 1) % 7; - } - - /** - * Decrement the month. - */ - public void previousMonth() { - mCalendar.add(Calendar.MONTH, -1); - recalculate(); - } - - /** - * Increment the month. - */ - public void nextMonth() { - mCalendar.add(Calendar.MONTH, 1); - recalculate(); - } - - /** - * @return Whether the row and column fall within the month. - */ - public boolean isWithinCurrentMonth(int row, int column) { - - if (row < 0 || column < 0 || row > 5 || column > 6) { - return false; - } - - if (row == 0 && column < mOffset) { - return false; - } - - int day = 7 * row + column - mOffset + 1; - if (day > mNumDaysInMonth) { - return false; - } - return true; - } - - - // helper method that recalculates cached values based on current month / year - private void recalculate() { - - mNumDaysInMonth = mCalendar.getActualMaximum(Calendar.DAY_OF_MONTH); - - mCalendar.add(Calendar.MONTH, -1); - mNumDaysInPrevMonth = mCalendar.getActualMaximum(Calendar.DAY_OF_MONTH); - mCalendar.add(Calendar.MONTH, 1); - - int firstDayOfMonth = getFirstDayOfMonth(); - int offset = firstDayOfMonth - mWeekStartDay; - if (offset < 0) { - offset += 7; - } - mOffset = offset; - } -} diff --git a/src/main/java/android/util/MonthDisplayHelperTest.java b/src/main/java/android/util/MonthDisplayHelperTest.java deleted file mode 100644 index 55da665..0000000 --- a/src/main/java/android/util/MonthDisplayHelperTest.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import android.test.suitebuilder.annotation.SmallTest; - -import java.util.Calendar; - -import junit.framework.TestCase; - -/** - * Unit tests for {@link MonthDisplayHelper}. - */ -public class MonthDisplayHelperTest extends TestCase { - - - @SmallTest - public void testFirstDayOfMonth() { - - assertEquals("august 2007", - Calendar.WEDNESDAY, - new MonthDisplayHelper(2007, Calendar.AUGUST).getFirstDayOfMonth()); - - assertEquals("september, 2007", - Calendar.SATURDAY, - new MonthDisplayHelper(2007, Calendar.SEPTEMBER).getFirstDayOfMonth()); - } - - @SmallTest - public void testNumberOfDaysInCurrentMonth() { - assertEquals(30, - new MonthDisplayHelper(2007, Calendar.SEPTEMBER).getNumberOfDaysInMonth()); - } - - @SmallTest - public void testMonthRows() { - MonthDisplayHelper helper = new MonthDisplayHelper(2007, Calendar.SEPTEMBER); - - assertArraysEqual(new int[]{26, 27, 28, 29, 30, 31, 1}, - helper.getDigitsForRow(0)); - assertArraysEqual(new int[]{2, 3, 4, 5, 6, 7, 8}, - helper.getDigitsForRow(1)); - assertArraysEqual(new int[]{30, 1, 2, 3, 4, 5, 6}, - helper.getDigitsForRow(5)); - - } - - @SmallTest - public void testMonthRowsWeekStartsMonday() { - MonthDisplayHelper helper = new MonthDisplayHelper(2007, - Calendar.SEPTEMBER, Calendar.MONDAY); - - assertArraysEqual(new int[]{27, 28, 29, 30, 31, 1, 2}, - helper.getDigitsForRow(0)); - assertArraysEqual(new int[]{3, 4, 5, 6, 7, 8, 9}, - helper.getDigitsForRow(1)); - assertArraysEqual(new int[]{24, 25, 26, 27, 28, 29, 30}, - helper.getDigitsForRow(4)); - assertArraysEqual(new int[]{1, 2, 3, 4, 5, 6, 7}, - helper.getDigitsForRow(5)); - } - - @SmallTest - public void testMonthRowsWeekStartsSaturday() { - MonthDisplayHelper helper = new MonthDisplayHelper(2007, - Calendar.SEPTEMBER, Calendar.SATURDAY); - - assertArraysEqual(new int[]{1, 2, 3, 4, 5, 6, 7}, - helper.getDigitsForRow(0)); - assertArraysEqual(new int[]{8, 9, 10, 11, 12, 13, 14}, - helper.getDigitsForRow(1)); - assertArraysEqual(new int[]{29, 30, 1, 2, 3, 4, 5}, - helper.getDigitsForRow(4)); - - - helper = new MonthDisplayHelper(2007, - Calendar.AUGUST, Calendar.SATURDAY); - - assertArraysEqual(new int[]{28, 29, 30, 31, 1, 2, 3}, - helper.getDigitsForRow(0)); - assertArraysEqual(new int[]{4, 5, 6, 7, 8, 9, 10}, - helper.getDigitsForRow(1)); - assertArraysEqual(new int[]{25, 26, 27, 28, 29, 30, 31}, - helper.getDigitsForRow(4)); - } - - @SmallTest - public void testGetDayAt() { - MonthDisplayHelper helper = new MonthDisplayHelper(2007, - Calendar.SEPTEMBER, Calendar.SUNDAY); - - assertEquals(26, helper.getDayAt(0, 0)); - assertEquals(1, helper.getDayAt(0, 6)); - assertEquals(17, helper.getDayAt(3, 1)); - assertEquals(2, helper.getDayAt(5, 2)); - } - - @SmallTest - public void testPrevMonth() { - MonthDisplayHelper helper = new MonthDisplayHelper(2007, - Calendar.SEPTEMBER, Calendar.SUNDAY); - - assertArraysEqual(new int[]{26, 27, 28, 29, 30, 31, 1}, - helper.getDigitsForRow(0)); - - helper.previousMonth(); - - assertEquals(Calendar.AUGUST, helper.getMonth()); - assertArraysEqual(new int[]{29, 30, 31, 1, 2, 3, 4}, - helper.getDigitsForRow(0)); - } - - @SmallTest - public void testPrevMonthRollOver() { - MonthDisplayHelper helper = new MonthDisplayHelper(2007, - Calendar.JANUARY); - - helper.previousMonth(); - - assertEquals(2006, helper.getYear()); - assertEquals(Calendar.DECEMBER, helper.getMonth()); - } - - @SmallTest - public void testNextMonth() { - MonthDisplayHelper helper = new MonthDisplayHelper(2007, - Calendar.AUGUST, Calendar.SUNDAY); - - assertArraysEqual(new int[]{29, 30, 31, 1, 2, 3, 4}, - helper.getDigitsForRow(0)); - - helper.nextMonth(); - - assertEquals(Calendar.SEPTEMBER, helper.getMonth()); - assertArraysEqual(new int[]{26, 27, 28, 29, 30, 31, 1}, - helper.getDigitsForRow(0)); - } - - @SmallTest - public void testGetRowOf() { - MonthDisplayHelper helper = new MonthDisplayHelper(2007, - Calendar.AUGUST, Calendar.SUNDAY); - - assertEquals(0, helper.getRowOf(2)); - assertEquals(0, helper.getRowOf(4)); - assertEquals(2, helper.getRowOf(12)); - assertEquals(2, helper.getRowOf(18)); - assertEquals(3, helper.getRowOf(19)); - } - - @SmallTest - public void testGetColumnOf() { - MonthDisplayHelper helper = new MonthDisplayHelper(2007, - Calendar.AUGUST, Calendar.SUNDAY); - - assertEquals(3, helper.getColumnOf(1)); - assertEquals(4, helper.getColumnOf(9)); - assertEquals(5, helper.getColumnOf(17)); - assertEquals(6, helper.getColumnOf(25)); - assertEquals(0, helper.getColumnOf(26)); - } - - @SmallTest - public void testWithinCurrentMonth() { - MonthDisplayHelper helper = new MonthDisplayHelper(2007, - Calendar.SEPTEMBER, Calendar.SUNDAY); - - // out of bounds - assertFalse(helper.isWithinCurrentMonth(-1, 3)); - assertFalse(helper.isWithinCurrentMonth(6, 3)); - assertFalse(helper.isWithinCurrentMonth(2, -1)); - assertFalse(helper.isWithinCurrentMonth(2, 7)); - - // last day of previous month - assertFalse(helper.isWithinCurrentMonth(0, 5)); - - // first day of next month - assertFalse(helper.isWithinCurrentMonth(5, 1)); - - // first day in month - assertTrue(helper.isWithinCurrentMonth(0, 6)); - - // last day in month - assertTrue(helper.isWithinCurrentMonth(5, 0)); - } - - private void assertArraysEqual(int[] expected, int[] actual) { - assertEquals("array length", expected.length, actual.length); - for (int i = 0; i < expected.length; i++) { - assertEquals("index " + i, - expected[i], actual[i]); - } - } - -} diff --git a/src/main/java/android/util/MutableBoolean.java b/src/main/java/android/util/MutableBoolean.java deleted file mode 100644 index 5a8a200..0000000 --- a/src/main/java/android/util/MutableBoolean.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2011 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.util; - -/** - */ -public final class MutableBoolean { - public boolean value; - - public MutableBoolean(boolean value) { - this.value = value; - } -} diff --git a/src/main/java/android/util/MutableByte.java b/src/main/java/android/util/MutableByte.java deleted file mode 100644 index 7397ba4..0000000 --- a/src/main/java/android/util/MutableByte.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2011 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.util; - -/** - */ -public final class MutableByte { - public byte value; - - public MutableByte(byte value) { - this.value = value; - } -} diff --git a/src/main/java/android/util/MutableChar.java b/src/main/java/android/util/MutableChar.java deleted file mode 100644 index f435331..0000000 --- a/src/main/java/android/util/MutableChar.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2011 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.util; - -/** - */ -public final class MutableChar { - public char value; - - public MutableChar(char value) { - this.value = value; - } -} diff --git a/src/main/java/android/util/MutableDouble.java b/src/main/java/android/util/MutableDouble.java deleted file mode 100644 index f62f47e..0000000 --- a/src/main/java/android/util/MutableDouble.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2011 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.util; - -/** - */ -public final class MutableDouble { - public double value; - - public MutableDouble(double value) { - this.value = value; - } -} diff --git a/src/main/java/android/util/MutableFloat.java b/src/main/java/android/util/MutableFloat.java deleted file mode 100644 index 6b5441c..0000000 --- a/src/main/java/android/util/MutableFloat.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2011 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.util; - -/** - */ -public final class MutableFloat { - public float value; - - public MutableFloat(float value) { - this.value = value; - } -} diff --git a/src/main/java/android/util/MutableInt.java b/src/main/java/android/util/MutableInt.java deleted file mode 100644 index 2f93030..0000000 --- a/src/main/java/android/util/MutableInt.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2011 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.util; - -/** - */ -public final class MutableInt { - public int value; - - public MutableInt(int value) { - this.value = value; - } -} diff --git a/src/main/java/android/util/MutableLong.java b/src/main/java/android/util/MutableLong.java deleted file mode 100644 index 94beab5..0000000 --- a/src/main/java/android/util/MutableLong.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2011 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.util; - -/** - */ -public final class MutableLong { - public long value; - - public MutableLong(long value) { - this.value = value; - } -} diff --git a/src/main/java/android/util/MutableShort.java b/src/main/java/android/util/MutableShort.java deleted file mode 100644 index cdd9923..0000000 --- a/src/main/java/android/util/MutableShort.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2011 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.util; - -/** - */ -public final class MutableShort { - public short value; - - public MutableShort(short value) { - this.value = value; - } -} diff --git a/src/main/java/android/util/NoSuchPropertyException.java b/src/main/java/android/util/NoSuchPropertyException.java deleted file mode 100644 index b93f983..0000000 --- a/src/main/java/android/util/NoSuchPropertyException.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2011 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.util; - -/** - * Thrown when code requests a {@link Property} on a class that does - * not expose the appropriate method or field. - * - * @see Property#of(java.lang.Class, java.lang.Class, java.lang.String) - */ -public class NoSuchPropertyException extends RuntimeException { - - public NoSuchPropertyException(String s) { - super(s); - } - -} diff --git a/src/main/java/android/util/NtpTrustedTime.java b/src/main/java/android/util/NtpTrustedTime.java deleted file mode 100644 index 8ebcacd..0000000 --- a/src/main/java/android/util/NtpTrustedTime.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (C) 2011 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.util; - -import android.content.ContentResolver; -import android.content.Context; -import android.content.res.Resources; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.net.SntpClient; -import android.os.SystemClock; -import android.provider.Settings; - -/** - * {@link TrustedTime} that connects with a remote NTP server as its trusted - * time source. - * - * @hide - */ -public class NtpTrustedTime implements TrustedTime { - private static final String TAG = "NtpTrustedTime"; - private static final boolean LOGD = false; - - private static NtpTrustedTime sSingleton; - private static Context sContext; - - private final String mServer; - private final long mTimeout; - - private ConnectivityManager mCM; - - private boolean mHasCache; - private long mCachedNtpTime; - private long mCachedNtpElapsedRealtime; - private long mCachedNtpCertainty; - - private NtpTrustedTime(String server, long timeout) { - if (LOGD) Log.d(TAG, "creating NtpTrustedTime using " + server); - mServer = server; - mTimeout = timeout; - } - - public static synchronized NtpTrustedTime getInstance(Context context) { - if (sSingleton == null) { - final Resources res = context.getResources(); - final ContentResolver resolver = context.getContentResolver(); - - final String defaultServer = res.getString( - com.android.internal.R.string.config_ntpServer); - final long defaultTimeout = res.getInteger( - com.android.internal.R.integer.config_ntpTimeout); - - final String secureServer = Settings.Global.getString( - resolver, Settings.Global.NTP_SERVER); - final long timeout = Settings.Global.getLong( - resolver, Settings.Global.NTP_TIMEOUT, defaultTimeout); - - final String server = secureServer != null ? secureServer : defaultServer; - sSingleton = new NtpTrustedTime(server, timeout); - sContext = context; - } - - return sSingleton; - } - - @Override - public boolean forceRefresh() { - if (mServer == null) { - // missing server, so no trusted time available - return false; - } - - // We can't do this at initialization time: ConnectivityService might not be running yet. - synchronized (this) { - if (mCM == null) { - mCM = (ConnectivityManager) sContext.getSystemService(Context.CONNECTIVITY_SERVICE); - } - } - - final NetworkInfo ni = mCM == null ? null : mCM.getActiveNetworkInfo(); - if (ni == null || !ni.isConnected()) { - if (LOGD) Log.d(TAG, "forceRefresh: no connectivity"); - return false; - } - - - if (LOGD) Log.d(TAG, "forceRefresh() from cache miss"); - final SntpClient client = new SntpClient(); - if (client.requestTime(mServer, (int) mTimeout)) { - mHasCache = true; - mCachedNtpTime = client.getNtpTime(); - mCachedNtpElapsedRealtime = client.getNtpTimeReference(); - mCachedNtpCertainty = client.getRoundTripTime() / 2; - return true; - } else { - return false; - } - } - - @Override - public boolean hasCache() { - return mHasCache; - } - - @Override - public long getCacheAge() { - if (mHasCache) { - return SystemClock.elapsedRealtime() - mCachedNtpElapsedRealtime; - } else { - return Long.MAX_VALUE; - } - } - - @Override - public long getCacheCertainty() { - if (mHasCache) { - return mCachedNtpCertainty; - } else { - return Long.MAX_VALUE; - } - } - - @Override - public long currentTimeMillis() { - if (!mHasCache) { - throw new IllegalStateException("Missing authoritative time source"); - } - if (LOGD) Log.d(TAG, "currentTimeMillis() cache hit"); - - // current time is age after the last ntp cache; callers who - // want fresh values will hit makeAuthoritative() first. - return mCachedNtpTime + getCacheAge(); - } - - public long getCachedNtpTime() { - if (LOGD) Log.d(TAG, "getCachedNtpTime() cache hit"); - return mCachedNtpTime; - } - - public long getCachedNtpTimeReference() { - return mCachedNtpElapsedRealtime; - } -} diff --git a/src/main/java/android/util/Pair.java b/src/main/java/android/util/Pair.java deleted file mode 100644 index 6027d08..0000000 --- a/src/main/java/android/util/Pair.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import libcore.util.Objects; - -/** - * Container to ease passing around a tuple of two objects. This object provides a sensible - * implementation of equals(), returning true if equals() is true on each of the contained - * objects. - */ -public class Pair { - public final F first; - public final S second; - - /** - * Constructor for a Pair. - * - * @param first the first object in the Pair - * @param second the second object in the pair - */ - public Pair(F first, S second) { - this.first = first; - this.second = second; - } - - /** - * Checks the two objects for equality by delegating to their respective - * {@link Object#equals(Object)} methods. - * - * @param o the {@link Pair} to which this one is to be checked for equality - * @return true if the underlying objects of the Pair are both considered - * equal - */ - @Override - public boolean equals(Object o) { - if (!(o instanceof Pair)) { - return false; - } - Pair p = (Pair) o; - return Objects.equal(p.first, first) && Objects.equal(p.second, second); - } - - /** - * Compute a hash code using the hash codes of the underlying objects - * - * @return a hashcode of the Pair - */ - @Override - public int hashCode() { - return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode()); - } - - /** - * Convenience method for creating an appropriately typed pair. - * @param a the first object in the Pair - * @param b the second object in the pair - * @return a Pair that is templatized with the types of a and b - */ - public static Pair create(A a, B b) { - return new Pair(a, b); - } -} diff --git a/src/main/java/android/util/PathParser.java b/src/main/java/android/util/PathParser.java deleted file mode 100644 index 92b19be..0000000 --- a/src/main/java/android/util/PathParser.java +++ /dev/null @@ -1,690 +0,0 @@ -/* - * Copyright (C) 2014 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.util; - -import android.graphics.Path; -import android.util.Log; - -import java.util.ArrayList; -import java.util.Arrays; - -/** - * @hide - */ -public class PathParser { - static final String LOGTAG = PathParser.class.getSimpleName(); - - /** - * @param pathData The string representing a path, the same as "d" string in svg file. - * @return the generated Path object. - */ - public static Path createPathFromPathData(String pathData) { - Path path = new Path(); - PathDataNode[] nodes = createNodesFromPathData(pathData); - if (nodes != null) { - try { - PathDataNode.nodesToPath(nodes, path); - } catch (RuntimeException e) { - throw new RuntimeException("Error in parsing " + pathData, e); - } - return path; - } - return null; - } - - /** - * @param pathData The string representing a path, the same as "d" string in svg file. - * @return an array of the PathDataNode. - */ - public static PathDataNode[] createNodesFromPathData(String pathData) { - if (pathData == null) { - return null; - } - int start = 0; - int end = 1; - - ArrayList list = new ArrayList(); - while (end < pathData.length()) { - end = nextStart(pathData, end); - String s = pathData.substring(start, end).trim(); - if (s.length() > 0) { - float[] val = getFloats(s); - addNode(list, s.charAt(0), val); - } - - start = end; - end++; - } - if ((end - start) == 1 && start < pathData.length()) { - addNode(list, pathData.charAt(start), new float[0]); - } - return list.toArray(new PathDataNode[list.size()]); - } - - /** - * @param source The array of PathDataNode to be duplicated. - * @return a deep copy of the source. - */ - public static PathDataNode[] deepCopyNodes(PathDataNode[] source) { - if (source == null) { - return null; - } - PathDataNode[] copy = new PathParser.PathDataNode[source.length]; - for (int i = 0; i < source.length; i ++) { - copy[i] = new PathDataNode(source[i]); - } - return copy; - } - - /** - * @param nodesFrom The source path represented in an array of PathDataNode - * @param nodesTo The target path represented in an array of PathDataNode - * @return whether the nodesFrom can morph into nodesTo - */ - public static boolean canMorph(PathDataNode[] nodesFrom, PathDataNode[] nodesTo) { - if (nodesFrom == null || nodesTo == null) { - return false; - } - - if (nodesFrom.length != nodesTo.length) { - return false; - } - - for (int i = 0; i < nodesFrom.length; i ++) { - if (nodesFrom[i].mType != nodesTo[i].mType - || nodesFrom[i].mParams.length != nodesTo[i].mParams.length) { - return false; - } - } - return true; - } - - /** - * Update the target's data to match the source. - * Before calling this, make sure canMorph(target, source) is true. - * - * @param target The target path represented in an array of PathDataNode - * @param source The source path represented in an array of PathDataNode - */ - public static void updateNodes(PathDataNode[] target, PathDataNode[] source) { - for (int i = 0; i < source.length; i ++) { - target[i].mType = source[i].mType; - for (int j = 0; j < source[i].mParams.length; j ++) { - target[i].mParams[j] = source[i].mParams[j]; - } - } - } - - private static int nextStart(String s, int end) { - char c; - - while (end < s.length()) { - c = s.charAt(end); - // Note that 'e' or 'E' are not valid path commands, but could be - // used for floating point numbers' scientific notation. - // Therefore, when searching for next command, we should ignore 'e' - // and 'E'. - if ((((c - 'A') * (c - 'Z') <= 0) || ((c - 'a') * (c - 'z') <= 0)) - && c != 'e' && c != 'E') { - return end; - } - end++; - } - return end; - } - - private static void addNode(ArrayList list, char cmd, float[] val) { - list.add(new PathDataNode(cmd, val)); - } - - private static class ExtractFloatResult { - // We need to return the position of the next separator and whether the - // next float starts with a '-' or a '.'. - int mEndPosition; - boolean mEndWithNegOrDot; - } - - /** - * Parse the floats in the string. - * This is an optimized version of parseFloat(s.split(",|\\s")); - * - * @param s the string containing a command and list of floats - * @return array of floats - */ - private static float[] getFloats(String s) { - if (s.charAt(0) == 'z' | s.charAt(0) == 'Z') { - return new float[0]; - } - try { - float[] results = new float[s.length()]; - int count = 0; - int startPosition = 1; - int endPosition = 0; - - ExtractFloatResult result = new ExtractFloatResult(); - int totalLength = s.length(); - - // The startPosition should always be the first character of the - // current number, and endPosition is the character after the current - // number. - while (startPosition < totalLength) { - extract(s, startPosition, result); - endPosition = result.mEndPosition; - - if (startPosition < endPosition) { - results[count++] = Float.parseFloat( - s.substring(startPosition, endPosition)); - } - - if (result.mEndWithNegOrDot) { - // Keep the '-' or '.' sign with next number. - startPosition = endPosition; - } else { - startPosition = endPosition + 1; - } - } - return Arrays.copyOf(results, count); - } catch (NumberFormatException e) { - throw new RuntimeException("error in parsing \"" + s + "\"", e); - } - } - - /** - * Calculate the position of the next comma or space or negative sign - * @param s the string to search - * @param start the position to start searching - * @param result the result of the extraction, including the position of the - * the starting position of next number, whether it is ending with a '-'. - */ - private static void extract(String s, int start, ExtractFloatResult result) { - // Now looking for ' ', ',', '.' or '-' from the start. - int currentIndex = start; - boolean foundSeparator = false; - result.mEndWithNegOrDot = false; - boolean secondDot = false; - boolean isExponential = false; - for (; currentIndex < s.length(); currentIndex++) { - boolean isPrevExponential = isExponential; - isExponential = false; - char currentChar = s.charAt(currentIndex); - switch (currentChar) { - case ' ': - case ',': - foundSeparator = true; - break; - case '-': - // The negative sign following a 'e' or 'E' is not a separator. - if (currentIndex != start && !isPrevExponential) { - foundSeparator = true; - result.mEndWithNegOrDot = true; - } - break; - case '.': - if (!secondDot) { - secondDot = true; - } else { - // This is the second dot, and it is considered as a separator. - foundSeparator = true; - result.mEndWithNegOrDot = true; - } - break; - case 'e': - case 'E': - isExponential = true; - break; - } - if (foundSeparator) { - break; - } - } - // When there is nothing found, then we put the end position to the end - // of the string. - result.mEndPosition = currentIndex; - } - - /** - * Each PathDataNode represents one command in the "d" attribute of the svg - * file. - * An array of PathDataNode can represent the whole "d" attribute. - */ - public static class PathDataNode { - private char mType; - private float[] mParams; - - private PathDataNode(char type, float[] params) { - mType = type; - mParams = params; - } - - private PathDataNode(PathDataNode n) { - mType = n.mType; - mParams = Arrays.copyOf(n.mParams, n.mParams.length); - } - - /** - * Convert an array of PathDataNode to Path. - * - * @param node The source array of PathDataNode. - * @param path The target Path object. - */ - public static void nodesToPath(PathDataNode[] node, Path path) { - float[] current = new float[6]; - char previousCommand = 'm'; - for (int i = 0; i < node.length; i++) { - addCommand(path, current, previousCommand, node[i].mType, node[i].mParams); - previousCommand = node[i].mType; - } - } - - /** - * The current PathDataNode will be interpolated between the - * nodeFrom and nodeTo according to the - * fraction. - * - * @param nodeFrom The start value as a PathDataNode. - * @param nodeTo The end value as a PathDataNode - * @param fraction The fraction to interpolate. - */ - public void interpolatePathDataNode(PathDataNode nodeFrom, - PathDataNode nodeTo, float fraction) { - for (int i = 0; i < nodeFrom.mParams.length; i++) { - mParams[i] = nodeFrom.mParams[i] * (1 - fraction) - + nodeTo.mParams[i] * fraction; - } - } - - private static void addCommand(Path path, float[] current, - char previousCmd, char cmd, float[] val) { - - int incr = 2; - float currentX = current[0]; - float currentY = current[1]; - float ctrlPointX = current[2]; - float ctrlPointY = current[3]; - float currentSegmentStartX = current[4]; - float currentSegmentStartY = current[5]; - float reflectiveCtrlPointX; - float reflectiveCtrlPointY; - - switch (cmd) { - case 'z': - case 'Z': - path.close(); - // Path is closed here, but we need to move the pen to the - // closed position. So we cache the segment's starting position, - // and restore it here. - currentX = currentSegmentStartX; - currentY = currentSegmentStartY; - ctrlPointX = currentSegmentStartX; - ctrlPointY = currentSegmentStartY; - path.moveTo(currentX, currentY); - break; - case 'm': - case 'M': - case 'l': - case 'L': - case 't': - case 'T': - incr = 2; - break; - case 'h': - case 'H': - case 'v': - case 'V': - incr = 1; - break; - case 'c': - case 'C': - incr = 6; - break; - case 's': - case 'S': - case 'q': - case 'Q': - incr = 4; - break; - case 'a': - case 'A': - incr = 7; - break; - } - - for (int k = 0; k < val.length; k += incr) { - switch (cmd) { - case 'm': // moveto - Start a new sub-path (relative) - path.rMoveTo(val[k + 0], val[k + 1]); - currentX += val[k + 0]; - currentY += val[k + 1]; - currentSegmentStartX = currentX; - currentSegmentStartY = currentY; - break; - case 'M': // moveto - Start a new sub-path - path.moveTo(val[k + 0], val[k + 1]); - currentX = val[k + 0]; - currentY = val[k + 1]; - currentSegmentStartX = currentX; - currentSegmentStartY = currentY; - break; - case 'l': // lineto - Draw a line from the current point (relative) - path.rLineTo(val[k + 0], val[k + 1]); - currentX += val[k + 0]; - currentY += val[k + 1]; - break; - case 'L': // lineto - Draw a line from the current point - path.lineTo(val[k + 0], val[k + 1]); - currentX = val[k + 0]; - currentY = val[k + 1]; - break; - case 'h': // horizontal lineto - Draws a horizontal line (relative) - path.rLineTo(val[k + 0], 0); - currentX += val[k + 0]; - break; - case 'H': // horizontal lineto - Draws a horizontal line - path.lineTo(val[k + 0], currentY); - currentX = val[k + 0]; - break; - case 'v': // vertical lineto - Draws a vertical line from the current point (r) - path.rLineTo(0, val[k + 0]); - currentY += val[k + 0]; - break; - case 'V': // vertical lineto - Draws a vertical line from the current point - path.lineTo(currentX, val[k + 0]); - currentY = val[k + 0]; - break; - case 'c': // curveto - Draws a cubic Bézier curve (relative) - path.rCubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3], - val[k + 4], val[k + 5]); - - ctrlPointX = currentX + val[k + 2]; - ctrlPointY = currentY + val[k + 3]; - currentX += val[k + 4]; - currentY += val[k + 5]; - - break; - case 'C': // curveto - Draws a cubic Bézier curve - path.cubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3], - val[k + 4], val[k + 5]); - currentX = val[k + 4]; - currentY = val[k + 5]; - ctrlPointX = val[k + 2]; - ctrlPointY = val[k + 3]; - break; - case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp) - reflectiveCtrlPointX = 0; - reflectiveCtrlPointY = 0; - if (previousCmd == 'c' || previousCmd == 's' - || previousCmd == 'C' || previousCmd == 'S') { - reflectiveCtrlPointX = currentX - ctrlPointX; - reflectiveCtrlPointY = currentY - ctrlPointY; - } - path.rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY, - val[k + 0], val[k + 1], - val[k + 2], val[k + 3]); - - ctrlPointX = currentX + val[k + 0]; - ctrlPointY = currentY + val[k + 1]; - currentX += val[k + 2]; - currentY += val[k + 3]; - break; - case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp) - reflectiveCtrlPointX = currentX; - reflectiveCtrlPointY = currentY; - if (previousCmd == 'c' || previousCmd == 's' - || previousCmd == 'C' || previousCmd == 'S') { - reflectiveCtrlPointX = 2 * currentX - ctrlPointX; - reflectiveCtrlPointY = 2 * currentY - ctrlPointY; - } - path.cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY, - val[k + 0], val[k + 1], val[k + 2], val[k + 3]); - ctrlPointX = val[k + 0]; - ctrlPointY = val[k + 1]; - currentX = val[k + 2]; - currentY = val[k + 3]; - break; - case 'q': // Draws a quadratic Bézier (relative) - path.rQuadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]); - ctrlPointX = currentX + val[k + 0]; - ctrlPointY = currentY + val[k + 1]; - currentX += val[k + 2]; - currentY += val[k + 3]; - break; - case 'Q': // Draws a quadratic Bézier - path.quadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]); - ctrlPointX = val[k + 0]; - ctrlPointY = val[k + 1]; - currentX = val[k + 2]; - currentY = val[k + 3]; - break; - case 't': // Draws a quadratic Bézier curve(reflective control point)(relative) - reflectiveCtrlPointX = 0; - reflectiveCtrlPointY = 0; - if (previousCmd == 'q' || previousCmd == 't' - || previousCmd == 'Q' || previousCmd == 'T') { - reflectiveCtrlPointX = currentX - ctrlPointX; - reflectiveCtrlPointY = currentY - ctrlPointY; - } - path.rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, - val[k + 0], val[k + 1]); - ctrlPointX = currentX + reflectiveCtrlPointX; - ctrlPointY = currentY + reflectiveCtrlPointY; - currentX += val[k + 0]; - currentY += val[k + 1]; - break; - case 'T': // Draws a quadratic Bézier curve (reflective control point) - reflectiveCtrlPointX = currentX; - reflectiveCtrlPointY = currentY; - if (previousCmd == 'q' || previousCmd == 't' - || previousCmd == 'Q' || previousCmd == 'T') { - reflectiveCtrlPointX = 2 * currentX - ctrlPointX; - reflectiveCtrlPointY = 2 * currentY - ctrlPointY; - } - path.quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, - val[k + 0], val[k + 1]); - ctrlPointX = reflectiveCtrlPointX; - ctrlPointY = reflectiveCtrlPointY; - currentX = val[k + 0]; - currentY = val[k + 1]; - break; - case 'a': // Draws an elliptical arc - // (rx ry x-axis-rotation large-arc-flag sweep-flag x y) - drawArc(path, - currentX, - currentY, - val[k + 5] + currentX, - val[k + 6] + currentY, - val[k + 0], - val[k + 1], - val[k + 2], - val[k + 3] != 0, - val[k + 4] != 0); - currentX += val[k + 5]; - currentY += val[k + 6]; - ctrlPointX = currentX; - ctrlPointY = currentY; - break; - case 'A': // Draws an elliptical arc - drawArc(path, - currentX, - currentY, - val[k + 5], - val[k + 6], - val[k + 0], - val[k + 1], - val[k + 2], - val[k + 3] != 0, - val[k + 4] != 0); - currentX = val[k + 5]; - currentY = val[k + 6]; - ctrlPointX = currentX; - ctrlPointY = currentY; - break; - } - previousCmd = cmd; - } - current[0] = currentX; - current[1] = currentY; - current[2] = ctrlPointX; - current[3] = ctrlPointY; - current[4] = currentSegmentStartX; - current[5] = currentSegmentStartY; - } - - private static void drawArc(Path p, - float x0, - float y0, - float x1, - float y1, - float a, - float b, - float theta, - boolean isMoreThanHalf, - boolean isPositiveArc) { - - /* Convert rotation angle from degrees to radians */ - double thetaD = Math.toRadians(theta); - /* Pre-compute rotation matrix entries */ - double cosTheta = Math.cos(thetaD); - double sinTheta = Math.sin(thetaD); - /* Transform (x0, y0) and (x1, y1) into unit space */ - /* using (inverse) rotation, followed by (inverse) scale */ - double x0p = (x0 * cosTheta + y0 * sinTheta) / a; - double y0p = (-x0 * sinTheta + y0 * cosTheta) / b; - double x1p = (x1 * cosTheta + y1 * sinTheta) / a; - double y1p = (-x1 * sinTheta + y1 * cosTheta) / b; - - /* Compute differences and averages */ - double dx = x0p - x1p; - double dy = y0p - y1p; - double xm = (x0p + x1p) / 2; - double ym = (y0p + y1p) / 2; - /* Solve for intersecting unit circles */ - double dsq = dx * dx + dy * dy; - if (dsq == 0.0) { - Log.w(LOGTAG, " Points are coincident"); - return; /* Points are coincident */ - } - double disc = 1.0 / dsq - 1.0 / 4.0; - if (disc < 0.0) { - Log.w(LOGTAG, "Points are too far apart " + dsq); - float adjust = (float) (Math.sqrt(dsq) / 1.99999); - drawArc(p, x0, y0, x1, y1, a * adjust, - b * adjust, theta, isMoreThanHalf, isPositiveArc); - return; /* Points are too far apart */ - } - double s = Math.sqrt(disc); - double sdx = s * dx; - double sdy = s * dy; - double cx; - double cy; - if (isMoreThanHalf == isPositiveArc) { - cx = xm - sdy; - cy = ym + sdx; - } else { - cx = xm + sdy; - cy = ym - sdx; - } - - double eta0 = Math.atan2((y0p - cy), (x0p - cx)); - - double eta1 = Math.atan2((y1p - cy), (x1p - cx)); - - double sweep = (eta1 - eta0); - if (isPositiveArc != (sweep >= 0)) { - if (sweep > 0) { - sweep -= 2 * Math.PI; - } else { - sweep += 2 * Math.PI; - } - } - - cx *= a; - cy *= b; - double tcx = cx; - cx = cx * cosTheta - cy * sinTheta; - cy = tcx * sinTheta + cy * cosTheta; - - arcToBezier(p, cx, cy, a, b, x0, y0, thetaD, eta0, sweep); - } - - /** - * Converts an arc to cubic Bezier segments and records them in p. - * - * @param p The target for the cubic Bezier segments - * @param cx The x coordinate center of the ellipse - * @param cy The y coordinate center of the ellipse - * @param a The radius of the ellipse in the horizontal direction - * @param b The radius of the ellipse in the vertical direction - * @param e1x E(eta1) x coordinate of the starting point of the arc - * @param e1y E(eta2) y coordinate of the starting point of the arc - * @param theta The angle that the ellipse bounding rectangle makes with horizontal plane - * @param start The start angle of the arc on the ellipse - * @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse - */ - private static void arcToBezier(Path p, - double cx, - double cy, - double a, - double b, - double e1x, - double e1y, - double theta, - double start, - double sweep) { - // Taken from equations at: http://spaceroots.org/documents/ellipse/node8.html - // and http://www.spaceroots.org/documents/ellipse/node22.html - - // Maximum of 45 degrees per cubic Bezier segment - int numSegments = Math.abs((int) Math.ceil(sweep * 4 / Math.PI)); - - double eta1 = start; - double cosTheta = Math.cos(theta); - double sinTheta = Math.sin(theta); - double cosEta1 = Math.cos(eta1); - double sinEta1 = Math.sin(eta1); - double ep1x = (-a * cosTheta * sinEta1) - (b * sinTheta * cosEta1); - double ep1y = (-a * sinTheta * sinEta1) + (b * cosTheta * cosEta1); - - double anglePerSegment = sweep / numSegments; - for (int i = 0; i < numSegments; i++) { - double eta2 = eta1 + anglePerSegment; - double sinEta2 = Math.sin(eta2); - double cosEta2 = Math.cos(eta2); - double e2x = cx + (a * cosTheta * cosEta2) - (b * sinTheta * sinEta2); - double e2y = cy + (a * sinTheta * cosEta2) + (b * cosTheta * sinEta2); - double ep2x = -a * cosTheta * sinEta2 - b * sinTheta * cosEta2; - double ep2y = -a * sinTheta * sinEta2 + b * cosTheta * cosEta2; - double tanDiff2 = Math.tan((eta2 - eta1) / 2); - double alpha = - Math.sin(eta2 - eta1) * (Math.sqrt(4 + (3 * tanDiff2 * tanDiff2)) - 1) / 3; - double q1x = e1x + alpha * ep1x; - double q1y = e1y + alpha * ep1y; - double q2x = e2x - alpha * ep2x; - double q2y = e2y - alpha * ep2y; - - p.cubicTo((float) q1x, - (float) q1y, - (float) q2x, - (float) q2y, - (float) e2x, - (float) e2y); - eta1 = eta2; - e1x = e2x; - e1y = e2y; - ep1x = ep2x; - ep1y = ep2y; - } - } - } -} diff --git a/src/main/java/android/util/Patterns.java b/src/main/java/android/util/Patterns.java deleted file mode 100644 index 2cc91b9..0000000 --- a/src/main/java/android/util/Patterns.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Commonly used regular expression patterns. - */ -public class Patterns { - /** - * Regular expression to match all IANA top-level domains. - * List accurate as of 2011/07/18. List taken from: - * http://data.iana.org/TLD/tlds-alpha-by-domain.txt - * This pattern is auto-generated by frameworks/ex/common/tools/make-iana-tld-pattern.py - * - * @deprecated Due to the recent profileration of gTLDs, this API is - * expected to become out-of-date very quickly. Therefore it is now - * deprecated. - */ - @Deprecated - public static final String TOP_LEVEL_DOMAIN_STR = - "((aero|arpa|asia|a[cdefgilmnoqrstuwxz])" - + "|(biz|b[abdefghijmnorstvwyz])" - + "|(cat|com|coop|c[acdfghiklmnoruvxyz])" - + "|d[ejkmoz]" - + "|(edu|e[cegrstu])" - + "|f[ijkmor]" - + "|(gov|g[abdefghilmnpqrstuwy])" - + "|h[kmnrtu]" - + "|(info|int|i[delmnoqrst])" - + "|(jobs|j[emop])" - + "|k[eghimnprwyz]" - + "|l[abcikrstuvy]" - + "|(mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])" - + "|(name|net|n[acefgilopruz])" - + "|(org|om)" - + "|(pro|p[aefghklmnrstwy])" - + "|qa" - + "|r[eosuw]" - + "|s[abcdeghijklmnortuvyz]" - + "|(tel|travel|t[cdfghjklmnoprtvwz])" - + "|u[agksyz]" - + "|v[aceginu]" - + "|w[fs]" - + "|(\u03b4\u03bf\u03ba\u03b9\u03bc\u03ae|\u0438\u0441\u043f\u044b\u0442\u0430\u043d\u0438\u0435|\u0440\u0444|\u0441\u0440\u0431|\u05d8\u05e2\u05e1\u05d8|\u0622\u0632\u0645\u0627\u06cc\u0634\u06cc|\u0625\u062e\u062a\u0628\u0627\u0631|\u0627\u0644\u0627\u0631\u062f\u0646|\u0627\u0644\u062c\u0632\u0627\u0626\u0631|\u0627\u0644\u0633\u0639\u0648\u062f\u064a\u0629|\u0627\u0644\u0645\u063a\u0631\u0628|\u0627\u0645\u0627\u0631\u0627\u062a|\u0628\u06be\u0627\u0631\u062a|\u062a\u0648\u0646\u0633|\u0633\u0648\u0631\u064a\u0629|\u0641\u0644\u0633\u0637\u064a\u0646|\u0642\u0637\u0631|\u0645\u0635\u0631|\u092a\u0930\u0940\u0915\u094d\u0937\u093e|\u092d\u093e\u0930\u0924|\u09ad\u09be\u09b0\u09a4|\u0a2d\u0a3e\u0a30\u0a24|\u0aad\u0abe\u0ab0\u0aa4|\u0b87\u0ba8\u0bcd\u0ba4\u0bbf\u0baf\u0bbe|\u0b87\u0bb2\u0b99\u0bcd\u0b95\u0bc8|\u0b9a\u0bbf\u0b99\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0bc2\u0bb0\u0bcd|\u0baa\u0bb0\u0bbf\u0b9f\u0bcd\u0b9a\u0bc8|\u0c2d\u0c3e\u0c30\u0c24\u0c4d|\u0dbd\u0d82\u0d9a\u0dcf|\u0e44\u0e17\u0e22|\u30c6\u30b9\u30c8|\u4e2d\u56fd|\u4e2d\u570b|\u53f0\u6e7e|\u53f0\u7063|\u65b0\u52a0\u5761|\u6d4b\u8bd5|\u6e2c\u8a66|\u9999\u6e2f|\ud14c\uc2a4\ud2b8|\ud55c\uad6d|xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-3e0b707e|xn\\-\\-45brj9c|xn\\-\\-80akhbyknj4f|xn\\-\\-90a3ac|xn\\-\\-9t4b11yi5a|xn\\-\\-clchc0ea0b2g2a9gcd|xn\\-\\-deba0ad|xn\\-\\-fiqs8s|xn\\-\\-fiqz9s|xn\\-\\-fpcrj9c3d|xn\\-\\-fzc2c9e2c|xn\\-\\-g6w251d|xn\\-\\-gecrj9c|xn\\-\\-h2brj9c|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-j6w193g|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-kprw13d|xn\\-\\-kpry57d|xn\\-\\-lgbbat1ad8j|xn\\-\\-mgbaam7a8h|xn\\-\\-mgbayh7gpa|xn\\-\\-mgbbh1a71e|xn\\-\\-mgbc0a9azcg|xn\\-\\-mgberp4a5d4ar|xn\\-\\-o3cw4h|xn\\-\\-ogbpf8fl|xn\\-\\-p1ai|xn\\-\\-pgbs0dh|xn\\-\\-s9brj9c|xn\\-\\-wgbh1c|xn\\-\\-wgbl6a|xn\\-\\-xkc2al3hye2a|xn\\-\\-xkc2dl3a5ee0h|xn\\-\\-yfro4i67o|xn\\-\\-ygbi2ammx|xn\\-\\-zckzah|xxx)" - + "|y[et]" - + "|z[amw])"; - - /** - * Regular expression pattern to match all IANA top-level domains. - * @deprecated This API is deprecated. See {@link #TOP_LEVEL_DOMAIN_STR}. - */ - @Deprecated - public static final Pattern TOP_LEVEL_DOMAIN = - Pattern.compile(TOP_LEVEL_DOMAIN_STR); - - /** - * Regular expression to match all IANA top-level domains for WEB_URL. - * List accurate as of 2011/07/18. List taken from: - * http://data.iana.org/TLD/tlds-alpha-by-domain.txt - * This pattern is auto-generated by frameworks/ex/common/tools/make-iana-tld-pattern.py - * - * @deprecated This API is deprecated. See {@link #TOP_LEVEL_DOMAIN_STR}. - */ - @Deprecated - public static final String TOP_LEVEL_DOMAIN_STR_FOR_WEB_URL = - "(?:" - + "(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])" - + "|(?:biz|b[abdefghijmnorstvwyz])" - + "|(?:cat|com|coop|c[acdfghiklmnoruvxyz])" - + "|d[ejkmoz]" - + "|(?:edu|e[cegrstu])" - + "|f[ijkmor]" - + "|(?:gov|g[abdefghilmnpqrstuwy])" - + "|h[kmnrtu]" - + "|(?:info|int|i[delmnoqrst])" - + "|(?:jobs|j[emop])" - + "|k[eghimnprwyz]" - + "|l[abcikrstuvy]" - + "|(?:mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])" - + "|(?:name|net|n[acefgilopruz])" - + "|(?:org|om)" - + "|(?:pro|p[aefghklmnrstwy])" - + "|qa" - + "|r[eosuw]" - + "|s[abcdeghijklmnortuvyz]" - + "|(?:tel|travel|t[cdfghjklmnoprtvwz])" - + "|u[agksyz]" - + "|v[aceginu]" - + "|w[fs]" - + "|(?:\u03b4\u03bf\u03ba\u03b9\u03bc\u03ae|\u0438\u0441\u043f\u044b\u0442\u0430\u043d\u0438\u0435|\u0440\u0444|\u0441\u0440\u0431|\u05d8\u05e2\u05e1\u05d8|\u0622\u0632\u0645\u0627\u06cc\u0634\u06cc|\u0625\u062e\u062a\u0628\u0627\u0631|\u0627\u0644\u0627\u0631\u062f\u0646|\u0627\u0644\u062c\u0632\u0627\u0626\u0631|\u0627\u0644\u0633\u0639\u0648\u062f\u064a\u0629|\u0627\u0644\u0645\u063a\u0631\u0628|\u0627\u0645\u0627\u0631\u0627\u062a|\u0628\u06be\u0627\u0631\u062a|\u062a\u0648\u0646\u0633|\u0633\u0648\u0631\u064a\u0629|\u0641\u0644\u0633\u0637\u064a\u0646|\u0642\u0637\u0631|\u0645\u0635\u0631|\u092a\u0930\u0940\u0915\u094d\u0937\u093e|\u092d\u093e\u0930\u0924|\u09ad\u09be\u09b0\u09a4|\u0a2d\u0a3e\u0a30\u0a24|\u0aad\u0abe\u0ab0\u0aa4|\u0b87\u0ba8\u0bcd\u0ba4\u0bbf\u0baf\u0bbe|\u0b87\u0bb2\u0b99\u0bcd\u0b95\u0bc8|\u0b9a\u0bbf\u0b99\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0bc2\u0bb0\u0bcd|\u0baa\u0bb0\u0bbf\u0b9f\u0bcd\u0b9a\u0bc8|\u0c2d\u0c3e\u0c30\u0c24\u0c4d|\u0dbd\u0d82\u0d9a\u0dcf|\u0e44\u0e17\u0e22|\u30c6\u30b9\u30c8|\u4e2d\u56fd|\u4e2d\u570b|\u53f0\u6e7e|\u53f0\u7063|\u65b0\u52a0\u5761|\u6d4b\u8bd5|\u6e2c\u8a66|\u9999\u6e2f|\ud14c\uc2a4\ud2b8|\ud55c\uad6d|xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-3e0b707e|xn\\-\\-45brj9c|xn\\-\\-80akhbyknj4f|xn\\-\\-90a3ac|xn\\-\\-9t4b11yi5a|xn\\-\\-clchc0ea0b2g2a9gcd|xn\\-\\-deba0ad|xn\\-\\-fiqs8s|xn\\-\\-fiqz9s|xn\\-\\-fpcrj9c3d|xn\\-\\-fzc2c9e2c|xn\\-\\-g6w251d|xn\\-\\-gecrj9c|xn\\-\\-h2brj9c|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-j6w193g|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-kprw13d|xn\\-\\-kpry57d|xn\\-\\-lgbbat1ad8j|xn\\-\\-mgbaam7a8h|xn\\-\\-mgbayh7gpa|xn\\-\\-mgbbh1a71e|xn\\-\\-mgbc0a9azcg|xn\\-\\-mgberp4a5d4ar|xn\\-\\-o3cw4h|xn\\-\\-ogbpf8fl|xn\\-\\-p1ai|xn\\-\\-pgbs0dh|xn\\-\\-s9brj9c|xn\\-\\-wgbh1c|xn\\-\\-wgbl6a|xn\\-\\-xkc2al3hye2a|xn\\-\\-xkc2dl3a5ee0h|xn\\-\\-yfro4i67o|xn\\-\\-ygbi2ammx|xn\\-\\-zckzah|xxx)" - + "|y[et]" - + "|z[amw]))"; - - /** - * Good characters for Internationalized Resource Identifiers (IRI). - * This comprises most common used Unicode characters allowed in IRI - * as detailed in RFC 3987. - * Specifically, those two byte Unicode characters are not included. - */ - public static final String GOOD_IRI_CHAR = - "a-zA-Z0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF"; - - public static final Pattern IP_ADDRESS - = Pattern.compile( - "((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4]" - + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]" - + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}" - + "|[1-9][0-9]|[0-9]))"); - - /** - * RFC 1035 Section 2.3.4 limits the labels to a maximum 63 octets. - */ - private static final String IRI - = "[" + GOOD_IRI_CHAR + "]([" + GOOD_IRI_CHAR + "\\-]{0,61}[" + GOOD_IRI_CHAR + "]){0,1}"; - - private static final String GOOD_GTLD_CHAR = - "a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF"; - private static final String GTLD = "[" + GOOD_GTLD_CHAR + "]{2,63}"; - private static final String HOST_NAME = "(" + IRI + "\\.)+" + GTLD; - - public static final Pattern DOMAIN_NAME - = Pattern.compile("(" + HOST_NAME + "|" + IP_ADDRESS + ")"); - - /** - * Regular expression pattern to match most part of RFC 3987 - * Internationalized URLs, aka IRIs. Commonly used Unicode characters are - * added. - */ - public static final Pattern WEB_URL = Pattern.compile( - "((?:(http|https|Http|Https|rtsp|Rtsp):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)" - + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_" - + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?" - + "(?:" + DOMAIN_NAME + ")" - + "(?:\\:\\d{1,5})?)" // plus option port number - + "(\\/(?:(?:[" + GOOD_IRI_CHAR + "\\;\\/\\?\\:\\@\\&\\=\\#\\~" // plus option query params - + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?" - + "(?:\\b|$)"); // and finally, a word boundary or end of - // input. This is to stop foo.sure from - // matching as foo.su - - public static final Pattern EMAIL_ADDRESS - = Pattern.compile( - "[a-zA-Z0-9\\+\\.\\_\\%\\-\\+]{1,256}" + - "\\@" + - "[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}" + - "(" + - "\\." + - "[a-zA-Z0-9][a-zA-Z0-9\\-]{0,25}" + - ")+" - ); - - /** - * This pattern is intended for searching for things that look like they - * might be phone numbers in arbitrary text, not for validating whether - * something is in fact a phone number. It will miss many things that - * are legitimate phone numbers. - * - *

    The pattern matches the following: - *

      - *
    • Optionally, a + sign followed immediately by one or more digits. Spaces, dots, or dashes - * may follow. - *
    • Optionally, sets of digits in parentheses, separated by spaces, dots, or dashes. - *
    • A string starting and ending with a digit, containing digits, spaces, dots, and/or dashes. - *
    - */ - public static final Pattern PHONE - = Pattern.compile( // sdd = space, dot, or dash - "(\\+[0-9]+[\\- \\.]*)?" // +* - + "(\\([0-9]+\\)[\\- \\.]*)?" // ()* - + "([0-9][0-9\\- \\.]+[0-9])"); // + - - /** - * Convenience method to take all of the non-null matching groups in a - * regex Matcher and return them as a concatenated string. - * - * @param matcher The Matcher object from which grouped text will - * be extracted - * - * @return A String comprising all of the non-null matched - * groups concatenated together - */ - public static final String concatGroups(Matcher matcher) { - StringBuilder b = new StringBuilder(); - final int numGroups = matcher.groupCount(); - - for (int i = 1; i <= numGroups; i++) { - String s = matcher.group(i); - - if (s != null) { - b.append(s); - } - } - - return b.toString(); - } - - /** - * Convenience method to return only the digits and plus signs - * in the matching string. - * - * @param matcher The Matcher object from which digits and plus will - * be extracted - * - * @return A String comprising all of the digits and plus in - * the match - */ - public static final String digitsAndPlusOnly(Matcher matcher) { - StringBuilder buffer = new StringBuilder(); - String matchingRegion = matcher.group(); - - for (int i = 0, size = matchingRegion.length(); i < size; i++) { - char character = matchingRegion.charAt(i); - - if (character == '+' || Character.isDigit(character)) { - buffer.append(character); - } - } - return buffer.toString(); - } - - /** - * Do not create this static utility class. - */ - private Patterns() {} -} diff --git a/src/main/java/android/util/PatternsTest.java b/src/main/java/android/util/PatternsTest.java deleted file mode 100644 index ebdbb0e..0000000 --- a/src/main/java/android/util/PatternsTest.java +++ /dev/null @@ -1,190 +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.util; - -import android.test.suitebuilder.annotation.SmallTest; -import android.util.Patterns; - -import java.util.regex.Matcher; - -import junit.framework.TestCase; - -public class PatternsTest extends TestCase { - - @SmallTest - public void testTldPattern() throws Exception { - boolean t; - - t = Patterns.TOP_LEVEL_DOMAIN.matcher("com").matches(); - assertTrue("Missed valid TLD", t); - - // One of the new top level domain. - t = Patterns.TOP_LEVEL_DOMAIN.matcher("me").matches(); - assertTrue("Missed valid TLD", t); - - // One of the new top level test domain. - t = Patterns.TOP_LEVEL_DOMAIN.matcher("xn--0zwm56d").matches(); - assertTrue("Missed valid TLD", t); - - // One of the new top level internationalized domain. - t = Patterns.TOP_LEVEL_DOMAIN.matcher("\uD55C\uAD6D").matches(); - assertTrue("Missed valid TLD", t); - - t = Patterns.TOP_LEVEL_DOMAIN.matcher("mem").matches(); - assertFalse("Matched invalid TLD!", t); - - t = Patterns.TOP_LEVEL_DOMAIN.matcher("xn").matches(); - assertFalse("Matched invalid TLD!", t); - - t = Patterns.TOP_LEVEL_DOMAIN.matcher("xer").matches(); - assertFalse("Matched invalid TLD!", t); - } - - @SmallTest - public void testUrlPattern() throws Exception { - boolean t; - - t = Patterns.WEB_URL.matcher("http://www.google.com").matches(); - assertTrue("Valid URL", t); - - // Google in one of the new top level domain. - t = Patterns.WEB_URL.matcher("http://www.google.me").matches(); - assertTrue("Valid URL", t); - t = Patterns.WEB_URL.matcher("google.me").matches(); - assertTrue("Valid URL", t); - - // Test url in Chinese: http://xn--fsqu00a.xn--0zwm56d - t = Patterns.WEB_URL.matcher("http://xn--fsqu00a.xn--0zwm56d").matches(); - assertTrue("Valid URL", t); - t = Patterns.WEB_URL.matcher("xn--fsqu00a.xn--0zwm56d").matches(); - assertTrue("Valid URL", t); - - // Url for testing top level Arabic country code domain in Punycode: - // http://xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx - t = Patterns.WEB_URL.matcher("http://xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx").matches(); - assertTrue("Valid URL", t); - t = Patterns.WEB_URL.matcher("xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx").matches(); - assertTrue("Valid URL", t); - - // Internationalized URL. - t = Patterns.WEB_URL.matcher("http://\uD604\uAE08\uC601\uC218\uC99D.kr").matches(); - assertTrue("Valid URL", t); - t = Patterns.WEB_URL.matcher("\uD604\uAE08\uC601\uC218\uC99D.kr").matches(); - assertTrue("Valid URL", t); - // URL with international TLD. - t = Patterns.WEB_URL.matcher("\uB3C4\uBA54\uC778.\uD55C\uAD6D").matches(); - assertTrue("Valid URL", t); - - t = Patterns.WEB_URL.matcher("http://brainstormtech.blogs.fortune.cnn.com/2010/03/11/" + - "top-five-moments-from-eric-schmidt\u2019s-talk-in-abu-dhabi/").matches(); - assertTrue("Valid URL", t); - - t = Patterns.WEB_URL.matcher("ftp://www.example.com").matches(); - assertFalse("Matched invalid protocol", t); - - t = Patterns.WEB_URL.matcher("http://www.example.com:8080").matches(); - assertTrue("Didn't match valid URL with port", t); - - t = Patterns.WEB_URL.matcher("http://www.example.com:8080/?foo=bar").matches(); - assertTrue("Didn't match valid URL with port and query args", t); - - t = Patterns.WEB_URL.matcher("http://www.example.com:8080/~user/?foo=bar").matches(); - assertTrue("Didn't match valid URL with ~", t); - } - - @SmallTest - public void testIpPattern() throws Exception { - boolean t; - - t = Patterns.IP_ADDRESS.matcher("172.29.86.3").matches(); - assertTrue("Valid IP", t); - - t = Patterns.IP_ADDRESS.matcher("1234.4321.9.9").matches(); - assertFalse("Invalid IP", t); - } - - @SmallTest - public void testDomainPattern() throws Exception { - boolean t; - - t = Patterns.DOMAIN_NAME.matcher("mail.example.com").matches(); - assertTrue("Valid domain", t); - - t = Patterns.DOMAIN_NAME.matcher("google.me").matches(); - assertTrue("Valid domain", t); - - // Internationalized domains. - t = Patterns.DOMAIN_NAME.matcher("\uD604\uAE08\uC601\uC218\uC99D.kr").matches(); - assertTrue("Valid domain", t); - - t = Patterns.DOMAIN_NAME.matcher("__+&42.xer").matches(); - assertFalse("Invalid domain", t); - - // Obsolete domain .yu - t = Patterns.DOMAIN_NAME.matcher("test.yu").matches(); - assertFalse("Obsolete country code top level domain", t); - - // Testing top level Arabic country code domain in Punycode: - t = Patterns.DOMAIN_NAME.matcher("xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c").matches(); - assertTrue("Valid domain", t); - } - - @SmallTest - public void testPhonePattern() throws Exception { - boolean t; - - t = Patterns.PHONE.matcher("(919) 555-1212").matches(); - assertTrue("Valid phone", t); - - t = Patterns.PHONE.matcher("2334 9323/54321").matches(); - assertFalse("Invalid phone", t); - - String[] tests = { - "Me: 16505551212 this\n", - "Me: 6505551212 this\n", - "Me: 5551212 this\n", - "Me: 2211 this\n", - "Me: 112 this\n", - - "Me: 1-650-555-1212 this\n", - "Me: (650) 555-1212 this\n", - "Me: +1 (650) 555-1212 this\n", - "Me: +1-650-555-1212 this\n", - "Me: 650-555-1212 this\n", - "Me: 555-1212 this\n", - - "Me: 1.650.555.1212 this\n", - "Me: (650) 555.1212 this\n", - "Me: +1 (650) 555.1212 this\n", - "Me: +1.650.555.1212 this\n", - "Me: 650.555.1212 this\n", - "Me: 555.1212 this\n", - - "Me: 1 650 555 1212 this\n", - "Me: (650) 555 1212 this\n", - "Me: +1 (650) 555 1212 this\n", - "Me: +1 650 555 1212 this\n", - "Me: 650 555 1212 this\n", - "Me: 555 1212 this\n", - }; - - for (String test : tests) { - Matcher m = Patterns.PHONE.matcher(test); - - assertTrue("Valid phone " + test, m.find()); - } - } -} diff --git a/src/main/java/android/util/Pools.java b/src/main/java/android/util/Pools.java deleted file mode 100644 index 70581be..0000000 --- a/src/main/java/android/util/Pools.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -/** - * Helper class for crating pools of objects. An example use looks like this: - *
    - * public class MyPooledClass {
    - *
    - *     private static final SynchronizedPool sPool =
    - *             new SynchronizedPool(10);
    - *
    - *     public static MyPooledClass obtain() {
    - *         MyPooledClass instance = sPool.acquire();
    - *         return (instance != null) ? instance : new MyPooledClass();
    - *     }
    - *
    - *     public void recycle() {
    - *          // Clear state if needed.
    - *          sPool.release(this);
    - *     }
    - *
    - *     . . .
    - * }
    - * 
    - * - * @hide - */ -public final class Pools { - - /** - * Interface for managing a pool of objects. - * - * @param The pooled type. - */ - public static interface Pool { - - /** - * @return An instance from the pool if such, null otherwise. - */ - public T acquire(); - - /** - * Release an instance to the pool. - * - * @param instance The instance to release. - * @return Whether the instance was put in the pool. - * - * @throws IllegalStateException If the instance is already in the pool. - */ - public boolean release(T instance); - } - - private Pools() { - /* do nothing - hiding constructor */ - } - - /** - * Simple (non-synchronized) pool of objects. - * - * @param The pooled type. - */ - public static class SimplePool implements Pool { - private final Object[] mPool; - - private int mPoolSize; - - /** - * Creates a new instance. - * - * @param maxPoolSize The max pool size. - * - * @throws IllegalArgumentException If the max pool size is less than zero. - */ - public SimplePool(int maxPoolSize) { - if (maxPoolSize <= 0) { - throw new IllegalArgumentException("The max pool size must be > 0"); - } - mPool = new Object[maxPoolSize]; - } - - @Override - @SuppressWarnings("unchecked") - public T acquire() { - if (mPoolSize > 0) { - final int lastPooledIndex = mPoolSize - 1; - T instance = (T) mPool[lastPooledIndex]; - mPool[lastPooledIndex] = null; - mPoolSize--; - return instance; - } - return null; - } - - @Override - public boolean release(T instance) { - if (isInPool(instance)) { - throw new IllegalStateException("Already in the pool!"); - } - if (mPoolSize < mPool.length) { - mPool[mPoolSize] = instance; - mPoolSize++; - return true; - } - return false; - } - - private boolean isInPool(T instance) { - for (int i = 0; i < mPoolSize; i++) { - if (mPool[i] == instance) { - return true; - } - } - return false; - } - } - - /** - * Synchronized) pool of objects. - * - * @param The pooled type. - */ - public static class SynchronizedPool extends SimplePool { - private final Object mLock = new Object(); - - /** - * Creates a new instance. - * - * @param maxPoolSize The max pool size. - * - * @throws IllegalArgumentException If the max pool size is less than zero. - */ - public SynchronizedPool(int maxPoolSize) { - super(maxPoolSize); - } - - @Override - public T acquire() { - synchronized (mLock) { - return super.acquire(); - } - } - - @Override - public boolean release(T element) { - synchronized (mLock) { - return super.release(element); - } - } - } -} diff --git a/src/main/java/android/util/PrefixPrinter.java b/src/main/java/android/util/PrefixPrinter.java deleted file mode 100644 index 62f7da1..0000000 --- a/src/main/java/android/util/PrefixPrinter.java +++ /dev/null @@ -1,50 +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.util; - -/** - * PrefixPrinter is a Printer which prefixes all lines with a given - * prefix. - * - * @hide - */ -public class PrefixPrinter implements Printer { - private final Printer mPrinter; - private final String mPrefix; - - /** - * Creates a new PrefixPrinter. - * - *

    If prefix is null or empty, the provided printer is returned, rather - * than making a prefixing printer. - */ - public static Printer create(Printer printer, String prefix) { - if (prefix == null || prefix.equals("")) { - return printer; - } - return new PrefixPrinter(printer, prefix); - } - - private PrefixPrinter(Printer printer, String prefix) { - mPrinter = printer; - mPrefix = prefix; - } - - public void println(String str) { - mPrinter.println(mPrefix + str); - } -} diff --git a/src/main/java/android/util/PrintStreamPrinter.java b/src/main/java/android/util/PrintStreamPrinter.java deleted file mode 100644 index 1c11f15..0000000 --- a/src/main/java/android/util/PrintStreamPrinter.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import java.io.PrintStream; - -/** - * Implementation of a {@link android.util.Printer} that sends its output - * to a {@link java.io.PrintStream}. - */ -public class PrintStreamPrinter implements Printer { - private final PrintStream mPS; - - /** - * Create a new Printer that sends to a PrintWriter object. - * - * @param pw The PrintWriter where you would like output to go. - */ - public PrintStreamPrinter(PrintStream pw) { - mPS = pw; - } - - public void println(String x) { - mPS.println(x); - } -} diff --git a/src/main/java/android/util/PrintWriterPrinter.java b/src/main/java/android/util/PrintWriterPrinter.java deleted file mode 100644 index 82c4d03..0000000 --- a/src/main/java/android/util/PrintWriterPrinter.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import java.io.PrintWriter; - -/** - * Implementation of a {@link android.util.Printer} that sends its output - * to a {@link java.io.PrintWriter}. - */ -public class PrintWriterPrinter implements Printer { - private final PrintWriter mPW; - - /** - * Create a new Printer that sends to a PrintWriter object. - * - * @param pw The PrintWriter where you would like output to go. - */ - public PrintWriterPrinter(PrintWriter pw) { - mPW = pw; - } - - public void println(String x) { - mPW.println(x); - } -} diff --git a/src/main/java/android/util/Printer.java b/src/main/java/android/util/Printer.java deleted file mode 100644 index 595cf70..0000000 --- a/src/main/java/android/util/Printer.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -/** - * Simple interface for printing text, allowing redirection to various - * targets. Standard implementations are {@link android.util.LogPrinter}, - * {@link android.util.StringBuilderPrinter}, and - * {@link android.util.PrintWriterPrinter}. - */ -public interface Printer { - /** - * Write a line of text to the output. There is no need to terminate - * the given string with a newline. - */ - void println(String x); -} diff --git a/src/main/java/android/util/Property.java b/src/main/java/android/util/Property.java deleted file mode 100644 index 146db80..0000000 --- a/src/main/java/android/util/Property.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2011 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.util; - - -/** - * A property is an abstraction that can be used to represent a mutable value that is held - * in a host object. The Property's {@link #set(Object, Object)} or {@link #get(Object)} - * methods can be implemented in terms of the private fields of the host object, or via "setter" and - * "getter" methods or by some other mechanism, as appropriate. - * - * @param The class on which the property is declared. - * @param The type that this property represents. - */ -public abstract class Property { - - private final String mName; - private final Class mType; - - /** - * This factory method creates and returns a Property given the class and - * name parameters, where the "name" parameter represents either: - *

      - *
    • a public getName() method on the class which takes no arguments, plus an - * optional public setName() method which takes a value of the same type - * returned by getName() - *
    • a public isName() method on the class which takes no arguments, plus an - * optional public setName() method which takes a value of the same type - * returned by isName() - *
    • a public name field on the class - *
    - * - *

    If either of the get/is method alternatives is found on the class, but an appropriate - * setName() method is not found, the Property will be - * {@link #isReadOnly() readOnly}. Calling the {@link #set(Object, Object)} method on such - * a property is allowed, but will have no effect.

    - * - *

    If neither the methods nor the field are found on the class a - * {@link NoSuchPropertyException} exception will be thrown.

    - */ - public static Property of(Class hostType, Class valueType, String name) { - return new ReflectiveProperty(hostType, valueType, name); - } - - /** - * A constructor that takes an identifying name and {@link #getType() type} for the property. - */ - public Property(Class type, String name) { - mName = name; - mType = type; - } - - /** - * Returns true if the {@link #set(Object, Object)} method does not set the value on the target - * object (in which case the {@link #set(Object, Object) set()} method should throw a {@link - * NoSuchPropertyException} exception). This may happen if the Property wraps functionality that - * allows querying the underlying value but not setting it. For example, the {@link #of(Class, - * Class, String)} factory method may return a Property with name "foo" for an object that has - * only a getFoo() or isFoo() method, but no matching - * setFoo() method. - */ - public boolean isReadOnly() { - return false; - } - - /** - * Sets the value on object which this property represents. If the method is unable - * to set the value on the target object it will throw an {@link UnsupportedOperationException} - * exception. - */ - public void set(T object, V value) { - throw new UnsupportedOperationException("Property " + getName() +" is read-only"); - } - - /** - * Returns the current value that this property represents on the given object. - */ - public abstract V get(T object); - - /** - * Returns the name for this property. - */ - public String getName() { - return mName; - } - - /** - * Returns the type for this property. - */ - public Class getType() { - return mType; - } -} diff --git a/src/main/java/android/util/Range.java b/src/main/java/android/util/Range.java deleted file mode 100644 index 211d01a..0000000 --- a/src/main/java/android/util/Range.java +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Copyright (C) 2014 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.util; - -import static com.android.internal.util.Preconditions.*; - -import android.hardware.camera2.utils.HashCodeHelpers; - -/** - * Immutable class for describing the range of two numeric values. - *

    - * A range (or "interval") defines the inclusive boundaries around a contiguous span of - * values of some {@link Comparable} type; for example, - * "integers from 1 to 100 inclusive." - *

    - *

    - * All ranges are bounded, and the left side of the range is always {@code >=} - * the right side of the range. - *

    - * - *

    Although the implementation itself is immutable, there is no restriction that objects - * stored must also be immutable. If mutable objects are stored here, then the range - * effectively becomes mutable.

    - */ -public final class Range> { - /** - * Create a new immutable range. - * - *

    - * The endpoints are {@code [lower, upper]}; that - * is the range is bounded. {@code lower} must be {@link Comparable#compareTo lesser or equal} - * to {@code upper}. - *

    - * - * @param lower The lower endpoint (inclusive) - * @param upper The upper endpoint (inclusive) - * - * @throws NullPointerException if {@code lower} or {@code upper} is {@code null} - */ - public Range(final T lower, final T upper) { - mLower = checkNotNull(lower, "lower must not be null"); - mUpper = checkNotNull(upper, "upper must not be null"); - - if (lower.compareTo(upper) > 0) { - throw new IllegalArgumentException("lower must be less than or equal to upper"); - } - } - - /** - * Create a new immutable range, with the argument types inferred. - * - *

    - * The endpoints are {@code [lower, upper]}; that - * is the range is bounded. {@code lower} must be {@link Comparable#compareTo lesser or equal} - * to {@code upper}. - *

    - * - * @param lower The lower endpoint (inclusive) - * @param upper The upper endpoint (inclusive) - * - * @throws NullPointerException if {@code lower} or {@code upper} is {@code null} - */ - public static > Range create(final T lower, final T upper) { - return new Range(lower, upper); - } - - /** - * Get the lower endpoint. - * - * @return a non-{@code null} {@code T} reference - */ - public T getLower() { - return mLower; - } - - /** - * Get the upper endpoint. - * - * @return a non-{@code null} {@code T} reference - */ - public T getUpper() { - return mUpper; - } - - /** - * Checks if the {@code value} is within the bounds of this range. - * - *

    A value is considered to be within this range if it's {@code >=} - * the lower endpoint and {@code <=} the upper endpoint (using the {@link Comparable} - * interface.)

    - * - * @param value a non-{@code null} {@code T} reference - * @return {@code true} if the value is within this inclusive range, {@code false} otherwise - * - * @throws NullPointerException if {@code value} was {@code null} - */ - public boolean contains(T value) { - checkNotNull(value, "value must not be null"); - - boolean gteLower = value.compareTo(mLower) >= 0; - boolean lteUpper = value.compareTo(mUpper) <= 0; - - return gteLower && lteUpper; - } - - /** - * Checks if another {@code range} is within the bounds of this range. - * - *

    A range is considered to be within this range if both of its endpoints - * are within this range.

    - * - * @param range a non-{@code null} {@code T} reference - * @return {@code true} if the range is within this inclusive range, {@code false} otherwise - * - * @throws NullPointerException if {@code range} was {@code null} - */ - public boolean contains(Range range) { - checkNotNull(range, "value must not be null"); - - boolean gteLower = range.mLower.compareTo(mLower) >= 0; - boolean lteUpper = range.mUpper.compareTo(mUpper) <= 0; - - return gteLower && lteUpper; - } - - /** - * Compare two ranges for equality. - * - *

    A range is considered equal if and only if both the lower and upper endpoints - * are also equal.

    - * - * @return {@code true} if the ranges are equal, {@code false} otherwise - */ - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } else if (this == obj) { - return true; - } else if (obj instanceof Range) { - @SuppressWarnings("rawtypes") - Range other = (Range) obj; - return mLower.equals(other.mLower) && mUpper.equals(other.mUpper); - } - return false; - } - - /** - * Clamps {@code value} to this range. - * - *

    If the value is within this range, it is returned. Otherwise, if it - * is {@code <} than the lower endpoint, the lower endpoint is returned, - * else the upper endpoint is returned. Comparisons are performed using the - * {@link Comparable} interface.

    - * - * @param value a non-{@code null} {@code T} reference - * @return {@code value} clamped to this range. - */ - public T clamp(T value) { - checkNotNull(value, "value must not be null"); - - if (value.compareTo(mLower) < 0) { - return mLower; - } else if (value.compareTo(mUpper) > 0) { - return mUpper; - } else { - return value; - } - } - - /** - * Returns the intersection of this range and another {@code range}. - *

    - * E.g. if a {@code <} b {@code <} c {@code <} d, the - * intersection of [a, c] and [b, d] ranges is [b, c]. - * As the endpoints are object references, there is no guarantee - * which specific endpoint reference is used from the input ranges:

    - *

    - * E.g. if a {@code ==} a' {@code <} b {@code <} c, the - * intersection of [a, b] and [a', c] ranges could be either - * [a, b] or ['a, b], where [a, b] could be either the exact - * input range, or a newly created range with the same endpoints.

    - * - * @param range a non-{@code null} {@code Range} reference - * @return the intersection of this range and the other range. - * - * @throws NullPointerException if {@code range} was {@code null} - * @throws IllegalArgumentException if the ranges are disjoint. - */ - public Range intersect(Range range) { - checkNotNull(range, "range must not be null"); - - int cmpLower = range.mLower.compareTo(mLower); - int cmpUpper = range.mUpper.compareTo(mUpper); - - if (cmpLower <= 0 && cmpUpper >= 0) { - // range includes this - return this; - } else if (cmpLower >= 0 && cmpUpper <= 0) { - // this inludes range - return range; - } else { - return Range.create( - cmpLower <= 0 ? mLower : range.mLower, - cmpUpper >= 0 ? mUpper : range.mUpper); - } - } - - /** - * Returns the intersection of this range and the inclusive range - * specified by {@code [lower, upper]}. - *

    - * See {@link #intersect(Range)} for more details.

    - * - * @param lower a non-{@code null} {@code T} reference - * @param upper a non-{@code null} {@code T} reference - * @return the intersection of this range and the other range - * - * @throws NullPointerException if {@code lower} or {@code upper} was {@code null} - * @throws IllegalArgumentException if the ranges are disjoint. - */ - public Range intersect(T lower, T upper) { - checkNotNull(lower, "lower must not be null"); - checkNotNull(upper, "upper must not be null"); - - int cmpLower = lower.compareTo(mLower); - int cmpUpper = upper.compareTo(mUpper); - - if (cmpLower <= 0 && cmpUpper >= 0) { - // [lower, upper] includes this - return this; - } else { - return Range.create( - cmpLower <= 0 ? mLower : lower, - cmpUpper >= 0 ? mUpper : upper); - } - } - - /** - * Returns the smallest range that includes this range and - * another {@code range}. - *

    - * E.g. if a {@code <} b {@code <} c {@code <} d, the - * extension of [a, c] and [b, d] ranges is [a, d]. - * As the endpoints are object references, there is no guarantee - * which specific endpoint reference is used from the input ranges:

    - *

    - * E.g. if a {@code ==} a' {@code <} b {@code <} c, the - * extension of [a, b] and [a', c] ranges could be either - * [a, c] or ['a, c], where ['a, c] could be either the exact - * input range, or a newly created range with the same endpoints.

    - * - * @param range a non-{@code null} {@code Range} reference - * @return the extension of this range and the other range. - * - * @throws NullPointerException if {@code range} was {@code null} - */ - public Range extend(Range range) { - checkNotNull(range, "range must not be null"); - - int cmpLower = range.mLower.compareTo(mLower); - int cmpUpper = range.mUpper.compareTo(mUpper); - - if (cmpLower <= 0 && cmpUpper >= 0) { - // other includes this - return range; - } else if (cmpLower >= 0 && cmpUpper <= 0) { - // this inludes other - return this; - } else { - return Range.create( - cmpLower >= 0 ? mLower : range.mLower, - cmpUpper <= 0 ? mUpper : range.mUpper); - } - } - - /** - * Returns the smallest range that includes this range and - * the inclusive range specified by {@code [lower, upper]}. - *

    - * See {@link #extend(Range)} for more details.

    - * - * @param lower a non-{@code null} {@code T} reference - * @param upper a non-{@code null} {@code T} reference - * @return the extension of this range and the other range. - * - * @throws NullPointerException if {@code lower} or {@code - * upper} was {@code null} - */ - public Range extend(T lower, T upper) { - checkNotNull(lower, "lower must not be null"); - checkNotNull(upper, "upper must not be null"); - - int cmpLower = lower.compareTo(mLower); - int cmpUpper = upper.compareTo(mUpper); - - if (cmpLower >= 0 && cmpUpper <= 0) { - // this inludes other - return this; - } else { - return Range.create( - cmpLower >= 0 ? mLower : lower, - cmpUpper <= 0 ? mUpper : upper); - } - } - - /** - * Returns the smallest range that includes this range and - * the {@code value}. - *

    - * See {@link #extend(Range)} for more details, as this method is - * equivalent to {@code extend(Range.create(value, value))}.

    - * - * @param value a non-{@code null} {@code T} reference - * @return the extension of this range and the value. - * - * @throws NullPointerException if {@code value} was {@code null} - */ - public Range extend(T value) { - checkNotNull(value, "value must not be null"); - return extend(value, value); - } - - /** - * Return the range as a string representation {@code "[lower, upper]"}. - * - * @return string representation of the range - */ - @Override - public String toString() { - return String.format("[%s, %s]", mLower, mUpper); - } - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - return HashCodeHelpers.hashCode(mLower, mUpper); - } - - private final T mLower; - private final T mUpper; -}; diff --git a/src/main/java/android/util/Rational.java b/src/main/java/android/util/Rational.java deleted file mode 100644 index 80d26d9..0000000 --- a/src/main/java/android/util/Rational.java +++ /dev/null @@ -1,602 +0,0 @@ -/* - * Copyright (C) 2013 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.util; - -import static com.android.internal.util.Preconditions.*; - -import java.io.IOException; -import java.io.InvalidObjectException; - -/** - *

    An immutable data type representation a rational number.

    - * - *

    Contains a pair of {@code int}s representing the numerator and denominator of a - * Rational number.

    - */ -public final class Rational extends Number implements Comparable { - /** - * Constant for the Not-a-Number (NaN) value of the {@code Rational} type. - * - *

    A {@code NaN} value is considered to be equal to itself (that is {@code NaN.equals(NaN)} - * will return {@code true}; it is always greater than any non-{@code NaN} value (that is - * {@code NaN.compareTo(notNaN)} will return a number greater than {@code 0}).

    - * - *

    Equivalent to constructing a new rational with both the numerator and denominator - * equal to {@code 0}.

    - */ - public static final Rational NaN = new Rational(0, 0); - - /** - * Constant for the positive infinity value of the {@code Rational} type. - * - *

    Equivalent to constructing a new rational with a positive numerator and a denominator - * equal to {@code 0}.

    - */ - public static final Rational POSITIVE_INFINITY = new Rational(1, 0); - - /** - * Constant for the negative infinity value of the {@code Rational} type. - * - *

    Equivalent to constructing a new rational with a negative numerator and a denominator - * equal to {@code 0}.

    - */ - public static final Rational NEGATIVE_INFINITY = new Rational(-1, 0); - - /** - * Constant for the zero value of the {@code Rational} type. - * - *

    Equivalent to constructing a new rational with a numerator equal to {@code 0} and - * any non-zero denominator.

    - */ - public static final Rational ZERO = new Rational(0, 1); - - /** - * Unique version number per class to be compliant with {@link java.io.Serializable}. - * - *

    Increment each time the fields change in any way.

    - */ - private static final long serialVersionUID = 1L; - - /* - * Do not change the order of these fields or add new instance fields to maintain the - * Serializable compatibility across API revisions. - */ - private final int mNumerator; - private final int mDenominator; - - /** - *

    Create a {@code Rational} with a given numerator and denominator.

    - * - *

    The signs of the numerator and the denominator may be flipped such that the denominator - * is always positive. Both the numerator and denominator will be converted to their reduced - * forms (see {@link #equals} for more details).

    - * - *

    For example, - *

      - *
    • a rational of {@code 2/4} will be reduced to {@code 1/2}. - *
    • a rational of {@code 1/-1} will be flipped to {@code -1/1} - *
    • a rational of {@code 5/0} will be reduced to {@code 1/0} - *
    • a rational of {@code 0/5} will be reduced to {@code 0/1} - *
    - *

    - * - * @param numerator the numerator of the rational - * @param denominator the denominator of the rational - * - * @see #equals - */ - public Rational(int numerator, int denominator) { - - if (denominator < 0) { - numerator = -numerator; - denominator = -denominator; - } - - // Convert to reduced form - if (denominator == 0 && numerator > 0) { - mNumerator = 1; // +Inf - mDenominator = 0; - } else if (denominator == 0 && numerator < 0) { - mNumerator = -1; // -Inf - mDenominator = 0; - } else if (denominator == 0 && numerator == 0) { - mNumerator = 0; // NaN - mDenominator = 0; - } else if (numerator == 0) { - mNumerator = 0; - mDenominator = 1; - } else { - int gcd = gcd(numerator, denominator); - - mNumerator = numerator / gcd; - mDenominator = denominator / gcd; - } - } - - /** - * Gets the numerator of the rational. - * - *

    The numerator will always return {@code 1} if this rational represents - * infinity (that is, the denominator is {@code 0}).

    - */ - public int getNumerator() { - return mNumerator; - } - - /** - * Gets the denominator of the rational - * - *

    The denominator may return {@code 0}, in which case the rational may represent - * positive infinity (if the numerator was positive), negative infinity (if the numerator - * was negative), or {@code NaN} (if the numerator was {@code 0}).

    - * - *

    The denominator will always return {@code 1} if the numerator is {@code 0}. - */ - public int getDenominator() { - return mDenominator; - } - - /** - * Indicates whether this rational is a Not-a-Number (NaN) value. - * - *

    A {@code NaN} value occurs when both the numerator and the denominator are {@code 0}.

    - * - * @return {@code true} if this rational is a Not-a-Number (NaN) value; - * {@code false} if this is a (potentially infinite) number value - */ - public boolean isNaN() { - return mDenominator == 0 && mNumerator == 0; - } - - /** - * Indicates whether this rational represents an infinite value. - * - *

    An infinite value occurs when the denominator is {@code 0} (but the numerator is not).

    - * - * @return {@code true} if this rational is a (positive or negative) infinite value; - * {@code false} if this is a finite number value (or {@code NaN}) - */ - public boolean isInfinite() { - return mNumerator != 0 && mDenominator == 0; - } - - /** - * Indicates whether this rational represents a finite value. - * - *

    A finite value occurs when the denominator is not {@code 0}; in other words - * the rational is neither infinity or {@code NaN}.

    - * - * @return {@code true} if this rational is a (positive or negative) infinite value; - * {@code false} if this is a finite number value (or {@code NaN}) - */ - public boolean isFinite() { - return mDenominator != 0; - } - - /** - * Indicates whether this rational represents a zero value. - * - *

    A zero value is a {@link #isFinite finite} rational with a numerator of {@code 0}.

    - * - * @return {@code true} if this rational is finite zero value; - * {@code false} otherwise - */ - public boolean isZero() { - return isFinite() && mNumerator == 0; - } - - private boolean isPosInf() { - return mDenominator == 0 && mNumerator > 0; - } - - private boolean isNegInf() { - return mDenominator == 0 && mNumerator < 0; - } - - /** - *

    Compare this Rational to another object and see if they are equal.

    - * - *

    A Rational object can only be equal to another Rational object (comparing against any - * other type will return {@code false}).

    - * - *

    A Rational object is considered equal to another Rational object if and only if one of - * the following holds:

    - *
    • Both are {@code NaN}
    • - *
    • Both are infinities of the same sign
    • - *
    • Both have the same numerator and denominator in their reduced form
    • - *
    - * - *

    A reduced form of a Rational is calculated by dividing both the numerator and the - * denominator by their greatest common divisor.

    - * - *
    {@code
    -     * (new Rational(1, 2)).equals(new Rational(1, 2)) == true   // trivially true
    -     * (new Rational(2, 3)).equals(new Rational(1, 2)) == false  // trivially false
    -     * (new Rational(1, 2)).equals(new Rational(2, 4)) == true   // true after reduction
    -     * (new Rational(0, 0)).equals(new Rational(0, 0)) == true   // NaN.equals(NaN)
    -     * (new Rational(1, 0)).equals(new Rational(5, 0)) == true   // both are +infinity
    -     * (new Rational(1, 0)).equals(new Rational(-1, 0)) == false // +infinity != -infinity
    -     * }
    - * - * @param obj a reference to another object - * - * @return A boolean that determines whether or not the two Rational objects are equal. - */ - @Override - public boolean equals(Object obj) { - return obj instanceof Rational && equals((Rational) obj); - } - - private boolean equals(Rational other) { - return (mNumerator == other.mNumerator && mDenominator == other.mDenominator); - } - - /** - * Return a string representation of this rational, e.g. {@code "1/2"}. - * - *

    The following rules of conversion apply: - *

      - *
    • {@code NaN} values will return {@code "NaN"} - *
    • Positive infinity values will return {@code "Infinity"} - *
    • Negative infinity values will return {@code "-Infinity"} - *
    • All other values will return {@code "numerator/denominator"} where {@code numerator} - * and {@code denominator} are substituted with the appropriate numerator and denominator - * values. - *

    - */ - @Override - public String toString() { - if (isNaN()) { - return "NaN"; - } else if (isPosInf()) { - return "Infinity"; - } else if (isNegInf()) { - return "-Infinity"; - } else { - return mNumerator + "/" + mDenominator; - } - } - - /** - *

    Convert to a floating point representation.

    - * - * @return The floating point representation of this rational number. - * @hide - */ - public float toFloat() { - // TODO: remove this duplicate function (used in CTS and the shim) - return floatValue(); - } - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - // Bias the hash code for the first (2^16) values for both numerator and denominator - int numeratorFlipped = mNumerator << 16 | mNumerator >>> 16; - - return mDenominator ^ numeratorFlipped; - } - - /** - * Calculates the greatest common divisor using Euclid's algorithm. - * - *

    Visible for testing only.

    - * - * @param numerator the numerator in a fraction - * @param denominator the denominator in a fraction - * - * @return An int value representing the gcd. Always positive. - * @hide - */ - public static int gcd(int numerator, int denominator) { - /* - * Non-recursive implementation of Euclid's algorithm: - * - * gcd(a, 0) := a - * gcd(a, b) := gcd(b, a mod b) - * - */ - int a = numerator; - int b = denominator; - - while (b != 0) { - int oldB = b; - - b = a % b; - a = oldB; - } - - return Math.abs(a); - } - - /** - * Returns the value of the specified number as a {@code double}. - * - *

    The {@code double} is calculated by converting both the numerator and denominator - * to a {@code double}; then returning the result of dividing the numerator by the - * denominator.

    - * - * @return the divided value of the numerator and denominator as a {@code double}. - */ - @Override - public double doubleValue() { - double num = mNumerator; - double den = mDenominator; - - return num / den; - } - - /** - * Returns the value of the specified number as a {@code float}. - * - *

    The {@code float} is calculated by converting both the numerator and denominator - * to a {@code float}; then returning the result of dividing the numerator by the - * denominator.

    - * - * @return the divided value of the numerator and denominator as a {@code float}. - */ - @Override - public float floatValue() { - float num = mNumerator; - float den = mDenominator; - - return num / den; - } - - /** - * Returns the value of the specified number as a {@code int}. - * - *

    {@link #isInfinite Finite} rationals are converted to an {@code int} value - * by dividing the numerator by the denominator; conversion for non-finite values happens - * identically to casting a floating point value to an {@code int}, in particular: - * - *

    - *

      - *
    • Positive infinity saturates to the largest maximum integer - * {@link Integer#MAX_VALUE}
    • - *
    • Negative infinity saturates to the smallest maximum integer - * {@link Integer#MIN_VALUE}
    • - *
    • Not-A-Number (NaN) returns {@code 0}.
    • - *
    - *

    - * - * @return the divided value of the numerator and denominator as a {@code int}. - */ - @Override - public int intValue() { - // Mimic float to int conversion rules from JLS 5.1.3 - - if (isPosInf()) { - return Integer.MAX_VALUE; - } else if (isNegInf()) { - return Integer.MIN_VALUE; - } else if (isNaN()) { - return 0; - } else { // finite - return mNumerator / mDenominator; - } - } - - /** - * Returns the value of the specified number as a {@code long}. - * - *

    {@link #isInfinite Finite} rationals are converted to an {@code long} value - * by dividing the numerator by the denominator; conversion for non-finite values happens - * identically to casting a floating point value to a {@code long}, in particular: - * - *

    - *

      - *
    • Positive infinity saturates to the largest maximum long - * {@link Long#MAX_VALUE}
    • - *
    • Negative infinity saturates to the smallest maximum long - * {@link Long#MIN_VALUE}
    • - *
    • Not-A-Number (NaN) returns {@code 0}.
    • - *
    - *

    - * - * @return the divided value of the numerator and denominator as a {@code long}. - */ - @Override - public long longValue() { - // Mimic float to long conversion rules from JLS 5.1.3 - - if (isPosInf()) { - return Long.MAX_VALUE; - } else if (isNegInf()) { - return Long.MIN_VALUE; - } else if (isNaN()) { - return 0; - } else { // finite - return mNumerator / mDenominator; - } - } - - /** - * Returns the value of the specified number as a {@code short}. - * - *

    {@link #isInfinite Finite} rationals are converted to a {@code short} value - * identically to {@link #intValue}; the {@code int} result is then truncated to a - * {@code short} before returning the value.

    - * - * @return the divided value of the numerator and denominator as a {@code short}. - */ - @Override - public short shortValue() { - return (short) intValue(); - } - - /** - * Compare this rational to the specified rational to determine their natural order. - * - *

    {@link #NaN} is considered to be equal to itself and greater than all other - * {@code Rational} values. Otherwise, if the objects are not {@link #equals equal}, then - * the following rules apply:

    - * - *
      - *
    • Positive infinity is greater than any other finite number (or negative infinity) - *
    • Negative infinity is less than any other finite number (or positive infinity) - *
    • The finite number represented by this rational is checked numerically - * against the other finite number by converting both rationals to a common denominator multiple - * and comparing their numerators. - *
    - * - * @param another the rational to be compared - * - * @return a negative integer, zero, or a positive integer as this object is less than, - * equal to, or greater than the specified rational. - * - * @throws NullPointerException if {@code another} was {@code null} - */ - @Override - public int compareTo(Rational another) { - checkNotNull(another, "another must not be null"); - - if (equals(another)) { - return 0; - } else if (isNaN()) { // NaN is greater than the other non-NaN value - return 1; - } else if (another.isNaN()) { // the other NaN is greater than this non-NaN value - return -1; - } else if (isPosInf() || another.isNegInf()) { - return 1; // positive infinity is greater than any non-NaN/non-posInf value - } else if (isNegInf() || another.isPosInf()) { - return -1; // negative infinity is less than any non-NaN/non-negInf value - } - - // else both this and another are finite numbers - - // make the denominators the same, then compare numerators - long thisNumerator = ((long)mNumerator) * another.mDenominator; // long to avoid overflow - long otherNumerator = ((long)another.mNumerator) * mDenominator; // long to avoid overflow - - // avoid underflow from subtraction by doing comparisons - if (thisNumerator < otherNumerator) { - return -1; - } else if (thisNumerator > otherNumerator) { - return 1; - } else { - // This should be covered by #equals, but have this code path just in case - return 0; - } - } - - /* - * Serializable implementation. - * - * The following methods are omitted: - * >> writeObject - the default is sufficient (field by field serialization) - * >> readObjectNoData - the default is sufficient (0s for both fields is a NaN) - */ - - /** - * writeObject with default serialized form - guards against - * deserializing non-reduced forms of the rational. - * - * @throws InvalidObjectException if the invariants were violated - */ - private void readObject(java.io.ObjectInputStream in) - throws IOException, ClassNotFoundException { - in.defaultReadObject(); - - /* - * Guard against trying to deserialize illegal values (in this case, ones - * that don't have a standard reduced form). - * - * - Non-finite values must be one of [0, 1], [0, 0], [0, 1], [0, -1] - * - Finite values must always have their greatest common divisor as 1 - */ - - if (mNumerator == 0) { // either zero or NaN - if (mDenominator == 1 || mDenominator == 0) { - return; - } - throw new InvalidObjectException( - "Rational must be deserialized from a reduced form for zero values"); - } else if (mDenominator == 0) { // either positive or negative infinity - if (mNumerator == 1 || mNumerator == -1) { - return; - } - throw new InvalidObjectException( - "Rational must be deserialized from a reduced form for infinity values"); - } else { // finite value - if (gcd(mNumerator, mDenominator) > 1) { - throw new InvalidObjectException( - "Rational must be deserialized from a reduced form for finite values"); - } - } - } - - private static NumberFormatException invalidRational(String s) { - throw new NumberFormatException("Invalid Rational: \"" + s + "\""); - } - - /** - * Parses the specified string as a rational value. - *

    The ASCII characters {@code \}{@code u003a} (':') and - * {@code \}{@code u002f} ('/') are recognized as separators between - * the numerator and denumerator.

    - *

    - * For any {@code Rational r}: {@code Rational.parseRational(r.toString()).equals(r)}. - * However, the method also handles rational numbers expressed in the - * following forms:

    - *

    - * "num{@code /}den" or - * "num{@code :}den" {@code => new Rational(num, den);}, - * where num and den are string integers potentially - * containing a sign, such as "-10", "+7" or "5".

    - * - *
    {@code
    -     * Rational.parseRational("3:+6").equals(new Rational(1, 2)) == true
    -     * Rational.parseRational("-3/-6").equals(new Rational(1, 2)) == true
    -     * Rational.parseRational("4.56") => throws NumberFormatException
    -     * }
    - * - * @param string the string representation of a rational value. - * @return the rational value represented by {@code string}. - * - * @throws NumberFormatException if {@code string} cannot be parsed - * as a rational value. - * @throws NullPointerException if {@code string} was {@code null} - */ - public static Rational parseRational(String string) - throws NumberFormatException { - checkNotNull(string, "string must not be null"); - - if (string.equals("NaN")) { - return NaN; - } else if (string.equals("Infinity")) { - return POSITIVE_INFINITY; - } else if (string.equals("-Infinity")) { - return NEGATIVE_INFINITY; - } - - int sep_ix = string.indexOf(':'); - if (sep_ix < 0) { - sep_ix = string.indexOf('/'); - } - if (sep_ix < 0) { - throw invalidRational(string); - } - try { - return new Rational(Integer.parseInt(string.substring(0, sep_ix)), - Integer.parseInt(string.substring(sep_ix + 1))); - } catch (NumberFormatException e) { - throw invalidRational(string); - } - } -} diff --git a/src/main/java/android/util/ReflectiveProperty.java b/src/main/java/android/util/ReflectiveProperty.java deleted file mode 100644 index 6832240..0000000 --- a/src/main/java/android/util/ReflectiveProperty.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (C) 2011 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.util; - -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -/** - * Internal class to automatically generate a Property for a given class/name pair, given the - * specification of {@link Property#of(java.lang.Class, java.lang.Class, java.lang.String)} - */ -class ReflectiveProperty extends Property { - - private static final String PREFIX_GET = "get"; - private static final String PREFIX_IS = "is"; - private static final String PREFIX_SET = "set"; - private Method mSetter; - private Method mGetter; - private Field mField; - - /** - * For given property name 'name', look for getName/isName method or 'name' field. - * Also look for setName method (optional - could be readonly). Failing method getters and - * field results in throwing NoSuchPropertyException. - * - * @param propertyHolder The class on which the methods or field are found - * @param name The name of the property, where this name is capitalized and appended to - * "get" and "is to search for the appropriate methods. If the get/is methods are not found, - * the constructor will search for a field with that exact name. - */ - public ReflectiveProperty(Class propertyHolder, Class valueType, String name) { - // TODO: cache reflection info for each new class/name pair - super(valueType, name); - char firstLetter = Character.toUpperCase(name.charAt(0)); - String theRest = name.substring(1); - String capitalizedName = firstLetter + theRest; - String getterName = PREFIX_GET + capitalizedName; - try { - mGetter = propertyHolder.getMethod(getterName, (Class[])null); - } catch (NoSuchMethodException e) { - // getName() not available - try isName() instead - getterName = PREFIX_IS + capitalizedName; - try { - mGetter = propertyHolder.getMethod(getterName, (Class[])null); - } catch (NoSuchMethodException e1) { - // Try public field instead - try { - mField = propertyHolder.getField(name); - Class fieldType = mField.getType(); - if (!typesMatch(valueType, fieldType)) { - throw new NoSuchPropertyException("Underlying type (" + fieldType + ") " + - "does not match Property type (" + valueType + ")"); - } - return; - } catch (NoSuchFieldException e2) { - // no way to access property - throw appropriate exception - throw new NoSuchPropertyException("No accessor method or field found for" - + " property with name " + name); - } - } - } - Class getterType = mGetter.getReturnType(); - // Check to make sure our getter type matches our valueType - if (!typesMatch(valueType, getterType)) { - throw new NoSuchPropertyException("Underlying type (" + getterType + ") " + - "does not match Property type (" + valueType + ")"); - } - String setterName = PREFIX_SET + capitalizedName; - try { - mSetter = propertyHolder.getMethod(setterName, getterType); - } catch (NoSuchMethodException ignored) { - // Okay to not have a setter - just a readonly property - } - } - - /** - * Utility method to check whether the type of the underlying field/method on the target - * object matches the type of the Property. The extra checks for primitive types are because - * generics will force the Property type to be a class, whereas the type of the underlying - * method/field will probably be a primitive type instead. Accept float as matching Float, - * etc. - */ - private boolean typesMatch(Class valueType, Class getterType) { - if (getterType != valueType) { - if (getterType.isPrimitive()) { - return (getterType == float.class && valueType == Float.class) || - (getterType == int.class && valueType == Integer.class) || - (getterType == boolean.class && valueType == Boolean.class) || - (getterType == long.class && valueType == Long.class) || - (getterType == double.class && valueType == Double.class) || - (getterType == short.class && valueType == Short.class) || - (getterType == byte.class && valueType == Byte.class) || - (getterType == char.class && valueType == Character.class); - } - return false; - } - return true; - } - - @Override - public void set(T object, V value) { - if (mSetter != null) { - try { - mSetter.invoke(object, value); - } catch (IllegalAccessException e) { - throw new AssertionError(); - } catch (InvocationTargetException e) { - throw new RuntimeException(e.getCause()); - } - } else if (mField != null) { - try { - mField.set(object, value); - } catch (IllegalAccessException e) { - throw new AssertionError(); - } - } else { - throw new UnsupportedOperationException("Property " + getName() +" is read-only"); - } - } - - @Override - public V get(T object) { - if (mGetter != null) { - try { - return (V) mGetter.invoke(object, (Object[])null); - } catch (IllegalAccessException e) { - throw new AssertionError(); - } catch (InvocationTargetException e) { - throw new RuntimeException(e.getCause()); - } - } else if (mField != null) { - try { - return (V) mField.get(object); - } catch (IllegalAccessException e) { - throw new AssertionError(); - } - } - // Should not get here: there should always be a non-null getter or field - throw new AssertionError(); - } - - /** - * Returns false if there is no setter or public field underlying this Property. - */ - @Override - public boolean isReadOnly() { - return (mSetter == null && mField == null); - } -} diff --git a/src/main/java/android/util/ScrollViewScenario.java b/src/main/java/android/util/ScrollViewScenario.java deleted file mode 100644 index db3d9d0..0000000 --- a/src/main/java/android/util/ScrollViewScenario.java +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import com.google.android.collect.Lists; - -import android.app.Activity; -import android.content.Context; -import android.os.Bundle; -import android.view.View; -import android.view.ViewGroup; -import android.view.Window; -import android.widget.Button; -import android.widget.LinearLayout; -import android.widget.ScrollView; -import android.widget.TextView; - -import java.util.List; - -/** - * Utility base class for creating scroll view scenarios, allowing you to add - * a series of different kinds of views arranged vertically, taking up a - * specified amount of the screen height. - */ -public abstract class ScrollViewScenario extends Activity { - - /** - * Holds content of scroll view - */ - private LinearLayout mLinearLayout; - - /** - * The actual scroll view - */ - private ScrollView mScrollView; - - - /** - * What we need of each view that the user wants: the view, and the ratio - * to the screen height for its desired height. - */ - private interface ViewFactory { - View create(final Context context); - - float getHeightRatio(); - } - - /** - * Partially implement ViewFactory given a height ratio. - * A negative height ratio means that WRAP_CONTENT will be used as height - */ - private static abstract class ViewFactoryBase implements ViewFactory { - - private float mHeightRatio; - - @SuppressWarnings({"UnusedDeclaration"}) - private ViewFactoryBase() {throw new UnsupportedOperationException("don't call this!");} - - protected ViewFactoryBase(float heightRatio) { - mHeightRatio = heightRatio; - } - - public float getHeightRatio() { - return mHeightRatio; - } - } - - /** - * Builder for selecting the views to be vertically arranged in the scroll - * view. - */ - @SuppressWarnings({"JavaDoc"}) - public static class Params { - - List mViewFactories = Lists.newArrayList(); - - int mTopPadding = 0; - int mBottomPadding = 0; - - /** - * Add a text view. - * @param text The text of the text view. - * @param heightRatio The view's height will be this * the screen height. - */ - public Params addTextView(final String text, float heightRatio) { - mViewFactories.add(new ViewFactoryBase(heightRatio) { - public View create(final Context context) { - final TextView tv = new TextView(context); - tv.setText(text); - return tv; - } - }); - return this; - } - - /** - * Add multiple text views. - * @param numViews the number of views to add. - * @param textPrefix The text to prepend to each text view. - * @param heightRatio The view's height will be this * the screen height. - */ - public Params addTextViews(int numViews, String textPrefix, float heightRatio) { - for (int i = 0; i < numViews; i++) { - addTextView(textPrefix + i, heightRatio); - } - return this; - } - - /** - * Add a button. - * @param text The text of the button. - * @param heightRatio The view's height will be this * the screen height. - */ - public Params addButton(final String text, float heightRatio) { - mViewFactories.add(new ViewFactoryBase(heightRatio) { - public View create(final Context context) { - final Button button = new Button(context); - button.setText(text); - return button; - } - }); - return this; - } - - /** - * Add multiple buttons. - * @param numButtons the number of views to add. - * @param textPrefix The text to prepend to each button. - * @param heightRatio The view's height will be this * the screen height. - */ - public Params addButtons(int numButtons, String textPrefix, float heightRatio) { - for (int i = 0; i < numButtons; i++) { - addButton(textPrefix + i, heightRatio); - } - return this; - } - - /** - * Add an {@link InternalSelectionView}. - * @param numRows The number of rows in the internal selection view. - * @param heightRatio The view's height will be this * the screen height. - */ - public Params addInternalSelectionView(final int numRows, float heightRatio) { - mViewFactories.add(new ViewFactoryBase(heightRatio) { - public View create(final Context context) { - return new InternalSelectionView(context, numRows, "isv"); - } - }); - return this; - } - - /** - * Add a sublayout of buttons as a single child of the scroll view. - * @param numButtons The number of buttons in the sub layout - * @param heightRatio The layout's height will be this * the screen height. - */ - public Params addVerticalLLOfButtons(final String prefix, final int numButtons, float heightRatio) { - mViewFactories.add(new ViewFactoryBase(heightRatio) { - - public View create(Context context) { - final LinearLayout ll = new LinearLayout(context); - ll.setOrientation(LinearLayout.VERTICAL); - - // fill width, equally weighted on height - final LinearLayout.LayoutParams lp = - new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, 0, 1f); - for (int i = 0; i < numButtons; i++) { - final Button button = new Button(context); - button.setText(prefix + i); - ll.addView(button, lp); - } - - return ll; - } - }); - return this; - } - - public Params addPaddingToScrollView(int topPadding, int bottomPadding) { - mTopPadding = topPadding; - mBottomPadding = bottomPadding; - - return this; - } - } - - /** - * Override this and initialized the views in the scroll view. - * @param params Used to configure the contents of the scroll view. - */ - protected abstract void init(Params params); - - public LinearLayout getLinearLayout() { - return mLinearLayout; - } - - public ScrollView getScrollView() { - return mScrollView; - } - - /** - * Get the child contained within the vertical linear layout of the - * scroll view. - * @param index The index within the linear layout. - * @return the child within the vertical linear layout of the scroll view - * at the specified index. - */ - @SuppressWarnings({"unchecked"}) - public T getContentChildAt(int index) { - return (T) mLinearLayout.getChildAt(index); - } - - /** - * Hook for changing how scroll view's are created. - */ - @SuppressWarnings({"JavaDoc"}) - protected ScrollView createScrollView() { - return new ScrollView(this); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - // for test stability, turn off title bar - requestWindowFeature(Window.FEATURE_NO_TITLE); - int screenHeight = getWindowManager().getDefaultDisplay().getHeight() - - 25; - mLinearLayout = new LinearLayout(this); - mLinearLayout.setOrientation(LinearLayout.VERTICAL); - - // initialize params - final Params params = new Params(); - init(params); - - // create views specified by params - for (ViewFactory viewFactory : params.mViewFactories) { - int height = ViewGroup.LayoutParams.WRAP_CONTENT; - if (viewFactory.getHeightRatio() >= 0) { - height = (int) (viewFactory.getHeightRatio() * screenHeight); - } - final LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, height); - mLinearLayout.addView(viewFactory.create(this), lp); - } - - mScrollView = createScrollView(); - mScrollView.setPadding(0, params.mTopPadding, 0, params.mBottomPadding); - mScrollView.addView(mLinearLayout, new ViewGroup.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT)); - - // no animation to speed up tests - mScrollView.setSmoothScrollingEnabled(false); - - setContentView(mScrollView); - } -} diff --git a/src/main/java/android/util/Singleton.java b/src/main/java/android/util/Singleton.java deleted file mode 100644 index 8a38bdb..0000000 --- a/src/main/java/android/util/Singleton.java +++ /dev/null @@ -1,39 +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.util; - -/** - * Singleton helper class for lazily initialization. - * - * Modeled after frameworks/base/include/utils/Singleton.h - * - * @hide - */ -public abstract class Singleton { - private T mInstance; - - protected abstract T create(); - - public final T get() { - synchronized (this) { - if (mInstance == null) { - mInstance = create(); - } - return mInstance; - } - } -} diff --git a/src/main/java/android/util/Size.java b/src/main/java/android/util/Size.java deleted file mode 100644 index 62df564..0000000 --- a/src/main/java/android/util/Size.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (C) 2013 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.util; - -import static com.android.internal.util.Preconditions.checkNotNull; - -/** - * Immutable class for describing width and height dimensions in pixels. - */ -public final class Size { - /** - * Create a new immutable Size instance. - * - * @param width The width of the size, in pixels - * @param height The height of the size, in pixels - */ - public Size(int width, int height) { - mWidth = width; - mHeight = height; - } - - /** - * Get the width of the size (in pixels). - * @return width - */ - public int getWidth() { - return mWidth; - } - - /** - * Get the height of the size (in pixels). - * @return height - */ - public int getHeight() { - return mHeight; - } - - /** - * Check if this size is equal to another size. - *

    - * Two sizes are equal if and only if both their widths and heights are - * equal. - *

    - *

    - * A size object is never equal to any other type of object. - *

    - * - * @return {@code true} if the objects were equal, {@code false} otherwise - */ - @Override - public boolean equals(final Object obj) { - if (obj == null) { - return false; - } - if (this == obj) { - return true; - } - if (obj instanceof Size) { - Size other = (Size) obj; - return mWidth == other.mWidth && mHeight == other.mHeight; - } - return false; - } - - /** - * Return the size represented as a string with the format {@code "WxH"} - * - * @return string representation of the size - */ - @Override - public String toString() { - return mWidth + "x" + mHeight; - } - - private static NumberFormatException invalidSize(String s) { - throw new NumberFormatException("Invalid Size: \"" + s + "\""); - } - - /** - * Parses the specified string as a size value. - *

    - * The ASCII characters {@code \}{@code u002a} ('*') and - * {@code \}{@code u0078} ('x') are recognized as separators between - * the width and height.

    - *

    - * For any {@code Size s}: {@code Size.parseSize(s.toString()).equals(s)}. - * However, the method also handles sizes expressed in the - * following forms:

    - *

    - * "width{@code x}height" or - * "width{@code *}height" {@code => new Size(width, height)}, - * where width and height are string integers potentially - * containing a sign, such as "-10", "+7" or "5".

    - * - *
    {@code
    -     * Size.parseSize("3*+6").equals(new Size(3, 6)) == true
    -     * Size.parseSize("-3x-6").equals(new Size(-3, -6)) == true
    -     * Size.parseSize("4 by 3") => throws NumberFormatException
    -     * }
    - * - * @param string the string representation of a size value. - * @return the size value represented by {@code string}. - * - * @throws NumberFormatException if {@code string} cannot be parsed - * as a size value. - * @throws NullPointerException if {@code string} was {@code null} - */ - public static Size parseSize(String string) - throws NumberFormatException { - checkNotNull(string, "string must not be null"); - - int sep_ix = string.indexOf('*'); - if (sep_ix < 0) { - sep_ix = string.indexOf('x'); - } - if (sep_ix < 0) { - throw invalidSize(string); - } - try { - return new Size(Integer.parseInt(string.substring(0, sep_ix)), - Integer.parseInt(string.substring(sep_ix + 1))); - } catch (NumberFormatException e) { - throw invalidSize(string); - } - } - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - // assuming most sizes are <2^16, doing a rotate will give us perfect hashing - return mHeight ^ ((mWidth << (Integer.SIZE / 2)) | (mWidth >>> (Integer.SIZE / 2))); - } - - private final int mWidth; - private final int mHeight; -} diff --git a/src/main/java/android/util/SizeF.java b/src/main/java/android/util/SizeF.java deleted file mode 100644 index 2edc4a7..0000000 --- a/src/main/java/android/util/SizeF.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (C) 2014 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.util; - -import static com.android.internal.util.Preconditions.checkNotNull; -import static com.android.internal.util.Preconditions.checkArgumentFinite; - -/** - * Immutable class for describing width and height dimensions in some arbitrary - * unit. - *

    - * Width and height are finite values stored as a floating point representation. - *

    - */ -public final class SizeF { - /** - * Create a new immutable SizeF instance. - * - *

    Both the {@code width} and the {@code height} must be a finite number. - * In particular, {@code NaN} and positive/negative infinity are illegal values.

    - * - * @param width The width of the size - * @param height The height of the size - * - * @throws IllegalArgumentException - * if either {@code width} or {@code height} was not finite. - */ - public SizeF(final float width, final float height) { - mWidth = checkArgumentFinite(width, "width"); - mHeight = checkArgumentFinite(height, "height"); - } - - /** - * Get the width of the size (as an arbitrary unit). - * @return width - */ - public float getWidth() { - return mWidth; - } - - /** - * Get the height of the size (as an arbitrary unit). - * @return height - */ - public float getHeight() { - return mHeight; - } - - /** - * Check if this size is equal to another size. - * - *

    Two sizes are equal if and only if both their widths and heights are the same.

    - * - *

    For this purpose, the width/height float values are considered to be the same if and only - * if the method {@link Float#floatToIntBits(float)} returns the identical {@code int} value - * when applied to each.

    - * - * @return {@code true} if the objects were equal, {@code false} otherwise - */ - @Override - public boolean equals(final Object obj) { - if (obj == null) { - return false; - } - if (this == obj) { - return true; - } - if (obj instanceof SizeF) { - final SizeF other = (SizeF) obj; - return mWidth == other.mWidth && mHeight == other.mHeight; - } - return false; - } - - /** - * Return the size represented as a string with the format {@code "WxH"} - * - * @return string representation of the size - */ - @Override - public String toString() { - return mWidth + "x" + mHeight; - } - - private static NumberFormatException invalidSizeF(String s) { - throw new NumberFormatException("Invalid SizeF: \"" + s + "\""); - } - - /** - * Parses the specified string as a size value. - *

    - * The ASCII characters {@code \}{@code u002a} ('*') and - * {@code \}{@code u0078} ('x') are recognized as separators between - * the width and height.

    - *

    - * For any {@code SizeF s}: {@code SizeF.parseSizeF(s.toString()).equals(s)}. - * However, the method also handles sizes expressed in the - * following forms:

    - *

    - * "width{@code x}height" or - * "width{@code *}height" {@code => new SizeF(width, height)}, - * where width and height are string floats potentially - * containing a sign, such as "-10.3", "+7" or "5.2", but not containing - * an {@code 'x'} (such as a float in hexadecimal string format).

    - * - *
    {@code
    -     * SizeF.parseSizeF("3.2*+6").equals(new SizeF(3.2f, 6.0f)) == true
    -     * SizeF.parseSizeF("-3x-6").equals(new SizeF(-3.0f, -6.0f)) == true
    -     * SizeF.parseSizeF("4 by 3") => throws NumberFormatException
    -     * }
    - * - * @param string the string representation of a size value. - * @return the size value represented by {@code string}. - * - * @throws NumberFormatException if {@code string} cannot be parsed - * as a size value. - * @throws NullPointerException if {@code string} was {@code null} - */ - public static SizeF parseSizeF(String string) - throws NumberFormatException { - checkNotNull(string, "string must not be null"); - - int sep_ix = string.indexOf('*'); - if (sep_ix < 0) { - sep_ix = string.indexOf('x'); - } - if (sep_ix < 0) { - throw invalidSizeF(string); - } - try { - return new SizeF(Float.parseFloat(string.substring(0, sep_ix)), - Float.parseFloat(string.substring(sep_ix + 1))); - } catch (NumberFormatException e) { - throw invalidSizeF(string); - } catch (IllegalArgumentException e) { - throw invalidSizeF(string); - } - } - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - return Float.floatToIntBits(mWidth) ^ Float.floatToIntBits(mHeight); - } - - private final float mWidth; - private final float mHeight; -} diff --git a/src/main/java/android/util/Slog.java b/src/main/java/android/util/Slog.java deleted file mode 100644 index 58a2703..0000000 --- a/src/main/java/android/util/Slog.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -/** - * @hide - */ -public final class Slog { - - private Slog() { - } - - public static int v(String tag, String msg) { - return Log.println_native(Log.LOG_ID_SYSTEM, Log.VERBOSE, tag, msg); - } - - public static int v(String tag, String msg, Throwable tr) { - return Log.println_native(Log.LOG_ID_SYSTEM, Log.VERBOSE, tag, - msg + '\n' + Log.getStackTraceString(tr)); - } - - public static int d(String tag, String msg) { - return Log.println_native(Log.LOG_ID_SYSTEM, Log.DEBUG, tag, msg); - } - - public static int d(String tag, String msg, Throwable tr) { - return Log.println_native(Log.LOG_ID_SYSTEM, Log.DEBUG, tag, - msg + '\n' + Log.getStackTraceString(tr)); - } - - public static int i(String tag, String msg) { - return Log.println_native(Log.LOG_ID_SYSTEM, Log.INFO, tag, msg); - } - - public static int i(String tag, String msg, Throwable tr) { - return Log.println_native(Log.LOG_ID_SYSTEM, Log.INFO, tag, - msg + '\n' + Log.getStackTraceString(tr)); - } - - public static int w(String tag, String msg) { - return Log.println_native(Log.LOG_ID_SYSTEM, Log.WARN, tag, msg); - } - - public static int w(String tag, String msg, Throwable tr) { - return Log.println_native(Log.LOG_ID_SYSTEM, Log.WARN, tag, - msg + '\n' + Log.getStackTraceString(tr)); - } - - public static int w(String tag, Throwable tr) { - return Log.println_native(Log.LOG_ID_SYSTEM, Log.WARN, tag, Log.getStackTraceString(tr)); - } - - public static int e(String tag, String msg) { - return Log.println_native(Log.LOG_ID_SYSTEM, Log.ERROR, tag, msg); - } - - public static int e(String tag, String msg, Throwable tr) { - return Log.println_native(Log.LOG_ID_SYSTEM, Log.ERROR, tag, - msg + '\n' + Log.getStackTraceString(tr)); - } - - /** - * Like {@link Log#wtf(String, String)}, but will never cause the caller to crash, and - * will always be handled asynchronously. Primarily for use by coding running within - * the system process. - */ - public static int wtf(String tag, String msg) { - return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, null, false, true); - } - - /** - * Like {@link #wtf(String, String)}, but does not output anything to the log. - */ - public static void wtfQuiet(String tag, String msg) { - Log.wtfQuiet(Log.LOG_ID_SYSTEM, tag, msg, true); - } - - /** - * Like {@link Log#wtfStack(String, String)}, but will never cause the caller to crash, and - * will always be handled asynchronously. Primarily for use by coding running within - * the system process. - */ - public static int wtfStack(String tag, String msg) { - return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, null, true, true); - } - - /** - * Like {@link Log#wtf(String, Throwable)}, but will never cause the caller to crash, - * and will always be handled asynchronously. Primarily for use by coding running within - * the system process. - */ - public static int wtf(String tag, Throwable tr) { - return Log.wtf(Log.LOG_ID_SYSTEM, tag, tr.getMessage(), tr, false, true); - } - - /** - * Like {@link Log#wtf(String, String, Throwable)}, but will never cause the caller to crash, - * and will always be handled asynchronously. Primarily for use by coding running within - * the system process. - */ - public static int wtf(String tag, String msg, Throwable tr) { - return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, tr, false, true); - } - - public static int println(int priority, String tag, String msg) { - return Log.println_native(Log.LOG_ID_SYSTEM, priority, tag, msg); - } -} - diff --git a/src/main/java/android/util/SparseArray.java b/src/main/java/android/util/SparseArray.java deleted file mode 100644 index 92e874f..0000000 --- a/src/main/java/android/util/SparseArray.java +++ /dev/null @@ -1,390 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import com.android.internal.util.ArrayUtils; -import com.android.internal.util.GrowingArrayUtils; - -import libcore.util.EmptyArray; - -/** - * SparseArrays map integers to Objects. Unlike a normal array of Objects, - * there can be gaps in the indices. It is intended to be more memory efficient - * than using a HashMap to map Integers to Objects, both because it avoids - * auto-boxing keys and its data structure doesn't rely on an extra entry object - * for each mapping. - * - *

    Note that this container keeps its mappings in an array data structure, - * using a binary search to find keys. The implementation is not intended to be appropriate for - * data structures - * that may contain large numbers of items. It is generally slower than a traditional - * HashMap, since lookups require a binary search and adds and removes require inserting - * and deleting entries in the array. For containers holding up to hundreds of items, - * the performance difference is not significant, less than 50%.

    - * - *

    To help with performance, the container includes an optimization when removing - * keys: instead of compacting its array immediately, it leaves the removed entry marked - * as deleted. The entry can then be re-used for the same key, or compacted later in - * a single garbage collection step of all removed entries. This garbage collection will - * need to be performed at any time the array needs to be grown or the the map size or - * entry values are retrieved.

    - * - *

    It is possible to iterate over the items in this container using - * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using - * keyAt(int) with ascending values of the index will return the - * keys in ascending order, or the values corresponding to the keys in ascending - * order in the case of valueAt(int).

    - */ -public class SparseArray implements Cloneable { - private static final Object DELETED = new Object(); - private boolean mGarbage = false; - - private int[] mKeys; - private Object[] mValues; - private int mSize; - - /** - * Creates a new SparseArray containing no mappings. - */ - public SparseArray() { - this(10); - } - - /** - * Creates a new SparseArray containing no mappings that will not - * require any additional memory allocation to store the specified - * number of mappings. If you supply an initial capacity of 0, the - * sparse array will be initialized with a light-weight representation - * not requiring any additional array allocations. - */ - public SparseArray(int initialCapacity) { - if (initialCapacity == 0) { - mKeys = EmptyArray.INT; - mValues = EmptyArray.OBJECT; - } else { - mValues = ArrayUtils.newUnpaddedObjectArray(initialCapacity); - mKeys = new int[mValues.length]; - } - mSize = 0; - } - - @Override - @SuppressWarnings("unchecked") - public SparseArray clone() { - SparseArray clone = null; - try { - clone = (SparseArray) super.clone(); - clone.mKeys = mKeys.clone(); - clone.mValues = mValues.clone(); - } catch (CloneNotSupportedException cnse) { - /* ignore */ - } - return clone; - } - - /** - * Gets the Object mapped from the specified key, or null - * if no such mapping has been made. - */ - public E get(int key) { - return get(key, null); - } - - /** - * Gets the Object mapped from the specified key, or the specified Object - * if no such mapping has been made. - */ - @SuppressWarnings("unchecked") - public E get(int key, E valueIfKeyNotFound) { - int i = ContainerHelpers.binarySearch(mKeys, mSize, key); - - if (i < 0 || mValues[i] == DELETED) { - return valueIfKeyNotFound; - } else { - return (E) mValues[i]; - } - } - - /** - * Removes the mapping from the specified key, if there was any. - */ - public void delete(int key) { - int i = ContainerHelpers.binarySearch(mKeys, mSize, key); - - if (i >= 0) { - if (mValues[i] != DELETED) { - mValues[i] = DELETED; - mGarbage = true; - } - } - } - - /** - * Alias for {@link #delete(int)}. - */ - public void remove(int key) { - delete(key); - } - - /** - * Removes the mapping at the specified index. - */ - public void removeAt(int index) { - if (mValues[index] != DELETED) { - mValues[index] = DELETED; - mGarbage = true; - } - } - - /** - * Remove a range of mappings as a batch. - * - * @param index Index to begin at - * @param size Number of mappings to remove - */ - public void removeAtRange(int index, int size) { - final int end = Math.min(mSize, index + size); - for (int i = index; i < end; i++) { - removeAt(i); - } - } - - private void gc() { - // Log.e("SparseArray", "gc start with " + mSize); - - int n = mSize; - int o = 0; - int[] keys = mKeys; - Object[] values = mValues; - - for (int i = 0; i < n; i++) { - Object val = values[i]; - - if (val != DELETED) { - if (i != o) { - keys[o] = keys[i]; - values[o] = val; - values[i] = null; - } - - o++; - } - } - - mGarbage = false; - mSize = o; - - // Log.e("SparseArray", "gc end with " + mSize); - } - - /** - * Adds a mapping from the specified key to the specified value, - * replacing the previous mapping from the specified key if there - * was one. - */ - public void put(int key, E value) { - int i = ContainerHelpers.binarySearch(mKeys, mSize, key); - - if (i >= 0) { - mValues[i] = value; - } else { - i = ~i; - - if (i < mSize && mValues[i] == DELETED) { - mKeys[i] = key; - mValues[i] = value; - return; - } - - if (mGarbage && mSize >= mKeys.length) { - gc(); - - // Search again because indices may have changed. - i = ~ContainerHelpers.binarySearch(mKeys, mSize, key); - } - - mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key); - mValues = GrowingArrayUtils.insert(mValues, mSize, i, value); - mSize++; - } - } - - /** - * Returns the number of key-value mappings that this SparseArray - * currently stores. - */ - public int size() { - if (mGarbage) { - gc(); - } - - return mSize; - } - - /** - * Given an index in the range 0...size()-1, returns - * the key from the indexth key-value mapping that this - * SparseArray stores. - * - *

    The keys corresponding to indices in ascending order are guaranteed to - * be in ascending order, e.g., keyAt(0) will return the - * smallest key and keyAt(size()-1) will return the largest - * key.

    - */ - public int keyAt(int index) { - if (mGarbage) { - gc(); - } - - return mKeys[index]; - } - - /** - * Given an index in the range 0...size()-1, returns - * the value from the indexth key-value mapping that this - * SparseArray stores. - * - *

    The values corresponding to indices in ascending order are guaranteed - * to be associated with keys in ascending order, e.g., - * valueAt(0) will return the value associated with the - * smallest key and valueAt(size()-1) will return the value - * associated with the largest key.

    - */ - @SuppressWarnings("unchecked") - public E valueAt(int index) { - if (mGarbage) { - gc(); - } - - return (E) mValues[index]; - } - - /** - * Given an index in the range 0...size()-1, sets a new - * value for the indexth key-value mapping that this - * SparseArray stores. - */ - public void setValueAt(int index, E value) { - if (mGarbage) { - gc(); - } - - mValues[index] = value; - } - - /** - * Returns the index for which {@link #keyAt} would return the - * specified key, or a negative number if the specified - * key is not mapped. - */ - public int indexOfKey(int key) { - if (mGarbage) { - gc(); - } - - return ContainerHelpers.binarySearch(mKeys, mSize, key); - } - - /** - * Returns an index for which {@link #valueAt} would return the - * specified key, or a negative number if no keys map to the - * specified value. - *

    Beware that this is a linear search, unlike lookups by key, - * and that multiple keys can map to the same value and this will - * find only one of them. - *

    Note also that unlike most collections' {@code indexOf} methods, - * this method compares values using {@code ==} rather than {@code equals}. - */ - public int indexOfValue(E value) { - if (mGarbage) { - gc(); - } - - for (int i = 0; i < mSize; i++) - if (mValues[i] == value) - return i; - - return -1; - } - - /** - * Removes all key-value mappings from this SparseArray. - */ - public void clear() { - int n = mSize; - Object[] values = mValues; - - for (int i = 0; i < n; i++) { - values[i] = null; - } - - mSize = 0; - mGarbage = false; - } - - /** - * Puts a key/value pair into the array, optimizing for the case where - * the key is greater than all existing keys in the array. - */ - public void append(int key, E value) { - if (mSize != 0 && key <= mKeys[mSize - 1]) { - put(key, value); - return; - } - - if (mGarbage && mSize >= mKeys.length) { - gc(); - } - - mKeys = GrowingArrayUtils.append(mKeys, mSize, key); - mValues = GrowingArrayUtils.append(mValues, mSize, value); - mSize++; - } - - /** - * {@inheritDoc} - * - *

    This implementation composes a string by iterating over its mappings. If - * this map contains itself as a value, the string "(this Map)" - * will appear in its place. - */ - @Override - public String toString() { - if (size() <= 0) { - return "{}"; - } - - StringBuilder buffer = new StringBuilder(mSize * 28); - buffer.append('{'); - for (int i=0; i 0) { - buffer.append(", "); - } - int key = keyAt(i); - buffer.append(key); - buffer.append('='); - Object value = valueAt(i); - if (value != this) { - buffer.append(value); - } else { - buffer.append("(this Map)"); - } - } - buffer.append('}'); - return buffer.toString(); - } -} diff --git a/src/main/java/android/util/SparseBooleanArray.java b/src/main/java/android/util/SparseBooleanArray.java deleted file mode 100644 index e293b1f..0000000 --- a/src/main/java/android/util/SparseBooleanArray.java +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import com.android.internal.util.ArrayUtils; -import com.android.internal.util.GrowingArrayUtils; - -import libcore.util.EmptyArray; - -/** - * SparseBooleanArrays map integers to booleans. - * Unlike a normal array of booleans - * there can be gaps in the indices. It is intended to be more memory efficient - * than using a HashMap to map Integers to Booleans, both because it avoids - * auto-boxing keys and values and its data structure doesn't rely on an extra entry object - * for each mapping. - * - *

    Note that this container keeps its mappings in an array data structure, - * using a binary search to find keys. The implementation is not intended to be appropriate for - * data structures - * that may contain large numbers of items. It is generally slower than a traditional - * HashMap, since lookups require a binary search and adds and removes require inserting - * and deleting entries in the array. For containers holding up to hundreds of items, - * the performance difference is not significant, less than 50%.

    - * - *

    It is possible to iterate over the items in this container using - * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using - * keyAt(int) with ascending values of the index will return the - * keys in ascending order, or the values corresponding to the keys in ascending - * order in the case of valueAt(int).

    - */ -public class SparseBooleanArray implements Cloneable { - /** - * Creates a new SparseBooleanArray containing no mappings. - */ - public SparseBooleanArray() { - this(10); - } - - /** - * Creates a new SparseBooleanArray containing no mappings that will not - * require any additional memory allocation to store the specified - * number of mappings. If you supply an initial capacity of 0, the - * sparse array will be initialized with a light-weight representation - * not requiring any additional array allocations. - */ - public SparseBooleanArray(int initialCapacity) { - if (initialCapacity == 0) { - mKeys = EmptyArray.INT; - mValues = EmptyArray.BOOLEAN; - } else { - mKeys = ArrayUtils.newUnpaddedIntArray(initialCapacity); - mValues = new boolean[mKeys.length]; - } - mSize = 0; - } - - @Override - public SparseBooleanArray clone() { - SparseBooleanArray clone = null; - try { - clone = (SparseBooleanArray) super.clone(); - clone.mKeys = mKeys.clone(); - clone.mValues = mValues.clone(); - } catch (CloneNotSupportedException cnse) { - /* ignore */ - } - return clone; - } - - /** - * Gets the boolean mapped from the specified key, or false - * if no such mapping has been made. - */ - public boolean get(int key) { - return get(key, false); - } - - /** - * Gets the boolean mapped from the specified key, or the specified value - * if no such mapping has been made. - */ - public boolean get(int key, boolean valueIfKeyNotFound) { - int i = ContainerHelpers.binarySearch(mKeys, mSize, key); - - if (i < 0) { - return valueIfKeyNotFound; - } else { - return mValues[i]; - } - } - - /** - * Removes the mapping from the specified key, if there was any. - */ - public void delete(int key) { - int i = ContainerHelpers.binarySearch(mKeys, mSize, key); - - if (i >= 0) { - System.arraycopy(mKeys, i + 1, mKeys, i, mSize - (i + 1)); - System.arraycopy(mValues, i + 1, mValues, i, mSize - (i + 1)); - mSize--; - } - } - - /** @hide */ - public void removeAt(int index) { - System.arraycopy(mKeys, index + 1, mKeys, index, mSize - (index + 1)); - System.arraycopy(mValues, index + 1, mValues, index, mSize - (index + 1)); - mSize--; - } - - /** - * Adds a mapping from the specified key to the specified value, - * replacing the previous mapping from the specified key if there - * was one. - */ - public void put(int key, boolean value) { - int i = ContainerHelpers.binarySearch(mKeys, mSize, key); - - if (i >= 0) { - mValues[i] = value; - } else { - i = ~i; - - mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key); - mValues = GrowingArrayUtils.insert(mValues, mSize, i, value); - mSize++; - } - } - - /** - * Returns the number of key-value mappings that this SparseBooleanArray - * currently stores. - */ - public int size() { - return mSize; - } - - /** - * Given an index in the range 0...size()-1, returns - * the key from the indexth key-value mapping that this - * SparseBooleanArray stores. - * - *

    The keys corresponding to indices in ascending order are guaranteed to - * be in ascending order, e.g., keyAt(0) will return the - * smallest key and keyAt(size()-1) will return the largest - * key.

    - */ - public int keyAt(int index) { - return mKeys[index]; - } - - /** - * Given an index in the range 0...size()-1, returns - * the value from the indexth key-value mapping that this - * SparseBooleanArray stores. - * - *

    The values corresponding to indices in ascending order are guaranteed - * to be associated with keys in ascending order, e.g., - * valueAt(0) will return the value associated with the - * smallest key and valueAt(size()-1) will return the value - * associated with the largest key.

    - */ - public boolean valueAt(int index) { - return mValues[index]; - } - - /** @hide */ - public void setValueAt(int index, boolean value) { - mValues[index] = value; - } - - /** - * Returns the index for which {@link #keyAt} would return the - * specified key, or a negative number if the specified - * key is not mapped. - */ - public int indexOfKey(int key) { - return ContainerHelpers.binarySearch(mKeys, mSize, key); - } - - /** - * Returns an index for which {@link #valueAt} would return the - * specified key, or a negative number if no keys map to the - * specified value. - * Beware that this is a linear search, unlike lookups by key, - * and that multiple keys can map to the same value and this will - * find only one of them. - */ - public int indexOfValue(boolean value) { - for (int i = 0; i < mSize; i++) - if (mValues[i] == value) - return i; - - return -1; - } - - /** - * Removes all key-value mappings from this SparseBooleanArray. - */ - public void clear() { - mSize = 0; - } - - /** - * Puts a key/value pair into the array, optimizing for the case where - * the key is greater than all existing keys in the array. - */ - public void append(int key, boolean value) { - if (mSize != 0 && key <= mKeys[mSize - 1]) { - put(key, value); - return; - } - - mKeys = GrowingArrayUtils.append(mKeys, mSize, key); - mValues = GrowingArrayUtils.append(mValues, mSize, value); - mSize++; - } - - /** - * {@inheritDoc} - * - *

    This implementation composes a string by iterating over its mappings. - */ - @Override - public String toString() { - if (size() <= 0) { - return "{}"; - } - - StringBuilder buffer = new StringBuilder(mSize * 28); - buffer.append('{'); - for (int i=0; i 0) { - buffer.append(", "); - } - int key = keyAt(i); - buffer.append(key); - buffer.append('='); - boolean value = valueAt(i); - buffer.append(value); - } - buffer.append('}'); - return buffer.toString(); - } - - private int[] mKeys; - private boolean[] mValues; - private int mSize; -} diff --git a/src/main/java/android/util/SparseIntArray.java b/src/main/java/android/util/SparseIntArray.java deleted file mode 100644 index 2b85a21..0000000 --- a/src/main/java/android/util/SparseIntArray.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import com.android.internal.util.ArrayUtils; -import com.android.internal.util.GrowingArrayUtils; - -import libcore.util.EmptyArray; - -/** - * SparseIntArrays map integers to integers. Unlike a normal array of integers, - * there can be gaps in the indices. It is intended to be more memory efficient - * than using a HashMap to map Integers to Integers, both because it avoids - * auto-boxing keys and values and its data structure doesn't rely on an extra entry object - * for each mapping. - * - *

    Note that this container keeps its mappings in an array data structure, - * using a binary search to find keys. The implementation is not intended to be appropriate for - * data structures - * that may contain large numbers of items. It is generally slower than a traditional - * HashMap, since lookups require a binary search and adds and removes require inserting - * and deleting entries in the array. For containers holding up to hundreds of items, - * the performance difference is not significant, less than 50%.

    - * - *

    It is possible to iterate over the items in this container using - * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using - * keyAt(int) with ascending values of the index will return the - * keys in ascending order, or the values corresponding to the keys in ascending - * order in the case of valueAt(int).

    - */ -public class SparseIntArray implements Cloneable { - private int[] mKeys; - private int[] mValues; - private int mSize; - - /** - * Creates a new SparseIntArray containing no mappings. - */ - public SparseIntArray() { - this(10); - } - - /** - * Creates a new SparseIntArray containing no mappings that will not - * require any additional memory allocation to store the specified - * number of mappings. If you supply an initial capacity of 0, the - * sparse array will be initialized with a light-weight representation - * not requiring any additional array allocations. - */ - public SparseIntArray(int initialCapacity) { - if (initialCapacity == 0) { - mKeys = EmptyArray.INT; - mValues = EmptyArray.INT; - } else { - mKeys = ArrayUtils.newUnpaddedIntArray(initialCapacity); - mValues = new int[mKeys.length]; - } - mSize = 0; - } - - @Override - public SparseIntArray clone() { - SparseIntArray clone = null; - try { - clone = (SparseIntArray) super.clone(); - clone.mKeys = mKeys.clone(); - clone.mValues = mValues.clone(); - } catch (CloneNotSupportedException cnse) { - /* ignore */ - } - return clone; - } - - /** - * Gets the int mapped from the specified key, or 0 - * if no such mapping has been made. - */ - public int get(int key) { - return get(key, 0); - } - - /** - * Gets the int mapped from the specified key, or the specified value - * if no such mapping has been made. - */ - public int get(int key, int valueIfKeyNotFound) { - int i = ContainerHelpers.binarySearch(mKeys, mSize, key); - - if (i < 0) { - return valueIfKeyNotFound; - } else { - return mValues[i]; - } - } - - /** - * Removes the mapping from the specified key, if there was any. - */ - public void delete(int key) { - int i = ContainerHelpers.binarySearch(mKeys, mSize, key); - - if (i >= 0) { - removeAt(i); - } - } - - /** - * Removes the mapping at the given index. - */ - public void removeAt(int index) { - System.arraycopy(mKeys, index + 1, mKeys, index, mSize - (index + 1)); - System.arraycopy(mValues, index + 1, mValues, index, mSize - (index + 1)); - mSize--; - } - - /** - * Adds a mapping from the specified key to the specified value, - * replacing the previous mapping from the specified key if there - * was one. - */ - public void put(int key, int value) { - int i = ContainerHelpers.binarySearch(mKeys, mSize, key); - - if (i >= 0) { - mValues[i] = value; - } else { - i = ~i; - - mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key); - mValues = GrowingArrayUtils.insert(mValues, mSize, i, value); - mSize++; - } - } - - /** - * Returns the number of key-value mappings that this SparseIntArray - * currently stores. - */ - public int size() { - return mSize; - } - - /** - * Given an index in the range 0...size()-1, returns - * the key from the indexth key-value mapping that this - * SparseIntArray stores. - * - *

    The keys corresponding to indices in ascending order are guaranteed to - * be in ascending order, e.g., keyAt(0) will return the - * smallest key and keyAt(size()-1) will return the largest - * key.

    - */ - public int keyAt(int index) { - return mKeys[index]; - } - - /** - * Given an index in the range 0...size()-1, returns - * the value from the indexth key-value mapping that this - * SparseIntArray stores. - * - *

    The values corresponding to indices in ascending order are guaranteed - * to be associated with keys in ascending order, e.g., - * valueAt(0) will return the value associated with the - * smallest key and valueAt(size()-1) will return the value - * associated with the largest key.

    - */ - public int valueAt(int index) { - return mValues[index]; - } - - /** - * Returns the index for which {@link #keyAt} would return the - * specified key, or a negative number if the specified - * key is not mapped. - */ - public int indexOfKey(int key) { - return ContainerHelpers.binarySearch(mKeys, mSize, key); - } - - /** - * Returns an index for which {@link #valueAt} would return the - * specified key, or a negative number if no keys map to the - * specified value. - * Beware that this is a linear search, unlike lookups by key, - * and that multiple keys can map to the same value and this will - * find only one of them. - */ - public int indexOfValue(int value) { - for (int i = 0; i < mSize; i++) - if (mValues[i] == value) - return i; - - return -1; - } - - /** - * Removes all key-value mappings from this SparseIntArray. - */ - public void clear() { - mSize = 0; - } - - /** - * Puts a key/value pair into the array, optimizing for the case where - * the key is greater than all existing keys in the array. - */ - public void append(int key, int value) { - if (mSize != 0 && key <= mKeys[mSize - 1]) { - put(key, value); - return; - } - - mKeys = GrowingArrayUtils.append(mKeys, mSize, key); - mValues = GrowingArrayUtils.append(mValues, mSize, value); - mSize++; - } - - /** - * {@inheritDoc} - * - *

    This implementation composes a string by iterating over its mappings. - */ - @Override - public String toString() { - if (size() <= 0) { - return "{}"; - } - - StringBuilder buffer = new StringBuilder(mSize * 28); - buffer.append('{'); - for (int i=0; i 0) { - buffer.append(", "); - } - int key = keyAt(i); - buffer.append(key); - buffer.append('='); - int value = valueAt(i); - buffer.append(value); - } - buffer.append('}'); - return buffer.toString(); - } -} diff --git a/src/main/java/android/util/SparseLongArray.java b/src/main/java/android/util/SparseLongArray.java deleted file mode 100644 index 0166c4a..0000000 --- a/src/main/java/android/util/SparseLongArray.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (C) 2011 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.util; - -import com.android.internal.util.ArrayUtils; -import com.android.internal.util.GrowingArrayUtils; - -import libcore.util.EmptyArray; - -/** - * SparseLongArrays map integers to longs. Unlike a normal array of longs, - * there can be gaps in the indices. It is intended to be more memory efficient - * than using a HashMap to map Integers to Longs, both because it avoids - * auto-boxing keys and values and its data structure doesn't rely on an extra entry object - * for each mapping. - * - *

    Note that this container keeps its mappings in an array data structure, - * using a binary search to find keys. The implementation is not intended to be appropriate for - * data structures - * that may contain large numbers of items. It is generally slower than a traditional - * HashMap, since lookups require a binary search and adds and removes require inserting - * and deleting entries in the array. For containers holding up to hundreds of items, - * the performance difference is not significant, less than 50%.

    - * - *

    It is possible to iterate over the items in this container using - * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using - * keyAt(int) with ascending values of the index will return the - * keys in ascending order, or the values corresponding to the keys in ascending - * order in the case of valueAt(int).

    - */ -public class SparseLongArray implements Cloneable { - private int[] mKeys; - private long[] mValues; - private int mSize; - - /** - * Creates a new SparseLongArray containing no mappings. - */ - public SparseLongArray() { - this(10); - } - - /** - * Creates a new SparseLongArray containing no mappings that will not - * require any additional memory allocation to store the specified - * number of mappings. If you supply an initial capacity of 0, the - * sparse array will be initialized with a light-weight representation - * not requiring any additional array allocations. - */ - public SparseLongArray(int initialCapacity) { - if (initialCapacity == 0) { - mKeys = EmptyArray.INT; - mValues = EmptyArray.LONG; - } else { - mValues = ArrayUtils.newUnpaddedLongArray(initialCapacity); - mKeys = new int[mValues.length]; - } - mSize = 0; - } - - @Override - public SparseLongArray clone() { - SparseLongArray clone = null; - try { - clone = (SparseLongArray) super.clone(); - clone.mKeys = mKeys.clone(); - clone.mValues = mValues.clone(); - } catch (CloneNotSupportedException cnse) { - /* ignore */ - } - return clone; - } - - /** - * Gets the long mapped from the specified key, or 0 - * if no such mapping has been made. - */ - public long get(int key) { - return get(key, 0); - } - - /** - * Gets the long mapped from the specified key, or the specified value - * if no such mapping has been made. - */ - public long get(int key, long valueIfKeyNotFound) { - int i = ContainerHelpers.binarySearch(mKeys, mSize, key); - - if (i < 0) { - return valueIfKeyNotFound; - } else { - return mValues[i]; - } - } - - /** - * Removes the mapping from the specified key, if there was any. - */ - public void delete(int key) { - int i = ContainerHelpers.binarySearch(mKeys, mSize, key); - - if (i >= 0) { - removeAt(i); - } - } - - /** - * Removes the mapping at the given index. - */ - public void removeAt(int index) { - System.arraycopy(mKeys, index + 1, mKeys, index, mSize - (index + 1)); - System.arraycopy(mValues, index + 1, mValues, index, mSize - (index + 1)); - mSize--; - } - - /** - * Adds a mapping from the specified key to the specified value, - * replacing the previous mapping from the specified key if there - * was one. - */ - public void put(int key, long value) { - int i = ContainerHelpers.binarySearch(mKeys, mSize, key); - - if (i >= 0) { - mValues[i] = value; - } else { - i = ~i; - - mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key); - mValues = GrowingArrayUtils.insert(mValues, mSize, i, value); - mSize++; - } - } - - /** - * Returns the number of key-value mappings that this SparseIntArray - * currently stores. - */ - public int size() { - return mSize; - } - - /** - * Given an index in the range 0...size()-1, returns - * the key from the indexth key-value mapping that this - * SparseLongArray stores. - * - *

    The keys corresponding to indices in ascending order are guaranteed to - * be in ascending order, e.g., keyAt(0) will return the - * smallest key and keyAt(size()-1) will return the largest - * key.

    - */ - public int keyAt(int index) { - return mKeys[index]; - } - - /** - * Given an index in the range 0...size()-1, returns - * the value from the indexth key-value mapping that this - * SparseLongArray stores. - * - *

    The values corresponding to indices in ascending order are guaranteed - * to be associated with keys in ascending order, e.g., - * valueAt(0) will return the value associated with the - * smallest key and valueAt(size()-1) will return the value - * associated with the largest key.

    - */ - public long valueAt(int index) { - return mValues[index]; - } - - /** - * Returns the index for which {@link #keyAt} would return the - * specified key, or a negative number if the specified - * key is not mapped. - */ - public int indexOfKey(int key) { - return ContainerHelpers.binarySearch(mKeys, mSize, key); - } - - /** - * Returns an index for which {@link #valueAt} would return the - * specified key, or a negative number if no keys map to the - * specified value. - * Beware that this is a linear search, unlike lookups by key, - * and that multiple keys can map to the same value and this will - * find only one of them. - */ - public int indexOfValue(long value) { - for (int i = 0; i < mSize; i++) - if (mValues[i] == value) - return i; - - return -1; - } - - /** - * Removes all key-value mappings from this SparseIntArray. - */ - public void clear() { - mSize = 0; - } - - /** - * Puts a key/value pair into the array, optimizing for the case where - * the key is greater than all existing keys in the array. - */ - public void append(int key, long value) { - if (mSize != 0 && key <= mKeys[mSize - 1]) { - put(key, value); - return; - } - - mKeys = GrowingArrayUtils.append(mKeys, mSize, key); - mValues = GrowingArrayUtils.append(mValues, mSize, value); - mSize++; - } - - /** - * {@inheritDoc} - * - *

    This implementation composes a string by iterating over its mappings. - */ - @Override - public String toString() { - if (size() <= 0) { - return "{}"; - } - - StringBuilder buffer = new StringBuilder(mSize * 28); - buffer.append('{'); - for (int i=0; i 0) { - buffer.append(", "); - } - int key = keyAt(i); - buffer.append(key); - buffer.append('='); - long value = valueAt(i); - buffer.append(value); - } - buffer.append('}'); - return buffer.toString(); - } -} diff --git a/src/main/java/android/util/Spline.java b/src/main/java/android/util/Spline.java deleted file mode 100644 index 41a2e5d..0000000 --- a/src/main/java/android/util/Spline.java +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -/** - * Performs spline interpolation given a set of control points. - * @hide - */ -public abstract class Spline { - - /** - * Interpolates the value of Y = f(X) for given X. - * Clamps X to the domain of the spline. - * - * @param x The X value. - * @return The interpolated Y = f(X) value. - */ - public abstract float interpolate(float x); - - /** - * Creates an appropriate spline based on the properties of the control points. - * - * If the control points are monotonic then the resulting spline will preserve that and - * otherwise optimize for error bounds. - */ - public static Spline createSpline(float[] x, float[] y) { - if (!isStrictlyIncreasing(x)) { - throw new IllegalArgumentException("The control points must all have strictly " - + "increasing X values."); - } - - if (isMonotonic(y)) { - return createMonotoneCubicSpline(x, y); - } else { - return createLinearSpline(x, y); - } - } - - /** - * Creates a monotone cubic spline from a given set of control points. - * - * The spline is guaranteed to pass through each control point exactly. - * Moreover, assuming the control points are monotonic (Y is non-decreasing or - * non-increasing) then the interpolated values will also be monotonic. - * - * This function uses the Fritsch-Carlson method for computing the spline parameters. - * http://en.wikipedia.org/wiki/Monotone_cubic_interpolation - * - * @param x The X component of the control points, strictly increasing. - * @param y The Y component of the control points, monotonic. - * @return - * - * @throws IllegalArgumentException if the X or Y arrays are null, have - * different lengths or have fewer than 2 values. - * @throws IllegalArgumentException if the control points are not monotonic. - */ - public static Spline createMonotoneCubicSpline(float[] x, float[] y) { - return new MonotoneCubicSpline(x, y); - } - - /** - * Creates a linear spline from a given set of control points. - * - * Like a monotone cubic spline, the interpolated curve will be monotonic if the control points - * are monotonic. - * - * @param x The X component of the control points, strictly increasing. - * @param y The Y component of the control points. - * @return - * - * @throws IllegalArgumentException if the X or Y arrays are null, have - * different lengths or have fewer than 2 values. - * @throws IllegalArgumentException if the X components of the control points are not strictly - * increasing. - */ - public static Spline createLinearSpline(float[] x, float[] y) { - return new LinearSpline(x, y); - } - - private static boolean isStrictlyIncreasing(float[] x) { - if (x == null || x.length < 2) { - throw new IllegalArgumentException("There must be at least two control points."); - } - float prev = x[0]; - for (int i = 1; i < x.length; i++) { - float curr = x[i]; - if (curr <= prev) { - return false; - } - prev = curr; - } - return true; - } - - private static boolean isMonotonic(float[] x) { - if (x == null || x.length < 2) { - throw new IllegalArgumentException("There must be at least two control points."); - } - float prev = x[0]; - for (int i = 1; i < x.length; i++) { - float curr = x[i]; - if (curr < prev) { - return false; - } - prev = curr; - } - return true; - } - - public static class MonotoneCubicSpline extends Spline { - private float[] mX; - private float[] mY; - private float[] mM; - - public MonotoneCubicSpline(float[] x, float[] y) { - if (x == null || y == null || x.length != y.length || x.length < 2) { - throw new IllegalArgumentException("There must be at least two control " - + "points and the arrays must be of equal length."); - } - - final int n = x.length; - float[] d = new float[n - 1]; // could optimize this out - float[] m = new float[n]; - - // Compute slopes of secant lines between successive points. - for (int i = 0; i < n - 1; i++) { - float h = x[i + 1] - x[i]; - if (h <= 0f) { - throw new IllegalArgumentException("The control points must all " - + "have strictly increasing X values."); - } - d[i] = (y[i + 1] - y[i]) / h; - } - - // Initialize the tangents as the average of the secants. - m[0] = d[0]; - for (int i = 1; i < n - 1; i++) { - m[i] = (d[i - 1] + d[i]) * 0.5f; - } - m[n - 1] = d[n - 2]; - - // Update the tangents to preserve monotonicity. - for (int i = 0; i < n - 1; i++) { - if (d[i] == 0f) { // successive Y values are equal - m[i] = 0f; - m[i + 1] = 0f; - } else { - float a = m[i] / d[i]; - float b = m[i + 1] / d[i]; - if (a < 0f || b < 0f) { - throw new IllegalArgumentException("The control points must have " - + "monotonic Y values."); - } - float h = FloatMath.hypot(a, b); - if (h > 9f) { - float t = 3f / h; - m[i] = t * a * d[i]; - m[i + 1] = t * b * d[i]; - } - } - } - - mX = x; - mY = y; - mM = m; - } - - @Override - public float interpolate(float x) { - // Handle the boundary cases. - final int n = mX.length; - if (Float.isNaN(x)) { - return x; - } - if (x <= mX[0]) { - return mY[0]; - } - if (x >= mX[n - 1]) { - return mY[n - 1]; - } - - // Find the index 'i' of the last point with smaller X. - // We know this will be within the spline due to the boundary tests. - int i = 0; - while (x >= mX[i + 1]) { - i += 1; - if (x == mX[i]) { - return mY[i]; - } - } - - // Perform cubic Hermite spline interpolation. - float h = mX[i + 1] - mX[i]; - float t = (x - mX[i]) / h; - return (mY[i] * (1 + 2 * t) + h * mM[i] * t) * (1 - t) * (1 - t) - + (mY[i + 1] * (3 - 2 * t) + h * mM[i + 1] * (t - 1)) * t * t; - } - - // For debugging. - @Override - public String toString() { - StringBuilder str = new StringBuilder(); - final int n = mX.length; - str.append("MonotoneCubicSpline{["); - for (int i = 0; i < n; i++) { - if (i != 0) { - str.append(", "); - } - str.append("(").append(mX[i]); - str.append(", ").append(mY[i]); - str.append(": ").append(mM[i]).append(")"); - } - str.append("]}"); - return str.toString(); - } - } - - public static class LinearSpline extends Spline { - private final float[] mX; - private final float[] mY; - private final float[] mM; - - public LinearSpline(float[] x, float[] y) { - if (x == null || y == null || x.length != y.length || x.length < 2) { - throw new IllegalArgumentException("There must be at least two control " - + "points and the arrays must be of equal length."); - } - final int N = x.length; - mM = new float[N-1]; - for (int i = 0; i < N-1; i++) { - mM[i] = (y[i+1] - y[i]) / (x[i+1] - x[i]); - } - mX = x; - mY = y; - } - - @Override - public float interpolate(float x) { - // Handle the boundary cases. - final int n = mX.length; - if (Float.isNaN(x)) { - return x; - } - if (x <= mX[0]) { - return mY[0]; - } - if (x >= mX[n - 1]) { - return mY[n - 1]; - } - - // Find the index 'i' of the last point with smaller X. - // We know this will be within the spline due to the boundary tests. - int i = 0; - while (x >= mX[i + 1]) { - i += 1; - if (x == mX[i]) { - return mY[i]; - } - } - return mY[i] + mM[i] * (x - mX[i]); - } - - @Override - public String toString() { - StringBuilder str = new StringBuilder(); - final int n = mX.length; - str.append("LinearSpline{["); - for (int i = 0; i < n; i++) { - if (i != 0) { - str.append(", "); - } - str.append("(").append(mX[i]); - str.append(", ").append(mY[i]); - if (i < n-1) { - str.append(": ").append(mM[i]); - } - str.append(")"); - } - str.append("]}"); - return str.toString(); - } - } -} diff --git a/src/main/java/android/util/StateSet.java b/src/main/java/android/util/StateSet.java deleted file mode 100644 index 2623638..0000000 --- a/src/main/java/android/util/StateSet.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import com.android.internal.R; - -/** - * State sets are arrays of positive ints where each element - * represents the state of a {@link android.view.View} (e.g. focused, - * selected, visible, etc.). A {@link android.view.View} may be in - * one or more of those states. - * - * A state spec is an array of signed ints where each element - * represents a required (if positive) or an undesired (if negative) - * {@link android.view.View} state. - * - * Utils dealing with state sets. - * - * In theory we could encapsulate the state set and state spec arrays - * and not have static methods here but there is some concern about - * performance since these methods are called during view drawing. - */ - -public class StateSet { - /** @hide */ public StateSet() {} - - public static final int[] WILD_CARD = new int[0]; - public static final int[] NOTHING = new int[] { 0 }; - - /** - * Return whether the stateSetOrSpec is matched by all StateSets. - * - * @param stateSetOrSpec a state set or state spec. - */ - public static boolean isWildCard(int[] stateSetOrSpec) { - return stateSetOrSpec.length == 0 || stateSetOrSpec[0] == 0; - } - - /** - * Return whether the stateSet matches the desired stateSpec. - * - * @param stateSpec an array of required (if positive) or - * prohibited (if negative) {@link android.view.View} states. - * @param stateSet an array of {@link android.view.View} states - */ - public static boolean stateSetMatches(int[] stateSpec, int[] stateSet) { - if (stateSet == null) { - return (stateSpec == null || isWildCard(stateSpec)); - } - int stateSpecSize = stateSpec.length; - int stateSetSize = stateSet.length; - for (int i = 0; i < stateSpecSize; i++) { - int stateSpecState = stateSpec[i]; - if (stateSpecState == 0) { - // We've reached the end of the cases to match against. - return true; - } - final boolean mustMatch; - if (stateSpecState > 0) { - mustMatch = true; - } else { - // We use negative values to indicate must-NOT-match states. - mustMatch = false; - stateSpecState = -stateSpecState; - } - boolean found = false; - for (int j = 0; j < stateSetSize; j++) { - final int state = stateSet[j]; - if (state == 0) { - // We've reached the end of states to match. - if (mustMatch) { - // We didn't find this must-match state. - return false; - } else { - // Continue checking other must-not-match states. - break; - } - } - if (state == stateSpecState) { - if (mustMatch) { - found = true; - // Continue checking other other must-match states. - break; - } else { - // Any match of a must-not-match state returns false. - return false; - } - } - } - if (mustMatch && !found) { - // We've reached the end of states to match and we didn't - // find a must-match state. - return false; - } - } - return true; - } - - /** - * Return whether the state matches the desired stateSpec. - * - * @param stateSpec an array of required (if positive) or - * prohibited (if negative) {@link android.view.View} states. - * @param state a {@link android.view.View} state - */ - public static boolean stateSetMatches(int[] stateSpec, int state) { - int stateSpecSize = stateSpec.length; - for (int i = 0; i < stateSpecSize; i++) { - int stateSpecState = stateSpec[i]; - if (stateSpecState == 0) { - // We've reached the end of the cases to match against. - return true; - } - if (stateSpecState > 0) { - if (state != stateSpecState) { - return false; - } - } else { - // We use negative values to indicate must-NOT-match states. - if (state == -stateSpecState) { - // We matched a must-not-match case. - return false; - } - } - } - return true; - } - - public static int[] trimStateSet(int[] states, int newSize) { - if (states.length == newSize) { - return states; - } - - int[] trimmedStates = new int[newSize]; - System.arraycopy(states, 0, trimmedStates, 0, newSize); - return trimmedStates; - } - - public static String dump(int[] states) { - StringBuilder sb = new StringBuilder(); - - int count = states.length; - for (int i = 0; i < count; i++) { - - switch (states[i]) { - case R.attr.state_window_focused: - sb.append("W "); - break; - case R.attr.state_pressed: - sb.append("P "); - break; - case R.attr.state_selected: - sb.append("S "); - break; - case R.attr.state_focused: - sb.append("F "); - break; - case R.attr.state_enabled: - sb.append("E "); - break; - } - } - - return sb.toString(); - } -} diff --git a/src/main/java/android/util/StateSetTest.java b/src/main/java/android/util/StateSetTest.java deleted file mode 100644 index e481ce0..0000000 --- a/src/main/java/android/util/StateSetTest.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import junit.framework.TestCase; -import android.test.suitebuilder.annotation.SmallTest; - -/** - * Tests for {@link StateSet} - */ - -public class StateSetTest extends TestCase { - - @SmallTest - public void testStateSetPositiveMatches() throws Exception { - int[] stateSpec = new int[2]; - int[] stateSet = new int[3]; - // Single states in both sets - match - stateSpec[0] = 1; - stateSet[0] = 1; - assertTrue(StateSet.stateSetMatches(stateSpec, stateSet)); - // Single states in both sets - non-match - stateSet[0] = 2; - assertFalse(StateSet.stateSetMatches(stateSpec, stateSet)); - // Add another state to the spec which the stateSet doesn't match - stateSpec[1] = 2; - assertFalse(StateSet.stateSetMatches(stateSpec, stateSet)); - // Add the missing matching element to the stateSet - stateSet[1] = 1; - assertTrue(StateSet.stateSetMatches(stateSpec, stateSet)); - // Add an irrelevent state to the stateSpec - stateSet[2] = 12345; - assertTrue(StateSet.stateSetMatches(stateSpec, stateSet)); - } - - @SmallTest - public void testStatesSetMatchMixEmUp() throws Exception { - int[] stateSpec = new int[2]; - int[] stateSet = new int[2]; - // One element in stateSpec which we must match and one which we must - // not match. stateSet only contains the match. - stateSpec[0] = 1; - stateSpec[1] = -2; - stateSet[0] = 1; - assertTrue(StateSet.stateSetMatches(stateSpec, stateSet)); - // stateSet now contains just the element we must not match - stateSet[0] = 2; - assertFalse(StateSet.stateSetMatches(stateSpec, stateSet)); - // Add another matching state to the the stateSet. We still fail - // because stateSet contains a must-not-match element - stateSet[1] = 1; - assertFalse(StateSet.stateSetMatches(stateSpec, stateSet)); - // Switch the must-not-match element in stateSet with a don't care - stateSet[0] = 12345; - assertTrue(StateSet.stateSetMatches(stateSpec, stateSet)); - } - - @SmallTest - public void testStateSetNegativeMatches() throws Exception { - int[] stateSpec = new int[2]; - int[] stateSet = new int[3]; - // Single states in both sets - match - stateSpec[0] = -1; - stateSet[0] = 2; - assertTrue(StateSet.stateSetMatches(stateSpec, stateSet)); - // Add another arrelevent state to the stateSet - stateSet[1] = 12345; - assertTrue(StateSet.stateSetMatches(stateSpec, stateSet)); - // Single states in both sets - non-match - stateSet[0] = 1; - assertFalse(StateSet.stateSetMatches(stateSpec, stateSet)); - // Add another state to the spec which the stateSet doesn't match - stateSpec[1] = -2; - assertFalse(StateSet.stateSetMatches(stateSpec, stateSet)); - // Add an irrelevent state to the stateSet - stateSet[2] = 12345; - assertFalse(StateSet.stateSetMatches(stateSpec, stateSet)); - } - - @SmallTest - public void testEmptySetMatchesNegtives() throws Exception { - int[] stateSpec = {-12345, -6789}; - int[] stateSet = new int[0]; - assertTrue(StateSet.stateSetMatches(stateSpec, stateSet)); - int[] stateSet2 = {0}; - assertTrue(StateSet.stateSetMatches(stateSpec, stateSet2)); - } - - @SmallTest - public void testEmptySetFailsPositives() throws Exception { - int[] stateSpec = {12345}; - int[] stateSet = new int[0]; - assertFalse(StateSet.stateSetMatches(stateSpec, stateSet)); - int[] stateSet2 = {0}; - assertFalse(StateSet.stateSetMatches(stateSpec, stateSet2)); - } - - @SmallTest - public void testEmptySetMatchesWildcard() throws Exception { - int[] stateSpec = StateSet.WILD_CARD; - int[] stateSet = new int[0]; - assertTrue(StateSet.stateSetMatches(stateSpec, stateSet)); - int[] stateSet2 = {0}; - assertTrue(StateSet.stateSetMatches(stateSpec, stateSet2)); - } - - @SmallTest - public void testSingleStatePositiveMatches() throws Exception { - int[] stateSpec = new int[2]; - int state; - // match - stateSpec[0] = 1; - state = 1; - assertTrue(StateSet.stateSetMatches(stateSpec, state)); - // non-match - state = 2; - assertFalse(StateSet.stateSetMatches(stateSpec, state)); - // add irrelevant must-not-match - stateSpec[1] = -12345; - assertFalse(StateSet.stateSetMatches(stateSpec, state)); - } - - @SmallTest - public void testSingleStateNegativeMatches() throws Exception { - int[] stateSpec = new int[2]; - int state; - // match - stateSpec[0] = -1; - state = 1; - assertFalse(StateSet.stateSetMatches(stateSpec, state)); - // non-match - state = 2; - assertTrue(StateSet.stateSetMatches(stateSpec, state)); - // add irrelevant must-not-match - stateSpec[1] = -12345; - assertTrue(StateSet.stateSetMatches(stateSpec, state)); - } - - @SmallTest - public void testZeroStateOnlyMatchesDefault() throws Exception { - int[] stateSpec = new int[3]; - int state = 0; - // non-match - stateSpec[0] = 1; - assertFalse(StateSet.stateSetMatches(stateSpec, state)); - // non-match - stateSpec[1] = -1; - assertFalse(StateSet.stateSetMatches(stateSpec, state)); - // match - stateSpec = StateSet.WILD_CARD; - assertTrue(StateSet.stateSetMatches(stateSpec, state)); - } - - @SmallTest - public void testNullStateOnlyMatchesDefault() throws Exception { - int[] stateSpec = new int[3]; - int[] stateSet = null; - // non-match - stateSpec[0] = 1; - assertFalse(StateSet.stateSetMatches(stateSpec, stateSet)); - // non-match - stateSpec[1] = -1; - assertFalse(StateSet.stateSetMatches(stateSpec, stateSet)); - // match - stateSpec = StateSet.WILD_CARD; - assertTrue(StateSet.stateSetMatches(stateSpec, stateSet)); - } -} diff --git a/src/main/java/android/util/StringBuilderPrinter.java b/src/main/java/android/util/StringBuilderPrinter.java deleted file mode 100644 index d0fc1e7..0000000 --- a/src/main/java/android/util/StringBuilderPrinter.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -/** - * Implementation of a {@link android.util.Printer} that sends its output - * to a {@link StringBuilder}. - */ -public class StringBuilderPrinter implements Printer { - private final StringBuilder mBuilder; - - /** - * Create a new Printer that sends to a StringBuilder object. - * - * @param builder The StringBuilder where you would like output to go. - */ - public StringBuilderPrinter(StringBuilder builder) { - mBuilder = builder; - } - - public void println(String x) { - mBuilder.append(x); - int len = x.length(); - if (len <= 0 || x.charAt(len-1) != '\n') { - mBuilder.append('\n'); - } - } -} diff --git a/src/main/java/android/util/SuperNotCalledException.java b/src/main/java/android/util/SuperNotCalledException.java deleted file mode 100644 index 1836142..0000000 --- a/src/main/java/android/util/SuperNotCalledException.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2013 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.util; - -/** - * @hide - */ -public final class SuperNotCalledException extends AndroidRuntimeException { - public SuperNotCalledException(String msg) { - super(msg); - } -} diff --git a/src/main/java/android/util/TimeFormatException.java b/src/main/java/android/util/TimeFormatException.java deleted file mode 100644 index f520523..0000000 --- a/src/main/java/android/util/TimeFormatException.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -public class TimeFormatException extends RuntimeException -{ - - /** - * @hide - */ - public TimeFormatException(String s) - { - super(s); - } -} - diff --git a/src/main/java/android/util/TimeUtils.java b/src/main/java/android/util/TimeUtils.java deleted file mode 100644 index f7d2821..0000000 --- a/src/main/java/android/util/TimeUtils.java +++ /dev/null @@ -1,424 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import android.content.res.Resources; -import android.content.res.XmlResourceParser; -import android.os.SystemClock; -import android.text.format.DateUtils; - -import com.android.internal.util.XmlUtils; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collection; -import java.util.Date; -import java.util.TimeZone; - -import libcore.util.ZoneInfoDB; - -/** - * A class containing utility methods related to time zones. - */ -public class TimeUtils { - /** @hide */ public TimeUtils() {} - private static final boolean DBG = false; - private static final String TAG = "TimeUtils"; - - /** Cached results of getTineZones */ - private static final Object sLastLockObj = new Object(); - private static ArrayList sLastZones = null; - private static String sLastCountry = null; - - /** Cached results of getTimeZonesWithUniqueOffsets */ - private static final Object sLastUniqueLockObj = new Object(); - private static ArrayList sLastUniqueZoneOffsets = null; - private static String sLastUniqueCountry = null; - - - /** - * Tries to return a time zone that would have had the specified offset - * and DST value at the specified moment in the specified country. - * Returns null if no suitable zone could be found. - */ - public static TimeZone getTimeZone(int offset, boolean dst, long when, String country) { - TimeZone best = null; - final Date d = new Date(when); - - TimeZone current = TimeZone.getDefault(); - String currentName = current.getID(); - int currentOffset = current.getOffset(when); - boolean currentDst = current.inDaylightTime(d); - - for (TimeZone tz : getTimeZones(country)) { - // If the current time zone is from the right country - // and meets the other known properties, keep it - // instead of changing to another one. - - if (tz.getID().equals(currentName)) { - if (currentOffset == offset && currentDst == dst) { - return current; - } - } - - // Otherwise, take the first zone from the right - // country that has the correct current offset and DST. - // (Keep iterating instead of returning in case we - // haven't encountered the current time zone yet.) - - if (best == null) { - if (tz.getOffset(when) == offset && - tz.inDaylightTime(d) == dst) { - best = tz; - } - } - } - - return best; - } - - /** - * Return list of unique time zones for the country. Do not modify - * - * @param country to find - * @return list of unique time zones, maybe empty but never null. Do not modify. - * @hide - */ - public static ArrayList getTimeZonesWithUniqueOffsets(String country) { - synchronized(sLastUniqueLockObj) { - if ((country != null) && country.equals(sLastUniqueCountry)) { - if (DBG) { - Log.d(TAG, "getTimeZonesWithUniqueOffsets(" + - country + "): return cached version"); - } - return sLastUniqueZoneOffsets; - } - } - - Collection zones = getTimeZones(country); - ArrayList uniqueTimeZones = new ArrayList(); - for (TimeZone zone : zones) { - // See if we already have this offset, - // Using slow but space efficient and these are small. - boolean found = false; - for (int i = 0; i < uniqueTimeZones.size(); i++) { - if (uniqueTimeZones.get(i).getRawOffset() == zone.getRawOffset()) { - found = true; - break; - } - } - if (found == false) { - if (DBG) { - Log.d(TAG, "getTimeZonesWithUniqueOffsets: add unique offset=" + - zone.getRawOffset() + " zone.getID=" + zone.getID()); - } - uniqueTimeZones.add(zone); - } - } - - synchronized(sLastUniqueLockObj) { - // Cache the last result - sLastUniqueZoneOffsets = uniqueTimeZones; - sLastUniqueCountry = country; - - return sLastUniqueZoneOffsets; - } - } - - /** - * Returns the time zones for the country, which is the code - * attribute of the timezone element in time_zones_by_country.xml. Do not modify. - * - * @param country is a two character country code. - * @return TimeZone list, maybe empty but never null. Do not modify. - * @hide - */ - public static ArrayList getTimeZones(String country) { - synchronized (sLastLockObj) { - if ((country != null) && country.equals(sLastCountry)) { - if (DBG) Log.d(TAG, "getTimeZones(" + country + "): return cached version"); - return sLastZones; - } - } - - ArrayList tzs = new ArrayList(); - - if (country == null) { - if (DBG) Log.d(TAG, "getTimeZones(null): return empty list"); - return tzs; - } - - Resources r = Resources.getSystem(); - XmlResourceParser parser = r.getXml(com.android.internal.R.xml.time_zones_by_country); - - try { - XmlUtils.beginDocument(parser, "timezones"); - - while (true) { - XmlUtils.nextElement(parser); - - String element = parser.getName(); - if (element == null || !(element.equals("timezone"))) { - break; - } - - String code = parser.getAttributeValue(null, "code"); - - if (country.equals(code)) { - if (parser.next() == XmlPullParser.TEXT) { - String zoneIdString = parser.getText(); - TimeZone tz = TimeZone.getTimeZone(zoneIdString); - if (tz.getID().startsWith("GMT") == false) { - // tz.getID doesn't start not "GMT" so its valid - tzs.add(tz); - if (DBG) { - Log.d(TAG, "getTimeZone('" + country + "'): found tz.getID==" - + ((tz != null) ? tz.getID() : "")); - } - } - } - } - } - } catch (XmlPullParserException e) { - Log.e(TAG, "Got xml parser exception getTimeZone('" + country + "'): e=", e); - } catch (IOException e) { - Log.e(TAG, "Got IO exception getTimeZone('" + country + "'): e=", e); - } finally { - parser.close(); - } - - synchronized(sLastLockObj) { - // Cache the last result; - sLastZones = tzs; - sLastCountry = country; - return sLastZones; - } - } - - /** - * Returns a String indicating the version of the time zone database currently - * in use. The format of the string is dependent on the underlying time zone - * database implementation, but will typically contain the year in which the database - * was updated plus a letter from a to z indicating changes made within that year. - * - *

    Time zone database updates should be expected to occur periodically due to - * political and legal changes that cannot be anticipated in advance. Therefore, - * when computing the UTC time for a future event, applications should be aware that - * the results may differ following a time zone database update. This method allows - * applications to detect that a database change has occurred, and to recalculate any - * cached times accordingly. - * - *

    The time zone database may be assumed to change only when the device runtime - * is restarted. Therefore, it is not necessary to re-query the database version - * during the lifetime of an activity. - */ - public static String getTimeZoneDatabaseVersion() { - return ZoneInfoDB.getInstance().getVersion(); - } - - /** @hide Field length that can hold 999 days of time */ - public static final int HUNDRED_DAY_FIELD_LEN = 19; - - private static final int SECONDS_PER_MINUTE = 60; - private static final int SECONDS_PER_HOUR = 60 * 60; - private static final int SECONDS_PER_DAY = 24 * 60 * 60; - - /** @hide */ - public static final long NANOS_PER_MS = 1000000; - - private static final Object sFormatSync = new Object(); - private static char[] sFormatStr = new char[HUNDRED_DAY_FIELD_LEN+5]; - - private static final long LARGEST_DURATION = (1000 * DateUtils.DAY_IN_MILLIS) - 1; - - static private int accumField(int amt, int suffix, boolean always, int zeropad) { - if (amt > 99 || (always && zeropad >= 3)) { - return 3+suffix; - } - if (amt > 9 || (always && zeropad >= 2)) { - return 2+suffix; - } - if (always || amt > 0) { - return 1+suffix; - } - return 0; - } - - static private int printField(char[] formatStr, int amt, char suffix, int pos, - boolean always, int zeropad) { - if (always || amt > 0) { - final int startPos = pos; - if ((always && zeropad >= 3) || amt > 99) { - int dig = amt/100; - formatStr[pos] = (char)(dig + '0'); - pos++; - amt -= (dig*100); - } - if ((always && zeropad >= 2) || amt > 9 || startPos != pos) { - int dig = amt/10; - formatStr[pos] = (char)(dig + '0'); - pos++; - amt -= (dig*10); - } - formatStr[pos] = (char)(amt + '0'); - pos++; - formatStr[pos] = suffix; - pos++; - } - return pos; - } - - private static int formatDurationLocked(long duration, int fieldLen) { - if (sFormatStr.length < fieldLen) { - sFormatStr = new char[fieldLen]; - } - - char[] formatStr = sFormatStr; - - if (duration == 0) { - int pos = 0; - fieldLen -= 1; - while (pos < fieldLen) { - formatStr[pos++] = ' '; - } - formatStr[pos] = '0'; - return pos+1; - } - - char prefix; - if (duration > 0) { - prefix = '+'; - } else { - prefix = '-'; - duration = -duration; - } - - if (duration > LARGEST_DURATION) { - duration = LARGEST_DURATION; - } - - int millis = (int)(duration%1000); - int seconds = (int) Math.floor(duration / 1000); - int days = 0, hours = 0, minutes = 0; - - if (seconds > SECONDS_PER_DAY) { - days = seconds / SECONDS_PER_DAY; - seconds -= days * SECONDS_PER_DAY; - } - if (seconds > SECONDS_PER_HOUR) { - hours = seconds / SECONDS_PER_HOUR; - seconds -= hours * SECONDS_PER_HOUR; - } - if (seconds > SECONDS_PER_MINUTE) { - minutes = seconds / SECONDS_PER_MINUTE; - seconds -= minutes * SECONDS_PER_MINUTE; - } - - int pos = 0; - - if (fieldLen != 0) { - int myLen = accumField(days, 1, false, 0); - myLen += accumField(hours, 1, myLen > 0, 2); - myLen += accumField(minutes, 1, myLen > 0, 2); - myLen += accumField(seconds, 1, myLen > 0, 2); - myLen += accumField(millis, 2, true, myLen > 0 ? 3 : 0) + 1; - while (myLen < fieldLen) { - formatStr[pos] = ' '; - pos++; - myLen++; - } - } - - formatStr[pos] = prefix; - pos++; - - int start = pos; - boolean zeropad = fieldLen != 0; - pos = printField(formatStr, days, 'd', pos, false, 0); - pos = printField(formatStr, hours, 'h', pos, pos != start, zeropad ? 2 : 0); - pos = printField(formatStr, minutes, 'm', pos, pos != start, zeropad ? 2 : 0); - pos = printField(formatStr, seconds, 's', pos, pos != start, zeropad ? 2 : 0); - pos = printField(formatStr, millis, 'm', pos, true, (zeropad && pos != start) ? 3 : 0); - formatStr[pos] = 's'; - return pos + 1; - } - - /** @hide Just for debugging; not internationalized. */ - public static void formatDuration(long duration, StringBuilder builder) { - synchronized (sFormatSync) { - int len = formatDurationLocked(duration, 0); - builder.append(sFormatStr, 0, len); - } - } - - /** @hide Just for debugging; not internationalized. */ - public static void formatDuration(long duration, PrintWriter pw, int fieldLen) { - synchronized (sFormatSync) { - int len = formatDurationLocked(duration, fieldLen); - pw.print(new String(sFormatStr, 0, len)); - } - } - - /** @hide Just for debugging; not internationalized. */ - public static void formatDuration(long duration, PrintWriter pw) { - formatDuration(duration, pw, 0); - } - - /** @hide Just for debugging; not internationalized. */ - public static void formatDuration(long time, long now, PrintWriter pw) { - if (time == 0) { - pw.print("--"); - return; - } - formatDuration(time-now, pw, 0); - } - - /** @hide Just for debugging; not internationalized. */ - public static String formatUptime(long time) { - final long diff = time - SystemClock.uptimeMillis(); - if (diff > 0) { - return time + " (in " + diff + " ms)"; - } - if (diff < 0) { - return time + " (" + -diff + " ms ago)"; - } - return time + " (now)"; - } - - /** - * Convert a System.currentTimeMillis() value to a time of day value like - * that printed in logs. MM-DD HH:MM:SS.MMM - * - * @param millis since the epoch (1/1/1970) - * @return String representation of the time. - * @hide - */ - public static String logTimeOfDay(long millis) { - Calendar c = Calendar.getInstance(); - if (millis >= 0) { - c.setTimeInMillis(millis); - return String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c); - } else { - return Long.toString(millis); - } - } -} diff --git a/src/main/java/android/util/TimeUtilsTest.java b/src/main/java/android/util/TimeUtilsTest.java deleted file mode 100644 index 74c8e04..0000000 --- a/src/main/java/android/util/TimeUtilsTest.java +++ /dev/null @@ -1,455 +0,0 @@ -/* - * Copyright (C) 2008 Google Inc. - * - * 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.util; - -import junit.framework.TestCase; - -import java.util.Calendar; -import java.util.TimeZone; - -/** - * TimeUtilsTest tests the time zone guesser. - */ -public class TimeUtilsTest extends TestCase { - public void testMainstream() throws Exception { - String[] mainstream = new String[] { - "America/New_York", // Eastern - "America/Chicago", // Central - "America/Denver", // Mountain - "America/Los_Angeles", // Pacific - "America/Anchorage", // Alaska - "Pacific/Honolulu", // Hawaii, no DST - }; - - for (String name : mainstream) { - TimeZone tz = TimeZone.getTimeZone(name); - Calendar c = Calendar.getInstance(tz); - TimeZone guess; - - c.set(2008, Calendar.OCTOBER, 20, 12, 00, 00); - guess = guess(c, "us"); - assertEquals(name, guess.getID()); - - c.set(2009, Calendar.JANUARY, 20, 12, 00, 00); - guess = guess(c, "us"); - assertEquals(name, guess.getID()); - } - } - - public void testWeird() throws Exception { - String[] weird = new String[] { - "America/Phoenix", // Mountain, no DST - "America/Adak", // Same as Hawaii, but with DST - }; - - for (String name : weird) { - TimeZone tz = TimeZone.getTimeZone(name); - Calendar c = Calendar.getInstance(tz); - TimeZone guess; - - c.set(2008, Calendar.OCTOBER, 20, 12, 00, 00); - guess = guess(c, "us"); - assertEquals(name, guess.getID()); - } - } - - public void testOld() throws Exception { - String[] old = new String[] { - "America/Indiana/Indianapolis", // Eastern, formerly no DST - }; - - for (String name : old) { - TimeZone tz = TimeZone.getTimeZone(name); - Calendar c = Calendar.getInstance(tz); - TimeZone guess; - - c.set(2005, Calendar.OCTOBER, 20, 12, 00, 00); - guess = guess(c, "us"); - assertEquals(name, guess.getID()); - } - } - - public void testWorld() throws Exception { - String[] world = new String[] { - "ad", "Europe/Andorra", - "ae", "Asia/Dubai", - "af", "Asia/Kabul", - "ag", "America/Antigua", - "ai", "America/Anguilla", - "al", "Europe/Tirane", - "am", "Asia/Yerevan", - "an", "America/Curacao", - "ao", "Africa/Luanda", - "aq", "Antarctica/McMurdo", - "aq", "Antarctica/DumontDUrville", - "aq", "Antarctica/Casey", - "aq", "Antarctica/Davis", - "aq", "Antarctica/Mawson", - "aq", "Antarctica/Syowa", - "aq", "Antarctica/Rothera", - "aq", "Antarctica/Palmer", - "ar", "America/Argentina/Buenos_Aires", - "as", "Pacific/Pago_Pago", - "at", "Europe/Vienna", - "au", "Australia/Sydney", - "au", "Australia/Adelaide", - "au", "Australia/Perth", - "au", "Australia/Eucla", - "aw", "America/Aruba", - "ax", "Europe/Mariehamn", - "az", "Asia/Baku", - "ba", "Europe/Sarajevo", - "bb", "America/Barbados", - "bd", "Asia/Dhaka", - "be", "Europe/Brussels", - "bf", "Africa/Ouagadougou", - "bg", "Europe/Sofia", - "bh", "Asia/Bahrain", - "bi", "Africa/Bujumbura", - "bj", "Africa/Porto-Novo", - "bm", "Atlantic/Bermuda", - "bn", "Asia/Brunei", - "bo", "America/La_Paz", - "br", "America/Noronha", - "br", "America/Sao_Paulo", - "br", "America/Manaus", - "bs", "America/Nassau", - "bt", "Asia/Thimphu", - "bw", "Africa/Gaborone", - "by", "Europe/Minsk", - "bz", "America/Belize", - "ca", "America/St_Johns", - "ca", "America/Halifax", - "ca", "America/Toronto", - "ca", "America/Winnipeg", - "ca", "America/Edmonton", - "ca", "America/Vancouver", - "cc", "Indian/Cocos", - "cd", "Africa/Lubumbashi", - "cd", "Africa/Kinshasa", - "cf", "Africa/Bangui", - "cg", "Africa/Brazzaville", - "ch", "Europe/Zurich", - "ci", "Africa/Abidjan", - "ck", "Pacific/Rarotonga", - "cl", "America/Santiago", - "cl", "Pacific/Easter", - "cm", "Africa/Douala", - "cn", "Asia/Shanghai", - "co", "America/Bogota", - "cr", "America/Costa_Rica", - "cu", "America/Havana", - "cv", "Atlantic/Cape_Verde", - "cx", "Indian/Christmas", - "cy", "Asia/Nicosia", - "cz", "Europe/Prague", - "de", "Europe/Berlin", - "dj", "Africa/Djibouti", - "dk", "Europe/Copenhagen", - "dm", "America/Dominica", - "do", "America/Santo_Domingo", - "dz", "Africa/Algiers", - "ec", "America/Guayaquil", - "ec", "Pacific/Galapagos", - "ee", "Europe/Tallinn", - "eg", "Africa/Cairo", - "eh", "Africa/El_Aaiun", - "er", "Africa/Asmara", - "es", "Europe/Madrid", - "es", "Atlantic/Canary", - "et", "Africa/Addis_Ababa", - "fi", "Europe/Helsinki", - "fj", "Pacific/Fiji", - "fk", "Atlantic/Stanley", - "fm", "Pacific/Ponape", - "fm", "Pacific/Truk", - "fo", "Atlantic/Faroe", - "fr", "Europe/Paris", - "ga", "Africa/Libreville", - "gb", "Europe/London", - "gd", "America/Grenada", - "ge", "Asia/Tbilisi", - "gf", "America/Cayenne", - "gg", "Europe/Guernsey", - "gh", "Africa/Accra", - "gi", "Europe/Gibraltar", - "gl", "America/Danmarkshavn", - "gl", "America/Scoresbysund", - "gl", "America/Godthab", - "gl", "America/Thule", - "gm", "Africa/Banjul", - "gn", "Africa/Conakry", - "gp", "America/Guadeloupe", - "gq", "Africa/Malabo", - "gr", "Europe/Athens", - "gs", "Atlantic/South_Georgia", - "gt", "America/Guatemala", - "gu", "Pacific/Guam", - "gw", "Africa/Bissau", - "gy", "America/Guyana", - "hk", "Asia/Hong_Kong", - "hn", "America/Tegucigalpa", - "hr", "Europe/Zagreb", - "ht", "America/Port-au-Prince", - "hu", "Europe/Budapest", - "id", "Asia/Jayapura", - "id", "Asia/Makassar", - "id", "Asia/Jakarta", - "ie", "Europe/Dublin", - "il", "Asia/Jerusalem", - "im", "Europe/Isle_of_Man", - "in", "Asia/Calcutta", - "io", "Indian/Chagos", - "iq", "Asia/Baghdad", - "ir", "Asia/Tehran", - "is", "Atlantic/Reykjavik", - "it", "Europe/Rome", - "je", "Europe/Jersey", - "jm", "America/Jamaica", - "jo", "Asia/Amman", - "jp", "Asia/Tokyo", - "ke", "Africa/Nairobi", - "kg", "Asia/Bishkek", - "kh", "Asia/Phnom_Penh", - "ki", "Pacific/Kiritimati", - "ki", "Pacific/Enderbury", - "ki", "Pacific/Tarawa", - "km", "Indian/Comoro", - "kn", "America/St_Kitts", - "kp", "Asia/Pyongyang", - "kr", "Asia/Seoul", - "kw", "Asia/Kuwait", - "ky", "America/Cayman", - "kz", "Asia/Almaty", - "kz", "Asia/Aqtau", - "la", "Asia/Vientiane", - "lb", "Asia/Beirut", - "lc", "America/St_Lucia", - "li", "Europe/Vaduz", - "lk", "Asia/Colombo", - "lr", "Africa/Monrovia", - "ls", "Africa/Maseru", - "lt", "Europe/Vilnius", - "lu", "Europe/Luxembourg", - "lv", "Europe/Riga", - "ly", "Africa/Tripoli", - "ma", "Africa/Casablanca", - "mc", "Europe/Monaco", - "md", "Europe/Chisinau", - "me", "Europe/Podgorica", - "mg", "Indian/Antananarivo", - "mh", "Pacific/Majuro", - "mk", "Europe/Skopje", - "ml", "Africa/Bamako", - "mm", "Asia/Rangoon", - "mn", "Asia/Choibalsan", - "mn", "Asia/Hovd", - "mo", "Asia/Macau", - "mp", "Pacific/Saipan", - "mq", "America/Martinique", - "mr", "Africa/Nouakchott", - "ms", "America/Montserrat", - "mt", "Europe/Malta", - "mu", "Indian/Mauritius", - "mv", "Indian/Maldives", - "mw", "Africa/Blantyre", - "mx", "America/Mexico_City", - "mx", "America/Chihuahua", - "mx", "America/Tijuana", - "my", "Asia/Kuala_Lumpur", - "mz", "Africa/Maputo", - "na", "Africa/Windhoek", - "nc", "Pacific/Noumea", - "ne", "Africa/Niamey", - "nf", "Pacific/Norfolk", - "ng", "Africa/Lagos", - "ni", "America/Managua", - "nl", "Europe/Amsterdam", - "no", "Europe/Oslo", - "np", "Asia/Katmandu", - "nr", "Pacific/Nauru", - "nu", "Pacific/Niue", - "nz", "Pacific/Auckland", - "nz", "Pacific/Chatham", - "om", "Asia/Muscat", - "pa", "America/Panama", - "pe", "America/Lima", - "pf", "Pacific/Gambier", - "pf", "Pacific/Marquesas", - "pf", "Pacific/Tahiti", - "pg", "Pacific/Port_Moresby", - "ph", "Asia/Manila", - "pk", "Asia/Karachi", - "pl", "Europe/Warsaw", - "pm", "America/Miquelon", - "pn", "Pacific/Pitcairn", - "pr", "America/Puerto_Rico", - "ps", "Asia/Gaza", - "pt", "Europe/Lisbon", - "pt", "Atlantic/Azores", - "pw", "Pacific/Palau", - "py", "America/Asuncion", - "qa", "Asia/Qatar", - "re", "Indian/Reunion", - "ro", "Europe/Bucharest", - "rs", "Europe/Belgrade", - "ru", "Asia/Kamchatka", - "ru", "Asia/Magadan", - "ru", "Asia/Vladivostok", - "ru", "Asia/Yakutsk", - "ru", "Asia/Irkutsk", - "ru", "Asia/Krasnoyarsk", - "ru", "Asia/Novosibirsk", - "ru", "Asia/Yekaterinburg", - "ru", "Europe/Samara", - "ru", "Europe/Moscow", - "ru", "Europe/Kaliningrad", - "rw", "Africa/Kigali", - "sa", "Asia/Riyadh", - "sb", "Pacific/Guadalcanal", - "sc", "Indian/Mahe", - "sd", "Africa/Khartoum", - "se", "Europe/Stockholm", - "sg", "Asia/Singapore", - "sh", "Atlantic/St_Helena", - "si", "Europe/Ljubljana", - "sj", "Arctic/Longyearbyen", - "sk", "Europe/Bratislava", - "sl", "Africa/Freetown", - "sm", "Europe/San_Marino", - "sn", "Africa/Dakar", - "so", "Africa/Mogadishu", - "sr", "America/Paramaribo", - "st", "Africa/Sao_Tome", - "sv", "America/El_Salvador", - "sy", "Asia/Damascus", - "sz", "Africa/Mbabane", - "tc", "America/Grand_Turk", - "td", "Africa/Ndjamena", - "tf", "Indian/Kerguelen", - "tg", "Africa/Lome", - "th", "Asia/Bangkok", - "tj", "Asia/Dushanbe", - "tk", "Pacific/Fakaofo", - "tl", "Asia/Dili", - "tm", "Asia/Ashgabat", - "tn", "Africa/Tunis", - "to", "Pacific/Tongatapu", - "tr", "Europe/Istanbul", - "tt", "America/Port_of_Spain", - "tv", "Pacific/Funafuti", - "tw", "Asia/Taipei", - "tz", "Africa/Dar_es_Salaam", - "ua", "Europe/Kiev", - "ug", "Africa/Kampala", - "um", "Pacific/Wake", - "um", "Pacific/Johnston", - "um", "Pacific/Midway", - "us", "America/New_York", - "us", "America/Chicago", - "us", "America/Denver", - "us", "America/Los_Angeles", - "us", "America/Anchorage", - "us", "Pacific/Honolulu", - "uy", "America/Montevideo", - "uz", "Asia/Tashkent", - "va", "Europe/Vatican", - "vc", "America/St_Vincent", - "ve", "America/Caracas", - "vg", "America/Tortola", - "vi", "America/St_Thomas", - "vn", "Asia/Saigon", - "vu", "Pacific/Efate", - "wf", "Pacific/Wallis", - "ws", "Pacific/Apia", - "ye", "Asia/Aden", - "yt", "Indian/Mayotte", - "za", "Africa/Johannesburg", - "zm", "Africa/Lusaka", - "zw", "Africa/Harare", - }; - - for (int i = 0; i < world.length; i += 2) { - String country = world[i]; - String name = world[i + 1]; - - TimeZone tz = TimeZone.getTimeZone(name); - Calendar c = Calendar.getInstance(tz); - TimeZone guess; - - c.set(2009, Calendar.JULY, 20, 12, 00, 00); - guess = guess(c, country); - assertEquals(name, guess.getID()); - - c.set(2009, Calendar.JANUARY, 20, 12, 00, 00); - guess = guess(c, country); - assertEquals(name, guess.getID()); - } - } - - public void testWorldWeird() throws Exception { - String[] world = new String[] { - // Distinguisable from Sydney only when DST not in effect - "au", "Australia/Lord_Howe", - }; - - for (int i = 0; i < world.length; i += 2) { - String country = world[i]; - String name = world[i + 1]; - - TimeZone tz = TimeZone.getTimeZone(name); - Calendar c = Calendar.getInstance(tz); - TimeZone guess; - - c.set(2009, Calendar.JULY, 20, 12, 00, 00); - guess = guess(c, country); - assertEquals(name, guess.getID()); - } - } - - private static TimeZone guess(Calendar c, String country) { - return TimeUtils.getTimeZone(c.get(c.ZONE_OFFSET) + c.get(c.DST_OFFSET), - c.get(c.DST_OFFSET) != 0, - c.getTimeInMillis(), - country); - } - - public void testFormatDuration() { - assertFormatDuration("0", 0); - assertFormatDuration("-1ms", -1); - assertFormatDuration("+1ms", 1); - assertFormatDuration("+10ms", 10); - assertFormatDuration("+100ms", 100); - assertFormatDuration("+101ms", 101); - assertFormatDuration("+330ms", 330); - assertFormatDuration("+1s330ms", 1330); - assertFormatDuration("+10s24ms", 10024); - } - - public void testFormatHugeDuration() { - //assertFormatDuration("+15542d1h11m11s555ms", 1342833071555L); - // TODO: improve formatDuration() API - assertFormatDuration("+999d23h59m59s999ms", 1342833071555L); - assertFormatDuration("-999d23h59m59s999ms", -1342833071555L); - } - - private void assertFormatDuration(String expected, long duration) { - StringBuilder sb = new StringBuilder(); - TimeUtils.formatDuration(duration, sb); - assertEquals("formatDuration(" + duration + ")", expected, sb.toString()); - } -} diff --git a/src/main/java/android/util/TimedRemoteCaller.java b/src/main/java/android/util/TimedRemoteCaller.java deleted file mode 100644 index abb2b64..0000000 --- a/src/main/java/android/util/TimedRemoteCaller.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2013 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.util; - -import android.os.SystemClock; - -import java.util.concurrent.TimeoutException; - -/** - * This is a helper class for making an async one way call and - * its async one way response response in a sync fashion within - * a timeout. The key idea is to call the remote method with a - * sequence number and a callback and then starting to wait for - * the response. The remote method calls back with the result and - * the sequence number. If the response comes within the timeout - * and its sequence number is the one sent in the method invocation, - * then the call succeeded. If the response does not come within - * the timeout then the call failed. Older result received when - * waiting for the result are ignored. - *

    - * Typical usage is: - *

    - *

    
    - * public class MyMethodCaller extends TimeoutRemoteCallHelper {
    - *     // The one way remote method to call.
    - *     private final IRemoteInterface mTarget;
    - *
    - *     // One way callback invoked when the remote method is done.
    - *     private final IRemoteCallback mCallback = new IRemoteCallback.Stub() {
    - *         public void onCompleted(Object result, int sequence) {
    - *             onRemoteMethodResult(result, sequence);
    - *         }
    - *     };
    - *
    - *     public MyMethodCaller(IRemoteInterface target) {
    - *         mTarget = target;
    - *     }
    - *
    - *     public Object onCallMyMethod(Object arg) throws RemoteException {
    - *         final int sequence = onBeforeRemoteCall();
    - *         mTarget.myMethod(arg, sequence);
    - *         return getResultTimed(sequence);
    - *     }
    - * }
    - * 

    - * - * @param The type of the expected result. - * - * @hide - */ -public abstract class TimedRemoteCaller { - - public static final long DEFAULT_CALL_TIMEOUT_MILLIS = 5000; - - private static final int UNDEFINED_SEQUENCE = -1; - - private final Object mLock = new Object(); - - private final long mCallTimeoutMillis; - - private int mSequenceCounter; - - private int mReceivedSequence = UNDEFINED_SEQUENCE; - - private int mAwaitedSequence = UNDEFINED_SEQUENCE; - - private T mResult; - - public TimedRemoteCaller(long callTimeoutMillis) { - mCallTimeoutMillis = callTimeoutMillis; - } - - public final int onBeforeRemoteCall() { - synchronized (mLock) { - mAwaitedSequence = mSequenceCounter++; - return mAwaitedSequence; - } - } - - public final T getResultTimed(int sequence) throws TimeoutException { - synchronized (mLock) { - final boolean success = waitForResultTimedLocked(sequence); - if (!success) { - throw new TimeoutException("No reponse for sequence: " + sequence); - } - T result = mResult; - mResult = null; - return result; - } - } - - public final void onRemoteMethodResult(T result, int sequence) { - synchronized (mLock) { - if (sequence == mAwaitedSequence) { - mReceivedSequence = sequence; - mResult = result; - mLock.notifyAll(); - } - } - } - - private boolean waitForResultTimedLocked(int sequence) { - final long startMillis = SystemClock.uptimeMillis(); - while (true) { - try { - if (mReceivedSequence == sequence) { - return true; - } - final long elapsedMillis = SystemClock.uptimeMillis() - startMillis; - final long waitMillis = mCallTimeoutMillis - elapsedMillis; - if (waitMillis <= 0) { - return false; - } - mLock.wait(waitMillis); - } catch (InterruptedException ie) { - /* ignore */ - } - } - } -} diff --git a/src/main/java/android/util/TimingLogger.java b/src/main/java/android/util/TimingLogger.java deleted file mode 100644 index be442da..0000000 --- a/src/main/java/android/util/TimingLogger.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import java.util.ArrayList; - -import android.os.SystemClock; - -/** - * A utility class to help log timings splits throughout a method call. - * Typical usage is: - * - *
    - *     TimingLogger timings = new TimingLogger(TAG, "methodA");
    - *     // ... do some work A ...
    - *     timings.addSplit("work A");
    - *     // ... do some work B ...
    - *     timings.addSplit("work B");
    - *     // ... do some work C ...
    - *     timings.addSplit("work C");
    - *     timings.dumpToLog();
    - * 
    - * - *

    The dumpToLog call would add the following to the log:

    - * - *
    - *     D/TAG     ( 3459): methodA: begin
    - *     D/TAG     ( 3459): methodA:      9 ms, work A
    - *     D/TAG     ( 3459): methodA:      1 ms, work B
    - *     D/TAG     ( 3459): methodA:      6 ms, work C
    - *     D/TAG     ( 3459): methodA: end, 16 ms
    - * 
    - */ -public class TimingLogger { - - /** - * The Log tag to use for checking Log.isLoggable and for - * logging the timings. - */ - private String mTag; - - /** A label to be included in every log. */ - private String mLabel; - - /** Used to track whether Log.isLoggable was enabled at reset time. */ - private boolean mDisabled; - - /** Stores the time of each split. */ - ArrayList mSplits; - - /** Stores the labels for each split. */ - ArrayList mSplitLabels; - - /** - * Create and initialize a TimingLogger object that will log using - * the specific tag. If the Log.isLoggable is not enabled to at - * least the Log.VERBOSE level for that tag at creation time then - * the addSplit and dumpToLog call will do nothing. - * @param tag the log tag to use while logging the timings - * @param label a string to be displayed with each log - */ - public TimingLogger(String tag, String label) { - reset(tag, label); - } - - /** - * Clear and initialize a TimingLogger object that will log using - * the specific tag. If the Log.isLoggable is not enabled to at - * least the Log.VERBOSE level for that tag at creation time then - * the addSplit and dumpToLog call will do nothing. - * @param tag the log tag to use while logging the timings - * @param label a string to be displayed with each log - */ - public void reset(String tag, String label) { - mTag = tag; - mLabel = label; - reset(); - } - - /** - * Clear and initialize a TimingLogger object that will log using - * the tag and label that was specified previously, either via - * the constructor or a call to reset(tag, label). If the - * Log.isLoggable is not enabled to at least the Log.VERBOSE - * level for that tag at creation time then the addSplit and - * dumpToLog call will do nothing. - */ - public void reset() { - mDisabled = !Log.isLoggable(mTag, Log.VERBOSE); - if (mDisabled) return; - if (mSplits == null) { - mSplits = new ArrayList(); - mSplitLabels = new ArrayList(); - } else { - mSplits.clear(); - mSplitLabels.clear(); - } - addSplit(null); - } - - /** - * Add a split for the current time, labeled with splitLabel. If - * Log.isLoggable was not enabled to at least the Log.VERBOSE for - * the specified tag at construction or reset() time then this - * call does nothing. - * @param splitLabel a label to associate with this split. - */ - public void addSplit(String splitLabel) { - if (mDisabled) return; - long now = SystemClock.elapsedRealtime(); - mSplits.add(now); - mSplitLabels.add(splitLabel); - } - - /** - * Dumps the timings to the log using Log.d(). If Log.isLoggable was - * not enabled to at least the Log.VERBOSE for the specified tag at - * construction or reset() time then this call does nothing. - */ - public void dumpToLog() { - if (mDisabled) return; - Log.d(mTag, mLabel + ": begin"); - final long first = mSplits.get(0); - long now = first; - for (int i = 1; i < mSplits.size(); i++) { - now = mSplits.get(i); - final String splitLabel = mSplitLabels.get(i); - final long prev = mSplits.get(i - 1); - - Log.d(mTag, mLabel + ": " + (now - prev) + " ms, " + splitLabel); - } - Log.d(mTag, mLabel + ": end, " + (now - first) + " ms"); - } -} diff --git a/src/main/java/android/util/TouchModeFlexibleAsserts.java b/src/main/java/android/util/TouchModeFlexibleAsserts.java deleted file mode 100644 index ca12a15..0000000 --- a/src/main/java/android/util/TouchModeFlexibleAsserts.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import junit.framework.Assert; - -import android.test.InstrumentationTestCase; -import android.test.TouchUtils; -import android.view.View; - -/** - * When entering touch mode via touch, the tests can be flaky. These asserts - * are more flexible (allowing up to MAX_ATTEMPTS touches to enter touch mode via touch or - * tap) until we can find a way to solve the flakiness. - */ -public class TouchModeFlexibleAsserts { - - private static int MAX_ATTEMPTS = 2; - - private static int MAX_DELAY_MILLIS = 2000; - - public static void assertInTouchModeAfterClick(InstrumentationTestCase test, View viewToTouch) { - int numAttemptsAtTouchMode = 0; - while (numAttemptsAtTouchMode < MAX_ATTEMPTS && - !viewToTouch.isInTouchMode()) { - TouchUtils.clickView(test, viewToTouch); - numAttemptsAtTouchMode++; - } - Assert.assertTrue("even after " + MAX_ATTEMPTS + " clicks, did not enter " - + "touch mode", viewToTouch.isInTouchMode()); - //Assert.assertEquals("number of touches to enter touch mode", 1, numAttemptsAtTouchMode); - } - - public static void assertInTouchModeAfterTap(InstrumentationTestCase test, View viewToTouch) { - int numAttemptsAtTouchMode = 0; - while (numAttemptsAtTouchMode < MAX_ATTEMPTS && - !viewToTouch.isInTouchMode()) { - TouchUtils.tapView(test, viewToTouch); - numAttemptsAtTouchMode++; - } - Assert.assertTrue("even after " + MAX_ATTEMPTS + " taps, did not enter " - + "touch mode", viewToTouch.isInTouchMode()); - //Assert.assertEquals("number of touches to enter touch mode", 1, numAttemptsAtTouchMode); - } - - public static void assertNotInTouchModeAfterKey(InstrumentationTestCase test, int keyCode, View checkForTouchMode) { - test.sendKeys(keyCode); - int amountLeft = MAX_DELAY_MILLIS; - - while (checkForTouchMode.isInTouchMode() && amountLeft > 0) { - amountLeft -= 200; - try { - Thread.sleep(200); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - Assert.assertFalse("even after waiting " + MAX_DELAY_MILLIS + " millis after " - + "pressing key event, still in touch mode", checkForTouchMode.isInTouchMode()); - } -} diff --git a/src/main/java/android/util/TrustedTime.java b/src/main/java/android/util/TrustedTime.java deleted file mode 100644 index 263d782..0000000 --- a/src/main/java/android/util/TrustedTime.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2011 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.util; - -/** - * Interface that provides trusted time information, possibly coming from an NTP - * server. Implementations may cache answers until {@link #forceRefresh()}. - * - * @hide - */ -public interface TrustedTime { - /** - * Force update with an external trusted time source, returning {@code true} - * when successful. - */ - public boolean forceRefresh(); - - /** - * Check if this instance has cached a response from a trusted time source. - */ - public boolean hasCache(); - - /** - * Return time since last trusted time source contact, or - * {@link Long#MAX_VALUE} if never contacted. - */ - public long getCacheAge(); - - /** - * Return certainty of cached trusted time in milliseconds, or - * {@link Long#MAX_VALUE} if never contacted. Smaller values are more - * precise. - */ - public long getCacheCertainty(); - - /** - * Return current time similar to {@link System#currentTimeMillis()}, - * possibly using a cached authoritative time source. - */ - public long currentTimeMillis(); -} diff --git a/src/main/java/android/util/TypedValue.java b/src/main/java/android/util/TypedValue.java deleted file mode 100644 index 74d4245..0000000 --- a/src/main/java/android/util/TypedValue.java +++ /dev/null @@ -1,513 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -/** - * Container for a dynamically typed data value. Primarily used with - * {@link android.content.res.Resources} for holding resource values. - */ -public class TypedValue { - /** The value contains no data. */ - public static final int TYPE_NULL = 0x00; - - /** The data field holds a resource identifier. */ - public static final int TYPE_REFERENCE = 0x01; - /** The data field holds an attribute resource - * identifier (referencing an attribute in the current theme - * style, not a resource entry). */ - public static final int TYPE_ATTRIBUTE = 0x02; - /** The string field holds string data. In addition, if - * data is non-zero then it is the string block - * index of the string and assetCookie is the set of - * assets the string came from. */ - public static final int TYPE_STRING = 0x03; - /** The data field holds an IEEE 754 floating point number. */ - public static final int TYPE_FLOAT = 0x04; - /** The data field holds a complex number encoding a - * dimension value. */ - public static final int TYPE_DIMENSION = 0x05; - /** The data field holds a complex number encoding a fraction - * of a container. */ - public static final int TYPE_FRACTION = 0x06; - - /** Identifies the start of plain integer values. Any type value - * from this to {@link #TYPE_LAST_INT} means the - * data field holds a generic integer value. */ - public static final int TYPE_FIRST_INT = 0x10; - - /** The data field holds a number that was - * originally specified in decimal. */ - public static final int TYPE_INT_DEC = 0x10; - /** The data field holds a number that was - * originally specified in hexadecimal (0xn). */ - public static final int TYPE_INT_HEX = 0x11; - /** The data field holds 0 or 1 that was originally - * specified as "false" or "true". */ - public static final int TYPE_INT_BOOLEAN = 0x12; - - /** Identifies the start of integer values that were specified as - * color constants (starting with '#'). */ - public static final int TYPE_FIRST_COLOR_INT = 0x1c; - - /** The data field holds a color that was originally - * specified as #aarrggbb. */ - public static final int TYPE_INT_COLOR_ARGB8 = 0x1c; - /** The data field holds a color that was originally - * specified as #rrggbb. */ - public static final int TYPE_INT_COLOR_RGB8 = 0x1d; - /** The data field holds a color that was originally - * specified as #argb. */ - public static final int TYPE_INT_COLOR_ARGB4 = 0x1e; - /** The data field holds a color that was originally - * specified as #rgb. */ - public static final int TYPE_INT_COLOR_RGB4 = 0x1f; - - /** Identifies the end of integer values that were specified as color - * constants. */ - public static final int TYPE_LAST_COLOR_INT = 0x1f; - - /** Identifies the end of plain integer values. */ - public static final int TYPE_LAST_INT = 0x1f; - - /* ------------------------------------------------------------ */ - - /** Complex data: bit location of unit information. */ - public static final int COMPLEX_UNIT_SHIFT = 0; - /** Complex data: mask to extract unit information (after shifting by - * {@link #COMPLEX_UNIT_SHIFT}). This gives us 16 possible types, as - * defined below. */ - public static final int COMPLEX_UNIT_MASK = 0xf; - - /** {@link #TYPE_DIMENSION} complex unit: Value is raw pixels. */ - public static final int COMPLEX_UNIT_PX = 0; - /** {@link #TYPE_DIMENSION} complex unit: Value is Device Independent - * Pixels. */ - public static final int COMPLEX_UNIT_DIP = 1; - /** {@link #TYPE_DIMENSION} complex unit: Value is a scaled pixel. */ - public static final int COMPLEX_UNIT_SP = 2; - /** {@link #TYPE_DIMENSION} complex unit: Value is in points. */ - public static final int COMPLEX_UNIT_PT = 3; - /** {@link #TYPE_DIMENSION} complex unit: Value is in inches. */ - public static final int COMPLEX_UNIT_IN = 4; - /** {@link #TYPE_DIMENSION} complex unit: Value is in millimeters. */ - public static final int COMPLEX_UNIT_MM = 5; - - /** {@link #TYPE_FRACTION} complex unit: A basic fraction of the overall - * size. */ - public static final int COMPLEX_UNIT_FRACTION = 0; - /** {@link #TYPE_FRACTION} complex unit: A fraction of the parent size. */ - public static final int COMPLEX_UNIT_FRACTION_PARENT = 1; - - /** Complex data: where the radix information is, telling where the decimal - * place appears in the mantissa. */ - public static final int COMPLEX_RADIX_SHIFT = 4; - /** Complex data: mask to extract radix information (after shifting by - * {@link #COMPLEX_RADIX_SHIFT}). This give us 4 possible fixed point - * representations as defined below. */ - public static final int COMPLEX_RADIX_MASK = 0x3; - - /** Complex data: the mantissa is an integral number -- i.e., 0xnnnnnn.0 */ - public static final int COMPLEX_RADIX_23p0 = 0; - /** Complex data: the mantissa magnitude is 16 bits -- i.e, 0xnnnn.nn */ - public static final int COMPLEX_RADIX_16p7 = 1; - /** Complex data: the mantissa magnitude is 8 bits -- i.e, 0xnn.nnnn */ - public static final int COMPLEX_RADIX_8p15 = 2; - /** Complex data: the mantissa magnitude is 0 bits -- i.e, 0x0.nnnnnn */ - public static final int COMPLEX_RADIX_0p23 = 3; - - /** Complex data: bit location of mantissa information. */ - public static final int COMPLEX_MANTISSA_SHIFT = 8; - /** Complex data: mask to extract mantissa information (after shifting by - * {@link #COMPLEX_MANTISSA_SHIFT}). This gives us 23 bits of precision; - * the top bit is the sign. */ - public static final int COMPLEX_MANTISSA_MASK = 0xffffff; - - /* ------------------------------------------------------------ */ - - /** - * {@link #TYPE_NULL} data indicating the value was not specified. - */ - public static final int DATA_NULL_UNDEFINED = 0; - /** - * {@link #TYPE_NULL} data indicating the value was explicitly set to null. - */ - public static final int DATA_NULL_EMPTY = 1; - - /* ------------------------------------------------------------ */ - - /** - * If {@link #density} is equal to this value, then the density should be - * treated as the system's default density value: {@link DisplayMetrics#DENSITY_DEFAULT}. - */ - public static final int DENSITY_DEFAULT = 0; - - /** - * If {@link #density} is equal to this value, then there is no density - * associated with the resource and it should not be scaled. - */ - public static final int DENSITY_NONE = 0xffff; - - /* ------------------------------------------------------------ */ - - /** The type held by this value, as defined by the constants here. - * This tells you how to interpret the other fields in the object. */ - public int type; - - /** If the value holds a string, this is it. */ - public CharSequence string; - - /** Basic data in the value, interpreted according to {@link #type} */ - public int data; - - /** Additional information about where the value came from; only - * set for strings. */ - public int assetCookie; - - /** If Value came from a resource, this holds the corresponding resource id. */ - public int resourceId; - - /** If Value came from a resource, these are the configurations for which - * its contents can change. */ - public int changingConfigurations = -1; - - /** - * If the Value came from a resource, this holds the corresponding pixel density. - * */ - public int density; - - /* ------------------------------------------------------------ */ - - /** Return the data for this value as a float. Only use for values - * whose type is {@link #TYPE_FLOAT}. */ - public final float getFloat() { - return Float.intBitsToFloat(data); - } - - private static final float MANTISSA_MULT = - 1.0f / (1<>TypedValue.COMPLEX_RADIX_SHIFT) - & TypedValue.COMPLEX_RADIX_MASK]; - } - - /** - * Converts a complex data value holding a dimension to its final floating - * point value. The given data must be structured as a - * {@link #TYPE_DIMENSION}. - * - * @param data A complex data value holding a unit, magnitude, and - * mantissa. - * @param metrics Current display metrics to use in the conversion -- - * supplies display density and scaling information. - * - * @return The complex floating point value multiplied by the appropriate - * metrics depending on its unit. - */ - public static float complexToDimension(int data, DisplayMetrics metrics) - { - return applyDimension( - (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK, - complexToFloat(data), - metrics); - } - - /** - * Converts a complex data value holding a dimension to its final value - * as an integer pixel offset. This is the same as - * {@link #complexToDimension}, except the raw floating point value is - * truncated to an integer (pixel) value. - * The given data must be structured as a - * {@link #TYPE_DIMENSION}. - * - * @param data A complex data value holding a unit, magnitude, and - * mantissa. - * @param metrics Current display metrics to use in the conversion -- - * supplies display density and scaling information. - * - * @return The number of pixels specified by the data and its desired - * multiplier and units. - */ - public static int complexToDimensionPixelOffset(int data, - DisplayMetrics metrics) - { - return (int)applyDimension( - (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK, - complexToFloat(data), - metrics); - } - - /** - * Converts a complex data value holding a dimension to its final value - * as an integer pixel size. This is the same as - * {@link #complexToDimension}, except the raw floating point value is - * converted to an integer (pixel) value for use as a size. A size - * conversion involves rounding the base value, and ensuring that a - * non-zero base value is at least one pixel in size. - * The given data must be structured as a - * {@link #TYPE_DIMENSION}. - * - * @param data A complex data value holding a unit, magnitude, and - * mantissa. - * @param metrics Current display metrics to use in the conversion -- - * supplies display density and scaling information. - * - * @return The number of pixels specified by the data and its desired - * multiplier and units. - */ - public static int complexToDimensionPixelSize(int data, - DisplayMetrics metrics) - { - final float value = complexToFloat(data); - final float f = applyDimension( - (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK, - value, - metrics); - final int res = (int)(f+0.5f); - if (res != 0) return res; - if (value == 0) return 0; - if (value > 0) return 1; - return -1; - } - - /** - * @hide Was accidentally exposed in API level 1 for debugging purposes. - * Kept for compatibility just in case although the debugging code has been removed. - */ - @Deprecated - public static float complexToDimensionNoisy(int data, DisplayMetrics metrics) - { - return complexToDimension(data, metrics); - } - - /** - * Return the complex unit type for this value. For example, a dimen type - * with value 12sp will return {@link #COMPLEX_UNIT_SP}. Only use for values - * whose type is {@link #TYPE_DIMENSION}. - * - * @return The complex unit type. - */ - public int getComplexUnit() - { - return COMPLEX_UNIT_MASK & (data>>TypedValue.COMPLEX_UNIT_SHIFT); - } - - /** - * Converts an unpacked complex data value holding a dimension to its final floating - * point value. The two parameters unit and value - * are as in {@link #TYPE_DIMENSION}. - * - * @param unit The unit to convert from. - * @param value The value to apply the unit to. - * @param metrics Current display metrics to use in the conversion -- - * supplies display density and scaling information. - * - * @return The complex floating point value multiplied by the appropriate - * metrics depending on its unit. - */ - public static float applyDimension(int unit, float value, - DisplayMetrics metrics) - { - switch (unit) { - case COMPLEX_UNIT_PX: - return value; - case COMPLEX_UNIT_DIP: - return value * metrics.density; - case COMPLEX_UNIT_SP: - return value * metrics.scaledDensity; - case COMPLEX_UNIT_PT: - return value * metrics.xdpi * (1.0f/72); - case COMPLEX_UNIT_IN: - return value * metrics.xdpi; - case COMPLEX_UNIT_MM: - return value * metrics.xdpi * (1.0f/25.4f); - } - return 0; - } - - /** - * Return the data for this value as a dimension. Only use for values - * whose type is {@link #TYPE_DIMENSION}. - * - * @param metrics Current display metrics to use in the conversion -- - * supplies display density and scaling information. - * - * @return The complex floating point value multiplied by the appropriate - * metrics depending on its unit. - */ - public float getDimension(DisplayMetrics metrics) - { - return complexToDimension(data, metrics); - } - - /** - * Converts a complex data value holding a fraction to its final floating - * point value. The given data must be structured as a - * {@link #TYPE_FRACTION}. - * - * @param data A complex data value holding a unit, magnitude, and - * mantissa. - * @param base The base value of this fraction. In other words, a - * standard fraction is multiplied by this value. - * @param pbase The parent base value of this fraction. In other - * words, a parent fraction (nn%p) is multiplied by this - * value. - * - * @return The complex floating point value multiplied by the appropriate - * base value depending on its unit. - */ - public static float complexToFraction(int data, float base, float pbase) - { - switch ((data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK) { - case COMPLEX_UNIT_FRACTION: - return complexToFloat(data) * base; - case COMPLEX_UNIT_FRACTION_PARENT: - return complexToFloat(data) * pbase; - } - return 0; - } - - /** - * Return the data for this value as a fraction. Only use for values whose - * type is {@link #TYPE_FRACTION}. - * - * @param base The base value of this fraction. In other words, a - * standard fraction is multiplied by this value. - * @param pbase The parent base value of this fraction. In other - * words, a parent fraction (nn%p) is multiplied by this - * value. - * - * @return The complex floating point value multiplied by the appropriate - * base value depending on its unit. - */ - public float getFraction(float base, float pbase) - { - return complexToFraction(data, base, pbase); - } - - /** - * Regardless of the actual type of the value, try to convert it to a - * string value. For example, a color type will be converted to a - * string of the form #aarrggbb. - * - * @return CharSequence The coerced string value. If the value is - * null or the type is not known, null is returned. - */ - public final CharSequence coerceToString() - { - int t = type; - if (t == TYPE_STRING) { - return string; - } - return coerceToString(t, data); - } - - private static final String[] DIMENSION_UNIT_STRS = new String[] { - "px", "dip", "sp", "pt", "in", "mm" - }; - private static final String[] FRACTION_UNIT_STRS = new String[] { - "%", "%p" - }; - - /** - * Perform type conversion as per {@link #coerceToString()} on an - * explicitly supplied type and data. - * - * @param type The data type identifier. - * @param data The data value. - * - * @return String The coerced string value. If the value is - * null or the type is not known, null is returned. - */ - public static final String coerceToString(int type, int data) - { - switch (type) { - case TYPE_NULL: - return null; - case TYPE_REFERENCE: - return "@" + data; - case TYPE_ATTRIBUTE: - return "?" + data; - case TYPE_FLOAT: - return Float.toString(Float.intBitsToFloat(data)); - case TYPE_DIMENSION: - return Float.toString(complexToFloat(data)) + DIMENSION_UNIT_STRS[ - (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK]; - case TYPE_FRACTION: - return Float.toString(complexToFloat(data)*100) + FRACTION_UNIT_STRS[ - (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK]; - case TYPE_INT_HEX: - return "0x" + Integer.toHexString(data); - case TYPE_INT_BOOLEAN: - return data != 0 ? "true" : "false"; - } - - if (type >= TYPE_FIRST_COLOR_INT && type <= TYPE_LAST_COLOR_INT) { - return "#" + Integer.toHexString(data); - } else if (type >= TYPE_FIRST_INT && type <= TYPE_LAST_INT) { - return Integer.toString(data); - } - - return null; - } - - public void setTo(TypedValue other) - { - type = other.type; - string = other.string; - data = other.data; - assetCookie = other.assetCookie; - resourceId = other.resourceId; - density = other.density; - } - - public String toString() - { - StringBuilder sb = new StringBuilder(); - sb.append("TypedValue{t=0x").append(Integer.toHexString(type)); - sb.append("/d=0x").append(Integer.toHexString(data)); - if (type == TYPE_STRING) { - sb.append(" \"").append(string != null ? string : "").append("\""); - } - if (assetCookie != 0) { - sb.append(" a=").append(assetCookie); - } - if (resourceId != 0) { - sb.append(" r=0x").append(Integer.toHexString(resourceId)); - } - sb.append("}"); - return sb.toString(); - } -}; - diff --git a/src/main/java/android/util/Xml.java b/src/main/java/android/util/Xml.java deleted file mode 100644 index 041e8a8..0000000 --- a/src/main/java/android/util/Xml.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.io.StringReader; -import java.io.UnsupportedEncodingException; -import org.apache.harmony.xml.ExpatReader; -import org.kxml2.io.KXmlParser; -import org.xml.sax.ContentHandler; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.XMLReader; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlPullParserFactory; -import org.xmlpull.v1.XmlSerializer; - -/** - * XML utility methods. - */ -public class Xml { - /** @hide */ public Xml() {} - - /** - * {@link org.xmlpull.v1.XmlPullParser} "relaxed" feature name. - * - * @see - * specification - */ - public static String FEATURE_RELAXED = "http://xmlpull.org/v1/doc/features.html#relaxed"; - - /** - * Parses the given xml string and fires events on the given SAX handler. - */ - public static void parse(String xml, ContentHandler contentHandler) - throws SAXException { - try { - XMLReader reader = new ExpatReader(); - reader.setContentHandler(contentHandler); - reader.parse(new InputSource(new StringReader(xml))); - } catch (IOException e) { - throw new AssertionError(e); - } - } - - /** - * Parses xml from the given reader and fires events on the given SAX - * handler. - */ - public static void parse(Reader in, ContentHandler contentHandler) - throws IOException, SAXException { - XMLReader reader = new ExpatReader(); - reader.setContentHandler(contentHandler); - reader.parse(new InputSource(in)); - } - - /** - * Parses xml from the given input stream and fires events on the given SAX - * handler. - */ - public static void parse(InputStream in, Encoding encoding, - ContentHandler contentHandler) throws IOException, SAXException { - XMLReader reader = new ExpatReader(); - reader.setContentHandler(contentHandler); - InputSource source = new InputSource(in); - source.setEncoding(encoding.expatName); - reader.parse(source); - } - - /** - * Returns a new pull parser with namespace support. - */ - public static XmlPullParser newPullParser() { - try { - KXmlParser parser = new KXmlParser(); - parser.setFeature(XmlPullParser.FEATURE_PROCESS_DOCDECL, true); - parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); - return parser; - } catch (XmlPullParserException e) { - throw new AssertionError(); - } - } - - /** - * Creates a new xml serializer. - */ - public static XmlSerializer newSerializer() { - try { - return XmlSerializerFactory.instance.newSerializer(); - } catch (XmlPullParserException e) { - throw new AssertionError(e); - } - } - - /** Factory for xml serializers. Initialized on demand. */ - static class XmlSerializerFactory { - static final String TYPE - = "org.kxml2.io.KXmlParser,org.kxml2.io.KXmlSerializer"; - static final XmlPullParserFactory instance; - static { - try { - instance = XmlPullParserFactory.newInstance(TYPE, null); - } catch (XmlPullParserException e) { - throw new AssertionError(e); - } - } - } - - /** - * Supported character encodings. - */ - public enum Encoding { - - US_ASCII("US-ASCII"), - UTF_8("UTF-8"), - UTF_16("UTF-16"), - ISO_8859_1("ISO-8859-1"); - - final String expatName; - - Encoding(String expatName) { - this.expatName = expatName; - } - } - - /** - * Finds an encoding by name. Returns UTF-8 if you pass {@code null}. - */ - public static Encoding findEncodingByName(String encodingName) - throws UnsupportedEncodingException { - if (encodingName == null) { - return Encoding.UTF_8; - } - - for (Encoding encoding : Encoding.values()) { - if (encoding.expatName.equalsIgnoreCase(encodingName)) - return encoding; - } - throw new UnsupportedEncodingException(encodingName); - } - - /** - * Return an AttributeSet interface for use with the given XmlPullParser. - * If the given parser itself implements AttributeSet, that implementation - * is simply returned. Otherwise a wrapper class is - * instantiated on top of the XmlPullParser, as a proxy for retrieving its - * attributes, and returned to you. - * - * @param parser The existing parser for which you would like an - * AttributeSet. - * - * @return An AttributeSet you can use to retrieve the - * attribute values at each of the tags as the parser moves - * through its XML document. - * - * @see AttributeSet - */ - public static AttributeSet asAttributeSet(XmlPullParser parser) { - return (parser instanceof AttributeSet) - ? (AttributeSet) parser - : new XmlPullAttributes(parser); - } -} diff --git a/src/main/java/android/util/XmlPullAttributes.java b/src/main/java/android/util/XmlPullAttributes.java deleted file mode 100644 index 6c8bb39..0000000 --- a/src/main/java/android/util/XmlPullAttributes.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -import org.xmlpull.v1.XmlPullParser; - -import android.util.AttributeSet; - -import com.android.internal.util.XmlUtils; - -/** - * Provides an implementation of AttributeSet on top of an XmlPullParser. - */ -class XmlPullAttributes implements AttributeSet { - public XmlPullAttributes(XmlPullParser parser) { - mParser = parser; - } - - public int getAttributeCount() { - return mParser.getAttributeCount(); - } - - public String getAttributeName(int index) { - return mParser.getAttributeName(index); - } - - public String getAttributeValue(int index) { - return mParser.getAttributeValue(index); - } - - public String getAttributeValue(String namespace, String name) { - return mParser.getAttributeValue(namespace, name); - } - - public String getPositionDescription() { - return mParser.getPositionDescription(); - } - - public int getAttributeNameResource(int index) { - return 0; - } - - public int getAttributeListValue(String namespace, String attribute, - String[] options, int defaultValue) { - return XmlUtils.convertValueToList( - getAttributeValue(namespace, attribute), options, defaultValue); - } - - public boolean getAttributeBooleanValue(String namespace, String attribute, - boolean defaultValue) { - return XmlUtils.convertValueToBoolean( - getAttributeValue(namespace, attribute), defaultValue); - } - - public int getAttributeResourceValue(String namespace, String attribute, - int defaultValue) { - return XmlUtils.convertValueToInt( - getAttributeValue(namespace, attribute), defaultValue); - } - - public int getAttributeIntValue(String namespace, String attribute, - int defaultValue) { - return XmlUtils.convertValueToInt( - getAttributeValue(namespace, attribute), defaultValue); - } - - public int getAttributeUnsignedIntValue(String namespace, String attribute, - int defaultValue) { - return XmlUtils.convertValueToUnsignedInt( - getAttributeValue(namespace, attribute), defaultValue); - } - - public float getAttributeFloatValue(String namespace, String attribute, - float defaultValue) { - String s = getAttributeValue(namespace, attribute); - if (s != null) { - return Float.parseFloat(s); - } - return defaultValue; - } - - public int getAttributeListValue(int index, - String[] options, int defaultValue) { - return XmlUtils.convertValueToList( - getAttributeValue(index), options, defaultValue); - } - - public boolean getAttributeBooleanValue(int index, boolean defaultValue) { - return XmlUtils.convertValueToBoolean( - getAttributeValue(index), defaultValue); - } - - public int getAttributeResourceValue(int index, int defaultValue) { - return XmlUtils.convertValueToInt( - getAttributeValue(index), defaultValue); - } - - public int getAttributeIntValue(int index, int defaultValue) { - return XmlUtils.convertValueToInt( - getAttributeValue(index), defaultValue); - } - - public int getAttributeUnsignedIntValue(int index, int defaultValue) { - return XmlUtils.convertValueToUnsignedInt( - getAttributeValue(index), defaultValue); - } - - public float getAttributeFloatValue(int index, float defaultValue) { - String s = getAttributeValue(index); - if (s != null) { - return Float.parseFloat(s); - } - return defaultValue; - } - - public String getIdAttribute() { - return getAttributeValue(null, "id"); - } - - public String getClassAttribute() { - return getAttributeValue(null, "class"); - } - - public int getIdAttributeResourceValue(int defaultValue) { - return getAttributeResourceValue(null, "id", defaultValue); - } - - public int getStyleAttribute() { - return getAttributeResourceValue(null, "style", 0); - } - - /*package*/ XmlPullParser mParser; -} diff --git a/src/main/java/android/util/Xml_Delegate.java b/src/main/java/android/util/Xml_Delegate.java deleted file mode 100644 index a193330..0000000 --- a/src/main/java/android/util/Xml_Delegate.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2014 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.util; - -import com.android.layoutlib.bridge.impl.DelegateManager; -import com.android.tools.layoutlib.annotations.LayoutlibDelegate; - -import org.kxml2.io.KXmlParser; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -/** - * Delegate overriding some methods of android.util.Xml - * - * Through the layoutlib_create tool, the original methods of Xml have been replaced - * by calls to methods of the same name in this delegate class. - * - * Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager} - * around to map int to instance of the delegate. - */ -public class Xml_Delegate { - - @LayoutlibDelegate - /*package*/ static XmlPullParser newPullParser() { - try { - KXmlParser parser = new KXmlParser(); - // The prebuilt kxml2 library with the IDE doesn't support DOCECL. -// parser.setFeature(XmlPullParser.FEATURE_PROCESS_DOCDECL, true); - parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); - return parser; - } catch (XmlPullParserException e) { - throw new AssertionError(); - } - } -} diff --git a/src/main/java/framework/network/HttpAsyncConnection.java b/src/main/java/framework/network/HttpAsyncConnection.java index c4b3a8e..49ae5a6 100644 --- a/src/main/java/framework/network/HttpAsyncConnection.java +++ b/src/main/java/framework/network/HttpAsyncConnection.java @@ -10,11 +10,10 @@ import java.net.MalformedURLException; import java.net.URL; -import android.os.AsyncTask; -import android.util.Log; +//import android.os.AsyncTask; +//import android.util.Log; - -abstract public class HttpAsyncConnection extends AsyncTask { +abstract public class HttpAsyncConnection extends Thread{ private HttpURLConnection conn = null; private String baseUrl = null; @@ -30,42 +29,42 @@ public HttpAsyncConnection(String url) { baseUrl = url; } - - + + public void doPost() { setMethod("POST"); - execute(); + start(); } - + public void doGet() { setMethod("GET"); - execute(); + start(); } - + public void doPut() { setMethod("PUT"); - execute(); + start(); } - + public void doDelete() { setMethod("DELETE"); - execute(); + start(); } - + public void setCallBack(CallBack callBack) { this.callBack = callBack; } - + private void setMethod(String method) { this.method = method; } - - @Override - protected String doInBackground(Void... urls) { + + public void run() { doAnything(); - return doReceive(); + onPostExecute(doReceive()); } + /* (non-Javadoc) * @see android.os.AsyncTask#onPostExecute(java.lang.Object) */ @@ -74,11 +73,11 @@ if (callBack != null) callBack.onResponse(response); } catch (Exception e) { // TODO: handle exception - e.printStackTrace(); + //Log.d("error", "エラー!"); } } - + // request public void doAnything() { try { @@ -107,9 +106,9 @@ } pathParams = ""; queryParams = ""; - + conn.connect(); - + if(clientSessionID == null ) { clientSessionID = conn.getHeaderField("Set-Cookie"); @@ -153,14 +152,14 @@ } queryParams += (key + "=" + value); } - + public void addFormParam(String key, String value) { if(formParams.length() > 0) { formParams += "&"; } formParams += (key + "=" + value); } - + public void addPathParam(String param){ pathParams += "/" + param; } diff --git a/src/main/java/org/ntlab/SproutServer/accounts/Account.java b/src/main/java/org/ntlab/SproutServer/accounts/Account.java deleted file mode 100644 index 4d50c76..0000000 --- a/src/main/java/org/ntlab/SproutServer/accounts/Account.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.ntlab.SproutServer.accounts; - -import java.net.URI; - -import javax.ws.rs.FormParam; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.UriBuilder; - -public class Account { - - private String userName; //ユーザーネーム - private String mode = null; //モード選択 - private int userID; //ユーザID - - public Account(int userID,String userName){ - this.userID = userID; - this.userName = userName; - } - - public Account(){ - - } - - public static Account getInstance() { - return getInstance(); - } - - public String getUserName() { - return userName; - } - - public void setUserName(String userName) { - this.userName = userName; - } - - public String getMode() { - return mode; - } - - public void setMode(String mode) { - this.mode = mode; - } - - public int getUserID() { - return userID; - } - - public void setUserID(int userID) { - this.userID = userID; - } -} diff --git a/src/main/java/org/ntlab/SproutServer/accounts/Accounts.java b/src/main/java/org/ntlab/SproutServer/accounts/Accounts.java deleted file mode 100644 index 8e3cd50..0000000 --- a/src/main/java/org/ntlab/SproutServer/accounts/Accounts.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.ntlab.SproutServer.accounts; - -import javax.inject.Singleton; -import javax.ws.rs.*; -import javax.ws.rs.core.MediaType; -import java.util.ArrayList; - - -public class Accounts { - - private static Accounts theInstance = null; - private ArrayList accounts = new ArrayList(); - private int userID = 0; - - public Accounts() { - if (theInstance == null) { - theInstance = this; - } - } - - public static Accounts getInstance() { - if (theInstance == null) { - theInstance = new Accounts(); - } - return theInstance; - } - - - public void createAccount(int userId){ - Account newAccount = new Account(userId, "user"+userId); - accounts.add(newAccount); - System.out.println(accounts.size()); - } - - - public Accounts getAccount() { - Account ac = new Account(); - this.userID = ac.getUserID(); - return new Accounts(); - } - - public boolean checkCreatedUser(int userId) { - for (Account account : accounts) { - if (account.getUserID() == userId) { - return true; - } - } - return false; - } - - public ArrayList getAccounts() { - return accounts; - } - - public void setAccounts(ArrayList accounts) { - this.accounts = accounts; - } - - public String getUserNameById(int userId){ - for (Account account: accounts){ - if (account.getUserID() == userId) - return account.getUserName(); - } - return "nameNone"; - } - - public int getUserID() { - return userID; - } - - public void setUserID(int userId){ - this.userID = userId; - } -} \ No newline at end of file diff --git a/src/main/java/org/ntlab/SproutServer/accounts/AccountsRest.java b/src/main/java/org/ntlab/SproutServer/accounts/AccountsRest.java deleted file mode 100644 index 7686bce..0000000 --- a/src/main/java/org/ntlab/SproutServer/accounts/AccountsRest.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.ntlab.SproutServer.accounts; - -import javax.ws.rs.*; -import javax.ws.rs.core.MediaType; -import java.util.ArrayList; - -@Path("accounts") -public class AccountsRest { - Accounts accounts; - - @POST - @Produces(MediaType.APPLICATION_JSON) - public Account createAcount(@FormParam("userName") String userName) { - int userId = accounts.getUserID(); - System.out.println(userName); - - Account newAccount = new Account(accounts.getUserID(),userName); -// newAccount.setUserName(userName);s -// accounts.add(new Account(this.userID,userName)); - accounts.getAccounts().add(newAccount); - userId++; - accounts.setUserID(userId); - - return newAccount; - } - - @GET - @Produces(MediaType.APPLICATION_JSON) - public ArrayList getAccountList() { - return accounts.getAccounts(); - } - - @Path("/{userID}") - @PUT - @Produces(MediaType.APPLICATION_JSON) - public Account updateAcount(@PathParam("userID") String userID, @FormParam("userName") String userName, @FormParam("mode") String mode) { - Account editAccount = accounts.getAccounts().get(Integer.valueOf(userID)); - - editAccount.setUserName(userName); - editAccount.setMode(mode); - - accounts.getAccounts().set(Integer.valueOf(userID), editAccount); - - return editAccount; - } - - @Path("/{userID}") - @GET - @Produces(MediaType.APPLICATION_JSON) - public Account getAcount(@PathParam("userID") String userID) { - Account editAccount = accounts.getAccounts().get(Integer.valueOf(userID)); - return editAccount; - } - -} diff --git a/src/main/java/org/ntlab/SproutServer/battles/Battle.java b/src/main/java/org/ntlab/SproutServer/battles/Battle.java deleted file mode 100644 index 8a618d9..0000000 --- a/src/main/java/org/ntlab/SproutServer/battles/Battle.java +++ /dev/null @@ -1,255 +0,0 @@ -package org.ntlab.SproutServer.battles; - -import framework.model3D.Placeable; -import framework.model3D.Position3D; -import framework.model3D.Universe; -import framework.physics.Ground; -import org.ntlab.SproutServer.rooms.Room; -import org.ntlab.SproutServer.rooms.Rooms; - -import javax.vecmath.Vector3d; -import java.net.URLDecoder; -import java.util.ArrayList; -import java.util.HashMap; - -/** - * バトル - * - * @author matsumoto_k - */ -public class Battle { - private HashMap teamMap = new HashMap<>(); // チームの情報を保持 - private double time = BattlesConst.BATTLE_INIT_TIME; // タイム - private Universe universe = null; - private Ground ground = null; - - private int teamId1 = -1; // チームを判別するID - private int teamId2 = -1; // チームを判別するID - /** - * バトルの状態に関する変数 - * battle:対戦中, end:終了 - */ - private String state = "battle"; - - public Battle(Room room1, Room room2) { - universe = new Universe(); - teamId1 = room1.getRoomId(); - teamId2 = room2.getRoomId(); - teamMap.put(room1.getRoomId(), new Team(room1)); - teamMap.put(room2.getRoomId(), new Team(room2)); - - ground = createStage(); - placeStage(ground); - } - - public Team getTeam(int roomId) { - return teamMap.get(roomId); - } - - public HashMap getTeamMap() { - return teamMap; - } - - public void setTeamMap(HashMap teamMap) { - this.teamMap = teamMap; - } - - public double getTime() { - return time; - } - - public void setTime(double time) { - } - - public String getState() { - return state; - } - - public void setState(String state) { - this.state = state; - } - - /** - * ステージを作成 - * - * @return ステージオブジェクト - */ - private Ground createStage() { - String path = ""; - try { - path = URLDecoder.decode(Battles.getInstance().getClass().getResource("standardStage.obj").getPath(), "utf-8"); - } catch (Exception e) { - System.out.println("error path"); - } - return new StandardStage(path); - } - - /** - * ステージを配置 - * - * @param ground 配置するステージオブジェクト - */ - private void placeStage(Ground ground) { - universe.place(ground); - } - - /** - * idによってチームを取得する - * - * @param teamId 取得したいチームのID - * @return チーム - */ - private Team findTeamByID(int teamId) { - return teamMap.get(teamId); - } - - /** - * 対戦相手のチームを取得 - * - * @param teamId 自身のteamId - * @return 対戦相手のチーム - */ - private Team getOppositeTeam(int teamId) { - if (teamId != teamId1) - return findTeamByID(teamId1); - return findTeamByID(teamId2); - } - - /** - * クライアントからのアップデート - * - * @param userId - * @param teamId - * @param playerData 更新するプレイヤーデータ - */ - public void update(int userId, int teamId, PlayerData playerData) { - Player player = findTeamByID(teamId).findPlayerById(userId); - - Position3D position3D = player.getPlayerPosition3d(); // 更新する前のプレイヤーの位置を記録 - Vector3d vector3d = player.getPlayerVector3d(); // 更新する前のプレイヤーの向きを状態を記録 - - /* プレイヤーのアップデート */ - player.update(playerData.getUserPosition(), playerData.getUserVector()); - - /* プレイヤー同士の衝突判定 */ - boolean collision = checkPlayerCollision(player, userId); - player.setPlayerCollision(collision); - - /* プレイヤー同士が衝突していた時は前の状態に戻す */ - if (player.isPlayerCollision()) { - player.update(position3D, vector3d); - } - - /* playerと相手チームの弾の衝突判定 */ - checkCollisionWithWeapons(player, teamId); - - /* playerDataに弾の情報が含まれている ∧ プレイヤーが生きている 場合実行 */ - if (playerData.isWeaponShoot() && player.isAlive()) { - // switch (Role.getRole(Rooms.getInstance().roomList.get(teamId).getMemberList().get(userId).getRole())){ - //case Gunman: - Bullet bullet = findTeamByID(teamId).createBullet(playerData.getWeaponPosition(), playerData.getWeaponVector(), playerData.getWeaponVelocity()); - universe.place(bullet.getActor()); - // break; - //case Witch: - //Magic magic = findTeamByID(teamId).createMagic(playerData.getWeaponPosition(), playerData.getWeaponVector(), playerData.getWeaponVelocity()); - //universe.place(magic.getActor()); - // break; - //} - } - - /* 生存者による勝利のチェック */ - updateResultByAllDead(); - } - - /** - * プレイヤーの衝突判定 - * - * @param player プレイヤーインスタンス - * @param userId userId - * @return 衝突している時はtrue, していない時はfalse - */ - public boolean checkPlayerCollision(Player player, int userId) { - return findTeamByID(teamId1).checkCollision(player, userId) || findTeamByID(teamId2).checkCollision(player, userId); - } - - private void playerUpdate(Player player, Position3D userPosition, Vector3d userVector) { - player.update(userPosition, userVector); - } - - /** - * プレイヤーと相手チームの武器の衝突判定 - * - * @param player - * @param teamId - */ - public void checkCollisionWithWeapons(Player player, int teamId) { - ArrayList colliedObjects = getOppositeTeam(teamId).getColliedObjects(player); // 取り除くオブジェクトを取得に変更する - for (Placeable obj : colliedObjects) { - universe.displace(obj); - } - } - - /** - * バトルをアップデートする - */ - public void update() { - if (getTime() > 0) { - this.time -= BattlesConst.UPDATE_INTERVAL; - } else { - updateResultByTimeOut(); - return; - } - /* universeに配置している全ての武器を動かす */ - universe.update(BattlesConst.UPDATE_INTERVAL); - checkAllWeaponCollision(findTeamByID(teamId1), findTeamByID(teamId2)); - updateResultByAllDead(); - } - - /** - * 両チームのプレイヤーと弾の当たり判定 - */ - public void checkAllWeaponCollision(Team team1, Team team2) { - ArrayList displaceObj = team1.getColliedObjects(team2); - for (Placeable obj : displaceObj) { - universe.displace(obj); - } - displaceObj = team2.getColliedObjects(team1); - for (Placeable obj : displaceObj) { - universe.displace(obj); - } - } - - /** - * 生存者の数によって勝敗をチェックする - */ - private void updateResultByTimeOut() { - if (findTeamByID(teamId1).getAliveCount() > findTeamByID(teamId2).getAliveCount()) - findTeamByID(teamId1).setResult(true); - else - findTeamByID(teamId2).setResult(true); - finish(); - } - - /** - * 生存者による勝敗のチェック - */ - private void updateResultByAllDead() { - Team team1 = findTeamByID(teamId1); - Team team2 = findTeamByID(teamId2); - - if (team1.isAllPlayerDead() || team2.isAllPlayerDead()) { - team1.setResult(!team1.isAllPlayerDead()); - team2.setResult(!team2.isAllPlayerDead()); - finish(); - } - } - - /** - * バトルを終了させる - */ - public void finish() { - state = "end"; - Rooms.getInstance().getRoomList().get(teamId1).roomInitialize(); - Rooms.getInstance().getRoomList().get(teamId2).roomInitialize(); - } -} \ No newline at end of file diff --git a/src/main/java/org/ntlab/SproutServer/battles/Battles.java b/src/main/java/org/ntlab/SproutServer/battles/Battles.java deleted file mode 100644 index b8fa527..0000000 --- a/src/main/java/org/ntlab/SproutServer/battles/Battles.java +++ /dev/null @@ -1,103 +0,0 @@ -package org.ntlab.SproutServer.battles; - -import net.arnx.jsonic.JSON; -import org.ntlab.SproutServer.accounts.Accounts; -import org.ntlab.SproutServer.rooms.Room; -import org.ntlab.SproutServer.rooms.Rooms; - -import javax.inject.Singleton; -import javax.print.attribute.standard.Media; -import javax.ws.rs.*; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.UriInfo; -import java.util.HashMap; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -/** - * バトルを管理するクラス - * - * @author matsumoto_k - */ -public class Battles implements Runnable { - private static Battles theInstance = null; // シングルトンパターン - private HashMap battleMap = new HashMap<>(); // バトル一覧 - private int battleCount = 0; // バトルを識別するためのid - private ScheduledThreadPoolExecutor schedule = null; - - @Context - UriInfo uriInfo; - - private Battles() { - System.out.println("create battles singleton"); - schedule = new ScheduledThreadPoolExecutor(1); - schedule.scheduleAtFixedRate(this, BattlesConst.UPDATE_DELAY, BattlesConst.UPDATE_INTERVAL, TimeUnit.MILLISECONDS); - } - - public static Battles getInstance() { - if (theInstance == null) { - theInstance = new Battles(); - } - return theInstance; - } - - // バトル作成 - public int createBattle(Room room1, Room room2) { - Battle battle = new Battle(room1, room2); - battleMap.put(battleCount, battle); - int resBattleCount = battleCount; - battleCount++; - return resBattleCount; - } - - // ダミーバトル作成 - public void createDummyBattle(int battleId, Room room1, Room room2) { - Battle battle = new Battle(room1, room2); - if (battleMap.get(battleId) != null) { - battleMap.remove(battleId); - } - battleMap.put(battleId, battle); - } - - // バトル削除 - public void removeBattle(int battleId) { - battleMap.remove(battleId); - } - - public HashMap getBattleMap() { - return battleMap; - } - - /** - * プレイヤー情報の更新 - * - * @param battleId バトルID - * @param roomId ルームID - * @param userId ユーザーID - * @param playerData 更新するプレイヤーの情報 - */ - public void updatePlayer(int battleId, int roomId, int userId, PlayerData playerData) { - findBattleById(battleId).update(userId, roomId, playerData); - } - - /** - * Battlesのメインループ - */ - @Override - public void run() { - for (Battle battle : battleMap.values()) { - battle.update(); - } - } - - /** - * battleIdによってBattleを取得 - * - * @param battleId 取得したいbattleのbattleId - * @return Battle - */ - public Battle findBattleById(int battleId) { - return battleMap.get(battleId); - } -} diff --git a/src/main/java/org/ntlab/SproutServer/battles/BattlesConst.java b/src/main/java/org/ntlab/SproutServer/battles/BattlesConst.java deleted file mode 100644 index 98e277e..0000000 --- a/src/main/java/org/ntlab/SproutServer/battles/BattlesConst.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.ntlab.SproutServer.battles; - -/** - * バトルで利用する定数 - * - * @author matsumoto_k - */ -public class BattlesConst { - /** - * ゲームをループさせるスレッドのコアプールサイズ - */ - public static final int CORE_POOL_SIZE = 1; - /** - * ゲームをループさせるインターバル(ミリ秒) - */ - public static final int UPDATE_INTERVAL = 100; - /** - * ゲームをループさせる時の初期遅延時間(ミリ秒) - */ - public static final int UPDATE_DELAY = 1000; - /** - * バトルの初期時間(ミリ秒) - */ - public static final long BATTLE_INIT_TIME = 3000000; - /** - * プレイヤーの初期ヒットポイント - */ - public static final int PLAYER_INIT_HP = 1000; - /** - * 弾の寿命(ミリ秒) - */ - public static final long BULLET_LIFE_TIME = 3000; -} diff --git a/src/main/java/org/ntlab/SproutServer/battles/BattlesRest.java b/src/main/java/org/ntlab/SproutServer/battles/BattlesRest.java deleted file mode 100644 index a133434..0000000 --- a/src/main/java/org/ntlab/SproutServer/battles/BattlesRest.java +++ /dev/null @@ -1,91 +0,0 @@ -package org.ntlab.SproutServer.battles; - - -import net.arnx.jsonic.JSON; -import org.ntlab.SproutServer.accounts.Accounts; -import org.ntlab.SproutServer.rooms.Rooms; - -import javax.ws.rs.*; -import javax.ws.rs.core.MediaType; -import java.util.HashMap; - -/** - * http://nitta-lab-www2.is.konan-u.ac.jp/battles - * 上記URIへの各種リクエストを処理するクラス - * - * @author matsumoto_k - */ -@Path("battles") -public class BattlesRest { - public BattlesRest(){ - - } - - @Path("/test") - @GET - @Produces(MediaType.TEXT_PLAIN) - public String hoge() { - return "deploy jenkins from tomcat"; - } - - /** - * バトル一覧取得API - * @return バトル一覧 - */ - @GET - @Produces(MediaType.APPLICATION_JSON) - public HashMap getBattle(){ - return Battles.getInstance().getBattleMap(); - } - - /** - * 指定したbattleIdのバトルを取得する - * @param battleId - * @return - */ - @Path("/{battleId}") - @GET - @Produces(MediaType.APPLICATION_JSON) - public Battle getBattle(@PathParam("battleId") int battleId) { - return Battles.getInstance().getBattleMap().get(battleId); - } - - /** - * 指定したパラメータのバトルを更新する - * @param battleId - * @param roomId - * @param userId - * @param stringPlayerData - * @return - */ - @Path("/{battleId}") - @PUT - public Battle putBattle(@PathParam("battleId") int battleId, @FormParam("roomId") int roomId, - @FormParam("userId") int userId, @FormParam("playerData") String stringPlayerData) { - PlayerData playerData = JSON.decode(stringPlayerData, PlayerData.class); - Battles.getInstance().updatePlayer(battleId, roomId, userId, playerData); - return Battles.getInstance().findBattleById(battleId); - } - - /** - * ダミーデータの作成 - */ - @Path("/develop") - @GET - public void createDummyBattle() { - Accounts accounts = Accounts.getInstance(); - if (!accounts.checkCreatedUser(1000)) { - for (int i = 1000; i < 1008; i++) { - accounts.createAccount(i); - } - } - Rooms rooms = Rooms.getInstance(); - rooms.makeRoomBattle(1000, 1000, "room1", "hoge"); - - rooms.makeRoomBattle(1001, 1004, "room2", "hoge"); - - int battleId = 1000; - - Battles.getInstance().createDummyBattle(battleId, rooms.getRoomList().get(1000), rooms.getRoomList().get(1001)); - } -} diff --git a/src/main/java/org/ntlab/SproutServer/battles/Bullet.java b/src/main/java/org/ntlab/SproutServer/battles/Bullet.java deleted file mode 100644 index 2b7ce41..0000000 --- a/src/main/java/org/ntlab/SproutServer/battles/Bullet.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.ntlab.SproutServer.battles; - -import framework.model3D.CollisionResult; -import framework.model3D.Object3D; -import framework.model3D.Position3D; -import framework.physics.Solid3D; -import framework.physics.Velocity3D; -import net.arnx.jsonic.JSONHint; - -import javax.vecmath.Vector3d; -import java.net.URLDecoder; - -/** - * プレイヤーの弾 - * - * @author matsumoto_k - */ -public class Bullet extends Weapon { - - private static final int attack = 100; - - public Bullet(Position3D position3D, Vector3d vector3d, Velocity3D velocity3D) { - this.actor = new WeaponActor(new Solid3D(createObject()), null) { - @Override - public void onIntersect(CollisionResult normal, long interval) { - if (normal != null) - alive = false; - } - }; - initWeapon(position3D, vector3d, velocity3D); - } - - @Override - Object3D createObject() { - //TODO:弾のオブジェクトを決める - String path = Battles.getInstance().getClass().getResource("pocha.stl").getPath(); - try { - path = URLDecoder.decode(path, "utf-8"); - } catch (Exception e) { - - } - BulletModel bulletModel = new BulletModel(path, null); - return bulletModel.createObject(); - } - - public Position3D getPosition3d() { - return getActor().getPosition(); - } - - public Vector3d getVector3d() { - return getActor().getDirection(); - } - - @Override - long getInitWeaponLife() { - return BattlesConst.BULLET_LIFE_TIME; - } - - @Override - @JSONHint(ignore = true) - public int getAttack() { - return attack; - } -} diff --git a/src/main/java/org/ntlab/SproutServer/battles/BulletModel.java b/src/main/java/org/ntlab/SproutServer/battles/BulletModel.java deleted file mode 100644 index 64bd5aa..0000000 --- a/src/main/java/org/ntlab/SproutServer/battles/BulletModel.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.ntlab.SproutServer.battles; - -import framework.model3D.ModelFactory; -import framework.model3D.Object3D; - -public class BulletModel { - String modelFileName = null; - String animationFileName = null; - - public BulletModel(String modelFileName, String animationFileName) { - this.modelFileName = modelFileName; - this.animationFileName = animationFileName; - } - - public Object3D createObject() { - Object3D object3D = null; - try { - object3D = ModelFactory.loadModel(modelFileName, false, false).createObject(); - } catch (Exception e) { - - } - return object3D; - } -} diff --git a/src/main/java/org/ntlab/SproutServer/battles/Magic.java b/src/main/java/org/ntlab/SproutServer/battles/Magic.java deleted file mode 100644 index 16df108..0000000 --- a/src/main/java/org/ntlab/SproutServer/battles/Magic.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.ntlab.SproutServer.battles; - -import framework.model3D.CollisionResult; -import framework.model3D.Object3D; -import framework.model3D.Position3D; -import framework.physics.Solid3D; -import framework.physics.Velocity3D; -import net.arnx.jsonic.JSONHint; - -import javax.vecmath.Vector3d; -import java.net.URLDecoder; - -/** - * プレイヤーの魔法 - * - * @author matsumoto_k - */ -public class Magic extends Weapon { - - private static final int attack = 100; - - public Magic(Position3D position3D, Vector3d vector3d, Velocity3D velocity3D) { - this.actor = new WeaponActor(new Solid3D(createObject()), null) { - @Override - public void onIntersect(CollisionResult normal, long interval) { - } - }; - initWeapon(position3D, vector3d, velocity3D); - } - - @Override - Object3D createObject() { - //TODO:弾のオブジェクトを決める - String path = Battles.getInstance().getClass().getResource("pocha.stl").getPath(); - try { - path = URLDecoder.decode(path, "utf-8"); - } catch (Exception e) { - - } - BulletModel bulletModel = new BulletModel(path, null); - return bulletModel.createObject(); - } - - public Position3D getPosition3d() { - return getActor().getPosition(); - } - - public Vector3d getVector3d() { - return getActor().getDirection(); - } - - @Override - long getInitWeaponLife() { - return BattlesConst.BULLET_LIFE_TIME; - } - - @Override - @JSONHint(ignore = true) - public int getAttack() { - return attack; - } -} diff --git a/src/main/java/org/ntlab/SproutServer/battles/Player.java b/src/main/java/org/ntlab/SproutServer/battles/Player.java deleted file mode 100644 index 3fe8e72..0000000 --- a/src/main/java/org/ntlab/SproutServer/battles/Player.java +++ /dev/null @@ -1,198 +0,0 @@ -package org.ntlab.SproutServer.battles; - -import framework.animation.Animation3D; -import framework.gameMain.OvergroundActor; -import framework.model3D.Object3D; -import framework.model3D.Position3D; -import framework.physics.PhysicsUtility; -import framework.physics.Solid3D; -import net.arnx.jsonic.JSONHint; -import org.ntlab.SproutServer.accounts.Accounts; - -import javax.vecmath.Vector3d; -import java.net.URLDecoder; - -/** - * プレイヤー - * - * @author matsumoto_k - */ -public class Player { - - private OvergroundActor actor = null; // プレイヤーのオブジェクト - private int hp = BattlesConst.PLAYER_INIT_HP; // プレイヤーのHP - private boolean playerCollision = false; - private int userId = -1; - private int memberId = -1; - private String userName = ""; - - public Player(int userId, int memberId) { - this.userId = userId; - this.memberId = memberId; - this.userName = Accounts.getInstance().getUserNameById(this.userId); - actor = createPlayerObject(null); - setInitDirection(0.0, 0.0, 0.0); - // TODO:初期位置を設定する - setInitPosition(Math.random()*100, Math.random()*100, 0); - } - - /** - * プレイヤーの情報を更新する - * - * @param position3D プレイヤーの位置 - * @param vector3d プレイヤーの向き - */ - public void update(Position3D position3D, Vector3d vector3d) { - actor.setPosition(position3D); // プレイヤーの新しい位置をセット - actor.setDirection(vector3d); // プレイヤーの新しい向いている方向をセット - } - - /** - * プレイヤーのオブジェクトを作成 - * - * @param animation3D アニメーション - * @return プレイヤーのオブジェクト - */ - private OvergroundActor createPlayerObject(Animation3D animation3D) { - // TODO:プレイヤーの見た目を考える - String path = Battles.getInstance().getClass().getResource("pocha.stl").getPath(); - try { - path = URLDecoder.decode(path, "utf-8"); - } catch (Exception e) { - - } - PlayerModel playerModel = new PlayerModel(path, null); - return new OvergroundActor(new Solid3D(playerModel.createObject()), null); - } - - public String getUserName() { - return userName; - } - - /** - * プレイヤーの初期位置を設定する - * - * @param x x座標 - * @param y y座標 - * @param z z座標 - */ - public void setInitPosition(double x, double y, double z){ - actor.setPosition(new Position3D(x, y, z)); - } - - /** - * プレイヤーの初期方向を設定する - * - * @param x x方向 - * @param y y方向 - * @param z z方向 - */ - public void setInitDirection(double x, double y, double z) { - actor.setDirection(new Vector3d(x, y, z)); - } - - /** - * プレイヤーの位置を取得 - * - * @return プレイヤーの位置 - */ - public Position3D getPlayerPosition3d() { - return actor.getPosition(); - } - - /** - * プレイヤーの向きを取得 - * - * @return プレイヤーの向き - */ - public Vector3d getPlayerVector3d() { - return actor.getDirection(); - } - - /** - * プレイヤーのHPを取得 - * - * @return プレイヤーのHP - */ - public int getHp() { - return hp; - } - - /** - * プレイヤーにダメージを与える - * - * @param damage 与えるダメージ - */ - public void setDamage(int damage) { - hp -= damage; - } - - /** - * プレイヤーが生存しているかどうか判定 - * - * @return 生きている:true, 死んでいる:false - */ - @JSONHint(ignore = true) - public boolean isAlive() { - if (hp < 0) { - return false; - } - return true; - } - - /** - * プレイヤー同士の衝突判定 - * - * @param player 判定するプレイヤー - * @return 衝突している時はtrue, していない時はfalse - */ - public boolean checkCollision(Player player) { - if (PhysicsUtility.checkCollision(getBody(), null, player.getBody(), null) != null) { - return true; - } - return false; - } - - public boolean isPlayerCollision() { - return playerCollision; - } - - /** - * プレイヤー同士の衝突フラグ - * - * @param playerCollision - */ - public void setPlayerCollision(boolean playerCollision) { - this.playerCollision = playerCollision; - } - - /** - * プレイヤーのオブジェクトを取得する - * - * @return プレイヤーのオブジェクト - */ - @JSONHint(ignore = true) - public Object3D getBody() { - return actor.body; - } - - /** - * プレイヤーのuserIdを取得する - * - * @return userId - */ - @JSONHint(ignore = true) - public int getUserId() { - return userId; - } - - /** - * プレイヤーのmemberIdを取得する - * - * @return memberId - */ - @JSONHint(ignore = true) - public int getMemberId() { - return memberId; - } -} diff --git a/src/main/java/org/ntlab/SproutServer/battles/PlayerData.java b/src/main/java/org/ntlab/SproutServer/battles/PlayerData.java deleted file mode 100644 index 53a5e65..0000000 --- a/src/main/java/org/ntlab/SproutServer/battles/PlayerData.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.ntlab.SproutServer.battles; - -import framework.model3D.Position3D; -import framework.physics.Velocity3D; - -import javax.vecmath.Vector3d; - -/** - * プレイヤー情報を更新するためのデータ - * - * @author matsumoto_k - */ -public class PlayerData { - - /* プレイヤーに関するデータ */ - private Position3D userPosition = null; // プレイヤーの位置 - private Vector3d userVector = null; // プレイヤー向き - - /* 武器に関するデータ */ - private Position3D weaponPosition = null; // 武器の位置 - private Vector3d weaponVector = null; // 武器の向き - private Velocity3D weaponVelocity = null; // 武器の速度 - - public PlayerData() { - } - - public boolean isWeaponShoot() { - return weaponPosition != null; - } - - public Position3D getUserPosition() { - return userPosition; - } - - public void setUserPosition(Position3D userPosition) { - this.userPosition = userPosition; - } - - public Vector3d getUserVector() { - return userVector; - } - - public void setUserVector(Vector3d userVector) { - this.userVector = userVector; - } - - public Position3D getWeaponPosition() { - return weaponPosition; - } - - public void setWeaponPosition(Position3D weaponPosition) { - this.weaponPosition = weaponPosition; - } - - public Vector3d getWeaponVector() { - return weaponVector; - } - - public void setWeaponVector(Vector3d weaponVector) { - this.weaponVector = weaponVector; - } - - public Velocity3D getWeaponVelocity() { - return weaponVelocity; - } - - public void setWeaponVelocity(Velocity3D weaponVelocity) { - this.weaponVelocity = weaponVelocity; - } -} diff --git a/src/main/java/org/ntlab/SproutServer/battles/PlayerModel.java b/src/main/java/org/ntlab/SproutServer/battles/PlayerModel.java deleted file mode 100644 index eff97bf..0000000 --- a/src/main/java/org/ntlab/SproutServer/battles/PlayerModel.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.ntlab.SproutServer.battles; - -import framework.model3D.ModelFactory; -import framework.model3D.Object3D; - -public class PlayerModel { - String modelFileName = null; - String animationFileName = null; - - public PlayerModel(String modelFileName, String animationFileName) { - this.animationFileName = animationFileName; - this.modelFileName = modelFileName; - } - - public Object3D createObject() { - Object3D object3D = null; - try { - object3D = ModelFactory.loadModel(modelFileName, false, false).createObject(); - } catch (Exception e) { - - } - return object3D; - } -} diff --git a/src/main/java/org/ntlab/SproutServer/battles/Role.java b/src/main/java/org/ntlab/SproutServer/battles/Role.java deleted file mode 100644 index 44e35c2..0000000 --- a/src/main/java/org/ntlab/SproutServer/battles/Role.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.ntlab.SproutServer.battles; - -/** - * 職業に関するクラス - * @author matsumoto_k - */ -public enum Role { - Gunman(0), - Witch(1); - - private int id; - - private Role(int id) { - this.id = id; - } - - public static Role getRole(int id) { - for (Role role : values()) { - if (id == role.id) - return role; - } - return null; - } -} diff --git a/src/main/java/org/ntlab/SproutServer/battles/StandardStage.java b/src/main/java/org/ntlab/SproutServer/battles/StandardStage.java deleted file mode 100644 index 41477d0..0000000 --- a/src/main/java/org/ntlab/SproutServer/battles/StandardStage.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.ntlab.SproutServer.battles; - -import framework.model3D.ModelFactory; -import framework.physics.Ground; -import framework.physics.Solid3D; - -/** - * ステージ - * - * @author matsumoto_k - * TODO:ステージを決める - */ -public class StandardStage extends Ground { - public StandardStage(String filePath) { - super(new Solid3D(ModelFactory.loadModel(filePath, false, false).createObject())); - } -} diff --git a/src/main/java/org/ntlab/SproutServer/battles/Team.java b/src/main/java/org/ntlab/SproutServer/battles/Team.java deleted file mode 100644 index 987379c..0000000 --- a/src/main/java/org/ntlab/SproutServer/battles/Team.java +++ /dev/null @@ -1,264 +0,0 @@ -package org.ntlab.SproutServer.battles; - -import framework.model3D.Placeable; -import framework.model3D.Position3D; -import framework.physics.PhysicsUtility; -import framework.physics.Velocity3D; -import net.arnx.jsonic.JSONHint; -import org.ntlab.SproutServer.rooms.Member; -import org.ntlab.SproutServer.rooms.Room; - -import javax.vecmath.Vector3d; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -/** - * チーム - * - * @author matsumoto_k - */ -public class Team { - private HashMap playerMap = new HashMap<>(); // チームのプレイヤー情報 - private HashMap bullets = new HashMap<>(); // チームの弾の情報 - private HashMap magics = new HashMap<>(); // チームの魔法の情報 - private int bulletId = 0; // 弾を判別するID - private int magicId = 0; - private boolean result; // 勝敗 - - public Team(Room room) { - playerMap = new HashMap<>(); - for (Member member : room.getMemberList().values()) { - /** - * e.getKey : userId - */ - playerMap.put(member.getUserId(), new Player(member.getUserId(), member.getMemberId())); - } - } - - public HashMap getPlayerMap() { - return playerMap; - } - - public void setPlayerMap(HashMap playerMap) { - this.playerMap = playerMap; - } - - public boolean isResult() { - return result; - } - - public void setResult(boolean result) { - this.result = result; - } - - public HashMap getBullets() { - return bullets; - } - - public HashMap getMagics() { - return magics; - } - - /** - * userIdによってプレイヤーを取得 - * - * @param userId 取得するプレイヤーのuserId - * @return プレイヤー - */ - public Player findPlayerById(int userId) { - return playerMap.get(userId); - } - - /** - * チーム内の生存者の数を取得する - * - * @return 生存者の数 - */ - @JSONHint(ignore = true) - public int getAliveCount() { - int count = 0; - for (Player player : playerMap.values()) { - if (player.isAlive()) - count++; - } - return count; - } - - /** - * チーム内のプレイヤーが全員死亡しているか取得 - * - * @return 全員死亡している:true, 一人でも生きている:false - */ - @JSONHint(ignore = true) - public boolean isAllPlayerDead() { - if (getAliveCount() == 0) - return true; - return false; - } - - /** - * 自クラスの武器と他のチームのプレイヤーの衝突したオブジェクトを取得する - * - * @param enemyTeam 判定させるチーム - * @return colliedObjects 衝突したオブジェクト - */ - public ArrayList getColliedObjects(Team enemyTeam) { - ArrayList colliedObjects = new ArrayList<>(); - - /* 弾 */ - for (Iterator bulletIterator = bullets.values().iterator(); bulletIterator.hasNext(); ) { - Bullet bullet = bulletIterator.next(); - - if (!bullet.isAlive()) { - colliedObjects.add(bullet.getActor()); - bulletIterator.remove(); - continue; - } - - for (Player player : enemyTeam.getPlayerMap().values()) { - /* 自チームの弾と他のチームのプレイヤーが衝突した時 */ - if (checkCollision(bullet, player)) { - /* 他のチームのプレイヤーにダメージを与える */ - player.setDamage(bullet.getAttack()); - /* 弾は取り除く */ - colliedObjects.add(bullet.getActor()); - bulletIterator.remove(); - } - } - } - - /* 魔法 */ - for (Iterator magicIterator = magics.values().iterator(); magicIterator.hasNext(); ) { - Magic magic = magicIterator.next(); - - if (!magic.isAlive()) { - colliedObjects.add(magic.getActor()); - magicIterator.remove(); - continue; - } - - for (Player player : enemyTeam.getPlayerMap().values()) { - /* 自チームの弾と他のチームのプレイヤーが衝突した時 */ - if (checkCollision(magic, player)) { - /* 他のチームのプレイヤーにダメージを与える */ - player.setDamage(magic.getAttack()); - /* 弾は取り除く */ - colliedObjects.add(magic.getActor()); - magicIterator.remove(); - } - } - } - - return colliedObjects; - } - - /** - * 自クラスの武器と他のチームのプレイヤーの衝突したオブジェクトを取得する - * - * @param enemyPlayer 敵プレイヤー - * @return 衝突したオブジェクト - */ - public ArrayList getColliedObjects(Player enemyPlayer) { - ArrayList obj = new ArrayList<>(); - - /* 弾 */ - for (Iterator bulletIterator = bullets.values().iterator(); bulletIterator.hasNext(); ) { - Bullet bullet = bulletIterator.next(); - - if (!bullet.isAlive()) { - obj.add(bullet.getActor()); - bulletIterator.remove(); - continue; - } - - if (checkCollision(bullet, enemyPlayer)) { - /* 他のチームのプレイヤーにダメージを与える */ - enemyPlayer.setDamage(bullet.getAttack()); - /* 弾は取り除く */ - obj.add(bullet.getActor()); - bulletIterator.remove(); - } - } - - /* 魔法 */ - for (Iterator magicIterator = magics.values().iterator(); magicIterator.hasNext(); ) { - Magic magic = magicIterator.next(); - - if (!magic.isAlive()) { - obj.add(magic.getActor()); - magicIterator.remove(); - continue; - } - - if (checkCollision(magic, enemyPlayer)) { - /* 他のチームのプレイヤーにダメージを与える */ - enemyPlayer.setDamage(magic.getAttack()); - /* 弾は取り除く */ - obj.add(magic.getActor()); - magicIterator.remove(); - } - } - return obj; - } - - /** - * プレイヤーと武器の衝突判定 - * - * @param weapon - * @param player 他のチームのプレイヤー - * @return - */ - public boolean checkCollision(Weapon weapon, Player player) { - return PhysicsUtility.checkCollision(weapon.getBody(), null, player.getBody(), null) != null; - } - - /** - * チーム内のプレイヤーとの衝突判定 - * - * @param player 判定するプレイヤー - * @param playerId 判定するプレイヤーid - * @return 衝突している時はtrue, していない時はfalse - */ - public boolean checkCollision(Player player, int playerId) { - for (Map.Entry entry : playerMap.entrySet()) { - /* idがplayerと違う時 */ - if (entry.getKey() != playerId) { - if (player.checkCollision(entry.getValue())) - return true; - } - } - return false; - } - - /** - * プレイヤーの弾を作成する - * - * @param position3D 弾の位置 - * @param vector3d 弾の向き - * @param velocity3D 弾の速度 - * @return - */ - public Bullet createBullet(Position3D position3D, Vector3d vector3d, Velocity3D velocity3D) { - Bullet bullet = new Bullet(position3D, vector3d, velocity3D); - bullets.put(bulletId, bullet); - bulletId++; - return bullet; - } - - /** - * プレイヤーの魔法を作成する - * - * @param position3D 魔法の位置 - * @param vector3d 魔法の向き - * @param velocity3D 魔法の速度 - * @return - */ - public Magic createMagic(Position3D position3D, Vector3d vector3d, Velocity3D velocity3D) { - Magic magic = new Magic(position3D, vector3d, velocity3D); - magics.put(magicId, magic); - magicId++; - return magic; - } -} diff --git a/src/main/java/org/ntlab/SproutServer/battles/Weapon.java b/src/main/java/org/ntlab/SproutServer/battles/Weapon.java deleted file mode 100644 index 5cb5eb4..0000000 --- a/src/main/java/org/ntlab/SproutServer/battles/Weapon.java +++ /dev/null @@ -1,137 +0,0 @@ -package org.ntlab.SproutServer.battles; - -import framework.animation.Animation3D; -import framework.gameMain.Actor; -import framework.model3D.CollisionResult; -import framework.model3D.Object3D; -import framework.model3D.Position3D; -import framework.physics.Force3D; -import framework.physics.Ground; -import framework.physics.Solid3D; -import framework.physics.Velocity3D; -import net.arnx.jsonic.JSONHint; - -import javax.vecmath.Vector3d; - -/** - * 飛ぶ武器 - * - * @author matsumoto_k - */ -abstract class Weapon { - - protected boolean alive = true; // 武器の生存フラグ - private long left = 0; // 武器の寿命 - private int attack = 0; // 武器の攻撃力 - protected Actor actor; // 武器のオブジェクト - - public Weapon() { - left = getInitWeaponLife(); - attack = getAttack(); - this.actor = new WeaponActor(new Solid3D(createObject()), null) { - public void onIntersect(CollisionResult normal, long interval) { - if (normal != null) - alive = false; - } - }; - } - - abstract protected class WeaponActor extends Actor { - protected WeaponActor(Solid3D o, Animation3D animation3D) { - super(o, animation3D); - } - - @Override - public void onEndFall() { - - } - - @Override - abstract public void onIntersect(CollisionResult normal, long interval); - - @Override - public void motion(long interval, Ground ground) { - super.motion(interval, ground); - left -= interval; - if (left < 0L) { - alive = false; - } - } - - @Override - public Force3D getGravity() { - return Force3D.ZERO; - } - - @Override - public void onEndAnimation() { - - } - } - - /** - * 武器のオブジェクトを作成する - * - * @return 武器のオブジェクト - */ - abstract Object3D createObject(); - - /** - * 武器の初期値を設定 - * - * @param weaponPosition 武器の位置 - * @param weaponVector 武器の方向 - * @param weaponVelocity 武器の速度 - */ - public void initWeapon(Position3D weaponPosition, Vector3d weaponVector, Velocity3D weaponVelocity) { - actor.setPosition(weaponPosition); // 弾の位置を設定 - actor.setDirection(weaponVector); // 弾の方向を設定 - actor.setVelocity(weaponVelocity); // 弾の速度を設定 - } - - /** - * 武器のActorを取得 - * - * @return 武器のActor - */ - @JSONHint(ignore = true) - public Actor getActor() { - return actor; - } - - /** - * 武器のオブジェクトを取得 - * - * @return 武器のオブジェクト - */ - @JSONHint(ignore = true) - public Object3D getBody() { - return actor.body; - } - - /** - * 武器の生存確認 - * - * @return 武器が壁や地面と接触した、武器の寿命が切れたなどの場合はfalseを返す - */ - @JSONHint(ignore = true) - public boolean isAlive() { - return alive; - } - - /** - * 武器の初期寿命を取得 - * - * @return 武器の初期寿命(ミリ秒) - */ - @JSONHint(ignore = true) - abstract long getInitWeaponLife(); - - /** - * 武器の攻撃力を取得 - * - * @return 武器の攻撃力 - */ - @JSONHint(ignore = true) - abstract public int getAttack(); -} diff --git a/src/main/java/org/ntlab/SproutServer/rooms/Member.java b/src/main/java/org/ntlab/SproutServer/rooms/Member.java deleted file mode 100644 index c634fce..0000000 --- a/src/main/java/org/ntlab/SproutServer/rooms/Member.java +++ /dev/null @@ -1,102 +0,0 @@ -package org.ntlab.SproutServer.rooms; -import java.util.ArrayList; - -import javax.ws.rs.DELETE; -import javax.ws.rs.GET; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; - -import org.ntlab.SproutServer.accounts.Account; -import org.ntlab.SproutServer.accounts.Accounts; - -import net.arnx.jsonic.JSONHint; - -/** - * Root resource (exposed at "Rooms" path) - */ - -public class Member { - - /** - * アカウントリストからユーザ情報の検索 - */ - public Member(int userId) { - Accounts ac = Accounts.getInstance(); - for(int i=0; i memberList = new HashMap(); - public boolean readyToFight = false; //全員準備完了したか判定 - private int memberId=0; - public boolean startFrag; - public boolean battleState = false; - public int battleId = -1; - - - public Room(String roomName,int roomId,String roomKey,Member member){ - this.roomId = roomId; - this.roomName = roomName; - this.roomKey = roomKey; - this.memberList.put(this.memberId,member); - memberList.get(this.memberId).setMemberId(this.memberId); - this.memberList.get(memberId).setHostState(true); - this.hostName = member.getUserName(); - this.memberId++; - - if(roomKey != null){ - this.keyCheck = true; - } - - } - - public Room(int roomId){ - this.roomId = roomId; - } - - public Room() { - // TODO Auto-generated constructor stub - } - - - /** - * 入室処理 - */ - public void enterRoom(int memberId,Member member){ - getMemberList().put(memberId, member); - this.memberList.get(this.memberId).setMemberId(this.memberId); - this.memberId++; - } - - /** - * パスワードのチェック - */ - public boolean keyCheck(String key,int memberId){ - if(this.keyCheck == false){ - return true; - } - - boolean counts = false; - if(key.equals(this.getRoomKey())){ - counts = true; - } - System.out.println("key chek = " + counts); - return counts; - } - - - /** - * バトル終了時のルームの状態の初期化 - */ - public void roomInitialize(){ - this.battleState = false; - this.readyToFight = false; - this.startFrag = false; - this.battleId = -1; - for(int value : this.memberList.keySet()){ - if(this.memberList.get(value) != null){ - this.memberList.get(value).setReady(false); - } - } - } - - - /** - * ホストの次に入った人のメンバーIDを返す - */ - public int minimumMemberCount(int memberId){ - int count = 0; - for(int i = 0;i getMemberList() { - return memberList; - } - - public void setMemberList(HashMap memberList) { - this.memberList = memberList; - } - - - //ルームID - @JSONHint(ignore=true) - public int getRoomId() { - return roomId; - } - - public void setId(int id) { - this.roomId = id; - } - - - //ルーム名 - @JSONHint(ignore=true) - public String getRoomName() { - return roomName; - } - - public void setRoomName(String roomName) { - this.roomName = roomName; - } - - - //ホストネーム - @JSONHint(ignore=true) - public String getHostName() { - return hostName; - } - - public void setHostName(String hostName) { - this.hostName = hostName; - } - - - //キーのチェック - @JSONHint(ignore=true) - public boolean isKeyCheck() { - return keyCheck; - } - - public void setKeyCheck(boolean keyCheck) { - this.keyCheck = keyCheck; - } - - - //準備完了判定 - @JSONHint(ignore=true) - public boolean isReadyToFight() { - return readyToFight; - } - - public void setReadyToFight(boolean allReady) { - this.readyToFight = allReady; - } - - - //ルームキー(ルームパスワード) - @JSONHint(ignore=true) - public String getRoomKey() { - return roomKey; - } - - public void setRoomKey(String roomKey) { - this.roomKey = roomKey; - } - - //メンバーID(入った順番) - @JSONHint(ignore=true) - public int getMemberId() { - return memberId; - } - - public void setMemberId(int memberId) { - this.memberId = memberId; - } - - //全員準備 - public boolean isStartFrag() { - return startFrag; - } - - public void setStartFrag(boolean startFrag) { - this.startFrag = startFrag; - } - - //バトル中か否か - public boolean isBattleState() { - return battleState; - } - - public void setBattleState(boolean battleState) { - this.battleState = battleState; - } - - - //バトルID - public int getBattleId() { - return battleId; - } - - public void setBattleId(int battleId) { - this.battleId = battleId; - } - - - - - - - - - - - - - - - -} diff --git a/src/main/java/org/ntlab/SproutServer/rooms/RoomResponse.java b/src/main/java/org/ntlab/SproutServer/rooms/RoomResponse.java deleted file mode 100644 index ce16feb..0000000 --- a/src/main/java/org/ntlab/SproutServer/rooms/RoomResponse.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.ntlab.SproutServer.rooms; - -public class RoomResponse { - - public Room room; - public int memberId; - public boolean check; - public int battleId; - - public RoomResponse(Room room,int userId,int memberId,boolean check){ - this.room = room; - this.check = check; - this.memberId = memberId; - } - - public RoomResponse(Room room,int userId){ - this.room = room; - this.battleId = room.getBattleId(); - for(int i = 0;i roomList = new HashMap(); - public int roomId = 0; // ルームID - private Room waitingRoom = null; //待ち部屋 - private Room waitingRoomSecond = null; //待ち部屋2 - - - - - private Rooms(){ - if (theInstance == null) { - theInstance = this; - } - } - - public static Rooms getInstance() { - if (theInstance == null) { - theInstance = new Rooms(); - } - return theInstance; - } - - - - /** - * 部屋のメンバーの準備チェック - */ - public int readyCheck(int roomId,boolean frag){ - int checkCount = 0; - int battleCount = 0; - Room room = roomList.get(roomId); - - if(frag == true){ - for(int i = 0;i getRoomList() { - return roomList; - } - - -// public void setRoomList(HashMap roomList) { -// Rooms.roomList = roomList; -// } - - - //待ち部屋1 - //@JSONHint(ignore=true) - public Room getWaitingRoom() { - return waitingRoom; - } - - public void setWaitingRoom(Room waitingRoom) { - this.waitingRoom = waitingRoom; - } - - //待ち部屋2 - //@JSONHint(ignore=true) - public Room getWaitingRoomSecond() { - return waitingRoomSecond; - } - - public void setWaitingRoomSecond(Room waitingRoomSecond) { - this.waitingRoomSecond = waitingRoomSecond; - } - - //人数 - @JSONHint(ignore=true) - public int getPlayerNumber() { - return playerNumber; - } - - - //ルームID - public int getRoomId() { - return roomId; - } - - public void setRoomId(int roomId) { - this.roomId = roomId; - } - - -} diff --git a/src/main/java/org/ntlab/SproutServer/rooms/RoomsRest.java b/src/main/java/org/ntlab/SproutServer/rooms/RoomsRest.java deleted file mode 100644 index 0202eda..0000000 --- a/src/main/java/org/ntlab/SproutServer/rooms/RoomsRest.java +++ /dev/null @@ -1,216 +0,0 @@ -package org.ntlab.SproutServer.rooms; - -import org.ntlab.SproutServer.battles.Battles; - -import javax.ws.rs.*; -import javax.ws.rs.core.MediaType; -import java.util.HashMap; - -@Path("rooms") -public class RoomsRest { - - Rooms rooms; - /** - * 部屋一覧取得(Rooms) - */ - @GET - @Produces(MediaType.APPLICATION_JSON) - public Rooms roomsView() { - return rooms.getInstance(); - } - - - /** - * 部屋の状態(Room) - */ - @GET - @Path("/{roomId}") - @Produces(MediaType.APPLICATION_JSON) - public Room roomState(@PathParam("roomId") int roomId){ - return rooms.getRoomList().get(roomId); - } - - - /** - * 他アカウント情報取得(member) - */ - @GET - @Path("/{roomId}/{memberId}") - @Produces(MediaType.APPLICATION_JSON) - public HashMap getOtherAccount(@PathParam("roomId") int roomId, @QueryParam("userId") int userId) { - return rooms.getRoomList().get(roomId).getMemberList(); - } - - - /** - * 部屋作成(Rooms) - */ - @POST - @Produces(MediaType.APPLICATION_JSON) - public RoomResponse makeRoom(@FormParam("userId") int userId, @FormParam("roomName") String roomName, @FormParam("key") String key) { - int roomId = rooms.getRoomId(); - Member member = new Member(userId); - - Room room = new Room(roomName,rooms.getRoomId(),key,member); - rooms.getRoomList().put(rooms.getRoomId(),room); - - RoomResponse roomRes = new RoomResponse(room, userId); - - roomId++; - rooms.setRoomId(roomId); - - return roomRes; - } - - - /** - * 入室(Room) - */ - @PUT - @Path("/{roomId}") - @Produces(MediaType.APPLICATION_JSON) - public RoomResponse enterRoom(@PathParam("roomId") int roomId,@FormParam("userId") int userId,@FormParam("key") String key){ - Room room = rooms.getRoomList().get(roomId); - RoomResponse roomRes; - int memberId = room.getMemberId(); - boolean check = room.keyCheck(key, memberId); - boolean keyCheck = true; - - if(check == true && room.getMemberList().size() accounts = new ArrayList(); + private int userID = 0; + private AccountsConnection accountsConnection = null; + + private Accounts() { + + } + + public static Accounts getInstance() { + if (theInstance == null) { + theInstance = new Accounts(); + } + return theInstance; + } + + + public void createAccount(int userId){ + Account newAccount = new Account(userId, "user"+userId); + accounts.add(newAccount); + System.out.println(accounts.size()); + } + + + public Accounts getAccount() { + Account ac = new Account(); + this.userID = ac.getUserID(); + return new Accounts(); + } + + public boolean checkCreatedUser(int userId) { + for (Account account : accounts) { + if (account.getUserID() == userId) { + return true; + } + } + return false; + } + + public ArrayList getAccounts() { + return accounts; + } + + public void setAccounts(ArrayList accounts) { + this.accounts = accounts; + } + + public String getUserNameById(int userId){ + for (Account account: accounts){ + if (account.getUserID() == userId) + return account.getUserName(); + } + return "nameNone"; + } + + public int getUserID() { + return userID; + } + + public void setUserID(int userId){ + this.userID = userId; + } + + @JSONHint(ignore = true) + public AccountsConnection getAccountsConnection() { + return accountsConnection; + } +} \ No newline at end of file diff --git a/src/main/java/org/ntlab/SproutServerMicro/accounts/AccountsConnection.java b/src/main/java/org/ntlab/SproutServerMicro/accounts/AccountsConnection.java new file mode 100644 index 0000000..0832cf5 --- /dev/null +++ b/src/main/java/org/ntlab/SproutServerMicro/accounts/AccountsConnection.java @@ -0,0 +1,10 @@ +package org.ntlab.SproutServerMicro.accounts; + +import framework.network.HttpAsyncConnection; + +public class AccountsConnection extends HttpAsyncConnection{ + + public AccountsConnection(){ + super("http://nitta-lab-www2.is.konan-u.ac.jp:8080/SproutServerMicro/accounts"); + } +} diff --git a/src/main/java/org/ntlab/SproutServerMicro/accounts/AccountsRest.java b/src/main/java/org/ntlab/SproutServerMicro/accounts/AccountsRest.java new file mode 100644 index 0000000..24a0920 --- /dev/null +++ b/src/main/java/org/ntlab/SproutServerMicro/accounts/AccountsRest.java @@ -0,0 +1,59 @@ +package org.ntlab.SproutServerMicro.accounts; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import java.util.ArrayList; + +@Path("accounts") +public class AccountsRest { + Accounts accounts; + + public AccountsRest() { + accounts = Accounts.getInstance(); + } + + @POST + @Produces(MediaType.APPLICATION_JSON) + public Account createAcount(@FormParam("userName") String userName) { + int userId = accounts.getUserID(); + System.out.println(userName); + + Account newAccount = new Account(accounts.getUserID(),userName); +// newAccount.setUserName(userName);s +// accounts.add(new Account(this.userID,userName)); + accounts.getAccounts().add(newAccount); + userId++; + accounts.setUserID(userId); + + return newAccount; + } + + @GET + @Produces(MediaType.APPLICATION_JSON) + public ArrayList getAccountList() { + return accounts.getAccounts(); + } + + @Path("/{userID}") + @PUT + @Produces(MediaType.APPLICATION_JSON) + public Account updateAcount(@PathParam("userID") String userID, @FormParam("userName") String userName, @FormParam("mode") String mode) { + Account editAccount = accounts.getAccounts().get(Integer.valueOf(userID)); + + editAccount.setUserName(userName); + editAccount.setMode(mode); + + accounts.getAccounts().set(Integer.valueOf(userID), editAccount); + + return editAccount; + } + + @Path("/{userID}") + @GET + @Produces(MediaType.APPLICATION_JSON) + public Account getAcount(@PathParam("userID") String userID) { + Account editAccount = accounts.getAccounts().get(Integer.valueOf(userID)); + return editAccount; + } + +} diff --git a/src/main/java/org/ntlab/SproutServerMicro/battles/Battle.java b/src/main/java/org/ntlab/SproutServerMicro/battles/Battle.java new file mode 100644 index 0000000..bc35ad7 --- /dev/null +++ b/src/main/java/org/ntlab/SproutServerMicro/battles/Battle.java @@ -0,0 +1,255 @@ +package org.ntlab.SproutServerMicro.battles; + +import framework.model3D.Placeable; +import framework.model3D.Position3D; +import framework.model3D.Universe; +import framework.physics.Ground; +import org.ntlab.SproutServerMicro.rooms.Room; +import org.ntlab.SproutServerMicro.rooms.Rooms; + +import javax.vecmath.Vector3d; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.HashMap; + +/** + * バトル + * + * @author matsumoto_k + */ +public class Battle { + private HashMap teamMap = new HashMap<>(); // チームの情報を保持 + private double time = BattlesConst.BATTLE_INIT_TIME; // タイム + private Universe universe = null; + private Ground ground = null; + + private int teamId1 = -1; // チームを判別するID + private int teamId2 = -1; // チームを判別するID + /** + * バトルの状態に関する変数 + * battle:対戦中, end:終了 + */ + private String state = "battle"; + + public Battle(Room room1, Room room2) { + universe = new Universe(); + teamId1 = room1.getRoomId(); + teamId2 = room2.getRoomId(); + teamMap.put(room1.getRoomId(), new Team(room1)); + teamMap.put(room2.getRoomId(), new Team(room2)); + + ground = createStage(); + placeStage(ground); + } + + public Team getTeam(int roomId) { + return teamMap.get(roomId); + } + + public HashMap getTeamMap() { + return teamMap; + } + + public void setTeamMap(HashMap teamMap) { + this.teamMap = teamMap; + } + + public double getTime() { + return time; + } + + public void setTime(double time) { + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + /** + * ステージを作成 + * + * @return ステージオブジェクト + */ + private Ground createStage() { + String path = ""; + try { + path = URLDecoder.decode(Battles.getInstance().getClass().getResource("standardStage.obj").getPath(), "utf-8"); + } catch (Exception e) { + System.out.println("error path"); + } + return new StandardStage(path); + } + + /** + * ステージを配置 + * + * @param ground 配置するステージオブジェクト + */ + private void placeStage(Ground ground) { + universe.place(ground); + } + + /** + * idによってチームを取得する + * + * @param teamId 取得したいチームのID + * @return チーム + */ + private Team findTeamByID(int teamId) { + return teamMap.get(teamId); + } + + /** + * 対戦相手のチームを取得 + * + * @param teamId 自身のteamId + * @return 対戦相手のチーム + */ + private Team getOppositeTeam(int teamId) { + if (teamId != teamId1) + return findTeamByID(teamId1); + return findTeamByID(teamId2); + } + + /** + * クライアントからのアップデート + * + * @param userId + * @param teamId + * @param playerData 更新するプレイヤーデータ + */ + public void update(int userId, int teamId, PlayerData playerData) { + Player player = findTeamByID(teamId).findPlayerById(userId); + + Position3D position3D = player.getPlayerPosition3d(); // 更新する前のプレイヤーの位置を記録 + Vector3d vector3d = player.getPlayerVector3d(); // 更新する前のプレイヤーの向きを状態を記録 + + /* プレイヤーのアップデート */ + player.update(playerData.getUserPosition(), playerData.getUserVector()); + + /* プレイヤー同士の衝突判定 */ + boolean collision = checkPlayerCollision(player, userId); + player.setPlayerCollision(collision); + + /* プレイヤー同士が衝突していた時は前の状態に戻す */ + if (player.isPlayerCollision()) { + player.update(position3D, vector3d); + } + + /* playerと相手チームの弾の衝突判定 */ + checkCollisionWithWeapons(player, teamId); + + /* playerDataに弾の情報が含まれている ∧ プレイヤーが生きている 場合実行 */ + if (playerData.isWeaponShoot() && player.isAlive()) { + // switch (Role.getRole(Rooms.getInstance().roomList.get(teamId).getMemberList().get(userId).getRole())){ + //case Gunman: + Bullet bullet = findTeamByID(teamId).createBullet(playerData.getWeaponPosition(), playerData.getWeaponVector(), playerData.getWeaponVelocity()); + universe.place(bullet.getActor()); + // break; + //case Witch: + //Magic magic = findTeamByID(teamId).createMagic(playerData.getWeaponPosition(), playerData.getWeaponVector(), playerData.getWeaponVelocity()); + //universe.place(magic.getActor()); + // break; + //} + } + + /* 生存者による勝利のチェック */ + updateResultByAllDead(); + } + + /** + * プレイヤーの衝突判定 + * + * @param player プレイヤーインスタンス + * @param userId userId + * @return 衝突している時はtrue, していない時はfalse + */ + public boolean checkPlayerCollision(Player player, int userId) { + return findTeamByID(teamId1).checkCollision(player, userId) || findTeamByID(teamId2).checkCollision(player, userId); + } + + private void playerUpdate(Player player, Position3D userPosition, Vector3d userVector) { + player.update(userPosition, userVector); + } + + /** + * プレイヤーと相手チームの武器の衝突判定 + * + * @param player + * @param teamId + */ + public void checkCollisionWithWeapons(Player player, int teamId) { + ArrayList colliedObjects = getOppositeTeam(teamId).getColliedObjects(player); // 取り除くオブジェクトを取得に変更する + for (Placeable obj : colliedObjects) { + universe.displace(obj); + } + } + + /** + * バトルをアップデートする + */ + public void update() { + if (getTime() > 0) { + this.time -= BattlesConst.UPDATE_INTERVAL; + } else { + updateResultByTimeOut(); + return; + } + /* universeに配置している全ての武器を動かす */ + universe.update(BattlesConst.UPDATE_INTERVAL); + checkAllWeaponCollision(findTeamByID(teamId1), findTeamByID(teamId2)); + updateResultByAllDead(); + } + + /** + * 両チームのプレイヤーと弾の当たり判定 + */ + public void checkAllWeaponCollision(Team team1, Team team2) { + ArrayList displaceObj = team1.getColliedObjects(team2); + for (Placeable obj : displaceObj) { + universe.displace(obj); + } + displaceObj = team2.getColliedObjects(team1); + for (Placeable obj : displaceObj) { + universe.displace(obj); + } + } + + /** + * 生存者の数によって勝敗をチェックする + */ + private void updateResultByTimeOut() { + if (findTeamByID(teamId1).getAliveCount() > findTeamByID(teamId2).getAliveCount()) + findTeamByID(teamId1).setResult(true); + else + findTeamByID(teamId2).setResult(true); + finish(); + } + + /** + * 生存者による勝敗のチェック + */ + private void updateResultByAllDead() { + Team team1 = findTeamByID(teamId1); + Team team2 = findTeamByID(teamId2); + + if (team1.isAllPlayerDead() || team2.isAllPlayerDead()) { + team1.setResult(!team1.isAllPlayerDead()); + team2.setResult(!team2.isAllPlayerDead()); + finish(); + } + } + + /** + * バトルを終了させる + */ + public void finish() { + state = "end"; + Rooms.getInstance().getRoomList().get(teamId1).roomInitialize(); + Rooms.getInstance().getRoomList().get(teamId2).roomInitialize(); + } +} \ No newline at end of file diff --git a/src/main/java/org/ntlab/SproutServerMicro/battles/Battles.java b/src/main/java/org/ntlab/SproutServerMicro/battles/Battles.java new file mode 100644 index 0000000..5bf3407 --- /dev/null +++ b/src/main/java/org/ntlab/SproutServerMicro/battles/Battles.java @@ -0,0 +1,103 @@ +package org.ntlab.SproutServerMicro.battles; + +import net.arnx.jsonic.JSONHint; +import org.ntlab.SproutServerMicro.rooms.Room; + +import javax.ws.rs.core.Context; +import javax.ws.rs.core.UriInfo; +import java.util.HashMap; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * バトルを管理するクラス + * + * @author matsumoto_k + */ +public class Battles implements Runnable { + private static Battles theInstance = null; // シングルトンパターン + private HashMap battleMap = new HashMap<>(); // バトル一覧 + private int battleCount = 0; // バトルを識別するためのid + private ScheduledThreadPoolExecutor schedule = null; + private BattlesConnection battlesConnection = null; + + @Context + UriInfo uriInfo; + + private Battles() { + System.out.println("create battles singleton"); + schedule = new ScheduledThreadPoolExecutor(1); + schedule.scheduleAtFixedRate(this, BattlesConst.UPDATE_DELAY, BattlesConst.UPDATE_INTERVAL, TimeUnit.MILLISECONDS); + } + + public static Battles getInstance() { + if (theInstance == null) { + theInstance = new Battles(); + } + return theInstance; + } + + // バトル作成 + public int createBattle(Room room1, Room room2) { + Battle battle = new Battle(room1, room2); + battleMap.put(battleCount, battle); + int resBattleCount = battleCount; + battleCount++; + return resBattleCount; + } + + // ダミーバトル作成 + public void createDummyBattle(int battleId, Room room1, Room room2) { + Battle battle = new Battle(room1, room2); + if (battleMap.get(battleId) != null) { + battleMap.remove(battleId); + } + battleMap.put(battleId, battle); + } + + // バトル削除 + public void removeBattle(int battleId) { + battleMap.remove(battleId); + } + + public HashMap getBattleMap() { + return battleMap; + } + + /** + * プレイヤー情報の更新 + * + * @param battleId バトルID + * @param roomId ルームID + * @param userId ユーザーID + * @param playerData 更新するプレイヤーの情報 + */ + public void updatePlayer(int battleId, int roomId, int userId, PlayerData playerData) { + findBattleById(battleId).update(userId, roomId, playerData); + } + + /** + * Battlesのメインループ + */ + @Override + public void run() { + for (Battle battle : battleMap.values()) { + battle.update(); + } + } + + /** + * battleIdによってBattleを取得 + * + * @param battleId 取得したいbattleのbattleId + * @return Battle + */ + public Battle findBattleById(int battleId) { + return battleMap.get(battleId); + } + + @JSONHint(ignore = true) + public BattlesConnection getBattlesConnection() { + return battlesConnection; + } +} diff --git a/src/main/java/org/ntlab/SproutServerMicro/battles/BattlesConnection.java b/src/main/java/org/ntlab/SproutServerMicro/battles/BattlesConnection.java new file mode 100644 index 0000000..cbb48b4 --- /dev/null +++ b/src/main/java/org/ntlab/SproutServerMicro/battles/BattlesConnection.java @@ -0,0 +1,11 @@ +package org.ntlab.SproutServerMicro.battles; + +import framework.network.HttpAsyncConnection; + +public class BattlesConnection extends HttpAsyncConnection { + + public BattlesConnection(){ + super("http://nitta-lab-www3.is.konan-u.ac.jp:8080/SproutServerMicro/battles"); + } +} + diff --git a/src/main/java/org/ntlab/SproutServerMicro/battles/BattlesConst.java b/src/main/java/org/ntlab/SproutServerMicro/battles/BattlesConst.java new file mode 100644 index 0000000..fac52e7 --- /dev/null +++ b/src/main/java/org/ntlab/SproutServerMicro/battles/BattlesConst.java @@ -0,0 +1,33 @@ +package org.ntlab.SproutServerMicro.battles; + +/** + * バトルで利用する定数 + * + * @author matsumoto_k + */ +public class BattlesConst { + /** + * ゲームをループさせるスレッドのコアプールサイズ + */ + public static final int CORE_POOL_SIZE = 1; + /** + * ゲームをループさせるインターバル(ミリ秒) + */ + public static final int UPDATE_INTERVAL = 100; + /** + * ゲームをループさせる時の初期遅延時間(ミリ秒) + */ + public static final int UPDATE_DELAY = 1000; + /** + * バトルの初期時間(ミリ秒) + */ + public static final long BATTLE_INIT_TIME = 3000000; + /** + * プレイヤーの初期ヒットポイント + */ + public static final int PLAYER_INIT_HP = 1000; + /** + * 弾の寿命(ミリ秒) + */ + public static final long BULLET_LIFE_TIME = 3000; +} diff --git a/src/main/java/org/ntlab/SproutServerMicro/battles/BattlesRest.java b/src/main/java/org/ntlab/SproutServerMicro/battles/BattlesRest.java new file mode 100644 index 0000000..f835c8b --- /dev/null +++ b/src/main/java/org/ntlab/SproutServerMicro/battles/BattlesRest.java @@ -0,0 +1,91 @@ +package org.ntlab.SproutServerMicro.battles; + + +import net.arnx.jsonic.JSON; +import org.ntlab.SproutServerMicro.accounts.Accounts; +import org.ntlab.SproutServerMicro.rooms.Rooms; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import java.util.HashMap; + +/** + * http://nitta-lab-www2.is.konan-u.ac.jp/battles + * 上記URIへの各種リクエストを処理するクラス + * + * @author matsumoto_k + */ +@Path("battles") +public class BattlesRest { + public BattlesRest(){ + + } + + @Path("/test") + @GET + @Produces(MediaType.TEXT_PLAIN) + public String hoge() { + return "deploy jenkins from tomcat"; + } + + /** + * バトル一覧取得API + * @return バトル一覧 + */ + @GET + @Produces(MediaType.APPLICATION_JSON) + public HashMap getBattle(){ + return Battles.getInstance().getBattleMap(); + } + + /** + * 指定したbattleIdのバトルを取得する + * @param battleId + * @return + */ + @Path("/{battleId}") + @GET + @Produces(MediaType.APPLICATION_JSON) + public Battle getBattle(@PathParam("battleId") int battleId) { + return Battles.getInstance().getBattleMap().get(battleId); + } + + /** + * 指定したパラメータのバトルを更新する + * @param battleId + * @param roomId + * @param userId + * @param stringPlayerData + * @return + */ + @Path("/{battleId}") + @PUT + public Battle putBattle(@PathParam("battleId") int battleId, @FormParam("roomId") int roomId, + @FormParam("userId") int userId, @FormParam("playerData") String stringPlayerData) { + PlayerData playerData = JSON.decode(stringPlayerData, PlayerData.class); + Battles.getInstance().updatePlayer(battleId, roomId, userId, playerData); + return Battles.getInstance().findBattleById(battleId); + } + + /** + * ダミーデータの作成 + */ + @Path("/develop") + @GET + public void createDummyBattle() { + Accounts accounts = Accounts.getInstance(); + if (!accounts.checkCreatedUser(1000)) { + for (int i = 1000; i < 1008; i++) { + accounts.createAccount(i); + } + } + Rooms rooms = Rooms.getInstance(); + rooms.makeRoomBattle(1000, 1000, "room1", "hoge"); + + rooms.makeRoomBattle(1001, 1004, "room2", "hoge"); + + int battleId = 1000; + + Battles.getInstance().createDummyBattle(battleId, rooms.getRoomList().get(1000), rooms.getRoomList().get(1001)); + } +} diff --git a/src/main/java/org/ntlab/SproutServerMicro/battles/Bullet.java b/src/main/java/org/ntlab/SproutServerMicro/battles/Bullet.java new file mode 100644 index 0000000..98fcf51 --- /dev/null +++ b/src/main/java/org/ntlab/SproutServerMicro/battles/Bullet.java @@ -0,0 +1,64 @@ +package org.ntlab.SproutServerMicro.battles; + +import framework.model3D.CollisionResult; +import framework.model3D.Object3D; +import framework.model3D.Position3D; +import framework.physics.Solid3D; +import framework.physics.Velocity3D; +import net.arnx.jsonic.JSONHint; + +import javax.vecmath.Vector3d; +import java.net.URLDecoder; + +/** + * プレイヤーの弾 + * + * @author matsumoto_k + */ +public class Bullet extends Weapon { + + private static final int attack = 100; + + public Bullet(Position3D position3D, Vector3d vector3d, Velocity3D velocity3D) { + this.actor = new WeaponActor(new Solid3D(createObject()), null) { + @Override + public void onIntersect(CollisionResult normal, long interval) { + if (normal != null) + alive = false; + } + }; + initWeapon(position3D, vector3d, velocity3D); + } + + @Override + Object3D createObject() { + //TODO:弾のオブジェクトを決める + String path = Battles.getInstance().getClass().getResource("pocha.stl").getPath(); + try { + path = URLDecoder.decode(path, "utf-8"); + } catch (Exception e) { + + } + BulletModel bulletModel = new BulletModel(path, null); + return bulletModel.createObject(); + } + + public Position3D getPosition3d() { + return getActor().getPosition(); + } + + public Vector3d getVector3d() { + return getActor().getDirection(); + } + + @Override + long getInitWeaponLife() { + return BattlesConst.BULLET_LIFE_TIME; + } + + @Override + @JSONHint(ignore = true) + public int getAttack() { + return attack; + } +} diff --git a/src/main/java/org/ntlab/SproutServerMicro/battles/BulletModel.java b/src/main/java/org/ntlab/SproutServerMicro/battles/BulletModel.java new file mode 100644 index 0000000..c85c881 --- /dev/null +++ b/src/main/java/org/ntlab/SproutServerMicro/battles/BulletModel.java @@ -0,0 +1,24 @@ +package org.ntlab.SproutServerMicro.battles; + +import framework.model3D.ModelFactory; +import framework.model3D.Object3D; + +public class BulletModel { + String modelFileName = null; + String animationFileName = null; + + public BulletModel(String modelFileName, String animationFileName) { + this.modelFileName = modelFileName; + this.animationFileName = animationFileName; + } + + public Object3D createObject() { + Object3D object3D = null; + try { + object3D = ModelFactory.loadModel(modelFileName, false, false).createObject(); + } catch (Exception e) { + + } + return object3D; + } +} diff --git a/src/main/java/org/ntlab/SproutServerMicro/battles/Magic.java b/src/main/java/org/ntlab/SproutServerMicro/battles/Magic.java new file mode 100644 index 0000000..412ed04 --- /dev/null +++ b/src/main/java/org/ntlab/SproutServerMicro/battles/Magic.java @@ -0,0 +1,62 @@ +package org.ntlab.SproutServerMicro.battles; + +import framework.model3D.CollisionResult; +import framework.model3D.Object3D; +import framework.model3D.Position3D; +import framework.physics.Solid3D; +import framework.physics.Velocity3D; +import net.arnx.jsonic.JSONHint; + +import javax.vecmath.Vector3d; +import java.net.URLDecoder; + +/** + * プレイヤーの魔法 + * + * @author matsumoto_k + */ +public class Magic extends Weapon { + + private static final int attack = 100; + + public Magic(Position3D position3D, Vector3d vector3d, Velocity3D velocity3D) { + this.actor = new WeaponActor(new Solid3D(createObject()), null) { + @Override + public void onIntersect(CollisionResult normal, long interval) { + } + }; + initWeapon(position3D, vector3d, velocity3D); + } + + @Override + Object3D createObject() { + //TODO:弾のオブジェクトを決める + String path = Battles.getInstance().getClass().getResource("pocha.stl").getPath(); + try { + path = URLDecoder.decode(path, "utf-8"); + } catch (Exception e) { + + } + BulletModel bulletModel = new BulletModel(path, null); + return bulletModel.createObject(); + } + + public Position3D getPosition3d() { + return getActor().getPosition(); + } + + public Vector3d getVector3d() { + return getActor().getDirection(); + } + + @Override + long getInitWeaponLife() { + return BattlesConst.BULLET_LIFE_TIME; + } + + @Override + @JSONHint(ignore = true) + public int getAttack() { + return attack; + } +} diff --git a/src/main/java/org/ntlab/SproutServerMicro/battles/Player.java b/src/main/java/org/ntlab/SproutServerMicro/battles/Player.java new file mode 100644 index 0000000..76a7d68 --- /dev/null +++ b/src/main/java/org/ntlab/SproutServerMicro/battles/Player.java @@ -0,0 +1,198 @@ +package org.ntlab.SproutServerMicro.battles; + +import framework.animation.Animation3D; +import framework.gameMain.OvergroundActor; +import framework.model3D.Object3D; +import framework.model3D.Position3D; +import framework.physics.PhysicsUtility; +import framework.physics.Solid3D; +import net.arnx.jsonic.JSONHint; +import org.ntlab.SproutServerMicro.accounts.Accounts; + +import javax.vecmath.Vector3d; +import java.net.URLDecoder; + +/** + * プレイヤー + * + * @author matsumoto_k + */ +public class Player { + + private OvergroundActor actor = null; // プレイヤーのオブジェクト + private int hp = BattlesConst.PLAYER_INIT_HP; // プレイヤーのHP + private boolean playerCollision = false; + private int userId = -1; + private int memberId = -1; + private String userName = ""; + + public Player(int userId, int memberId) { + this.userId = userId; + this.memberId = memberId; + this.userName = Accounts.getInstance().getUserNameById(this.userId); + actor = createPlayerObject(null); + setInitDirection(0.0, 0.0, 0.0); + // TODO:初期位置を設定する + setInitPosition(Math.random()*100, Math.random()*100, 0); + } + + /** + * プレイヤーの情報を更新する + * + * @param position3D プレイヤーの位置 + * @param vector3d プレイヤーの向き + */ + public void update(Position3D position3D, Vector3d vector3d) { + actor.setPosition(position3D); // プレイヤーの新しい位置をセット + actor.setDirection(vector3d); // プレイヤーの新しい向いている方向をセット + } + + /** + * プレイヤーのオブジェクトを作成 + * + * @param animation3D アニメーション + * @return プレイヤーのオブジェクト + */ + private OvergroundActor createPlayerObject(Animation3D animation3D) { + // TODO:プレイヤーの見た目を考える + String path = Battles.getInstance().getClass().getResource("pocha.stl").getPath(); + try { + path = URLDecoder.decode(path, "utf-8"); + } catch (Exception e) { + + } + PlayerModel playerModel = new PlayerModel(path, null); + return new OvergroundActor(new Solid3D(playerModel.createObject()), null); + } + + public String getUserName() { + return userName; + } + + /** + * プレイヤーの初期位置を設定する + * + * @param x x座標 + * @param y y座標 + * @param z z座標 + */ + public void setInitPosition(double x, double y, double z){ + actor.setPosition(new Position3D(x, y, z)); + } + + /** + * プレイヤーの初期方向を設定する + * + * @param x x方向 + * @param y y方向 + * @param z z方向 + */ + public void setInitDirection(double x, double y, double z) { + actor.setDirection(new Vector3d(x, y, z)); + } + + /** + * プレイヤーの位置を取得 + * + * @return プレイヤーの位置 + */ + public Position3D getPlayerPosition3d() { + return actor.getPosition(); + } + + /** + * プレイヤーの向きを取得 + * + * @return プレイヤーの向き + */ + public Vector3d getPlayerVector3d() { + return actor.getDirection(); + } + + /** + * プレイヤーのHPを取得 + * + * @return プレイヤーのHP + */ + public int getHp() { + return hp; + } + + /** + * プレイヤーにダメージを与える + * + * @param damage 与えるダメージ + */ + public void setDamage(int damage) { + hp -= damage; + } + + /** + * プレイヤーが生存しているかどうか判定 + * + * @return 生きている:true, 死んでいる:false + */ + @JSONHint(ignore = true) + public boolean isAlive() { + if (hp < 0) { + return false; + } + return true; + } + + /** + * プレイヤー同士の衝突判定 + * + * @param player 判定するプレイヤー + * @return 衝突している時はtrue, していない時はfalse + */ + public boolean checkCollision(Player player) { + if (PhysicsUtility.checkCollision(getBody(), null, player.getBody(), null) != null) { + return true; + } + return false; + } + + public boolean isPlayerCollision() { + return playerCollision; + } + + /** + * プレイヤー同士の衝突フラグ + * + * @param playerCollision + */ + public void setPlayerCollision(boolean playerCollision) { + this.playerCollision = playerCollision; + } + + /** + * プレイヤーのオブジェクトを取得する + * + * @return プレイヤーのオブジェクト + */ + @JSONHint(ignore = true) + public Object3D getBody() { + return actor.body; + } + + /** + * プレイヤーのuserIdを取得する + * + * @return userId + */ + @JSONHint(ignore = true) + public int getUserId() { + return userId; + } + + /** + * プレイヤーのmemberIdを取得する + * + * @return memberId + */ + @JSONHint(ignore = true) + public int getMemberId() { + return memberId; + } +} diff --git a/src/main/java/org/ntlab/SproutServerMicro/battles/PlayerData.java b/src/main/java/org/ntlab/SproutServerMicro/battles/PlayerData.java new file mode 100644 index 0000000..db05222 --- /dev/null +++ b/src/main/java/org/ntlab/SproutServerMicro/battles/PlayerData.java @@ -0,0 +1,70 @@ +package org.ntlab.SproutServerMicro.battles; + +import framework.model3D.Position3D; +import framework.physics.Velocity3D; + +import javax.vecmath.Vector3d; + +/** + * プレイヤー情報を更新するためのデータ + * + * @author matsumoto_k + */ +public class PlayerData { + + /* プレイヤーに関するデータ */ + private Position3D userPosition = null; // プレイヤーの位置 + private Vector3d userVector = null; // プレイヤー向き + + /* 武器に関するデータ */ + private Position3D weaponPosition = null; // 武器の位置 + private Vector3d weaponVector = null; // 武器の向き + private Velocity3D weaponVelocity = null; // 武器の速度 + + public PlayerData() { + } + + public boolean isWeaponShoot() { + return weaponPosition != null; + } + + public Position3D getUserPosition() { + return userPosition; + } + + public void setUserPosition(Position3D userPosition) { + this.userPosition = userPosition; + } + + public Vector3d getUserVector() { + return userVector; + } + + public void setUserVector(Vector3d userVector) { + this.userVector = userVector; + } + + public Position3D getWeaponPosition() { + return weaponPosition; + } + + public void setWeaponPosition(Position3D weaponPosition) { + this.weaponPosition = weaponPosition; + } + + public Vector3d getWeaponVector() { + return weaponVector; + } + + public void setWeaponVector(Vector3d weaponVector) { + this.weaponVector = weaponVector; + } + + public Velocity3D getWeaponVelocity() { + return weaponVelocity; + } + + public void setWeaponVelocity(Velocity3D weaponVelocity) { + this.weaponVelocity = weaponVelocity; + } +} diff --git a/src/main/java/org/ntlab/SproutServerMicro/battles/PlayerModel.java b/src/main/java/org/ntlab/SproutServerMicro/battles/PlayerModel.java new file mode 100644 index 0000000..1ad33b1 --- /dev/null +++ b/src/main/java/org/ntlab/SproutServerMicro/battles/PlayerModel.java @@ -0,0 +1,24 @@ +package org.ntlab.SproutServerMicro.battles; + +import framework.model3D.ModelFactory; +import framework.model3D.Object3D; + +public class PlayerModel { + String modelFileName = null; + String animationFileName = null; + + public PlayerModel(String modelFileName, String animationFileName) { + this.animationFileName = animationFileName; + this.modelFileName = modelFileName; + } + + public Object3D createObject() { + Object3D object3D = null; + try { + object3D = ModelFactory.loadModel(modelFileName, false, false).createObject(); + } catch (Exception e) { + + } + return object3D; + } +} diff --git a/src/main/java/org/ntlab/SproutServerMicro/battles/Role.java b/src/main/java/org/ntlab/SproutServerMicro/battles/Role.java new file mode 100644 index 0000000..8b7c72b --- /dev/null +++ b/src/main/java/org/ntlab/SproutServerMicro/battles/Role.java @@ -0,0 +1,24 @@ +package org.ntlab.SproutServerMicro.battles; + +/** + * 職業に関するクラス + * @author matsumoto_k + */ +public enum Role { + Gunman(0), + Witch(1); + + private int id; + + private Role(int id) { + this.id = id; + } + + public static Role getRole(int id) { + for (Role role : values()) { + if (id == role.id) + return role; + } + return null; + } +} diff --git a/src/main/java/org/ntlab/SproutServerMicro/battles/StandardStage.java b/src/main/java/org/ntlab/SproutServerMicro/battles/StandardStage.java new file mode 100644 index 0000000..7261d9d --- /dev/null +++ b/src/main/java/org/ntlab/SproutServerMicro/battles/StandardStage.java @@ -0,0 +1,17 @@ +package org.ntlab.SproutServerMicro.battles; + +import framework.model3D.ModelFactory; +import framework.physics.Ground; +import framework.physics.Solid3D; + +/** + * ステージ + * + * @author matsumoto_k + * TODO:ステージを決める + */ +public class StandardStage extends Ground { + public StandardStage(String filePath) { + super(new Solid3D(ModelFactory.loadModel(filePath, false, false).createObject())); + } +} diff --git a/src/main/java/org/ntlab/SproutServerMicro/battles/Team.java b/src/main/java/org/ntlab/SproutServerMicro/battles/Team.java new file mode 100644 index 0000000..5fe3786 --- /dev/null +++ b/src/main/java/org/ntlab/SproutServerMicro/battles/Team.java @@ -0,0 +1,264 @@ +package org.ntlab.SproutServerMicro.battles; + +import framework.model3D.Placeable; +import framework.model3D.Position3D; +import framework.physics.PhysicsUtility; +import framework.physics.Velocity3D; +import net.arnx.jsonic.JSONHint; +import org.ntlab.SproutServerMicro.rooms.Member; +import org.ntlab.SproutServerMicro.rooms.Room; + +import javax.vecmath.Vector3d; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * チーム + * + * @author matsumoto_k + */ +public class Team { + private HashMap playerMap = new HashMap<>(); // チームのプレイヤー情報 + private HashMap bullets = new HashMap<>(); // チームの弾の情報 + private HashMap magics = new HashMap<>(); // チームの魔法の情報 + private int bulletId = 0; // 弾を判別するID + private int magicId = 0; + private boolean result; // 勝敗 + + public Team(Room room) { + playerMap = new HashMap<>(); + for (Member member : room.getMemberList().values()) { + /** + * e.getKey : userId + */ + playerMap.put(member.getUserId(), new Player(member.getUserId(), member.getMemberId())); + } + } + + public HashMap getPlayerMap() { + return playerMap; + } + + public void setPlayerMap(HashMap playerMap) { + this.playerMap = playerMap; + } + + public boolean isResult() { + return result; + } + + public void setResult(boolean result) { + this.result = result; + } + + public HashMap getBullets() { + return bullets; + } + + public HashMap getMagics() { + return magics; + } + + /** + * userIdによってプレイヤーを取得 + * + * @param userId 取得するプレイヤーのuserId + * @return プレイヤー + */ + public Player findPlayerById(int userId) { + return playerMap.get(userId); + } + + /** + * チーム内の生存者の数を取得する + * + * @return 生存者の数 + */ + @JSONHint(ignore = true) + public int getAliveCount() { + int count = 0; + for (Player player : playerMap.values()) { + if (player.isAlive()) + count++; + } + return count; + } + + /** + * チーム内のプレイヤーが全員死亡しているか取得 + * + * @return 全員死亡している:true, 一人でも生きている:false + */ + @JSONHint(ignore = true) + public boolean isAllPlayerDead() { + if (getAliveCount() == 0) + return true; + return false; + } + + /** + * 自クラスの武器と他のチームのプレイヤーの衝突したオブジェクトを取得する + * + * @param enemyTeam 判定させるチーム + * @return colliedObjects 衝突したオブジェクト + */ + public ArrayList getColliedObjects(Team enemyTeam) { + ArrayList colliedObjects = new ArrayList<>(); + + /* 弾 */ + for (Iterator bulletIterator = bullets.values().iterator(); bulletIterator.hasNext(); ) { + Bullet bullet = bulletIterator.next(); + + if (!bullet.isAlive()) { + colliedObjects.add(bullet.getActor()); + bulletIterator.remove(); + continue; + } + + for (Player player : enemyTeam.getPlayerMap().values()) { + /* 自チームの弾と他のチームのプレイヤーが衝突した時 */ + if (checkCollision(bullet, player)) { + /* 他のチームのプレイヤーにダメージを与える */ + player.setDamage(bullet.getAttack()); + /* 弾は取り除く */ + colliedObjects.add(bullet.getActor()); + bulletIterator.remove(); + } + } + } + + /* 魔法 */ + for (Iterator magicIterator = magics.values().iterator(); magicIterator.hasNext(); ) { + Magic magic = magicIterator.next(); + + if (!magic.isAlive()) { + colliedObjects.add(magic.getActor()); + magicIterator.remove(); + continue; + } + + for (Player player : enemyTeam.getPlayerMap().values()) { + /* 自チームの弾と他のチームのプレイヤーが衝突した時 */ + if (checkCollision(magic, player)) { + /* 他のチームのプレイヤーにダメージを与える */ + player.setDamage(magic.getAttack()); + /* 弾は取り除く */ + colliedObjects.add(magic.getActor()); + magicIterator.remove(); + } + } + } + + return colliedObjects; + } + + /** + * 自クラスの武器と他のチームのプレイヤーの衝突したオブジェクトを取得する + * + * @param enemyPlayer 敵プレイヤー + * @return 衝突したオブジェクト + */ + public ArrayList getColliedObjects(Player enemyPlayer) { + ArrayList obj = new ArrayList<>(); + + /* 弾 */ + for (Iterator bulletIterator = bullets.values().iterator(); bulletIterator.hasNext(); ) { + Bullet bullet = bulletIterator.next(); + + if (!bullet.isAlive()) { + obj.add(bullet.getActor()); + bulletIterator.remove(); + continue; + } + + if (checkCollision(bullet, enemyPlayer)) { + /* 他のチームのプレイヤーにダメージを与える */ + enemyPlayer.setDamage(bullet.getAttack()); + /* 弾は取り除く */ + obj.add(bullet.getActor()); + bulletIterator.remove(); + } + } + + /* 魔法 */ + for (Iterator magicIterator = magics.values().iterator(); magicIterator.hasNext(); ) { + Magic magic = magicIterator.next(); + + if (!magic.isAlive()) { + obj.add(magic.getActor()); + magicIterator.remove(); + continue; + } + + if (checkCollision(magic, enemyPlayer)) { + /* 他のチームのプレイヤーにダメージを与える */ + enemyPlayer.setDamage(magic.getAttack()); + /* 弾は取り除く */ + obj.add(magic.getActor()); + magicIterator.remove(); + } + } + return obj; + } + + /** + * プレイヤーと武器の衝突判定 + * + * @param weapon + * @param player 他のチームのプレイヤー + * @return + */ + public boolean checkCollision(Weapon weapon, Player player) { + return PhysicsUtility.checkCollision(weapon.getBody(), null, player.getBody(), null) != null; + } + + /** + * チーム内のプレイヤーとの衝突判定 + * + * @param player 判定するプレイヤー + * @param playerId 判定するプレイヤーid + * @return 衝突している時はtrue, していない時はfalse + */ + public boolean checkCollision(Player player, int playerId) { + for (Map.Entry entry : playerMap.entrySet()) { + /* idがplayerと違う時 */ + if (entry.getKey() != playerId) { + if (player.checkCollision(entry.getValue())) + return true; + } + } + return false; + } + + /** + * プレイヤーの弾を作成する + * + * @param position3D 弾の位置 + * @param vector3d 弾の向き + * @param velocity3D 弾の速度 + * @return + */ + public Bullet createBullet(Position3D position3D, Vector3d vector3d, Velocity3D velocity3D) { + Bullet bullet = new Bullet(position3D, vector3d, velocity3D); + bullets.put(bulletId, bullet); + bulletId++; + return bullet; + } + + /** + * プレイヤーの魔法を作成する + * + * @param position3D 魔法の位置 + * @param vector3d 魔法の向き + * @param velocity3D 魔法の速度 + * @return + */ + public Magic createMagic(Position3D position3D, Vector3d vector3d, Velocity3D velocity3D) { + Magic magic = new Magic(position3D, vector3d, velocity3D); + magics.put(magicId, magic); + magicId++; + return magic; + } +} diff --git a/src/main/java/org/ntlab/SproutServerMicro/battles/Weapon.java b/src/main/java/org/ntlab/SproutServerMicro/battles/Weapon.java new file mode 100644 index 0000000..21045f7 --- /dev/null +++ b/src/main/java/org/ntlab/SproutServerMicro/battles/Weapon.java @@ -0,0 +1,137 @@ +package org.ntlab.SproutServerMicro.battles; + +import framework.animation.Animation3D; +import framework.gameMain.Actor; +import framework.model3D.CollisionResult; +import framework.model3D.Object3D; +import framework.model3D.Position3D; +import framework.physics.Force3D; +import framework.physics.Ground; +import framework.physics.Solid3D; +import framework.physics.Velocity3D; +import net.arnx.jsonic.JSONHint; + +import javax.vecmath.Vector3d; + +/** + * 飛ぶ武器 + * + * @author matsumoto_k + */ +abstract class Weapon { + + protected boolean alive = true; // 武器の生存フラグ + private long left = 0; // 武器の寿命 + private int attack = 0; // 武器の攻撃力 + protected Actor actor; // 武器のオブジェクト + + public Weapon() { + left = getInitWeaponLife(); + attack = getAttack(); + this.actor = new WeaponActor(new Solid3D(createObject()), null) { + public void onIntersect(CollisionResult normal, long interval) { + if (normal != null) + alive = false; + } + }; + } + + abstract protected class WeaponActor extends Actor { + protected WeaponActor(Solid3D o, Animation3D animation3D) { + super(o, animation3D); + } + + @Override + public void onEndFall() { + + } + + @Override + abstract public void onIntersect(CollisionResult normal, long interval); + + @Override + public void motion(long interval, Ground ground) { + super.motion(interval, ground); + left -= interval; + if (left < 0L) { + alive = false; + } + } + + @Override + public Force3D getGravity() { + return Force3D.ZERO; + } + + @Override + public void onEndAnimation() { + + } + } + + /** + * 武器のオブジェクトを作成する + * + * @return 武器のオブジェクト + */ + abstract Object3D createObject(); + + /** + * 武器の初期値を設定 + * + * @param weaponPosition 武器の位置 + * @param weaponVector 武器の方向 + * @param weaponVelocity 武器の速度 + */ + public void initWeapon(Position3D weaponPosition, Vector3d weaponVector, Velocity3D weaponVelocity) { + actor.setPosition(weaponPosition); // 弾の位置を設定 + actor.setDirection(weaponVector); // 弾の方向を設定 + actor.setVelocity(weaponVelocity); // 弾の速度を設定 + } + + /** + * 武器のActorを取得 + * + * @return 武器のActor + */ + @JSONHint(ignore = true) + public Actor getActor() { + return actor; + } + + /** + * 武器のオブジェクトを取得 + * + * @return 武器のオブジェクト + */ + @JSONHint(ignore = true) + public Object3D getBody() { + return actor.body; + } + + /** + * 武器の生存確認 + * + * @return 武器が壁や地面と接触した、武器の寿命が切れたなどの場合はfalseを返す + */ + @JSONHint(ignore = true) + public boolean isAlive() { + return alive; + } + + /** + * 武器の初期寿命を取得 + * + * @return 武器の初期寿命(ミリ秒) + */ + @JSONHint(ignore = true) + abstract long getInitWeaponLife(); + + /** + * 武器の攻撃力を取得 + * + * @return 武器の攻撃力 + */ + @JSONHint(ignore = true) + abstract public int getAttack(); +} diff --git a/src/main/java/org/ntlab/SproutServerMicro/rooms/Member.java b/src/main/java/org/ntlab/SproutServerMicro/rooms/Member.java new file mode 100644 index 0000000..900a61d --- /dev/null +++ b/src/main/java/org/ntlab/SproutServerMicro/rooms/Member.java @@ -0,0 +1,90 @@ +package org.ntlab.SproutServerMicro.rooms; + +import org.ntlab.SproutServerMicro.accounts.Accounts; + +/** + * Root resource (exposed at "Rooms" path) + */ + +public class Member { + + /** + * アカウントリストからユーザ情報の検索 + */ + public Member(int userId) { + Accounts ac = Accounts.getInstance(); + for(int i=0; i memberList = new HashMap(); + public boolean readyToFight = false; //全員準備完了したか判定 + private int memberId=0; + public boolean startFrag; + public boolean battleState = false; + public int battleId = -1; + + + public Room(String roomName,int roomId,String roomKey,Member member){ + this.roomId = roomId; + this.roomName = roomName; + this.roomKey = roomKey; + this.memberList.put(this.memberId,member); + memberList.get(this.memberId).setMemberId(this.memberId); + this.memberList.get(memberId).setHostState(true); + this.hostName = member.getUserName(); + this.memberId++; + + if(roomKey != null){ + this.keyCheck = true; + } + + } + + public Room(int roomId){ + this.roomId = roomId; + } + + public Room() { + // TODO Auto-generated constructor stub + } + + + /** + * 入室処理 + */ + public void enterRoom(int memberId,Member member){ + getMemberList().put(memberId, member); + this.memberList.get(this.memberId).setMemberId(this.memberId); + this.memberId++; + } + + /** + * パスワードのチェック + */ + public boolean keyCheck(String key,int memberId){ + if(this.keyCheck == false){ + return true; + } + + boolean counts = false; + if(key.equals(this.getRoomKey())){ + counts = true; + } + System.out.println("key chek = " + counts); + return counts; + } + + + /** + * バトル終了時のルームの状態の初期化 + */ + public void roomInitialize(){ + this.battleState = false; + this.readyToFight = false; + this.startFrag = false; + this.battleId = -1; + for(int value : this.memberList.keySet()){ + if(this.memberList.get(value) != null){ + this.memberList.get(value).setReady(false); + } + } + } + + + /** + * ホストの次に入った人のメンバーIDを返す + */ + public int minimumMemberCount(int memberId){ + int count = 0; + for(int i = 0;i getMemberList() { + return memberList; + } + + public void setMemberList(HashMap memberList) { + this.memberList = memberList; + } + + + //ルームID + @JSONHint(ignore=true) + public int getRoomId() { + return roomId; + } + + public void setId(int id) { + this.roomId = id; + } + + + //ルーム名 + @JSONHint(ignore=true) + public String getRoomName() { + return roomName; + } + + public void setRoomName(String roomName) { + this.roomName = roomName; + } + + + //ホストネーム + @JSONHint(ignore=true) + public String getHostName() { + return hostName; + } + + public void setHostName(String hostName) { + this.hostName = hostName; + } + + + //キーのチェック + @JSONHint(ignore=true) + public boolean isKeyCheck() { + return keyCheck; + } + + public void setKeyCheck(boolean keyCheck) { + this.keyCheck = keyCheck; + } + + + //準備完了判定 + @JSONHint(ignore=true) + public boolean isReadyToFight() { + return readyToFight; + } + + public void setReadyToFight(boolean allReady) { + this.readyToFight = allReady; + } + + + //ルームキー(ルームパスワード) + @JSONHint(ignore=true) + public String getRoomKey() { + return roomKey; + } + + public void setRoomKey(String roomKey) { + this.roomKey = roomKey; + } + + //メンバーID(入った順番) + @JSONHint(ignore=true) + public int getMemberId() { + return memberId; + } + + public void setMemberId(int memberId) { + this.memberId = memberId; + } + + //全員準備 + public boolean isStartFrag() { + return startFrag; + } + + public void setStartFrag(boolean startFrag) { + this.startFrag = startFrag; + } + + //バトル中か否か + public boolean isBattleState() { + return battleState; + } + + public void setBattleState(boolean battleState) { + this.battleState = battleState; + } + + + //バトルID + public int getBattleId() { + return battleId; + } + + public void setBattleId(int battleId) { + this.battleId = battleId; + } + + + + + + + + + + + + + + + +} diff --git a/src/main/java/org/ntlab/SproutServerMicro/rooms/RoomResponse.java b/src/main/java/org/ntlab/SproutServerMicro/rooms/RoomResponse.java new file mode 100644 index 0000000..6038e32 --- /dev/null +++ b/src/main/java/org/ntlab/SproutServerMicro/rooms/RoomResponse.java @@ -0,0 +1,59 @@ +package org.ntlab.SproutServerMicro.rooms; + +public class RoomResponse { + + public Room room; + public int memberId; + public boolean check; + public int battleId; + + public RoomResponse(Room room,int userId,int memberId,boolean check){ + this.room = room; + this.check = check; + this.memberId = memberId; + } + + public RoomResponse(Room room,int userId){ + this.room = room; + this.battleId = room.getBattleId(); + for(int i = 0;i roomList = new HashMap(); + public int roomId = 0; // ルームID + private Room waitingRoom = null; //待ち部屋 + private Room waitingRoomSecond = null; //待ち部屋2 + private RoomsConnection roomsConnection = null; + + + private Rooms(){ + if (theInstance == null) { + theInstance = this; + } + } + + public static Rooms getInstance() { + if (theInstance == null) { + theInstance = new Rooms(); + } + return theInstance; + } + + + + /** + * 部屋のメンバーの準備チェック + */ + public int readyCheck(int roomId,boolean frag){ + int checkCount = 0; + int battleCount = 0; + Room room = roomList.get(roomId); + + if(frag == true){ + for(int i = 0;i getRoomList() { + return roomList; + } + + +// public void setRoomList(HashMap roomList) { +// Rooms.roomList = roomList; +// } + + + //待ち部屋1 + //@JSONHint(ignore=true) + public Room getWaitingRoom() { + return waitingRoom; + } + + public void setWaitingRoom(Room waitingRoom) { + this.waitingRoom = waitingRoom; + } + + //待ち部屋2 + //@JSONHint(ignore=true) + public Room getWaitingRoomSecond() { + return waitingRoomSecond; + } + + public void setWaitingRoomSecond(Room waitingRoomSecond) { + this.waitingRoomSecond = waitingRoomSecond; + } + + //人数 + @JSONHint(ignore=true) + public int getPlayerNumber() { + return playerNumber; + } + + + //ルームID + public int getRoomId() { + return roomId; + } + + public void setRoomId(int roomId) { + this.roomId = roomId; + } + + @JSONHint(ignore = true) + public RoomsConnection getRoomsConnection() { + return roomsConnection; + } + +} diff --git a/src/main/java/org/ntlab/SproutServerMicro/rooms/RoomsConnection.java b/src/main/java/org/ntlab/SproutServerMicro/rooms/RoomsConnection.java new file mode 100644 index 0000000..a0674f2 --- /dev/null +++ b/src/main/java/org/ntlab/SproutServerMicro/rooms/RoomsConnection.java @@ -0,0 +1,10 @@ +package org.ntlab.SproutServerMicro.rooms; + +import framework.network.HttpAsyncConnection; + +public class RoomsConnection extends HttpAsyncConnection{ + + public RoomsConnection(){ + super("http://nitta-lab-www2.is.konan-u.ac.jp:8080/SproutServerMicro/rooms"); + } +} diff --git a/src/main/java/org/ntlab/SproutServerMicro/rooms/RoomsRest.java b/src/main/java/org/ntlab/SproutServerMicro/rooms/RoomsRest.java new file mode 100644 index 0000000..3111687 --- /dev/null +++ b/src/main/java/org/ntlab/SproutServerMicro/rooms/RoomsRest.java @@ -0,0 +1,221 @@ +package org.ntlab.SproutServerMicro.rooms; + +import org.ntlab.SproutServerMicro.battles.Battles; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import java.util.HashMap; + +@Path("rooms") +public class RoomsRest { + + Rooms rooms; + + public RoomsRest() { + rooms = Rooms.getInstance(); + } + + /** + * 部屋一覧取得(Rooms) + */ + @GET + @Produces(MediaType.APPLICATION_JSON) + public Rooms roomsView() { + return rooms.getInstance(); + } + + + /** + * 部屋の状態(Room) + */ + @GET + @Path("/{roomId}") + @Produces(MediaType.APPLICATION_JSON) + public Room roomState(@PathParam("roomId") int roomId){ + return rooms.getRoomList().get(roomId); + } + + + /** + * 他アカウント情報取得(member) + */ + @GET + @Path("/{roomId}/{memberId}") + @Produces(MediaType.APPLICATION_JSON) + public HashMap getOtherAccount(@PathParam("roomId") int roomId, @QueryParam("userId") int userId) { + return rooms.getRoomList().get(roomId).getMemberList(); + } + + + /** + * 部屋作成(Rooms) + */ + @POST + @Produces(MediaType.APPLICATION_JSON) + public RoomResponse makeRoom(@FormParam("userId") int userId, @FormParam("roomName") String roomName, @FormParam("key") String key) { + int roomId = rooms.getRoomId(); + Member member = new Member(userId); + + Room room = new Room(roomName,rooms.getRoomId(),key,member); + rooms.getRoomList().put(rooms.getRoomId(),room); + + RoomResponse roomRes = new RoomResponse(room, userId); + + roomId++; + rooms.setRoomId(roomId); + + return roomRes; + } + + + /** + * 入室(Room) + */ + @PUT + @Path("/{roomId}") + @Produces(MediaType.APPLICATION_JSON) + public RoomResponse enterRoom(@PathParam("roomId") int roomId,@FormParam("userId") int userId,@FormParam("key") String key){ + Room room = rooms.getRoomList().get(roomId); + RoomResponse roomRes; + int memberId = room.getMemberId(); + boolean check = room.keyCheck(key, memberId); + boolean keyCheck = true; + + if(check == true && room.getMemberList().size()org.glassfish.jersey.servlet.ServletContainer jersey.config.server.provider.packages - org.ntlab.SproutServer + org.ntlab.SproutServerMicro 1