<commit_before>/*
 HostDeviceService.java
 Copyright (c) 2014 NTT DOCOMO,INC.
 Released under the MIT license
 http://opensource.org/licenses/mit-license.php
 */
package org.deviceconnect.android.deviceplugin.host;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;

import org.deviceconnect.android.deviceplugin.host.camera.CameraOverlay;
import org.deviceconnect.android.deviceplugin.host.camera.MixedReplaceMediaServer;
import org.deviceconnect.android.deviceplugin.host.file.FileDataManager;
import org.deviceconnect.android.deviceplugin.host.manager.HostBatteryManager;
import org.deviceconnect.android.deviceplugin.host.profile.HostBatteryProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostCanvasProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostConnectProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostDeviceOrientationProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostFileDescriptorProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostFileProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostMediaPlayerProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostMediaStreamingRecordingProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostNotificationProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostPhoneProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostProximityProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostServiceDiscoveryProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostSettingsProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostSystemProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostTouchProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostKeyEventProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostVibrationProfile;
import org.deviceconnect.android.deviceplugin.host.video.VideoConst;
import org.deviceconnect.android.deviceplugin.host.video.VideoPlayer;
import org.deviceconnect.android.event.Event;
import org.deviceconnect.android.event.EventManager;
import org.deviceconnect.android.event.cache.MemoryCacheController;
import org.deviceconnect.android.message.DConnectMessageService;
import org.deviceconnect.android.message.MessageUtils;
import org.deviceconnect.android.profile.MediaPlayerProfile;
import org.deviceconnect.android.profile.ServiceDiscoveryProfile;
import org.deviceconnect.android.profile.ServiceInformationProfile;
import org.deviceconnect.android.profile.SystemProfile;
import org.deviceconnect.android.provider.FileManager;
import org.deviceconnect.message.DConnectMessage;
import org.deviceconnect.profile.PhoneProfileConstants.CallState;

import android.app.ActivityManager;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.provider.MediaStore;
import android.webkit.MimeTypeMap;

/**
 * Host Device Service.
 * 
 * @author NTT DOCOMO, INC.
 */
public class HostDeviceService extends DConnectMessageService {
    /** Application class instance. */
    private HostDeviceApplication mApp;

    /** マルチキャスト用のタグ. */
    private static final String HOST_MULTICAST = "deviceplugin.host";

    /** ファイル管理クラス. */
    private FileManager mFileMgr;

    /** ServiceID. */
    private String mServiceId;

    /** バッテリー関連の処理と値処理. */
    private HostBatteryManager mHostBatteryManager;

    /** ミリ秒 - 秒オーダー変換用. */
    private static final int UNIT_SEC = 1000;

    /** Video Current Position response. */
    private Intent mResponse = null;

    /** Intent filter for battery charge event. */
    private IntentFilter mIfBatteryCharge;

    /** Intent filter for battery connect event. */
    private IntentFilter mIfBatteryConnect;

    /** ファイルデータ管理クラス. */
    private FileDataManager mFileDataManager;

    @Override
    public void onCreate() {

        super.onCreate();
        
        // Get application class instance.
        mApp = (HostDeviceApplication) this.getApplication();

        // Get application class instance.
        mApp = (HostDeviceApplication) this.getApplication();

        // EventManagerの初期化
        EventManager.INSTANCE.setController(new MemoryCacheController());

        // ファイル管理クラスの作成
        mFileMgr = new FileManager(this);
        mFileDataManager = new FileDataManager(mFileMgr);
        mFileDataManager.startTimer();

        // add supported profiles
        addProfile(new HostConnectProfile(BluetoothAdapter.getDefaultAdapter()));
        addProfile(new HostNotificationProfile());
        addProfile(new HostDeviceOrientationProfile());
        addProfile(new HostBatteryProfile());
        addProfile(new HostMediaStreamingRecordingProfile());
        addProfile(new HostPhoneProfile());
        addProfile(new HostSettingsProfile());
        addProfile(new HostMediaPlayerProfile());
        addProfile(new HostFileProfile(mFileMgr));
        addProfile(new HostFileDescriptorProfile(mFileDataManager));
        addProfile(new HostVibrationProfile());
        addProfile(new HostProximityProfile());
        addProfile(new HostCanvasProfile());
        addProfile(new HostTouchProfile());
        addProfile(new HostKeyEventProfile());

        // バッテリー関連の処理と値の保持
        mHostBatteryManager = new HostBatteryManager();
        mHostBatteryManager.getBatteryInfo(this.getContext());

        mIfBatteryCharge = new IntentFilter();
        mIfBatteryCharge.addAction(Intent.ACTION_BATTERY_CHANGED);
        mIfBatteryCharge.addAction(Intent.ACTION_BATTERY_LOW);
        mIfBatteryCharge.addAction(Intent.ACTION_BATTERY_OKAY);

        mIfBatteryConnect = new IntentFilter();
        mIfBatteryConnect.addAction(Intent.ACTION_POWER_CONNECTED);
        mIfBatteryConnect.addAction(Intent.ACTION_POWER_DISCONNECTED);

        // オーバーレイ
        mCameraOverlay = new CameraOverlay(this);
        mCameraOverlay.setFileManager(mFileMgr);
    }

    @Override
    public int onStartCommand(final Intent intent, final int flags, final int startId) {

        if (intent == null) {
            return START_STICKY;
        }
        String action = intent.getAction();
        if (action.equals("android.intent.action.NEW_OUTGOING_CALL")) {
            // Phone
            List<Event> events = EventManager.INSTANCE.getEventList(mServiceId, HostPhoneProfile.PROFILE_NAME, null,
                    HostPhoneProfile.ATTRIBUTE_ON_CONNECT);

            for (int i = 0; i < events.size(); i++) {
                Event event = events.get(i);
                Intent mIntent = EventManager.createEventMessage(event);
                HostPhoneProfile.setAttribute(mIntent, HostPhoneProfile.ATTRIBUTE_ON_CONNECT);
                Bundle phoneStatus = new Bundle();
                HostPhoneProfile.setPhoneNumber(phoneStatus, intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER));
                HostPhoneProfile.setState(phoneStatus, CallState.START);
                HostPhoneProfile.setPhoneStatus(mIntent, phoneStatus);
                getContext().sendBroadcast(mIntent);
            }
            return START_STICKY;
        } else if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)
                || WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
            // Wifi
            List<Event> events = EventManager.INSTANCE.getEventList(mServiceId, HostConnectProfile.PROFILE_NAME, null,
                    HostConnectProfile.ATTRIBUTE_ON_WIFI_CHANGE);

            for (int i = 0; i < events.size(); i++) {
                Event event = events.get(i);
                Intent mIntent = EventManager.createEventMessage(event);
                HostConnectProfile.setAttribute(mIntent, HostConnectProfile.ATTRIBUTE_ON_WIFI_CHANGE);
                Bundle wifiConnecting = new Bundle();
                WifiManager wifiMgr = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
                HostConnectProfile.setEnable(wifiConnecting, wifiMgr.isWifiEnabled());
                HostConnectProfile.setConnectStatus(mIntent, wifiConnecting);
                getContext().sendBroadcast(mIntent);
            }
            return START_STICKY;
        } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
            List<Event> events = EventManager.INSTANCE.getEventList(mServiceId, HostConnectProfile.PROFILE_NAME, null,
                    HostConnectProfile.ATTRIBUTE_ON_BLUETOOTH_CHANGE);

            for (int i = 0; i < events.size(); i++) {
                Event event = events.get(i);
                Intent mIntent = EventManager.createEventMessage(event);
                HostConnectProfile.setAttribute(mIntent, HostConnectProfile.ATTRIBUTE_ON_BLUETOOTH_CHANGE);
                Bundle bluetoothConnecting = new Bundle();
                BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
                HostConnectProfile.setEnable(bluetoothConnecting, mBluetoothAdapter.isEnabled());
                HostConnectProfile.setConnectStatus(mIntent, bluetoothConnecting);
                getContext().sendBroadcast(mIntent);
            }
            return START_STICKY;
        }
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mFileDataManager.stopTimer();
    }

    /**
     * Get a instance of FileManager.
     * 
     * @return FileManager
     */
    public FileManager getFileManager() {
        return mFileMgr;
    }

    /**
     * Register broadcast receiver for battery charge event.
     */
    public void registerBatteryChargeBroadcastReceiver() {
        registerReceiver(mBatteryChargeBR, mIfBatteryCharge);
    }

    /**
     * Unregister broadcast receiver for battery charge event.
     */
    public void unregisterBatteryChargeBroadcastReceiver() {
        unregisterReceiver(mBatteryChargeBR);
    }

    /**
     * Register broadcast receiver for battery connect event.
     */
    public void registerBatteryConnectBroadcastReceiver() {
        registerReceiver(mBatteryConnectBR, mIfBatteryConnect);
    }

    /**
     * Unregister broadcast receiver for battery connect event.
     */
    public void unregisterBatteryConnectBroadcastReceiver() {
        unregisterReceiver(mBatteryConnectBR);
    }

    /**
     * Broadcast receiver for battery charge event.
     */
    private BroadcastReceiver mBatteryChargeBR = new BroadcastReceiver() {
        @Override
        public void onReceive(final Context context, final Intent intent) {
            String action = intent.getAction();
            if (Intent.ACTION_BATTERY_CHANGED.equals(action) || Intent.ACTION_BATTERY_LOW.equals(action)
                    || Intent.ACTION_BATTERY_OKAY.equals(action)) {
                // バッテリーが変化した時
                mHostBatteryManager.setBatteryRequest(intent);
                List<Event> events = EventManager.INSTANCE.getEventList(mServiceId, HostBatteryProfile.PROFILE_NAME,
                        null, HostBatteryProfile.ATTRIBUTE_ON_BATTERY_CHANGE);

                for (int i = 0; i < events.size(); i++) {
                    Event event = events.get(i);
                    Intent mIntent = EventManager.createEventMessage(event);
                    HostBatteryProfile.setAttribute(mIntent, HostBatteryProfile.ATTRIBUTE_ON_BATTERY_CHANGE);
                    Bundle battery = new Bundle();
                    double level = ((double) (mHostBatteryManager.getBatteryLevel())) / ((double) getBatteryScale());
                    HostBatteryProfile.setLevel(battery, level);
                    HostBatteryProfile.setBattery(mIntent, battery);
                    getContext().sendBroadcast(mIntent);
                }
            }
        }
    };

    /**
     * Broadcast receiver for battery connect event.
     */
    private BroadcastReceiver mBatteryConnectBR = new BroadcastReceiver() {
        @Override
        public void onReceive(final Context context, final Intent intent) {
            String action = intent.getAction();
            if (Intent.ACTION_POWER_CONNECTED.equals(action) || Intent.ACTION_POWER_DISCONNECTED.equals(action)) {
                // バッテリーが充電された時
                mHostBatteryManager.setBatteryRequest(intent);
                List<Event> events = EventManager.INSTANCE.getEventList(mServiceId, HostBatteryProfile.PROFILE_NAME,
                        null, HostBatteryProfile.ATTRIBUTE_ON_CHARGING_CHANGE);

                for (int i = 0; i < events.size(); i++) {
                    Event event = events.get(i);
                    Intent mIntent = EventManager.createEventMessage(event);
                    HostBatteryProfile.setAttribute(mIntent, HostBatteryProfile.ATTRIBUTE_ON_CHARGING_CHANGE);
                    Bundle charging = new Bundle();
                    if (Intent.ACTION_POWER_CONNECTED.equals(action)) {
                        HostBatteryProfile.setCharging(charging, true);
                    } else {
                        HostBatteryProfile.setCharging(charging, false);
                    }
                    HostBatteryProfile.setBattery(mIntent, charging);
                    getContext().sendBroadcast(mIntent);
                }
            }
        }
    };

    @Override
    protected SystemProfile getSystemProfile() {
        return new HostSystemProfile();
    }

    @Override
    protected ServiceInformationProfile getServiceInformationProfile() {
        return new ServiceInformationProfile(this) {
        };
    }

    @Override
    protected ServiceDiscoveryProfile getServiceDiscoveryProfile() {
        return new HostServiceDiscoveryProfile(this);
    }

    /**
     * ServiceIDを設定.
     * 
     * @param serviceId サービスID
     */
    public void setServiceId(final String serviceId) {
        mServiceId = serviceId;
    }

    /**
     * Battery Profile<br>
     * バッテリーレベルを取得.
     * 
     * @return バッテリーレベル
     */
    public int getBatteryLevel() {
        mHostBatteryManager.getBatteryInfo(this.getContext());
        return mHostBatteryManager.getBatteryLevel();
    }

    /**
     * Battery Profile<br>
     * バッテリーステータスを取得.
     * 
     * @return バッテリーレベル
     */
    public int getBatteryStatus() {
        mHostBatteryManager.getBatteryInfo(this.getContext());
        return mHostBatteryManager.getBatteryStatus();
    }

    /**
     * Battery Profile<br>
     * バッテリーレベルを取得.
     * 
     * @return バッテリーレベル
     */
    public int getBatteryScale() {
        mHostBatteryManager.getBatteryInfo(this.getContext());
        return mHostBatteryManager.getBatteryScale();
    }

    //
    // File Descriptor Profile
    //

    /**
     * ファイル操作管理クラスを取得する.
     * @return FileDataManager
     */
    public FileDataManager getFileDataManager() {
        return mFileDataManager;
    }

    // ----------------------------------------------
    // MediaPlayer Profile
    // ----------------------------------------------
    /** MediaPlayerのインスタンス. */
    private MediaPlayer mMediaPlayer;
    /** Mediaのステータス. */
    private int mMediaStatus = 0;
    /** Mediaが未設定. */
    private static final int MEDIA_PLAYER_NODATA = 0;
    /** Mediaがセット. */
    private static final int MEDIA_PLAYER_SET = 1;
    /** Mediaが再生中. */
    private static final int MEDIA_PLAYER_PLAY = 2;
    /** Mediaが一時停止中. */
    private static final int MEDIA_PLAYER_PAUSE = 3;
    /** Mediaが停止. */
    private static final int MEDIA_PLAYER_STOP = 4;
    /** Mediaが再生完了. */
    private static final int MEDIA_PLAYER_COMPLETE = 5;
    /** MEDIAタイプ(動画). */
    private static final int MEDIA_TYPE_VIDEO = 1;
    /** MEDIAタイプ(音楽). */
    private static final int MEDIA_TYPE_MUSIC = 2;
    // /** MEDIAタイプ(音声). */
    // private static final int MEDIA_TYPE_AUDIO = 3;
    /** Media Status. */
    private int mSetMediaType = 0;
    /** onStatusChange Eventの状態. */
    private boolean mOnStatusChangeEventFlag = false;
    /** 現在再生中のファイルパス. */
    private String mMyCurrentFilePath = "";
    /** 現在再生中のファイルパス. */
    private String mMyCurrentFileMIMEType = "";
    /** 現在再生中のPosition. */
    private int mMyCurrentMediaPosition = 0;
    /** Backup MediaId. (Used in KITKAT more). */
    String mBackupMediaId;
    /** Media duration. */
    private int mMyCurrentMediaDuration = 0;

    /**
     * サポートしているaudioのタイプ一覧.
     */
    private static final List<String> AUDIO_TYPE_LIST = Arrays.asList("audio/mpeg", "audio/x-wav", "application/ogg",
            "audio/x-ms-wma", "audio/mp3", "audio/ogg", "audio/mp4");

    /**
     * サポートしているvideoのタイプ一覧.
     */
    private static final List<String> VIDEO_TYPE_LIST = Arrays.asList("video/3gpp", "video/mp4", "video/m4v",
            "video/3gpp2", "video/mpeg");

    /**
     * 再生するメディアをセットする(Idから).
     * 
     * @param response レスポンス
     * @param mediaId MediaID
     */
    public void putMediaId(final Intent response, final String mediaId) {
        // Backup MediaId.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            mBackupMediaId = mediaId;
        }

        // Videoとしてパスを取得
        Uri mUri = ContentUris.withAppendedId(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, Long.valueOf(mediaId));

        String filePath = getPathFromUri(mUri);

        // nullなら、Audioとしてパスを取得
        if (filePath == null) {
            mUri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, Long.valueOf(mediaId));
            filePath = getPathFromUri(mUri);
        }

        String mMineType = getMIMEType(filePath);

        // パス指定の場合
        if (AUDIO_TYPE_LIST.contains(mMineType)) {
            mMediaPlayer = new MediaPlayer();

            try {
                mSetMediaType = MEDIA_TYPE_MUSIC;
                mMyCurrentFilePath = filePath;
                mMyCurrentFileMIMEType = mMineType;
                mMediaStatus = MEDIA_PLAYER_SET;
                mMediaPlayer.setDataSource(filePath);
                mMediaPlayer.setOnCompletionListener(new OnCompletionListener() {
                    @Override
                    public void onCompletion(final MediaPlayer arg0) {
                        mMediaStatus = MEDIA_PLAYER_COMPLETE;
                        sendOnStatusChangeEvent("complete");
                    }
                });
                mMediaPlayer.prepareAsync();
                mMyCurrentMediaPosition = 0;
                mMediaPlayer.setOnPreparedListener(new OnPreparedListener() {
                    @Override
                    public void onPrepared(final MediaPlayer mp) {
                        mMyCurrentMediaDuration = mMediaPlayer.getDuration() / UNIT_SEC;
                    }
                });

                if (response != null) {
                    response.putExtra(DConnectMessage.EXTRA_RESULT,
                            DConnectMessage.RESULT_OK);
                    response.putExtra(DConnectMessage.EXTRA_VALUE, "regist:"
                            + filePath);
                    sendOnStatusChangeEvent("media");
                    sendBroadcast(response);
                }
            } catch (IOException e) {
                if (response != null) {
                    response.putExtra(DConnectMessage.EXTRA_RESULT,
                            DConnectMessage.EXTRA_ERROR_CODE);
                    response.putExtra(DConnectMessage.EXTRA_VALUE,
                            "can't not mount:" + filePath);
                    sendBroadcast(response);
                }
            }
        } else if (VIDEO_TYPE_LIST.contains(mMineType)) {
            try {

                mSetMediaType = MEDIA_TYPE_VIDEO;
                mMyCurrentFilePath = filePath;
                mMyCurrentFileMIMEType = mMineType;

                mMediaPlayer = new MediaPlayer();
                FileInputStream fis = null;
                FileDescriptor mFd = null;

                fis = new FileInputStream(mMyCurrentFilePath);
                mFd = fis.getFD();

                mMediaPlayer.setDataSource(mFd);
                mMediaPlayer.prepare();
                mMyCurrentMediaDuration = mMediaPlayer.getDuration() / UNIT_SEC;
                mMediaPlayer.release();
                fis.close();

                if (response != null) {
                    response.putExtra(DConnectMessage.EXTRA_RESULT,
                            DConnectMessage.RESULT_OK);
                    response.putExtra(DConnectMessage.EXTRA_VALUE, "regist:"
                            + filePath);
                    sendOnStatusChangeEvent("media");
                    sendBroadcast(response);
                }
            } catch (IllegalArgumentException e) {
                if (response != null) {<commit_msg>Modify Host MediaPlayer Profile.   Fix media player variable overwrite.<commit_after>/*
 HostDeviceService.java
 Copyright (c) 2014 NTT DOCOMO,INC.
 Released under the MIT license
 http://opensource.org/licenses/mit-license.php
 */
package org.deviceconnect.android.deviceplugin.host;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;

import org.deviceconnect.android.deviceplugin.host.camera.CameraOverlay;
import org.deviceconnect.android.deviceplugin.host.camera.MixedReplaceMediaServer;
import org.deviceconnect.android.deviceplugin.host.file.FileDataManager;
import org.deviceconnect.android.deviceplugin.host.manager.HostBatteryManager;
import org.deviceconnect.android.deviceplugin.host.profile.HostBatteryProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostCanvasProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostConnectProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostDeviceOrientationProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostFileDescriptorProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostFileProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostMediaPlayerProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostMediaStreamingRecordingProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostNotificationProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostPhoneProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostProximityProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostServiceDiscoveryProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostSettingsProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostSystemProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostTouchProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostKeyEventProfile;
import org.deviceconnect.android.deviceplugin.host.profile.HostVibrationProfile;
import org.deviceconnect.android.deviceplugin.host.video.VideoConst;
import org.deviceconnect.android.deviceplugin.host.video.VideoPlayer;
import org.deviceconnect.android.event.Event;
import org.deviceconnect.android.event.EventManager;
import org.deviceconnect.android.event.cache.MemoryCacheController;
import org.deviceconnect.android.message.DConnectMessageService;
import org.deviceconnect.android.message.MessageUtils;
import org.deviceconnect.android.profile.MediaPlayerProfile;
import org.deviceconnect.android.profile.ServiceDiscoveryProfile;
import org.deviceconnect.android.profile.ServiceInformationProfile;
import org.deviceconnect.android.profile.SystemProfile;
import org.deviceconnect.android.provider.FileManager;
import org.deviceconnect.message.DConnectMessage;
import org.deviceconnect.profile.PhoneProfileConstants.CallState;

import android.app.ActivityManager;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.provider.MediaStore;
import android.webkit.MimeTypeMap;

/**
 * Host Device Service.
 * 
 * @author NTT DOCOMO, INC.
 */
public class HostDeviceService extends DConnectMessageService {
    /** Application class instance. */
    private HostDeviceApplication mApp;

    /** マルチキャスト用のタグ. */
    private static final String HOST_MULTICAST = "deviceplugin.host";

    /** ファイル管理クラス. */
    private FileManager mFileMgr;

    /** ServiceID. */
    private String mServiceId;

    /** バッテリー関連の処理と値処理. */
    private HostBatteryManager mHostBatteryManager;

    /** ミリ秒 - 秒オーダー変換用. */
    private static final int UNIT_SEC = 1000;

    /** Video Current Position response. */
    private Intent mResponse = null;

    /** Intent filter for battery charge event. */
    private IntentFilter mIfBatteryCharge;

    /** Intent filter for battery connect event. */
    private IntentFilter mIfBatteryConnect;

    /** ファイルデータ管理クラス. */
    private FileDataManager mFileDataManager;

    @Override
    public void onCreate() {

        super.onCreate();
        
        // Get application class instance.
        mApp = (HostDeviceApplication) this.getApplication();

        // Get application class instance.
        mApp = (HostDeviceApplication) this.getApplication();

        // EventManagerの初期化
        EventManager.INSTANCE.setController(new MemoryCacheController());

        // ファイル管理クラスの作成
        mFileMgr = new FileManager(this);
        mFileDataManager = new FileDataManager(mFileMgr);
        mFileDataManager.startTimer();

        // add supported profiles
        addProfile(new HostConnectProfile(BluetoothAdapter.getDefaultAdapter()));
        addProfile(new HostNotificationProfile());
        addProfile(new HostDeviceOrientationProfile());
        addProfile(new HostBatteryProfile());
        addProfile(new HostMediaStreamingRecordingProfile());
        addProfile(new HostPhoneProfile());
        addProfile(new HostSettingsProfile());
        addProfile(new HostMediaPlayerProfile());
        addProfile(new HostFileProfile(mFileMgr));
        addProfile(new HostFileDescriptorProfile(mFileDataManager));
        addProfile(new HostVibrationProfile());
        addProfile(new HostProximityProfile());
        addProfile(new HostCanvasProfile());
        addProfile(new HostTouchProfile());
        addProfile(new HostKeyEventProfile());

        // バッテリー関連の処理と値の保持
        mHostBatteryManager = new HostBatteryManager();
        mHostBatteryManager.getBatteryInfo(this.getContext());

        mIfBatteryCharge = new IntentFilter();
        mIfBatteryCharge.addAction(Intent.ACTION_BATTERY_CHANGED);
        mIfBatteryCharge.addAction(Intent.ACTION_BATTERY_LOW);
        mIfBatteryCharge.addAction(Intent.ACTION_BATTERY_OKAY);

        mIfBatteryConnect = new IntentFilter();
        mIfBatteryConnect.addAction(Intent.ACTION_POWER_CONNECTED);
        mIfBatteryConnect.addAction(Intent.ACTION_POWER_DISCONNECTED);

        // オーバーレイ
        mCameraOverlay = new CameraOverlay(this);
        mCameraOverlay.setFileManager(mFileMgr);
    }

    @Override
    public int onStartCommand(final Intent intent, final int flags, final int startId) {

        if (intent == null) {
            return START_STICKY;
        }
        String action = intent.getAction();
        if (action.equals("android.intent.action.NEW_OUTGOING_CALL")) {
            // Phone
            List<Event> events = EventManager.INSTANCE.getEventList(mServiceId, HostPhoneProfile.PROFILE_NAME, null,
                    HostPhoneProfile.ATTRIBUTE_ON_CONNECT);

            for (int i = 0; i < events.size(); i++) {
                Event event = events.get(i);
                Intent mIntent = EventManager.createEventMessage(event);
                HostPhoneProfile.setAttribute(mIntent, HostPhoneProfile.ATTRIBUTE_ON_CONNECT);
                Bundle phoneStatus = new Bundle();
                HostPhoneProfile.setPhoneNumber(phoneStatus, intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER));
                HostPhoneProfile.setState(phoneStatus, CallState.START);
                HostPhoneProfile.setPhoneStatus(mIntent, phoneStatus);
                getContext().sendBroadcast(mIntent);
            }
            return START_STICKY;
        } else if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)
                || WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
            // Wifi
            List<Event> events = EventManager.INSTANCE.getEventList(mServiceId, HostConnectProfile.PROFILE_NAME, null,
                    HostConnectProfile.ATTRIBUTE_ON_WIFI_CHANGE);

            for (int i = 0; i < events.size(); i++) {
                Event event = events.get(i);
                Intent mIntent = EventManager.createEventMessage(event);
                HostConnectProfile.setAttribute(mIntent, HostConnectProfile.ATTRIBUTE_ON_WIFI_CHANGE);
                Bundle wifiConnecting = new Bundle();
                WifiManager wifiMgr = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
                HostConnectProfile.setEnable(wifiConnecting, wifiMgr.isWifiEnabled());
                HostConnectProfile.setConnectStatus(mIntent, wifiConnecting);
                getContext().sendBroadcast(mIntent);
            }
            return START_STICKY;
        } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
            List<Event> events = EventManager.INSTANCE.getEventList(mServiceId, HostConnectProfile.PROFILE_NAME, null,
                    HostConnectProfile.ATTRIBUTE_ON_BLUETOOTH_CHANGE);

            for (int i = 0; i < events.size(); i++) {
                Event event = events.get(i);
                Intent mIntent = EventManager.createEventMessage(event);
                HostConnectProfile.setAttribute(mIntent, HostConnectProfile.ATTRIBUTE_ON_BLUETOOTH_CHANGE);
                Bundle bluetoothConnecting = new Bundle();
                BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
                HostConnectProfile.setEnable(bluetoothConnecting, mBluetoothAdapter.isEnabled());
                HostConnectProfile.setConnectStatus(mIntent, bluetoothConnecting);
                getContext().sendBroadcast(mIntent);
            }
            return START_STICKY;
        }
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mFileDataManager.stopTimer();
    }

    /**
     * Get a instance of FileManager.
     * 
     * @return FileManager
     */
    public FileManager getFileManager() {
        return mFileMgr;
    }

    /**
     * Register broadcast receiver for battery charge event.
     */
    public void registerBatteryChargeBroadcastReceiver() {
        registerReceiver(mBatteryChargeBR, mIfBatteryCharge);
    }

    /**
     * Unregister broadcast receiver for battery charge event.
     */
    public void unregisterBatteryChargeBroadcastReceiver() {
        unregisterReceiver(mBatteryChargeBR);
    }

    /**
     * Register broadcast receiver for battery connect event.
     */
    public void registerBatteryConnectBroadcastReceiver() {
        registerReceiver(mBatteryConnectBR, mIfBatteryConnect);
    }

    /**
     * Unregister broadcast receiver for battery connect event.
     */
    public void unregisterBatteryConnectBroadcastReceiver() {
        unregisterReceiver(mBatteryConnectBR);
    }

    /**
     * Broadcast receiver for battery charge event.
     */
    private BroadcastReceiver mBatteryChargeBR = new BroadcastReceiver() {
        @Override
        public void onReceive(final Context context, final Intent intent) {
            String action = intent.getAction();
            if (Intent.ACTION_BATTERY_CHANGED.equals(action) || Intent.ACTION_BATTERY_LOW.equals(action)
                    || Intent.ACTION_BATTERY_OKAY.equals(action)) {
                // バッテリーが変化した時
                mHostBatteryManager.setBatteryRequest(intent);
                List<Event> events = EventManager.INSTANCE.getEventList(mServiceId, HostBatteryProfile.PROFILE_NAME,
                        null, HostBatteryProfile.ATTRIBUTE_ON_BATTERY_CHANGE);

                for (int i = 0; i < events.size(); i++) {
                    Event event = events.get(i);
                    Intent mIntent = EventManager.createEventMessage(event);
                    HostBatteryProfile.setAttribute(mIntent, HostBatteryProfile.ATTRIBUTE_ON_BATTERY_CHANGE);
                    Bundle battery = new Bundle();
                    double level = ((double) (mHostBatteryManager.getBatteryLevel())) / ((double) getBatteryScale());
                    HostBatteryProfile.setLevel(battery, level);
                    HostBatteryProfile.setBattery(mIntent, battery);
                    getContext().sendBroadcast(mIntent);
                }
            }
        }
    };

    /**
     * Broadcast receiver for battery connect event.
     */
    private BroadcastReceiver mBatteryConnectBR = new BroadcastReceiver() {
        @Override
        public void onReceive(final Context context, final Intent intent) {
            String action = intent.getAction();
            if (Intent.ACTION_POWER_CONNECTED.equals(action) || Intent.ACTION_POWER_DISCONNECTED.equals(action)) {
                // バッテリーが充電された時
                mHostBatteryManager.setBatteryRequest(intent);
                List<Event> events = EventManager.INSTANCE.getEventList(mServiceId, HostBatteryProfile.PROFILE_NAME,
                        null, HostBatteryProfile.ATTRIBUTE_ON_CHARGING_CHANGE);

                for (int i = 0; i < events.size(); i++) {
                    Event event = events.get(i);
                    Intent mIntent = EventManager.createEventMessage(event);
                    HostBatteryProfile.setAttribute(mIntent, HostBatteryProfile.ATTRIBUTE_ON_CHARGING_CHANGE);
                    Bundle charging = new Bundle();
                    if (Intent.ACTION_POWER_CONNECTED.equals(action)) {
                        HostBatteryProfile.setCharging(charging, true);
                    } else {
                        HostBatteryProfile.setCharging(charging, false);
                    }
                    HostBatteryProfile.setBattery(mIntent, charging);
                    getContext().sendBroadcast(mIntent);
                }
            }
        }
    };

    @Override
    protected SystemProfile getSystemProfile() {
        return new HostSystemProfile();
    }

    @Override
    protected ServiceInformationProfile getServiceInformationProfile() {
        return new ServiceInformationProfile(this) {
        };
    }

    @Override
    protected ServiceDiscoveryProfile getServiceDiscoveryProfile() {
        return new HostServiceDiscoveryProfile(this);
    }

    /**
     * ServiceIDを設定.
     * 
     * @param serviceId サービスID
     */
    public void setServiceId(final String serviceId) {
        mServiceId = serviceId;
    }

    /**
     * Battery Profile<br>
     * バッテリーレベルを取得.
     * 
     * @return バッテリーレベル
     */
    public int getBatteryLevel() {
        mHostBatteryManager.getBatteryInfo(this.getContext());
        return mHostBatteryManager.getBatteryLevel();
    }

    /**
     * Battery Profile<br>
     * バッテリーステータスを取得.
     * 
     * @return バッテリーレベル
     */
    public int getBatteryStatus() {
        mHostBatteryManager.getBatteryInfo(this.getContext());
        return mHostBatteryManager.getBatteryStatus();
    }

    /**
     * Battery Profile<br>
     * バッテリーレベルを取得.
     * 
     * @return バッテリーレベル
     */
    public int getBatteryScale() {
        mHostBatteryManager.getBatteryInfo(this.getContext());
        return mHostBatteryManager.getBatteryScale();
    }

    //
    // File Descriptor Profile
    //

    /**
     * ファイル操作管理クラスを取得する.
     * @return FileDataManager
     */
    public FileDataManager getFileDataManager() {
        return mFileDataManager;
    }

    // ----------------------------------------------
    // MediaPlayer Profile
    // ----------------------------------------------
    /** MediaPlayerのインスタンス. */
    private MediaPlayer mMediaPlayer = null;
    /** Mediaのステータス. */
    private int mMediaStatus = 0;
    /** Mediaが未設定. */
    private static final int MEDIA_PLAYER_NODATA = 0;
    /** Mediaがセット. */
    private static final int MEDIA_PLAYER_SET = 1;
    /** Mediaが再生中. */
    private static final int MEDIA_PLAYER_PLAY = 2;
    /** Mediaが一時停止中. */
    private static final int MEDIA_PLAYER_PAUSE = 3;
    /** Mediaが停止. */
    private static final int MEDIA_PLAYER_STOP = 4;
    /** Mediaが再生完了. */
    private static final int MEDIA_PLAYER_COMPLETE = 5;
    /** MEDIAタイプ(動画). */
    private static final int MEDIA_TYPE_VIDEO = 1;
    /** MEDIAタイプ(音楽). */
    private static final int MEDIA_TYPE_MUSIC = 2;
    // /** MEDIAタイプ(音声). */
    // private static final int MEDIA_TYPE_AUDIO = 3;
    /** Media Status. */
    private int mSetMediaType = 0;
    /** onStatusChange Eventの状態. */
    private boolean mOnStatusChangeEventFlag = false;
    /** 現在再生中のファイルパス. */
    private String mMyCurrentFilePath = "";
    /** 現在再生中のファイルパス. */
    private String mMyCurrentFileMIMEType = "";
    /** 現在再生中のPosition. */
    private int mMyCurrentMediaPosition = 0;
    /** Backup MediaId. (Used in KITKAT more). */
    String mBackupMediaId;
    /** Media duration. */
    private int mMyCurrentMediaDuration = 0;

    /**
     * サポートしているaudioのタイプ一覧.
     */
    private static final List<String> AUDIO_TYPE_LIST = Arrays.asList("audio/mpeg", "audio/x-wav", "application/ogg",
            "audio/x-ms-wma", "audio/mp3", "audio/ogg", "audio/mp4");

    /**
     * サポートしているvideoのタイプ一覧.
     */
    private static final List<String> VIDEO_TYPE_LIST = Arrays.asList("video/3gpp", "video/mp4", "video/m4v",
            "video/3gpp2", "video/mpeg");

    /**
     * 再生するメディアをセットする(Idから).
     * 
     * @param response レスポンス
     * @param mediaId MediaID
     */
    public void putMediaId(final Intent response, final String mediaId) {
        // Backup MediaId.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            mBackupMediaId = mediaId;
        }

        // Videoとしてパスを取得
        Uri mUri = ContentUris.withAppendedId(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, Long.valueOf(mediaId));

        String filePath = getPathFromUri(mUri);

        // nullなら、Audioとしてパスを取得
        if (filePath == null) {
            mUri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, Long.valueOf(mediaId));
            filePath = getPathFromUri(mUri);
        }

        String mMineType = getMIMEType(filePath);

        // パス指定の場合
        if (AUDIO_TYPE_LIST.contains(mMineType)) {
            if (mMediaPlayer != null) {
                mMediaPlayer.reset();
                mMediaPlayer.release();
                mMediaPlayer = null;
            }
            mMediaPlayer = new MediaPlayer();

            try {
                mSetMediaType = MEDIA_TYPE_MUSIC;
                mMyCurrentFilePath = filePath;
                mMyCurrentFileMIMEType = mMineType;
                mMediaStatus = MEDIA_PLAYER_SET;
                mMediaPlayer.setDataSource(filePath);
                mMediaPlayer.setOnCompletionListener(new OnCompletionListener() {
                    @Override
                    public void onCompletion(final MediaPlayer arg0) {
                        mMediaStatus = MEDIA_PLAYER_COMPLETE;
                        sendOnStatusChangeEvent("complete");
                    }
                });
                mMediaPlayer.prepareAsync();
                mMyCurrentMediaPosition = 0;
                mMediaPlayer.setOnPreparedListener(new OnPreparedListener() {
                    @Override
                    public void onPrepared(final MediaPlayer mp) {
                        mMyCurrentMediaDuration = mMediaPlayer.getDuration() / UNIT_SEC;
                    }
                });

                if (response != null) {
                    response.putExtra(DConnectMessage.EXTRA_RESULT,
                            DConnectMessage.RESULT_OK);
                    response.putExtra(DConnectMessage.EXTRA_VALUE, "regist:"
                            + filePath);
                    sendOnStatusChangeEvent("media");
                    sendBroadcast(response);
                }
            } catch (IOException e) {
                if (response != null) {
                    response.putExtra(DConnectMessage.EXTRA_RESULT,
                            DConnectMessage.EXTRA_ERROR_CODE);
                    response.putExtra(DConnectMessage.EXTRA_VALUE,
                            "can't not mount:" + filePath);
                    sendBroadcast(response);
                }
            }
        } else if (VIDEO_TYPE_LIST.contains(mMineType)) {
            try {

                mSetMediaType = MEDIA_TYPE_VIDEO;
                mMyCurrentFilePath = filePath;
                mMyCurrentFileMIMEType = mMineType;

                if (mMediaPlayer != null) {
                    mMediaPlayer.reset();
                    mMediaPlayer.release();
                    mMediaPlayer = null;
                }
                mMediaPlayer = new MediaPlayer();
                FileInputStream fis = null;
                FileDescriptor mFd = null;

                fis = new FileInputStream(mMyCurrentFilePath);
                mFd = fis.getFD();

                mMediaPlayer.setDataSource(mFd);
                mMediaPlayer.prepare();
                mMyCurrentMediaDuration = mMediaPlayer.getDuration() / UNIT_SEC;
                mMediaPlayer.reset();
                mMediaPlayer.release();
                mMediaPlayer = null;
                fis.close();

                if (response != null) {
                    response.putExtra(DConnectMessage.EXTRA_RESULT,
                            DConnectMessage.RESULT_OK);
                    response.putExtra(DConnectMessage.EXTRA_VALUE, "regist:"
                            + filePath);
                    sendOnStatusChangeEvent("media");
                    sendBroadcast(response);
                }
            } catch (IllegalArgumentException e) {
                if (response != null) {
{'fraction_non_alphanumeric': 0.09416739843786107, 'fraction_numerical': 0.0016175994823681655, 'mean_word_length': 2.4664370394104456, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2659871', 'n_tokens_mistral': 12198, 'n_tokens_neox': 11852, 'n_words': 2024}