summaryrefslogtreecommitdiffstats
path: root/core/java/android
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/annotation/TransitionRes.java37
-rw-r--r--core/java/android/app/ActivityManagerNative.java24
-rw-r--r--core/java/android/app/ApplicationPackageManager.java5
-rw-r--r--core/java/android/app/IActivityManager.java4
-rw-r--r--core/java/android/app/ResourcesManager.java17
-rw-r--r--core/java/android/app/SystemServiceRegistry.java8
-rw-r--r--core/java/android/app/VoiceInteractor.aidl19
-rw-r--r--core/java/android/app/VoiceInteractor.java282
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java16
-rw-r--r--core/java/android/content/Context.java12
-rw-r--r--core/java/android/content/Intent.java25
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl4
-rw-r--r--core/java/android/hardware/camera2/CameraManager.java6
-rw-r--r--core/java/android/hardware/camera2/DngCreator.java2
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java6
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java2
-rw-r--r--core/java/android/hardware/camera2/legacy/RequestThreadManager.java4
-rw-r--r--core/java/android/hardware/location/GeofenceHardwareImpl.java2
-rw-r--r--core/java/android/hardware/radio/RadioManager.java1308
-rw-r--r--core/java/android/hardware/radio/RadioMetadata.java449
-rw-r--r--core/java/android/hardware/radio/RadioModule.java218
-rw-r--r--core/java/android/hardware/radio/RadioTuner.java302
-rw-r--r--core/java/android/net/NetworkUtils.java44
-rw-r--r--core/java/android/os/INetworkManagementService.aidl12
-rw-r--r--core/java/android/os/Parcel.java34
-rw-r--r--core/java/android/os/PowerManager.java6
-rw-r--r--core/java/android/preference/PreferenceFragment.java3
-rw-r--r--core/java/android/print/PrintDocumentInfo.java2
-rw-r--r--core/java/android/provider/CallLog.java8
-rw-r--r--core/java/android/provider/Settings.java31
-rw-r--r--core/java/android/provider/VoicemailContract.java161
-rw-r--r--core/java/android/service/voice/IVoiceInteractionSession.aidl2
-rw-r--r--core/java/android/service/voice/VoiceInteractionService.java8
-rw-r--r--core/java/android/service/voice/VoiceInteractionSession.java111
-rw-r--r--core/java/android/speech/tts/TextToSpeech.java2
-rw-r--r--core/java/android/text/util/Linkify.java4
-rw-r--r--core/java/android/transition/TransitionInflater.java8
-rw-r--r--core/java/android/util/PathParser.java2
-rw-r--r--core/java/android/view/ActionMode.java39
-rw-r--r--core/java/android/view/ContextThemeWrapper.java3
-rw-r--r--core/java/android/view/IWindowManager.aidl9
-rw-r--r--core/java/android/view/PhoneWindow.java34
-rw-r--r--core/java/android/view/View.java3
-rw-r--r--core/java/android/view/Window.java3
-rw-r--r--core/java/android/view/WindowManager.java3
-rw-r--r--core/java/android/view/accessibility/AccessibilityWindowInfo.java2
-rw-r--r--core/java/android/view/animation/Animation.java3
-rw-r--r--core/java/android/view/animation/LayoutAnimationController.java6
-rw-r--r--core/java/android/webkit/WebView.java68
-rw-r--r--core/java/android/webkit/WebViewClient.java26
-rw-r--r--core/java/android/webkit/WebViewProvider.java4
-rw-r--r--core/java/android/widget/ActionMenuView.java3
-rw-r--r--core/java/android/widget/ArrayAdapter.java11
-rw-r--r--core/java/android/widget/FastScroller.java3
-rw-r--r--core/java/android/widget/SimpleAdapter.java4
-rw-r--r--core/java/android/widget/Toolbar.java24
-rw-r--r--core/java/android/widget/ViewAnimator.java5
57 files changed, 3295 insertions, 148 deletions
diff --git a/core/java/android/annotation/TransitionRes.java b/core/java/android/annotation/TransitionRes.java
new file mode 100644
index 0000000..06bac74
--- /dev/null
+++ b/core/java/android/annotation/TransitionRes.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Denotes that an integer parameter, field or method return value is expected
+ * to be a transition resource reference.
+ *
+ * {@hide}
+ */
+@Documented
+@Retention(SOURCE)
+@Target({METHOD, PARAMETER, FIELD})
+public @interface TransitionRes {
+}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 997f69d..1484af8 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2440,6 +2440,16 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
reply.writeNoException();
return true;
}
+
+ case SET_VOICE_KEEP_AWAKE_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IVoiceInteractionSession session = IVoiceInteractionSession.Stub.asInterface(
+ data.readStrongBinder());
+ boolean keepAwake = data.readInt() != 0;
+ setVoiceKeepAwake(session, keepAwake);
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -5658,5 +5668,19 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
}
+ @Override
+ public void setVoiceKeepAwake(IVoiceInteractionSession session, boolean keepAwake)
+ throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(session.asBinder());
+ data.writeInt(keepAwake ? 1 : 0);
+ mRemote.transact(SET_VOICE_KEEP_AWAKE_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index f35e746..9f81670 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1662,7 +1662,7 @@ final class ApplicationPackageManager extends PackageManager {
int flags) {
try {
mPM.addCrossProfileIntentFilter(filter, mContext.getOpPackageName(),
- mContext.getUserId(), sourceUserId, targetUserId, flags);
+ sourceUserId, targetUserId, flags);
} catch (RemoteException e) {
// Should never happen!
}
@@ -1674,8 +1674,7 @@ final class ApplicationPackageManager extends PackageManager {
@Override
public void clearCrossProfileIntentFilters(int sourceUserId) {
try {
- mPM.clearCrossProfileIntentFilters(sourceUserId, mContext.getOpPackageName(),
- mContext.getUserId());
+ mPM.clearCrossProfileIntentFilters(sourceUserId, mContext.getOpPackageName());
} catch (RemoteException e) {
// Should never happen!
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 3dcbdd2..d794aa3 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -485,6 +485,9 @@ public interface IActivityManager extends IInterface {
public void setDumpHeapDebugLimit(String processName, long maxMemSize) throws RemoteException;
public void dumpHeapFinished(String path) throws RemoteException;
+ public void setVoiceKeepAwake(IVoiceInteractionSession session, boolean keepAwake)
+ throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -818,4 +821,5 @@ public interface IActivityManager extends IInterface {
int GET_LOCK_TASK_MODE_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+286;
int SET_DUMP_HEAP_DEBUG_LIMIT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+287;
int DUMP_HEAP_FINISHED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+288;
+ int SET_VOICE_KEEP_AWAKE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+289;
}
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 8abe223..79797c9 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -27,6 +27,7 @@ import android.content.res.ResourcesKey;
import android.hardware.display.DisplayManagerGlobal;
import android.util.ArrayMap;
import android.util.DisplayMetrics;
+import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.view.Display;
@@ -164,7 +165,7 @@ public class ResourcesManager {
WeakReference<Resources> wr = mActiveResources.get(key);
r = wr != null ? wr.get() : null;
- //if (r != null) Slog.i(TAG, "isUpToDate " + resDir + ": " + r.getAssets().isUpToDate());
+ //if (r != null) Log.i(TAG, "isUpToDate " + resDir + ": " + r.getAssets().isUpToDate());
if (r != null && r.getAssets().isUpToDate()) {
if (DEBUG) Slog.w(TAG, "Returning cached resources " + r + " " + resDir
+ ": appScale=" + r.getCompatibilityInfo().applicationScale
@@ -174,7 +175,7 @@ public class ResourcesManager {
}
//if (r != null) {
- // Slog.w(TAG, "Throwing away out-of-date resources!!!! "
+ // Log.w(TAG, "Throwing away out-of-date resources!!!! "
// + r + " " + resDir);
//}
@@ -204,14 +205,18 @@ public class ResourcesManager {
if (libDirs != null) {
for (String libDir : libDirs) {
- if (assets.addAssetPath(libDir) == 0) {
- Slog.w(TAG, "Asset path '" + libDir +
- "' does not exist or contains no resources.");
+ if (libDir.endsWith(".apk")) {
+ // Avoid opening files we know do not have resources,
+ // like code-only .jar files.
+ if (assets.addAssetPath(libDir) == 0) {
+ Log.w(TAG, "Asset path '" + libDir +
+ "' does not exist or contains no resources.");
+ }
}
}
}
- //Slog.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics);
+ //Log.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics);
DisplayMetrics dm = getDisplayMetricsLocked(displayId);
Configuration config;
final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 993f416..fd7bae7 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -49,6 +49,7 @@ import android.hardware.hdmi.IHdmiControlService;
import android.hardware.input.InputManager;
import android.hardware.usb.IUsbManager;
import android.hardware.usb.UsbManager;
+import android.hardware.radio.RadioManager;
import android.location.CountryDetector;
import android.location.ICountryDetector;
import android.location.ILocationManager;
@@ -683,6 +684,13 @@ final class SystemServiceRegistry {
IBinder b = ServiceManager.getService(Context.MIDI_SERVICE);
return new MidiManager(ctx, IMidiManager.Stub.asInterface(b));
}});
+
+ registerService(Context.RADIO_SERVICE, RadioManager.class,
+ new CachedServiceFetcher<RadioManager>() {
+ @Override
+ public RadioManager createService(ContextImpl ctx) {
+ return new RadioManager(ctx);
+ }});
}
/**
diff --git a/core/java/android/app/VoiceInteractor.aidl b/core/java/android/app/VoiceInteractor.aidl
new file mode 100644
index 0000000..40a4a0e
--- /dev/null
+++ b/core/java/android/app/VoiceInteractor.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.app;
+
+parcelable VoiceInteractor.PickOptionRequest.Option;
diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java
index 7b84cb4..da7bb05 100644
--- a/core/java/android/app/VoiceInteractor.java
+++ b/core/java/android/app/VoiceInteractor.java
@@ -21,6 +21,8 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.Log;
@@ -69,6 +71,7 @@ public class VoiceInteractor {
public void executeMessage(Message msg) {
SomeArgs args = (SomeArgs)msg.obj;
Request request;
+ boolean complete;
switch (msg.what) {
case MSG_CONFIRMATION_RESULT:
request = pullRequest((IVoiceInteractorRequest)args.arg1, true);
@@ -81,13 +84,28 @@ public class VoiceInteractor {
request.clear();
}
break;
+ case MSG_PICK_OPTION_RESULT:
+ complete = msg.arg1 != 0;
+ request = pullRequest((IVoiceInteractorRequest)args.arg1, complete);
+ if (DEBUG) Log.d(TAG, "onPickOptionResult: req="
+ + ((IVoiceInteractorRequest)args.arg1).asBinder() + "/" + request
+ + " finished=" + complete + " selection=" + args.arg2
+ + " result=" + args.arg3);
+ if (request != null) {
+ ((PickOptionRequest)request).onPickOptionResult(complete,
+ (PickOptionRequest.Option[]) args.arg2, (Bundle) args.arg3);
+ if (complete) {
+ request.clear();
+ }
+ }
+ break;
case MSG_COMPLETE_VOICE_RESULT:
request = pullRequest((IVoiceInteractorRequest)args.arg1, true);
if (DEBUG) Log.d(TAG, "onCompleteVoice: req="
+ ((IVoiceInteractorRequest)args.arg1).asBinder() + "/" + request
+ " result=" + args.arg1);
if (request != null) {
- ((CompleteVoiceRequest)request).onCompleteResult((Bundle) args.arg2);
+ ((CompleteVoiceRequest)request).onCompleteResult((Bundle) args.arg1);
request.clear();
}
break;
@@ -95,21 +113,22 @@ public class VoiceInteractor {
request = pullRequest((IVoiceInteractorRequest)args.arg1, true);
if (DEBUG) Log.d(TAG, "onAbortVoice: req="
+ ((IVoiceInteractorRequest)args.arg1).asBinder() + "/" + request
- + " result=" + args.arg1);
+ + " result=" + args.arg2);
if (request != null) {
((AbortVoiceRequest)request).onAbortResult((Bundle) args.arg2);
request.clear();
}
break;
case MSG_COMMAND_RESULT:
- request = pullRequest((IVoiceInteractorRequest)args.arg1, msg.arg1 != 0);
+ complete = msg.arg1 != 0;
+ request = pullRequest((IVoiceInteractorRequest)args.arg1, complete);
if (DEBUG) Log.d(TAG, "onCommandResult: req="
+ ((IVoiceInteractorRequest)args.arg1).asBinder() + "/" + request
+ " completed=" + msg.arg1 + " result=" + args.arg2);
if (request != null) {
((CommandRequest)request).onCommandResult(msg.arg1 != 0,
(Bundle) args.arg2);
- if (msg.arg1 != 0) {
+ if (complete) {
request.clear();
}
}
@@ -129,10 +148,17 @@ public class VoiceInteractor {
final IVoiceInteractorCallback.Stub mCallback = new IVoiceInteractorCallback.Stub() {
@Override
- public void deliverConfirmationResult(IVoiceInteractorRequest request, boolean confirmed,
+ public void deliverConfirmationResult(IVoiceInteractorRequest request, boolean finished,
Bundle result) {
mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIOO(
- MSG_CONFIRMATION_RESULT, confirmed ? 1 : 0, request, result));
+ MSG_CONFIRMATION_RESULT, finished ? 1 : 0, request, result));
+ }
+
+ @Override
+ public void deliverPickOptionResult(IVoiceInteractorRequest request,
+ boolean finished, PickOptionRequest.Option[] options, Bundle result) {
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIOOO(
+ MSG_PICK_OPTION_RESULT, finished ? 1 : 0, request, options, result));
}
@Override
@@ -164,17 +190,22 @@ public class VoiceInteractor {
final ArrayMap<IBinder, Request> mActiveRequests = new ArrayMap<IBinder, Request>();
static final int MSG_CONFIRMATION_RESULT = 1;
- static final int MSG_COMPLETE_VOICE_RESULT = 2;
- static final int MSG_ABORT_VOICE_RESULT = 3;
- static final int MSG_COMMAND_RESULT = 4;
- static final int MSG_CANCEL_RESULT = 5;
+ static final int MSG_PICK_OPTION_RESULT = 2;
+ static final int MSG_COMPLETE_VOICE_RESULT = 3;
+ static final int MSG_ABORT_VOICE_RESULT = 4;
+ static final int MSG_COMMAND_RESULT = 5;
+ static final int MSG_CANCEL_RESULT = 6;
+ /**
+ * Base class for voice interaction requests that can be submitted to the interactor.
+ * Do not instantiate this directly -- instead, use the appropriate subclass.
+ */
public static abstract class Request {
IVoiceInteractorRequest mRequestInterface;
Context mContext;
Activity mActivity;
- public Request() {
+ Request() {
}
public void cancel() {
@@ -212,22 +243,25 @@ public class VoiceInteractor {
String packageName, IVoiceInteractorCallback callback) throws RemoteException;
}
+ /**
+ * Confirms an operation with the user via the trusted system
+ * VoiceInteractionService. This allows an Activity to complete an unsafe operation that
+ * would require the user to touch the screen when voice interaction mode is not enabled.
+ * The result of the confirmation will be returned through an asynchronous call to
+ * either {@link #onConfirmationResult(boolean, android.os.Bundle)} or
+ * {@link #onCancel()}.
+ *
+ * <p>In some cases this may be a simple yes / no confirmation or the confirmation could
+ * include context information about how the action will be completed
+ * (e.g. booking a cab might include details about how long until the cab arrives)
+ * so the user can give a confirmation.
+ */
public static class ConfirmationRequest extends Request {
final CharSequence mPrompt;
final Bundle mExtras;
/**
- * Confirms an operation with the user via the trusted system
- * VoiceInteractionService. This allows an Activity to complete an unsafe operation that
- * would require the user to touch the screen when voice interaction mode is not enabled.
- * The result of the confirmation will be returned through an asynchronous call to
- * either {@link #onConfirmationResult(boolean, android.os.Bundle)} or
- * {@link #onCancel()}.
- *
- * <p>In some cases this may be a simple yes / no confirmation or the confirmation could
- * include context information about how the action will be completed
- * (e.g. booking a cab might include details about how long until the cab arrives)
- * so the user can give a confirmation.
+ * Create a new confirmation request.
* @param prompt Optional confirmation text to read to the user as the action being
* confirmed.
* @param extras Additional optional information.
@@ -246,19 +280,155 @@ public class VoiceInteractor {
}
}
+ /**
+ * Select a single option from multiple potential options with the user via the trusted system
+ * VoiceInteractionService. Typically, the application would present this visually as
+ * a list view to allow selecting the option by touch.
+ * The result of the confirmation will be returned through an asynchronous call to
+ * either {@link #onPickOptionResult} or {@link #onCancel()}.
+ */
+ public static class PickOptionRequest extends Request {
+ final CharSequence mPrompt;
+ final Option[] mOptions;
+ final Bundle mExtras;
+
+ /**
+ * Represents a single option that the user may select using their voice.
+ */
+ public static final class Option implements Parcelable {
+ final CharSequence mLabel;
+ ArrayList<CharSequence> mSynonyms;
+ Bundle mExtras;
+
+ /**
+ * Creates an option that a user can select with their voice by matching the label
+ * or one of several synonyms.
+ * @param label The label that will both be matched against what the user speaks
+ * and displayed visually.
+ */
+ public Option(CharSequence label) {
+ mLabel = label;
+ }
+
+ /**
+ * Add a synonym term to the option to indicate an alternative way the content
+ * may be matched.
+ * @param synonym The synonym that will be matched against what the user speaks,
+ * but not displayed.
+ */
+ public Option addSynonym(CharSequence synonym) {
+ if (mSynonyms == null) {
+ mSynonyms = new ArrayList<>();
+ }
+ mSynonyms.add(synonym);
+ return this;
+ }
+
+ public CharSequence getLabel() {
+ return mLabel;
+ }
+
+ public int countSynonyms() {
+ return mSynonyms != null ? mSynonyms.size() : 0;
+ }
+
+ public CharSequence getSynonymAt(int index) {
+ return mSynonyms != null ? mSynonyms.get(index) : null;
+ }
+
+ /**
+ * Set optional extra information associated with this option. Note that this
+ * method takes ownership of the supplied extras Bundle.
+ */
+ public void setExtras(Bundle extras) {
+ mExtras = extras;
+ }
+
+ /**
+ * Return any optional extras information associated with this option, or null
+ * if there is none. Note that this method returns a reference to the actual
+ * extras Bundle in the option, so modifications to it will directly modify the
+ * extras in the option.
+ */
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
+ Option(Parcel in) {
+ mLabel = in.readCharSequence();
+ mSynonyms = in.readCharSequenceList();
+ mExtras = in.readBundle();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeCharSequence(mLabel);
+ dest.writeCharSequenceList(mSynonyms);
+ dest.writeBundle(mExtras);
+ }
+
+ public static final Parcelable.Creator<Option> CREATOR
+ = new Parcelable.Creator<Option>() {
+ public Option createFromParcel(Parcel in) {
+ return new Option(in);
+ }
+
+ public Option[] newArray(int size) {
+ return new Option[size];
+ }
+ };
+ };
+
+ /**
+ * Create a new pick option request.
+ * @param prompt Optional question to be spoken to the user via text to speech.
+ * @param options The set of {@link Option}s the user is selecting from.
+ * @param extras Additional optional information.
+ */
+ public PickOptionRequest(CharSequence prompt, Option[] options, Bundle extras) {
+ mPrompt = prompt;
+ mOptions = options;
+ mExtras = extras;
+ }
+
+ /**
+ * Called when a single option is confirmed or narrowed to one of several options.
+ * @param finished True if the voice interaction has finished making a selection, in
+ * which case {@code selections} contains the final result. If false, this request is
+ * still active and you will continue to get calls on it.
+ * @param selections Either a single {@link Option} or one of several {@link Option}s the
+ * user has narrowed the choices down to.
+ * @param result Additional optional information.
+ */
+ public void onPickOptionResult(boolean finished, Option[] selections, Bundle result) {
+ }
+
+ IVoiceInteractorRequest submit(IVoiceInteractor interactor, String packageName,
+ IVoiceInteractorCallback callback) throws RemoteException {
+ return interactor.startPickOption(packageName, callback, mPrompt, mOptions, mExtras);
+ }
+ }
+
+ /**
+ * Reports that the current interaction was successfully completed with voice, so the
+ * application can report the final status to the user. When the response comes back, the
+ * voice system has handled the request and is ready to switch; at that point the
+ * application can start a new non-voice activity or finish. Be sure when starting the new
+ * activity to use {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK
+ * Intent.FLAG_ACTIVITY_NEW_TASK} to keep the new activity out of the current voice
+ * interaction task.
+ */
public static class CompleteVoiceRequest extends Request {
final CharSequence mMessage;
final Bundle mExtras;
/**
- * Reports that the current interaction was successfully completed with voice, so the
- * application can report the final status to the user. When the response comes back, the
- * voice system has handled the request and is ready to switch; at that point the
- * application can start a new non-voice activity or finish. Be sure when starting the new
- * activity to use {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK
- * Intent.FLAG_ACTIVITY_NEW_TASK} to keep the new activity out of the current voice
- * interaction task.
- *
+ * Create a new completed voice interaction request.
* @param message Optional message to tell user about the completion status of the task.
* @param extras Additional optional information.
*/
@@ -276,21 +446,23 @@ public class VoiceInteractor {
}
}
+ /**
+ * Reports that the current interaction can not be complete with voice, so the
+ * application will need to switch to a traditional input UI. Applications should
+ * only use this when they need to completely bail out of the voice interaction
+ * and switch to a traditional UI. When the response comes back, the voice
+ * system has handled the request and is ready to switch; at that point the application
+ * can start a new non-voice activity. Be sure when starting the new activity
+ * to use {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK
+ * Intent.FLAG_ACTIVITY_NEW_TASK} to keep the new activity out of the current voice
+ * interaction task.
+ */
public static class AbortVoiceRequest extends Request {
final CharSequence mMessage;
final Bundle mExtras;
/**
- * Reports that the current interaction can not be complete with voice, so the
- * application will need to switch to a traditional input UI. Applications should
- * only use this when they need to completely bail out of the voice interaction
- * and switch to a traditional UI. When the response comes back, the voice
- * system has handled the request and is ready to switch; at that point the application
- * can start a new non-voice activity. Be sure when starting the new activity
- * to use {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK
- * Intent.FLAG_ACTIVITY_NEW_TASK} to keep the new activity out of the current voice
- * interaction task.
- *
+ * Create a new voice abort request.
* @param message Optional message to tell user about not being able to complete
* the interaction with voice.
* @param extras Additional optional information.
@@ -309,25 +481,27 @@ public class VoiceInteractor {
}
}
+ /**
+ * Execute an extended command using the trusted system VoiceInteractionService.
+ * This allows an Activity to request additional information from the user needed to
+ * complete an action (e.g. booking a table might have several possible times that the
+ * user could select from or an app might need the user to agree to a terms of service).
+ * The result of the confirmation will be returned through an asynchronous call to
+ * either {@link #onCommandResult(boolean, android.os.Bundle)} or
+ * {@link #onCancel()}.
+ *
+ * <p>The command is a string that describes the generic operation to be performed.
+ * The command will determine how the properties in extras are interpreted and the set of
+ * available commands is expected to grow over time. An example might be
+ * "com.google.voice.commands.REQUEST_NUMBER_BAGS" to request the number of bags as part of
+ * airline check-in. (This is not an actual working example.)
+ */
public static class CommandRequest extends Request {
final String mCommand;
final Bundle mArgs;
/**
- * Execute a command using the trusted system VoiceInteractionService.
- * This allows an Activity to request additional information from the user needed to
- * complete an action (e.g. booking a table might have several possible times that the
- * user could select from or an app might need the user to agree to a terms of service).
- * The result of the confirmation will be returned through an asynchronous call to
- * either {@link #onCommandResult(boolean, android.os.Bundle)} or
- * {@link #onCancel()}.
- *
- * <p>The command is a string that describes the generic operation to be performed.
- * The command will determine how the properties in extras are interpreted and the set of
- * available commands is expected to grow over time. An example might be
- * "com.google.voice.commands.REQUEST_NUMBER_BAGS" to request the number of bags as part of
- * airline check-in. (This is not an actual working example.)
- *
+ * Create a new generic command request.
* @param command The desired command to perform.
* @param args Additional arguments to control execution of the command.
*/
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 245db06..a659acb 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1766,7 +1766,7 @@ public class DevicePolicyManager {
public static final int ENCRYPTION_STATUS_INACTIVE = 1;
/**
- * Result code for {@link #setStorageEncryption} and {@link #getStorageEncryptionStatus}:
+ * Result code for {@link #getStorageEncryptionStatus}:
* indicating that encryption is not currently active, but is currently
* being activated. This is only reported by devices that support
* encryption of data and only when the storage is currently
@@ -1782,6 +1782,13 @@ public class DevicePolicyManager {
public static final int ENCRYPTION_STATUS_ACTIVE = 3;
/**
+ * Result code for {@link #getStorageEncryptionStatus}:
+ * indicating that encryption is active, but an encryption key has not
+ * been set by the user.
+ */
+ public static final int ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY = 4;
+
+ /**
* Activity action: begin the process of encrypting data on the device. This activity should
* be launched after using {@link #setStorageEncryption} to request encryption be activated.
* After resuming from this activity, use {@link #getStorageEncryption}
@@ -1905,12 +1912,15 @@ public class DevicePolicyManager {
* storage system does not support encryption. If the
* result is {@link #ENCRYPTION_STATUS_INACTIVE}, use {@link
* #ACTION_START_ENCRYPTION} to begin the process of encrypting or decrypting the
- * storage. If the result is {@link #ENCRYPTION_STATUS_ACTIVATING} or
+ * storage. If the result is {@link #ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY}, the
+ * storage system has enabled encryption but no password is set so further action
+ * may be required. If the result is {@link #ENCRYPTION_STATUS_ACTIVATING} or
* {@link #ENCRYPTION_STATUS_ACTIVE}, no further action is required.
*
* @return current status of encryption. The value will be one of
* {@link #ENCRYPTION_STATUS_UNSUPPORTED}, {@link #ENCRYPTION_STATUS_INACTIVE},
- * {@link #ENCRYPTION_STATUS_ACTIVATING}, or{@link #ENCRYPTION_STATUS_ACTIVE}.
+ * {@link #ENCRYPTION_STATUS_ACTIVATING}, {@link #ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY},
+ * or {@link #ENCRYPTION_STATUS_ACTIVE}.
*/
public int getStorageEncryptionStatus() {
return getStorageEncryptionStatus(UserHandle.myUserId());
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 61cdec3..80b5e0b 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2200,6 +2200,7 @@ public abstract class Context {
//@hide: PERSISTENT_DATA_BLOCK_SERVICE,
MEDIA_PROJECTION_SERVICE,
MIDI_SERVICE,
+ RADIO_SERVICE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ServiceName {}
@@ -3026,6 +3027,17 @@ public abstract class Context {
*/
public static final String MIDI_SERVICE = "midi";
+
+ /**
+ * Use with {@link #getSystemService} to retrieve a
+ * {@link android.hardware.radio.RadioManager} for accessing the broadcast radio service.
+ *
+ * @see #getSystemService
+ * @hide
+ */
+ public static final String RADIO_SERVICE = "radio";
+
+
/**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 2ed8c44..f685475 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2790,6 +2790,31 @@ public class Intent implements Parcelable, Cloneable {
/** {@hide} */
public static final String ACTION_MASTER_CLEAR = "android.intent.action.MASTER_CLEAR";
+ /**
+ * Broadcast action: report that a settings element is being restored from backup. The intent
+ * contains three extras: EXTRA_SETTING_NAME is a string naming the restored setting,
+ * EXTRA_SETTING_NEW_VALUE is the value being restored, and EXTRA_SETTING_PREVIOUS_VALUE
+ * is the value of that settings entry prior to the restore operation. All of these values are
+ * represented as strings.
+ *
+ * <p>This broadcast is sent only for settings provider entries known to require special handling
+ * around restore time. These entries are found in the BROADCAST_ON_RESTORE table within
+ * the provider's backup agent implementation.
+ *
+ * @see #EXTRA_SETTING_NAME
+ * @see #EXTRA_SETTING_PREVIOUS_VALUE
+ * @see #EXTRA_SETTING_NEW_VALUE
+ * {@hide}
+ */
+ public static final String ACTION_SETTING_RESTORED = "android.os.action.SETTING_RESTORED";
+
+ /** {@hide} */
+ public static final String EXTRA_SETTING_NAME = "setting_name";
+ /** {@hide} */
+ public static final String EXTRA_SETTING_PREVIOUS_VALUE = "previous_value";
+ /** {@hide} */
+ public static final String EXTRA_SETTING_NEW_VALUE = "new_value";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Standard intent categories (see addCategory()).
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index b518498..3e5d362 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -261,9 +261,9 @@ interface IPackageManager {
void clearPackagePersistentPreferredActivities(String packageName, int userId);
void addCrossProfileIntentFilter(in IntentFilter intentFilter, String ownerPackage,
- int ownerUserId, int sourceUserId, int targetUserId, int flags);
+ int sourceUserId, int targetUserId, int flags);
- void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage, int ownerUserId);
+ void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage);
/**
* Report the set of 'Home' activity candidates, plus (if any) which of them
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index faa782a..b513379 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -1013,10 +1013,10 @@ public final class CameraManager {
if (DEBUG) {
Log.v(TAG,
String.format(
- "Device status was previously available (%d), " +
- " and is now again available (%d)" +
+ "Device status was previously available (%b), " +
+ " and is now again available (%b)" +
"so no new client visible update will be sent",
- isAvailable(status), isAvailable(status)));
+ isAvailable(oldStatus), isAvailable(status)));
}
return;
}
diff --git a/core/java/android/hardware/camera2/DngCreator.java b/core/java/android/hardware/camera2/DngCreator.java
index 33d539c..f16d650 100644
--- a/core/java/android/hardware/camera2/DngCreator.java
+++ b/core/java/android/hardware/camera2/DngCreator.java
@@ -453,7 +453,7 @@ public final class DngCreator implements AutoCloseable {
height + ") passed to write");
}
long capacity = pixels.capacity();
- long totalSize = rowStride * height + offset;
+ long totalSize = ((long) rowStride) * height + offset;
if (capacity < totalSize) {
throw new IllegalArgumentException("Image size " + capacity +
" is too small (must be larger than " + totalSize + ")");
diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
index 367a078..b5a019d 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
@@ -292,6 +292,10 @@ public class LegacyCameraDevice implements AutoCloseable {
Log.e(TAG, "configureOutputs - null outputs are not allowed");
return BAD_VALUE;
}
+ if (!output.isValid()) {
+ Log.e(TAG, "configureOutputs - invalid output surfaces are not allowed");
+ return BAD_VALUE;
+ }
StreamConfigurationMap streamConfigurations = mStaticCharacteristics.
get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
@@ -522,7 +526,7 @@ public class LegacyCameraDevice implements AutoCloseable {
* @return the width and height of the surface
*
* @throws NullPointerException if the {@code surface} was {@code null}
- * @throws IllegalStateException if the {@code surface} was invalid
+ * @throws BufferQueueAbandonedException if the {@code surface} was invalid
*/
public static Size getSurfaceSize(Surface surface) throws BufferQueueAbandonedException {
checkNotNull(surface);
diff --git a/core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java b/core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java
index 7e0c01b..4b7cfbf 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java
@@ -60,7 +60,7 @@ public class LegacyExceptionUtils {
case CameraBinderDecorator.NO_ERROR: {
return CameraBinderDecorator.NO_ERROR;
}
- case CameraBinderDecorator.ENODEV: {
+ case CameraBinderDecorator.BAD_VALUE: {
throw new BufferQueueAbandonedException();
}
}
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index ff74c59..691798f 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -498,6 +498,10 @@ public class RequestThreadManager {
return;
}
for(Surface s : surfaces) {
+ if (s == null || !s.isValid()) {
+ Log.w(TAG, "Jpeg surface is invalid, skipping...");
+ continue;
+ }
try {
LegacyCameraDevice.setSurfaceFormat(s, LegacyMetadataMapper.HAL_PIXEL_FORMAT_BLOB);
} catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
diff --git a/core/java/android/hardware/location/GeofenceHardwareImpl.java b/core/java/android/hardware/location/GeofenceHardwareImpl.java
index 6e5d064..4696b2a 100644
--- a/core/java/android/hardware/location/GeofenceHardwareImpl.java
+++ b/core/java/android/hardware/location/GeofenceHardwareImpl.java
@@ -436,7 +436,7 @@ public final class GeofenceHardwareImpl {
int monitoringType,
int sourcesUsed) {
if(location == null) {
- Log.e(TAG, String.format("Invalid Geofence Transition: location=%p", location));
+ Log.e(TAG, String.format("Invalid Geofence Transition: location=null"));
return;
}
if(DEBUG) {
diff --git a/core/java/android/hardware/radio/RadioManager.java b/core/java/android/hardware/radio/RadioManager.java
new file mode 100644
index 0000000..32930a7
--- /dev/null
+++ b/core/java/android/hardware/radio/RadioManager.java
@@ -0,0 +1,1308 @@
+/**
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.hardware.radio;
+
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Parcel;
+import android.os.Parcelable;
+import java.util.List;
+import java.util.Arrays;
+
+/**
+ * The RadioManager class allows to control a broadcast radio tuner present on the device.
+ * It provides data structures and methods to query for available radio modules, list their
+ * properties and open an interface to control tuning operations and receive callbacks when
+ * asynchronous operations complete or events occur.
+ * @hide
+ */
+@SystemApi
+public class RadioManager {
+
+ /** Method return status: successful operation */
+ public static final int STATUS_OK = 0;
+ /** Method return status: unspecified error */
+ public static final int STATUS_ERROR = Integer.MIN_VALUE;
+ /** Method return status: permission denied */
+ public static final int STATUS_PERMISSION_DENIED = -1;
+ /** Method return status: initialization failure */
+ public static final int STATUS_NO_INIT = -19;
+ /** Method return status: invalid argument provided */
+ public static final int STATUS_BAD_VALUE = -22;
+ /** Method return status: cannot reach service */
+ public static final int STATUS_DEAD_OBJECT = -32;
+ /** Method return status: invalid or out of sequence operation */
+ public static final int STATUS_INVALID_OPERATION = -38;
+ /** Method return status: time out before operation completion */
+ public static final int STATUS_TIMED_OUT = -110;
+
+
+ // keep in sync with radio_class_t in /system/core/incluse/system/radio.h
+ /** Radio module class supporting FM (including HD radio) and AM */
+ public static final int CLASS_AM_FM = 0;
+ /** Radio module class supporting satellite radio */
+ public static final int CLASS_SAT = 1;
+ /** Radio module class supporting Digital terrestrial radio */
+ public static final int CLASS_DT = 2;
+
+ // keep in sync with radio_band_t in /system/core/incluse/system/radio.h
+ /** AM radio band (LW/MW/SW).
+ * @see BandDescriptor */
+ public static final int BAND_AM = 0;
+ /** FM radio band.
+ * @see BandDescriptor */
+ public static final int BAND_FM = 1;
+ /** FM HD radio or DRM band.
+ * @see BandDescriptor */
+ public static final int BAND_FM_HD = 2;
+ /** AM HD radio or DRM band.
+ * @see BandDescriptor */
+ public static final int BAND_AM_HD = 3;
+
+ // keep in sync with radio_region_t in /system/core/incluse/system/radio.h
+ /** Africa, Europe.
+ * @see BandDescriptor */
+ public static final int REGION_ITU_1 = 0;
+ /** Americas.
+ * @see BandDescriptor */
+ public static final int REGION_ITU_2 = 1;
+ /** Russia.
+ * @see BandDescriptor */
+ public static final int REGION_OIRT = 2;
+ /** Japan.
+ * @see BandDescriptor */
+ public static final int REGION_JAPAN = 3;
+ /** Korea.
+ * @see BandDescriptor */
+ public static final int REGION_KOREA = 4;
+
+ /*****************************************************************************
+ * Lists properties, options and radio bands supported by a given broadcast radio module.
+ * Each module has a unique ID used to address it when calling RadioManager APIs.
+ * Module properties are returned by {@link #listModules(List <ModuleProperties>)} method.
+ ****************************************************************************/
+ public static class ModuleProperties implements Parcelable {
+
+ private final int mId;
+ private final int mClassId;
+ private final String mImplementor;
+ private final String mProduct;
+ private final String mVersion;
+ private final String mSerial;
+ private final int mNumTuners;
+ private final int mNumAudioSources;
+ private final boolean mIsCaptureSupported;
+ private final BandDescriptor[] mBands;
+
+ ModuleProperties(int id, int classId, String implementor, String product, String version,
+ String serial, int numTuners, int numAudioSources, boolean isCaptureSupported,
+ BandDescriptor[] bands) {
+ mId = id;
+ mClassId = classId;
+ mImplementor = implementor;
+ mProduct = product;
+ mVersion = version;
+ mSerial = serial;
+ mNumTuners = numTuners;
+ mNumAudioSources = numAudioSources;
+ mIsCaptureSupported = isCaptureSupported;
+ mBands = bands;
+ }
+
+
+ /** Unique module identifier provided by the native service.
+ * For use with {@link #openTuner(int, BandConfig, boolean, Callback, Handler)}.
+ * @return the radio module unique identifier.
+ */
+ public int getId() {
+ return mId;
+ }
+
+ /** Module class identifier: {@link #CLASS_AM_FM}, {@link #CLASS_SAT}, {@link #CLASS_DT}
+ * @return the radio module class identifier.
+ */
+ public int getClassId() {
+ return mClassId;
+ }
+
+ /** Human readable broadcast radio module implementor
+ * @return the name of the radio module implementator.
+ */
+ public String getImplementor() {
+ return mImplementor;
+ }
+
+ /** Human readable broadcast radio module product name
+ * @return the radio module product name.
+ */
+ public String getProduct() {
+ return mProduct;
+ }
+
+ /** Human readable broadcast radio module version number
+ * @return the radio module version.
+ */
+ public String getVersion() {
+ return mVersion;
+ }
+
+ /** Radio module serial number.
+ * Can be used for subscription services.
+ * @return the radio module serial number.
+ */
+ public String getSerial() {
+ return mSerial;
+ }
+
+ /** Number of tuners available.
+ * This is the number of tuners that can be open simultaneously.
+ * @return the number of tuners supported.
+ */
+ public int getNumTuners() {
+ return mNumTuners;
+ }
+
+ /** Number tuner audio sources available. Must be less or equal to getNumTuners().
+ * When more than one tuner is supported, one is usually for playback and has one
+ * associated audio source and the other is for pre scanning and building a
+ * program list.
+ * @return the number of audio sources available.
+ */
+ public int getNumAudioSources() {
+ return mNumAudioSources;
+ }
+
+ /** {@code true} if audio capture is possible from radio tuner output.
+ * This indicates if routing to audio devices not connected to the same HAL as the FM radio
+ * is possible (e.g. to USB) or DAR (Digital Audio Recorder) feature can be implemented.
+ * @return {@code true} if audio capture is possible, {@code false} otherwise.
+ */
+ public boolean isCaptureSupported() {
+ return mIsCaptureSupported;
+ }
+
+ /** List of descriptors for all bands supported by this module.
+ * @return an array of {@link BandDescriptor}.
+ */
+ public BandDescriptor[] getBands() {
+ return mBands;
+ }
+
+ private ModuleProperties(Parcel in) {
+ mId = in.readInt();
+ mClassId = in.readInt();
+ mImplementor = in.readString();
+ mProduct = in.readString();
+ mVersion = in.readString();
+ mSerial = in.readString();
+ mNumTuners = in.readInt();
+ mNumAudioSources = in.readInt();
+ mIsCaptureSupported = in.readInt() == 1;
+ Parcelable[] tmp = in.readParcelableArray(BandDescriptor.class.getClassLoader());
+ mBands = new BandDescriptor[tmp.length];
+ for (int i = 0; i < tmp.length; i++) {
+ mBands[i] = (BandDescriptor) tmp[i];
+ }
+ }
+
+ public static final Parcelable.Creator<ModuleProperties> CREATOR
+ = new Parcelable.Creator<ModuleProperties>() {
+ public ModuleProperties createFromParcel(Parcel in) {
+ return new ModuleProperties(in);
+ }
+
+ public ModuleProperties[] newArray(int size) {
+ return new ModuleProperties[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mId);
+ dest.writeInt(mClassId);
+ dest.writeString(mImplementor);
+ dest.writeString(mProduct);
+ dest.writeString(mVersion);
+ dest.writeString(mSerial);
+ dest.writeInt(mNumTuners);
+ dest.writeInt(mNumAudioSources);
+ dest.writeInt(mIsCaptureSupported ? 1 : 0);
+ dest.writeParcelableArray(mBands, flags);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return "ModuleProperties [mId=" + mId + ", mClassId=" + mClassId
+ + ", mImplementor=" + mImplementor + ", mProduct=" + mProduct
+ + ", mVersion=" + mVersion + ", mSerial=" + mSerial
+ + ", mNumTuners=" + mNumTuners
+ + ", mNumAudioSources=" + mNumAudioSources
+ + ", mIsCaptureSupported=" + mIsCaptureSupported
+ + ", mBands=" + Arrays.toString(mBands) + "]";
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + mId;
+ result = prime * result + mClassId;
+ result = prime * result + ((mImplementor == null) ? 0 : mImplementor.hashCode());
+ result = prime * result + ((mProduct == null) ? 0 : mProduct.hashCode());
+ result = prime * result + ((mVersion == null) ? 0 : mVersion.hashCode());
+ result = prime * result + ((mSerial == null) ? 0 : mSerial.hashCode());
+ result = prime * result + mNumTuners;
+ result = prime * result + mNumAudioSources;
+ result = prime * result + (mIsCaptureSupported ? 1 : 0);
+ result = prime * result + Arrays.hashCode(mBands);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!(obj instanceof ModuleProperties))
+ return false;
+ ModuleProperties other = (ModuleProperties) obj;
+ if (mId != other.getId())
+ return false;
+ if (mClassId != other.getClassId())
+ return false;
+ if (mImplementor == null) {
+ if (other.getImplementor() != null)
+ return false;
+ } else if (!mImplementor.equals(other.getImplementor()))
+ return false;
+ if (mProduct == null) {
+ if (other.getProduct() != null)
+ return false;
+ } else if (!mProduct.equals(other.getProduct()))
+ return false;
+ if (mVersion == null) {
+ if (other.getVersion() != null)
+ return false;
+ } else if (!mVersion.equals(other.getVersion()))
+ return false;
+ if (mSerial == null) {
+ if (other.getSerial() != null)
+ return false;
+ } else if (!mSerial.equals(other.getSerial()))
+ return false;
+ if (mNumTuners != other.getNumTuners())
+ return false;
+ if (mNumAudioSources != other.getNumAudioSources())
+ return false;
+ if (mIsCaptureSupported != other.isCaptureSupported())
+ return false;
+ if (!Arrays.equals(mBands, other.getBands()))
+ return false;
+ return true;
+ }
+ }
+
+ /** Radio band descriptor: an element in ModuleProperties bands array.
+ * It is either an instance of {@link FmBandDescriptor} or {@link AmBandDescriptor} */
+ public static class BandDescriptor implements Parcelable {
+
+ private final int mRegion;
+ private final int mType;
+ private final int mLowerLimit;
+ private final int mUpperLimit;
+ private final int mSpacing;
+
+ BandDescriptor(int region, int type, int lowerLimit, int upperLimit, int spacing) {
+ mRegion = region;
+ mType = type;
+ mLowerLimit = lowerLimit;
+ mUpperLimit = upperLimit;
+ mSpacing = spacing;
+ }
+
+ /** Region this band applies to. E.g. {@link #REGION_ITU_1}
+ * @return the region this band is associated to.
+ */
+ public int getRegion() {
+ return mRegion;
+ }
+ /** Band type, e.g {@link #BAND_FM}. Defines the subclass this descriptor can be cast to:
+ * <ul>
+ * <li>{@link #BAND_FM} or {@link #BAND_FM_HD} cast to {@link FmBandDescriptor}, </li>
+ * <li>{@link #BAND_AM} cast to {@link AmBandDescriptor}, </li>
+ * </ul>
+ * @return the band type.
+ */
+ public int getType() {
+ return mType;
+ }
+ /** Lower band limit expressed in units according to band type.
+ * Currently all defined band types express channels as frequency in kHz
+ * @return the lower band limit.
+ */
+ public int getLowerLimit() {
+ return mLowerLimit;
+ }
+ /** Upper band limit expressed in units according to band type.
+ * Currently all defined band types express channels as frequency in kHz
+ * @return the upper band limit.
+ */
+ public int getUpperLimit() {
+ return mUpperLimit;
+ }
+ /** Channel spacing in units according to band type.
+ * Currently all defined band types express channels as frequency in kHz
+ * @return the channel spacing.
+ */
+ public int getSpacing() {
+ return mSpacing;
+ }
+
+ private BandDescriptor(Parcel in) {
+ mRegion = in.readInt();
+ mType = in.readInt();
+ mLowerLimit = in.readInt();
+ mUpperLimit = in.readInt();
+ mSpacing = in.readInt();
+ }
+
+ public static final Parcelable.Creator<BandDescriptor> CREATOR
+ = new Parcelable.Creator<BandDescriptor>() {
+ public BandDescriptor createFromParcel(Parcel in) {
+ return new BandDescriptor(in);
+ }
+
+ public BandDescriptor[] newArray(int size) {
+ return new BandDescriptor[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mRegion);
+ dest.writeInt(mType);
+ dest.writeInt(mLowerLimit);
+ dest.writeInt(mUpperLimit);
+ dest.writeInt(mSpacing);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return "BandDescriptor [mRegion=" + mRegion + ", mType=" + mType + ", mLowerLimit="
+ + mLowerLimit + ", mUpperLimit=" + mUpperLimit + ", mSpacing=" + mSpacing + "]";
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + mRegion;
+ result = prime * result + mType;
+ result = prime * result + mLowerLimit;
+ result = prime * result + mUpperLimit;
+ result = prime * result + mSpacing;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!(obj instanceof BandDescriptor))
+ return false;
+ BandDescriptor other = (BandDescriptor) obj;
+ if (mRegion != other.getRegion())
+ return false;
+ if (mType != other.getType())
+ return false;
+ if (mLowerLimit != other.getLowerLimit())
+ return false;
+ if (mUpperLimit != other.getUpperLimit())
+ return false;
+ if (mSpacing != other.getSpacing())
+ return false;
+ return true;
+ }
+ }
+
+ /** FM band descriptor
+ * @see #BAND_FM
+ * @see #BAND_FM_HD */
+ public static class FmBandDescriptor extends BandDescriptor {
+ private final boolean mStereo;
+ private final boolean mRds;
+ private final boolean mTa;
+ private final boolean mAf;
+
+ FmBandDescriptor(int region, int type, int lowerLimit, int upperLimit, int spacing,
+ boolean stereo, boolean rds, boolean ta, boolean af) {
+ super(region, type, lowerLimit, upperLimit, spacing);
+ mStereo = stereo;
+ mRds = rds;
+ mTa = ta;
+ mAf = af;
+ }
+
+ /** Stereo is supported
+ * @return {@code true} if stereo is supported, {@code false} otherwise.
+ */
+ public boolean isStereoSupported() {
+ return mStereo;
+ }
+ /** RDS or RBDS(if region is ITU2) is supported
+ * @return {@code true} if RDS or RBDS is supported, {@code false} otherwise.
+ */
+ public boolean isRdsSupported() {
+ return mRds;
+ }
+ /** Traffic announcement is supported
+ * @return {@code true} if TA is supported, {@code false} otherwise.
+ */
+ public boolean isTaSupported() {
+ return mTa;
+ }
+ /** Alternate Frequency Switching is supported
+ * @return {@code true} if AF switching is supported, {@code false} otherwise.
+ */
+ public boolean isAfSupported() {
+ return mAf;
+ }
+
+ /* Parcelable implementation */
+ private FmBandDescriptor(Parcel in) {
+ super(in);
+ mStereo = in.readByte() == 1;
+ mRds = in.readByte() == 1;
+ mTa = in.readByte() == 1;
+ mAf = in.readByte() == 1;
+ }
+
+ public static final Parcelable.Creator<FmBandDescriptor> CREATOR
+ = new Parcelable.Creator<FmBandDescriptor>() {
+ public FmBandDescriptor createFromParcel(Parcel in) {
+ return new FmBandDescriptor(in);
+ }
+
+ public FmBandDescriptor[] newArray(int size) {
+ return new FmBandDescriptor[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeByte((byte) (mStereo ? 1 : 0));
+ dest.writeByte((byte) (mRds ? 1 : 0));
+ dest.writeByte((byte) (mTa ? 1 : 0));
+ dest.writeByte((byte) (mAf ? 1 : 0));
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return "FmBandDescriptor [ "+ super.toString() + " mStereo=" + mStereo
+ + ", mRds=" + mRds + ", mTa=" + mTa + ", mAf=" + mAf + "]";
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + (mStereo ? 1 : 0);
+ result = prime * result + (mRds ? 1 : 0);
+ result = prime * result + (mTa ? 1 : 0);
+ result = prime * result + (mAf ? 1 : 0);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (!(obj instanceof FmBandDescriptor))
+ return false;
+ FmBandDescriptor other = (FmBandDescriptor) obj;
+ if (mStereo != other.isStereoSupported())
+ return false;
+ if (mRds != other.isRdsSupported())
+ return false;
+ if (mTa != other.isTaSupported())
+ return false;
+ if (mAf != other.isAfSupported())
+ return false;
+ return true;
+ }
+ }
+
+ /** AM band descriptor.
+ * @see #BAND_AM */
+ public static class AmBandDescriptor extends BandDescriptor {
+
+ private final boolean mStereo;
+
+ AmBandDescriptor(int region, int type, int lowerLimit, int upperLimit, int spacing,
+ boolean stereo) {
+ super(region, type, lowerLimit, upperLimit, spacing);
+ mStereo = stereo;
+ }
+
+ /** Stereo is supported
+ * @return {@code true} if stereo is supported, {@code false} otherwise.
+ */
+ public boolean isStereoSupported() {
+ return mStereo;
+ }
+
+ private AmBandDescriptor(Parcel in) {
+ super(in);
+ mStereo = in.readByte() == 1;
+ }
+
+ public static final Parcelable.Creator<AmBandDescriptor> CREATOR
+ = new Parcelable.Creator<AmBandDescriptor>() {
+ public AmBandDescriptor createFromParcel(Parcel in) {
+ return new AmBandDescriptor(in);
+ }
+
+ public AmBandDescriptor[] newArray(int size) {
+ return new AmBandDescriptor[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeByte((byte) (mStereo ? 1 : 0));
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return "AmBandDescriptor [ "+ super.toString() + " mStereo=" + mStereo + "]";
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + (mStereo ? 1 : 0);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (!(obj instanceof AmBandDescriptor))
+ return false;
+ AmBandDescriptor other = (AmBandDescriptor) obj;
+ if (mStereo != other.isStereoSupported())
+ return false;
+ return true;
+ }
+ }
+
+
+ /** Radio band configuration. */
+ public static class BandConfig implements Parcelable {
+
+ final BandDescriptor mDescriptor;
+
+ BandConfig(BandDescriptor descriptor) {
+ mDescriptor = descriptor;
+ }
+
+ BandConfig(int region, int type, int lowerLimit, int upperLimit, int spacing) {
+ mDescriptor = new BandDescriptor(region, type, lowerLimit, upperLimit, spacing);
+ }
+
+ private BandConfig(Parcel in) {
+ mDescriptor = new BandDescriptor(in);
+ }
+
+ BandDescriptor getDescriptor() {
+ return mDescriptor;
+ }
+
+ /** Region this band applies to. E.g. {@link #REGION_ITU_1}
+ * @return the region associated with this band.
+ */
+ public int getRegion() {
+ return mDescriptor.getRegion();
+ }
+ /** Band type, e.g {@link #BAND_FM}. Defines the subclass this descriptor can be cast to:
+ * <ul>
+ * <li>{@link #BAND_FM} or {@link #BAND_FM_HD} cast to {@link FmBandDescriptor}, </li>
+ * <li>{@link #BAND_AM} cast to {@link AmBandDescriptor}, </li>
+ * </ul>
+ * @return the band type.
+ */
+ public int getType() {
+ return mDescriptor.getType();
+ }
+ /** Lower band limit expressed in units according to band type.
+ * Currently all defined band types express channels as frequency in kHz
+ * @return the lower band limit.
+ */
+ public int getLowerLimit() {
+ return mDescriptor.getLowerLimit();
+ }
+ /** Upper band limit expressed in units according to band type.
+ * Currently all defined band types express channels as frequency in kHz
+ * @return the upper band limit.
+ */
+ public int getUpperLimit() {
+ return mDescriptor.getUpperLimit();
+ }
+ /** Channel spacing in units according to band type.
+ * Currently all defined band types express channels as frequency in kHz
+ * @return the channel spacing.
+ */
+ public int getSpacing() {
+ return mDescriptor.getSpacing();
+ }
+
+
+ public static final Parcelable.Creator<BandConfig> CREATOR
+ = new Parcelable.Creator<BandConfig>() {
+ public BandConfig createFromParcel(Parcel in) {
+ return new BandConfig(in);
+ }
+
+ public BandConfig[] newArray(int size) {
+ return new BandConfig[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ mDescriptor.writeToParcel(dest, flags);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return "BandConfig [ " + mDescriptor.toString() + "]";
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + mDescriptor.hashCode();
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!(obj instanceof BandConfig))
+ return false;
+ BandConfig other = (BandConfig) obj;
+ if (mDescriptor != other.getDescriptor())
+ return false;
+ return true;
+ }
+ }
+
+ /** FM band configuration.
+ * @see #BAND_FM
+ * @see #BAND_FM_HD */
+ public static class FmBandConfig extends BandConfig {
+ private final boolean mStereo;
+ private final boolean mRds;
+ private final boolean mTa;
+ private final boolean mAf;
+
+ FmBandConfig(FmBandDescriptor descriptor) {
+ super((BandDescriptor)descriptor);
+ mStereo = descriptor.isStereoSupported();
+ mRds = descriptor.isRdsSupported();
+ mTa = descriptor.isTaSupported();
+ mAf = descriptor.isAfSupported();
+ }
+
+ FmBandConfig(int region, int type, int lowerLimit, int upperLimit, int spacing,
+ boolean stereo, boolean rds, boolean ta, boolean af) {
+ super(region, type, lowerLimit, upperLimit, spacing);
+ mStereo = stereo;
+ mRds = rds;
+ mTa = ta;
+ mAf = af;
+ }
+
+ /** Get stereo enable state
+ * @return the enable state.
+ */
+ public boolean getStereo() {
+ return mStereo;
+ }
+
+ /** Get RDS or RBDS(if region is ITU2) enable state
+ * @return the enable state.
+ */
+ public boolean getRds() {
+ return mRds;
+ }
+
+ /** Get Traffic announcement enable state
+ * @return the enable state.
+ */
+ public boolean getTa() {
+ return mTa;
+ }
+
+ /** Get Alternate Frequency Switching enable state
+ * @return the enable state.
+ */
+ public boolean getAf() {
+ return mAf;
+ }
+
+ private FmBandConfig(Parcel in) {
+ super(in);
+ mStereo = in.readByte() == 1;
+ mRds = in.readByte() == 1;
+ mTa = in.readByte() == 1;
+ mAf = in.readByte() == 1;
+ }
+
+ public static final Parcelable.Creator<FmBandConfig> CREATOR
+ = new Parcelable.Creator<FmBandConfig>() {
+ public FmBandConfig createFromParcel(Parcel in) {
+ return new FmBandConfig(in);
+ }
+
+ public FmBandConfig[] newArray(int size) {
+ return new FmBandConfig[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeByte((byte) (mStereo ? 1 : 0));
+ dest.writeByte((byte) (mRds ? 1 : 0));
+ dest.writeByte((byte) (mTa ? 1 : 0));
+ dest.writeByte((byte) (mAf ? 1 : 0));
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return "FmBandConfig [" + super.toString()
+ + ", mStereo=" + mStereo + ", mRds=" + mRds + ", mTa=" + mTa
+ + ", mAf=" + mAf + "]";
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + (mStereo ? 1 : 0);
+ result = prime * result + (mRds ? 1 : 0);
+ result = prime * result + (mTa ? 1 : 0);
+ result = prime * result + (mAf ? 1 : 0);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (!(obj instanceof FmBandConfig))
+ return false;
+ FmBandConfig other = (FmBandConfig) obj;
+ if (mStereo != other.mStereo)
+ return false;
+ if (mRds != other.mRds)
+ return false;
+ if (mTa != other.mTa)
+ return false;
+ if (mAf != other.mAf)
+ return false;
+ return true;
+ }
+
+ /**
+ * Builder class for {@link FmBandConfig} objects.
+ */
+ public static class Builder {
+ private final BandDescriptor mDescriptor;
+ private boolean mStereo;
+ private boolean mRds;
+ private boolean mTa;
+ private boolean mAf;
+
+ /**
+ * Constructs a new Builder with the defaults from an {@link FmBandDescriptor} .
+ * @param descriptor the FmBandDescriptor defaults are read from .
+ */
+ public Builder(FmBandDescriptor descriptor) {
+ mDescriptor = new BandDescriptor(descriptor.getRegion(), descriptor.getType(),
+ descriptor.getLowerLimit(), descriptor.getUpperLimit(),
+ descriptor.getSpacing());
+ mStereo = descriptor.isStereoSupported();
+ mRds = descriptor.isRdsSupported();
+ mTa = descriptor.isTaSupported();
+ mAf = descriptor.isAfSupported();
+ }
+
+ /**
+ * Constructs a new Builder from a given {@link FmBandConfig}
+ * @param config the FmBandConfig object whose data will be reused in the new Builder.
+ */
+ public Builder(FmBandConfig config) {
+ mDescriptor = new BandDescriptor(config.getRegion(), config.getType(),
+ config.getLowerLimit(), config.getUpperLimit(), config.getSpacing());
+ mStereo = config.getStereo();
+ mRds = config.getRds();
+ mTa = config.getTa();
+ mAf = config.getAf();
+ }
+
+ /**
+ * Combines all of the parameters that have been set and return a new
+ * {@link FmBandConfig} object.
+ * @return a new {@link FmBandConfig} object
+ */
+ public FmBandConfig build() {
+ FmBandConfig config = new FmBandConfig(mDescriptor.getRegion(),
+ mDescriptor.getType(), mDescriptor.getLowerLimit(),
+ mDescriptor.getUpperLimit(), mDescriptor.getSpacing(),
+ mStereo, mRds, mTa, mAf);
+ return config;
+ }
+
+ /** Set stereo enable state
+ * @param state The new enable state.
+ * @return the same Builder instance.
+ */
+ public Builder setStereo(boolean state) {
+ mStereo = state;
+ return this;
+ }
+
+ /** Set RDS or RBDS(if region is ITU2) enable state
+ * @param state The new enable state.
+ * @return the same Builder instance.
+ */
+ public Builder setRds(boolean state) {
+ mRds = state;
+ return this;
+ }
+
+ /** Set Traffic announcement enable state
+ * @param state The new enable state.
+ * @return the same Builder instance.
+ */
+ public Builder setTa(boolean state) {
+ mTa = state;
+ return this;
+ }
+
+ /** Set Alternate Frequency Switching enable state
+ * @param state The new enable state.
+ * @return the same Builder instance.
+ */
+ public Builder setAf(boolean state) {
+ mAf = state;
+ return this;
+ }
+ };
+ }
+
+ /** AM band configuration.
+ * @see #BAND_AM */
+ public static class AmBandConfig extends BandConfig {
+ private final boolean mStereo;
+
+ AmBandConfig(AmBandDescriptor descriptor) {
+ super((BandDescriptor)descriptor);
+ mStereo = descriptor.isStereoSupported();
+ }
+
+ AmBandConfig(int region, int type, int lowerLimit, int upperLimit, int spacing,
+ boolean stereo) {
+ super(region, type, lowerLimit, upperLimit, spacing);
+ mStereo = stereo;
+ }
+
+ /** Get stereo enable state
+ * @return the enable state.
+ */
+ public boolean getStereo() {
+ return mStereo;
+ }
+
+ private AmBandConfig(Parcel in) {
+ super(in);
+ mStereo = in.readByte() == 1;
+ }
+
+ public static final Parcelable.Creator<AmBandConfig> CREATOR
+ = new Parcelable.Creator<AmBandConfig>() {
+ public AmBandConfig createFromParcel(Parcel in) {
+ return new AmBandConfig(in);
+ }
+
+ public AmBandConfig[] newArray(int size) {
+ return new AmBandConfig[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeByte((byte) (mStereo ? 1 : 0));
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return "AmBandConfig [" + super.toString()
+ + ", mStereo=" + mStereo + "]";
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + (mStereo ? 1 : 0);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (!(obj instanceof AmBandConfig))
+ return false;
+ AmBandConfig other = (AmBandConfig) obj;
+ if (mStereo != other.getStereo())
+ return false;
+ return true;
+ }
+
+ /**
+ * Builder class for {@link AmBandConfig} objects.
+ */
+ public static class Builder {
+ private final BandDescriptor mDescriptor;
+ private boolean mStereo;
+
+ /**
+ * Constructs a new Builder with the defaults from an {@link AmBandDescriptor} .
+ * @param descriptor the FmBandDescriptor defaults are read from .
+ */
+ public Builder(AmBandDescriptor descriptor) {
+ mDescriptor = new BandDescriptor(descriptor.getRegion(), descriptor.getType(),
+ descriptor.getLowerLimit(), descriptor.getUpperLimit(),
+ descriptor.getSpacing());
+ mStereo = descriptor.isStereoSupported();
+ }
+
+ /**
+ * Constructs a new Builder from a given {@link AmBandConfig}
+ * @param config the FmBandConfig object whose data will be reused in the new Builder.
+ */
+ public Builder(AmBandConfig config) {
+ mDescriptor = new BandDescriptor(config.getRegion(), config.getType(),
+ config.getLowerLimit(), config.getUpperLimit(), config.getSpacing());
+ mStereo = config.getStereo();
+ }
+
+ /**
+ * Combines all of the parameters that have been set and return a new
+ * {@link AmBandConfig} object.
+ * @return a new {@link AmBandConfig} object
+ */
+ public AmBandConfig build() {
+ AmBandConfig config = new AmBandConfig(mDescriptor.getRegion(),
+ mDescriptor.getType(), mDescriptor.getLowerLimit(),
+ mDescriptor.getUpperLimit(), mDescriptor.getSpacing(),
+ mStereo);
+ return config;
+ }
+
+ /** Set stereo enable state
+ * @param state The new enable state.
+ * @return the same Builder instance.
+ */
+ public Builder setStereo(boolean state) {
+ mStereo = state;
+ return this;
+ }
+ };
+ }
+
+ /** Radio program information returned by
+ * {@link RadioTuner#getProgramInformation(RadioManager.ProgramInfo[])} */
+ public static class ProgramInfo implements Parcelable {
+
+ private final int mChannel;
+ private final int mSubChannel;
+ private final boolean mTuned;
+ private final boolean mStereo;
+ private final boolean mDigital;
+ private final int mSignalStrength;
+ private final RadioMetadata mMetadata;
+
+ ProgramInfo(int channel, int subChannel, boolean tuned, boolean stereo,
+ boolean digital, int signalStrength, RadioMetadata metadata) {
+ mChannel = channel;
+ mSubChannel = subChannel;
+ mTuned = tuned;
+ mStereo = stereo;
+ mDigital = digital;
+ mSignalStrength = signalStrength;
+ mMetadata = metadata;
+ }
+
+ /** Main channel expressed in units according to band type.
+ * Currently all defined band types express channels as frequency in kHz
+ * @return the program channel
+ */
+ public int getChannel() {
+ return mChannel;
+ }
+ /** Sub channel ID. E.g 1 for HD radio HD1
+ * @return the program sub channel
+ */
+ public int getSubChannel() {
+ return mSubChannel;
+ }
+ /** {@code true} if the tuner is currently tuned on a valid station
+ * @return {@code true} if currently tuned, {@code false} otherwise.
+ */
+ public boolean isTuned() {
+ return mTuned;
+ }
+ /** {@code true} if the received program is stereo
+ * @return {@code true} if stereo, {@code false} otherwise.
+ */
+ public boolean isStereo() {
+ return mStereo;
+ }
+ /** {@code true} if the received program is digital (e.g HD radio)
+ * @return {@code true} if digital, {@code false} otherwise.
+ */
+ public boolean isDigital() {
+ return mDigital;
+ }
+ /** Signal strength indicator from 0 (no signal) to 100 (excellent)
+ * @return the signal strength indication.
+ */
+ public int getSignalStrength() {
+ return mSignalStrength;
+ }
+ /** Metadata currently received from this station.
+ * null if no metadata have been received
+ * @return current meta data received from this program.
+ */
+ public RadioMetadata getMetadata() {
+ return mMetadata;
+ }
+
+ private ProgramInfo(Parcel in) {
+ mChannel = in.readInt();
+ mSubChannel = in.readInt();
+ mTuned = in.readByte() == 1;
+ mStereo = in.readByte() == 1;
+ mDigital = in.readByte() == 1;
+ mSignalStrength = in.readInt();
+ if (in.readByte() == 1) {
+ mMetadata = RadioMetadata.CREATOR.createFromParcel(in);
+ } else {
+ mMetadata = null;
+ }
+ }
+
+ public static final Parcelable.Creator<ProgramInfo> CREATOR
+ = new Parcelable.Creator<ProgramInfo>() {
+ public ProgramInfo createFromParcel(Parcel in) {
+ return new ProgramInfo(in);
+ }
+
+ public ProgramInfo[] newArray(int size) {
+ return new ProgramInfo[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mChannel);
+ dest.writeInt(mSubChannel);
+ dest.writeByte((byte)(mTuned ? 1 : 0));
+ dest.writeByte((byte)(mStereo ? 1 : 0));
+ dest.writeByte((byte)(mDigital ? 1 : 0));
+ dest.writeInt(mSignalStrength);
+ if (mMetadata == null) {
+ dest.writeByte((byte)0);
+ } else {
+ dest.writeByte((byte)1);
+ mMetadata.writeToParcel(dest, flags);
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return "ProgramInfo [mChannel=" + mChannel + ", mSubChannel=" + mSubChannel
+ + ", mTuned=" + mTuned + ", mStereo=" + mStereo + ", mDigital=" + mDigital
+ + ", mSignalStrength=" + mSignalStrength
+ + ((mMetadata == null) ? "" : (", mMetadata=" + mMetadata.toString()))
+ + "]";
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + mChannel;
+ result = prime * result + mSubChannel;
+ result = prime * result + (mTuned ? 1 : 0);
+ result = prime * result + (mStereo ? 1 : 0);
+ result = prime * result + (mDigital ? 1 : 0);
+ result = prime * result + mSignalStrength;
+ result = prime * result + ((mMetadata == null) ? 0 : mMetadata.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!(obj instanceof ProgramInfo))
+ return false;
+ ProgramInfo other = (ProgramInfo) obj;
+ if (mChannel != other.getChannel())
+ return false;
+ if (mSubChannel != other.getSubChannel())
+ return false;
+ if (mTuned != other.isTuned())
+ return false;
+ if (mStereo != other.isStereo())
+ return false;
+ if (mDigital != other.isDigital())
+ return false;
+ if (mSignalStrength != other.getSignalStrength())
+ return false;
+ if (mMetadata == null) {
+ if (other.getMetadata() != null)
+ return false;
+ } else if (!mMetadata.equals(other.getMetadata()))
+ return false;
+ return true;
+ }
+ }
+
+
+ /**
+ * Returns a list of descriptors for all broadcast radio modules present on the device.
+ * @param modules An List of {@link ModuleProperties} where the list will be returned.
+ * @return
+ * <ul>
+ * <li>{@link #STATUS_OK} in case of success, </li>
+ * <li>{@link #STATUS_ERROR} in case of unspecified error, </li>
+ * <li>{@link #STATUS_NO_INIT} if the native service cannot be reached, </li>
+ * <li>{@link #STATUS_BAD_VALUE} if modules is null, </li>
+ * <li>{@link #STATUS_DEAD_OBJECT} if the binder transaction to the native service fails, </li>
+ * </ul>
+ */
+ public native int listModules(List <ModuleProperties> modules);
+
+ /**
+ * Open an interface to control a tuner on a given broadcast radio module.
+ * Optionally selects and applies the configuration passed as "config" argument.
+ * @param moduleId radio module identifier {@link ModuleProperties#getId()}. Mandatory.
+ * @param config desired band and configuration to apply when enabling the hardware module.
+ * optional, can be null.
+ * @param withAudio {@code true} to request a tuner with an audio source.
+ * This tuner is intended for live listening or recording or a radio program.
+ * If {@code false}, the tuner can only be used to retrieve program informations.
+ * @param callback {@link RadioTuner.Callback} interface. Mandatory.
+ * @param handler the Handler on which the callbacks will be received.
+ * Can be null if default handler is OK.
+ * @return a valid {@link RadioTuner} interface in case of success or null in case of error.
+ */
+ public RadioTuner openTuner(int moduleId, BandConfig config, boolean withAudio,
+ RadioTuner.Callback callback, Handler handler) {
+ if (callback == null) {
+ return null;
+ }
+ RadioModule module = new RadioModule(moduleId, config, withAudio, callback, handler);
+ if (module != null) {
+ if (!module.initCheck()) {
+ module = null;
+ }
+ }
+ return (RadioTuner)module;
+ }
+
+ private final Context mContext;
+
+ /**
+ * @hide
+ */
+ public RadioManager(Context context) {
+ mContext = context;
+ }
+}
diff --git a/core/java/android/hardware/radio/RadioMetadata.java b/core/java/android/hardware/radio/RadioMetadata.java
new file mode 100644
index 0000000..8b1851b
--- /dev/null
+++ b/core/java/android/hardware/radio/RadioMetadata.java
@@ -0,0 +1,449 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.hardware.radio;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.content.ContentResolver;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.SparseArray;
+
+import java.util.ArrayList;
+import java.util.Set;
+
+/**
+ * Contains meta data about a radio program such as station name, song title, artist etc...
+ * @hide
+ */
+@SystemApi
+public final class RadioMetadata implements Parcelable {
+ private static final String TAG = "RadioMetadata";
+
+ /**
+ * The RDS Program Information.
+ */
+ public static final String METADATA_KEY_RDS_PI = "android.hardware.radio.metadata.RDS_PI";
+
+ /**
+ * The RDS Program Service.
+ */
+ public static final String METADATA_KEY_RDS_PS = "android.hardware.radio.metadata.RDS_PS";
+
+ /**
+ * The RDS PTY.
+ */
+ public static final String METADATA_KEY_RDS_PTY = "android.hardware.radio.metadata.RDS_PTY";
+
+ /**
+ * The RBDS PTY.
+ */
+ public static final String METADATA_KEY_RBDS_PTY = "android.hardware.radio.metadata.RBDS_PTY";
+
+ /**
+ * The RBDS Radio Text.
+ */
+ public static final String METADATA_KEY_RDS_RT = "android.hardware.radio.metadata.RDS_RT";
+
+ /**
+ * The song title.
+ */
+ public static final String METADATA_KEY_TITLE = "android.hardware.radio.metadata.TITLE";
+
+ /**
+ * The artist name.
+ */
+ public static final String METADATA_KEY_ARTIST = "android.hardware.radio.metadata.ARTIST";
+
+ /**
+ * The album name.
+ */
+ public static final String METADATA_KEY_ALBUM = "android.hardware.radio.metadata.ALBUM";
+
+ /**
+ * The music genre.
+ */
+ public static final String METADATA_KEY_GENRE = "android.hardware.radio.metadata.GENRE";
+
+ /**
+ * The radio station icon {@link Bitmap}.
+ */
+ public static final String METADATA_KEY_ICON = "android.hardware.radio.metadata.ICON";
+
+ /**
+ * The artwork for the song/album {@link Bitmap}.
+ */
+ public static final String METADATA_KEY_ART = "android.hardware.radio.metadata.ART";
+
+
+ private static final int METADATA_TYPE_INVALID = -1;
+ private static final int METADATA_TYPE_INT = 0;
+ private static final int METADATA_TYPE_TEXT = 1;
+ private static final int METADATA_TYPE_BITMAP = 2;
+
+ private static final ArrayMap<String, Integer> METADATA_KEYS_TYPE;
+
+ static {
+ METADATA_KEYS_TYPE = new ArrayMap<String, Integer>();
+ METADATA_KEYS_TYPE.put(METADATA_KEY_RDS_PI, METADATA_TYPE_TEXT);
+ METADATA_KEYS_TYPE.put(METADATA_KEY_RDS_PS, METADATA_TYPE_TEXT);
+ METADATA_KEYS_TYPE.put(METADATA_KEY_RDS_PTY, METADATA_TYPE_INT);
+ METADATA_KEYS_TYPE.put(METADATA_KEY_RBDS_PTY, METADATA_TYPE_INT);
+ METADATA_KEYS_TYPE.put(METADATA_KEY_RDS_RT, METADATA_TYPE_TEXT);
+ METADATA_KEYS_TYPE.put(METADATA_KEY_TITLE, METADATA_TYPE_TEXT);
+ METADATA_KEYS_TYPE.put(METADATA_KEY_ARTIST, METADATA_TYPE_TEXT);
+ METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM, METADATA_TYPE_TEXT);
+ METADATA_KEYS_TYPE.put(METADATA_KEY_GENRE, METADATA_TYPE_TEXT);
+ METADATA_KEYS_TYPE.put(METADATA_KEY_ICON, METADATA_TYPE_BITMAP);
+ METADATA_KEYS_TYPE.put(METADATA_KEY_ART, METADATA_TYPE_BITMAP);
+ }
+
+ // keep in sync with: system/media/radio/include/system/radio_metadata.h
+ private static final int NATIVE_KEY_INVALID = -1;
+ private static final int NATIVE_KEY_RDS_PI = 0;
+ private static final int NATIVE_KEY_RDS_PS = 1;
+ private static final int NATIVE_KEY_RDS_PTY = 2;
+ private static final int NATIVE_KEY_RBDS_PTY = 3;
+ private static final int NATIVE_KEY_RDS_RT = 4;
+ private static final int NATIVE_KEY_TITLE = 5;
+ private static final int NATIVE_KEY_ARTIST = 6;
+ private static final int NATIVE_KEY_ALBUM = 7;
+ private static final int NATIVE_KEY_GENRE = 8;
+ private static final int NATIVE_KEY_ICON = 9;
+ private static final int NATIVE_KEY_ART = 10;
+
+ private static final SparseArray<String> NATIVE_KEY_MAPPING;
+
+ static {
+ NATIVE_KEY_MAPPING = new SparseArray<String>();
+ NATIVE_KEY_MAPPING.put(NATIVE_KEY_RDS_PI, METADATA_KEY_RDS_PI);
+ NATIVE_KEY_MAPPING.put(NATIVE_KEY_RDS_PS, METADATA_KEY_RDS_PS);
+ NATIVE_KEY_MAPPING.put(NATIVE_KEY_RDS_PTY, METADATA_KEY_RDS_PTY);
+ NATIVE_KEY_MAPPING.put(NATIVE_KEY_RBDS_PTY, METADATA_KEY_RBDS_PTY);
+ NATIVE_KEY_MAPPING.put(NATIVE_KEY_RDS_RT, METADATA_KEY_RDS_RT);
+ NATIVE_KEY_MAPPING.put(NATIVE_KEY_TITLE, METADATA_KEY_TITLE);
+ NATIVE_KEY_MAPPING.put(NATIVE_KEY_ARTIST, METADATA_KEY_ARTIST);
+ NATIVE_KEY_MAPPING.put(NATIVE_KEY_ALBUM, METADATA_KEY_ALBUM);
+ NATIVE_KEY_MAPPING.put(NATIVE_KEY_GENRE, METADATA_KEY_GENRE);
+ NATIVE_KEY_MAPPING.put(NATIVE_KEY_ICON, METADATA_KEY_ICON);
+ NATIVE_KEY_MAPPING.put(NATIVE_KEY_ART, METADATA_KEY_ART);
+ }
+
+ private final Bundle mBundle;
+
+ RadioMetadata() {
+ mBundle = new Bundle();
+ }
+
+ private RadioMetadata(Bundle bundle) {
+ mBundle = new Bundle(bundle);
+ }
+
+ private RadioMetadata(Parcel in) {
+ mBundle = in.readBundle();
+ }
+
+ /**
+ * Returns {@code true} if the given key is contained in the meta data
+ *
+ * @param key a String key
+ * @return {@code true} if the key exists in this meta data, {@code false} otherwise
+ */
+ public boolean containsKey(String key) {
+ return mBundle.containsKey(key);
+ }
+
+ /**
+ * Returns the text value associated with the given key as a String, or null
+ * if the key is not found in the meta data.
+ *
+ * @param key The key the value is stored under
+ * @return a String value, or null
+ */
+ public String getString(String key) {
+ return mBundle.getString(key);
+ }
+
+ /**
+ * Returns the value associated with the given key,
+ * or 0 if the key is not found in the meta data.
+ *
+ * @param key The key the value is stored under
+ * @return an int value
+ */
+ public int getInt(String key) {
+ return mBundle.getInt(key, 0);
+ }
+
+ /**
+ * Returns a {@link Bitmap} for the given key or null if the key is not found in the meta data.
+ *
+ * @param key The key the value is stored under
+ * @return a {@link Bitmap} or null
+ */
+ public Bitmap getBitmap(String key) {
+ Bitmap bmp = null;
+ try {
+ bmp = mBundle.getParcelable(key);
+ } catch (Exception e) {
+ // ignore, value was not a bitmap
+ Log.w(TAG, "Failed to retrieve a key as Bitmap.", e);
+ }
+ return bmp;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeBundle(mBundle);
+ }
+
+ /**
+ * Returns the number of fields in this meta data.
+ *
+ * @return the number of fields in the meta data.
+ */
+ public int size() {
+ return mBundle.size();
+ }
+
+ /**
+ * Returns a Set containing the Strings used as keys in this meta data.
+ *
+ * @return a Set of String keys
+ */
+ public Set<String> keySet() {
+ return mBundle.keySet();
+ }
+
+ /**
+ * Helper for getting the String key used by {@link RadioMetadata} from the
+ * corrsponding native integer key.
+ *
+ * @param editorKey The key used by the editor
+ * @return the key used by this class or null if no mapping exists
+ * @hide
+ */
+ public static String getKeyFromNativeKey(int nativeKey) {
+ return NATIVE_KEY_MAPPING.get(nativeKey, null);
+ }
+
+ public static final Parcelable.Creator<RadioMetadata> CREATOR =
+ new Parcelable.Creator<RadioMetadata>() {
+ @Override
+ public RadioMetadata createFromParcel(Parcel in) {
+ return new RadioMetadata(in);
+ }
+
+ @Override
+ public RadioMetadata[] newArray(int size) {
+ return new RadioMetadata[size];
+ }
+ };
+
+ /**
+ * Use to build RadioMetadata objects.
+ */
+ public static final class Builder {
+ private final Bundle mBundle;
+
+ /**
+ * Create an empty Builder. Any field that should be included in the
+ * {@link RadioMetadata} must be added.
+ */
+ public Builder() {
+ mBundle = new Bundle();
+ }
+
+ /**
+ * Create a Builder using a {@link RadioMetadata} instance to set the
+ * initial values. All fields in the source meta data will be included in
+ * the new meta data. Fields can be overwritten by adding the same key.
+ *
+ * @param source
+ */
+ public Builder(RadioMetadata source) {
+ mBundle = new Bundle(source.mBundle);
+ }
+
+ /**
+ * Create a Builder using a {@link RadioMetadata} instance to set
+ * initial values, but replace bitmaps with a scaled down copy if they
+ * are larger than maxBitmapSize.
+ *
+ * @param source The original meta data to copy.
+ * @param maxBitmapSize The maximum height/width for bitmaps contained
+ * in the meta data.
+ * @hide
+ */
+ public Builder(RadioMetadata source, int maxBitmapSize) {
+ this(source);
+ for (String key : mBundle.keySet()) {
+ Object value = mBundle.get(key);
+ if (value != null && value instanceof Bitmap) {
+ Bitmap bmp = (Bitmap) value;
+ if (bmp.getHeight() > maxBitmapSize || bmp.getWidth() > maxBitmapSize) {
+ putBitmap(key, scaleBitmap(bmp, maxBitmapSize));
+ }
+ }
+ }
+ }
+
+ /**
+ * Put a String value into the meta data. Custom keys may be used, but if
+ * the METADATA_KEYs defined in this class are used they may only be one
+ * of the following:
+ * <ul>
+ * <li>{@link #METADATA_KEY_RDS_PI}</li>
+ * <li>{@link #METADATA_KEY_RDS_PS}</li>
+ * <li>{@link #METADATA_KEY_RDS_RT}</li>
+ * <li>{@link #METADATA_KEY_TITLE}</li>
+ * <li>{@link #METADATA_KEY_ARTIST}</li>
+ * <li>{@link #METADATA_KEY_ALBUM}</li>
+ * <li>{@link #METADATA_KEY_GENRE}</li>
+ * </ul>
+ *
+ * @param key The key for referencing this value
+ * @param value The String value to store
+ * @return the same Builder instance
+ */
+ public Builder putString(String key, String value) {
+ if (!METADATA_KEYS_TYPE.containsKey(key) ||
+ METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) {
+ throw new IllegalArgumentException("The " + key
+ + " key cannot be used to put a String");
+ }
+ mBundle.putString(key, value);
+ return this;
+ }
+
+ /**
+ * Put an int value into the meta data. Custom keys may be used, but if
+ * the METADATA_KEYs defined in this class are used they may only be one
+ * of the following:
+ * <ul>
+ * <li>{@link #METADATA_KEY_RDS_PTY}</li>
+ * <li>{@link #METADATA_KEY_RBDS_PTY}</li>
+ * </ul>
+ *
+ * @param key The key for referencing this value
+ * @param value The int value to store
+ * @return the same Builder instance
+ */
+ public Builder putInt(String key, int value) {
+ if (!METADATA_KEYS_TYPE.containsKey(key) ||
+ METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_INT) {
+ throw new IllegalArgumentException("The " + key
+ + " key cannot be used to put a long");
+ }
+ mBundle.putInt(key, value);
+ return this;
+ }
+
+ /**
+ * Put a {@link Bitmap} into the meta data. Custom keys may be used, but
+ * if the METADATA_KEYs defined in this class are used they may only be
+ * one of the following:
+ * <ul>
+ * <li>{@link #METADATA_KEY_ICON}</li>
+ * <li>{@link #METADATA_KEY_ART}</li>
+ * </ul>
+ * <p>
+ *
+ * @param key The key for referencing this value
+ * @param value The Bitmap to store
+ * @return the same Builder instance
+ */
+ public Builder putBitmap(String key, Bitmap value) {
+ if (!METADATA_KEYS_TYPE.containsKey(key) ||
+ METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_BITMAP) {
+ throw new IllegalArgumentException("The " + key
+ + " key cannot be used to put a Bitmap");
+ }
+ mBundle.putParcelable(key, value);
+ return this;
+ }
+
+ /**
+ * Creates a {@link RadioMetadata} instance with the specified fields.
+ *
+ * @return a new {@link RadioMetadata} object
+ */
+ public RadioMetadata build() {
+ return new RadioMetadata(mBundle);
+ }
+
+ private Bitmap scaleBitmap(Bitmap bmp, int maxSize) {
+ float maxSizeF = maxSize;
+ float widthScale = maxSizeF / bmp.getWidth();
+ float heightScale = maxSizeF / bmp.getHeight();
+ float scale = Math.min(widthScale, heightScale);
+ int height = (int) (bmp.getHeight() * scale);
+ int width = (int) (bmp.getWidth() * scale);
+ return Bitmap.createScaledBitmap(bmp, width, height, true);
+ }
+ }
+
+ int putIntFromNative(int nativeKey, int value) {
+ String key = getKeyFromNativeKey(nativeKey);
+ if (!METADATA_KEYS_TYPE.containsKey(key) ||
+ METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_INT) {
+ return -1;
+ }
+ mBundle.putInt(key, value);
+ return 0;
+ }
+
+ int putStringFromNative(int nativeKey, String value) {
+ String key = getKeyFromNativeKey(nativeKey);
+ if (!METADATA_KEYS_TYPE.containsKey(key) ||
+ METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) {
+ return -1;
+ }
+ mBundle.putString(key, value);
+ return 0;
+ }
+
+ int putBitmapFromNative(int nativeKey, byte[] value) {
+ String key = getKeyFromNativeKey(nativeKey);
+ if (!METADATA_KEYS_TYPE.containsKey(key) ||
+ METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_BITMAP) {
+ return -1;
+ }
+ Bitmap bmp = null;
+ try {
+ bmp = BitmapFactory.decodeByteArray(value, 0, value.length);
+ } catch (Exception e) {
+ } finally {
+ if (bmp == null) {
+ return -1;
+ }
+ mBundle.putParcelable(key, bmp);
+ return 0;
+ }
+ }
+}
diff --git a/core/java/android/hardware/radio/RadioModule.java b/core/java/android/hardware/radio/RadioModule.java
new file mode 100644
index 0000000..15916ae
--- /dev/null
+++ b/core/java/android/hardware/radio/RadioModule.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.hardware.radio;
+
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import java.lang.ref.WeakReference;
+import java.util.UUID;
+
+/**
+ * A RadioModule implements the RadioTuner interface for a broadcast radio tuner physically
+ * present on the device and exposed by the radio HAL.
+ *
+ * @hide
+ */
+public class RadioModule extends RadioTuner {
+ private long mNativeContext = 0;
+ private int mId;
+ private NativeEventHandlerDelegate mEventHandlerDelegate;
+
+ RadioModule(int moduleId, RadioManager.BandConfig config, boolean withAudio,
+ RadioTuner.Callback callback, Handler handler) {
+ mId = moduleId;
+ mEventHandlerDelegate = new NativeEventHandlerDelegate(callback, handler);
+ native_setup(new WeakReference<RadioModule>(this), config, withAudio);
+ }
+ private native void native_setup(Object module_this,
+ RadioManager.BandConfig config, boolean withAudio);
+
+ @Override
+ protected void finalize() {
+ native_finalize();
+ }
+ private native void native_finalize();
+
+ boolean initCheck() {
+ return mNativeContext != 0;
+ }
+
+ // RadioTuner implementation
+ public native void close();
+
+ public native int setConfiguration(RadioManager.BandConfig config);
+
+ public native int getConfiguration(RadioManager.BandConfig[] config);
+
+ public native int setMute(boolean mute);
+
+ public native boolean getMute();
+
+ public native int step(int direction, boolean skipSubChannel);
+
+ public native int scan(int direction, boolean skipSubChannel);
+
+ public native int tune(int channel, int subChannel);
+
+ public native int cancel();
+
+ public native int getProgramInformation(RadioManager.ProgramInfo[] info);
+
+ public native boolean isAntennaConnected();
+
+ public native boolean hasControl();
+
+
+ /* keep in sync with radio_event_type_t in system/core/include/system/radio.h */
+ static final int EVENT_HW_FAILURE = 0;
+ static final int EVENT_CONFIG = 1;
+ static final int EVENT_ANTENNA = 2;
+ static final int EVENT_TUNED = 3;
+ static final int EVENT_METADATA = 4;
+ static final int EVENT_TA = 5;
+ static final int EVENT_AF_SWITCH = 6;
+ static final int EVENT_CONTROL = 100;
+ static final int EVENT_SERVER_DIED = 101;
+
+ private class NativeEventHandlerDelegate {
+ private final Handler mHandler;
+
+ NativeEventHandlerDelegate(final RadioTuner.Callback callback,
+ Handler handler) {
+ // find the looper for our new event handler
+ Looper looper;
+ if (handler != null) {
+ looper = handler.getLooper();
+ } else {
+ looper = Looper.getMainLooper();
+ }
+
+ // construct the event handler with this looper
+ if (looper != null) {
+ // implement the event handler delegate
+ mHandler = new Handler(looper) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case EVENT_HW_FAILURE:
+ if (callback != null) {
+ callback.onError(RadioTuner.ERROR_HARDWARE_FAILURE);
+ }
+ break;
+ case EVENT_CONFIG: {
+ RadioManager.BandConfig config = (RadioManager.BandConfig)msg.obj;
+ switch(msg.arg1) {
+ case RadioManager.STATUS_OK:
+ if (callback != null) {
+ callback.onConfigurationChanged(config);
+ }
+ break;
+ default:
+ if (callback != null) {
+ callback.onError(RadioTuner.ERROR_CONFIG);
+ }
+ break;
+ }
+ } break;
+ case EVENT_ANTENNA:
+ if (callback != null) {
+ callback.onAntennaState(msg.arg2 == 1);
+ }
+ break;
+ case EVENT_AF_SWITCH:
+ case EVENT_TUNED: {
+ RadioManager.ProgramInfo info = (RadioManager.ProgramInfo)msg.obj;
+ switch (msg.arg1) {
+ case RadioManager.STATUS_OK:
+ if (callback != null) {
+ callback.onProgramInfoChanged(info);
+ }
+ break;
+ case RadioManager.STATUS_TIMED_OUT:
+ if (callback != null) {
+ callback.onError(RadioTuner.ERROR_SCAN_TIMEOUT);
+ }
+ break;
+ case RadioManager.STATUS_INVALID_OPERATION:
+ default:
+ if (callback != null) {
+ callback.onError(RadioTuner.ERROR_CANCELLED);
+ }
+ break;
+ }
+ } break;
+ case EVENT_METADATA: {
+ RadioMetadata metadata = (RadioMetadata)msg.obj;
+ if (callback != null) {
+ callback.onMetadataChanged(metadata);
+ }
+ } break;
+ case EVENT_TA:
+ if (callback != null) {
+ callback.onTrafficAnnouncement(msg.arg2 == 1);
+ }
+ break;
+ case EVENT_CONTROL:
+ if (callback != null) {
+ callback.onControlChanged(msg.arg2 == 1);
+ }
+ break;
+ case EVENT_SERVER_DIED:
+ if (callback != null) {
+ callback.onError(RadioTuner.ERROR_SERVER_DIED);
+ }
+ break;
+ default:
+ // Should not happen
+ break;
+ }
+ }
+ };
+ } else {
+ mHandler = null;
+ }
+ }
+
+ Handler handler() {
+ return mHandler;
+ }
+ }
+
+
+ @SuppressWarnings("unused")
+ private static void postEventFromNative(Object module_ref,
+ int what, int arg1, int arg2, Object obj) {
+ RadioModule module = (RadioModule)((WeakReference)module_ref).get();
+ if (module == null) {
+ return;
+ }
+
+ NativeEventHandlerDelegate delegate = module.mEventHandlerDelegate;
+ if (delegate != null) {
+ Handler handler = delegate.handler();
+ if (handler != null) {
+ Message m = handler.obtainMessage(what, arg1, arg2, obj);
+ handler.sendMessage(m);
+ }
+ }
+ }
+}
+
diff --git a/core/java/android/hardware/radio/RadioTuner.java b/core/java/android/hardware/radio/RadioTuner.java
new file mode 100644
index 0000000..376900a
--- /dev/null
+++ b/core/java/android/hardware/radio/RadioTuner.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.hardware.radio;
+
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import java.lang.ref.WeakReference;
+import java.util.UUID;
+
+/**
+ * RadioTuner interface provides methods to control a radio tuner on the device: selecting and
+ * configuring the active band, muting/unmuting, scanning and tuning, etc...
+ *
+ * Obtain a RadioTuner interface by calling {@link RadioManager#openTuner(int,
+ * RadioManager.BandConfig, boolean, RadioTuner.Callback, Handler)}.
+ * @hide
+ */
+@SystemApi
+public abstract class RadioTuner {
+
+ /** Scanning direction UP for {@link #step(int, boolean)}, {@link #scan(int, boolean)} */
+ public static final int DIRECTION_UP = 0;
+
+ /** Scanning directions DOWN for {@link #step(int, boolean)}, {@link #scan(int, boolean)} */
+ public static final int DIRECTION_DOWN = 1;
+
+ /**
+ * Close the tuner interface. The {@link Callback} callback will not be called
+ * anymore and associated resources will be released.
+ * Must be called when the tuner is not needed to make hardware resources available to others.
+ * */
+ public abstract void close();
+
+ /**
+ * Set the active band configuration for this module.
+ * Must be a valid configuration obtained via buildConfig() from a valid BandDescriptor listed
+ * in the ModuleProperties of the module with the specified ID.
+ * @param config The desired band configuration (FmBandConfig or AmBandConfig).
+ * @return
+ * <ul>
+ * <li>{@link RadioManager#STATUS_OK} in case of success, </li>
+ * <li>{@link RadioManager#STATUS_ERROR} in case of unspecified error, </li>
+ * <li>{@link RadioManager#STATUS_NO_INIT} if the native service cannot be reached, </li>
+ * <li>{@link RadioManager#STATUS_BAD_VALUE} if parameters are invalid, </li>
+ * <li>{@link RadioManager#STATUS_INVALID_OPERATION} if the call is out of sequence, </li>
+ * <li>{@link RadioManager#STATUS_DEAD_OBJECT} if the binder transaction to the native
+ * service fails, </li>
+ * </ul>
+ */
+ public abstract int setConfiguration(RadioManager.BandConfig config);
+
+ /**
+ * Get current configuration.
+ * @param config a BandConfig array of lengh 1 where the configuration is returned.
+ * @return
+ * <ul>
+ * <li>{@link RadioManager#STATUS_OK} in case of success, </li>
+ * <li>{@link RadioManager#STATUS_ERROR} in case of unspecified error, </li>
+ * <li>{@link RadioManager#STATUS_NO_INIT} if the native service cannot be reached, </li>
+ * <li>{@link RadioManager#STATUS_BAD_VALUE} if parameters are invalid, </li>
+ * <li>{@link RadioManager#STATUS_INVALID_OPERATION} if the call is out of sequence, </li>
+ * <li>{@link RadioManager#STATUS_DEAD_OBJECT} if the binder transaction to the native
+ * service fails, </li>
+ * </ul>
+ */
+ public abstract int getConfiguration(RadioManager.BandConfig[] config);
+
+
+ /**
+ * Set mute state. When muted, the radio tuner audio source is not available for playback on
+ * any audio device. when unmuted, the radio tuner audio source is output as a media source
+ * and renderd over the audio device selected for media use case.
+ * The radio tuner audio source is muted by default when the tuner is first attached.
+ * Only effective if the tuner is attached with audio enabled.
+ *
+ * @param mute the requested mute state.
+ * @return
+ * <ul>
+ * <li>{@link RadioManager#STATUS_OK} in case of success, </li>
+ * <li>{@link RadioManager#STATUS_ERROR} in case of unspecified error, </li>
+ * <li>{@link RadioManager#STATUS_NO_INIT} if the native service cannot be reached, </li>
+ * <li>{@link RadioManager#STATUS_INVALID_OPERATION} if the call is out of sequence, </li>
+ * <li>{@link RadioManager#STATUS_DEAD_OBJECT} if the binder transaction to the native
+ * service fails, </li>
+ * </ul>
+ */
+ public abstract int setMute(boolean mute);
+
+ /**
+ * Get mute state.
+ *
+ * @return {@code true} if the radio tuner audio source is muted or a problem occured
+ * retrieving the mute state, {@code false} otherwise.
+ */
+ public abstract boolean getMute();
+
+ /**
+ * Step up or down by one channel spacing.
+ * The operation is asynchronous and {@link Callback}
+ * onProgramInfoChanged() will be called when step completes or
+ * onError() when cancelled or timeout.
+ * @param direction {@link #DIRECTION_UP} or {@link #DIRECTION_DOWN}.
+ * @param skipSubChannel indicates to skip sub channels when the configuration currently
+ * selected supports sub channel (e.g HD Radio). N/A otherwise.
+ * @return
+ * <ul>
+ * <li>{@link RadioManager#STATUS_OK} in case of success, </li>
+ * <li>{@link RadioManager#STATUS_ERROR} in case of unspecified error, </li>
+ * <li>{@link RadioManager#STATUS_NO_INIT} if the native service cannot be reached, </li>
+ * <li>{@link RadioManager#STATUS_BAD_VALUE} if parameters are invalid, </li>
+ * <li>{@link RadioManager#STATUS_INVALID_OPERATION} if the call is out of sequence, </li>
+ * <li>{@link RadioManager#STATUS_DEAD_OBJECT} if the binder transaction to the native
+ * service fails, </li>
+ * </ul>
+ */
+ public abstract int step(int direction, boolean skipSubChannel);
+
+ /**
+ * Scan up or down to next valid station.
+ * The operation is asynchronous and {@link Callback}
+ * onProgramInfoChanged() will be called when scan completes or
+ * onError() when cancelled or timeout.
+ * @param direction {@link #DIRECTION_UP} or {@link #DIRECTION_DOWN}.
+ * @param skipSubChannel indicates to skip sub channels when the configuration currently
+ * selected supports sub channel (e.g HD Radio). N/A otherwise.
+ * @return
+ * <ul>
+ * <li>{@link RadioManager#STATUS_OK} in case of success, </li>
+ * <li>{@link RadioManager#STATUS_ERROR} in case of unspecified error, </li>
+ * <li>{@link RadioManager#STATUS_NO_INIT} if the native service cannot be reached, </li>
+ * <li>{@link RadioManager#STATUS_BAD_VALUE} if parameters are invalid, </li>
+ * <li>{@link RadioManager#STATUS_INVALID_OPERATION} if the call is out of sequence, </li>
+ * <li>{@link RadioManager#STATUS_DEAD_OBJECT} if the binder transaction to the native
+ * service fails, </li>
+ * </ul>
+ */
+ public abstract int scan(int direction, boolean skipSubChannel);
+
+ /**
+ * Tune to a specific frequency.
+ * The operation is asynchronous and {@link Callback}
+ * onProgramInfoChanged() will be called when tune completes or
+ * onError() when cancelled or timeout.
+ * @param channel the specific channel or frequency to tune to.
+ * @param subChannel the specific sub-channel to tune to. N/A if the selected configuration
+ * does not support cub channels.
+ * @return
+ * <ul>
+ * <li>{@link RadioManager#STATUS_OK} in case of success, </li>
+ * <li>{@link RadioManager#STATUS_ERROR} in case of unspecified error, </li>
+ * <li>{@link RadioManager#STATUS_NO_INIT} if the native service cannot be reached, </li>
+ * <li>{@link RadioManager#STATUS_BAD_VALUE} if parameters are invalid, </li>
+ * <li>{@link RadioManager#STATUS_INVALID_OPERATION} if the call is out of sequence, </li>
+ * <li>{@link RadioManager#STATUS_DEAD_OBJECT} if the binder transaction to the native
+ * service fails, </li>
+ * </ul>
+ */
+ public abstract int tune(int channel, int subChannel);
+
+ /**
+ * Cancel a pending scan or tune operation.
+ * If an operation is pending, {@link Callback} onError() will be called with
+ * {@link #ERROR_CANCELLED}.
+ * @return
+ * <ul>
+ * <li>{@link RadioManager#STATUS_OK} in case of success, </li>
+ * <li>{@link RadioManager#STATUS_ERROR} in case of unspecified error, </li>
+ * <li>{@link RadioManager#STATUS_NO_INIT} if the native service cannot be reached, </li>
+ * <li>{@link RadioManager#STATUS_BAD_VALUE} if parameters are invalid, </li>
+ * <li>{@link RadioManager#STATUS_INVALID_OPERATION} if the call is out of sequence, </li>
+ * <li>{@link RadioManager#STATUS_DEAD_OBJECT} if the binder transaction to the native
+ * service fails, </li>
+ * </ul>
+ */
+ public abstract int cancel();
+
+ /**
+ * Get current station information.
+ * @param info a ProgramInfo array of lengh 1 where the information is returned.
+ * @return
+ * <ul>
+ * <li>{@link RadioManager#STATUS_OK} in case of success, </li>
+ * <li>{@link RadioManager#STATUS_ERROR} in case of unspecified error, </li>
+ * <li>{@link RadioManager#STATUS_NO_INIT} if the native service cannot be reached, </li>
+ * <li>{@link RadioManager#STATUS_BAD_VALUE} if parameters are invalid, </li>
+ * <li>{@link RadioManager#STATUS_INVALID_OPERATION} if the call is out of sequence, </li>
+ * <li>{@link RadioManager#STATUS_DEAD_OBJECT} if the binder transaction to the native
+ * service fails, </li>
+ * </ul>
+ */
+ public abstract int getProgramInformation(RadioManager.ProgramInfo[] info);
+
+ /**
+ * Get current antenna connection state for current configuration.
+ * Only valid if a configuration has been applied.
+ * @return {@code true} if the antenna is connected, {@code false} otherwise.
+ */
+ public abstract boolean isAntennaConnected();
+
+ /**
+ * Indicates if this client actually controls the tuner.
+ * Control is always granted after
+ * {@link RadioManager#openTuner(int,
+ * RadioManager.BandConfig, boolean, Callback, Handler)}
+ * returns a non null tuner interface.
+ * Control is lost when another client opens an interface on the same tuner.
+ * When this happens, {@link Callback#onControlChanged(boolean)} is received.
+ * The client can either wait for control to be returned (which is indicated by the same
+ * callback) or close and reopen the tuner interface.
+ * @return {@code true} if this interface controls the tuner,
+ * {@code false} otherwise or if a problem occured retrieving the state.
+ */
+ public abstract boolean hasControl();
+
+ /** Indicates a failure of radio IC or driver.
+ * The application must close and re open the tuner */
+ public static final int ERROR_HARDWARE_FAILURE = 0;
+ /** Indicates a failure of the radio service.
+ * The application must close and re open the tuner */
+ public static final int ERROR_SERVER_DIED = 1;
+ /** A pending seek or tune operation was cancelled */
+ public static final int ERROR_CANCELLED = 2;
+ /** A pending seek or tune operation timed out */
+ public static final int ERROR_SCAN_TIMEOUT = 3;
+ /** The requested configuration could not be applied */
+ public static final int ERROR_CONFIG = 4;
+
+ /**
+ * Callback provided by the client application when opening a {@link RadioTuner}
+ * to receive asynchronous operation results, updates and error notifications.
+ */
+ public static abstract class Callback {
+ /**
+ * onError() is called when an error occured while performing an asynchronous
+ * operation of when the hardware or system service experiences a problem.
+ * status is one of {@link #ERROR_HARDWARE_FAILURE}, {@link #ERROR_SERVER_DIED},
+ * {@link #ERROR_CANCELLED}, {@link #ERROR_SCAN_TIMEOUT},
+ * {@link #ERROR_CONFIG}
+ */
+ public void onError(int status) {}
+ /**
+ * onConfigurationChanged() is called upon successful completion of
+ * {@link RadioManager#openTuner(int, RadioManager.BandConfig, boolean, Callback, Handler)}
+ * or {@link RadioTuner#setConfiguration(RadioManager.BandConfig)}
+ */
+ public void onConfigurationChanged(RadioManager.BandConfig config) {}
+ /**
+ * onProgramInfoChanged() is called upon successful completion of
+ * {@link RadioTuner#step(int, boolean)}, {@link RadioTuner#scan(int, boolean)},
+ * {@link RadioTuner#tune(int, int)} or when a switching to alternate frequency occurs.
+ * Note that if metadata only are updated, {@link #onMetadataChanged(RadioMetadata)} will
+ * be called.
+ */
+ public void onProgramInfoChanged(RadioManager.ProgramInfo info) {}
+ /**
+ * onMetadataChanged() is called when new meta data are received on current program.
+ * Meta data are also received in {@link RadioManager.ProgramInfo} when
+ * {@link #onProgramInfoChanged(RadioManager.ProgramInfo)} is called.
+ */
+ public void onMetadataChanged(RadioMetadata metadata) {}
+ /**
+ * onTrafficAnnouncement() is called when a traffic announcement starts and stops.
+ */
+ public void onTrafficAnnouncement(boolean active) {}
+ /**
+ * onAntennaState() is called when the antenna is connected or disconnected.
+ */
+ public void onAntennaState(boolean connected) {}
+ /**
+ * onControlChanged() is called when the client loses or gains control of the radio tuner.
+ * The control is always granted after a successful call to
+ * {@link RadioManager#openTuner(int, RadioManager.BandConfig, boolean, Callback, Handler)}.
+ * If another client opens the same tuner, onControlChanged() will be called with
+ * control set to {@code false} to indicate loss of control.
+ * At this point, RadioTuner APIs other than getters will return
+ * {@link RadioManager#STATUS_INVALID_OPERATION}.
+ * When the other client releases the tuner, onControlChanged() will be called
+ * with control set to {@code true}.
+ */
+ public void onControlChanged(boolean control) {}
+ }
+
+}
+
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index d2a2997..8003afb 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -56,6 +56,30 @@ public class NetworkUtils {
/**
* Start the DHCP client daemon, in order to have it request addresses
+ * for the named interface. This returns {@code true} if the DHCPv4 daemon
+ * starts, {@code false} otherwise. This call blocks until such time as a
+ * result is available or the default discovery timeout has been reached.
+ * Callers should check {@link #getDhcpResults} to determine whether DHCP
+ * succeeded or failed, and if it succeeded, to fetch the {@link DhcpResults}.
+ * @param interfaceName the name of the interface to configure
+ * @return {@code true} for success, {@code false} for failure
+ */
+ public native static boolean startDhcp(String interfaceName);
+
+ /**
+ * Initiate renewal on the DHCP client daemon for the named interface. This
+ * returns {@code true} if the DHCPv4 daemon has been notified, {@code false}
+ * otherwise. This call blocks until such time as a result is available or
+ * the default renew timeout has been reached. Callers should check
+ * {@link #getDhcpResults} to determine whether DHCP succeeded or failed,
+ * and if it succeeded, to fetch the {@link DhcpResults}.
+ * @param interfaceName the name of the interface to configure
+ * @return {@code true} for success, {@code false} for failure
+ */
+ public native static boolean startDhcpRenew(String interfaceName);
+
+ /**
+ * Start the DHCP client daemon, in order to have it request addresses
* for the named interface, and then configure the interface with those
* addresses. This call blocks until it obtains a result (either success
* or failure) from the daemon.
@@ -64,17 +88,31 @@ public class NetworkUtils {
* the IP address information.
* @return {@code true} for success, {@code false} for failure
*/
- public native static boolean runDhcp(String interfaceName, DhcpResults dhcpResults);
+ public static boolean runDhcp(String interfaceName, DhcpResults dhcpResults) {
+ return startDhcp(interfaceName) && getDhcpResults(interfaceName, dhcpResults);
+ }
/**
- * Initiate renewal on the Dhcp client daemon. This call blocks until it obtains
+ * Initiate renewal on the DHCP client daemon. This call blocks until it obtains
* a result (either success or failure) from the daemon.
* @param interfaceName the name of the interface to configure
* @param dhcpResults if the request succeeds, this object is filled in with
* the IP address information.
* @return {@code true} for success, {@code false} for failure
*/
- public native static boolean runDhcpRenew(String interfaceName, DhcpResults dhcpResults);
+ public static boolean runDhcpRenew(String interfaceName, DhcpResults dhcpResults) {
+ return startDhcpRenew(interfaceName) && getDhcpResults(interfaceName, dhcpResults);
+ }
+
+ /**
+ * Fetch results from the DHCP client daemon. This call returns {@code true} if
+ * if there are results available to be read, {@code false} otherwise.
+ * @param interfaceName the name of the interface to configure
+ * @param dhcpResults if the request succeeds, this object is filled in with
+ * the IP address information.
+ * @return {@code true} for success, {@code false} for failure
+ */
+ public native static boolean getDhcpResults(String interfaceName, DhcpResults dhcpResults);
/**
* Shut down the DHCP client daemon.
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index f0660eb..f93550a 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -178,6 +178,18 @@ interface INetworkManagementService
String[] getDnsForwarders();
/**
+ * Enables unidirectional packet forwarding from {@code fromIface} to
+ * {@code toIface}.
+ */
+ void startInterfaceForwarding(String fromIface, String toIface);
+
+ /**
+ * Disables unidirectional packet forwarding from {@code fromIface} to
+ * {@code toIface}.
+ */
+ void stopInterfaceForwarding(String fromIface, String toIface);
+
+ /**
* Enables Network Address Translation between two interfaces.
* The address and netmask of the external interface is used for
* the NAT'ed network.
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 3d5215b..9d8a1ba 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -1059,6 +1059,21 @@ public final class Parcel {
}
}
+ /**
+ * @hide
+ */
+ public final void writeCharSequenceList(ArrayList<CharSequence> val) {
+ if (val != null) {
+ int N = val.size();
+ writeInt(N);
+ for (int i=0; i<N; i++) {
+ writeCharSequence(val.get(i));
+ }
+ } else {
+ writeInt(-1);
+ }
+ }
+
public final IBinder[] createBinderArray() {
int N = readInt();
if (N >= 0) {
@@ -1828,6 +1843,25 @@ public final class Parcel {
}
/**
+ * Read and return an ArrayList&lt;CharSequence&gt; object from the parcel.
+ * {@hide}
+ */
+ public final ArrayList<CharSequence> readCharSequenceList() {
+ ArrayList<CharSequence> array = null;
+
+ int length = readInt();
+ if (length >= 0) {
+ array = new ArrayList<CharSequence>(length);
+
+ for (int i = 0 ; i < length ; i++) {
+ array.add(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
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index e303f61..de970cb 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -364,6 +364,12 @@ public final class PowerManager {
public static final int GO_TO_SLEEP_REASON_HDMI = 5;
/**
+ * Go to sleep reason code: Going to sleep due to the sleep button being pressed.
+ * @hide
+ */
+ public static final int GO_TO_SLEEP_REASON_SLEEP_BUTTON = 6;
+
+ /**
* Go to sleep flag: Skip dozing state and directly go to full sleep.
* @hide
*/
diff --git a/core/java/android/preference/PreferenceFragment.java b/core/java/android/preference/PreferenceFragment.java
index 29f9ca1..66642de 100644
--- a/core/java/android/preference/PreferenceFragment.java
+++ b/core/java/android/preference/PreferenceFragment.java
@@ -17,6 +17,7 @@
package android.preference;
import android.annotation.Nullable;
+import android.annotation.XmlRes;
import android.app.Activity;
import android.app.Fragment;
import android.content.Intent;
@@ -294,7 +295,7 @@ public abstract class PreferenceFragment extends Fragment implements
*
* @param preferencesResId The XML resource ID to inflate.
*/
- public void addPreferencesFromResource(int preferencesResId) {
+ public void addPreferencesFromResource(@XmlRes int preferencesResId) {
requirePreferenceManager();
setPreferenceScreen(mPreferenceManager.inflateFromResource(getActivity(),
diff --git a/core/java/android/print/PrintDocumentInfo.java b/core/java/android/print/PrintDocumentInfo.java
index e4e753e..44e6410 100644
--- a/core/java/android/print/PrintDocumentInfo.java
+++ b/core/java/android/print/PrintDocumentInfo.java
@@ -212,7 +212,7 @@ public final class PrintDocumentInfo implements Parcelable {
result = prime * result + mContentType;
result = prime * result + mPageCount;
result = prime * result + (int) mDataSize;
- result = prime * result + (int) mDataSize >> 32;
+ result = prime * result + (int) (mDataSize >> 32);
return result;
}
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 7d57233..6517f35 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -454,6 +454,7 @@ public class CallLog {
long start, int duration, Long dataUsage, boolean addForAllUsers) {
final ContentResolver resolver = context.getContentResolver();
int numberPresentation = PRESENTATION_ALLOWED;
+ boolean isHidden = false;
TelecomManager tm = null;
try {
@@ -468,6 +469,12 @@ public class CallLog {
if (address != null) {
accountAddress = address.getSchemeSpecificPart();
}
+ } else {
+ // We could not find the account through telecom. For call log entries that
+ // are added with a phone account which is not registered, we automatically
+ // mark them as hidden. They are unhidden once the account is registered.
+ Log.i(LOG_TAG, "Marking call log entry as hidden.");
+ isHidden = true;
}
}
@@ -513,6 +520,7 @@ public class CallLog {
values.put(PHONE_ACCOUNT_COMPONENT_NAME, accountComponentString);
values.put(PHONE_ACCOUNT_ID, accountId);
values.put(PHONE_ACCOUNT_ADDRESS, accountAddress);
+ values.put(PHONE_ACCOUNT_HIDDEN, Integer.valueOf(isHidden ? 1 : 0));
values.put(NEW, Integer.valueOf(1));
if (callType == MISSED_TYPE) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index cc84932..3813277 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5374,6 +5374,7 @@ public final class Settings {
ACCESSIBILITY_SCRIPT_INJECTION,
BACKUP_AUTO_RESTORE,
ENABLED_ACCESSIBILITY_SERVICES,
+ ENABLED_NOTIFICATION_LISTENERS,
TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
TOUCH_EXPLORATION_ENABLED,
ACCESSIBILITY_ENABLED,
@@ -5398,6 +5399,9 @@ public final class Settings {
WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, // moved to global
WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, // moved to global
WIFI_NUM_OPEN_NETWORKS_KEPT, // moved to global
+ SELECTED_SPELL_CHECKER,
+ SELECTED_SPELL_CHECKER_SUBTYPE,
+ SPELL_CHECKER_ENABLED,
MOUNT_PLAY_NOTIFICATION_SND,
MOUNT_UMS_AUTOSTART,
MOUNT_UMS_PROMPT,
@@ -7146,6 +7150,33 @@ public final class Settings {
public static final String ENHANCED_4G_MODE_ENABLED = "volte_vt_enabled";
/**
+ * Whether WFC is enabled
+ * <p>
+ * Type: int (0 for false, 1 for true)
+ *
+ * @hide
+ */
+ public static final String WFC_IMS_ENABLED = "wfc_ims_enabled";
+
+ /**
+ * WFC Mode.
+ * <p>
+ * Type: int - 2=Wi-Fi preferred, 1=Cellular preferred, 0=Wi-Fi only
+ *
+ * @hide
+ */
+ public static final String WFC_IMS_MODE = "wfc_ims_mode";
+
+ /**
+ * Whether WFC roaming is enabled
+ * <p>
+ * Type: int (0 for false, 1 for true)
+ *
+ * @hide
+ */
+ public static final String WFC_IMS_ROAMING_ENABLED = "wfc_ims_roaming_enabled";
+
+ /**
* Global override to disable VoLTE (independent of user setting)
* <p>
* Type: int (1 for disable VoLTE, 0 to use user configuration)
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index d71ad03..0da4fd5 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -19,10 +19,18 @@ package android.provider;
import android.Manifest;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
import android.content.Intent;
import android.database.ContentObserver;
+import android.database.Cursor;
import android.net.Uri;
import android.provider.CallLog.Calls;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.Voicemail;
+
+import java.util.List;
/**
* The contract between the voicemail provider and applications. Contains
@@ -199,13 +207,100 @@ public class VoicemailContract {
*/
public static final String _DATA = "_data";
+ // Note: PHONE_ACCOUNT_* constant values are "subscription_*" due to a historic naming
+ // that was encoded into call log databases.
+
+ /**
+ * The component name of the account in string form.
+ * <P>Type: TEXT</P>
+ */
+ public static final String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name";
+
+ /**
+ * The identifier of a account that is unique to a specified component.
+ * <P>Type: TEXT</P>
+ */
+ public static final String PHONE_ACCOUNT_ID = "subscription_id";
+
+ /**
+ * Flag used to indicate that local, unsynced changes are present.
+ * Currently, this is used to indicate that the voicemail was read or deleted.
+ * The value will be 1 if dirty is true, 0 if false.
+ * <P>Type: INTEGER (boolean)</P>
+ */
+ public static final String DIRTY = "dirty";
+
+ /**
+ * Flag used to indicate that the voicemail was deleted but not synced to the server.
+ * A deleted row should be ignored.
+ * The value will be 1 if deleted is true, 0 if false.
+ * <P>Type: INTEGER (boolean)</P>
+ */
+ public static final String DELETED = "deleted";
+
/**
* A convenience method to build voicemail URI specific to a source package by appending
* {@link VoicemailContract#PARAM_KEY_SOURCE_PACKAGE} param to the base URI.
*/
public static Uri buildSourceUri(String packageName) {
return Voicemails.CONTENT_URI.buildUpon()
- .appendQueryParameter(PARAM_KEY_SOURCE_PACKAGE, packageName).build();
+ .appendQueryParameter(PARAM_KEY_SOURCE_PACKAGE, packageName)
+ .build();
+ }
+
+ /**
+ * Inserts a new voicemail into the voicemail content provider.
+ *
+ * @param context The context of the app doing the inserting
+ * @param voicemail Data to be inserted
+ * @return {@link Uri} of the newly inserted {@link Voicemail}
+ */
+ public static Uri insert(Context context, Voicemail voicemail) {
+ ContentResolver contentResolver = context.getContentResolver();
+ ContentValues contentValues = getContentValues(voicemail);
+ return contentResolver.insert(Voicemails.CONTENT_URI, contentValues);
+ }
+
+ /**
+ * Inserts a list of voicemails into the voicemail content provider.
+ *
+ * @param context The context of the app doing the inserting
+ * @param voicemails Data to be inserted
+ * @return the number of voicemails inserted
+ */
+ public static int insert(Context context, List<Voicemail> voicemails) {
+ ContentResolver contentResolver = context.getContentResolver();
+ int count = voicemails.size();
+ for (int i = 0; i < count; i++) {
+ ContentValues contentValues = getContentValues(voicemails.get(i));
+ contentResolver.insert(Voicemails.CONTENT_URI, contentValues);
+ }
+ return count;
+ }
+
+ /**
+ * Clears all voicemails accessible to this voicemail content provider for the calling
+ * package. By default, a package only has permission to delete voicemails it inserted.
+ *
+ * @return the number of voicemails deleted
+ */
+ public static int deleteAll(Context context) {
+ return context.getContentResolver().delete(
+ buildSourceUri(context.getPackageName()), "", new String[0]);
+ }
+
+ /**
+ * Maps structured {@link Voicemail} to {@link ContentValues} in content provider.
+ */
+ private static ContentValues getContentValues(Voicemail voicemail) {
+ ContentValues contentValues = new ContentValues();
+ contentValues.put(Voicemails.DATE, String.valueOf(voicemail.getTimestampMillis()));
+ contentValues.put(Voicemails.NUMBER, voicemail.getNumber());
+ contentValues.put(Voicemails.DURATION, String.valueOf(voicemail.getDuration()));
+ contentValues.put(Voicemails.SOURCE_PACKAGE, voicemail.getSourcePackage());
+ contentValues.put(Voicemails.SOURCE_DATA, voicemail.getSourceData());
+ contentValues.put(Voicemails.IS_READ, voicemail.isRead() ? 1 : 0);
+ return contentValues;
}
}
@@ -222,10 +317,27 @@ public class VoicemailContract {
private Status() {
}
/**
- * The package name of the voicemail source. There can only be a one entry per source.
+ * The package name of the voicemail source. There can only be a one entry per account
+ * per source.
* <P>Type: TEXT</P>
*/
public static final String SOURCE_PACKAGE = SOURCE_PACKAGE_FIELD;
+
+ // Note: Multiple entries may exist for a single source if they are differentiated by the
+ // PHONE_ACCOUNT_* fields.
+
+ /**
+ * The component name of the account in string form.
+ * <P>Type: TEXT</P>
+ */
+ public static final String PHONE_ACCOUNT_COMPONENT_NAME = "phone_account_component_name";
+
+ /**
+ * The identifier of a account that is unique to a specified component.
+ * <P>Type: TEXT</P>
+ */
+ public static final String PHONE_ACCOUNT_ID = "phone_account_id";
+
/**
* The URI to call to invoke source specific voicemail settings screen. On a user request
* to setup voicemail an intent with action VIEW with this URI will be fired by the system.
@@ -318,5 +430,50 @@ public class VoicemailContract {
return Status.CONTENT_URI.buildUpon()
.appendQueryParameter(PARAM_KEY_SOURCE_PACKAGE, packageName).build();
}
+
+ /**
+ * A helper method to set the status of a voicemail source.
+ *
+ * @param context The context from the package calling the method. This will be the source.
+ * @param accountHandle The handle for the account the source is associated with.
+ * @param configurationState See {@link Status#CONFIGURATION_STATE}
+ * @param dataChannelState See {@link Status#DATA_CHANNEL_STATE}
+ * @param notificationChannelState See {@link Status#NOTIFICATION_CHANNEL_STATE}
+ */
+ public static void setStatus(Context context, PhoneAccountHandle accountHandle,
+ int configurationState, int dataChannelState, int notificationChannelState) {
+ ContentResolver contentResolver = context.getContentResolver();
+ Uri statusUri = buildSourceUri(context.getPackageName());
+ ContentValues values = new ContentValues();
+ values.put(Status.PHONE_ACCOUNT_COMPONENT_NAME,
+ accountHandle.getComponentName().toString());
+ values.put(Status.PHONE_ACCOUNT_ID, accountHandle.getId());
+ values.put(Status.CONFIGURATION_STATE, configurationState);
+ values.put(Status.DATA_CHANNEL_STATE, dataChannelState);
+ values.put(Status.NOTIFICATION_CHANNEL_STATE, notificationChannelState);
+
+ if (isStatusPresent(contentResolver, statusUri)) {
+ contentResolver.update(statusUri, values, null, null);
+ } else {
+ contentResolver.insert(statusUri, values);
+ }
+ }
+
+ /**
+ * Determines if a voicemail source exists in the status table.
+ *
+ * @param contentResolver A content resolver constructed from the appropriate context.
+ * @param statusUri The content uri for the source.
+ * @return {@code true} if a status entry for this source exists
+ */
+ private static boolean isStatusPresent(ContentResolver contentResolver, Uri statusUri) {
+ Cursor cursor = null;
+ try {
+ cursor = contentResolver.query(statusUri, null, null, null, null);
+ return cursor != null && cursor.getCount() != 0;
+ } finally {
+ if (cursor != null) cursor.close();
+ }
+ }
}
}
diff --git a/core/java/android/service/voice/IVoiceInteractionSession.aidl b/core/java/android/service/voice/IVoiceInteractionSession.aidl
index 797457a..4f4b2d5 100644
--- a/core/java/android/service/voice/IVoiceInteractionSession.aidl
+++ b/core/java/android/service/voice/IVoiceInteractionSession.aidl
@@ -17,6 +17,7 @@
package android.service.voice;
import android.content.Intent;
+import android.graphics.Bitmap;
import android.os.Bundle;
/**
@@ -26,6 +27,7 @@ oneway interface IVoiceInteractionSession {
void show(in Bundle sessionArgs, int flags);
void hide();
void handleAssist(in Bundle assistData);
+ void handleScreenshot(in Bitmap screenshot);
void taskStarted(in Intent intent, int taskId);
void taskFinished(in Intent intent, int taskId);
void closeSystemDialogs();
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index 0c01b25..419b92b 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -71,11 +71,17 @@ public class VoiceInteractionService extends Service {
public static final String SERVICE_META_DATA = "android.voice_interaction";
/**
- * Flag for use with {@link #showSession: request that the session be started with
+ * Flag for use with {@link #showSession}: request that the session be started with
* assist data from the currently focused activity.
*/
public static final int START_WITH_ASSIST = 1<<0;
+ /**
+ * Flag for use with {@link #showSession}: request that the session be started with
+ * a screen shot of the currently focused activity.
+ */
+ public static final int START_WITH_SCREENSHOT = 1<<1;
+
IVoiceInteractionService mInterface = new IVoiceInteractionService.Stub() {
@Override public void ready() {
mHandler.sendEmptyMessage(MSG_READY);
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 4cf0e4c..7a5bb90 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -18,9 +18,11 @@ package android.service.voice;
import android.app.Dialog;
import android.app.Instrumentation;
+import android.app.VoiceInteractor;
import android.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
+import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.Region;
import android.inputmethodservice.SoftInputWindow;
@@ -105,6 +107,17 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
}
@Override
+ public IVoiceInteractorRequest startPickOption(String callingPackage,
+ IVoiceInteractorCallback callback, CharSequence prompt,
+ VoiceInteractor.PickOptionRequest.Option[] options, Bundle extras) {
+ Request request = newRequest(callback);
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOOO(MSG_START_PICK_OPTION,
+ new Caller(callingPackage, Binder.getCallingUid()), request,
+ prompt, options, extras));
+ return request.mInterface;
+ }
+
+ @Override
public IVoiceInteractorRequest startCompleteVoice(String callingPackage,
IVoiceInteractorCallback callback, CharSequence message, Bundle extras) {
Request request = newRequest(callback);
@@ -167,6 +180,12 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
}
@Override
+ public void handleScreenshot(Bitmap screenshot) {
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_HANDLE_SCREENSHOT,
+ screenshot));
+ }
+
+ @Override
public void taskStarted(Intent intent, int taskId) {
mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIO(MSG_TASK_STARTED,
taskId, intent));
@@ -232,6 +251,20 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
}
}
+ public void sendPickOptionResult(boolean finished,
+ VoiceInteractor.PickOptionRequest.Option[] selections, Bundle result) {
+ try {
+ if (DEBUG) Log.d(TAG, "sendPickOptionResult: req=" + mInterface
+ + " finished=" + finished + " selections=" + selections
+ + " result=" + result);
+ if (finished) {
+ finishRequest();
+ }
+ mCallback.deliverPickOptionResult(mInterface, finished, selections, result);
+ } catch (RemoteException e) {
+ }
+ }
+
public void sendCompleteVoiceResult(Bundle result) {
try {
if (DEBUG) Log.d(TAG, "sendCompleteVoiceResult: req=" + mInterface
@@ -252,12 +285,14 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
}
}
- public void sendCommandResult(boolean complete, Bundle result) {
+ public void sendCommandResult(boolean finished, Bundle result) {
try {
if (DEBUG) Log.d(TAG, "sendCommandResult: req=" + mInterface
+ " result=" + result);
- finishRequest();
- mCallback.deliverCommandResult(mInterface, complete, result);
+ if (finished) {
+ finishRequest();
+ }
+ mCallback.deliverCommandResult(mInterface, finished, result);
} catch (RemoteException e) {
}
}
@@ -283,19 +318,21 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
}
static final int MSG_START_CONFIRMATION = 1;
- static final int MSG_START_COMPLETE_VOICE = 2;
- static final int MSG_START_ABORT_VOICE = 3;
- static final int MSG_START_COMMAND = 4;
- static final int MSG_SUPPORTS_COMMANDS = 5;
- static final int MSG_CANCEL = 6;
+ static final int MSG_START_PICK_OPTION = 2;
+ static final int MSG_START_COMPLETE_VOICE = 3;
+ static final int MSG_START_ABORT_VOICE = 4;
+ static final int MSG_START_COMMAND = 5;
+ static final int MSG_SUPPORTS_COMMANDS = 6;
+ static final int MSG_CANCEL = 7;
static final int MSG_TASK_STARTED = 100;
static final int MSG_TASK_FINISHED = 101;
static final int MSG_CLOSE_SYSTEM_DIALOGS = 102;
static final int MSG_DESTROY = 103;
static final int MSG_HANDLE_ASSIST = 104;
- static final int MSG_SHOW = 105;
- static final int MSG_HIDE = 106;
+ static final int MSG_HANDLE_SCREENSHOT = 105;
+ static final int MSG_SHOW = 106;
+ static final int MSG_HIDE = 107;
class MyCallbacks implements HandlerCaller.Callback, SoftInputWindow.Callback {
@Override
@@ -309,6 +346,15 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
onConfirm((Caller)args.arg1, (Request)args.arg2, (CharSequence)args.arg3,
(Bundle)args.arg4);
break;
+ case MSG_START_PICK_OPTION:
+ args = (SomeArgs)msg.obj;
+ if (DEBUG) Log.d(TAG, "onPickOption: req=" + ((Request) args.arg2).mInterface
+ + " prompt=" + args.arg3 + " options=" + args.arg4
+ + " extras=" + args.arg5);
+ onPickOption((Caller)args.arg1, (Request)args.arg2, (CharSequence)args.arg3,
+ (VoiceInteractor.PickOptionRequest.Option[])args.arg4,
+ (Bundle)args.arg5);
+ break;
case MSG_START_COMPLETE_VOICE:
args = (SomeArgs)msg.obj;
if (DEBUG) Log.d(TAG, "onCompleteVoice: req=" + ((Request) args.arg2).mInterface
@@ -358,9 +404,13 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
doDestroy();
break;
case MSG_HANDLE_ASSIST:
- if (DEBUG) Log.d(TAG, "onHandleAssist: " + (Bundle)msg.obj);
+ if (DEBUG) Log.d(TAG, "onHandleAssist: " + msg.obj);
onHandleAssist((Bundle) msg.obj);
break;
+ case MSG_HANDLE_SCREENSHOT:
+ if (DEBUG) Log.d(TAG, "onHandleScreenshot: " + msg.obj);
+ onHandleScreenshot((Bitmap) msg.obj);
+ break;
case MSG_SHOW:
if (DEBUG) Log.d(TAG, "doShow: args=" + msg.obj
+ " flags=" + msg.arg1);
@@ -614,6 +664,26 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
}
/**
+ * Set whether this session will keep the device awake while it is running a voice
+ * activity. By default, the system holds a wake lock for it while in this state,
+ * so that it can work even if the screen is off. Setting this to false removes that
+ * wake lock, allowing the CPU to go to sleep. This is typically used if the
+ * session decides it has been waiting too long for a response from the user and
+ * doesn't want to let this continue to drain the battery.
+ *
+ * <p>Passing false here will release the wake lock, and you can call later with
+ * true to re-acquire it. It will also be automatically re-acquired for you each
+ * time you start a new voice activity task -- that is when you call
+ * {@link #startVoiceActivity}.</p>
+ */
+ public void setKeepAwake(boolean keepAwake) {
+ try {
+ mSystemService.setKeepAwake(mToken, keepAwake);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
* Convenience for inflating views.
*/
public LayoutInflater getLayoutInflater() {
@@ -710,6 +780,9 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
public void onHandleAssist(Bundle assistBundle) {
}
+ public void onHandleScreenshot(Bitmap screenshot) {
+ }
+
public boolean onKeyDown(int keyCode, KeyEvent event) {
return false;
}
@@ -814,6 +887,22 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
Bundle extras);
/**
+ * Request for the user to pick one of N options, corresponding to a
+ * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}.
+ *
+ * @param caller Who is making the request.
+ * @param request The active request.
+ * @param prompt The prompt informing the user of what they are picking, as per
+ * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}.
+ * @param options The set of options the user is picking from, as per
+ * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}.
+ * @param extras Any additional information, as per
+ * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}.
+ */
+ public abstract void onPickOption(Caller caller, Request request, CharSequence prompt,
+ VoiceInteractor.PickOptionRequest.Option[] options, Bundle extras);
+
+ /**
* Request to complete the voice interaction session because the voice activity successfully
* completed its interaction using voice. Corresponds to
* {@link android.app.VoiceInteractor.CompleteVoiceRequest
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 668e028..13fb657 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -918,7 +918,7 @@ public class TextToSpeech {
*
* @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
*/
- public int addSpeech(CharSequence text, String packagename, int resourceId) {
+ public int addSpeech(CharSequence text, String packagename, @RawRes int resourceId) {
synchronized (mStartLock) {
mUtterances.put(text, makeResourceUri(packagename, resourceId));
return SUCCESS;
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index 8e9eb48..c119277 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -525,10 +525,6 @@ public class Linkify {
return 0;
}
-
- public final boolean equals(Object o) {
- return false;
- }
};
Collections.sort(links, c);
diff --git a/core/java/android/transition/TransitionInflater.java b/core/java/android/transition/TransitionInflater.java
index 9009d6a..a7d9503 100644
--- a/core/java/android/transition/TransitionInflater.java
+++ b/core/java/android/transition/TransitionInflater.java
@@ -16,6 +16,7 @@
package android.transition;
+import android.annotation.TransitionRes;
import com.android.internal.R;
import org.xmlpull.v1.XmlPullParser;
@@ -71,7 +72,8 @@ public class TransitionInflater {
* @throws android.content.res.Resources.NotFoundException when the
* transition cannot be loaded
*/
- public Transition inflateTransition(int resource) {
+ public Transition inflateTransition(@TransitionRes int resource) {
+ //noinspection ResourceType
XmlResourceParser parser = mContext.getResources().getXml(resource);
try {
return createTransitionFromXml(parser, Xml.asAttributeSet(parser), null);
@@ -98,7 +100,9 @@ public class TransitionInflater {
* @throws android.content.res.Resources.NotFoundException when the
* transition manager cannot be loaded
*/
- public TransitionManager inflateTransitionManager(int resource, ViewGroup sceneRoot) {
+ public TransitionManager inflateTransitionManager(@TransitionRes int resource,
+ ViewGroup sceneRoot) {
+ //noinspection ResourceType
XmlResourceParser parser = mContext.getResources().getXml(resource);
try {
return createTransitionManagerFromXml(parser, Xml.asAttributeSet(parser), sceneRoot);
diff --git a/core/java/android/util/PathParser.java b/core/java/android/util/PathParser.java
index 92b19be..18dc262 100644
--- a/core/java/android/util/PathParser.java
+++ b/core/java/android/util/PathParser.java
@@ -164,7 +164,7 @@ public class PathParser {
* @return array of floats
*/
private static float[] getFloats(String s) {
- if (s.charAt(0) == 'z' | s.charAt(0) == 'Z') {
+ if (s.charAt(0) == 'z' || s.charAt(0) == 'Z') {
return new float[0];
}
try {
diff --git a/core/java/android/view/ActionMode.java b/core/java/android/view/ActionMode.java
index a018138..9f202a9 100644
--- a/core/java/android/view/ActionMode.java
+++ b/core/java/android/view/ActionMode.java
@@ -18,6 +18,7 @@ package android.view;
import android.annotation.StringRes;
+import android.graphics.Rect;
/**
* Represents a contextual mode of the user interface. Action modes can be used to provide
@@ -197,6 +198,15 @@ public abstract class ActionMode {
public abstract void invalidate();
/**
+ * Invalidate the content rect associated to this ActionMode. This only makes sense for
+ * action modes that support dynamic positioning on the screen, and provides a more efficient
+ * way to reposition it without invalidating the whole action mode.
+ *
+ * @see Callback2#onGetContentRect(ActionMode, View, Rect) .
+ */
+ public void invalidateContentRect() {}
+
+ /**
* Finish and close this action mode. The action mode's {@link ActionMode.Callback} will
* have its {@link Callback#onDestroyActionMode(ActionMode)} method called.
*/
@@ -298,4 +308,31 @@ public abstract class ActionMode {
*/
public void onDestroyActionMode(ActionMode mode);
}
-} \ No newline at end of file
+
+ /**
+ * Extension of {@link ActionMode.Callback} to provide content rect information. This is
+ * required for ActionModes with dynamic positioning such as the ones with type
+ * {@link ActionMode#TYPE_FLOATING} to ensure the positioning doesn't obscure app content. If
+ * an app fails to provide a subclass of this class, a default implementation will be used.
+ */
+ public static abstract class Callback2 implements ActionMode.Callback {
+
+ /**
+ * Called when an ActionMode needs to be positioned on screen, potentially occluding view
+ * content. Note this may be called on a per-frame basis.
+ *
+ * @param mode The ActionMode that requires positioning.
+ * @param view The View that originated the ActionMode, in whose coordinates the Rect should
+ * be provided.
+ * @param outRect The Rect to be populated with the content position.
+ */
+ public void onGetContentRect(ActionMode mode, View view, Rect outRect) {
+ if (view != null) {
+ outRect.set(0, 0, view.getWidth(), view.getHeight());
+ } else {
+ outRect.set(0, 0, 0, 0);
+ }
+ }
+
+ }
+}
diff --git a/core/java/android/view/ContextThemeWrapper.java b/core/java/android/view/ContextThemeWrapper.java
index d9f6054..9047b1d 100644
--- a/core/java/android/view/ContextThemeWrapper.java
+++ b/core/java/android/view/ContextThemeWrapper.java
@@ -16,6 +16,7 @@
package android.view;
+import android.annotation.StyleRes;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Configuration;
@@ -36,7 +37,7 @@ public class ContextThemeWrapper extends ContextWrapper {
super(null);
}
- public ContextThemeWrapper(Context base, int themeResId) {
+ public ContextThemeWrapper(Context base, @StyleRes int themeResId) {
super(base);
mThemeResource = themeResId;
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 8ac8bc5..d6625c8 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -16,6 +16,7 @@
package android.view;
+import com.android.internal.app.IAssistScreenshotReceiver;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
@@ -220,10 +221,14 @@ interface IWindowManager
boolean isRotationFrozen();
/**
+ * Used only for assist -- request a screenshot of the current application.
+ */
+ boolean requestAssistScreenshot(IAssistScreenshotReceiver receiver);
+
+ /**
* Create a screenshot of the applications currently displayed.
*/
- Bitmap screenshotApplications(IBinder appToken, int displayId, int maxWidth,
- int maxHeight, boolean force565);
+ Bitmap screenshotApplications(IBinder appToken, int displayId, int maxWidth, int maxHeight);
/**
* Called by the status bar to notify Views of changes to System UI visiblity.
diff --git a/core/java/android/view/PhoneWindow.java b/core/java/android/view/PhoneWindow.java
index 8aef18a..543021e 100644
--- a/core/java/android/view/PhoneWindow.java
+++ b/core/java/android/view/PhoneWindow.java
@@ -1759,7 +1759,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
} else {
MediaSessionLegacyHelper.getHelper(getContext()).sendAdjustVolumeBy(
mVolumeControlStreamType, direction,
- AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE);
+ AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE
+ | AudioManager.FLAG_FROM_KEY);
}
return true;
}
@@ -1837,15 +1838,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN: {
+ final int flags = AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE
+ | AudioManager.FLAG_FROM_KEY;
// If we have a session send it the volume command, otherwise
// use the suggested stream.
if (mMediaController != null) {
- mMediaController.adjustVolume(0, AudioManager.FLAG_PLAY_SOUND
- | AudioManager.FLAG_VIBRATE);
+ mMediaController.adjustVolume(0, flags);
} else {
MediaSessionLegacyHelper.getHelper(getContext()).sendAdjustVolumeBy(
- mVolumeControlStreamType, 0,
- AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE);
+ mVolumeControlStreamType, 0, flags);
}
return true;
}
@@ -2669,17 +2670,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
@Override
public ActionMode startActionModeForChild(View originalView,
ActionMode.Callback callback) {
- // originalView can be used here to be sure that we don't obscure
- // relevant content with the context mode UI.
- return startActionMode(callback);
+ return startActionModeForChild(originalView, callback, ActionMode.TYPE_PRIMARY);
}
@Override
public ActionMode startActionModeForChild(
View child, ActionMode.Callback callback, int type) {
- // originalView can be used here to be sure that we don't obscure
- // relevant content with the context mode UI.
- return startActionMode(callback, type);
+ return startActionMode(child, callback, type);
}
@Override
@@ -2689,7 +2686,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
@Override
public ActionMode startActionMode(ActionMode.Callback callback, int type) {
- ActionMode.Callback wrappedCallback = new ActionModeCallbackWrapper(callback);
+ return startActionMode(this, callback, type);
+ }
+
+ private ActionMode startActionMode(
+ View originatingView, ActionMode.Callback callback, int type) {
+ ActionMode.Callback2 wrappedCallback = new ActionModeCallback2Wrapper(callback);
ActionMode mode = null;
if (getCallback() != null && !isDestroyed()) {
try {
@@ -3291,12 +3293,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
/**
- * Clears out internal reference when the action mode is destroyed.
+ * Clears out internal references when the action mode is destroyed.
*/
- private class ActionModeCallbackWrapper implements ActionMode.Callback {
- private ActionMode.Callback mWrapped;
+ private class ActionModeCallback2Wrapper extends ActionMode.Callback2 {
+ private final ActionMode.Callback mWrapped;
- public ActionModeCallbackWrapper(ActionMode.Callback wrapped) {
+ public ActionModeCallback2Wrapper(ActionMode.Callback wrapped) {
mWrapped = wrapped;
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3927096..d345bed 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -24,6 +24,7 @@ import android.annotation.DrawableRes;
import android.annotation.FloatRange;
import android.annotation.IdRes;
import android.annotation.IntDef;
+import android.annotation.LayoutRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Size;
@@ -18646,7 +18647,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* layout_* parameters.
* @see LayoutInflater
*/
- public static View inflate(Context context, int resource, ViewGroup root) {
+ public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) {
LayoutInflater factory = LayoutInflater.from(context);
return factory.inflate(resource, root);
}
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index f36fd5a..9a92932 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -22,6 +22,7 @@ import android.annotation.IdRes;
import android.annotation.LayoutRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.StyleRes;
import android.annotation.SystemApi;
import android.content.Context;
import android.content.res.Configuration;
@@ -753,7 +754,7 @@ public abstract class Window {
* 0 here will override the animations the window would
* normally retrieve from its theme.
*/
- public void setWindowAnimations(int resId) {
+ public void setWindowAnimations(@StyleRes int resId) {
final WindowManager.LayoutParams attrs = getAttributes();
attrs.windowAnimations = resId;
dispatchWindowAttributesChanged(attrs);
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 905d6d7..66dae7b 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1989,7 +1989,8 @@ public interface WindowManager extends ViewManager {
if (userActivityTimeout >= 0) {
sb.append(" userActivityTimeout=").append(userActivityTimeout);
}
- if (!surfaceInsets.equals(Insets.NONE) || hasManualSurfaceInsets) {
+ if (surfaceInsets.left != 0 || surfaceInsets.top != 0 || surfaceInsets.right != 0 ||
+ surfaceInsets.bottom != 0 || hasManualSurfaceInsets) {
sb.append(" surfaceInsets=").append(surfaceInsets);
if (hasManualSurfaceInsets) {
sb.append(" (manual)");
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index e1942be..a75e8a7 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -573,7 +573,7 @@ public final class AccessibilityWindowInfo implements Parcelable {
if (other.mType != mType) {
throw new IllegalArgumentException("Not same type.");
}
- if (!mBoundsInScreen.equals(mBoundsInScreen)) {
+ if (!mBoundsInScreen.equals(other.mBoundsInScreen)) {
return true;
}
if (mLayer != other.mLayer) {
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index a5524d8..be43952 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -17,6 +17,7 @@
package android.view.animation;
import android.annotation.ColorInt;
+import android.annotation.InterpolatorRes;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.RectF;
@@ -388,7 +389,7 @@ public abstract class Animation implements Cloneable {
* @param resID The resource identifier of the interpolator to load
* @attr ref android.R.styleable#Animation_interpolator
*/
- public void setInterpolator(Context context, int resID) {
+ public void setInterpolator(Context context, @InterpolatorRes int resID) {
setInterpolator(AnimationUtils.loadInterpolator(context, resID));
}
diff --git a/core/java/android/view/animation/LayoutAnimationController.java b/core/java/android/view/animation/LayoutAnimationController.java
index 882e738..df2f18c 100644
--- a/core/java/android/view/animation/LayoutAnimationController.java
+++ b/core/java/android/view/animation/LayoutAnimationController.java
@@ -16,6 +16,8 @@
package android.view.animation;
+import android.annotation.AnimRes;
+import android.annotation.InterpolatorRes;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
@@ -180,7 +182,7 @@ public class LayoutAnimationController {
*
* @attr ref android.R.styleable#LayoutAnimation_animation
*/
- public void setAnimation(Context context, int resourceID) {
+ public void setAnimation(Context context, @AnimRes int resourceID) {
setAnimation(AnimationUtils.loadAnimation(context, resourceID));
}
@@ -225,7 +227,7 @@ public class LayoutAnimationController {
*
* @attr ref android.R.styleable#LayoutAnimation_interpolator
*/
- public void setInterpolator(Context context, int resourceID) {
+ public void setInterpolator(Context context, @InterpolatorRes int resourceID) {
setInterpolator(AnimationUtils.loadInterpolator(context, resourceID));
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 67ad642..6711a6b 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -364,6 +364,20 @@ public class WebView extends AbsoluteLayout
}
/**
+ * Callback interface supplied to {@link #insertVisualStateCallback} for receiving
+ * notifications about the visual state.
+ */
+ public static abstract class VisualStateCallback {
+ /**
+ * Invoked when the visual state is ready to be drawn in the next {@link #onDraw}.
+ *
+ * @param requestId the id supplied to the corresponding {@link #insertVisualStateCallback}
+ * request
+ */
+ public abstract void onComplete(long requestId);
+ }
+
+ /**
* Interface to listen for new pictures as they change.
*
* @deprecated This interface is now obsolete.
@@ -1144,6 +1158,60 @@ public class WebView extends AbsoluteLayout
}
/**
+ * Inserts a {@link VisualStateCallback}.
+ *
+ * <p>Updates to the the DOM are reflected asynchronously such that when the DOM is updated the
+ * subsequent {@link WebView#onDraw} invocation might not reflect those updates. The
+ * {@link VisualStateCallback} provides a mechanism to notify the caller when the contents of
+ * the DOM at the current time are ready to be drawn the next time the {@link WebView} draws.
+ * By current time we mean the time at which this API was called. The next draw after the
+ * callback completes is guaranteed to reflect all the updates to the DOM applied before the
+ * current time, but it may also contain updates applied after the current time.</p>
+ *
+ * <p>The state of the DOM covered by this API includes the following:
+ * <ul>
+ * <li>primitive HTML elements (div, img, span, etc..)</li>
+ * <li>images</li>
+ * <li>CSS animations</li>
+ * <li>WebGL</li>
+ * <li>canvas</li>
+ * </ul>
+ * It does not include the state of:
+ * <ul>
+ * <li>the video tag</li>
+ * </ul></p>
+ *
+ * <p>To guarantee that the {@link WebView} will successfully render the first frame
+ * after the {@link VisualStateCallback#onComplete} method has been called a set of conditions
+ * must be met:
+ * <ul>
+ * <li>If the {@link WebView}'s visibility is set to {@link View#VISIBLE VISIBLE} then
+ * the {@link WebView} must be attached to the view hierarchy.</li>
+ * <li>If the {@link WebView}'s visibility is set to {@link View#INVISIBLE INVISIBLE}
+ * then the {@link WebView} must be attached to the view hierarchy and must be made
+ * {@link View#VISIBLE VISIBLE} from the {@link VisualStateCallback#onComplete} method.</li>
+ * <li>If the {@link WebView}'s visibility is set to {@link View#GONE GONE} then the
+ * {@link WebView} must be attached to the view hierarchy and its
+ * {@link AbsoluteLayout.LayoutParams LayoutParams}'s width and height need to be set to fixed
+ * values and must be made {@link View#VISIBLE VISIBLE} from the
+ * {@link VisualStateCallback#onComplete} method.</li>
+ * </ul></p>
+ *
+ * <p>When using this API it is also recommended to enable pre-rasterization if the
+ * {@link WebView} is offscreen to avoid flickering. See WebSettings#setOffscreenPreRaster for
+ * more details and do consider its caveats.</p>
+ *
+ * @param requestId an id that will be returned in the callback to allow callers to match
+ * requests with callbacks.
+ * @param callback the callback to be invoked.
+ */
+ public void insertVisualStateCallback(long requestId, VisualStateCallback callback) {
+ checkThread();
+ if (TRACE) Log.d(LOGTAG, "insertVisualStateCallback");
+ mProvider.insertVisualStateCallback(requestId, callback);
+ }
+
+ /**
* Clears this WebView so that onDraw() will draw nothing but white background,
* and onMeasure() will return 0 if MeasureSpec is not MeasureSpec.EXACTLY.
* @deprecated Use WebView.loadUrl("about:blank") to reliably reset the view state
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index 34b8cf6..53c7e04 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -83,6 +83,32 @@ public class WebViewClient {
}
/**
+ * Notify the host application that the page commit is visible.
+ *
+ * <p>This is the earliest point at which we can guarantee that the contents of the previously
+ * loaded page will not longer be drawn in the next {@link WebView#onDraw}. The next draw will
+ * render the {@link WebView#setBackgroundColor background color} of the WebView or some of the
+ * contents from the committed page already. This callback may be useful when reusing
+ * {@link WebView}s to ensure that no stale content is shown. This method is only called for
+ * the main frame.</p>
+ *
+ * <p>This method is called when the state of the DOM at the point at which the
+ * body of the HTTP response (commonly the string of html) had started loading will be visible.
+ * If you set a background color for the page in the HTTP response body this will most likely
+ * be visible and perhaps some other elements. At that point no other resources had usually
+ * been loaded, so you can expect images for example to not be visible. If you want
+ * a finer level of granularity consider calling {@link WebView#insertVisualStateCallback}
+ * directly.</p>
+ *
+ * <p>Please note that all the conditions and recommendations presented in
+ * {@link WebView#insertVisualStateCallback} also apply to this API.<p>
+ *
+ * @param url the url of the committed page
+ */
+ public void onPageCommitVisible(WebView view, String url) {
+ }
+
+ /**
* Notify the host application of a resource request and allow the
* application to return the data. If the return value is null, the WebView
* will continue to load the resource as usual. Otherwise, the return
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 0cdb875..fa2ce1b 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -40,6 +40,8 @@ import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.webkit.WebView.HitTestResult;
import android.webkit.WebView.PictureListener;
+import android.webkit.WebView.VisualStateCallback;
+
import java.io.BufferedWriter;
import java.io.File;
@@ -146,6 +148,8 @@ public interface WebViewProvider {
public boolean pageDown(boolean bottom);
+ public void insertVisualStateCallback(long requestId, VisualStateCallback callback);
+
public void clearView();
public Picture capturePicture();
diff --git a/core/java/android/widget/ActionMenuView.java b/core/java/android/widget/ActionMenuView.java
index 9d3a5dc..d6f2276 100644
--- a/core/java/android/widget/ActionMenuView.java
+++ b/core/java/android/widget/ActionMenuView.java
@@ -15,6 +15,7 @@
*/
package android.widget;
+import android.annotation.StyleRes;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
@@ -86,7 +87,7 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
* @param resId theme used to inflate popup menus
* @see #getPopupTheme()
*/
- public void setPopupTheme(int resId) {
+ public void setPopupTheme(@StyleRes int resId) {
if (mPopupTheme != resId) {
mPopupTheme = resId;
if (resId == 0) {
diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java
index 89e508f..ae94a10 100644
--- a/core/java/android/widget/ArrayAdapter.java
+++ b/core/java/android/widget/ArrayAdapter.java
@@ -19,6 +19,7 @@ package android.widget;
import android.annotation.ArrayRes;
import android.annotation.IdRes;
import android.annotation.LayoutRes;
+import android.annotation.NonNull;
import android.content.Context;
import android.content.res.Resources;
import android.util.Log;
@@ -133,7 +134,7 @@ public class ArrayAdapter<T> extends BaseAdapter implements Filterable,
* instantiating views.
* @param objects The objects to represent in the ListView.
*/
- public ArrayAdapter(Context context, @LayoutRes int resource, T[] objects) {
+ public ArrayAdapter(Context context, @LayoutRes int resource, @NonNull T[] objects) {
this(context, resource, 0, Arrays.asList(objects));
}
@@ -146,7 +147,8 @@ public class ArrayAdapter<T> extends BaseAdapter implements Filterable,
* @param textViewResourceId The id of the TextView within the layout resource to be populated
* @param objects The objects to represent in the ListView.
*/
- public ArrayAdapter(Context context, @LayoutRes int resource, @IdRes int textViewResourceId, T[] objects) {
+ public ArrayAdapter(Context context, @LayoutRes int resource, @IdRes int textViewResourceId,
+ @NonNull T[] objects) {
this(context, resource, textViewResourceId, Arrays.asList(objects));
}
@@ -158,7 +160,7 @@ public class ArrayAdapter<T> extends BaseAdapter implements Filterable,
* instantiating views.
* @param objects The objects to represent in the ListView.
*/
- public ArrayAdapter(Context context, @LayoutRes int resource, List<T> objects) {
+ public ArrayAdapter(Context context, @LayoutRes int resource, @NonNull List<T> objects) {
this(context, resource, 0, objects);
}
@@ -171,7 +173,8 @@ public class ArrayAdapter<T> extends BaseAdapter implements Filterable,
* @param textViewResourceId The id of the TextView within the layout resource to be populated
* @param objects The objects to represent in the ListView.
*/
- public ArrayAdapter(Context context, int resource, int textViewResourceId, List<T> objects) {
+ public ArrayAdapter(Context context, @LayoutRes int resource, @IdRes int textViewResourceId,
+ @NonNull List<T> objects) {
mContext = context;
mInflater = LayoutInflater.from(context);
mResource = mDropDownResource = resource;
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
index fe143de..133e102 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -22,6 +22,7 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
+import android.annotation.StyleRes;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
@@ -326,7 +327,7 @@ class FastScroller {
refreshDrawablePressedState();
}
- public void setStyle(int resId) {
+ public void setStyle(@StyleRes int resId) {
final Context context = mList.getContext();
final TypedArray ta = context.obtainStyledAttributes(null,
com.android.internal.R.styleable.FastScroll, android.R.attr.fastScrollStyle, resId);
diff --git a/core/java/android/widget/SimpleAdapter.java b/core/java/android/widget/SimpleAdapter.java
index a656712..2008ba8 100644
--- a/core/java/android/widget/SimpleAdapter.java
+++ b/core/java/android/widget/SimpleAdapter.java
@@ -16,6 +16,8 @@
package android.widget;
+import android.annotation.IdRes;
+import android.annotation.LayoutRes;
import android.content.Context;
import android.content.res.Resources;
import android.view.ContextThemeWrapper;
@@ -82,7 +84,7 @@ public class SimpleAdapter extends BaseAdapter implements Filterable, Spinner.Th
* in the from parameter.
*/
public SimpleAdapter(Context context, List<? extends Map<String, ?>> data,
- int resource, String[] from, int[] to) {
+ @LayoutRes int resource, String[] from, @IdRes int[] to) {
mData = data;
mResource = mDropDownResource = resource;
mFrom = from;
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index d2430bc..087406a 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -17,8 +17,12 @@
package android.widget;
import android.annotation.ColorInt;
+import android.annotation.DrawableRes;
+import android.annotation.MenuRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.StringRes;
+import android.annotation.StyleRes;
import android.app.ActionBar;
import android.content.Context;
import android.content.res.ColorStateList;
@@ -296,7 +300,7 @@ public class Toolbar extends ViewGroup {
* @param resId theme used to inflate popup menus
* @see #getPopupTheme()
*/
- public void setPopupTheme(int resId) {
+ public void setPopupTheme(@StyleRes int resId) {
if (mPopupTheme != resId) {
mPopupTheme = resId;
if (resId == 0) {
@@ -331,7 +335,7 @@ public class Toolbar extends ViewGroup {
*
* @param resId ID of a drawable resource
*/
- public void setLogo(int resId) {
+ public void setLogo(@DrawableRes int resId) {
setLogo(getContext().getDrawable(resId));
}
@@ -481,7 +485,7 @@ public class Toolbar extends ViewGroup {
*
* @param resId String resource id
*/
- public void setLogoDescription(int resId) {
+ public void setLogoDescription(@StringRes int resId) {
setLogoDescription(getContext().getText(resId));
}
@@ -566,7 +570,7 @@ public class Toolbar extends ViewGroup {
*
* @param resId Resource ID of a string to set as the title
*/
- public void setTitle(int resId) {
+ public void setTitle(@StringRes int resId) {
setTitle(getContext().getText(resId));
}
@@ -621,7 +625,7 @@ public class Toolbar extends ViewGroup {
*
* @param resId String resource ID
*/
- public void setSubtitle(int resId) {
+ public void setSubtitle(@StringRes int resId) {
setSubtitle(getContext().getText(resId));
}
@@ -663,7 +667,7 @@ public class Toolbar extends ViewGroup {
* Sets the text color, size, style, hint color, and highlight color
* from the specified TextAppearance resource.
*/
- public void setTitleTextAppearance(Context context, int resId) {
+ public void setTitleTextAppearance(Context context, @StyleRes int resId) {
mTitleTextAppearance = resId;
if (mTitleTextView != null) {
mTitleTextView.setTextAppearance(context, resId);
@@ -674,7 +678,7 @@ public class Toolbar extends ViewGroup {
* Sets the text color, size, style, hint color, and highlight color
* from the specified TextAppearance resource.
*/
- public void setSubtitleTextAppearance(Context context, int resId) {
+ public void setSubtitleTextAppearance(Context context, @StyleRes int resId) {
mSubtitleTextAppearance = resId;
if (mSubtitleTextView != null) {
mSubtitleTextView.setTextAppearance(context, resId);
@@ -729,7 +733,7 @@ public class Toolbar extends ViewGroup {
*
* @attr ref android.R.styleable#Toolbar_navigationContentDescription
*/
- public void setNavigationContentDescription(int resId) {
+ public void setNavigationContentDescription(@StringRes int resId) {
setNavigationContentDescription(resId != 0 ? getContext().getText(resId) : null);
}
@@ -766,7 +770,7 @@ public class Toolbar extends ViewGroup {
*
* @attr ref android.R.styleable#Toolbar_navigationIcon
*/
- public void setNavigationIcon(int resId) {
+ public void setNavigationIcon(@DrawableRes int resId) {
setNavigationIcon(getContext().getDrawable(resId));
}
@@ -972,7 +976,7 @@ public class Toolbar extends ViewGroup {
*
* @param resId ID of a menu resource to inflate
*/
- public void inflateMenu(int resId) {
+ public void inflateMenu(@MenuRes int resId) {
getMenuInflater().inflate(resId, getMenu());
}
diff --git a/core/java/android/widget/ViewAnimator.java b/core/java/android/widget/ViewAnimator.java
index f30fdd8..1580f51 100644
--- a/core/java/android/widget/ViewAnimator.java
+++ b/core/java/android/widget/ViewAnimator.java
@@ -17,6 +17,7 @@
package android.widget;
+import android.annotation.AnimRes;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
@@ -309,7 +310,7 @@ public class ViewAnimator extends FrameLayout {
* @see #getInAnimation()
* @see #setInAnimation(android.view.animation.Animation)
*/
- public void setInAnimation(Context context, int resourceID) {
+ public void setInAnimation(Context context, @AnimRes int resourceID) {
setInAnimation(AnimationUtils.loadAnimation(context, resourceID));
}
@@ -322,7 +323,7 @@ public class ViewAnimator extends FrameLayout {
* @see #getOutAnimation()
* @see #setOutAnimation(android.view.animation.Animation)
*/
- public void setOutAnimation(Context context, int resourceID) {
+ public void setOutAnimation(Context context, @AnimRes int resourceID) {
setOutAnimation(AnimationUtils.loadAnimation(context, resourceID));
}