11abddd9f6225298066094e20a6c29061b6af4590Nick Chalko/*
21abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Copyright (C) 2015 The Android Open Source Project
31abddd9f6225298066094e20a6c29061b6af4590Nick Chalko *
41abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Licensed under the Apache License, Version 2.0 (the "License");
51abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * you may not use this file except in compliance with the License.
61abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * You may obtain a copy of the License at
71abddd9f6225298066094e20a6c29061b6af4590Nick Chalko *
81abddd9f6225298066094e20a6c29061b6af4590Nick Chalko *      http://www.apache.org/licenses/LICENSE-2.0
91abddd9f6225298066094e20a6c29061b6af4590Nick Chalko *
101abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Unless required by applicable law or agreed to in writing, software
111abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * distributed under the License is distributed on an "AS IS" BASIS,
121abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * See the License for the specific language governing permissions and
141abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * limitations under the License.
151abddd9f6225298066094e20a6c29061b6af4590Nick Chalko */
161abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
1765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkopackage com.android.tv.tuner;
181abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
191abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.content.Context;
201abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.media.tv.TvInputManager;
211abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.os.ParcelFileDescriptor;
221abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.support.annotation.IntDef;
231abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.support.annotation.NonNull;
241abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.util.Log;
251abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
26ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport com.android.tv.common.recording.RecordingCapability;
2765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport com.android.tv.tuner.tvinput.TunerTvInputService;
28ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
291abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.lang.annotation.Retention;
301abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.lang.annotation.RetentionPolicy;
311abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.lang.reflect.InvocationTargetException;
321abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.lang.reflect.Method;
331abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.util.ArrayList;
341abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.util.Collections;
351abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.util.List;
3665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport java.util.Locale;
371abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
381abddd9f6225298066094e20a6c29061b6af4590Nick Chalko/**
391abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Provides with the file descriptors to access DVB device.
401abddd9f6225298066094e20a6c29061b6af4590Nick Chalko */
411abddd9f6225298066094e20a6c29061b6af4590Nick Chalkopublic class DvbDeviceAccessor {
421abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    private static final String TAG = "DvbDeviceAccessor";
431abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
441abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    @IntDef({DVB_DEVICE_DEMUX, DVB_DEVICE_DVR, DVB_DEVICE_FRONTEND})
451abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    @Retention(RetentionPolicy.SOURCE)
461abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    public @interface DvbDevice {}
471abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    public static final int DVB_DEVICE_DEMUX = 0; // TvInputManager.DVB_DEVICE_DEMUX;
481abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    public static final int DVB_DEVICE_DVR = 1; // TvInputManager.DVB_DEVICE_DVR;
491abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    public static final int DVB_DEVICE_FRONTEND = 2; // TvInputManager.DVB_DEVICE_FRONTEND;
501abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
511abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    private static Method sGetDvbDeviceListMethod;
521abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    private static Method sOpenDvbDeviceMethod;
531abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
541abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    private final TvInputManager mTvInputManager;
551abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
561abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    static {
571abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        try {
581abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            Class tvInputManagerClass = Class.forName("android.media.tv.TvInputManager");
591abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            Class dvbDeviceInfoClass = Class.forName("android.media.tv.DvbDeviceInfo");
601abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            sGetDvbDeviceListMethod = tvInputManagerClass.getDeclaredMethod("getDvbDeviceList");
611abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            sGetDvbDeviceListMethod.setAccessible(true);
621abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            sOpenDvbDeviceMethod = tvInputManagerClass.getDeclaredMethod(
631abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                    "openDvbDevice", dvbDeviceInfoClass, Integer.TYPE);
641abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            sOpenDvbDeviceMethod.setAccessible(true);
651abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        } catch (ClassNotFoundException e) {
661abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            Log.e(TAG, "Couldn't find class", e);
671abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        } catch (NoSuchMethodException e) {
681abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            Log.e(TAG, "Couldn't find method", e);
691abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        }
701abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
711abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
721abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    public DvbDeviceAccessor(Context context) {
7365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mTvInputManager = (TvInputManager) context.getSystemService(Context.TV_INPUT_SERVICE);
741abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
751abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
761abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    public List<DvbDeviceInfoWrapper> getDvbDeviceList() {
771abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        try {
781abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            List<DvbDeviceInfoWrapper> wrapperList = new ArrayList<>();
791abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            List dvbDeviceInfoList = (List) sGetDvbDeviceListMethod.invoke(mTvInputManager);
801abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            for (Object dvbDeviceInfo : dvbDeviceInfoList) {
811abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                wrapperList.add(new DvbDeviceInfoWrapper(dvbDeviceInfo));
821abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            }
831abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            Collections.sort(wrapperList);
841abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            return wrapperList;
851abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        } catch (IllegalAccessException e) {
861abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            Log.e(TAG, "Couldn't access", e);
871abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        } catch (InvocationTargetException e) {
881abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            Log.e(TAG, "Couldn't invoke", e);
891abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        }
901abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        return null;
911abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
921abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
9365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    /**
9465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     * Returns the number of currently connected DVB devices.
9565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     */
9665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public int getNumOfDvbDevices() {
9765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        List<DvbDeviceInfoWrapper> dvbDeviceList = getDvbDeviceList();
9865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        return dvbDeviceList == null ? 0 : dvbDeviceList.size();
9965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
10065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
1011abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    public boolean isDvbDeviceAvailable() {
1021abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        try {
1031abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            List dvbDeviceInfoList = (List) sGetDvbDeviceListMethod.invoke(mTvInputManager);
1041abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            return (!dvbDeviceInfoList.isEmpty());
1051abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        } catch (IllegalAccessException e) {
1061abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            Log.e(TAG, "Couldn't access", e);
1071abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        } catch (InvocationTargetException e) {
1081abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            Log.e(TAG, "Couldn't invoke", e);
1091abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        }
1101abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        return false;
1111abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
1121abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
1131abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    public ParcelFileDescriptor openDvbDevice(DvbDeviceInfoWrapper deviceInfo,
1141abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            @DvbDevice int device) {
1151abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        try {
1161abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            return (ParcelFileDescriptor) sOpenDvbDeviceMethod.invoke(
1171abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                    mTvInputManager, deviceInfo.getDvbDeviceInfo(), device);
1181abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        } catch (IllegalAccessException e) {
1191abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            Log.e(TAG, "Couldn't access", e);
1201abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        } catch (InvocationTargetException e) {
1211abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            Log.e(TAG, "Couldn't invoke", e);
1221abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        }
1231abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        return null;
1241abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
1251abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
126ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    /**
127ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     * Returns the current recording capability for USB tuner.
128ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     * @param inputId the input id to use.
129ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     */
130ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    public RecordingCapability getRecordingCapability(String inputId) {
131ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        List<DvbDeviceInfoWrapper> deviceList = getDvbDeviceList();
132ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        // TODO(DVR) implement accurate capabilities and updating values when needed.
133ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        return RecordingCapability.builder()
134ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko                .setInputId(inputId)
135ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko                .setMaxConcurrentPlayingSessions(1)
136ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko                .setMaxConcurrentTunedSessions(deviceList.size())
137ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko                .setMaxConcurrentSessionsOfAllTypes(deviceList.size() + 1)
138ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko                .build();
139ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    }
140ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
1411abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    public static class DvbDeviceInfoWrapper implements Comparable<DvbDeviceInfoWrapper> {
1421abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        private static Method sGetAdapterIdMethod;
1431abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        private static Method sGetDeviceIdMethod;
1441abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        private final Object mDvbDeviceInfo;
145ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        private final int mAdapterId;
146ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        private final int mDeviceId;
147ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        private final long mId;
1481abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
1491abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        static {
1501abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            try {
1511abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                Class dvbDeviceInfoClass = Class.forName("android.media.tv.DvbDeviceInfo");
1521abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                sGetAdapterIdMethod = dvbDeviceInfoClass.getDeclaredMethod("getAdapterId");
1531abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                sGetAdapterIdMethod.setAccessible(true);
1541abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                sGetDeviceIdMethod = dvbDeviceInfoClass.getDeclaredMethod("getDeviceId");
1551abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                sGetDeviceIdMethod.setAccessible(true);
1561abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            } catch (ClassNotFoundException e) {
1571abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                Log.e(TAG, "Couldn't find class", e);
1581abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            } catch (NoSuchMethodException e) {
1591abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                Log.e(TAG, "Couldn't find method", e);
1601abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            }
1611abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        }
1621abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
1631abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        public DvbDeviceInfoWrapper(Object dvbDeviceInfo) {
1641abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            mDvbDeviceInfo = dvbDeviceInfo;
165ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            mAdapterId = initAdapterId();
166ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            mDeviceId = initDeviceId();
167ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            mId = (((long) getAdapterId()) << 32) | (getDeviceId() & 0xffffffffL);
1681abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        }
1691abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
1701abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        public long getId() {
171ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            return mId;
1721abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        }
1731abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
1741abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        public int getAdapterId() {
175ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            return mAdapterId;
176ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        }
177ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
178ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        private int initAdapterId() {
1791abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            try {
1801abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                return (int) sGetAdapterIdMethod.invoke(mDvbDeviceInfo);
1811abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            } catch (InvocationTargetException e) {
1821abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                Log.e(TAG, "Couldn't invoke", e);
1831abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            } catch (IllegalAccessException e) {
1841abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                Log.e(TAG, "Couldn't access", e);
1851abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            }
1861abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            return -1;
1871abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        }
1881abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
1891abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        public int getDeviceId() {
190ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            return mDeviceId;
191ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        }
192ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
193ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        private int initDeviceId() {
1941abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            try {
1951abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                return (int) sGetDeviceIdMethod.invoke(mDvbDeviceInfo);
1961abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            } catch (InvocationTargetException e) {
1971abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                Log.e(TAG, "Couldn't invoke", e);
1981abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            } catch (IllegalAccessException e) {
1991abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                Log.e(TAG, "Couldn't access", e);
2001abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            }
2011abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            return -1;
2021abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        }
2031abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
2041abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        public Object getDvbDeviceInfo() {
2051abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            return mDvbDeviceInfo;
2061abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        }
2071abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
2081abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        @Override
2091abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        public int compareTo(@NonNull DvbDeviceInfoWrapper another) {
2101abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            if (getAdapterId() != another.getAdapterId()) {
2111abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                return getAdapterId() - another.getAdapterId();
2121abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            }
2131abddd9f6225298066094e20a6c29061b6af4590Nick Chalko            return getDeviceId() - another.getDeviceId();
2141abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        }
2151abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
2161abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        @Override
2171abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        public String toString() {
21865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return String.format(Locale.US, "DvbDeviceInfo {adapterId: %d, deviceId: %d}",
21965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    getAdapterId(),
2201abddd9f6225298066094e20a6c29061b6af4590Nick Chalko                    getDeviceId());
2211abddd9f6225298066094e20a6c29061b6af4590Nick Chalko        }
2221abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
2231abddd9f6225298066094e20a6c29061b6af4590Nick Chalko}
224