Revert "Revert "Add physical TV input handling to TvInputManagerService""
This reverts commit 1940e197a8de186df5edf0b78e0907ae539bd215. Bug: 14118245, Bug: 15197740 Change-Id: Ia308f16d2ed8ec55112a4d21c180ccb97e8d7c6a
This commit is contained in:
@ -216,6 +216,8 @@ LOCAL_SRC_FILES += \
|
||||
core/java/android/service/wallpaper/IWallpaperEngine.aidl \
|
||||
core/java/android/service/wallpaper/IWallpaperService.aidl \
|
||||
core/java/android/tv/ITvInputClient.aidl \
|
||||
core/java/android/tv/ITvInputHardware.aidl \
|
||||
core/java/android/tv/ITvInputHardwareCallback.aidl \
|
||||
core/java/android/tv/ITvInputManager.aidl \
|
||||
core/java/android/tv/ITvInputService.aidl \
|
||||
core/java/android/tv/ITvInputServiceCallback.aidl \
|
||||
|
46
core/java/android/tv/ITvInputHardware.aidl
Normal file
46
core/java/android/tv/ITvInputHardware.aidl
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
27
core/java/android/tv/ITvInputHardwareCallback.aidl
Normal file
27
core/java/android/tv/ITvInputHardwareCallback.aidl
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
@ -19,7 +19,10 @@ 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;
|
||||
|
||||
@ -46,4 +49,10 @@ interface ITvInputManager {
|
||||
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);
|
||||
}
|
||||
|
20
core/java/android/tv/TvInputHardwareInfo.aidl
Normal file
20
core/java/android/tv/TvInputHardwareInfo.aidl
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
*
|
||||
* 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;
|
93
core/java/android/tv/TvInputHardwareInfo.java
Normal file
93
core/java/android/tv/TvInputHardwareInfo.java
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
20
core/java/android/tv/TvStreamConfig.aidl
Normal file
20
core/java/android/tv/TvStreamConfig.aidl
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
*
|
||||
* 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;
|
157
core/java/android/tv/TvStreamConfig.java
Normal file
157
core/java/android/tv/TvStreamConfig.java
Normal file
@ -0,0 +1,157 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -1014,6 +1014,13 @@
|
||||
android:description="@string/permdesc_sim_communication"
|
||||
android:protectionLevel="dangerous" />
|
||||
|
||||
<!-- Allows TvInputService to access underlying TV input hardware such as
|
||||
built-in tuners and HDMI-in's.
|
||||
@hide This should only be used by OEM's TvInputService's.
|
||||
-->
|
||||
<permission android:name="android.permission.TV_INPUT_HARDWARE"
|
||||
android:protectionLevel="signatureOrSystem" />
|
||||
|
||||
<!-- =========================================== -->
|
||||
<!-- Permissions associated with audio capture -->
|
||||
<!-- =========================================== -->
|
||||
|
128
services/core/java/com/android/server/tv/TvInputHal.java
Normal file
128
services/core/java/com/android/server/tv/TvInputHal.java
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* 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 com.android.server.tv;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.tv.TvInputHardwareInfo;
|
||||
import android.tv.TvStreamConfig;
|
||||
import android.view.Surface;
|
||||
|
||||
/**
|
||||
* Provides access to the low-level TV input hardware abstraction layer.
|
||||
*/
|
||||
final class TvInputHal {
|
||||
public final static int SUCCESS = 0;
|
||||
public final static int ERROR_NO_INIT = -1;
|
||||
public final static int ERROR_STALE_CONFIG = -2;
|
||||
public final static int ERROR_UNKNOWN = -3;
|
||||
|
||||
public static final int TYPE_HDMI = 1;
|
||||
public static final int TYPE_BUILT_IN_TUNER = 2;
|
||||
public static final int TYPE_PASSTHROUGH = 3;
|
||||
|
||||
public interface Callback {
|
||||
public void onDeviceAvailable(
|
||||
TvInputHardwareInfo info, TvStreamConfig[] configs);
|
||||
public void onDeviceUnavailable(int deviceId);
|
||||
public void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs);
|
||||
}
|
||||
|
||||
private native long nativeOpen();
|
||||
|
||||
private static native int nativeSetSurface(long ptr, int deviceId, int streamId,
|
||||
Surface surface);
|
||||
private static native TvStreamConfig[] nativeGetStreamConfigs(long ptr, int deviceId,
|
||||
int generation);
|
||||
private static native void nativeClose(long ptr);
|
||||
|
||||
private long mPtr = 0l;
|
||||
private final Callback mCallback;
|
||||
private final HandlerThread mThread = new HandlerThread("TV input HAL event thread");
|
||||
private final Handler mHandler;
|
||||
private int mStreamConfigGeneration = 0;
|
||||
private TvStreamConfig[] mStreamConfigs;
|
||||
|
||||
public TvInputHal(Callback callback) {
|
||||
mCallback = callback;
|
||||
mThread.start();
|
||||
mHandler = new Handler(mThread.getLooper());
|
||||
}
|
||||
|
||||
public void init() {
|
||||
mPtr = nativeOpen();
|
||||
}
|
||||
|
||||
public int setSurface(int deviceId, Surface surface, TvStreamConfig streamConfig) {
|
||||
if (mPtr == 0) {
|
||||
return ERROR_NO_INIT;
|
||||
}
|
||||
if (mStreamConfigGeneration != streamConfig.getGeneration()) {
|
||||
return ERROR_STALE_CONFIG;
|
||||
}
|
||||
if (nativeSetSurface(mPtr, deviceId, streamConfig.getStreamId(), surface) == 0) {
|
||||
return SUCCESS;
|
||||
} else {
|
||||
return ERROR_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (mPtr != 0l) {
|
||||
nativeClose(mPtr);
|
||||
mThread.quitSafely();
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void retrieveStreamConfigs(int deviceId) {
|
||||
++mStreamConfigGeneration;
|
||||
mStreamConfigs = nativeGetStreamConfigs(mPtr, deviceId, mStreamConfigGeneration);
|
||||
}
|
||||
|
||||
// Called from native
|
||||
private void deviceAvailableFromNative(int deviceId, int type) {
|
||||
final TvInputHardwareInfo info = new TvInputHardwareInfo(deviceId, type);
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
retrieveStreamConfigs(info.getDeviceId());
|
||||
mCallback.onDeviceAvailable(info, mStreamConfigs);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void deviceUnavailableFromNative(int deviceId) {
|
||||
final int id = deviceId;
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mCallback.onDeviceUnavailable(id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void streamConfigsChangedFromNative(int deviceId) {
|
||||
final int id = deviceId;
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
retrieveStreamConfigs(id);
|
||||
mCallback.onStreamConfigurationChanged(id, mStreamConfigs);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,308 @@
|
||||
/*
|
||||
* 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 com.android.server.tv;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.tv.ITvInputHardware;
|
||||
import android.tv.ITvInputHardwareCallback;
|
||||
import android.tv.TvInputHardwareInfo;
|
||||
import android.tv.TvStreamConfig;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.Surface;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A helper class for TvInputManagerService to handle TV input hardware.
|
||||
*
|
||||
* This class does a basic connection management and forwarding calls to TvInputHal which eventually
|
||||
* calls to tv_input HAL module.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
class TvInputHardwareManager implements TvInputHal.Callback {
|
||||
private static final String TAG = TvInputHardwareManager.class.getSimpleName();
|
||||
private final TvInputHal mHal = new TvInputHal(this);
|
||||
private final SparseArray<Connection> mConnections = new SparseArray<Connection>();
|
||||
private final List<TvInputHardwareInfo> mInfoList = new ArrayList<TvInputHardwareInfo>();
|
||||
private final Context mContext;
|
||||
private final Set<Integer> mActiveHdmiSources = new HashSet<Integer>();
|
||||
|
||||
private final Object mLock = new Object();
|
||||
|
||||
public TvInputHardwareManager(Context context) {
|
||||
mContext = context;
|
||||
// TODO(hdmi): mHdmiManager = mContext.getSystemService(...);
|
||||
// TODO(hdmi): mHdmiClient = mHdmiManager.getTvClient();
|
||||
mHal.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceAvailable(
|
||||
TvInputHardwareInfo info, TvStreamConfig[] configs) {
|
||||
synchronized (mLock) {
|
||||
Connection connection = new Connection(info);
|
||||
connection.updateConfigsLocked(configs);
|
||||
mConnections.put(info.getDeviceId(), connection);
|
||||
buildInfoListLocked();
|
||||
// TODO: notify if necessary
|
||||
}
|
||||
}
|
||||
|
||||
private void buildInfoListLocked() {
|
||||
mInfoList.clear();
|
||||
for (int i = 0; i < mConnections.size(); ++i) {
|
||||
mInfoList.add(mConnections.valueAt(i).getInfoLocked());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceUnavailable(int deviceId) {
|
||||
synchronized (mLock) {
|
||||
Connection connection = mConnections.get(deviceId);
|
||||
if (connection == null) {
|
||||
Slog.e(TAG, "onDeviceUnavailable: Cannot find a connection with " + deviceId);
|
||||
return;
|
||||
}
|
||||
connection.resetLocked(null, null, null, null);
|
||||
mConnections.remove(deviceId);
|
||||
buildInfoListLocked();
|
||||
// TODO: notify if necessary
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs) {
|
||||
synchronized (mLock) {
|
||||
Connection connection = mConnections.get(deviceId);
|
||||
if (connection == null) {
|
||||
Slog.e(TAG, "StreamConfigurationChanged: Cannot find a connection with "
|
||||
+ deviceId);
|
||||
return;
|
||||
}
|
||||
connection.updateConfigsLocked(configs);
|
||||
try {
|
||||
connection.getCallbackLocked().onStreamConfigChanged(configs);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "onStreamConfigurationChanged: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<TvInputHardwareInfo> getHardwareList() {
|
||||
synchronized (mLock) {
|
||||
return mInfoList;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a TvInputHardware object with a specific deviceId. One service at a time can access
|
||||
* the object, and if more than one process attempts to create hardware with the same deviceId,
|
||||
* the latest service will get the object and all the other hardware are released. The
|
||||
* release is notified via ITvInputHardwareCallback.onReleased().
|
||||
*/
|
||||
public ITvInputHardware acquireHardware(int deviceId, ITvInputHardwareCallback callback,
|
||||
int callingUid, int resolvedUserId) {
|
||||
if (callback == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
synchronized (mLock) {
|
||||
Connection connection = mConnections.get(deviceId);
|
||||
if (connection == null) {
|
||||
Slog.e(TAG, "Invalid deviceId : " + deviceId);
|
||||
return null;
|
||||
}
|
||||
if (connection.getCallingUidLocked() != callingUid
|
||||
|| connection.getResolvedUserIdLocked() != resolvedUserId) {
|
||||
TvInputHardwareImpl hardware = new TvInputHardwareImpl(connection.getInfoLocked());
|
||||
try {
|
||||
callback.asBinder().linkToDeath(connection, 0);
|
||||
} catch (RemoteException e) {
|
||||
hardware.release();
|
||||
return null;
|
||||
}
|
||||
connection.resetLocked(hardware, callback, callingUid, resolvedUserId);
|
||||
}
|
||||
return connection.getHardwareLocked();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the specified hardware.
|
||||
*/
|
||||
public void releaseHardware(int deviceId, ITvInputHardware hardware, int callingUid,
|
||||
int resolvedUserId) {
|
||||
synchronized (mLock) {
|
||||
Connection connection = mConnections.get(deviceId);
|
||||
if (connection == null) {
|
||||
Slog.e(TAG, "Invalid deviceId : " + deviceId);
|
||||
return;
|
||||
}
|
||||
if (connection.getHardwareLocked() != hardware
|
||||
|| connection.getCallingUidLocked() != callingUid
|
||||
|| connection.getResolvedUserIdLocked() != resolvedUserId) {
|
||||
return;
|
||||
}
|
||||
connection.resetLocked(null, null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
private class Connection implements IBinder.DeathRecipient {
|
||||
private final TvInputHardwareInfo mInfo;
|
||||
private TvInputHardwareImpl mHardware = null;
|
||||
private ITvInputHardwareCallback mCallback;
|
||||
private TvStreamConfig[] mConfigs = null;
|
||||
private Integer mCallingUid = null;
|
||||
private Integer mResolvedUserId = null;
|
||||
|
||||
public Connection(TvInputHardwareInfo info) {
|
||||
mInfo = info;
|
||||
}
|
||||
|
||||
// *Locked methods assume TvInputHardwareManager.mLock is held.
|
||||
|
||||
public void resetLocked(TvInputHardwareImpl hardware,
|
||||
ITvInputHardwareCallback callback, Integer callingUid, Integer resolvedUserId) {
|
||||
if (mHardware != null) {
|
||||
try {
|
||||
mCallback.onReleased();
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Connection::resetHardware: " + e);
|
||||
}
|
||||
mHardware.release();
|
||||
}
|
||||
mHardware = hardware;
|
||||
mCallback = callback;
|
||||
mCallingUid = callingUid;
|
||||
mResolvedUserId = resolvedUserId;
|
||||
|
||||
if (mHardware != null && mCallback != null) {
|
||||
try {
|
||||
mCallback.onStreamConfigChanged(getConfigsLocked());
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Connection::resetHardware: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateConfigsLocked(TvStreamConfig[] configs) {
|
||||
mConfigs = configs;
|
||||
}
|
||||
|
||||
public TvInputHardwareInfo getInfoLocked() {
|
||||
return mInfo;
|
||||
}
|
||||
|
||||
public ITvInputHardware getHardwareLocked() {
|
||||
return mHardware;
|
||||
}
|
||||
|
||||
public ITvInputHardwareCallback getCallbackLocked() {
|
||||
return mCallback;
|
||||
}
|
||||
|
||||
public TvStreamConfig[] getConfigsLocked() {
|
||||
return mConfigs;
|
||||
}
|
||||
|
||||
public int getCallingUidLocked() {
|
||||
return mCallingUid;
|
||||
}
|
||||
|
||||
public int getResolvedUserIdLocked() {
|
||||
return mResolvedUserId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void binderDied() {
|
||||
synchronized (mLock) {
|
||||
resetLocked(null, null, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class TvInputHardwareImpl extends ITvInputHardware.Stub {
|
||||
private final TvInputHardwareInfo mInfo;
|
||||
private boolean mReleased = false;
|
||||
private final Object mImplLock = new Object();
|
||||
|
||||
public TvInputHardwareImpl(TvInputHardwareInfo info) {
|
||||
mInfo = info;
|
||||
}
|
||||
|
||||
public void release() {
|
||||
synchronized (mImplLock) {
|
||||
mReleased = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setSurface(Surface surface, TvStreamConfig config)
|
||||
throws RemoteException {
|
||||
synchronized (mImplLock) {
|
||||
if (mReleased) {
|
||||
throw new IllegalStateException("Device already released.");
|
||||
}
|
||||
if (mInfo.getType() == TvInputHal.TYPE_HDMI) {
|
||||
if (surface != null) {
|
||||
// Set "Active Source" for HDMI.
|
||||
// TODO(hdmi): mHdmiClient.deviceSelect(...);
|
||||
mActiveHdmiSources.add(mInfo.getDeviceId());
|
||||
} else {
|
||||
mActiveHdmiSources.remove(mInfo.getDeviceId());
|
||||
if (mActiveHdmiSources.size() == 0) {
|
||||
// Tell HDMI that no HDMI source is active
|
||||
// TODO(hdmi): mHdmiClient.portSelect(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
return mHal.setSurface(mInfo.getDeviceId(), surface, config) == TvInputHal.SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVolume(float volume) throws RemoteException {
|
||||
synchronized (mImplLock) {
|
||||
if (mReleased) {
|
||||
throw new IllegalStateException("Device already released.");
|
||||
}
|
||||
}
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEventToHdmi(KeyEvent event) throws RemoteException {
|
||||
synchronized (mImplLock) {
|
||||
if (mReleased) {
|
||||
throw new IllegalStateException("Device already released.");
|
||||
}
|
||||
}
|
||||
if (mInfo.getType() != TvInputHal.TYPE_HDMI) {
|
||||
return false;
|
||||
}
|
||||
// TODO(hdmi): mHdmiClient.sendKeyEvent(event);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -42,11 +42,14 @@ import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.TvContract;
|
||||
import android.tv.ITvInputClient;
|
||||
import android.tv.ITvInputHardware;
|
||||
import android.tv.ITvInputHardwareCallback;
|
||||
import android.tv.ITvInputManager;
|
||||
import android.tv.ITvInputService;
|
||||
import android.tv.ITvInputServiceCallback;
|
||||
import android.tv.ITvInputSession;
|
||||
import android.tv.ITvInputSessionCallback;
|
||||
import android.tv.TvInputHardwareInfo;
|
||||
import android.tv.TvInputInfo;
|
||||
import android.tv.TvInputService;
|
||||
import android.util.Slog;
|
||||
@ -71,6 +74,7 @@ public final class TvInputManagerService extends SystemService {
|
||||
private static final String TAG = "TvInputManagerService";
|
||||
|
||||
private final Context mContext;
|
||||
private final TvInputHardwareManager mTvInputHardwareManager;
|
||||
|
||||
private final ContentResolver mContentResolver;
|
||||
|
||||
@ -92,6 +96,7 @@ public final class TvInputManagerService extends SystemService {
|
||||
mContentResolver = context.getContentResolver();
|
||||
mLogHandler = new LogHandler(IoThread.get().getLooper());
|
||||
|
||||
mTvInputHardwareManager = new TvInputHardwareManager(context);
|
||||
registerBroadcastReceivers();
|
||||
|
||||
synchronized (mLock) {
|
||||
@ -730,6 +735,64 @@ public final class TvInputManagerService extends SystemService {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TvInputHardwareInfo> getHardwareList() throws RemoteException {
|
||||
if (mContext.checkCallingPermission(
|
||||
android.Manifest.permission.TV_INPUT_HARDWARE)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
return mTvInputHardwareManager.getHardwareList();
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITvInputHardware acquireTvInputHardware(int deviceId,
|
||||
ITvInputHardwareCallback callback, int userId) throws RemoteException {
|
||||
if (mContext.checkCallingPermission(
|
||||
android.Manifest.permission.TV_INPUT_HARDWARE)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
|
||||
userId, "acquireTvInputHardware");
|
||||
try {
|
||||
return mTvInputHardwareManager.acquireHardware(
|
||||
deviceId, callback, callingUid, resolvedUserId);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseTvInputHardware(int deviceId, ITvInputHardware hardware, int userId)
|
||||
throws RemoteException {
|
||||
if (mContext.checkCallingPermission(
|
||||
android.Manifest.permission.TV_INPUT_HARDWARE)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
return;
|
||||
}
|
||||
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
|
||||
userId, "releaseTvInputHardware");
|
||||
try {
|
||||
mTvInputHardwareManager.releaseHardware(
|
||||
deviceId, hardware, callingUid, resolvedUserId);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class UserState {
|
||||
|
@ -23,6 +23,7 @@ LOCAL_SRC_FILES += \
|
||||
$(LOCAL_REL_DIR)/com_android_server_power_PowerManagerService.cpp \
|
||||
$(LOCAL_REL_DIR)/com_android_server_SerialService.cpp \
|
||||
$(LOCAL_REL_DIR)/com_android_server_SystemServer.cpp \
|
||||
$(LOCAL_REL_DIR)/com_android_server_tv_TvInputHal.cpp \
|
||||
$(LOCAL_REL_DIR)/com_android_server_UsbDeviceManager.cpp \
|
||||
$(LOCAL_REL_DIR)/com_android_server_UsbHostManager.cpp \
|
||||
$(LOCAL_REL_DIR)/com_android_server_VibratorService.cpp \
|
||||
|
388
services/core/jni/com_android_server_tv_TvInputHal.cpp
Normal file
388
services/core/jni/com_android_server_tv_TvInputHal.cpp
Normal file
@ -0,0 +1,388 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "TvInputHal"
|
||||
|
||||
//#define LOG_NDEBUG 0
|
||||
|
||||
#include "android_runtime/AndroidRuntime.h"
|
||||
#include "android_runtime/android_view_Surface.h"
|
||||
#include "JNIHelp.h"
|
||||
#include "jni.h"
|
||||
|
||||
#include <gui/Surface.h>
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/KeyedVector.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/NativeHandle.h>
|
||||
#include <hardware/tv_input.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
static struct {
|
||||
jmethodID deviceAvailable;
|
||||
jmethodID deviceUnavailable;
|
||||
jmethodID streamConfigsChanged;
|
||||
} gTvInputHalClassInfo;
|
||||
|
||||
static struct {
|
||||
jclass clazz;
|
||||
} gTvStreamConfigClassInfo;
|
||||
|
||||
static struct {
|
||||
jclass clazz;
|
||||
|
||||
jmethodID constructor;
|
||||
jmethodID streamId;
|
||||
jmethodID type;
|
||||
jmethodID maxWidth;
|
||||
jmethodID maxHeight;
|
||||
jmethodID generation;
|
||||
jmethodID build;
|
||||
} gTvStreamConfigBuilderClassInfo;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class JTvInputHal {
|
||||
public:
|
||||
~JTvInputHal();
|
||||
|
||||
static JTvInputHal* createInstance(JNIEnv* env, jobject thiz);
|
||||
|
||||
int setSurface(int deviceId, int streamId, const sp<Surface>& surface);
|
||||
void getStreamConfigs(int deviceId, jobjectArray* array);
|
||||
const tv_stream_config_t* getStreamConfigs(int deviceId, int* numConfigs);
|
||||
|
||||
private:
|
||||
class Connection {
|
||||
public:
|
||||
Connection() : mStreamId(0) {}
|
||||
|
||||
sp<Surface> mSurface;
|
||||
sp<NativeHandle> mSourceHandle;
|
||||
int mStreamId;
|
||||
};
|
||||
|
||||
JTvInputHal(JNIEnv* env, jobject thiz, tv_input_device_t* dev);
|
||||
|
||||
static void notify(
|
||||
tv_input_device_t* dev,tv_input_event_t* event, void* data);
|
||||
|
||||
void onDeviceAvailable(const tv_input_device_info_t& info);
|
||||
void onDeviceUnavailable(int deviceId);
|
||||
void onStreamConfigurationsChanged(int deviceId);
|
||||
|
||||
jweak mThiz;
|
||||
tv_input_device_t* mDevice;
|
||||
tv_input_callback_ops_t mCallback;
|
||||
|
||||
KeyedVector<int, Connection> mConnections;
|
||||
};
|
||||
|
||||
JTvInputHal::JTvInputHal(JNIEnv* env, jobject thiz, tv_input_device_t* device) {
|
||||
mThiz = env->NewWeakGlobalRef(thiz);
|
||||
mDevice = device;
|
||||
mCallback.notify = &JTvInputHal::notify;
|
||||
|
||||
mDevice->initialize(mDevice, &mCallback, this);
|
||||
}
|
||||
|
||||
JTvInputHal::~JTvInputHal() {
|
||||
mDevice->common.close((hw_device_t*)mDevice);
|
||||
|
||||
JNIEnv* env = AndroidRuntime::getJNIEnv();
|
||||
env->DeleteWeakGlobalRef(mThiz);
|
||||
mThiz = NULL;
|
||||
}
|
||||
|
||||
JTvInputHal* JTvInputHal::createInstance(JNIEnv* env, jobject thiz) {
|
||||
tv_input_module_t* module = NULL;
|
||||
status_t err = hw_get_module(TV_INPUT_HARDWARE_MODULE_ID,
|
||||
(hw_module_t const**)&module);
|
||||
if (err) {
|
||||
ALOGE("Couldn't load %s module (%s)",
|
||||
TV_INPUT_HARDWARE_MODULE_ID, strerror(-err));
|
||||
return 0;
|
||||
}
|
||||
|
||||
tv_input_device_t* device = NULL;
|
||||
err = module->common.methods->open(
|
||||
(hw_module_t*)module,
|
||||
TV_INPUT_DEFAULT_DEVICE,
|
||||
(hw_device_t**)&device);
|
||||
if (err) {
|
||||
ALOGE("Couldn't open %s device (%s)",
|
||||
TV_INPUT_DEFAULT_DEVICE, strerror(-err));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return new JTvInputHal(env, thiz, device);
|
||||
}
|
||||
|
||||
int JTvInputHal::setSurface(int deviceId, int streamId, const sp<Surface>& surface) {
|
||||
Connection& connection = mConnections.editValueFor(deviceId);
|
||||
if (connection.mStreamId == streamId && connection.mSurface == surface) {
|
||||
// Nothing to do
|
||||
return NO_ERROR;
|
||||
}
|
||||
if (Surface::isValid(connection.mSurface)) {
|
||||
connection.mSurface.clear();
|
||||
}
|
||||
if (surface == NULL) {
|
||||
if (connection.mSurface != NULL) {
|
||||
connection.mSurface->setSidebandStream(NULL);
|
||||
connection.mSurface.clear();
|
||||
}
|
||||
if (connection.mSourceHandle != NULL) {
|
||||
// Need to reset streams
|
||||
if (mDevice->close_stream(
|
||||
mDevice, deviceId, connection.mStreamId) != 0) {
|
||||
ALOGE("Couldn't remove stream");
|
||||
return BAD_VALUE;
|
||||
}
|
||||
connection.mSourceHandle.clear();
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
connection.mSurface = surface;
|
||||
if (connection.mSourceHandle == NULL) {
|
||||
// Need to configure stream
|
||||
int numConfigs = 0;
|
||||
const tv_stream_config_t* configs = NULL;
|
||||
if (mDevice->get_stream_configurations(
|
||||
mDevice, deviceId, &numConfigs, &configs) != 0) {
|
||||
ALOGE("Couldn't get stream configs");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
int configIndex = -1;
|
||||
for (int i = 0; i < numConfigs; ++i) {
|
||||
if (configs[i].stream_id == streamId) {
|
||||
configIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (configIndex == -1) {
|
||||
ALOGE("Cannot find a config with given stream ID: %d", streamId);
|
||||
return BAD_VALUE;
|
||||
}
|
||||
// TODO: handle buffer producer profile.
|
||||
if (configs[configIndex].type !=
|
||||
TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE) {
|
||||
ALOGE("Profiles other than independent video source is not yet "
|
||||
"supported : type = %d", configs[configIndex].type);
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
tv_stream_t stream;
|
||||
stream.stream_id = configs[configIndex].stream_id;
|
||||
if (mDevice->open_stream(mDevice, deviceId, &stream) != 0) {
|
||||
ALOGE("Couldn't add stream");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
connection.mSourceHandle = NativeHandle::create(
|
||||
stream.sideband_stream_source_handle, false);
|
||||
connection.mStreamId = stream.stream_id;
|
||||
connection.mSurface->setSidebandStream(connection.mSourceHandle);
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
const tv_stream_config_t* JTvInputHal::getStreamConfigs(int deviceId, int* numConfigs) {
|
||||
const tv_stream_config_t* configs = NULL;
|
||||
if (mDevice->get_stream_configurations(
|
||||
mDevice, deviceId, numConfigs, &configs) != 0) {
|
||||
ALOGE("Couldn't get stream configs");
|
||||
return NULL;
|
||||
}
|
||||
return configs;
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
void JTvInputHal::notify(
|
||||
tv_input_device_t* dev, tv_input_event_t* event, void* data) {
|
||||
JTvInputHal* thiz = (JTvInputHal*)data;
|
||||
switch (event->type) {
|
||||
case TV_INPUT_EVENT_DEVICE_AVAILABLE: {
|
||||
thiz->onDeviceAvailable(event->device_info);
|
||||
} break;
|
||||
case TV_INPUT_EVENT_DEVICE_UNAVAILABLE: {
|
||||
thiz->onDeviceUnavailable(event->device_info.device_id);
|
||||
} break;
|
||||
case TV_INPUT_EVENT_STREAM_CONFIGURATIONS_CHANGED: {
|
||||
thiz->onStreamConfigurationsChanged(event->device_info.device_id);
|
||||
} break;
|
||||
default:
|
||||
ALOGE("Unrecognizable event");
|
||||
}
|
||||
}
|
||||
|
||||
void JTvInputHal::onDeviceAvailable(const tv_input_device_info_t& info) {
|
||||
JNIEnv* env = AndroidRuntime::getJNIEnv();
|
||||
mConnections.add(info.device_id, Connection());
|
||||
env->CallVoidMethod(
|
||||
mThiz,
|
||||
gTvInputHalClassInfo.deviceAvailable,
|
||||
info.device_id,
|
||||
info.type);
|
||||
}
|
||||
|
||||
void JTvInputHal::onDeviceUnavailable(int deviceId) {
|
||||
JNIEnv* env = AndroidRuntime::getJNIEnv();
|
||||
mConnections.removeItem(deviceId);
|
||||
env->CallVoidMethod(
|
||||
mThiz,
|
||||
gTvInputHalClassInfo.deviceUnavailable,
|
||||
deviceId);
|
||||
}
|
||||
|
||||
void JTvInputHal::onStreamConfigurationsChanged(int deviceId) {
|
||||
JNIEnv* env = AndroidRuntime::getJNIEnv();
|
||||
mConnections.removeItem(deviceId);
|
||||
env->CallVoidMethod(
|
||||
mThiz,
|
||||
gTvInputHalClassInfo.streamConfigsChanged,
|
||||
deviceId);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static jlong nativeOpen(JNIEnv* env, jobject thiz) {
|
||||
return (jlong)JTvInputHal::createInstance(env, thiz);
|
||||
}
|
||||
|
||||
static int nativeSetSurface(JNIEnv* env, jclass clazz,
|
||||
jlong ptr, jint deviceId, jint streamId, jobject jsurface) {
|
||||
JTvInputHal* tvInputHal = (JTvInputHal*)ptr;
|
||||
sp<Surface> surface(
|
||||
jsurface
|
||||
? android_view_Surface_getSurface(env, jsurface)
|
||||
: NULL);
|
||||
return tvInputHal->setSurface(deviceId, streamId, surface);
|
||||
}
|
||||
|
||||
static jobjectArray nativeGetStreamConfigs(JNIEnv* env, jclass clazz,
|
||||
jlong ptr, jint deviceId, jint generation) {
|
||||
JTvInputHal* tvInputHal = (JTvInputHal*)ptr;
|
||||
int numConfigs = 0;
|
||||
const tv_stream_config_t* configs = tvInputHal->getStreamConfigs(deviceId, &numConfigs);
|
||||
|
||||
jobjectArray result = env->NewObjectArray(numConfigs, gTvStreamConfigClassInfo.clazz, NULL);
|
||||
for (int i = 0; i < numConfigs; ++i) {
|
||||
jobject builder = env->NewObject(
|
||||
gTvStreamConfigBuilderClassInfo.clazz,
|
||||
gTvStreamConfigBuilderClassInfo.constructor);
|
||||
env->CallObjectMethod(
|
||||
builder, gTvStreamConfigBuilderClassInfo.streamId, configs[i].stream_id);
|
||||
env->CallObjectMethod(
|
||||
builder, gTvStreamConfigBuilderClassInfo.type, configs[i].type);
|
||||
env->CallObjectMethod(
|
||||
builder, gTvStreamConfigBuilderClassInfo.maxWidth, configs[i].max_video_width);
|
||||
env->CallObjectMethod(
|
||||
builder, gTvStreamConfigBuilderClassInfo.maxHeight, configs[i].max_video_height);
|
||||
env->CallObjectMethod(
|
||||
builder, gTvStreamConfigBuilderClassInfo.generation, generation);
|
||||
|
||||
jobject config = env->CallObjectMethod(builder, gTvStreamConfigBuilderClassInfo.build);
|
||||
|
||||
env->SetObjectArrayElement(result, i, config);
|
||||
|
||||
env->DeleteLocalRef(config);
|
||||
env->DeleteLocalRef(builder);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void nativeClose(JNIEnv* env, jclass clazz, jlong ptr) {
|
||||
JTvInputHal* tvInputHal = (JTvInputHal*)ptr;
|
||||
delete tvInputHal;
|
||||
}
|
||||
|
||||
static JNINativeMethod gTvInputHalMethods[] = {
|
||||
/* name, signature, funcPtr */
|
||||
{ "nativeOpen", "()J",
|
||||
(void*) nativeOpen },
|
||||
{ "nativeSetSurface", "(JIILandroid/view/Surface;)I",
|
||||
(void*) nativeSetSurface },
|
||||
{ "nativeGetStreamConfigs", "(JII)[Landroid/tv/TvStreamConfig;",
|
||||
(void*) nativeGetStreamConfigs },
|
||||
{ "nativeClose", "(J)V",
|
||||
(void*) nativeClose },
|
||||
};
|
||||
|
||||
#define FIND_CLASS(var, className) \
|
||||
var = env->FindClass(className); \
|
||||
LOG_FATAL_IF(! var, "Unable to find class " className)
|
||||
|
||||
#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
|
||||
var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
|
||||
LOG_FATAL_IF(! var, "Unable to find method" methodName)
|
||||
|
||||
int register_android_server_tv_TvInputHal(JNIEnv* env) {
|
||||
int res = jniRegisterNativeMethods(env, "com/android/server/tv/TvInputHal",
|
||||
gTvInputHalMethods, NELEM(gTvInputHalMethods));
|
||||
LOG_FATAL_IF(res < 0, "Unable to register native methods.");
|
||||
|
||||
jclass clazz;
|
||||
FIND_CLASS(clazz, "com/android/server/tv/TvInputHal");
|
||||
|
||||
GET_METHOD_ID(
|
||||
gTvInputHalClassInfo.deviceAvailable, clazz, "deviceAvailableFromNative", "(II)V");
|
||||
GET_METHOD_ID(
|
||||
gTvInputHalClassInfo.deviceUnavailable, clazz, "deviceUnavailableFromNative", "(I)V");
|
||||
GET_METHOD_ID(
|
||||
gTvInputHalClassInfo.streamConfigsChanged, clazz,
|
||||
"streamConfigsChangedFromNative", "(I)V");
|
||||
|
||||
FIND_CLASS(gTvStreamConfigClassInfo.clazz, "android/tv/TvStreamConfig");
|
||||
gTvStreamConfigClassInfo.clazz = jclass(env->NewGlobalRef(gTvStreamConfigClassInfo.clazz));
|
||||
|
||||
FIND_CLASS(gTvStreamConfigBuilderClassInfo.clazz, "android/tv/TvStreamConfig$Builder");
|
||||
gTvStreamConfigBuilderClassInfo.clazz =
|
||||
jclass(env->NewGlobalRef(gTvStreamConfigBuilderClassInfo.clazz));
|
||||
|
||||
GET_METHOD_ID(
|
||||
gTvStreamConfigBuilderClassInfo.constructor,
|
||||
gTvStreamConfigBuilderClassInfo.clazz,
|
||||
"<init>", "()V");
|
||||
GET_METHOD_ID(
|
||||
gTvStreamConfigBuilderClassInfo.streamId,
|
||||
gTvStreamConfigBuilderClassInfo.clazz,
|
||||
"streamId", "(I)Landroid/tv/TvStreamConfig$Builder;");
|
||||
GET_METHOD_ID(
|
||||
gTvStreamConfigBuilderClassInfo.type,
|
||||
gTvStreamConfigBuilderClassInfo.clazz,
|
||||
"type", "(I)Landroid/tv/TvStreamConfig$Builder;");
|
||||
GET_METHOD_ID(
|
||||
gTvStreamConfigBuilderClassInfo.maxWidth,
|
||||
gTvStreamConfigBuilderClassInfo.clazz,
|
||||
"maxWidth", "(I)Landroid/tv/TvStreamConfig$Builder;");
|
||||
GET_METHOD_ID(
|
||||
gTvStreamConfigBuilderClassInfo.maxHeight,
|
||||
gTvStreamConfigBuilderClassInfo.clazz,
|
||||
"maxHeight", "(I)Landroid/tv/TvStreamConfig$Builder;");
|
||||
GET_METHOD_ID(
|
||||
gTvStreamConfigBuilderClassInfo.generation,
|
||||
gTvStreamConfigBuilderClassInfo.clazz,
|
||||
"generation", "(I)Landroid/tv/TvStreamConfig$Builder;");
|
||||
GET_METHOD_ID(
|
||||
gTvStreamConfigBuilderClassInfo.build,
|
||||
gTvStreamConfigBuilderClassInfo.clazz,
|
||||
"build", "()Landroid/tv/TvStreamConfig;");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} /* namespace android */
|
@ -41,6 +41,7 @@ int register_android_server_dreams_McuHal(JNIEnv* env);
|
||||
int register_android_server_hdmi_HdmiCecController(JNIEnv* env);
|
||||
int register_android_server_hdmi_HdmiCecService(JNIEnv* env);
|
||||
int register_android_server_hdmi_HdmiMhlController(JNIEnv* env);
|
||||
int register_android_server_tv_TvInputHal(JNIEnv* env);
|
||||
};
|
||||
|
||||
using namespace android;
|
||||
@ -78,6 +79,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
|
||||
// TODO: remove this once replaces HdmiCecService with HdmiControlService.
|
||||
register_android_server_hdmi_HdmiCecService(env);
|
||||
register_android_server_hdmi_HdmiMhlController(env);
|
||||
register_android_server_tv_TvInputHal(env);
|
||||
|
||||
return JNI_VERSION_1_4;
|
||||
}
|
||||
|
Reference in New Issue
Block a user