Java tutorial
/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.usbtuner; import android.annotation.TargetApi; import android.content.ComponentName; import android.content.Context; import android.media.tv.TvInputInfo; import android.media.tv.TvInputManager; import android.os.Build; import android.os.ParcelFileDescriptor; import android.support.annotation.IntDef; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.os.BuildCompat; import android.util.Log; import com.android.tv.common.SoftPreconditions; import com.android.tv.common.feature.CommonFeatures; import com.android.tv.common.recording.RecordingCapability; import com.android.usbtuner.tvinput.UsbTunerTvInputService; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * Provides with the file descriptors to access DVB device. */ public class DvbDeviceAccessor { private static final String TAG = "DvbDeviceAccessor"; @IntDef({ DVB_DEVICE_DEMUX, DVB_DEVICE_DVR, DVB_DEVICE_FRONTEND }) @Retention(RetentionPolicy.SOURCE) public @interface DvbDevice { } public static final int DVB_DEVICE_DEMUX = 0; // TvInputManager.DVB_DEVICE_DEMUX; public static final int DVB_DEVICE_DVR = 1; // TvInputManager.DVB_DEVICE_DVR; public static final int DVB_DEVICE_FRONTEND = 2; // TvInputManager.DVB_DEVICE_FRONTEND; private static Method sGetDvbDeviceListMethod; private static Method sOpenDvbDeviceMethod; private final TvInputManager mTvInputManager; static { try { Class tvInputManagerClass = Class.forName("android.media.tv.TvInputManager"); Class dvbDeviceInfoClass = Class.forName("android.media.tv.DvbDeviceInfo"); sGetDvbDeviceListMethod = tvInputManagerClass.getDeclaredMethod("getDvbDeviceList"); sGetDvbDeviceListMethod.setAccessible(true); sOpenDvbDeviceMethod = tvInputManagerClass.getDeclaredMethod("openDvbDevice", dvbDeviceInfoClass, Integer.TYPE); sOpenDvbDeviceMethod.setAccessible(true); } catch (ClassNotFoundException e) { Log.e(TAG, "Couldn't find class", e); } catch (NoSuchMethodException e) { Log.e(TAG, "Couldn't find method", e); } } public DvbDeviceAccessor(Context context) { mTvInputManager = (TvInputManager) context.getSystemService(context.TV_INPUT_SERVICE); } public List<DvbDeviceInfoWrapper> getDvbDeviceList() { try { List<DvbDeviceInfoWrapper> wrapperList = new ArrayList<>(); List dvbDeviceInfoList = (List) sGetDvbDeviceListMethod.invoke(mTvInputManager); for (Object dvbDeviceInfo : dvbDeviceInfoList) { wrapperList.add(new DvbDeviceInfoWrapper(dvbDeviceInfo)); } Collections.sort(wrapperList); return wrapperList; } catch (IllegalAccessException e) { Log.e(TAG, "Couldn't access", e); } catch (InvocationTargetException e) { Log.e(TAG, "Couldn't invoke", e); } return null; } public boolean isDvbDeviceAvailable() { try { List dvbDeviceInfoList = (List) sGetDvbDeviceListMethod.invoke(mTvInputManager); return (!dvbDeviceInfoList.isEmpty()); } catch (IllegalAccessException e) { Log.e(TAG, "Couldn't access", e); } catch (InvocationTargetException e) { Log.e(TAG, "Couldn't invoke", e); } return false; } public ParcelFileDescriptor openDvbDevice(DvbDeviceInfoWrapper deviceInfo, @DvbDevice int device) { try { return (ParcelFileDescriptor) sOpenDvbDeviceMethod.invoke(mTvInputManager, deviceInfo.getDvbDeviceInfo(), device); } catch (IllegalAccessException e) { Log.e(TAG, "Couldn't access", e); } catch (InvocationTargetException e) { Log.e(TAG, "Couldn't invoke", e); } return null; } /** * Returns the current recording capability for USB tuner. * @param inputId the input id to use. */ public RecordingCapability getRecordingCapability(String inputId) { List<DvbDeviceInfoWrapper> deviceList = getDvbDeviceList(); // TODO(DVR) implement accurate capabilities and updating values when needed. return RecordingCapability.builder().setInputId(inputId).setMaxConcurrentPlayingSessions(1) .setMaxConcurrentTunedSessions(deviceList.size()) .setMaxConcurrentSessionsOfAllTypes(deviceList.size() + 1).build(); } @Nullable @TargetApi(Build.VERSION_CODES.N) public TvInputInfo buildTvInputInfo(Context context) { List<DvbDeviceInfoWrapper> deviceList = getDvbDeviceList(); TvInputInfo.Builder builder = new TvInputInfo.Builder(context, new ComponentName(context, UsbTunerTvInputService.class)); if (deviceList.size() > 0) { return builder.setCanRecord(CommonFeatures.DVR.isEnabled(context) && BuildCompat.isAtLeastN()) .setTunerCount(deviceList.size()).build(); } else { return null; } } public static class DvbDeviceInfoWrapper implements Comparable<DvbDeviceInfoWrapper> { private static Method sGetAdapterIdMethod; private static Method sGetDeviceIdMethod; private final Object mDvbDeviceInfo; private final int mAdapterId; private final int mDeviceId; private final long mId; static { try { Class dvbDeviceInfoClass = Class.forName("android.media.tv.DvbDeviceInfo"); sGetAdapterIdMethod = dvbDeviceInfoClass.getDeclaredMethod("getAdapterId"); sGetAdapterIdMethod.setAccessible(true); sGetDeviceIdMethod = dvbDeviceInfoClass.getDeclaredMethod("getDeviceId"); sGetDeviceIdMethod.setAccessible(true); } catch (ClassNotFoundException e) { Log.e(TAG, "Couldn't find class", e); } catch (NoSuchMethodException e) { Log.e(TAG, "Couldn't find method", e); } } public DvbDeviceInfoWrapper(Object dvbDeviceInfo) { mDvbDeviceInfo = dvbDeviceInfo; mAdapterId = initAdapterId(); mDeviceId = initDeviceId(); mId = (((long) getAdapterId()) << 32) | (getDeviceId() & 0xffffffffL); } public long getId() { return mId; } public int getAdapterId() { return mAdapterId; } private int initAdapterId() { try { return (int) sGetAdapterIdMethod.invoke(mDvbDeviceInfo); } catch (InvocationTargetException e) { Log.e(TAG, "Couldn't invoke", e); } catch (IllegalAccessException e) { Log.e(TAG, "Couldn't access", e); } return -1; } public int getDeviceId() { return mDeviceId; } private int initDeviceId() { try { return (int) sGetDeviceIdMethod.invoke(mDvbDeviceInfo); } catch (InvocationTargetException e) { Log.e(TAG, "Couldn't invoke", e); } catch (IllegalAccessException e) { Log.e(TAG, "Couldn't access", e); } return -1; } public Object getDvbDeviceInfo() { return mDvbDeviceInfo; } @Override public int compareTo(@NonNull DvbDeviceInfoWrapper another) { if (getAdapterId() != another.getAdapterId()) { return getAdapterId() - another.getAdapterId(); } return getDeviceId() - another.getDeviceId(); } @Override public String toString() { return String.format("DvbDeviceInfo {adapterId: %d, deviceId: %d}", getAdapterId(), getDeviceId()); } } }