/* ServiceDiscoveryProfile.java Copyright (c) 2014 NTT DOCOMO,INC. Released under the MIT license http://opensource.org/licenses/mit-license.php */ package org.deviceconnect.android.profile; import android.content.Intent; import android.os.Bundle; import org.deviceconnect.android.event.Event; import org.deviceconnect.android.event.EventError; import org.deviceconnect.android.event.EventManager; import org.deviceconnect.android.message.MessageUtils; import org.deviceconnect.android.profile.api.DConnectApi; import org.deviceconnect.android.profile.api.DeleteApi; import org.deviceconnect.android.profile.api.GetApi; import org.deviceconnect.android.profile.api.PutApi; import org.deviceconnect.android.service.DConnectService; import org.deviceconnect.android.service.DConnectServiceListener; import org.deviceconnect.android.service.DConnectServiceProvider; import org.deviceconnect.message.DConnectMessage; import org.deviceconnect.profile.ServiceDiscoveryProfileConstants; import java.util.ArrayList; import java.util.List; /** * Service Discovery プロファイル. * * <p> * Device Connectサービス検索機能を提供するAPI.<br> * </p> * @author NTT DOCOMO, INC. */ public class ServiceDiscoveryProfile extends DConnectProfile implements ServiceDiscoveryProfileConstants, DConnectServiceListener { /** * プロファイルプロバイダー. */ private final DConnectServiceProvider mProvider; /** * Service Discovery API. */ private final DConnectApi mServiceDiscoveryApi = new GetApi() { @Override public boolean onRequest(final Intent request, final Intent response) { appendServiceList(response); return true; } }; /** * Status Change Event API (PUT). */ private final DConnectApi mPutStatusChangeApi = new PutApi() { @Override public String getAttribute() { return ATTRIBUTE_ON_SERVICE_CHANGE; } @Override public boolean onRequest(final Intent request, final Intent response) { EventError error = EventManager.INSTANCE.addEvent(request); switch (error) { case NONE: setResult(response, DConnectMessage.RESULT_OK); break; case INVALID_PARAMETER: MessageUtils.setInvalidRequestParameterError(response); break; default: MessageUtils.setUnknownError(response); break; } return true; } }; /** * Status Change Event API (DELETE). */ private final DConnectApi mDeleteStatusChangeApi = new DeleteApi() { @Override public String getAttribute() { return ATTRIBUTE_ON_SERVICE_CHANGE; } @Override public boolean onRequest(final Intent request, final Intent response) { EventError error = EventManager.INSTANCE.removeEvent(request); switch (error) { case NONE: setResult(response, DConnectMessage.RESULT_OK); break; case INVALID_PARAMETER: MessageUtils.setInvalidRequestParameterError(response); break; default: MessageUtils.setUnknownError(response); break; } return true; } }; /** * 指定されたサービスプロバイダーをもつSystemプロファイルを生成する. * * @param provider サービスプロバイダー */ public ServiceDiscoveryProfile(final DConnectServiceProvider provider) { mProvider = provider; if (mProvider != null) { mProvider.addServiceListener(this); } addApi(mServiceDiscoveryApi); addApi(mPutStatusChangeApi); addApi(mDeleteStatusChangeApi); } /** * サービスプロバイダーを取得する. * * @return サービスプロバイダー */ protected DConnectServiceProvider getServiceProvider() { return mProvider; } @Override public final String getProfileName() { return PROFILE_NAME; } @Override public void onServiceAdded(final DConnectService service) { sendStatusChangeEvent(service, true); } @Override public void onServiceRemoved(final DConnectService service) { sendStatusChangeEvent(service, false); } @Override public void onStatusChange(final DConnectService service) { sendStatusChangeEvent(service, true); } private void sendStatusChangeEvent(final DConnectService service, final boolean exists) { List<Event> events = EventManager.INSTANCE.getEventList( PROFILE_NAME, ATTRIBUTE_ON_SERVICE_CHANGE ); if (events.size() == 0) { return; } Bundle eventBundle = new Bundle(); Bundle networkServiceBundle = createServiceBundle(service); setState(networkServiceBundle, exists); eventBundle.putParcelable(PARAM_NETWORK_SERVICE, networkServiceBundle); // NOTE: Service DiscoveryプロファイルのリクエストにはサービスIDが付加されないので、 // イベントマネージャのイベント管理テーブルにも保存されない。 // よって、イベント送信時に、下記のようにサービスIDを明示的に設定する必要がある。 eventBundle.putString(PARAM_SERVICE_ID, service.getId()); for (Event event : events) { sendEvent(event, eventBundle); } } private Bundle createServiceBundle(final DConnectService service) { Bundle serviceBundle = new Bundle(); setId(serviceBundle, service.getId()); setName(serviceBundle, service.getName()); setType(serviceBundle, service.getNetworkType()); setOnline(serviceBundle, service.isOnline()); setConfig(serviceBundle, service.getConfig()); setScopes(serviceBundle, service); return serviceBundle; } protected void appendServiceList(final Intent response) { List<Bundle> serviceBundles = new ArrayList<Bundle>(); for (DConnectService service : mProvider.getServiceList()) { serviceBundles.add(createServiceBundle(service)); } setServices(response, serviceBundles); setResult(response, DConnectMessage.RESULT_OK); } // ------------------------------------ // レスポンスセッターメソッド群 // ------------------------------------ /** * レスポンスにデバイス一覧を設定する. * * @param response レスポンスパラメータ * @param services デバイス一覧 */ public static void setServices(final Intent response, final Bundle[] services) { response.putExtra(PARAM_SERVICES, services); } /** * レスポンスにデバイス一覧を設定する. * * @param response レスポンスパラメータ * @param services デバイス一覧 */ public static void setServices(final Intent response, final List<Bundle> services) { setServices(response, services.toArray(new Bundle[services.size()])); } /** * メッセージにデバイス情報を設定する. * * @param message メッセージパラメータ * @param networkService デバイス情報 */ public static void setNetworkService(final Intent message, final Bundle networkService) { message.putExtra(PARAM_NETWORK_SERVICE, networkService); } /** * サービスIDを設定する. * * @param service デバイスパラメータ * @param id サービスID */ public static void setId(final Bundle service, final String id) { service.putString(PARAM_ID, id); } /** * デバイス名を設定する. * * @param service デバイスパラメータ * @param name デバイス名 */ public static void setName(final Bundle service, final String name) { service.putString(PARAM_NAME, name); } /** * デバイスのネットワークタイプを設定する. * * @param service デバイスパラメータ * @param type デバイスのネットワークタイプ * <ul> * <li>{@link NetworkType#WIFI}</li> * <li>{@link NetworkType#BLE}</li> * <li>{@link NetworkType#NFC}</li> * <li>{@link NetworkType#BLUETOOTH}</li> * </ul> */ public static void setType(final Bundle service, final NetworkType type) { setType(service, type.getValue()); } /** * デバイスのネットワークタイプを設定する. * * @param service デバイスパラメータ * @param type デバイスのネットワークタイプ */ public static void setType(final Bundle service, final String type) { service.putString(PARAM_TYPE, type); } /** * デバイスのオンライン状態を設定する. * * @param service デバイスパラメータ * @param online オンライン: true、 オフライン: false */ public static void setOnline(final Bundle service, final boolean online) { service.putBoolean(PARAM_ONLINE, online); } /** * デバイスの設定情報を設定する. * * @param service デバイスパラメータ * @param config 設定情報文字列 */ public static void setConfig(final Bundle service, final String config) { service.putString(PARAM_CONFIG, config); } /** * デバイスの接続状態を設定する. * * @param service デバイスパラメータ * @param state 接続 : true、未接続 : false */ public static void setState(final Bundle service, final boolean state) { service.putBoolean(PARAM_STATE, state); } /** * デバイスプラグインのサポートするプロファイル一覧を設定する. * * @param service デバイスパラメータ */ public static void setScopes(final Bundle serviceBundle, final DConnectService service) { ArrayList<String> scopes = new ArrayList<String>(); List<DConnectProfile> profileList = service.getProfileList(); for (DConnectProfile profile : profileList) { scopes.add(profile.getProfileName()); } serviceBundle.putStringArray(PARAM_SCOPES, scopes.toArray(new String[scopes.size()])); } }