diff options
Diffstat (limited to 'core/java')
44 files changed, 243 insertions, 5364 deletions
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java index 5e4ddd0..b739387 100644 --- a/core/java/android/app/ActivityTransitionCoordinator.java +++ b/core/java/android/app/ActivityTransitionCoordinator.java @@ -129,8 +129,8 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { protected static final String KEY_SCALE_TYPE = "shared_element:scaleType"; protected static final String KEY_IMAGE_MATRIX = "shared_element:imageMatrix"; - // The background fade in/out duration. 150ms is pretty quick, but not abrupt. - public static final int FADE_BACKGROUND_DURATION_MS = 150; + // The background fade in/out duration. TODO: Enable tuning this. + public static final int FADE_BACKGROUND_DURATION_MS = 300; protected static final ImageView.ScaleType[] SCALE_TYPE_VALUES = ImageView.ScaleType.values(); @@ -195,6 +195,11 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { */ public static final int MSG_SHARED_ELEMENT_DESTINATION = 107; + /** + * Send the shared element positions. + */ + public static final int MSG_SEND_SHARED_ELEMENT_DESTINATION = 108; + final private Window mWindow; final protected ArrayList<String> mAllSharedElementNames; final protected ArrayList<View> mSharedElements = new ArrayList<View>(); diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 4f335bb..e03224c 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -75,6 +75,8 @@ import android.location.LocationManager; import android.media.AudioManager; import android.media.MediaRouter; import android.media.session.MediaSessionManager; +import android.media.tv.ITvInputManager; +import android.media.tv.TvInputManager; import android.net.ConnectivityManager; import android.net.IConnectivityManager; import android.net.EthernetManager; @@ -119,8 +121,6 @@ import android.service.fingerprint.FingerprintManager; import android.service.fingerprint.FingerprintManagerReceiver; import android.service.fingerprint.FingerprintService; import android.telephony.TelephonyManager; -import android.tv.ITvInputManager; -import android.tv.TvInputManager; import android.content.ClipboardManager; import android.util.AndroidRuntimeException; import android.util.ArrayMap; diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java index a8617b8..4b052e7 100644 --- a/core/java/android/app/EnterTransitionCoordinator.java +++ b/core/java/android/app/EnterTransitionCoordinator.java @@ -29,6 +29,7 @@ import android.transition.TransitionManager; import android.util.ArrayMap; import android.util.Pair; import android.view.View; +import android.view.ViewGroup; import android.view.ViewGroupOverlay; import android.view.ViewTreeObserver; import android.widget.ImageView; @@ -72,8 +73,24 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { } }; mHandler.sendEmptyMessageDelayed(MSG_CANCEL, MAX_WAIT_MS); + send(MSG_SEND_SHARED_ELEMENT_DESTINATION, null); + } + } + + private void sendSharedElementDestination() { + ViewGroup decor = getDecor(); + if (!decor.isLayoutRequested()) { Bundle state = captureSharedElementState(); mResultReceiver.send(MSG_SHARED_ELEMENT_DESTINATION, state); + } else { + getDecor().getViewTreeObserver() + .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + getDecor().getViewTreeObserver().removeOnPreDrawListener(this); + return true; + } + }); } } @@ -105,6 +122,9 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { case MSG_CANCEL: cancel(); break; + case MSG_SEND_SHARED_ELEMENT_DESTINATION: + sendSharedElementDestination(); + break; } } diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java index a71d649..ba1638f 100644 --- a/core/java/android/app/ExitTransitionCoordinator.java +++ b/core/java/android/app/ExitTransitionCoordinator.java @@ -294,7 +294,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { } private void finishIfNecessary() { - if (mIsReturning && mExitNotified && (mSharedElements.isEmpty() + if (mIsReturning && mExitNotified && mActivity != null && (mSharedElements.isEmpty() || mSharedElements.get(0).getVisibility() == View.INVISIBLE)) { mActivity.finish(); mActivity.overridePendingTransition(0, 0); diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index b3b1d47..24a354f 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -104,6 +104,17 @@ public class DevicePolicyManager { = "android.app.action.ACTION_PROVISION_MANAGED_PROFILE"; /** + * A broadcast intent with this action can be sent to ManagedProvisionning to specify that the + * user has already consented to the creation of the managed profile. + * The intent must contain the extras + * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME} and + * {@link #EXTRA_PROVISIONING_TOKEN} + * @hide + */ + public static final String ACTION_PROVISIONING_USER_HAS_CONSENTED + = "android.app.action.USER_HAS_CONSENTED"; + + /** * A String extra holding the name of the package of the mobile device management application * that starts the managed provisioning flow. This package will be set as the profile owner. * <p>Use with {@link #ACTION_PROVISION_MANAGED_PROFILE}. @@ -112,6 +123,13 @@ public class DevicePolicyManager { = "deviceAdminPackageName"; /** + * An int extra used to identify the consent of the user to create the managed profile. + * <p>Use with {@link #ACTION_PROVISION_MANAGED_PROFILE} + */ + public static final String EXTRA_PROVISIONING_TOKEN + = "android.app.extra.token"; + + /** * A String extra holding the default name of the profile that is created during managed profile * provisioning. * <p>Use with {@link #ACTION_PROVISION_MANAGED_PROFILE} @@ -2152,45 +2170,6 @@ public class DevicePolicyManager { } /** - * Called by profile or device owner to re-enable a system app that was disabled by default - * when the managed profile was created. This should only be called from a profile or device - * owner running within a managed profile. - * - * @param admin Which {@link DeviceAdminReceiver} this request is associated with. - * @param packageName The package to be re-enabled in the current profile. - */ - public void enableSystemApp(ComponentName admin, String packageName) { - if (mService != null) { - try { - mService.enableSystemApp(admin, packageName); - } catch (RemoteException e) { - Log.w(TAG, "Failed to install package: " + packageName); - } - } - } - - /** - * Called by profile or device owner to re-enable system apps by intent that were disabled - * by default when the managed profile was created. This should only be called from a profile - * or device owner running within a managed profile. - * - * @param admin Which {@link DeviceAdminReceiver} this request is associated with. - * @param intent An intent matching the app(s) to be installed. All apps that resolve for this - * intent will be re-enabled in the current profile. - * @return int The number of activities that matched the intent and were installed. - */ - public int enableSystemApp(ComponentName admin, Intent intent) { - if (mService != null) { - try { - return mService.enableSystemAppWithIntent(admin, intent); - } catch (RemoteException e) { - Log.w(TAG, "Failed to install packages matching filter: " + intent); - } - } - return 0; - } - - /** * Called by a profile owner to disable account management for a specific type of account. * * <p>The calling device admin must be a profile owner. If it is not, a diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 7f754dc..7d7a312 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -135,9 +135,6 @@ interface IDevicePolicyManager { UserHandle createUser(in ComponentName who, in String name); boolean removeUser(in ComponentName who, in UserHandle userHandle); - void enableSystemApp(in ComponentName admin, in String packageName); - int enableSystemAppWithIntent(in ComponentName admin, in Intent intent); - void setAccountManagementDisabled(in ComponentName who, in String accountType, in boolean disabled); String[] getAccountTypesWithManagementDisabled(); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index c69e669..a040efb 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -2751,11 +2751,11 @@ public abstract class Context { /** * Use with {@link #getSystemService} to retrieve a - * {@link android.tv.TvInputManager} for interacting with TV inputs on the - * device. + * {@link android.media.tv.TvInputManager} for interacting with TV inputs + * on the device. * * @see #getSystemService - * @see android.tv.TvInputManager + * @see android.media.tv.TvInputManager */ public static final String TV_INPUT_SERVICE = "tv_input"; diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 3737638..ed3f9aa 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -702,12 +702,17 @@ public class Resources { * Context.obtainStyledAttributes} with * an array containing the resource ID of interest to create the TypedArray.</p> * + * <p class="note"><strong>Note:</strong> To obtain a themed drawable, use + * {@link android.content.Context#getDrawable(int) Context.getDrawable(int)} + * or {@link #getDrawable(int, Theme)} passing the desired theme.</p> + * * @param id The desired resource identifier, as generated by the aapt * tool. This integer encodes the package, type, and resource * entry. The value 0 is an invalid identifier. * @return Drawable An object that can be used to draw this resource. * @throws NotFoundException Throws NotFoundException if the given ID does * not exist. + * @see #getDrawable(int, Theme) */ public Drawable getDrawable(int id) throws NotFoundException { return getDrawable(id, null); @@ -715,7 +720,9 @@ public class Resources { /** * Return a drawable object associated with a particular resource ID and - * styled for the specified theme. + * styled for the specified theme. Various types of objects will be + * returned depending on the underlying resource -- for example, a solid + * color, PNG image, scalable image, etc. * * @param id The desired resource identifier, as generated by the aapt * tool. This integer encodes the package, type, and resource @@ -755,6 +762,11 @@ public class Resources { * image, scalable image, etc. The Drawable API hides these implementation * details. * + * <p class="note"><strong>Note:</strong> To obtain a themed drawable, use + * {@link android.content.Context#getDrawable(int) Context.getDrawable(int)} + * or {@link #getDrawableForDensity(int, int, Theme)} passing the desired + * theme.</p> + * * @param id The desired resource identifier, as generated by the aapt tool. * This integer encodes the package, type, and resource entry. * The value 0 is an invalid identifier. @@ -2340,12 +2352,12 @@ public class Resources { if (file.endsWith(".xml")) { final XmlResourceParser rp = loadXmlResourceParser( file, id, value.assetCookie, "drawable"); - dr = Drawable.createFromXmlThemed(this, rp, theme); + dr = Drawable.createFromXml(this, rp, theme); rp.close(); } else { final InputStream is = mAssets.openNonAsset( value.assetCookie, file, AssetManager.ACCESS_STREAMING); - dr = Drawable.createFromResourceStreamThemed(this, value, is, file, null, theme); + dr = Drawable.createFromResourceStream(this, value, is, file, null); is.close(); } } catch (Exception e) { diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index bc57b33..e627d49 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -931,6 +931,14 @@ public abstract class BatteryStats implements Parcelable { } } + /** + * Don't allow any more batching in to the current history event. This + * is called when printing partial histories, so to ensure that the next + * history event will go in to a new batch after what was printed in the + * last partial history. + */ + public abstract void commitCurrentHistoryBatchLocked(); + public abstract int getHistoryTotalSize(); public abstract int getHistoryUsedSize(); @@ -3366,6 +3374,7 @@ public abstract class BatteryStats implements Parcelable { } } if (histStart >= 0) { + commitCurrentHistoryBatchLocked(); pw.print(checkin ? "NEXT: " : " NEXT: "); pw.println(lastTime+1); } } diff --git a/core/java/android/provider/TvContract.java b/core/java/android/provider/TvContract.java deleted file mode 100644 index 0d90a16..0000000 --- a/core/java/android/provider/TvContract.java +++ /dev/null @@ -1,741 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.provider; - -import android.content.ComponentName; -import android.content.ContentResolver; -import android.content.ContentUris; -import android.net.Uri; -import android.tv.TvInputService; - -import java.util.List; - -/** - * <p> - * The contract between the TV provider and applications. Contains definitions for the supported - * URIs and columns. - * </p> - * <h3>Overview</h3> - * <p> - * TvContract defines a basic database of TV content metadata such as channel and program - * information. The information is stored in {@link Channels} and {@link Programs} tables. - * </p> - * <ul> - * <li>A row in the {@link Channels} table represents information about a TV channel. The data - * format can vary greatly from standard to standard or according to service provider, thus - * the columns here are mostly comprised of basic entities that are usually seen to users - * regardless of standard such as channel number and name.</li> - * <li>A row in the {@link Programs} table represents a set of data describing a TV program such - * as program title and start time.</li> - * </ul> - */ -public final class TvContract { - /** The authority for the TV provider. */ - public static final String AUTHORITY = "com.android.tv"; - - private static final String PATH_CHANNEL = "channel"; - private static final String PATH_PROGRAM = "program"; - private static final String PATH_INPUT = "input"; - - /** - * An optional query, update or delete URI parameter that allows the caller to specify start - * time (in milliseconds since the epoch) to filter programs. - * - * @hide - */ - public static final String PARAM_START_TIME = "start_time"; - - /** - * An optional query, update or delete URI parameter that allows the caller to specify end time - * (in milliseconds since the epoch) to filter programs. - * - * @hide - */ - public static final String PARAM_END_TIME = "end_time"; - - /** - * A query, update or delete URI parameter that allows the caller to operate on all or - * browsable-only channels. If set to "true", the rows that contain non-browsable channels are - * not affected. - * - * @hide - */ - public static final String PARAM_BROWSABLE_ONLY = "browsable_only"; - - /** - * Builds a URI that points to a specific channel. - * - * @param channelId The ID of the channel to point to. - */ - public static final Uri buildChannelUri(long channelId) { - return ContentUris.withAppendedId(Channels.CONTENT_URI, channelId); - } - - /** - * Builds a URI that points to all browsable channels from a given TV input. - * - * @param name {@link ComponentName} of the {@link android.tv.TvInputService} that implements - * the given TV input. - */ - public static final Uri buildChannelsUriForInput(ComponentName name) { - return buildChannelsUriForInput(name, true); - } - - /** - * Builds a URI that points to all or browsable-only channels from a given TV input. - * - * @param name {@link ComponentName} of the {@link android.tv.TvInputService} that implements - * the given TV input. - * @param browsableOnly If set to {@code true} the URI points to only browsable channels. If set - * to {@code false} the URI points to all channels regardless of whether they are - * browsable or not. - */ - public static final Uri buildChannelsUriForInput(ComponentName name, boolean browsableOnly) { - return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY) - .appendPath(PATH_INPUT).appendPath(name.getPackageName()) - .appendPath(name.getClassName()).appendPath(PATH_CHANNEL) - .appendQueryParameter(PARAM_BROWSABLE_ONLY, String.valueOf(browsableOnly)).build(); - } - - /** - * Builds a URI that points to a specific program. - * - * @param programId The ID of the program to point to. - */ - public static final Uri buildProgramUri(long programId) { - return ContentUris.withAppendedId(Programs.CONTENT_URI, programId); - } - - /** - * Builds a URI that points to all programs on a given channel. - * - * @param channelUri The URI of the channel to return programs for. - */ - public static final Uri buildProgramsUriForChannel(Uri channelUri) { - if (!PATH_CHANNEL.equals(channelUri.getPathSegments().get(0))) { - throw new IllegalArgumentException("Not a channel: " + channelUri); - } - String channelId = String.valueOf(ContentUris.parseId(channelUri)); - return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY) - .appendPath(PATH_CHANNEL).appendPath(channelId).appendPath(PATH_PROGRAM).build(); - } - - /** - * Builds a URI that points to programs on a specific channel whose schedules overlap with the - * given time frame. - * - * @param channelUri The URI of the channel to return programs for. - * @param startTime The start time used to filter programs. The returned programs should have - * {@link Programs#COLUMN_END_TIME_UTC_MILLIS} that is greater than this time. - * @param endTime The end time used to filter programs. The returned programs should have - * {@link Programs#COLUMN_START_TIME_UTC_MILLIS} that is less than this time. - */ - public static final Uri buildProgramsUriForChannel(Uri channelUri, long startTime, - long endTime) { - Uri uri = buildProgramsUriForChannel(channelUri); - return uri.buildUpon().appendQueryParameter(PARAM_START_TIME, String.valueOf(startTime)) - .appendQueryParameter(PARAM_END_TIME, String.valueOf(endTime)).build(); - } - - /** - * Builds a URI that points to a specific program the user watched. - * - * @param watchedProgramId The ID of the watched program to point to. - * @hide - */ - public static final Uri buildWatchedProgramUri(long watchedProgramId) { - return ContentUris.withAppendedId(WatchedPrograms.CONTENT_URI, watchedProgramId); - } - - /** - * Extracts the {@link Channels#COLUMN_PACKAGE_NAME} from a given URI. - * - * @param channelsUri A URI constructed by {@link #buildChannelsUriForInput(ComponentName)} or - * {@link #buildChannelsUriForInput(ComponentName, boolean)}. - * @hide - */ - public static final String getPackageName(Uri channelsUri) { - final List<String> paths = channelsUri.getPathSegments(); - if (paths.size() < 4) { - throw new IllegalArgumentException("Not channels: " + channelsUri); - } - if (!PATH_INPUT.equals(paths.get(0)) || !PATH_CHANNEL.equals(paths.get(3))) { - throw new IllegalArgumentException("Not channels: " + channelsUri); - } - return paths.get(1); - } - - /** - * Extracts the {@link Channels#COLUMN_SERVICE_NAME} from a given URI. - * - * @param channelsUri A URI constructed by {@link #buildChannelsUriForInput(ComponentName)} or - * {@link #buildChannelsUriForInput(ComponentName, boolean)}. - * @hide - */ - public static final String getServiceName(Uri channelsUri) { - final List<String> paths = channelsUri.getPathSegments(); - if (paths.size() < 4) { - throw new IllegalArgumentException("Not channels: " + channelsUri); - } - if (!PATH_INPUT.equals(paths.get(0)) || !PATH_CHANNEL.equals(paths.get(3))) { - throw new IllegalArgumentException("Not channels: " + channelsUri); - } - return paths.get(2); - } - - /** - * Extracts the {@link Channels#_ID} from a given URI. - * - * @param programsUri A URI constructed by {@link #buildProgramsUriForChannel(Uri)} or - * {@link #buildProgramsUriForChannel(Uri, long, long)}. - * @hide - */ - public static final String getChannelId(Uri programsUri) { - final List<String> paths = programsUri.getPathSegments(); - if (paths.size() < 3) { - throw new IllegalArgumentException("Not programs: " + programsUri); - } - if (!PATH_CHANNEL.equals(paths.get(0)) || !PATH_PROGRAM.equals(paths.get(2))) { - throw new IllegalArgumentException("Not programs: " + programsUri); - } - return paths.get(1); - } - - - private TvContract() {} - - /** - * Common base for the tables of TV channels/programs. - */ - public interface BaseTvColumns extends BaseColumns { - /** - * The name of the package that owns a row in each table. - * <p> - * The TV provider fills it in with the name of the package that provides the initial data - * of that row. If the package is later uninstalled, the rows it owns are automatically - * removed from the tables. - * </p><p> - * Type: TEXT - * </p> - */ - public static final String COLUMN_PACKAGE_NAME = "package_name"; - } - - /** Column definitions for the TV channels table. */ - public static final class Channels implements BaseTvColumns { - - /** The content:// style URI for this table. */ - public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" - + PATH_CHANNEL); - - /** The MIME type of a directory of TV channels. */ - public static final String CONTENT_TYPE = - "vnd.android.cursor.dir/vnd.com.android.tv.channels"; - - /** The MIME type of a single TV channel. */ - public static final String CONTENT_ITEM_TYPE = - "vnd.android.cursor.item/vnd.com.android.tv.channels"; - - /** A generic channel type. */ - public static final int TYPE_OTHER = 0x0; - - /** The special channel type used for pass-through inputs such as HDMI. */ - public static final int TYPE_PASSTHROUGH = 0x00010000; - - /** The channel type for DVB-T (terrestrial). */ - public static final int TYPE_DVB_T = 0x00020000; - - /** The channel type for DVB-T2 (terrestrial). */ - public static final int TYPE_DVB_T2 = 0x00020001; - - /** The channel type for DVB-S (satellite). */ - public static final int TYPE_DVB_S = 0x00020100; - - /** The channel type for DVB-S2 (satellite). */ - public static final int TYPE_DVB_S2 = 0x00020101; - - /** The channel type for DVB-C (cable). */ - public static final int TYPE_DVB_C = 0x00020200; - - /** The channel type for DVB-C2 (cable). */ - public static final int TYPE_DVB_C2 = 0x00020201; - - /** The channel type for DVB-H (handheld). */ - public static final int TYPE_DVB_H = 0x00020300; - - /** The channel type for DVB-SH (satellite). */ - public static final int TYPE_DVB_SH = 0x00020400; - - /** The channel type for ATSC (terrestrial). */ - public static final int TYPE_ATSC_T = 0x00030000; - - /** The channel type for ATSC (cable). */ - public static final int TYPE_ATSC_C = 0x00030200; - - /** The channel type for ATSC-M/H (mobile/handheld). */ - public static final int TYPE_ATSC_M_H = 0x00030200; - - /** The channel type for ISDB-T (terrestrial). */ - public static final int TYPE_ISDB_T = 0x00040000; - - /** The channel type for ISDB-Tb (Brazil). */ - public static final int TYPE_ISDB_TB = 0x00040100; - - /** The channel type for ISDB-S (satellite). */ - public static final int TYPE_ISDB_S = 0x00040200; - - /** The channel type for ISDB-C (cable). */ - public static final int TYPE_ISDB_C = 0x00040300; - - /** The channel type for 1seg (handheld). */ - public static final int TYPE_1SEG = 0x00040400; - - /** The channel type for DTMB (terrestrial). */ - public static final int TYPE_DTMB = 0x00050000; - - /** The channel type for CMMB (handheld). */ - public static final int TYPE_CMMB = 0x00050100; - - /** The channel type for T-DMB (terrestrial). */ - public static final int TYPE_T_DMB = 0x00060000; - - /** The channel type for S-DMB (satellite). */ - public static final int TYPE_S_DMB = 0x00060100; - - /** A generic service type. */ - public static final int SERVICE_TYPE_OTHER = 0x0; - - /** The service type for regular TV channels. */ - public static final int SERVICE_TYPE_TV = 0x1; - - /** The service type for radio channels. */ - public static final int SERVICE_TYPE_RADIO = 0x2; - - /** - * The name of the {@link TvInputService} subclass that provides this TV channel. This - * should be a fully qualified class name (such as, "com.example.project.TvInputService"). - * <p> - * This is a required field. - * </p><p> - * Type: TEXT - * </p> - */ - public static final String COLUMN_SERVICE_NAME = "service_name"; - - /** - * The predefined type of this TV channel. - * <p> - * This is primarily used to indicate which broadcast standard (e.g. ATSC, DVB or ISDB) the - * current channel conforms to, with an exception being {@link #TYPE_PASSTHROUGH}, which is - * a special channel type used only by pass-through inputs such as HDMI. The value should - * match to one of the followings: {@link #TYPE_OTHER}, {@link #TYPE_PASSTHROUGH}, - * {@link #TYPE_DVB_T}, {@link #TYPE_DVB_T2}, {@link #TYPE_DVB_S}, {@link #TYPE_DVB_S2}, - * {@link #TYPE_DVB_C}, {@link #TYPE_DVB_C2}, {@link #TYPE_DVB_H}, {@link #TYPE_DVB_SH}, - * {@link #TYPE_ATSC_T}, {@link #TYPE_ATSC_C}, {@link #TYPE_ATSC_M_H}, {@link #TYPE_ISDB_T}, - * {@link #TYPE_ISDB_TB}, {@link #TYPE_ISDB_S}, {@link #TYPE_ISDB_C} {@link #TYPE_1SEG}, - * {@link #TYPE_DTMB}, {@link #TYPE_CMMB}, {@link #TYPE_T_DMB}, {@link #TYPE_S_DMB} - * </p><p> - * This is a required field. - * </p><p> - * Type: INTEGER - * </p> - */ - public static final String COLUMN_TYPE = "type"; - - /** - * The predefined service type of this TV channel. - * <p> - * This is primarily used to indicate whether the current channel is a regular TV channel or - * a radio-like channel. Use the same coding for {@code service_type} in the underlying - * broadcast standard if it is defined there (e.g. ATSC A/53, ETSI EN 300 468 and ARIB - * STD-B10). Otherwise use one of the followings: {@link #SERVICE_TYPE_OTHER}, - * {@link #SERVICE_TYPE_TV}, {@link #SERVICE_TYPE_RADIO} - * </p><p> - * This is a required field. - * </p><p> - * Type: INTEGER - * </p> - */ - public static final String COLUMN_SERVICE_TYPE = "service_type"; - - /** - * The original network ID of this TV channel. - * <p> - * This is used to identify the originating delivery system, if applicable. Use the same - * coding for {@code origianal_network_id} in the underlying broadcast standard if it is - * defined there (e.g. ETSI EN 300 468/TR 101 211 and ARIB STD-B10). If channels cannot be - * globally identified by 2-tuple {{@link #COLUMN_TRANSPORT_STREAM_ID}, - * {@link #COLUMN_SERVICE_ID}}, one must carefully assign a value to this field to form a - * unique 3-tuple identification {{@link #COLUMN_ORIGINAL_NETWORK_ID}, - * {@link #COLUMN_TRANSPORT_STREAM_ID}, {@link #COLUMN_SERVICE_ID}} for its channels. - * </p><p> - * This is a required field if the channel cannot be uniquely identified by a 2-tuple - * {{@link #COLUMN_TRANSPORT_STREAM_ID}, {@link #COLUMN_SERVICE_ID}}. - * </p><p> - * Type: INTEGER - * </p> - */ - public static final String COLUMN_ORIGINAL_NETWORK_ID = "original_network_id"; - - /** - * The transport stream ID of this channel. - * <p> - * This is used to identify the Transport Stream that contains the current channel from any - * other multiplex within a network, if applicable. Use the same coding for - * {@code transport_stream_id} defined in ISO/IEC 13818-1 if the channel is transmitted via - * the MPEG Transport Stream as is the case for many digital broadcast standards. - * </p><p> - * This is a required field if the current channel is transmitted via the MPEG Transport - * Stream. - * </p><p> - * Type: INTEGER - * </p> - */ - public static final String COLUMN_TRANSPORT_STREAM_ID = "transport_stream_id"; - - /** - * The service ID of this channel. - * <p> - * This is used to identify the current service (roughly equivalent to channel) from any - * other service within the Transport Stream, if applicable. Use the same coding for - * {@code service_id} in the underlying broadcast standard if it is defined there (e.g. ETSI - * EN 300 468 and ARIB STD-B10) or {@code program_number} (which usually has the same value - * as {@code service_id}) in ISO/IEC 13818-1 if the channel is transmitted via the MPEG - * Transport Stream. - * </p><p> - * This is a required field if the current channel is transmitted via the MPEG Transport - * Stream. - * </p><p> - * Type: INTEGER - * </p> - */ - public static final String COLUMN_SERVICE_ID = "service_id"; - - /** - * The channel number that is displayed to the user. - * <p> - * The format can vary depending on broadcast standard and product specification. - * </p><p> - * Type: TEXT - * </p> - */ - public static final String COLUMN_DISPLAY_NUMBER = "display_number"; - - /** - * The channel name that is displayed to the user. - * <p> - * A call sign is a good candidate to use for this purpose but any name that helps the user - * recognize the current channel will be enough. Can also be empty depending on broadcast - * standard. - * </p><p> - * Type: TEXT - * </p> - */ - public static final String COLUMN_DISPLAY_NAME = "display_name"; - - /** - * The description of this TV channel. - * <p> - * Can be empty initially. - * </p><p> - * Type: TEXT - * </p> - */ - public static final String COLUMN_DESCRIPTION = "description"; - - /** - * The flag indicating whether this TV channel is browsable or not. - * <p> - * A value of 1 indicates the channel is included in the channel list that applications use - * to browse channels, a value of 0 indicates the channel is not included in the list. If - * not specified, this value is set to 1 (browsable) by default. - * </p><p> - * Type: INTEGER (boolean) - * </p> - */ - public static final String COLUMN_BROWSABLE = "browsable"; - - /** - * The flag indicating whether this TV channel is searchable or not. - * <p> - * In some regions, it is not allowed to surface search results for a given channel without - * broadcaster's consent. This is used to impose such restriction. A value of 1 indicates - * the channel is searchable and can be included in search results, a value of 0 indicates - * the channel and its TV programs are hidden from search. If not specified, this value is - * set to 1 (searchable) by default. - * </p> - * <p> - * Type: INTEGER (boolean) - * </p> - */ - public static final String COLUMN_SEARCHABLE = "searchable"; - - /** - * The flag indicating whether this TV channel is locked or not. - * <p> - * This is primarily used for alternative parental control to prevent unauthorized users - * from watching the current channel regardless of the content rating. A value of 1 - * indicates the channel is locked and the user is required to enter passcode to unlock it - * in order to watch the current program from the channel, a value of 0 indicates the - * channel is not locked thus the user is not prompted to enter passcode If not specified, - * this value is set to 0 (not locked) by default. - * </p><p> - * Type: INTEGER (boolean) - * </p> - */ - public static final String COLUMN_LOCKED = "locked"; - - /** - * Generic data used by individual TV input services. - * <p> - * Type: BLOB - * </p> - */ - public static final String COLUMN_DATA = "data"; - - - /** - * The version number of this row entry used by TV input services. - * <p> - * This is best used by sync adapters to identify the rows to update. The number can be - * defined by individual TV input services. One may assign the same value as - * {@code version_number} that appears in ETSI EN 300 468 or ATSC A/65, if the data are - * coming from a TV broadcast. - * </p><p> - * Type: INTEGER - * </p> - */ - public static final String COLUMN_VERSION_NUMBER = "version_number"; - - private Channels() {} - } - - /** Column definitions for the TV programs table. */ - public static final class Programs implements BaseTvColumns { - - /** The content:// style URI for this table. */ - public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" - + PATH_PROGRAM); - - /** The MIME type of a directory of TV programs. */ - public static final String CONTENT_TYPE = - "vnd.android.cursor.dir/vnd.com.android.tv.programs"; - - /** The MIME type of a single TV program. */ - public static final String CONTENT_ITEM_TYPE = - "vnd.android.cursor.item/vnd.com.android.tv.programs"; - - /** - * The ID of the TV channel that contains this TV program. - * <p> - * This is a part of the channel URI and matches to {@link BaseColumns#_ID}. - * </p><p> - * Type: INTEGER (long) - * </p> - */ - public static final String COLUMN_CHANNEL_ID = "channel_id"; - - /** - * The title of this TV program. - * <p> - * Type: TEXT - * </p> - **/ - public static final String COLUMN_TITLE = "title"; - - /** - * The start time of this TV program, in milliseconds since the epoch. - * <p> - * Type: INTEGER (long) - * </p> - */ - public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis"; - - /** - * The end time of this TV program, in milliseconds since the epoch. - * <p> - * Type: INTEGER (long) - * </p> - */ - public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis"; - - /** - * The comma-separated genre string of this TV program. - * <p> - * Use the same language appeared in the underlying broadcast standard, if applicable. (For - * example, one can refer to the genre strings used in Genre Descriptor of ATSC A/65 or - * Content Descriptor of ETSI EN 300 468, if appropriate.) Otherwise, use one of the - * following genres: - * <ul> - * <li>Family/Kids</li> - * <li>Sports</li> - * <li>Shopping</li> - * <li>Movies</li> - * <li>Comedy</li> - * <li>Travel</li> - * <li>Drama</li> - * <li>Education</li> - * <li>Animal/Wildlife</li> - * <li>News</li> - * <li>Gaming</li> - * <li>Others</li> - * </ul> - * </p><p> - * Type: TEXT - * </p> - */ - public static final String COLUMN_GENRE = "genre"; - - /** - * The description of this TV program that is displayed to the user by default. - * <p> - * The maximum length of this field is 256 characters. - * </p><p> - * Type: TEXT - * </p> - */ - public static final String COLUMN_DESCRIPTION = "description"; - - /** - * The detailed, lengthy description of this TV program that is displayed only when the user - * wants to see more information. - * <p> - * TV input services should leave this field empty if they have no additional - * details beyond {@link #COLUMN_DESCRIPTION}. - * </p><p> - * Type: TEXT - * </p> - */ - public static final String COLUMN_LONG_DESCRIPTION = "long_description"; - - /** - * The comma-separated audio languages of this TV program. - * <p> - * This is used to describe available audio languages included in the program. Use - * 3-character language code as specified by ISO 639-2. - * </p><p> - * Type: TEXT - * </p> - */ - public static final String COLUMN_AUDIO_LANGUAGE = "audio_language"; - - /** - * Generic data used by TV input services. - * <p> - * Type: BLOB - * </p> - */ - public static final String COLUMN_DATA = "data"; - - /** - * The version number of this row entry used by TV input services. - * <p> - * This is best used by sync adapters to identify the rows to update. The number can be - * defined by individual TV input services. One may assign the same value as - * {@code version_number} in ETSI EN 300 468 or ATSC A/65, if the data are coming from a TV - * broadcast. - * </p><p> - * Type: INTEGER - * </p> - */ - public static final String COLUMN_VERSION_NUMBER = "version_number"; - - private Programs() {} - } - - /** - * Column definitions for the TV programs that the user watched. Applications do not have access - * to this table. - * - * @hide - */ - public static final class WatchedPrograms implements BaseColumns { - - /** The content:// style URI for this table. */ - public static final Uri CONTENT_URI = - Uri.parse("content://" + AUTHORITY + "/watched_program"); - - /** The MIME type of a directory of watched programs. */ - public static final String CONTENT_TYPE = - "vnd.android.cursor.dir/vnd.com.android.tv.watched_programs"; - - /** The MIME type of a single item in this table. */ - public static final String CONTENT_ITEM_TYPE = - "vnd.android.cursor.item/vnd.com.android.tv.watched_programs"; - - /** - * The UTC time that the user started watching this TV program, in milliseconds since the - * epoch. - * <p> - * Type: INTEGER (long) - * </p> - */ - public static final String COLUMN_WATCH_START_TIME_UTC_MILLIS = - "watch_start_time_utc_millis"; - - /** - * The UTC time that the user stopped watching this TV program, in milliseconds since the - * epoch. - * <p> - * Type: INTEGER (long) - * </p> - */ - public static final String COLUMN_WATCH_END_TIME_UTC_MILLIS = "watch_end_time_utc_millis"; - - /** - * The channel ID that contains this TV program. - * <p> - * Type: INTEGER (long) - * </p> - */ - public static final String COLUMN_CHANNEL_ID = "channel_id"; - - /** - * The title of this TV program. - * <p> - * Type: TEXT - * </p> - */ - public static final String COLUMN_TITLE = "title"; - - /** - * The start time of this TV program, in milliseconds since the epoch. - * <p> - * Type: INTEGER (long) - * </p> - */ - public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis"; - - /** - * The end time of this TV program, in milliseconds since the epoch. - * <p> - * Type: INTEGER (long) - * </p> - */ - public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis"; - - /** - * The description of this TV program. - * <p> - * Type: TEXT - * </p> - */ - public static final String COLUMN_DESCRIPTION = "description"; - - private WatchedPrograms() {} - } -} diff --git a/core/java/android/speech/tts/TextToSpeechClient.java b/core/java/android/speech/tts/TextToSpeechClient.java index e17b498..0c0be83 100644 --- a/core/java/android/speech/tts/TextToSpeechClient.java +++ b/core/java/android/speech/tts/TextToSpeechClient.java @@ -793,15 +793,14 @@ public class TextToSpeechClient { return mService != null && mEstablished; } - boolean runAction(Action action) { + <T> ActionResult<T> runAction(Action<T> action) { synchronized (mLock) { try { - action.run(mService); - return true; + return new ActionResult<T>(true, action.run(mService)); } catch (Exception ex) { Log.e(TAG, action.getName() + " failed", ex); disconnect(); - return false; + return new ActionResult<T>(false); } } } @@ -821,7 +820,7 @@ public class TextToSpeechClient { } } - private abstract class Action { + private abstract class Action<T> { private final String mName; public Action(String name) { @@ -829,7 +828,21 @@ public class TextToSpeechClient { } public String getName() {return mName;} - abstract void run(ITextToSpeechService service) throws RemoteException; + abstract T run(ITextToSpeechService service) throws RemoteException; + } + + private class ActionResult<T> { + boolean mSuccess; + T mResult; + + ActionResult(boolean success) { + mSuccess = success; + } + + ActionResult(boolean success, T result) { + mSuccess = success; + mResult = result; + } } private IBinder getCallerIdentity() { @@ -839,18 +852,17 @@ public class TextToSpeechClient { return null; } - private boolean runAction(Action action) { + private <T> ActionResult<T> runAction(Action<T> action) { synchronized (mLock) { if (mServiceConnection == null) { Log.w(TAG, action.getName() + " failed: not bound to TTS engine"); - return false; + return new ActionResult<T>(false); } if (!mServiceConnection.isEstablished()) { Log.w(TAG, action.getName() + " failed: not fully bound to TTS engine"); - return false; + return new ActionResult<T>(false); } - mServiceConnection.runAction(action); - return true; + return mServiceConnection.runAction(action); } } @@ -861,13 +873,14 @@ public class TextToSpeechClient { * other utterances in the queue. */ public void stop() { - runAction(new Action(ACTION_STOP_NAME) { + runAction(new Action<Void>(ACTION_STOP_NAME) { @Override - public void run(ITextToSpeechService service) throws RemoteException { + public Void run(ITextToSpeechService service) throws RemoteException { if (service.stop(getCallerIdentity()) != Status.SUCCESS) { Log.e(TAG, "Stop failed"); } mCallbacks.clear(); + return null; } }); } @@ -915,9 +928,9 @@ public class TextToSpeechClient { final UtteranceId utteranceId, final RequestConfig config, final RequestCallbacks callbacks) { - runAction(new Action(ACTION_QUEUE_SPEAK_NAME) { + runAction(new Action<Void>(ACTION_QUEUE_SPEAK_NAME) { @Override - public void run(ITextToSpeechService service) throws RemoteException { + public Void run(ITextToSpeechService service) throws RemoteException { RequestCallbacks c = mDefaultRequestCallbacks; if (callbacks != null) { c = callbacks; @@ -925,7 +938,7 @@ public class TextToSpeechClient { int addCallbackStatus = addCallback(utteranceId, c); if (addCallbackStatus != Status.SUCCESS) { c.onSynthesisFailure(utteranceId, Status.ERROR_INVALID_REQUEST); - return; + return null; } int queueResult = service.speakV2( @@ -934,6 +947,7 @@ public class TextToSpeechClient { if (queueResult != Status.SUCCESS) { removeCallbackAndErr(utteranceId.toUniqueString(), queueResult); } + return null; } }); } @@ -984,9 +998,9 @@ public class TextToSpeechClient { final UtteranceId utteranceId, final File outputFile, final RequestConfig config, final RequestCallbacks callbacks) { - runAction(new Action(ACTION_QUEUE_SYNTHESIZE_TO_FILE) { + runAction(new Action<Void>(ACTION_QUEUE_SYNTHESIZE_TO_FILE) { @Override - public void run(ITextToSpeechService service) throws RemoteException { + public Void run(ITextToSpeechService service) throws RemoteException { RequestCallbacks c = mDefaultRequestCallbacks; if (callbacks != null) { c = callbacks; @@ -994,7 +1008,7 @@ public class TextToSpeechClient { int addCallbackStatus = addCallback(utteranceId, c); if (addCallbackStatus != Status.SUCCESS) { c.onSynthesisFailure(utteranceId, Status.ERROR_INVALID_REQUEST); - return; + return null; } ParcelFileDescriptor fileDescriptor = null; @@ -1002,7 +1016,7 @@ public class TextToSpeechClient { if (outputFile.exists() && !outputFile.canWrite()) { Log.e(TAG, "No permissions to write to " + outputFile); removeCallbackAndErr(utteranceId.toUniqueString(), Status.ERROR_OUTPUT); - return; + return null; } fileDescriptor = ParcelFileDescriptor.open(outputFile, ParcelFileDescriptor.MODE_WRITE_ONLY | @@ -1023,6 +1037,7 @@ public class TextToSpeechClient { Log.e(TAG, "Closing file " + outputFile + " failed", e); removeCallbackAndErr(utteranceId.toUniqueString(), Status.ERROR_OUTPUT); } + return null; } }); } @@ -1050,9 +1065,9 @@ public class TextToSpeechClient { */ public void queueSilence(final long durationInMs, final UtteranceId utteranceId, final RequestCallbacks callbacks) { - runAction(new Action(ACTION_QUEUE_SILENCE_NAME) { + runAction(new Action<Void>(ACTION_QUEUE_SILENCE_NAME) { @Override - public void run(ITextToSpeechService service) throws RemoteException { + public Void run(ITextToSpeechService service) throws RemoteException { RequestCallbacks c = mDefaultRequestCallbacks; if (callbacks != null) { c = callbacks; @@ -1068,6 +1083,7 @@ public class TextToSpeechClient { if (queueResult != Status.SUCCESS) { removeCallbackAndErr(utteranceId.toUniqueString(), queueResult); } + return null; } }); } @@ -1091,9 +1107,9 @@ public class TextToSpeechClient { */ public void queueAudio(final Uri audioUrl, final UtteranceId utteranceId, final RequestConfig config, final RequestCallbacks callbacks) { - runAction(new Action(ACTION_QUEUE_AUDIO_NAME) { + runAction(new Action<Void>(ACTION_QUEUE_AUDIO_NAME) { @Override - public void run(ITextToSpeechService service) throws RemoteException { + public Void run(ITextToSpeechService service) throws RemoteException { RequestCallbacks c = mDefaultRequestCallbacks; if (callbacks != null) { c = callbacks; @@ -1109,10 +1125,35 @@ public class TextToSpeechClient { if (queueResult != Status.SUCCESS) { removeCallbackAndErr(utteranceId.toUniqueString(), queueResult); } + return null; + } + }); + } + + private static final String ACTION_IS_SPEAKING_NAME = "isSpeaking"; + + /** + * Checks whether the TTS engine is busy speaking. Note that a speech item is + * considered complete once it's audio data has been sent to the audio mixer, or + * written to a file. There might be a finite lag between this point, and when + * the audio hardware completes playback. + * + * @return {@code true} if the TTS engine is speaking. + */ + public boolean isSpeaking() { + ActionResult<Boolean> result = runAction(new Action<Boolean>(ACTION_IS_SPEAKING_NAME) { + @Override + public Boolean run(ITextToSpeechService service) throws RemoteException { + return service.isSpeaking(); } }); + if (!result.mSuccess) { + return false; // We can't really say, return false + } + return result.mResult; } + class InternalHandler extends Handler { final static int WHAT_ENGINE_STATUS_CHANGED = 1; final static int WHAT_SERVICE_DISCONNECTED = 2; diff --git a/core/java/android/tv/ITvInputClient.aidl b/core/java/android/tv/ITvInputClient.aidl deleted file mode 100644 index ef89c68..0000000 --- a/core/java/android/tv/ITvInputClient.aidl +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.tv; - -import android.content.ComponentName; -import android.os.Bundle; -import android.tv.ITvInputSession; -import android.view.InputChannel; - -/** - * Interface a client of the ITvInputManager implements, to identify itself and receive information - * about changes to the state of each TV input service. - * @hide - */ -oneway interface ITvInputClient { - void onSessionCreated(in String inputId, IBinder token, in InputChannel channel, int seq); - void onAvailabilityChanged(in String inputId, boolean isAvailable); - void onSessionReleased(int seq); - void onSessionEvent(in String name, in Bundle args, int seq); - void onVideoSizeChanged(int width, int height, int seq); -} diff --git a/core/java/android/tv/ITvInputHardware.aidl b/core/java/android/tv/ITvInputHardware.aidl deleted file mode 100644 index 7250453..0000000 --- a/core/java/android/tv/ITvInputHardware.aidl +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.tv; - -import android.tv.TvStreamConfig; -import android.view.KeyEvent; -import android.view.Surface; - -/** - * TvInputService representing a physical port should connect to HAL through this interface. - * Framework will take care of communication among system services including TvInputManagerService, - * HdmiControlService, AudioService, etc. - * - * @hide - */ -interface ITvInputHardware { - /** - * Make the input render on the surface according to the config. In case of HDMI, this will - * trigger CEC commands for adjusting active HDMI source. Returns true on success. - */ - boolean setSurface(in Surface surface, in TvStreamConfig config); - /** - * Set volume for this stream via AudioGain. (TBD) - */ - void setVolume(float volume); - - /** - * Dispatch key event to HDMI service. The events would be automatically converted to - * HDMI CEC commands. If the hardware is not representing an HDMI port, this method will fail. - */ - boolean dispatchKeyEventToHdmi(in KeyEvent event); -} diff --git a/core/java/android/tv/ITvInputHardwareCallback.aidl b/core/java/android/tv/ITvInputHardwareCallback.aidl deleted file mode 100644 index 83041be..0000000 --- a/core/java/android/tv/ITvInputHardwareCallback.aidl +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.tv; - -import android.tv.TvStreamConfig; - -/** - * @hide - */ -oneway interface ITvInputHardwareCallback { - void onReleased(); - void onStreamConfigChanged(in TvStreamConfig[] configs); -} diff --git a/core/java/android/tv/ITvInputManager.aidl b/core/java/android/tv/ITvInputManager.aidl deleted file mode 100644 index c6f8d79..0000000 --- a/core/java/android/tv/ITvInputManager.aidl +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.tv; - -import android.content.ComponentName; -import android.graphics.Rect; -import android.net.Uri; -import android.tv.ITvInputHardware; -import android.tv.ITvInputHardwareCallback; -import android.tv.ITvInputClient; -import android.tv.TvInputHardwareInfo; -import android.tv.TvInputInfo; -import android.view.Surface; - -/** - * Interface to the TV input manager service. - * @hide - */ -interface ITvInputManager { - List<TvInputInfo> getTvInputList(int userId); - - boolean getAvailability(in ITvInputClient client, in String inputId, int userId); - - void registerCallback(in ITvInputClient client, in String inputId, int userId); - void unregisterCallback(in ITvInputClient client, in String inputId, int userId); - - void createSession(in ITvInputClient client, in String inputId, int seq, int userId); - void releaseSession(in IBinder sessionToken, int userId); - - void setSurface(in IBinder sessionToken, in Surface surface, int userId); - void setVolume(in IBinder sessionToken, float volume, int userId); - void tune(in IBinder sessionToken, in Uri channelUri, int userId); - - void createOverlayView(in IBinder sessionToken, in IBinder windowToken, in Rect frame, - int userId); - void relayoutOverlayView(in IBinder sessionToken, in Rect frame, int userId); - void removeOverlayView(in IBinder sessionToken, int userId); - - // For TV input hardware binding - List<TvInputHardwareInfo> getHardwareList(); - ITvInputHardware acquireTvInputHardware(int deviceId, in ITvInputHardwareCallback callback, - int userId); - void releaseTvInputHardware(int deviceId, in ITvInputHardware hardware, int userId); -} diff --git a/core/java/android/tv/ITvInputService.aidl b/core/java/android/tv/ITvInputService.aidl deleted file mode 100644 index 4f1bc2b..0000000 --- a/core/java/android/tv/ITvInputService.aidl +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.tv; - -import android.tv.ITvInputServiceCallback; -import android.tv.ITvInputSessionCallback; -import android.view.InputChannel; - -/** - * Top-level interface to a TV input component (implemented in a Service). - * @hide - */ -oneway interface ITvInputService { - void registerCallback(ITvInputServiceCallback callback); - void unregisterCallback(in ITvInputServiceCallback callback); - void createSession(in InputChannel channel, ITvInputSessionCallback callback); -} diff --git a/core/java/android/tv/ITvInputServiceCallback.aidl b/core/java/android/tv/ITvInputServiceCallback.aidl deleted file mode 100644 index 71fc780..0000000 --- a/core/java/android/tv/ITvInputServiceCallback.aidl +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.tv; - -import android.content.ComponentName; - -/** - * Helper interface for ITvInputService to allow the TV input to notify the client when its status - * has been changed. - * @hide - */ -oneway interface ITvInputServiceCallback { - void onAvailabilityChanged(in String inputId, boolean isAvailable); -} diff --git a/core/java/android/tv/ITvInputSession.aidl b/core/java/android/tv/ITvInputSession.aidl deleted file mode 100644 index 32fee4b..0000000 --- a/core/java/android/tv/ITvInputSession.aidl +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.tv; - -import android.graphics.Rect; -import android.net.Uri; -import android.view.Surface; - -/** - * Sub-interface of ITvInputService which is created per session and has its own context. - * @hide - */ -oneway interface ITvInputSession { - void release(); - - void setSurface(in Surface surface); - // TODO: Remove this once it becomes irrelevant for applications to handle audio focus. The plan - // is to introduce some new concepts that will solve a number of problems in audio policy today. - void setVolume(float volume); - void tune(in Uri channelUri); - - void createOverlayView(in IBinder windowToken, in Rect frame); - void relayoutOverlayView(in Rect frame); - void removeOverlayView(); -} diff --git a/core/java/android/tv/ITvInputSessionCallback.aidl b/core/java/android/tv/ITvInputSessionCallback.aidl deleted file mode 100644 index e27b8bf..0000000 --- a/core/java/android/tv/ITvInputSessionCallback.aidl +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.tv; - -import android.os.Bundle; -import android.tv.ITvInputSession; - -/** - * Helper interface for ITvInputSession to allow the TV input to notify the system service when a - * new session has been created. - * @hide - */ -oneway interface ITvInputSessionCallback { - void onSessionCreated(ITvInputSession session); - void onSessionEvent(in String name, in Bundle args); - void onVideoSizeChanged(int width, int height); -} diff --git a/core/java/android/tv/ITvInputSessionWrapper.java b/core/java/android/tv/ITvInputSessionWrapper.java deleted file mode 100644 index 3ccccf3..0000000 --- a/core/java/android/tv/ITvInputSessionWrapper.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.tv; - -import android.content.Context; -import android.graphics.Rect; -import android.net.Uri; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.tv.TvInputManager.Session; -import android.tv.TvInputService.TvInputSessionImpl; -import android.util.Log; -import android.view.InputChannel; -import android.view.InputEvent; -import android.view.InputEventReceiver; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.Surface; - -import com.android.internal.os.HandlerCaller; -import com.android.internal.os.SomeArgs; - -/** - * Implements the internal ITvInputSession interface to convert incoming calls on to it back to - * calls on the public TvInputSession interface, scheduling them on the main thread of the process. - * - * @hide - */ -public class ITvInputSessionWrapper extends ITvInputSession.Stub implements HandlerCaller.Callback { - private static final String TAG = "TvInputSessionWrapper"; - - private static final int DO_RELEASE = 1; - private static final int DO_SET_SURFACE = 2; - private static final int DO_SET_VOLUME = 3; - private static final int DO_TUNE = 4; - private static final int DO_CREATE_OVERLAY_VIEW = 5; - private static final int DO_RELAYOUT_OVERLAY_VIEW = 6; - private static final int DO_REMOVE_OVERLAY_VIEW = 7; - - private final HandlerCaller mCaller; - - private TvInputSessionImpl mTvInputSessionImpl; - private InputChannel mChannel; - private TvInputEventReceiver mReceiver; - - public ITvInputSessionWrapper(Context context, TvInputSessionImpl sessionImpl, - InputChannel channel) { - mCaller = new HandlerCaller(context, null, this, true /* asyncHandler */); - mTvInputSessionImpl = sessionImpl; - mChannel = channel; - if (channel != null) { - mReceiver = new TvInputEventReceiver(channel, context.getMainLooper()); - } - } - - @Override - public void executeMessage(Message msg) { - if (mTvInputSessionImpl == null) { - return; - } - - switch (msg.what) { - case DO_RELEASE: { - mTvInputSessionImpl.release(); - mTvInputSessionImpl = null; - if (mReceiver != null) { - mReceiver.dispose(); - mReceiver = null; - } - if (mChannel != null) { - mChannel.dispose(); - mChannel = null; - } - return; - } - case DO_SET_SURFACE: { - mTvInputSessionImpl.setSurface((Surface) msg.obj); - return; - } - case DO_SET_VOLUME: { - mTvInputSessionImpl.setVolume((Float) msg.obj); - return; - } - case DO_TUNE: { - mTvInputSessionImpl.tune((Uri) msg.obj); - return; - } - case DO_CREATE_OVERLAY_VIEW: { - SomeArgs args = (SomeArgs) msg.obj; - mTvInputSessionImpl.createOverlayView((IBinder) args.arg1, (Rect) args.arg2); - args.recycle(); - return; - } - case DO_RELAYOUT_OVERLAY_VIEW: { - mTvInputSessionImpl.relayoutOverlayView((Rect) msg.obj); - return; - } - case DO_REMOVE_OVERLAY_VIEW: { - mTvInputSessionImpl.removeOverlayView(true); - return; - } - default: { - Log.w(TAG, "Unhandled message code: " + msg.what); - return; - } - } - } - - @Override - public void release() { - mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_RELEASE)); - } - - @Override - public void setSurface(Surface surface) { - mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_SET_SURFACE, surface)); - } - - @Override - public final void setVolume(float volume) { - mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_SET_VOLUME, volume)); - } - - @Override - public void tune(Uri channelUri) { - mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_TUNE, channelUri)); - } - - @Override - public void createOverlayView(IBinder windowToken, Rect frame) { - mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_CREATE_OVERLAY_VIEW, windowToken, - frame)); - } - - @Override - public void relayoutOverlayView(Rect frame) { - mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_RELAYOUT_OVERLAY_VIEW, frame)); - } - - @Override - public void removeOverlayView() { - mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_REMOVE_OVERLAY_VIEW)); - } - - private final class TvInputEventReceiver extends InputEventReceiver { - public TvInputEventReceiver(InputChannel inputChannel, Looper looper) { - super(inputChannel, looper); - } - - @Override - public void onInputEvent(InputEvent event) { - if (mTvInputSessionImpl == null) { - // The session has been finished. - finishInputEvent(event, false); - return; - } - - int handled = mTvInputSessionImpl.dispatchInputEvent(event, this); - if (handled != Session.DISPATCH_IN_PROGRESS) { - finishInputEvent(event, handled == Session.DISPATCH_HANDLED); - } - } - } -} diff --git a/core/java/android/tv/TvInputHardwareInfo.aidl b/core/java/android/tv/TvInputHardwareInfo.aidl deleted file mode 100644 index 484ab60..0000000 --- a/core/java/android/tv/TvInputHardwareInfo.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * - * Copyright 2014, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.tv; - -parcelable TvInputHardwareInfo; diff --git a/core/java/android/tv/TvInputHardwareInfo.java b/core/java/android/tv/TvInputHardwareInfo.java deleted file mode 100644 index b0dc58e..0000000 --- a/core/java/android/tv/TvInputHardwareInfo.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.tv; - -import android.os.Parcel; -import android.os.Parcelable; -import android.util.Log; - -/** - * Simple container for information about TV input hardware. - * Not for third-party developers. - * - * @hide - */ -public final class TvInputHardwareInfo implements Parcelable { - static final String TAG = "TvInputHardwareInfo"; - - // Match hardware/libhardware/include/hardware/tv_input.h - public static final int TV_INPUT_TYPE_HDMI = 1; - public static final int TV_INPUT_TYPE_BUILT_IN_TUNER = 2; - public static final int TV_INPUT_TYPE_PASSTHROUGH = 3; - - public static final Parcelable.Creator<TvInputHardwareInfo> CREATOR = - new Parcelable.Creator<TvInputHardwareInfo>() { - @Override - public TvInputHardwareInfo createFromParcel(Parcel source) { - try { - TvInputHardwareInfo info = new TvInputHardwareInfo(); - info.readFromParcel(source); - return info; - } catch (Exception e) { - Log.e(TAG, "Exception creating TvInputHardwareInfo from parcel", e); - return null; - } - } - - @Override - public TvInputHardwareInfo[] newArray(int size) { - return new TvInputHardwareInfo[size]; - } - }; - - private int mDeviceId; - private int mType; - // TODO: Add audio port & audio address for audio service. - // TODO: Add HDMI handle for HDMI service. - - public TvInputHardwareInfo() { } - - public TvInputHardwareInfo(int deviceId, int type) { - mDeviceId = deviceId; - mType = type; - } - - public int getDeviceId() { - return mDeviceId; - } - - public int getType() { - return mType; - } - - // Parcelable - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mDeviceId); - dest.writeInt(mType); - } - - public void readFromParcel(Parcel source) { - mDeviceId = source.readInt(); - mType = source.readInt(); - } -} diff --git a/core/java/android/tv/TvInputInfo.aidl b/core/java/android/tv/TvInputInfo.aidl deleted file mode 100644 index abc4b47..0000000 --- a/core/java/android/tv/TvInputInfo.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.tv; - -parcelable TvInputInfo; diff --git a/core/java/android/tv/TvInputInfo.java b/core/java/android/tv/TvInputInfo.java deleted file mode 100644 index 217e4b7..0000000 --- a/core/java/android/tv/TvInputInfo.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.tv; - -import android.content.ComponentName; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.content.pm.ServiceInfo; -import android.os.Parcel; -import android.os.Parcelable; - -/** - * This class is used to specify meta information of a TV input. - */ -public final class TvInputInfo implements Parcelable { - private final ResolveInfo mService; - private final String mId; - - /** - * Constructor. - * - * @param service The ResolveInfo returned from the package manager about this TV input service. - * @hide - */ - public TvInputInfo(ResolveInfo service) { - mService = service; - ServiceInfo si = service.serviceInfo; - mId = generateInputIdForComponentName(new ComponentName(si.packageName, si.name)); - } - - /** - * Returns a unique ID for this TV input. The ID is generated from the package and class name - * implementing the TV input service. - */ - public String getId() { - return mId; - } - - /** - * Returns the .apk package that implements this TV input service. - */ - public String getPackageName() { - return mService.serviceInfo.packageName; - } - - /** - * Returns the class name of the service component that implements this TV input service. - */ - public String getServiceName() { - return mService.serviceInfo.name; - } - - /** - * Returns the component of the service that implements this TV input. - */ - public ComponentName getComponent() { - return new ComponentName(mService.serviceInfo.packageName, mService.serviceInfo.name); - } - - /** - * Loads the user-displayed label for this TV input service. - * - * @param pm Supplies a PackageManager used to load the TV input's resources. - * @return a CharSequence containing the TV input's label. If the TV input does not have - * a label, its name is returned. - */ - public CharSequence loadLabel(PackageManager pm) { - return mService.loadLabel(pm); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public int hashCode() { - return mId.hashCode(); - } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - - if (!(o instanceof TvInputInfo)) { - return false; - } - - TvInputInfo obj = (TvInputInfo) o; - return mId.equals(obj.mId) - && mService.serviceInfo.packageName.equals(obj.mService.serviceInfo.packageName) - && mService.serviceInfo.name.equals(obj.mService.serviceInfo.name); - } - - @Override - public String toString() { - return "TvInputInfo{id=" + mId - + ", pkg=" + mService.serviceInfo.packageName - + ", service=" + mService.serviceInfo.name + "}"; - } - - /** - * Used to package this object into a {@link Parcel}. - * - * @param dest The {@link Parcel} to be written. - * @param flags The flags used for parceling. - */ - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mId); - mService.writeToParcel(dest, flags); - } - - /** - * Used to generate an input id from a ComponentName. - * - * @param name the component name for generating an input id. - * @return the generated input id for the given {@code name}. - * @hide - */ - public static final String generateInputIdForComponentName(ComponentName name) { - return name.flattenToShortString(); - } - - /** - * Used to make this class parcelable. - * - * @hide - */ - public static final Parcelable.Creator<TvInputInfo> CREATOR = - new Parcelable.Creator<TvInputInfo>() { - @Override - public TvInputInfo createFromParcel(Parcel in) { - return new TvInputInfo(in); - } - - @Override - public TvInputInfo[] newArray(int size) { - return new TvInputInfo[size]; - } - }; - - private TvInputInfo(Parcel in) { - mId = in.readString(); - mService = ResolveInfo.CREATOR.createFromParcel(in); - } -} diff --git a/core/java/android/tv/TvInputManager.java b/core/java/android/tv/TvInputManager.java deleted file mode 100644 index d0c2ca6..0000000 --- a/core/java/android/tv/TvInputManager.java +++ /dev/null @@ -1,850 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.tv; - -import android.graphics.Rect; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.RemoteException; -import android.util.Log; -import android.util.Pools.Pool; -import android.util.Pools.SimplePool; -import android.util.SparseArray; -import android.view.InputChannel; -import android.view.InputEvent; -import android.view.InputEventSender; -import android.view.Surface; -import android.view.View; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -/** - * Central system API to the overall TV input framework (TIF) architecture, which arbitrates - * interaction between applications and the selected TV inputs. - */ -public final class TvInputManager { - private static final String TAG = "TvInputManager"; - - private final ITvInputManager mService; - - // A mapping from an input to the list of its TvInputListenerRecords. - private final Map<String, List<TvInputListenerRecord>> mTvInputListenerRecordsMap = - new HashMap<String, List<TvInputListenerRecord>>(); - - // A mapping from the sequence number of a session to its SessionCallbackRecord. - private final SparseArray<SessionCallbackRecord> mSessionCallbackRecordMap = - new SparseArray<SessionCallbackRecord>(); - - // A sequence number for the next session to be created. Should be protected by a lock - // {@code mSessionCallbackRecordMap}. - private int mNextSeq; - - private final ITvInputClient mClient; - - private final int mUserId; - - /** - * Interface used to receive the created session. - */ - public abstract static class SessionCallback { - /** - * This is called after {@link TvInputManager#createSession} has been processed. - * - * @param session A {@link TvInputManager.Session} instance created. This can be - * {@code null} if the creation request failed. - */ - public void onSessionCreated(Session session) { - } - - /** - * This is called when {@link TvInputManager.Session} is released. - * This typically happens when the process hosting the session has crashed or been killed. - * - * @param session A {@link TvInputManager.Session} instance released. - */ - public void onSessionReleased(Session session) { - } - - /** - * This is called at the beginning of the playback of a channel and later when the size of - * the video has been changed. - * - * @param session A {@link TvInputManager.Session} associated with this callback - * @param width the width of the video - * @param height the height of the video - * @hide - */ - public void onVideoSizeChanged(Session session, int width, int height) { - } - - /** - * This is called when a custom event has been sent from this session. - * - * @param session A {@link TvInputManager.Session} associated with this callback - * @param eventType The type of the event. - * @param eventArgs Optional arguments of the event. - * @hide - */ - public void onSessionEvent(Session session, String eventType, Bundle eventArgs) { - } - } - - private static final class SessionCallbackRecord { - private final SessionCallback mSessionCallback; - private final Handler mHandler; - private Session mSession; - - public SessionCallbackRecord(SessionCallback sessionCallback, - Handler handler) { - mSessionCallback = sessionCallback; - mHandler = handler; - } - - public void postSessionCreated(final Session session) { - mSession = session; - mHandler.post(new Runnable() { - @Override - public void run() { - mSessionCallback.onSessionCreated(session); - } - }); - } - - public void postSessionReleased() { - mHandler.post(new Runnable() { - @Override - public void run() { - mSessionCallback.onSessionReleased(mSession); - } - }); - } - - public void postVideoSizeChanged(final int width, final int height) { - mHandler.post(new Runnable() { - @Override - public void run() { - mSessionCallback.onVideoSizeChanged(mSession, width, height); - } - }); - } - - public void postSessionEvent(final String eventType, final Bundle eventArgs) { - mHandler.post(new Runnable() { - @Override - public void run() { - mSessionCallback.onSessionEvent(mSession, eventType, eventArgs); - } - }); - } - } - - /** - * Interface used to monitor status of the TV input. - */ - public abstract static class TvInputListener { - /** - * This is called when the availability status of a given TV input is changed. - * - * @param inputId the id of the TV input. - * @param isAvailable {@code true} if the given TV input is available to show TV programs. - * {@code false} otherwise. - */ - public void onAvailabilityChanged(String inputId, boolean isAvailable) { - } - } - - private static final class TvInputListenerRecord { - private final TvInputListener mListener; - private final Handler mHandler; - - public TvInputListenerRecord(TvInputListener listener, Handler handler) { - mListener = listener; - mHandler = handler; - } - - public TvInputListener getListener() { - return mListener; - } - - public void postAvailabilityChanged(final String inputId, final boolean isAvailable) { - mHandler.post(new Runnable() { - @Override - public void run() { - mListener.onAvailabilityChanged(inputId, isAvailable); - } - }); - } - } - - /** - * @hide - */ - public TvInputManager(ITvInputManager service, int userId) { - mService = service; - mUserId = userId; - mClient = new ITvInputClient.Stub() { - @Override - public void onSessionCreated(String inputId, IBinder token, InputChannel channel, - int seq) { - synchronized (mSessionCallbackRecordMap) { - SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq); - if (record == null) { - Log.e(TAG, "Callback not found for " + token); - return; - } - Session session = null; - if (token != null) { - session = new Session(token, channel, mService, mUserId, seq, - mSessionCallbackRecordMap); - } - record.postSessionCreated(session); - } - } - - @Override - public void onSessionReleased(int seq) { - synchronized (mSessionCallbackRecordMap) { - SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq); - mSessionCallbackRecordMap.delete(seq); - if (record == null) { - Log.e(TAG, "Callback not found for seq:" + seq); - return; - } - record.mSession.releaseInternal(); - record.postSessionReleased(); - } - } - - @Override - public void onVideoSizeChanged(int width, int height, int seq) { - synchronized (mSessionCallbackRecordMap) { - SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq); - if (record == null) { - Log.e(TAG, "Callback not found for seq " + seq); - return; - } - record.postVideoSizeChanged(width, height); - } - } - - @Override - public void onSessionEvent(String eventType, Bundle eventArgs, int seq) { - synchronized (mSessionCallbackRecordMap) { - SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq); - if (record == null) { - Log.e(TAG, "Callback not found for seq " + seq); - return; - } - record.postSessionEvent(eventType, eventArgs); - } - } - - @Override - public void onAvailabilityChanged(String inputId, boolean isAvailable) { - synchronized (mTvInputListenerRecordsMap) { - List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(inputId); - if (records == null) { - // Silently ignore - no listener is registered yet. - return; - } - int recordsCount = records.size(); - for (int i = 0; i < recordsCount; i++) { - records.get(i).postAvailabilityChanged(inputId, isAvailable); - } - } - } - }; - } - - /** - * Returns the complete list of TV inputs on the system. - * - * @return List of {@link TvInputInfo} for each TV input that describes its meta information. - */ - public List<TvInputInfo> getTvInputList() { - try { - return mService.getTvInputList(mUserId); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** - * Returns the availability of a given TV input. - * - * @param inputId the id of the TV input. - * @throws IllegalArgumentException if the argument is {@code null}. - * @throws IllegalStateException If there is no {@link TvInputListener} registered on the given - * TV input. - */ - public boolean getAvailability(String inputId) { - if (inputId == null) { - throw new IllegalArgumentException("id cannot be null"); - } - synchronized (mTvInputListenerRecordsMap) { - List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(inputId); - if (records == null || records.size() == 0) { - throw new IllegalStateException("At least one listener should be registered."); - } - } - try { - return mService.getAvailability(mClient, inputId, mUserId); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** - * Registers a {@link TvInputListener} for a given TV input. - * - * @param inputId the id of the TV input. - * @param listener a listener used to monitor status of the given TV input. - * @param handler a {@link Handler} that the status change will be delivered to. - * @throws IllegalArgumentException if any of the arguments is {@code null}. - */ - public void registerListener(String inputId, TvInputListener listener, Handler handler) { - if (inputId == null) { - throw new IllegalArgumentException("id cannot be null"); - } - if (listener == null) { - throw new IllegalArgumentException("listener cannot be null"); - } - if (handler == null) { - throw new IllegalArgumentException("handler cannot be null"); - } - synchronized (mTvInputListenerRecordsMap) { - List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(inputId); - if (records == null) { - records = new ArrayList<TvInputListenerRecord>(); - mTvInputListenerRecordsMap.put(inputId, records); - try { - mService.registerCallback(mClient, inputId, mUserId); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - records.add(new TvInputListenerRecord(listener, handler)); - } - } - - /** - * Unregisters the existing {@link TvInputListener} for a given TV input. - * - * @param inputId the id of the TV input. - * @param listener the existing listener to remove for the given TV input. - * @throws IllegalArgumentException if any of the arguments is {@code null}. - */ - public void unregisterListener(String inputId, final TvInputListener listener) { - if (inputId == null) { - throw new IllegalArgumentException("id cannot be null"); - } - if (listener == null) { - throw new IllegalArgumentException("listener cannot be null"); - } - synchronized (mTvInputListenerRecordsMap) { - List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(inputId); - if (records == null) { - Log.e(TAG, "No listener found for " + inputId); - return; - } - for (Iterator<TvInputListenerRecord> it = records.iterator(); it.hasNext();) { - TvInputListenerRecord record = it.next(); - if (record.getListener() == listener) { - it.remove(); - } - } - if (records.isEmpty()) { - try { - mService.unregisterCallback(mClient, inputId, mUserId); - } catch (RemoteException e) { - throw new RuntimeException(e); - } finally { - mTvInputListenerRecordsMap.remove(inputId); - } - } - } - } - - /** - * Creates a {@link Session} for a given TV input. - * <p> - * The number of sessions that can be created at the same time is limited by the capability of - * the given TV input. - * </p> - * - * @param inputId the id of the TV input. - * @param callback a callback used to receive the created session. - * @param handler a {@link Handler} that the session creation will be delivered to. - * @throws IllegalArgumentException if any of the arguments is {@code null}. - */ - public void createSession(String inputId, final SessionCallback callback, - Handler handler) { - if (inputId == null) { - throw new IllegalArgumentException("id cannot be null"); - } - if (callback == null) { - throw new IllegalArgumentException("callback cannot be null"); - } - if (handler == null) { - throw new IllegalArgumentException("handler cannot be null"); - } - SessionCallbackRecord record = new SessionCallbackRecord(callback, handler); - synchronized (mSessionCallbackRecordMap) { - int seq = mNextSeq++; - mSessionCallbackRecordMap.put(seq, record); - try { - mService.createSession(mClient, inputId, seq, mUserId); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - } - - /** The Session provides the per-session functionality of TV inputs. */ - public static final class Session { - static final int DISPATCH_IN_PROGRESS = -1; - static final int DISPATCH_NOT_HANDLED = 0; - static final int DISPATCH_HANDLED = 1; - - private static final long INPUT_SESSION_NOT_RESPONDING_TIMEOUT = 2500; - - private final ITvInputManager mService; - private final int mUserId; - private final int mSeq; - - // For scheduling input event handling on the main thread. This also serves as a lock to - // protect pending input events and the input channel. - private final InputEventHandler mHandler = new InputEventHandler(Looper.getMainLooper()); - - private final Pool<PendingEvent> mPendingEventPool = new SimplePool<PendingEvent>(20); - private final SparseArray<PendingEvent> mPendingEvents = new SparseArray<PendingEvent>(20); - private final SparseArray<SessionCallbackRecord> mSessionCallbackRecordMap; - - private IBinder mToken; - private TvInputEventSender mSender; - private InputChannel mChannel; - - /** @hide */ - private Session(IBinder token, InputChannel channel, ITvInputManager service, int userId, - int seq, SparseArray<SessionCallbackRecord> sessionCallbackRecordMap) { - mToken = token; - mChannel = channel; - mService = service; - mUserId = userId; - mSeq = seq; - mSessionCallbackRecordMap = sessionCallbackRecordMap; - } - - /** - * Releases this session. - * - * @throws IllegalStateException if the session has been already released. - */ - public void release() { - if (mToken == null) { - throw new IllegalStateException("the session has been already released"); - } - try { - mService.releaseSession(mToken, mUserId); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - - releaseInternal(); - } - - /** - * Sets the {@link android.view.Surface} for this session. - * - * @param surface A {@link android.view.Surface} used to render video. - * @throws IllegalStateException if the session has been already released. - * @hide - */ - public void setSurface(Surface surface) { - if (mToken == null) { - throw new IllegalStateException("the session has been already released"); - } - // surface can be null. - try { - mService.setSurface(mToken, surface, mUserId); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** - * Sets the relative volume of this session to handle a change of audio focus. - * - * @param volume A volume value between 0.0f to 1.0f. - * @throws IllegalArgumentException if the volume value is out of range. - * @throws IllegalStateException if the session has been already released. - */ - public void setVolume(float volume) { - if (mToken == null) { - throw new IllegalStateException("the session has been already released"); - } - try { - if (volume < 0.0f || volume > 1.0f) { - throw new IllegalArgumentException("volume should be between 0.0f and 1.0f"); - } - mService.setVolume(mToken, volume, mUserId); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** - * Tunes to a given channel. - * - * @param channelUri The URI of a channel. - * @throws IllegalArgumentException if the argument is {@code null}. - * @throws IllegalStateException if the session has been already released. - */ - public void tune(Uri channelUri) { - if (channelUri == null) { - throw new IllegalArgumentException("channelUri cannot be null"); - } - if (mToken == null) { - throw new IllegalStateException("the session has been already released"); - } - try { - mService.tune(mToken, channelUri, mUserId); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** - * Creates an overlay view. Once the overlay view is created, {@link #relayoutOverlayView} - * should be called whenever the layout of its containing view is changed. - * {@link #removeOverlayView()} should be called to remove the overlay view. - * Since a session can have only one overlay view, this method should be called only once - * or it can be called again after calling {@link #removeOverlayView()}. - * - * @param view A view playing TV. - * @param frame A position of the overlay view. - * @throws IllegalArgumentException if any of the arguments is {@code null}. - * @throws IllegalStateException if {@code view} is not attached to a window or - * if the session has been already released. - */ - void createOverlayView(View view, Rect frame) { - if (view == null) { - throw new IllegalArgumentException("view cannot be null"); - } - if (frame == null) { - throw new IllegalArgumentException("frame cannot be null"); - } - if (view.getWindowToken() == null) { - throw new IllegalStateException("view must be attached to a window"); - } - if (mToken == null) { - throw new IllegalStateException("the session has been already released"); - } - try { - mService.createOverlayView(mToken, view.getWindowToken(), frame, mUserId); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** - * Relayouts the current overlay view. - * - * @param frame A new position of the overlay view. - * @throws IllegalArgumentException if the arguments is {@code null}. - * @throws IllegalStateException if the session has been already released. - */ - void relayoutOverlayView(Rect frame) { - if (frame == null) { - throw new IllegalArgumentException("frame cannot be null"); - } - if (mToken == null) { - throw new IllegalStateException("the session has been already released"); - } - try { - mService.relayoutOverlayView(mToken, frame, mUserId); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** - * Removes the current overlay view. - * - * @throws IllegalStateException if the session has been already released. - */ - void removeOverlayView() { - if (mToken == null) { - throw new IllegalStateException("the session has been already released"); - } - try { - mService.removeOverlayView(mToken, mUserId); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - - /** - * Dispatches an input event to this session. - * - * @param event {@link InputEvent} to dispatch. - * @param token A token used to identify the input event later in the callback. - * @param callback A callback used to receive the dispatch result. - * @param handler {@link Handler} that the dispatch result will be delivered to. - * @return Returns {@link #DISPATCH_HANDLED} if the event was handled. Returns - * {@link #DISPATCH_NOT_HANDLED} if the event was not handled. Returns - * {@link #DISPATCH_IN_PROGRESS} if the event is in progress and the callback will - * be invoked later. - * @throws IllegalArgumentException if any of the necessary arguments is {@code null}. - * @hide - */ - public int dispatchInputEvent(InputEvent event, Object token, - FinishedInputEventCallback callback, Handler handler) { - if (event == null) { - throw new IllegalArgumentException("event cannot be null"); - } - if (callback != null && handler == null) { - throw new IllegalArgumentException("handler cannot be null"); - } - synchronized (mHandler) { - if (mChannel == null) { - return DISPATCH_NOT_HANDLED; - } - PendingEvent p = obtainPendingEventLocked(event, token, callback, handler); - if (Looper.myLooper() == Looper.getMainLooper()) { - // Already running on the main thread so we can send the event immediately. - return sendInputEventOnMainLooperLocked(p); - } - - // Post the event to the main thread. - Message msg = mHandler.obtainMessage(InputEventHandler.MSG_SEND_INPUT_EVENT, p); - msg.setAsynchronous(true); - mHandler.sendMessage(msg); - return DISPATCH_IN_PROGRESS; - } - } - - /** - * Callback that is invoked when an input event that was dispatched to this session has been - * finished. - * - * @hide - */ - public interface FinishedInputEventCallback { - /** - * Called when the dispatched input event is finished. - * - * @param token a token passed to {@link #dispatchInputEvent}. - * @param handled {@code true} if the dispatched input event was handled properly. - * {@code false} otherwise. - */ - public void onFinishedInputEvent(Object token, boolean handled); - } - - // Must be called on the main looper - private void sendInputEventAndReportResultOnMainLooper(PendingEvent p) { - synchronized (mHandler) { - int result = sendInputEventOnMainLooperLocked(p); - if (result == DISPATCH_IN_PROGRESS) { - return; - } - } - - invokeFinishedInputEventCallback(p, false); - } - - private int sendInputEventOnMainLooperLocked(PendingEvent p) { - if (mChannel != null) { - if (mSender == null) { - mSender = new TvInputEventSender(mChannel, mHandler.getLooper()); - } - - final InputEvent event = p.mEvent; - final int seq = event.getSequenceNumber(); - if (mSender.sendInputEvent(seq, event)) { - mPendingEvents.put(seq, p); - Message msg = mHandler.obtainMessage(InputEventHandler.MSG_TIMEOUT_INPUT_EVENT, p); - msg.setAsynchronous(true); - mHandler.sendMessageDelayed(msg, INPUT_SESSION_NOT_RESPONDING_TIMEOUT); - return DISPATCH_IN_PROGRESS; - } - - Log.w(TAG, "Unable to send input event to session: " + mToken + " dropping:" - + event); - } - return DISPATCH_NOT_HANDLED; - } - - void finishedInputEvent(int seq, boolean handled, boolean timeout) { - final PendingEvent p; - synchronized (mHandler) { - int index = mPendingEvents.indexOfKey(seq); - if (index < 0) { - return; // spurious, event already finished or timed out - } - - p = mPendingEvents.valueAt(index); - mPendingEvents.removeAt(index); - - if (timeout) { - Log.w(TAG, "Timeout waiting for seesion to handle input event after " - + INPUT_SESSION_NOT_RESPONDING_TIMEOUT + " ms: " + mToken); - } else { - mHandler.removeMessages(InputEventHandler.MSG_TIMEOUT_INPUT_EVENT, p); - } - } - - invokeFinishedInputEventCallback(p, handled); - } - - // Assumes the event has already been removed from the queue. - void invokeFinishedInputEventCallback(PendingEvent p, boolean handled) { - p.mHandled = handled; - if (p.mHandler.getLooper().isCurrentThread()) { - // Already running on the callback handler thread so we can send the callback - // immediately. - p.run(); - } else { - // Post the event to the callback handler thread. - // In this case, the callback will be responsible for recycling the event. - Message msg = Message.obtain(p.mHandler, p); - msg.setAsynchronous(true); - msg.sendToTarget(); - } - } - - private void flushPendingEventsLocked() { - mHandler.removeMessages(InputEventHandler.MSG_FLUSH_INPUT_EVENT); - - final int count = mPendingEvents.size(); - for (int i = 0; i < count; i++) { - int seq = mPendingEvents.keyAt(i); - Message msg = mHandler.obtainMessage(InputEventHandler.MSG_FLUSH_INPUT_EVENT, seq, 0); - msg.setAsynchronous(true); - msg.sendToTarget(); - } - } - - private PendingEvent obtainPendingEventLocked(InputEvent event, Object token, - FinishedInputEventCallback callback, Handler handler) { - PendingEvent p = mPendingEventPool.acquire(); - if (p == null) { - p = new PendingEvent(); - } - p.mEvent = event; - p.mToken = token; - p.mCallback = callback; - p.mHandler = handler; - return p; - } - - private void recyclePendingEventLocked(PendingEvent p) { - p.recycle(); - mPendingEventPool.release(p); - } - - private void releaseInternal() { - mToken = null; - synchronized (mHandler) { - if (mChannel != null) { - if (mSender != null) { - flushPendingEventsLocked(); - mSender.dispose(); - mSender = null; - } - mChannel.dispose(); - mChannel = null; - } - } - synchronized (mSessionCallbackRecordMap) { - mSessionCallbackRecordMap.remove(mSeq); - } - } - - private final class InputEventHandler extends Handler { - public static final int MSG_SEND_INPUT_EVENT = 1; - public static final int MSG_TIMEOUT_INPUT_EVENT = 2; - public static final int MSG_FLUSH_INPUT_EVENT = 3; - - InputEventHandler(Looper looper) { - super(looper, null, true); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_SEND_INPUT_EVENT: { - sendInputEventAndReportResultOnMainLooper((PendingEvent) msg.obj); - return; - } - case MSG_TIMEOUT_INPUT_EVENT: { - finishedInputEvent(msg.arg1, false, true); - return; - } - case MSG_FLUSH_INPUT_EVENT: { - finishedInputEvent(msg.arg1, false, false); - return; - } - } - } - } - - private final class TvInputEventSender extends InputEventSender { - public TvInputEventSender(InputChannel inputChannel, Looper looper) { - super(inputChannel, looper); - } - - @Override - public void onInputEventFinished(int seq, boolean handled) { - finishedInputEvent(seq, handled, false); - } - } - - private final class PendingEvent implements Runnable { - public InputEvent mEvent; - public Object mToken; - public FinishedInputEventCallback mCallback; - public Handler mHandler; - public boolean mHandled; - - public void recycle() { - mEvent = null; - mToken = null; - mCallback = null; - mHandler = null; - mHandled = false; - } - - @Override - public void run() { - mCallback.onFinishedInputEvent(mToken, mHandled); - - synchronized (mHandler) { - recyclePendingEventLocked(this); - } - } - } - } -} diff --git a/core/java/android/tv/TvInputService.java b/core/java/android/tv/TvInputService.java deleted file mode 100644 index 03d24db..0000000 --- a/core/java/android/tv/TvInputService.java +++ /dev/null @@ -1,598 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.tv; - -import android.app.Service; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.graphics.PixelFormat; -import android.graphics.Rect; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.IBinder; -import android.os.Message; -import android.os.RemoteCallbackList; -import android.os.RemoteException; -import android.tv.TvInputManager.Session; -import android.util.Log; -import android.view.Gravity; -import android.view.InputChannel; -import android.view.InputDevice; -import android.view.InputEvent; -import android.view.InputEventReceiver; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.Surface; -import android.view.View; -import android.view.WindowManager; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.os.SomeArgs; - -/** - * A base class for implementing television input service. - */ -public abstract class TvInputService extends Service { - // STOPSHIP: Turn debugging off. - private static final boolean DEBUG = true; - private static final String TAG = "TvInputService"; - - /** - * This is the interface name that a service implementing a TV input should say that it support - * -- that is, this is the action it uses for its intent filter. To be supported, the service - * must also require the {@link android.Manifest.permission#BIND_TV_INPUT} permission so that - * other applications cannot abuse it. - */ - public static final String SERVICE_INTERFACE = "android.tv.TvInputService"; - - private String mId; - private final Handler mHandler = new ServiceHandler(); - private final RemoteCallbackList<ITvInputServiceCallback> mCallbacks = - new RemoteCallbackList<ITvInputServiceCallback>(); - private boolean mAvailable; - - @Override - public void onCreate() { - super.onCreate(); - mId = TvInputInfo.generateInputIdForComponentName( - new ComponentName(getPackageName(), getClass().getName())); - } - - @Override - public final IBinder onBind(Intent intent) { - return new ITvInputService.Stub() { - @Override - public void registerCallback(ITvInputServiceCallback cb) { - if (cb != null) { - mCallbacks.register(cb); - // The first time a callback is registered, the service needs to report its - // availability status so that the system can know its initial value. - try { - cb.onAvailabilityChanged(mId, mAvailable); - } catch (RemoteException e) { - Log.e(TAG, "error in onAvailabilityChanged", e); - } - } - } - - @Override - public void unregisterCallback(ITvInputServiceCallback cb) { - if (cb != null) { - mCallbacks.unregister(cb); - } - } - - @Override - public void createSession(InputChannel channel, ITvInputSessionCallback cb) { - if (channel == null) { - Log.w(TAG, "Creating session without input channel"); - } - if (cb == null) { - return; - } - SomeArgs args = SomeArgs.obtain(); - args.arg1 = channel; - args.arg2 = cb; - mHandler.obtainMessage(ServiceHandler.DO_CREATE_SESSION, args).sendToTarget(); - } - }; - } - - /** - * Convenience method to notify an availability change of this TV input service. - * - * @param available {@code true} if the input service is available to show TV programs. - */ - public final void setAvailable(boolean available) { - if (available != mAvailable) { - mAvailable = available; - mHandler.obtainMessage(ServiceHandler.DO_BROADCAST_AVAILABILITY_CHANGE, available) - .sendToTarget(); - } - } - - /** - * Get the number of callbacks that are registered. - * - * @hide - */ - @VisibleForTesting - public final int getRegisteredCallbackCount() { - return mCallbacks.getRegisteredCallbackCount(); - } - - /** - * Returns a concrete implementation of {@link TvInputSessionImpl}. - * <p> - * May return {@code null} if this TV input service fails to create a session for some reason. - * </p> - */ - public abstract TvInputSessionImpl onCreateSession(); - - /** - * Base class for derived classes to implement to provide {@link TvInputManager.Session}. - */ - public abstract class TvInputSessionImpl implements KeyEvent.Callback { - private final KeyEvent.DispatcherState mDispatcherState = new KeyEvent.DispatcherState(); - private final WindowManager mWindowManager; - private WindowManager.LayoutParams mWindowParams; - private Surface mSurface; - private View mOverlayView; - private boolean mOverlayViewEnabled; - private IBinder mWindowToken; - private Rect mOverlayFrame; - private ITvInputSessionCallback mSessionCallback; - - public TvInputSessionImpl() { - mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); - } - - /** - * Enables or disables the overlay view. By default, the overlay view is disabled. Must be - * called explicitly after the session is created to enable the overlay view. - * - * @param enable {@code true} if you want to enable the overlay view. {@code false} - * otherwise. - */ - public void setOverlayViewEnabled(final boolean enable) { - mHandler.post(new Runnable() { - @Override - public void run() { - if (enable == mOverlayViewEnabled) { - return; - } - mOverlayViewEnabled = enable; - if (enable) { - if (mWindowToken != null) { - createOverlayView(mWindowToken, mOverlayFrame); - } - } else { - removeOverlayView(false); - } - } - }); - } - - /** - * Dispatches an event to the application using this session. - * - * @param eventType The type of the event. - * @param eventArgs Optional arguments of the event. - * @hide - */ - public void dispatchSessionEvent(final String eventType, final Bundle eventArgs) { - if (eventType == null) { - throw new IllegalArgumentException("eventType should not be null."); - } - mHandler.post(new Runnable() { - @Override - public void run() { - try { - if (DEBUG) Log.d(TAG, "dispatchSessionEvent(" + eventType + ")"); - mSessionCallback.onSessionEvent(eventType, eventArgs); - } catch (RemoteException e) { - Log.w(TAG, "error in sending event (event=" + eventType + ")"); - } - } - }); - } - - /** - * Sends the change on the size of the video. This is expected to be called at the - * beginning of the playback and later when the size has been changed. - * - * @param width The width of the video. - * @param height The height of the video. - * @hide - */ - public void dispatchVideoSizeChanged(final int width, final int height) { - mHandler.post(new Runnable() { - @Override - public void run() { - try { - if (DEBUG) Log.d(TAG, "dispatchVideoSizeChanged"); - mSessionCallback.onVideoSizeChanged(width, height); - } catch (RemoteException e) { - Log.w(TAG, "error in dispatchVideoSizeChanged"); - } - } - }); - } - - /** - * Called when the session is released. - */ - public abstract void onRelease(); - - /** - * Sets the {@link Surface} for the current input session on which the TV input renders - * video. - * - * @param surface {@link Surface} an application passes to this TV input session. - * @return {@code true} if the surface was set, {@code false} otherwise. - */ - public abstract boolean onSetSurface(Surface surface); - - /** - * Sets the relative volume of the current TV input session to handle the change of audio - * focus by setting. - * - * @param volume Volume scale from 0.0 to 1.0. - */ - public abstract void onSetVolume(float volume); - - /** - * Tunes to a given channel. - * - * @param channelUri The URI of the channel. - * @return {@code true} the tuning was successful, {@code false} otherwise. - */ - public abstract boolean onTune(Uri channelUri); - - /** - * Called when an application requests to create an overlay view. Each session - * implementation can override this method and return its own view. - * - * @return a view attached to the overlay window - */ - public View onCreateOverlayView() { - return null; - } - - /** - * Default implementation of {@link android.view.KeyEvent.Callback#onKeyDown(int, KeyEvent) - * KeyEvent.Callback.onKeyDown()}: always returns false (doesn't handle the event). - * <p> - * Override this to intercept key down events before they are processed by the application. - * If you return true, the application will not process the event itself. If you return - * false, the normal application processing will occur as if the TV input had not seen the - * event at all. - * - * @param keyCode The value in event.getKeyCode(). - * @param event Description of the key event. - * @return If you handled the event, return {@code true}. If you want to allow the event to - * be handled by the next receiver, return {@code false}. - */ - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - return false; - } - - /** - * Default implementation of - * {@link android.view.KeyEvent.Callback#onKeyLongPress(int, KeyEvent) - * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle the event). - * <p> - * Override this to intercept key long press events before they are processed by the - * application. If you return true, the application will not process the event itself. If - * you return false, the normal application processing will occur as if the TV input had not - * seen the event at all. - * - * @param keyCode The value in event.getKeyCode(). - * @param event Description of the key event. - * @return If you handled the event, return {@code true}. If you want to allow the event to - * be handled by the next receiver, return {@code false}. - */ - @Override - public boolean onKeyLongPress(int keyCode, KeyEvent event) { - return false; - } - - /** - * Default implementation of - * {@link android.view.KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) - * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle the event). - * <p> - * Override this to intercept special key multiple events before they are processed by the - * application. If you return true, the application will not itself process the event. If - * you return false, the normal application processing will occur as if the TV input had not - * seen the event at all. - * - * @param keyCode The value in event.getKeyCode(). - * @param count The number of times the action was made. - * @param event Description of the key event. - * @return If you handled the event, return {@code true}. If you want to allow the event to - * be handled by the next receiver, return {@code false}. - */ - @Override - public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) { - return false; - } - - /** - * Default implementation of {@link android.view.KeyEvent.Callback#onKeyUp(int, KeyEvent) - * KeyEvent.Callback.onKeyUp()}: always returns false (doesn't handle the event). - * <p> - * Override this to intercept key up events before they are processed by the application. If - * you return true, the application will not itself process the event. If you return false, - * the normal application processing will occur as if the TV input had not seen the event at - * all. - * - * @param keyCode The value in event.getKeyCode(). - * @param event Description of the key event. - * @return If you handled the event, return {@code true}. If you want to allow the event to - * be handled by the next receiver, return {@code false}. - */ - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - return false; - } - - /** - * Implement this method to handle touch screen motion events on the current input session. - * - * @param event The motion event being received. - * @return If you handled the event, return {@code true}. If you want to allow the event to - * be handled by the next receiver, return {@code false}. - * @see View#onTouchEvent - */ - public boolean onTouchEvent(MotionEvent event) { - return false; - } - - /** - * Implement this method to handle trackball events on the current input session. - * - * @param event The motion event being received. - * @return If you handled the event, return {@code true}. If you want to allow the event to - * be handled by the next receiver, return {@code false}. - * @see View#onTrackballEvent - */ - public boolean onTrackballEvent(MotionEvent event) { - return false; - } - - /** - * Implement this method to handle generic motion events on the current input session. - * - * @param event The motion event being received. - * @return If you handled the event, return {@code true}. If you want to allow the event to - * be handled by the next receiver, return {@code false}. - * @see View#onGenericMotionEvent - */ - public boolean onGenericMotionEvent(MotionEvent event) { - return false; - } - - /** - * This method is called when the application would like to stop using the current input - * session. - */ - void release() { - onRelease(); - if (mSurface != null) { - mSurface.release(); - mSurface = null; - } - removeOverlayView(true); - } - - /** - * Calls {@link #onSetSurface}. - */ - void setSurface(Surface surface) { - onSetSurface(surface); - if (mSurface != null) { - mSurface.release(); - } - mSurface = surface; - // TODO: Handle failure. - } - - /** - * Calls {@link #onSetVolume}. - */ - void setVolume(float volume) { - onSetVolume(volume); - } - - /** - * Calls {@link #onTune}. - */ - void tune(Uri channelUri) { - onTune(channelUri); - // TODO: Handle failure. - } - - /** - * Creates an overlay view. This calls {@link #onCreateOverlayView} to get a view to attach - * to the overlay window. - * - * @param windowToken A window token of an application. - * @param frame A position of the overlay view. - */ - void createOverlayView(IBinder windowToken, Rect frame) { - if (mOverlayView != null) { - mWindowManager.removeView(mOverlayView); - mOverlayView = null; - } - if (DEBUG) Log.d(TAG, "create overlay view(" + frame + ")"); - mWindowToken = windowToken; - mOverlayFrame = frame; - if (!mOverlayViewEnabled) { - return; - } - mOverlayView = onCreateOverlayView(); - if (mOverlayView == null) { - return; - } - // TvView's window type is TYPE_APPLICATION_MEDIA and we want to create - // an overlay window above the media window but below the application window. - int type = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY; - // We make the overlay view non-focusable and non-touchable so that - // the application that owns the window token can decide whether to consume or - // dispatch the input events. - int flag = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN - | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; - mWindowParams = new WindowManager.LayoutParams( - frame.right - frame.left, frame.bottom - frame.top, - frame.left, frame.top, type, flag, PixelFormat.TRANSPARENT); - mWindowParams.privateFlags |= - WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION; - mWindowParams.gravity = Gravity.START | Gravity.TOP; - mWindowParams.token = windowToken; - mWindowManager.addView(mOverlayView, mWindowParams); - } - - /** - * Relayouts the current overlay view. - * - * @param frame A new position of the overlay view. - */ - void relayoutOverlayView(Rect frame) { - if (DEBUG) Log.d(TAG, "relayoutOverlayView(" + frame + ")"); - mOverlayFrame = frame; - if (!mOverlayViewEnabled || mOverlayView == null) { - return; - } - mWindowParams.x = frame.left; - mWindowParams.y = frame.top; - mWindowParams.width = frame.right - frame.left; - mWindowParams.height = frame.bottom - frame.top; - mWindowManager.updateViewLayout(mOverlayView, mWindowParams); - } - - /** - * Removes the current overlay view. - */ - void removeOverlayView(boolean clearWindowToken) { - if (DEBUG) Log.d(TAG, "removeOverlayView(" + mOverlayView + ")"); - if (clearWindowToken) { - mWindowToken = null; - mOverlayFrame = null; - } - if (mOverlayView != null) { - mWindowManager.removeView(mOverlayView); - mOverlayView = null; - mWindowParams = null; - } - } - - /** - * Takes care of dispatching incoming input events and tells whether the event was handled. - */ - int dispatchInputEvent(InputEvent event, InputEventReceiver receiver) { - if (DEBUG) Log.d(TAG, "dispatchInputEvent(" + event + ")"); - if (event instanceof KeyEvent) { - if (((KeyEvent) event).dispatch(this, mDispatcherState, this)) { - return Session.DISPATCH_HANDLED; - } - } else if (event instanceof MotionEvent) { - MotionEvent motionEvent = (MotionEvent) event; - final int source = motionEvent.getSource(); - if (motionEvent.isTouchEvent()) { - if (onTouchEvent(motionEvent)) { - return Session.DISPATCH_HANDLED; - } - } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) { - if (onTrackballEvent(motionEvent)) { - return Session.DISPATCH_HANDLED; - } - } else { - if (onGenericMotionEvent(motionEvent)) { - return Session.DISPATCH_HANDLED; - } - } - } - if (mOverlayView == null || !mOverlayView.isAttachedToWindow()) { - return Session.DISPATCH_NOT_HANDLED; - } - if (!mOverlayView.hasWindowFocus()) { - mOverlayView.getViewRootImpl().windowFocusChanged(true, true); - } - mOverlayView.getViewRootImpl().dispatchInputEvent(event, receiver); - return Session.DISPATCH_IN_PROGRESS; - } - - private void setSessionCallback(ITvInputSessionCallback callback) { - mSessionCallback = callback; - } - } - - private final class ServiceHandler extends Handler { - private static final int DO_CREATE_SESSION = 1; - private static final int DO_BROADCAST_AVAILABILITY_CHANGE = 2; - - @Override - public final void handleMessage(Message msg) { - switch (msg.what) { - case DO_CREATE_SESSION: { - SomeArgs args = (SomeArgs) msg.obj; - InputChannel channel = (InputChannel) args.arg1; - ITvInputSessionCallback cb = (ITvInputSessionCallback) args.arg2; - try { - TvInputSessionImpl sessionImpl = onCreateSession(); - if (sessionImpl == null) { - // Failed to create a session. - cb.onSessionCreated(null); - } else { - sessionImpl.setSessionCallback(cb); - ITvInputSession stub = new ITvInputSessionWrapper(TvInputService.this, - sessionImpl, channel); - cb.onSessionCreated(stub); - } - } catch (RemoteException e) { - Log.e(TAG, "error in onSessionCreated"); - } - args.recycle(); - return; - } - case DO_BROADCAST_AVAILABILITY_CHANGE: { - boolean isAvailable = (Boolean) msg.obj; - int n = mCallbacks.beginBroadcast(); - try { - for (int i = 0; i < n; i++) { - mCallbacks.getBroadcastItem(i).onAvailabilityChanged(mId, isAvailable); - } - } catch (RemoteException e) { - Log.e(TAG, "Unexpected exception", e); - } finally { - mCallbacks.finishBroadcast(); - } - return; - } - default: { - Log.w(TAG, "Unhandled message code: " + msg.what); - return; - } - } - } - } -} diff --git a/core/java/android/tv/TvStreamConfig.aidl b/core/java/android/tv/TvStreamConfig.aidl deleted file mode 100644 index 4d0add4..0000000 --- a/core/java/android/tv/TvStreamConfig.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * - * Copyright 2014, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.tv; - -parcelable TvStreamConfig;
\ No newline at end of file diff --git a/core/java/android/tv/TvStreamConfig.java b/core/java/android/tv/TvStreamConfig.java deleted file mode 100644 index 03e63b1..0000000 --- a/core/java/android/tv/TvStreamConfig.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.tv; - -import android.os.Parcel; -import android.os.Parcelable; -import android.util.Log; - -/** - * @hide - */ -public class TvStreamConfig implements Parcelable { - static final String TAG = TvStreamConfig.class.getSimpleName(); - - public final static int STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE = 1; - public final static int STREAM_TYPE_BUFFER_PRODUCER = 2; - - private int mStreamId; - private int mType; - // TODO: Revisit if max widht/height really make sense. - private int mMaxWidth; - private int mMaxHeight; - /** - * Generations are incremented once framework receives STREAM_CONFIGURATION_CHANGED event from - * HAL module. Framework should throw away outdated configurations and get new configurations - * via tv_input_device::get_stream_configurations(). - */ - private int mGeneration; - - public static final Parcelable.Creator<TvStreamConfig> CREATOR = - new Parcelable.Creator<TvStreamConfig>() { - @Override - public TvStreamConfig createFromParcel(Parcel source) { - try { - return new Builder(). - streamId(source.readInt()). - type(source.readInt()). - maxWidth(source.readInt()). - maxHeight(source.readInt()). - generation(source.readInt()).build(); - } catch (Exception e) { - Log.e(TAG, "Exception creating TvStreamConfig from parcel", e); - return null; - } - } - - @Override - public TvStreamConfig[] newArray(int size) { - return new TvStreamConfig[size]; - } - }; - - private TvStreamConfig() {} - - public int getStreamId() { - return mStreamId; - } - - public int getType() { - return mType; - } - - public int getMaxWidth() { - return mMaxWidth; - } - - public int getMaxHeight() { - return mMaxHeight; - } - - public int getGeneration() { - return mGeneration; - } - - // Parcelable - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mStreamId); - dest.writeInt(mType); - dest.writeInt(mMaxWidth); - dest.writeInt(mMaxHeight); - dest.writeInt(mGeneration); - } - - /** - * A helper class for creating a TvStreamConfig object. - */ - public static final class Builder { - private Integer mStreamId; - private Integer mType; - private Integer mMaxWidth; - private Integer mMaxHeight; - private Integer mGeneration; - - public Builder() { - } - - public Builder streamId(int streamId) { - mStreamId = streamId; - return this; - } - - public Builder type(int type) { - mType = type; - return this; - } - - public Builder maxWidth(int maxWidth) { - mMaxWidth = maxWidth; - return this; - } - - public Builder maxHeight(int maxHeight) { - mMaxHeight = maxHeight; - return this; - } - - public Builder generation(int generation) { - mGeneration = generation; - return this; - } - - public TvStreamConfig build() { - if (mStreamId == null || mType == null || mMaxWidth == null || mMaxHeight == null - || mGeneration == null) { - throw new UnsupportedOperationException(); - } - - TvStreamConfig config = new TvStreamConfig(); - config.mStreamId = mStreamId; - config.mType = mType; - config.mMaxWidth = mMaxWidth; - config.mMaxHeight = mMaxHeight; - config.mGeneration = mGeneration; - return config; - } - } -}
\ No newline at end of file diff --git a/core/java/android/tv/TvView.java b/core/java/android/tv/TvView.java deleted file mode 100644 index 2d31701..0000000 --- a/core/java/android/tv/TvView.java +++ /dev/null @@ -1,402 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.tv; - -import android.content.Context; -import android.graphics.Rect; -import android.os.Bundle; -import android.os.Handler; -import android.text.TextUtils; -import android.tv.TvInputManager.Session; -import android.tv.TvInputManager.Session.FinishedInputEventCallback; -import android.tv.TvInputManager.SessionCallback; -import android.util.AttributeSet; -import android.util.Log; -import android.view.InputEvent; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.Surface; -import android.view.SurfaceHolder; -import android.view.SurfaceView; -import android.view.ViewRootImpl; - -/** - * View playing TV - */ -public class TvView extends SurfaceView { - // STOPSHIP: Turn debugging off. - private static final boolean DEBUG = true; - private static final String TAG = "TvView"; - - private final Handler mHandler = new Handler(); - private TvInputManager.Session mSession; - private Surface mSurface; - private boolean mOverlayViewCreated; - private Rect mOverlayViewFrame; - private final TvInputManager mTvInputManager; - private SessionCallback mSessionCallback; - private OnUnhandledInputEventListener mOnUnhandledInputEventListener; - - private final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() { - @Override - public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { - Log.d(TAG, "surfaceChanged(holder=" + holder + ", format=" + format + ", width=" + width - + ", height=" + height + ")"); - if (holder.getSurface() == mSurface) { - return; - } - mSurface = holder.getSurface(); - setSessionSurface(mSurface); - } - - @Override - public void surfaceCreated(SurfaceHolder holder) { - mSurface = holder.getSurface(); - setSessionSurface(mSurface); - } - - @Override - public void surfaceDestroyed(SurfaceHolder holder) { - mSurface = null; - setSessionSurface(null); - } - }; - - private final FinishedInputEventCallback mFinishedInputEventCallback = - new FinishedInputEventCallback() { - @Override - public void onFinishedInputEvent(Object token, boolean handled) { - if (DEBUG) { - Log.d(TAG, "onFinishedInputEvent(token=" + token + ", handled=" + handled + ")"); - } - if (handled) { - return; - } - // TODO: Re-order unhandled events. - InputEvent event = (InputEvent) token; - if (dispatchUnhandledInputEvent(event)) { - return; - } - ViewRootImpl viewRootImpl = getViewRootImpl(); - if (viewRootImpl != null) { - viewRootImpl.dispatchUnhandledInputEvent(event); - } - } - }; - - public TvView(Context context) { - this(context, null, 0); - } - - public TvView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public TvView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - getHolder().addCallback(mSurfaceHolderCallback); - mTvInputManager = (TvInputManager) getContext().getSystemService(Context.TV_INPUT_SERVICE); - } - - /** - * Binds a TV input to this view. {@link SessionCallback#onSessionCreated} will be - * called to send the result of this binding with {@link TvInputManager.Session}. - * If a TV input is already bound, the input will be unbound from this view and its session - * will be released. - * - * @param inputId the id of TV input which will be bound to this view. - * @param callback called when TV input is bound. The callback sends - * {@link TvInputManager.Session} - * @throws IllegalArgumentException if any of the arguments is {@code null}. - */ - public void bindTvInput(String inputId, SessionCallback callback) { - if (TextUtils.isEmpty(inputId)) { - throw new IllegalArgumentException("inputId cannot be null or an empty string"); - } - if (callback == null) { - throw new IllegalArgumentException("callback cannot be null"); - } - if (mSession != null) { - release(); - } - // When bindTvInput is called multiple times before the callback is called, - // only the callback of the last bindTvInput call will be actually called back. - // The previous callbacks will be ignored. For the logic, mSessionCallback - // is newly assigned for every bindTvInput call and compared with - // MySessionCreateCallback.this. - mSessionCallback = new MySessionCallback(callback); - mTvInputManager.createSession(inputId, mSessionCallback, mHandler); - } - - /** - * Unbinds a TV input currently bound. Its corresponding {@link TvInputManager.Session} - * is released. - */ - public void unbindTvInput() { - if (mSession != null) { - release(); - } - mSessionCallback = null; - } - - /** - * Dispatches an unhandled input event to the next receiver. - * <p> - * Except system keys, TvView always consumes input events in the normal flow. This is called - * asynchronously from where the event is dispatched. It gives the host application a chance to - * dispatch the unhandled input events. - * - * @param event The input event. - * @return {@code true} if the event was handled by the view, {@code false} otherwise. - */ - public boolean dispatchUnhandledInputEvent(InputEvent event) { - if (mOnUnhandledInputEventListener != null) { - if (mOnUnhandledInputEventListener.onUnhandledInputEvent(event)) { - return true; - } - } - return onUnhandledInputEvent(event); - } - - /** - * Called when an unhandled input event was also not handled by the user provided callback. This - * is the last chance to handle the unhandled input event in the TvView. - * - * @param event The input event. - * @return If you handled the event, return {@code true}. If you want to allow the event to be - * handled by the next receiver, return {@code false}. - */ - public boolean onUnhandledInputEvent(InputEvent event) { - return false; - } - - /** - * Registers a callback to be invoked when an input event was not handled by the bound TV input. - * - * @param listener The callback to invoke when the unhandled input event was received. - */ - public void setOnUnhandledInputEventListener(OnUnhandledInputEventListener listener) { - mOnUnhandledInputEventListener = listener; - } - - @Override - public boolean dispatchKeyEvent(KeyEvent event) { - if (super.dispatchKeyEvent(event)) { - return true; - } - if (DEBUG) Log.d(TAG, "dispatchKeyEvent(" + event + ")"); - if (mSession == null) { - return false; - } - InputEvent copiedEvent = event.copy(); - int ret = mSession.dispatchInputEvent(copiedEvent, copiedEvent, mFinishedInputEventCallback, - mHandler); - return ret != Session.DISPATCH_NOT_HANDLED; - } - - @Override - public boolean dispatchTouchEvent(MotionEvent event) { - if (super.dispatchTouchEvent(event)) { - return true; - } - if (DEBUG) Log.d(TAG, "dispatchTouchEvent(" + event + ")"); - if (mSession == null) { - return false; - } - InputEvent copiedEvent = event.copy(); - int ret = mSession.dispatchInputEvent(copiedEvent, copiedEvent, mFinishedInputEventCallback, - mHandler); - return ret != Session.DISPATCH_NOT_HANDLED; - } - - @Override - public boolean dispatchTrackballEvent(MotionEvent event) { - if (super.dispatchTrackballEvent(event)) { - return true; - } - if (DEBUG) Log.d(TAG, "dispatchTrackballEvent(" + event + ")"); - if (mSession == null) { - return false; - } - InputEvent copiedEvent = event.copy(); - int ret = mSession.dispatchInputEvent(copiedEvent, copiedEvent, mFinishedInputEventCallback, - mHandler); - return ret != Session.DISPATCH_NOT_HANDLED; - } - - @Override - public boolean dispatchGenericMotionEvent(MotionEvent event) { - if (super.dispatchGenericMotionEvent(event)) { - return true; - } - if (DEBUG) Log.d(TAG, "dispatchGenericMotionEvent(" + event + ")"); - if (mSession == null) { - return false; - } - InputEvent copiedEvent = event.copy(); - int ret = mSession.dispatchInputEvent(copiedEvent, copiedEvent, mFinishedInputEventCallback, - mHandler); - return ret != Session.DISPATCH_NOT_HANDLED; - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - createSessionOverlayView(); - } - - @Override - protected void onDetachedFromWindow() { - removeSessionOverlayView(); - super.onDetachedFromWindow(); - } - - /** @hide */ - @Override - protected void updateWindow(boolean force, boolean redrawNeeded) { - super.updateWindow(force, redrawNeeded); - relayoutSessionOverlayView(); - } - - private void release() { - setSessionSurface(null); - removeSessionOverlayView(); - mSession.release(); - mSession = null; - } - - private void setSessionSurface(Surface surface) { - if (mSession == null) { - return; - } - mSession.setSurface(surface); - } - - private void createSessionOverlayView() { - if (mSession == null || !isAttachedToWindow() - || mOverlayViewCreated) { - return; - } - mOverlayViewFrame = getViewFrameOnScreen(); - mSession.createOverlayView(this, mOverlayViewFrame); - mOverlayViewCreated = true; - } - - private void removeSessionOverlayView() { - if (mSession == null || !mOverlayViewCreated) { - return; - } - mSession.removeOverlayView(); - mOverlayViewCreated = false; - mOverlayViewFrame = null; - } - - private void relayoutSessionOverlayView() { - if (mSession == null || !isAttachedToWindow() - || !mOverlayViewCreated) { - return; - } - Rect viewFrame = getViewFrameOnScreen(); - if (viewFrame.equals(mOverlayViewFrame)) { - return; - } - mSession.relayoutOverlayView(viewFrame); - mOverlayViewFrame = viewFrame; - } - - private Rect getViewFrameOnScreen() { - int[] location = new int[2]; - getLocationOnScreen(location); - return new Rect(location[0], location[1], - location[0] + getWidth(), location[1] + getHeight()); - } - - /** - * Interface definition for a callback to be invoked when the unhandled input event is received. - */ - public interface OnUnhandledInputEventListener { - /** - * Called when an input event was not handled by the bound TV input. - * <p> - * This is called asynchronously from where the event is dispatched. It gives the host - * application a chance to handle the unhandled input events. - * - * @param event The input event. - * @return If you handled the event, return {@code true}. If you want to allow the event to - * be handled by the next receiver, return {@code false}. - */ - boolean onUnhandledInputEvent(InputEvent event); - } - - private class MySessionCallback extends SessionCallback { - final SessionCallback mExternalCallback; - - MySessionCallback(SessionCallback externalCallback) { - mExternalCallback = externalCallback; - } - - @Override - public void onSessionCreated(Session session) { - if (this != mSessionCallback) { - // This callback is obsolete. - if (session != null) { - session.release(); - } - return; - } - mSession = session; - if (session != null) { - // mSurface may not be ready yet as soon as starting an application. - // In the case, we don't send Session.setSurface(null) unnecessarily. - // setSessionSurface will be called in surfaceCreated. - if (mSurface != null) { - setSessionSurface(mSurface); - } - createSessionOverlayView(); - } - if (mExternalCallback != null) { - mExternalCallback.onSessionCreated(session); - } - } - - @Override - public void onSessionReleased(Session session) { - mSession = null; - if (mExternalCallback != null) { - mExternalCallback.onSessionReleased(session); - } - } - - @Override - public void onVideoSizeChanged(Session session, int width, int height) { - if (DEBUG) { - Log.d(TAG, "onVideoSizeChanged(" + width + ", " + height + ")"); - } - if (mExternalCallback != null) { - mExternalCallback.onVideoSizeChanged(session, width, height); - } - } - - @Override - public void onSessionEvent(TvInputManager.Session session, String eventType, - Bundle eventArgs) { - if (mExternalCallback != null) { - mExternalCallback.onSessionEvent(session, eventType, eventArgs); - } - } - } -} diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index 424d860..5056097 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -75,22 +75,10 @@ class GLES20Canvas extends HardwareCanvas { // Constructors /////////////////////////////////////////////////////////////////////////// - /** - * Creates a canvas to render directly on screen. - */ - GLES20Canvas(boolean translucent) { - this(false, translucent); - } - - protected GLES20Canvas(boolean record, boolean translucent) { - mOpaque = !translucent; - - if (record) { - mRenderer = nCreateDisplayListRenderer(); - } else { - mRenderer = nCreateRenderer(); - } - + // TODO: Merge with GLES20RecordingCanvas + protected GLES20Canvas() { + mOpaque = false; + mRenderer = nCreateDisplayListRenderer(); setupFinalizer(); } @@ -102,7 +90,6 @@ class GLES20Canvas extends HardwareCanvas { } } - private static native long nCreateRenderer(); private static native long nCreateDisplayListRenderer(); private static native void nResetDisplayListRenderer(long renderer); private static native void nDestroyRenderer(long renderer); @@ -131,36 +118,6 @@ class GLES20Canvas extends HardwareCanvas { private static native void nSetProperty(String name, String value); /////////////////////////////////////////////////////////////////////////// - // Hardware layers - /////////////////////////////////////////////////////////////////////////// - - @Override - void pushLayerUpdate(HardwareLayer layer) { - nPushLayerUpdate(mRenderer, layer.getLayer()); - } - - @Override - void cancelLayerUpdate(HardwareLayer layer) { - nCancelLayerUpdate(mRenderer, layer.getLayer()); - } - - @Override - void flushLayerUpdates() { - nFlushLayerUpdates(mRenderer); - } - - @Override - void clearLayerUpdates() { - nClearLayerUpdates(mRenderer); - } - - static native boolean nCopyLayer(long layerId, long bitmap); - private static native void nClearLayerUpdates(long renderer); - private static native void nFlushLayerUpdates(long renderer); - private static native void nPushLayerUpdate(long renderer, long layer); - private static native void nCancelLayerUpdate(long renderer, long layer); - - /////////////////////////////////////////////////////////////////////////// // Canvas management /////////////////////////////////////////////////////////////////////////// @@ -234,20 +191,6 @@ class GLES20Canvas extends HardwareCanvas { private static native void nFinish(long renderer); - /** - * Returns the size of the stencil buffer required by the underlying - * implementation. - * - * @return The minimum number of bits the stencil buffer must. Always >= 0. - * - * @hide - */ - public static int getStencilSize() { - return nGetStencilSize(); - } - - private static native int nGetStencilSize(); - /////////////////////////////////////////////////////////////////////////// // Functor /////////////////////////////////////////////////////////////////////////// @@ -284,49 +227,6 @@ class GLES20Canvas extends HardwareCanvas { */ static final int FLUSH_CACHES_FULL = 2; - /** - * Flush caches to reclaim as much memory as possible. The amount of memory - * to reclaim is indicate by the level parameter. - * - * The level can be one of {@link #FLUSH_CACHES_MODERATE} or - * {@link #FLUSH_CACHES_FULL}. - * - * @param level Hint about the amount of memory to reclaim - */ - static void flushCaches(int level) { - nFlushCaches(level); - } - - private static native void nFlushCaches(int level); - - /** - * Release all resources associated with the underlying caches. This should - * only be called after a full flushCaches(). - * - * @hide - */ - static void terminateCaches() { - nTerminateCaches(); - } - - private static native void nTerminateCaches(); - - static boolean initCaches() { - return nInitCaches(); - } - - private static native boolean nInitCaches(); - - /////////////////////////////////////////////////////////////////////////// - // Atlas - /////////////////////////////////////////////////////////////////////////// - - static void initAtlas(GraphicBuffer buffer, long[] map) { - nInitAtlas(buffer, map, map.length); - } - - private static native void nInitAtlas(GraphicBuffer buffer, long[] map, int count); - /////////////////////////////////////////////////////////////////////////// // Display list /////////////////////////////////////////////////////////////////////////// @@ -899,12 +799,6 @@ class GLES20Canvas extends HardwareCanvas { private static native void nDrawPath(long renderer, long path, long paint); private static native void nDrawRects(long renderer, long region, long paint); - void drawRects(float[] rects, int count, Paint paint) { - nDrawRects(mRenderer, rects, count, paint.mNativePaint); - } - - private static native void nDrawRects(long renderer, float[] rects, int count, long paint); - @Override public void drawPicture(Picture picture) { if (picture.createdFromStream) { diff --git a/core/java/android/view/GLES20RecordingCanvas.java b/core/java/android/view/GLES20RecordingCanvas.java index a94ec3a..b2961e5 100644 --- a/core/java/android/view/GLES20RecordingCanvas.java +++ b/core/java/android/view/GLES20RecordingCanvas.java @@ -36,7 +36,7 @@ class GLES20RecordingCanvas extends GLES20Canvas { RenderNode mNode; private GLES20RecordingCanvas() { - super(true, true); + super(); } static GLES20RecordingCanvas obtain(@NonNull RenderNode node) { diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java deleted file mode 100644 index f1163e2..0000000 --- a/core/java/android/view/GLRenderer.java +++ /dev/null @@ -1,1521 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.view; - -import static javax.microedition.khronos.egl.EGL10.EGL_ALPHA_SIZE; -import static javax.microedition.khronos.egl.EGL10.EGL_BAD_NATIVE_WINDOW; -import static javax.microedition.khronos.egl.EGL10.EGL_BLUE_SIZE; -import static javax.microedition.khronos.egl.EGL10.EGL_CONFIG_CAVEAT; -import static javax.microedition.khronos.egl.EGL10.EGL_DEFAULT_DISPLAY; -import static javax.microedition.khronos.egl.EGL10.EGL_DEPTH_SIZE; -import static javax.microedition.khronos.egl.EGL10.EGL_DRAW; -import static javax.microedition.khronos.egl.EGL10.EGL_GREEN_SIZE; -import static javax.microedition.khronos.egl.EGL10.EGL_HEIGHT; -import static javax.microedition.khronos.egl.EGL10.EGL_NONE; -import static javax.microedition.khronos.egl.EGL10.EGL_NO_CONTEXT; -import static javax.microedition.khronos.egl.EGL10.EGL_NO_DISPLAY; -import static javax.microedition.khronos.egl.EGL10.EGL_NO_SURFACE; -import static javax.microedition.khronos.egl.EGL10.EGL_RED_SIZE; -import static javax.microedition.khronos.egl.EGL10.EGL_RENDERABLE_TYPE; -import static javax.microedition.khronos.egl.EGL10.EGL_SAMPLES; -import static javax.microedition.khronos.egl.EGL10.EGL_SAMPLE_BUFFERS; -import static javax.microedition.khronos.egl.EGL10.EGL_STENCIL_SIZE; -import static javax.microedition.khronos.egl.EGL10.EGL_SUCCESS; -import static javax.microedition.khronos.egl.EGL10.EGL_SURFACE_TYPE; -import static javax.microedition.khronos.egl.EGL10.EGL_WIDTH; -import static javax.microedition.khronos.egl.EGL10.EGL_WINDOW_BIT; - -import android.content.ComponentCallbacks2; -import android.graphics.Bitmap; -import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.SurfaceTexture; -import android.opengl.EGL14; -import android.opengl.GLUtils; -import android.opengl.ManagedEGLContext; -import android.os.Handler; -import android.os.IBinder; -import android.os.Looper; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.SystemClock; -import android.os.SystemProperties; -import android.os.Trace; -import android.util.DisplayMetrics; -import android.util.Log; -import android.view.Surface.OutOfResourcesException; - -import com.google.android.gles_jni.EGLImpl; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.locks.ReentrantLock; - -import javax.microedition.khronos.egl.EGL10; -import javax.microedition.khronos.egl.EGL11; -import javax.microedition.khronos.egl.EGLConfig; -import javax.microedition.khronos.egl.EGLContext; -import javax.microedition.khronos.egl.EGLDisplay; -import javax.microedition.khronos.egl.EGLSurface; -import javax.microedition.khronos.opengles.GL; - -/** - * Hardware renderer using OpenGL - * - * @hide - */ -public class GLRenderer extends HardwareRenderer { - static final int SURFACE_STATE_ERROR = 0; - static final int SURFACE_STATE_SUCCESS = 1; - static final int SURFACE_STATE_UPDATED = 2; - - static final int FUNCTOR_PROCESS_DELAY = 4; - - /** - * Number of frames to profile. - */ - private static final int PROFILE_MAX_FRAMES = 128; - - /** - * Number of floats per profiled frame. - */ - private static final int PROFILE_FRAME_DATA_COUNT = 3; - - private static final int PROFILE_DRAW_MARGIN = 0; - private static final int PROFILE_DRAW_WIDTH = 3; - private static final int[] PROFILE_DRAW_COLORS = { 0xcf3e66cc, 0xcfdc3912, 0xcfe69800 }; - private static final int PROFILE_DRAW_CURRENT_FRAME_COLOR = 0xcf5faa4d; - private static final int PROFILE_DRAW_THRESHOLD_COLOR = 0xff5faa4d; - private static final int PROFILE_DRAW_THRESHOLD_STROKE_WIDTH = 2; - private static final int PROFILE_DRAW_DP_PER_MS = 7; - - private static final String[] VISUALIZERS = { - PROFILE_PROPERTY_VISUALIZE_BARS, - }; - - private static final String[] OVERDRAW = { - OVERDRAW_PROPERTY_SHOW, - }; - private static final int GL_VERSION = 2; - - static EGL10 sEgl; - static EGLDisplay sEglDisplay; - static EGLConfig sEglConfig; - static final Object[] sEglLock = new Object[0]; - int mWidth = -1, mHeight = -1; - - static final ThreadLocal<ManagedEGLContext> sEglContextStorage - = new ThreadLocal<ManagedEGLContext>(); - - EGLContext mEglContext; - Thread mEglThread; - - EGLSurface mEglSurface; - - GL mGl; - HardwareCanvas mCanvas; - - String mName; - - long mFrameCount; - Paint mDebugPaint; - - static boolean sDirtyRegions; - static final boolean sDirtyRegionsRequested; - static { - String dirtyProperty = SystemProperties.get(RENDER_DIRTY_REGIONS_PROPERTY, "true"); - //noinspection PointlessBooleanExpression,ConstantConditions - sDirtyRegions = "true".equalsIgnoreCase(dirtyProperty); - sDirtyRegionsRequested = sDirtyRegions; - } - - boolean mDirtyRegionsEnabled; - boolean mUpdateDirtyRegions; - - boolean mProfileEnabled; - int mProfileVisualizerType = -1; - float[] mProfileData; - ReentrantLock mProfileLock; - int mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT; - - GraphDataProvider mDebugDataProvider; - float[][] mProfileShapes; - Paint mProfilePaint; - - boolean mDebugDirtyRegions; - int mDebugOverdraw = -1; - - final boolean mTranslucent; - - private boolean mDestroyed; - - private final Rect mRedrawClip = new Rect(); - - private final int[] mSurfaceSize = new int[2]; - - private long mDrawDelta = Long.MAX_VALUE; - - private GLES20Canvas mGlCanvas; - - private DisplayMetrics mDisplayMetrics; - - private static EGLSurface sPbuffer; - private static final Object[] sPbufferLock = new Object[0]; - - private List<HardwareLayer> mLayerUpdates = new ArrayList<HardwareLayer>(); - - private static class GLRendererEglContext extends ManagedEGLContext { - final Handler mHandler = new Handler(); - - public GLRendererEglContext(EGLContext context) { - super(context); - } - - @Override - public void onTerminate(final EGLContext eglContext) { - // Make sure we do this on the correct thread. - if (mHandler.getLooper() != Looper.myLooper()) { - mHandler.post(new Runnable() { - @Override - public void run() { - onTerminate(eglContext); - } - }); - return; - } - - synchronized (sEglLock) { - if (sEgl == null) return; - - if (EGLImpl.getInitCount(sEglDisplay) == 1) { - usePbufferSurface(eglContext); - GLES20Canvas.terminateCaches(); - - sEgl.eglDestroyContext(sEglDisplay, eglContext); - sEglContextStorage.set(null); - sEglContextStorage.remove(); - - sEgl.eglDestroySurface(sEglDisplay, sPbuffer); - sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, - EGL_NO_SURFACE, EGL_NO_CONTEXT); - - sEgl.eglReleaseThread(); - sEgl.eglTerminate(sEglDisplay); - - sEgl = null; - sEglDisplay = null; - sEglConfig = null; - sPbuffer = null; - } - } - } - } - - HardwareCanvas createCanvas() { - return mGlCanvas = new GLES20Canvas(mTranslucent); - } - - ManagedEGLContext createManagedContext(EGLContext eglContext) { - return new GLRendererEglContext(mEglContext); - } - - int[] getConfig(boolean dirtyRegions) { - //noinspection PointlessBooleanExpression,ConstantConditions - final int stencilSize = GLES20Canvas.getStencilSize(); - final int swapBehavior = dirtyRegions ? EGL14.EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0; - - return new int[] { - EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT, - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_ALPHA_SIZE, 8, - EGL_DEPTH_SIZE, 0, - EGL_CONFIG_CAVEAT, EGL_NONE, - EGL_STENCIL_SIZE, stencilSize, - EGL_SURFACE_TYPE, EGL_WINDOW_BIT | swapBehavior, - EGL_NONE - }; - } - - void initCaches() { - if (GLES20Canvas.initCaches()) { - // Caches were (re)initialized, rebind atlas - initAtlas(); - } - } - - void initAtlas() { - IBinder binder = ServiceManager.getService("assetatlas"); - if (binder == null) return; - - IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder); - try { - if (atlas.isCompatible(android.os.Process.myPpid())) { - GraphicBuffer buffer = atlas.getBuffer(); - if (buffer != null) { - long[] map = atlas.getMap(); - if (map != null) { - GLES20Canvas.initAtlas(buffer, map); - } - // If IAssetAtlas is not the same class as the IBinder - // we are using a remote service and we can safely - // destroy the graphic buffer - if (atlas.getClass() != binder.getClass()) { - buffer.destroy(); - } - } - } - } catch (RemoteException e) { - Log.w(LOG_TAG, "Could not acquire atlas", e); - } - } - - boolean canDraw() { - return mGl != null && mCanvas != null && mGlCanvas != null; - } - - int onPreDraw(Rect dirty) { - return mGlCanvas.onPreDraw(dirty); - } - - void onPostDraw() { - mGlCanvas.onPostDraw(); - } - - void drawProfileData(View.AttachInfo attachInfo) { - if (mDebugDataProvider != null) { - final GraphDataProvider provider = mDebugDataProvider; - initProfileDrawData(attachInfo, provider); - - final int height = provider.getVerticalUnitSize(); - final int margin = provider.getHorizontaUnitMargin(); - final int width = provider.getHorizontalUnitSize(); - - int x = 0; - int count = 0; - int current = 0; - - final float[] data = provider.getData(); - final int elementCount = provider.getElementCount(); - final int graphType = provider.getGraphType(); - - int totalCount = provider.getFrameCount() * elementCount; - if (graphType == GraphDataProvider.GRAPH_TYPE_LINES) { - totalCount -= elementCount; - } - - for (int i = 0; i < totalCount; i += elementCount) { - if (data[i] < 0.0f) break; - - int index = count * 4; - if (i == provider.getCurrentFrame() * elementCount) current = index; - - x += margin; - int x2 = x + width; - - int y2 = mHeight; - int y1 = (int) (y2 - data[i] * height); - - switch (graphType) { - case GraphDataProvider.GRAPH_TYPE_BARS: { - for (int j = 0; j < elementCount; j++) { - //noinspection MismatchedReadAndWriteOfArray - final float[] r = mProfileShapes[j]; - r[index] = x; - r[index + 1] = y1; - r[index + 2] = x2; - r[index + 3] = y2; - - y2 = y1; - if (j < elementCount - 1) { - y1 = (int) (y2 - data[i + j + 1] * height); - } - } - } break; - case GraphDataProvider.GRAPH_TYPE_LINES: { - for (int j = 0; j < elementCount; j++) { - //noinspection MismatchedReadAndWriteOfArray - final float[] r = mProfileShapes[j]; - r[index] = (x + x2) * 0.5f; - r[index + 1] = index == 0 ? y1 : r[index - 1]; - r[index + 2] = r[index] + width; - r[index + 3] = y1; - - y2 = y1; - if (j < elementCount - 1) { - y1 = (int) (y2 - data[i + j + 1] * height); - } - } - } break; - } - - - x += width; - count++; - } - - x += margin; - - drawGraph(graphType, count); - drawCurrentFrame(graphType, current); - drawThreshold(x, height); - } - } - - private void drawGraph(int graphType, int count) { - for (int i = 0; i < mProfileShapes.length; i++) { - mDebugDataProvider.setupGraphPaint(mProfilePaint, i); - switch (graphType) { - case GraphDataProvider.GRAPH_TYPE_BARS: - mGlCanvas.drawRects(mProfileShapes[i], count * 4, mProfilePaint); - break; - case GraphDataProvider.GRAPH_TYPE_LINES: - mGlCanvas.drawLines(mProfileShapes[i], 0, count * 4, mProfilePaint); - break; - } - } - } - - private void drawCurrentFrame(int graphType, int index) { - if (index >= 0) { - mDebugDataProvider.setupCurrentFramePaint(mProfilePaint); - switch (graphType) { - case GraphDataProvider.GRAPH_TYPE_BARS: - mGlCanvas.drawRect(mProfileShapes[2][index], mProfileShapes[2][index + 1], - mProfileShapes[2][index + 2], mProfileShapes[0][index + 3], - mProfilePaint); - break; - case GraphDataProvider.GRAPH_TYPE_LINES: - mGlCanvas.drawLine(mProfileShapes[2][index], mProfileShapes[2][index + 1], - mProfileShapes[2][index], mHeight, mProfilePaint); - break; - } - } - } - - private void drawThreshold(int x, int height) { - float threshold = mDebugDataProvider.getThreshold(); - if (threshold > 0.0f) { - mDebugDataProvider.setupThresholdPaint(mProfilePaint); - int y = (int) (mHeight - threshold * height); - mGlCanvas.drawLine(0.0f, y, x, y, mProfilePaint); - } - } - - private void initProfileDrawData(View.AttachInfo attachInfo, GraphDataProvider provider) { - if (mProfileShapes == null) { - final int elementCount = provider.getElementCount(); - final int frameCount = provider.getFrameCount(); - - mProfileShapes = new float[elementCount][]; - for (int i = 0; i < elementCount; i++) { - mProfileShapes[i] = new float[frameCount * 4]; - } - - mProfilePaint = new Paint(); - } - - mProfilePaint.reset(); - if (provider.getGraphType() == GraphDataProvider.GRAPH_TYPE_LINES) { - mProfilePaint.setAntiAlias(true); - } - - if (mDisplayMetrics == null) { - mDisplayMetrics = new DisplayMetrics(); - } - - attachInfo.mDisplay.getMetrics(mDisplayMetrics); - provider.prepare(mDisplayMetrics); - } - - @Override - void destroy(boolean full) { - try { - if (full && mCanvas != null) { - mCanvas = null; - } - - if (!isEnabled() || mDestroyed) { - setEnabled(false); - return; - } - - destroySurface(); - setEnabled(false); - - mDestroyed = true; - mGl = null; - } finally { - if (full && mGlCanvas != null) { - mGlCanvas = null; - } - } - } - - @Override - void pushLayerUpdate(HardwareLayer layer) { - mLayerUpdates.add(layer); - } - - @Override - void flushLayerUpdates() { - if (validate()) { - flushLayerChanges(); - mGlCanvas.flushLayerUpdates(); - } - } - - @Override - HardwareLayer createTextureLayer() { - validate(); - return HardwareLayer.createTextureLayer(this); - } - - @Override - public HardwareLayer createDisplayListLayer(int width, int height) { - validate(); - return HardwareLayer.createDisplayListLayer(this, width, height); - } - - boolean hasContext() { - return sEgl != null && mEglContext != null - && mEglContext.equals(sEgl.eglGetCurrentContext()); - } - - @Override - void onLayerDestroyed(HardwareLayer layer) { - if (mGlCanvas != null) { - mGlCanvas.cancelLayerUpdate(layer); - } - mLayerUpdates.remove(layer); - } - - @Override - public SurfaceTexture createSurfaceTexture(HardwareLayer layer) { - return layer.createSurfaceTexture(); - } - - @Override - boolean copyLayerInto(HardwareLayer layer, Bitmap bitmap) { - if (!validate()) { - throw new IllegalStateException("Could not acquire hardware rendering context"); - } - layer.flushChanges(); - return GLES20Canvas.nCopyLayer(layer.getLayer(), bitmap.mNativeBitmap); - } - - @Override - boolean safelyRun(Runnable action) { - boolean needsContext = !isEnabled() || checkRenderContext() == SURFACE_STATE_ERROR; - - if (needsContext) { - GLRendererEglContext managedContext = - (GLRendererEglContext) sEglContextStorage.get(); - if (managedContext == null) return false; - usePbufferSurface(managedContext.getContext()); - } - - try { - action.run(); - } finally { - if (needsContext) { - sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, - EGL_NO_SURFACE, EGL_NO_CONTEXT); - } - } - - return true; - } - - @Override - void invokeFunctor(long functor, boolean waitForCompletion) { - boolean needsContext = !isEnabled() || checkRenderContext() == SURFACE_STATE_ERROR; - boolean hasContext = !needsContext; - - if (needsContext) { - GLRendererEglContext managedContext = - (GLRendererEglContext) sEglContextStorage.get(); - if (managedContext != null) { - usePbufferSurface(managedContext.getContext()); - hasContext = true; - } - } - - try { - nInvokeFunctor(functor, hasContext); - } finally { - if (needsContext) { - sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, - EGL_NO_SURFACE, EGL_NO_CONTEXT); - } - } - } - - private static native void nInvokeFunctor(long functor, boolean hasContext); - - @Override - void destroyHardwareResources(final View view) { - if (view != null) { - safelyRun(new Runnable() { - @Override - public void run() { - if (mCanvas != null) { - mCanvas.clearLayerUpdates(); - } - destroyResources(view); - GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS); - } - }); - } - } - - private static void destroyResources(View view) { - view.destroyHardwareResources(); - - if (view instanceof ViewGroup) { - ViewGroup group = (ViewGroup) view; - - int count = group.getChildCount(); - for (int i = 0; i < count; i++) { - destroyResources(group.getChildAt(i)); - } - } - } - - static void startTrimMemory(int level) { - if (sEgl == null || sEglConfig == null) return; - - GLRendererEglContext managedContext = - (GLRendererEglContext) sEglContextStorage.get(); - // We do not have OpenGL objects - if (managedContext == null) { - return; - } else { - usePbufferSurface(managedContext.getContext()); - } - - if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) { - GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_FULL); - } else if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { - GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_MODERATE); - } - } - - static void endTrimMemory() { - if (sEgl != null && sEglDisplay != null) { - sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - } - } - - private static void usePbufferSurface(EGLContext eglContext) { - synchronized (sPbufferLock) { - // Create a temporary 1x1 pbuffer so we have a context - // to clear our OpenGL objects - if (sPbuffer == null) { - sPbuffer = sEgl.eglCreatePbufferSurface(sEglDisplay, sEglConfig, new int[] { - EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE - }); - } - } - sEgl.eglMakeCurrent(sEglDisplay, sPbuffer, sPbuffer, eglContext); - } - - GLRenderer(boolean translucent) { - mTranslucent = translucent; - - loadSystemProperties(); - } - - @Override - void setOpaque(boolean opaque) { - // Not supported - } - - @Override - boolean loadSystemProperties() { - boolean value; - boolean changed = false; - - String profiling = SystemProperties.get(PROFILE_PROPERTY); - int graphType = search(VISUALIZERS, profiling); - value = graphType >= 0; - - if (graphType != mProfileVisualizerType) { - changed = true; - mProfileVisualizerType = graphType; - - mProfileShapes = null; - mProfilePaint = null; - - if (value) { - mDebugDataProvider = new GraphDataProvider(graphType); - } else { - mDebugDataProvider = null; - } - } - - // If on-screen profiling is not enabled, we need to check whether - // console profiling only is enabled - if (!value) { - value = Boolean.parseBoolean(profiling); - } - - if (value != mProfileEnabled) { - changed = true; - mProfileEnabled = value; - - if (mProfileEnabled) { - Log.d(LOG_TAG, "Profiling hardware renderer"); - - int maxProfileFrames = SystemProperties.getInt(PROFILE_MAXFRAMES_PROPERTY, - PROFILE_MAX_FRAMES); - mProfileData = new float[maxProfileFrames * PROFILE_FRAME_DATA_COUNT]; - for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) { - mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1; - } - - mProfileLock = new ReentrantLock(); - } else { - mProfileData = null; - mProfileLock = null; - mProfileVisualizerType = -1; - } - - mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT; - } - - value = SystemProperties.getBoolean(DEBUG_DIRTY_REGIONS_PROPERTY, false); - if (value != mDebugDirtyRegions) { - changed = true; - mDebugDirtyRegions = value; - - if (mDebugDirtyRegions) { - Log.d(LOG_TAG, "Debugging dirty regions"); - } - } - - String overdraw = SystemProperties.get(HardwareRenderer.DEBUG_OVERDRAW_PROPERTY); - int debugOverdraw = search(OVERDRAW, overdraw); - if (debugOverdraw != mDebugOverdraw) { - changed = true; - mDebugOverdraw = debugOverdraw; - } - - if (loadProperties()) { - changed = true; - } - - return changed; - } - - private static int search(String[] values, String value) { - for (int i = 0; i < values.length; i++) { - if (values[i].equals(value)) return i; - } - return -1; - } - - @Override - void dumpGfxInfo(PrintWriter pw, FileDescriptor fd) { - if (mProfileEnabled) { - pw.printf("\n\tDraw\tProcess\tExecute\n"); - - mProfileLock.lock(); - try { - for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) { - if (mProfileData[i] < 0) { - break; - } - pw.printf("\t%3.2f\t%3.2f\t%3.2f\n", mProfileData[i], mProfileData[i + 1], - mProfileData[i + 2]); - mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1; - } - mProfileCurrentFrame = mProfileData.length; - } finally { - mProfileLock.unlock(); - } - } - } - - /** - * Indicates whether this renderer instance can track and update dirty regions. - */ - boolean hasDirtyRegions() { - return mDirtyRegionsEnabled; - } - - /** - * Checks for OpenGL errors. If an error has occured, {@link #destroy(boolean)} - * is invoked and the requested flag is turned off. The error code is - * also logged as a warning. - */ - void checkEglErrors() { - if (isEnabled()) { - checkEglErrorsForced(); - } - } - - private void checkEglErrorsForced() { - int error = sEgl.eglGetError(); - if (error != EGL_SUCCESS) { - // something bad has happened revert to - // normal rendering. - Log.w(LOG_TAG, "EGL error: " + GLUtils.getEGLErrorString(error)); - fallback(error != EGL11.EGL_CONTEXT_LOST); - } - } - - private void fallback(boolean fallback) { - destroy(true); - if (fallback) { - // we'll try again if it was context lost - setRequested(false); - Log.w(LOG_TAG, "Mountain View, we've had a problem here. " - + "Switching back to software rendering."); - } - } - - @Override - boolean initialize(Surface surface) throws OutOfResourcesException { - if (isRequested() && !isEnabled()) { - boolean contextCreated = initializeEgl(); - mGl = createEglSurface(surface); - mDestroyed = false; - - if (mGl != null) { - int err = sEgl.eglGetError(); - if (err != EGL_SUCCESS) { - destroy(true); - setRequested(false); - } else { - if (mCanvas == null) { - mCanvas = createCanvas(); - } - setEnabled(true); - - if (contextCreated) { - initAtlas(); - } - } - - return mCanvas != null; - } - } - return false; - } - - @Override - void updateSurface(Surface surface) throws OutOfResourcesException { - if (isRequested() && isEnabled()) { - createEglSurface(surface); - } - } - - @Override - void pauseSurface(Surface surface) { - // No-op - } - - boolean initializeEgl() { - synchronized (sEglLock) { - if (sEgl == null && sEglConfig == null) { - sEgl = (EGL10) EGLContext.getEGL(); - - // Get to the default display. - sEglDisplay = sEgl.eglGetDisplay(EGL_DEFAULT_DISPLAY); - - if (sEglDisplay == EGL_NO_DISPLAY) { - throw new RuntimeException("eglGetDisplay failed " - + GLUtils.getEGLErrorString(sEgl.eglGetError())); - } - - // We can now initialize EGL for that display - int[] version = new int[2]; - if (!sEgl.eglInitialize(sEglDisplay, version)) { - throw new RuntimeException("eglInitialize failed " + - GLUtils.getEGLErrorString(sEgl.eglGetError())); - } - - checkEglErrorsForced(); - - sEglConfig = loadEglConfig(); - } - } - - ManagedEGLContext managedContext = sEglContextStorage.get(); - mEglContext = managedContext != null ? managedContext.getContext() : null; - mEglThread = Thread.currentThread(); - - if (mEglContext == null) { - mEglContext = createContext(sEgl, sEglDisplay, sEglConfig); - sEglContextStorage.set(createManagedContext(mEglContext)); - return true; - } - - return false; - } - - private EGLConfig loadEglConfig() { - EGLConfig eglConfig = chooseEglConfig(); - if (eglConfig == null) { - // We tried to use EGL_SWAP_BEHAVIOR_PRESERVED_BIT, try again without - if (sDirtyRegions) { - sDirtyRegions = false; - eglConfig = chooseEglConfig(); - if (eglConfig == null) { - throw new RuntimeException("eglConfig not initialized"); - } - } else { - throw new RuntimeException("eglConfig not initialized"); - } - } - return eglConfig; - } - - private EGLConfig chooseEglConfig() { - EGLConfig[] configs = new EGLConfig[1]; - int[] configsCount = new int[1]; - int[] configSpec = getConfig(sDirtyRegions); - - // Debug - final String debug = SystemProperties.get(PRINT_CONFIG_PROPERTY, ""); - if ("all".equalsIgnoreCase(debug)) { - sEgl.eglChooseConfig(sEglDisplay, configSpec, null, 0, configsCount); - - EGLConfig[] debugConfigs = new EGLConfig[configsCount[0]]; - sEgl.eglChooseConfig(sEglDisplay, configSpec, debugConfigs, - configsCount[0], configsCount); - - for (EGLConfig config : debugConfigs) { - printConfig(config); - } - } - - if (!sEgl.eglChooseConfig(sEglDisplay, configSpec, configs, 1, configsCount)) { - throw new IllegalArgumentException("eglChooseConfig failed " + - GLUtils.getEGLErrorString(sEgl.eglGetError())); - } else if (configsCount[0] > 0) { - if ("choice".equalsIgnoreCase(debug)) { - printConfig(configs[0]); - } - return configs[0]; - } - - return null; - } - - private static void printConfig(EGLConfig config) { - int[] value = new int[1]; - - Log.d(LOG_TAG, "EGL configuration " + config + ":"); - - sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_RED_SIZE, value); - Log.d(LOG_TAG, " RED_SIZE = " + value[0]); - - sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_GREEN_SIZE, value); - Log.d(LOG_TAG, " GREEN_SIZE = " + value[0]); - - sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_BLUE_SIZE, value); - Log.d(LOG_TAG, " BLUE_SIZE = " + value[0]); - - sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_ALPHA_SIZE, value); - Log.d(LOG_TAG, " ALPHA_SIZE = " + value[0]); - - sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_DEPTH_SIZE, value); - Log.d(LOG_TAG, " DEPTH_SIZE = " + value[0]); - - sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_STENCIL_SIZE, value); - Log.d(LOG_TAG, " STENCIL_SIZE = " + value[0]); - - sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SAMPLE_BUFFERS, value); - Log.d(LOG_TAG, " SAMPLE_BUFFERS = " + value[0]); - - sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SAMPLES, value); - Log.d(LOG_TAG, " SAMPLES = " + value[0]); - - sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SURFACE_TYPE, value); - Log.d(LOG_TAG, " SURFACE_TYPE = 0x" + Integer.toHexString(value[0])); - - sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_CONFIG_CAVEAT, value); - Log.d(LOG_TAG, " CONFIG_CAVEAT = 0x" + Integer.toHexString(value[0])); - } - - GL createEglSurface(Surface surface) throws OutOfResourcesException { - // Check preconditions. - if (sEgl == null) { - throw new RuntimeException("egl not initialized"); - } - if (sEglDisplay == null) { - throw new RuntimeException("eglDisplay not initialized"); - } - if (sEglConfig == null) { - throw new RuntimeException("eglConfig not initialized"); - } - if (Thread.currentThread() != mEglThread) { - throw new IllegalStateException("HardwareRenderer cannot be used " - + "from multiple threads"); - } - - // In case we need to destroy an existing surface - destroySurface(); - - // Create an EGL surface we can render into. - if (!createSurface(surface)) { - return null; - } - - initCaches(); - - return mEglContext.getGL(); - } - - private void enableDirtyRegions() { - // If mDirtyRegions is set, this means we have an EGL configuration - // with EGL_SWAP_BEHAVIOR_PRESERVED_BIT set - if (sDirtyRegions) { - if (!(mDirtyRegionsEnabled = preserveBackBuffer())) { - Log.w(LOG_TAG, "Backbuffer cannot be preserved"); - } - } else if (sDirtyRegionsRequested) { - // If mDirtyRegions is not set, our EGL configuration does not - // have EGL_SWAP_BEHAVIOR_PRESERVED_BIT; however, the default - // swap behavior might be EGL_BUFFER_PRESERVED, which means we - // want to set mDirtyRegions. We try to do this only if dirty - // regions were initially requested as part of the device - // configuration (see RENDER_DIRTY_REGIONS) - mDirtyRegionsEnabled = isBackBufferPreserved(); - } - } - - EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) { - final int[] attribs = { EGL14.EGL_CONTEXT_CLIENT_VERSION, GL_VERSION, EGL_NONE }; - - EGLContext context = egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, - attribs); - if (context == null || context == EGL_NO_CONTEXT) { - //noinspection ConstantConditions - throw new IllegalStateException( - "Could not create an EGL context. eglCreateContext failed with error: " + - GLUtils.getEGLErrorString(sEgl.eglGetError())); - } - - return context; - } - - void destroySurface() { - if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) { - if (mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW))) { - sEgl.eglMakeCurrent(sEglDisplay, - EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - } - sEgl.eglDestroySurface(sEglDisplay, mEglSurface); - mEglSurface = null; - } - } - - @Override - void invalidate(Surface surface) { - // Cancels any existing buffer to ensure we'll get a buffer - // of the right size before we call eglSwapBuffers - sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - - if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) { - sEgl.eglDestroySurface(sEglDisplay, mEglSurface); - mEglSurface = null; - setEnabled(false); - } - - if (surface.isValid()) { - if (!createSurface(surface)) { - return; - } - - mUpdateDirtyRegions = true; - - if (mCanvas != null) { - setEnabled(true); - } - } - } - - private boolean createSurface(Surface surface) { - mEglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, surface, null); - - if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) { - int error = sEgl.eglGetError(); - if (error == EGL_BAD_NATIVE_WINDOW) { - Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW."); - return false; - } - throw new RuntimeException("createWindowSurface failed " - + GLUtils.getEGLErrorString(error)); - } - - if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) { - throw new IllegalStateException("eglMakeCurrent failed " + - GLUtils.getEGLErrorString(sEgl.eglGetError())); - } - - enableDirtyRegions(); - - return true; - } - - boolean validate() { - return checkRenderContext() != SURFACE_STATE_ERROR; - } - - @Override - void setup(int width, int height, float lightX, float lightY, float lightZ, float lightRadius) { - if (validate()) { - mCanvas.setViewport(width, height); - mCanvas.initializeLight(lightX, lightY, lightZ, lightRadius); - mWidth = width; - mHeight = height; - } - } - - @Override - int getWidth() { - return mWidth; - } - - @Override - int getHeight() { - return mHeight; - } - - @Override - void setName(String name) { - mName = name; - } - - @Override - void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks, - Rect dirty) { - if (canDraw()) { - if (!hasDirtyRegions()) { - dirty = null; - } - attachInfo.mIgnoreDirtyState = true; - attachInfo.mDrawingTime = SystemClock.uptimeMillis(); - - view.mPrivateFlags |= View.PFLAG_DRAWN; - - // We are already on the correct thread - final int surfaceState = checkRenderContextUnsafe(); - if (surfaceState != SURFACE_STATE_ERROR) { - HardwareCanvas canvas = mCanvas; - - if (mProfileEnabled) { - mProfileLock.lock(); - } - - dirty = beginFrame(canvas, dirty, surfaceState); - - RenderNode displayList = buildDisplayList(view, canvas); - - flushLayerChanges(); - - // buildDisplayList() calls into user code which can cause - // an eglMakeCurrent to happen with a different surface/context. - // We must therefore check again here. - if (checkRenderContextUnsafe() == SURFACE_STATE_ERROR) { - return; - } - - int saveCount = 0; - int status = RenderNode.STATUS_DONE; - - long start = getSystemTime(); - try { - status = prepareFrame(dirty); - - saveCount = canvas.save(); - callbacks.onHardwarePreDraw(canvas); - - if (displayList != null) { - status |= drawDisplayList(canvas, displayList, status); - } else { - // Shouldn't reach here - view.draw(canvas); - } - } catch (Exception e) { - Log.e(LOG_TAG, "An error has occurred while drawing:", e); - } finally { - callbacks.onHardwarePostDraw(canvas); - canvas.restoreToCount(saveCount); - view.mRecreateDisplayList = false; - - mDrawDelta = getSystemTime() - start; - - if (mDrawDelta > 0) { - mFrameCount++; - - debugDirtyRegions(dirty, canvas); - drawProfileData(attachInfo); - } - } - - onPostDraw(); - - swapBuffers(status); - - if (mProfileEnabled) { - mProfileLock.unlock(); - } - - attachInfo.mIgnoreDirtyState = false; - } - } - } - - private void flushLayerChanges() { - // Loop through and apply any pending layer changes - for (int i = 0; i < mLayerUpdates.size(); i++) { - HardwareLayer layer = mLayerUpdates.get(i); - layer.flushChanges(); - if (!layer.isValid()) { - // The layer was removed from mAttachedLayers, rewind i by 1 - // Note that this shouldn't actually happen as View.getHardwareLayer() - // is already flushing for error checking reasons - i--; - } else if (layer.hasDisplayList()) { - mCanvas.pushLayerUpdate(layer); - } - } - mLayerUpdates.clear(); - } - - @Override - void fence() { - // Everything is immediate, so this is a no-op - } - - private RenderNode buildDisplayList(View view, HardwareCanvas canvas) { - view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED) - == View.PFLAG_INVALIDATED; - view.mPrivateFlags &= ~View.PFLAG_INVALIDATED; - - long buildDisplayListStartTime = startBuildDisplayListProfiling(); - canvas.clearLayerUpdates(); - - Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList"); - RenderNode renderNode = view.getDisplayList(); - Trace.traceEnd(Trace.TRACE_TAG_VIEW); - - endBuildDisplayListProfiling(buildDisplayListStartTime); - - return renderNode; - } - - private Rect beginFrame(HardwareCanvas canvas, Rect dirty, int surfaceState) { - // We had to change the current surface and/or context, redraw everything - if (surfaceState == SURFACE_STATE_UPDATED) { - dirty = null; - beginFrame(null); - } else { - int[] size = mSurfaceSize; - beginFrame(size); - - if (size[1] != mHeight || size[0] != mWidth) { - mWidth = size[0]; - mHeight = size[1]; - - canvas.setViewport(mWidth, mHeight); - - dirty = null; - } - } - - if (mDebugDataProvider != null) dirty = null; - - return dirty; - } - - private long startBuildDisplayListProfiling() { - if (mProfileEnabled) { - mProfileCurrentFrame += PROFILE_FRAME_DATA_COUNT; - if (mProfileCurrentFrame >= mProfileData.length) { - mProfileCurrentFrame = 0; - } - - return System.nanoTime(); - } - return 0; - } - - private void endBuildDisplayListProfiling(long getDisplayListStartTime) { - if (mProfileEnabled) { - long now = System.nanoTime(); - float total = (now - getDisplayListStartTime) * 0.000001f; - //noinspection PointlessArithmeticExpression - mProfileData[mProfileCurrentFrame] = total; - } - } - - private int prepareFrame(Rect dirty) { - int status; - Trace.traceBegin(Trace.TRACE_TAG_VIEW, "prepareFrame"); - try { - status = onPreDraw(dirty); - } finally { - Trace.traceEnd(Trace.TRACE_TAG_VIEW); - } - return status; - } - - private int drawDisplayList(HardwareCanvas canvas, RenderNode displayList, - int status) { - - long drawDisplayListStartTime = 0; - if (mProfileEnabled) { - drawDisplayListStartTime = System.nanoTime(); - } - - Trace.traceBegin(Trace.TRACE_TAG_VIEW, "drawDisplayList"); - nPrepareTree(displayList.getNativeDisplayList()); - try { - status |= canvas.drawDisplayList(displayList, mRedrawClip, - RenderNode.FLAG_CLIP_CHILDREN); - } finally { - Trace.traceEnd(Trace.TRACE_TAG_VIEW); - } - - if (mProfileEnabled) { - long now = System.nanoTime(); - float total = (now - drawDisplayListStartTime) * 0.000001f; - mProfileData[mProfileCurrentFrame + 1] = total; - } - - return status; - } - - private void swapBuffers(int status) { - if ((status & RenderNode.STATUS_DREW) == RenderNode.STATUS_DREW) { - long eglSwapBuffersStartTime = 0; - if (mProfileEnabled) { - eglSwapBuffersStartTime = System.nanoTime(); - } - - sEgl.eglSwapBuffers(sEglDisplay, mEglSurface); - - if (mProfileEnabled) { - long now = System.nanoTime(); - float total = (now - eglSwapBuffersStartTime) * 0.000001f; - mProfileData[mProfileCurrentFrame + 2] = total; - } - - checkEglErrors(); - } - } - - private void debugDirtyRegions(Rect dirty, HardwareCanvas canvas) { - if (mDebugDirtyRegions) { - if (mDebugPaint == null) { - mDebugPaint = new Paint(); - mDebugPaint.setColor(0x7fff0000); - } - - if (dirty != null && (mFrameCount & 1) == 0) { - canvas.drawRect(dirty, mDebugPaint); - } - } - } - - /** - * Ensures the current EGL context and surface are the ones we expect. - * This method throws an IllegalStateException if invoked from a thread - * that did not initialize EGL. - * - * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current, - * {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or - * {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one - * - * @see #checkRenderContextUnsafe() - */ - int checkRenderContext() { - if (mEglThread != Thread.currentThread()) { - throw new IllegalStateException("Hardware acceleration can only be used with a " + - "single UI thread.\nOriginal thread: " + mEglThread + "\n" + - "Current thread: " + Thread.currentThread()); - } - - return checkRenderContextUnsafe(); - } - - /** - * Ensures the current EGL context and surface are the ones we expect. - * This method does not check the current thread. - * - * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current, - * {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or - * {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one - * - * @see #checkRenderContext() - */ - private int checkRenderContextUnsafe() { - if (!mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW)) || - !mEglContext.equals(sEgl.eglGetCurrentContext())) { - if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) { - Log.e(LOG_TAG, "eglMakeCurrent failed " + - GLUtils.getEGLErrorString(sEgl.eglGetError())); - fallback(true); - return SURFACE_STATE_ERROR; - } else { - if (mUpdateDirtyRegions) { - enableDirtyRegions(); - mUpdateDirtyRegions = false; - } - return SURFACE_STATE_UPDATED; - } - } - return SURFACE_STATE_SUCCESS; - } - - private static int dpToPx(int dp, float density) { - return (int) (dp * density + 0.5f); - } - - static native boolean loadProperties(); - - static native void setupShadersDiskCache(String cacheFile); - - /** - * Notifies EGL that the frame is about to be rendered. - * @param size - */ - static native void beginFrame(int[] size); - - /** - * Returns the current system time according to the renderer. - * This method is used for debugging only and should not be used - * as a clock. - */ - static native long getSystemTime(); - - /** - * Preserves the back buffer of the current surface after a buffer swap. - * Calling this method sets the EGL_SWAP_BEHAVIOR attribute of the current - * surface to EGL_BUFFER_PRESERVED. Calling this method requires an EGL - * config that supports EGL_SWAP_BEHAVIOR_PRESERVED_BIT. - * - * @return True if the swap behavior was successfully changed, - * false otherwise. - */ - static native boolean preserveBackBuffer(); - - /** - * Indicates whether the current surface preserves its back buffer - * after a buffer swap. - * - * @return True, if the surface's EGL_SWAP_BEHAVIOR is EGL_BUFFER_PRESERVED, - * false otherwise - */ - static native boolean isBackBufferPreserved(); - - static native void nDestroyLayer(long layerPtr); - - private static native void nPrepareTree(long displayListPtr); - - class GraphDataProvider { - /** - * Draws the graph as bars. Frame elements are stacked on top of - * each other. - */ - public static final int GRAPH_TYPE_BARS = 0; - /** - * Draws the graph as lines. The number of series drawn corresponds - * to the number of elements. - */ - public static final int GRAPH_TYPE_LINES = 1; - - private final int mGraphType; - - private int mVerticalUnit; - private int mHorizontalUnit; - private int mHorizontalMargin; - private int mThresholdStroke; - - public GraphDataProvider(int graphType) { - mGraphType = graphType; - } - - void prepare(DisplayMetrics metrics) { - final float density = metrics.density; - - mVerticalUnit = dpToPx(PROFILE_DRAW_DP_PER_MS, density); - mHorizontalUnit = dpToPx(PROFILE_DRAW_WIDTH, density); - mHorizontalMargin = dpToPx(PROFILE_DRAW_MARGIN, density); - mThresholdStroke = dpToPx(PROFILE_DRAW_THRESHOLD_STROKE_WIDTH, density); - } - - int getGraphType() { - return mGraphType; - } - - int getVerticalUnitSize() { - return mVerticalUnit; - } - - int getHorizontalUnitSize() { - return mHorizontalUnit; - } - - int getHorizontaUnitMargin() { - return mHorizontalMargin; - } - - float[] getData() { - return mProfileData; - } - - float getThreshold() { - return 16; - } - - int getFrameCount() { - return mProfileData.length / PROFILE_FRAME_DATA_COUNT; - } - - int getElementCount() { - return PROFILE_FRAME_DATA_COUNT; - } - - int getCurrentFrame() { - return mProfileCurrentFrame / PROFILE_FRAME_DATA_COUNT; - } - - void setupGraphPaint(Paint paint, int elementIndex) { - paint.setColor(PROFILE_DRAW_COLORS[elementIndex]); - if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke); - } - - void setupThresholdPaint(Paint paint) { - paint.setColor(PROFILE_DRAW_THRESHOLD_COLOR); - paint.setStrokeWidth(mThresholdStroke); - } - - void setupCurrentFramePaint(Paint paint) { - paint.setColor(PROFILE_DRAW_CURRENT_FRAME_COLOR); - if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke); - } - } -} diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java index 9568760..b8e7d8c 100644 --- a/core/java/android/view/HardwareCanvas.java +++ b/core/java/android/view/HardwareCanvas.java @@ -110,48 +110,6 @@ public abstract class HardwareCanvas extends Canvas { return RenderNode.STATUS_DONE; } - /** - * Indicates that the specified layer must be updated as soon as possible. - * - * @param layer The layer to update - * - * @see #clearLayerUpdates() - * - * @hide - */ - abstract void pushLayerUpdate(HardwareLayer layer); - - /** - * Cancels a queued layer update. If the specified layer was not - * queued for update, this method has no effect. - * - * @param layer The layer whose update to cancel - * - * @see #pushLayerUpdate(HardwareLayer) - * @see #clearLayerUpdates() - * - * @hide - */ - abstract void cancelLayerUpdate(HardwareLayer layer); - - /** - * Immediately executes all enqueued layer updates. - * - * @see #pushLayerUpdate(HardwareLayer) - * - * @hide - */ - abstract void flushLayerUpdates(); - - /** - * Removes all enqueued layer updates. - * - * @see #pushLayerUpdate(HardwareLayer) - * - * @hide - */ - abstract void clearLayerUpdates(); - public abstract void drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy, CanvasProperty<Float> radius, CanvasProperty<Paint> paint); } diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java index 652bcd2..6acb134 100644 --- a/core/java/android/view/HardwareLayer.java +++ b/core/java/android/view/HardwareLayer.java @@ -172,24 +172,6 @@ final class HardwareLayer { }); } - /** - * This exists to minimize impact into the current HardwareLayer paths as - * some of the specifics of how to handle error cases in the fully - * deferred model will work - */ - @Deprecated - public void flushChanges() { - if (HardwareRenderer.sUseRenderThread) { - // Not supported, don't try. - return; - } - - boolean success = nFlushChanges(mFinalizer.get()); - if (!success) { - destroy(); - } - } - public long getLayer() { return nGetLayer(mFinalizer.get()); } @@ -216,33 +198,14 @@ final class HardwareLayer { return st; } - /** - * This should only be used by HardwareRenderer! Do not call directly - */ - static HardwareLayer createTextureLayer(HardwareRenderer renderer) { - return new HardwareLayer(renderer, nCreateTextureLayer(), LAYER_TYPE_TEXTURE); - } - static HardwareLayer adoptTextureLayer(HardwareRenderer renderer, long layer) { return new HardwareLayer(renderer, layer, LAYER_TYPE_TEXTURE); } - /** - * This should only be used by HardwareRenderer! Do not call directly - */ - static HardwareLayer createDisplayListLayer(HardwareRenderer renderer, - int width, int height) { - return new HardwareLayer(renderer, nCreateRenderLayer(width, height), LAYER_TYPE_DISPLAY_LIST); - } - static HardwareLayer adoptDisplayListLayer(HardwareRenderer renderer, long layer) { return new HardwareLayer(renderer, layer, LAYER_TYPE_DISPLAY_LIST); } - /** This also creates the underlying layer */ - private static native long nCreateTextureLayer(); - private static native long nCreateRenderLayer(int width, int height); - private static native void nOnTextureDestroyed(long layerUpdater); private static native boolean nPrepare(long layerUpdater, int width, int height, boolean isOpaque); diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index d71de9f..d67c974 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -171,9 +171,6 @@ public abstract class HardwareRenderer { */ public static boolean sSystemRendererDisabled = false; - /** @hide */ - public static boolean sUseRenderThread = true; - private boolean mEnabled; private boolean mRequested = true; @@ -309,7 +306,7 @@ public abstract class HardwareRenderer { * @hide */ public static void setupDiskCache(File cacheDir) { - GLRenderer.setupShadersDiskCache(new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath()); + ThreadedRenderer.setupShadersDiskCache(new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath()); } /** @@ -469,11 +466,7 @@ public abstract class HardwareRenderer { static HardwareRenderer create(boolean translucent) { HardwareRenderer renderer = null; if (GLES20Canvas.isAvailable()) { - if (sUseRenderThread) { - renderer = new ThreadedRenderer(translucent); - } else { - renderer = new GLRenderer(translucent); - } + renderer = new ThreadedRenderer(translucent); } return renderer; } @@ -500,7 +493,7 @@ public abstract class HardwareRenderer { * see {@link android.content.ComponentCallbacks} */ static void startTrimMemory(int level) { - GLRenderer.startTrimMemory(level); + ThreadedRenderer.startTrimMemory(level); } /** @@ -508,7 +501,7 @@ public abstract class HardwareRenderer { * cleanup special resources used by the memory trimming process. */ static void endTrimMemory() { - GLRenderer.endTrimMemory(); + ThreadedRenderer.endTrimMemory(); } /** diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index 11db996..9b3ef7f 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -331,6 +331,14 @@ public class ThreadedRenderer extends HardwareRenderer { } } + static void startTrimMemory(int level) { + // TODO + } + + static void endTrimMemory() { + // TODO + } + private static class AtlasInitializer { static AtlasInitializer sInstance = new AtlasInitializer(); @@ -367,6 +375,8 @@ public class ThreadedRenderer extends HardwareRenderer { } } + static native void setupShadersDiskCache(String cacheFile); + private static native void nSetAtlas(GraphicBuffer buffer, long[] map); private static native long nCreateRootRenderNode(); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index ce266d7..622fa8c 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -13593,12 +13593,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } - // The layer is not valid if the underlying GPU resources cannot be allocated - mHardwareLayer.flushChanges(); - if (!mHardwareLayer.isValid()) { - return null; - } - mHardwareLayer.setLayerPaint(mLayerPaint); RenderNode displayList = mHardwareLayer.startRecording(); updateDisplayListIfDirty(displayList, true); @@ -16197,6 +16191,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * Set this view's optical insets. + * + * <p>This method should be treated similarly to setMeasuredDimension and not as a general + * property. Views that compute their own optical insets should call it as part of measurement. + * This method does not request layout. If you are setting optical insets outside of + * measure/layout itself you will want to call requestLayout() yourself. + * </p> + * @hide + */ + public void setOpticalInsets(Insets insets) { + mLayoutInsets = insets; + } + + /** * Changes the selection state of this view. A view can be selected or not. * Note that selection is not the same as focus. Views are typically * selected in the context of an AdapterView like ListView or GridView; diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index ac25b57..f3d1e3c 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -716,17 +716,6 @@ public final class ViewRootImpl implements ViewParent, if (!HardwareRenderer.sRendererDisabled || (HardwareRenderer.sSystemRendererDisabled && forceHwAccelerated)) { - if (!HardwareRenderer.sUseRenderThread) { - // TODO: Delete - // Don't enable hardware acceleration when we're not on the main thread - if (!HardwareRenderer.sSystemRendererDisabled && - Looper.getMainLooper() != Looper.myLooper()) { - Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware " - + "acceleration outside of the main thread, aborting"); - return; - } - } - if (mAttachInfo.mHardwareRenderer != null) { mAttachInfo.mHardwareRenderer.destroy(true); } diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java index 7c32c5b..d14c19b 100644 --- a/core/java/android/webkit/WebSettings.java +++ b/core/java/android/webkit/WebSettings.java @@ -1460,4 +1460,36 @@ public abstract class WebSettings { * {@link #MIXED_CONTENT_NEVER_ALLOW} or {@link #MIXED_CONTENT_COMPATIBILITY_MODE}. */ public abstract int getMixedContentMode(); + + /** + * Sets whether to use a video overlay for embedded encrypted video. + * In API levels prior to {@link android.os.Build.VERSION_CODES#L}, encrypted video can + * only be rendered directly on a secure video surface, so it had been a hard problem to play + * encrypted video in HTML. When this flag is on, WebView can play encrypted video (MSE/EME) + * by using a video overlay (aka hole-punching) for videos embedded using HTML <video> + * tag.<br> + * Caution: This setting is intended for use only in a narrow set of circumstances and apps + * should only enable it if they require playback of encrypted video content. It will impose + * the following limitations on the WebView: + * <ul> + * <li> Only one video overlay can be played at a time. + * <li> Changes made to position or dimensions of a video element may be propagated to the + * corresponding video overlay with a noticeable delay. + * <li> The video overlay is not visible to web APIs and as such may not interact with + * script or styling. For example, CSS styles applied to the <video> tag may be ignored. + * </ul> + * This is not an exhaustive set of constraints and it may vary with new versions of the + * WebView. + * @hide + */ + public abstract void setVideoOverlayForEmbeddedEncryptedVideoEnabled(boolean flag); + + /** + * Gets whether a video overlay will be used for embedded encrypted video. + * + * @return true if WebView uses a video overlay for embedded encrypted video. + * @see #setVideoOverlayForEmbeddedEncryptedVideoEnabled + * @hide + */ + public abstract boolean getVideoOverlayForEmbeddedEncryptedVideoEnabled(); } diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java index eedacb5..572302a 100644 --- a/core/java/android/widget/ImageView.java +++ b/core/java/android/widget/ImageView.java @@ -664,7 +664,7 @@ public class ImageView extends View { InputStream stream = null; try { stream = mContext.getContentResolver().openInputStream(mUri); - d = Drawable.createFromStreamThemed(stream, null, mContext.getTheme()); + d = Drawable.createFromStream(stream, null); } catch (Exception e) { Log.w("ImageView", "Unable to open content: " + mUri, e); } finally { diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java index 0c3715d..b49938c 100644 --- a/core/java/android/widget/ProgressBar.java +++ b/core/java/android/widget/ProgressBar.java @@ -357,9 +357,8 @@ public class ProgressBar extends View { Shader.TileMode.REPEAT, Shader.TileMode.CLAMP); shapeDrawable.getPaint().setShader(bitmapShader); - // Ensure the color filter and tint are propagated. - shapeDrawable.setTint(bitmap.getTint()); - shapeDrawable.setTintMode(bitmap.getTintMode()); + // Ensure the tint and filter are propagated in the correct order. + shapeDrawable.setTint(bitmap.getTint(), bitmap.getTintMode()); shapeDrawable.setColorFilter(bitmap.getColorFilter()); return clip ? new ClipDrawable( diff --git a/core/java/android/widget/SuggestionsAdapter.java b/core/java/android/widget/SuggestionsAdapter.java index 0203301..c8917e0 100644 --- a/core/java/android/widget/SuggestionsAdapter.java +++ b/core/java/android/widget/SuggestionsAdapter.java @@ -574,7 +574,7 @@ class SuggestionsAdapter extends ResourceCursorAdapter implements OnClickListene throw new FileNotFoundException("Failed to open " + uri); } try { - return Drawable.createFromStreamThemed(stream, null, mContext.getTheme()); + return Drawable.createFromStream(stream, null); } finally { try { stream.close(); diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java index ba419f9..dab3aff 100644 --- a/core/java/com/android/internal/content/NativeLibraryHelper.java +++ b/core/java/com/android/internal/content/NativeLibraryHelper.java @@ -20,6 +20,7 @@ import android.content.pm.PackageManager; import android.util.Slog; import java.io.File; +import java.io.IOException; /** * Native libraries helper. @@ -141,4 +142,18 @@ public class NativeLibraryHelper { return deletedFiles; } + + // We don't care about the other return values for now. + private static final int BITCODE_PRESENT = 1; + + public static boolean hasRenderscriptBitcode(ApkHandle handle) throws IOException { + final int returnVal = hasRenderscriptBitcode(handle.apkHandle); + if (returnVal < 0) { + throw new IOException("Error scanning APK, code: " + returnVal); + } + + return (returnVal == BITCODE_PRESENT); + } + + private static native int hasRenderscriptBitcode(long apkHandle); } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index ed9f9bc..240d520 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -2006,6 +2006,11 @@ public final class BatteryStatsImpl extends BatteryStats { } } + @Override + public void commitCurrentHistoryBatchLocked() { + mHistoryLastWritten.cmd = HistoryItem.CMD_NULL; + } + void addHistoryBufferLocked(long elapsedRealtimeMs, long uptimeMs, HistoryItem cur) { if (!mHaveBatteryLevel || !mRecordingHistory) { return; @@ -2342,13 +2347,16 @@ public final class BatteryStatsImpl extends BatteryStats { // Only care about partial wake locks, since full wake locks // will be canceled when the user puts the screen to sleep. aggregateLastWakeupUptimeLocked(uptime); + if (historyName == null) { + historyName = name; + } if (mRecordAllWakeLocks) { - if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_START, name, uid, 0)) { + if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_START, historyName, + uid, 0)) { addHistoryEventLocked(elapsedRealtime, uptime, - HistoryItem.EVENT_WAKE_LOCK_START, name, uid); + HistoryItem.EVENT_WAKE_LOCK_START, historyName, uid); } } - historyName = historyName == null ? name : historyName; if (mWakeLockNesting == 0) { mHistoryCur.states |= HistoryItem.STATE_WAKE_LOCK_FLAG; if (DEBUG_HISTORY) Slog.v(TAG, "Start wake lock to: " @@ -2358,7 +2366,8 @@ public final class BatteryStatsImpl extends BatteryStats { mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid; mWakeLockImportant = !unimportantForLogging; addHistoryRecordLocked(elapsedRealtime, uptime); - } else if (!mWakeLockImportant && !unimportantForLogging) { + } else if (!mWakeLockImportant && !unimportantForLogging + && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE) { if (mHistoryLastWritten.wakelockTag != null) { // We'll try to update the last tag. mHistoryLastWritten.wakelockTag = null; @@ -2386,9 +2395,13 @@ public final class BatteryStatsImpl extends BatteryStats { if (type == WAKE_TYPE_PARTIAL) { mWakeLockNesting--; if (mRecordAllWakeLocks) { - if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_FINISH, name, uid, 0)) { + if (historyName == null) { + historyName = name; + } + if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, + uid, 0)) { addHistoryEventLocked(elapsedRealtime, uptime, - HistoryItem.EVENT_WAKE_LOCK_FINISH, name, uid); + HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, uid); } } if (mWakeLockNesting == 0) { |