mediametadataretriever.cpp revision 7562408b2261d38415453378b6188f74fda99d88
189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project/*
289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project**
389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project** Copyright 2008, The Android Open Source Project
489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project**
589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");
689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project** you may not use this file except in compliance with the License.
789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project** You may obtain a copy of the License at
889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project**
989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project**     http://www.apache.org/licenses/LICENSE-2.0
1089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project**
1189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project** Unless required by applicable law or agreed to in writing, software
1289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project** distributed under the License is distributed on an "AS IS" BASIS,
1389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project** See the License for the specific language governing permissions and
1589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project** limitations under the License.
1689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project*/
1789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
1889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project//#define LOG_NDEBUG 0
1989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#define LOG_TAG "MediaMetadataRetriever"
2089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
217562408b2261d38415453378b6188f74fda99d88Mathias Agopian#include <binder/IServiceManager.h>
227562408b2261d38415453378b6188f74fda99d88Mathias Agopian#include <binder/IPCThreadState.h>
2389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#include <media/mediametadataretriever.h>
2489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#include <media/IMediaPlayerService.h>
2589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#include <utils/Log.h>
2689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#include <dlfcn.h>
2789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
2889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectnamespace android {
2989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
3089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project// client singleton for binder interface to service
3189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source ProjectMutex MediaMetadataRetriever::sServiceLock;
3289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectsp<IMediaPlayerService> MediaMetadataRetriever::sService;
3389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectsp<MediaMetadataRetriever::DeathNotifier> MediaMetadataRetriever::sDeathNotifier;
3489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
3589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectconst sp<IMediaPlayerService>& MediaMetadataRetriever::getService()
3689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project{
3789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    Mutex::Autolock lock(sServiceLock);
3889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    if (sService.get() == 0) {
3989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        sp<IServiceManager> sm = defaultServiceManager();
4089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        sp<IBinder> binder;
4189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        do {
4289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            binder = sm->getService(String16("media.player"));
4389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            if (binder != 0) {
4489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                break;
4589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            }
4689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            LOGW("MediaPlayerService not published, waiting...");
4789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            usleep(500000); // 0.5 s
4889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        } while(true);
4989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        if (sDeathNotifier == NULL) {
5089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            sDeathNotifier = new DeathNotifier();
5189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        }
5289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        binder->linkToDeath(sDeathNotifier);
5389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        sService = interface_cast<IMediaPlayerService>(binder);
5489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    }
5589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    LOGE_IF(sService == 0, "no MediaPlayerService!?");
5689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    return sService;
5789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project}
5889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
5989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source ProjectMediaMetadataRetriever::MediaMetadataRetriever()
6089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project{
6189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    LOGV("constructor");
6289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    const sp<IMediaPlayerService>& service(getService());
6389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    if (service == 0) {
6489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        LOGE("failed to obtain MediaMetadataRetrieverService");
6589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        return;
6689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    }
6789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    sp<IMediaMetadataRetriever> retriever(service->createMetadataRetriever(getpid()));
6889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    if (retriever == 0) {
6989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        LOGE("failed to create IMediaMetadataRetriever object from server");
7089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    }
7189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    mRetriever = retriever;
7289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project}
7389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
7489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source ProjectMediaMetadataRetriever::~MediaMetadataRetriever()
7589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project{
7689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    LOGV("destructor");
7789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    disconnect();
7889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    IPCThreadState::self()->flushCommands();
7989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project}
8089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
8189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectvoid MediaMetadataRetriever::disconnect()
8289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project{
8389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    LOGV("disconnect");
8489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    sp<IMediaMetadataRetriever> retriever;
8589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    {
8689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        Mutex::Autolock _l(mLock);
8789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        retriever = mRetriever;
8889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        mRetriever.clear();
8989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    }
9089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    if (retriever != 0) {
9189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        retriever->disconnect();
9289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    }
9389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project}
9489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
9589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectstatus_t MediaMetadataRetriever::setDataSource(const char* srcUrl)
9689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project{
9789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    LOGV("setDataSource");
9889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    if (mRetriever == 0) {
9989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        LOGE("retriever is not initialized");
10089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        return INVALID_OPERATION;
10189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    }
10289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    if (srcUrl == NULL) {
10389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        LOGE("data source is a null pointer");
10489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        return UNKNOWN_ERROR;
10589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    }
10689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    LOGV("data source (%s)", srcUrl);
10789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    return mRetriever->setDataSource(srcUrl);
10889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project}
10989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
11089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectstatus_t MediaMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t length)
11189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project{
11289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
11389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    if (mRetriever == 0) {
11489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        LOGE("retriever is not initialized");
11589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        return INVALID_OPERATION;
11689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    }
11789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    if (fd < 0 || offset < 0 || length < 0) {
11889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        LOGE("Invalid negative argument");
11989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        return UNKNOWN_ERROR;
12089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    }
12189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    return mRetriever->setDataSource(fd, offset, length);
12289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project}
12389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
12489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectstatus_t MediaMetadataRetriever::setMode(int mode)
12589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project{
12689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    LOGV("setMode(%d)", mode);
12789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    if (mRetriever == 0) {
12889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        LOGE("retriever is not initialized");
12989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        return INVALID_OPERATION;
13089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    }
13189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    return mRetriever->setMode(mode);
13289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project}
13389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
13489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectstatus_t MediaMetadataRetriever::getMode(int* mode)
13589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project{
13689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    LOGV("getMode");
13789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    if (mRetriever == 0) {
13889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        LOGE("retriever is not initialized");
13989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        return INVALID_OPERATION;
14089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    }
14189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    return mRetriever->getMode(mode);
14289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project}
14389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
14489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectsp<IMemory> MediaMetadataRetriever::captureFrame()
14589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project{
14689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    LOGV("captureFrame");
14789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    if (mRetriever == 0) {
14889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        LOGE("retriever is not initialized");
14989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        return NULL;
15089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    }
15189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    return mRetriever->captureFrame();
15289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project}
15389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
15489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectconst char* MediaMetadataRetriever::extractMetadata(int keyCode)
15589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project{
15689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    LOGV("extractMetadata(%d)", keyCode);
15789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    if (mRetriever == 0) {
15889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        LOGE("retriever is not initialized");
15989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        return NULL;
16089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    }
16189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    return mRetriever->extractMetadata(keyCode);
16289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project}
16389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
16489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectsp<IMemory> MediaMetadataRetriever::extractAlbumArt()
16589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project{
16689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    LOGV("extractAlbumArt");
16789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    if (mRetriever == 0) {
16889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        LOGE("retriever is not initialized");
16989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        return NULL;
17089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    }
17189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    return mRetriever->extractAlbumArt();
17289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project}
17389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
17489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectvoid MediaMetadataRetriever::DeathNotifier::binderDied(const wp<IBinder>& who) {
17589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    Mutex::Autolock lock(MediaMetadataRetriever::sServiceLock);
17689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    MediaMetadataRetriever::sService.clear();
17789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    LOGW("MediaMetadataRetriever server died!");
17889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project}
17989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
18089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source ProjectMediaMetadataRetriever::DeathNotifier::~DeathNotifier()
18189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project{
18289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    Mutex::Autolock lock(sServiceLock);
18389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    if (sService != 0) {
18489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        sService->asBinder()->unlinkToDeath(this);
18589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    }
18689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project}
18789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
18889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project}; // namespace android
189