-
Notifications
You must be signed in to change notification settings - Fork 23
Application Manual for Android Studio
- 1. はじめに
- 2. Device Connect について
- 2.1. Device Connect対応のProfile
- 2.2. Device Connectへの接続
- 2.3. Device Connectの準備
- 3. サンプルアプリケーションの作成
- 3.1. プロジェクトの作成
- 3.2. MainActivityの編集
- 4. SDKを用いたAndroidアプリケーションの開発
- 4.1. AccessTokenをDevice Connectから取得
- 4.2. ServiceDiscoveryの実装
- 4.3. デバイスプラグインのRESTfulでの問い合わせ処理実装
- 5. Appendix
- 5.1. ライブラリの自動インポート
本ドキュメントは、Device Connect APIを用いてAndroidネイティブアプリケーションを開発する手法について解説します。Androidに関する一般的な知識と、Javaに関する一般的な知識を保持している事を提に解説していきます。
本ドキュメントでは、開発環境としてAndroid Studioを使用します。
Android Studioは、こちらからダウンロードを行ってください。
Device Connectでは、RESTfulで、命令やデータの送受信が可能です。各処理は、Profileという形でURIが割り振られ、そのURIをJavaやJavaScriptなどで呼び出す事で、処理を行います。
Device Connectで、使用出来るProfileを以下に示します。
| Profile名 | 説明 |
|---|---|
| System | Device Connect本体の情報や、プラグインの情報、プラグインの設定画面の起動などを行います。 |
| Battery | バッテリーの状態を保持します |
| Proximity | デバイスと物体との近接状態を取得します。 |
| Media Player | メディアの再生(音声, 音楽, 動画)を行います。 |
| Service Discovery | デバイスの対応Profile一覧を取得します。 |
| Vibration | デバイスをバイブレートする命令を送ります。 |
| Notification | デバイスに通知(Notification)を行います。 |
| Setting | デバイスの設定(音量, 画面輝度, 画面スリープ時間等)を行います。 |
| DeviceOrientation | デバイスの加速度等を取得します。 |
| File | デバイスとFileの送信、受信等を行います。 |
| MediaStream Recording API | メディアの録音(音声,音楽,動画)を行います。 |
| Phone API | デバイスに電話発信の命令を送ります。 |
ただし、デバイスによって、使用出来るProfileは変わりますので、ご注意ください。
Android版Device Connectでは、端末内のローカルに起動しているHTTPサーバ(DeviceConnectManager)に問い合わせを行う事で、ハードウェアの操作や、情報取得を行う事が可能です。
図1. Device Connect Managerへの問い合わせ
githubのDownload ZIPボタンを押下して、ダウンロードしてください。
もしくは、gitコマンドを用いてプロジェクトをチェックアウトしてください。
$ git clone https://github.com/DeviceConnect/DeviceConnect-Android.gitAndroid Studioで/DeviceConnect-Android/dConnectManager/dConnectManagerを開きます。
appを実行することで、Device Connect Managerがインストールされます。
Device Connect Managerのアイコンを押下して、アプリを起動します。
Device Connect Managerのスイッチを押下して、オンにします。
Device Connect Manager [デバイスプラグイン>デバイスプラグイン管理]を選択します。
リストに HOST (Device Connect Device Plug-in) が追加されていることを確認します。
以上で、Device Connectを使用するための準備が整いました。
次からサンプルの作成を説明します。
サンプルアプリケーションでは、Device Connect Managerに問い合わせを行い、結果のJSONを取得するサンプルを作成しながら解説をします。
AndroidStudioの[Start a new Android Studio project]を選択します。
Application Name, Project Name, Package Nameを入力します。
| 項目 | 設定値 |
|---|---|
| Application Name | AndroidAppSample |
| Project Name | AndroidAppSample |
| Package Name | com.example.androidappsample |
| Minimum Required SDK | Android 4.2 |
Activityを選択します。
Activity名を入力します。
ここまでCreate New Projectに従ってプロジェクトを作成すると、以下のようにプロジェクトが追加されます。
使用するAndroid StudioのバージョンやAndroid SDKのバージョンによっては、生成されるソースコードやxmlに違いがありますので、ご注意ください。
表示画面となる res/layout/activity_main.xmlと、MainActivity.javaを編集します。
res/layout/activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="${relativePackage}.${activityClass}" >
<Button android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button" />
</RelativeLayout>MainActivity.java
package com.example.androidappsample;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Looper;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends Activity implements OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(this);
}
@Override
public void onClick(View v) {
(new Thread(new Runnable() {
@Override
public void run() {
try {
String url = "http://localhost:4035/gotapi/availability";
HttpGet request = new HttpGet(url);
request.addHeader("origin", getPackageName());
HttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(request);
String result = EntityUtils.toString(response.getEntity(), "UTF-8");
Looper.prepare();
Toast.makeText(getApplicationContext(), result, Toast.LENGTH_LONG).show();
Looper.loop();
} catch (Exception e) {
e.printStackTrace();
}
}
})).start();
}
}HTTP通信を行うため、AndroidManifest.xmlに、INTERNETのPermissionを追加してください。
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.androidappsample"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>ここまでの作成を終えた後、このサンプルをインストールして起動すると、以下のような画面が表示されます。
Buttonを押す事で、端末にインストールされているDevice Connect 1.0 デバイスプラグインの情報を取得して、Toastで表示する事が出来ます。
Device Connectとの通信には、いくつかの手順を行う必要があります。Androidでアプリケーションを開発する際に、最初にAccessTokenを取得します。また、接続したハードウェアのServiceIdをService Discovery Profileにアクセスして取得します。AccessTokenとServiceIdを用いて、操作したいハードウェアのプラグインに対して処理の送信が可能となります。
Device Connectにアクセスするアプリは、OAuth(Local)認証で用いるAccessTokenを、Device Connect Managerより発行してもらう必要があります。本サンプルから、Device Connect SDK Android版を用いて解説します。
AndroidStudioのGradle Scriptの欄から「build.gradle」を開き以下のような内容を追記します。
build.gradle
apply plugin: 'com.android.application'
android {
compileSdkVersion 21
buildToolsVersion "21.1.1"
packagingOptions {
exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/DEPENDENCIES.txt'
}
defaultConfig {
applicationId "com.example.androidappsample"
minSdkVersion 17
targetSdkVersion 21
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
repositories {
maven { url 'http://raw.github.com/DeviceConnect/DeviceConnect-Android/main/dConnectSDK/dConnectSDKForAndroid/repository/' }
}
configurations {
all*.exclude group: 'org.apache.httpcomponents', module: 'httpclient'
all*.exclude group: 'commons-logging', module: 'commons-logging'
all*.exclude group: 'com.android.support', module: 'support-v4'
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:21.0.3'
compile 'org.deviceconnect:dconnect-sdk-for-android:1.0.1'
}repositoriesタグにより、GitHubからSDKをダウンロードすることができます。
configurationタグによって、support-v4ライブラリの重複を防ぐための処理を追加しています。
GradleScriptを編集すると、以下の図のようにGradleをビルドするかどうかを尋ねられるので、「Sync Now」でGradleをビルドします。
GradleScriptのビルドに成功すると、dconnect-sdk-for-androidがインポートされます。
画面にボタンを追加して、ボタン押下でAccessToken取得処理を行わせるように実装します。
res/layout/activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="${relativePackage}.${activityClass}" >
<Button android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="System" />
<Button android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/button1"
android:text="Get AccessToken" />
</RelativeLayout>MainActivity.java
package com.example.androidappsample;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Looper;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.deviceconnect.message.DConnectMessage.ErrorCode;
import org.deviceconnect.profile.AuthorizationProfileConstants;
import org.deviceconnect.profile.BatteryProfileConstants;
import org.deviceconnect.profile.ConnectProfileConstants;
import org.deviceconnect.profile.DeviceOrientationProfileConstants;
import org.deviceconnect.profile.FileDescriptorProfileConstants;
import org.deviceconnect.profile.FileProfileConstants;
import org.deviceconnect.profile.MediaPlayerProfileConstants;
import org.deviceconnect.profile.MediaStreamRecordingProfileConstants;
import org.deviceconnect.profile.NotificationProfileConstants;
import org.deviceconnect.profile.PhoneProfileConstants;
import org.deviceconnect.profile.ProximityProfileConstants;
import org.deviceconnect.profile.ServiceDiscoveryProfileConstants;
import org.deviceconnect.profile.SettingsProfileConstants;
import org.deviceconnect.profile.SystemProfileConstants;
import org.deviceconnect.profile.VibrationProfileConstants;
import org.deviceconnect.utils.AuthProcesser;
public class MainActivity extends Activity implements OnClickListener {
private Button mButton1;
private Button mButton2;
private Context mContext;
private String mClientId;
private String mAccessToken;
private ErrorCode mError;
/**
* Local OAuthに使用するスコープ一覧.
*/
private String[] scopes = {
ServiceInformationProfileConstants.PROFILE_NAME,
AuthorizationProfileConstants.PROFILE_NAME,
BatteryProfileConstants.PROFILE_NAME,
ConnectionProfileConstants.PROFILE_NAME,
DeviceOrientationProfileConstants.PROFILE_NAME,
FileDescriptorProfileConstants.PROFILE_NAME,
FileProfileConstants.PROFILE_NAME,
MediaPlayerProfileConstants.PROFILE_NAME,
MediaStreamRecordingProfileConstants.PROFILE_NAME,
ServiceDiscoveryProfileConstants.PROFILE_NAME,
NotificationProfileConstants.PROFILE_NAME,
PhoneProfileConstants.PROFILE_NAME,
ProximityProfileConstants.PROFILE_NAME,
SettingProfileConstants.PROFILE_NAME,
SystemProfileConstants.PROFILE_NAME,
VibrationProfileConstants.PROFILE_NAME,
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this.getBaseContext();
mButton1 = (Button) findViewById(R.id.button1);
mButton2 = (Button) findViewById(R.id.button2);
mButton1.setOnClickListener(this);
mButton2.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button1:
(new Thread(new Runnable() {
@Override
public void run() {
try {
String url = "http://localhost:4035/gotapi/availability";
HttpGet request = new HttpGet(url);
request.addHeader("origin", getPackageName());
HttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(request);
String result = EntityUtils.toString(response.getEntity(), "UTF-8");
Looper.prepare();
Toast.makeText(mContext, result, Toast.LENGTH_LONG).show();
Looper.loop();
} catch (Exception e) {
e.printStackTrace();
}
}
})).start();
break;
case R.id.button2:
String appName = getResources().getString(R.string.app_name);
AuthProcesser.asyncAuthorize("localhost", 4035, false, getPackageName(),
appName, scopes, mAuthHandler);
break;
}
}
/**
* Local OAuth のリスナー. */
private AuthProcesser.AuthorizationHandler mAuthHandler = new AuthProcesser.AuthorizationHandler() {
@Override
public void onAuthorized(final String clientId,
final String accessToken) {
mClientId = clientId;
mAccessToken = accessToken;
mError = null;
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "Success. AccessToken="
+ mAccessToken + " ClientId=" + clientId, Toast.LENGTH_LONG).show();
}
});
}
@Override
public void onAuthFailed(final ErrorCode error) {
mError = error;
mClientId = null;
mAccessToken = null;
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, error.toString(),
Toast.LENGTH_LONG).show();
}
});
}
};
}ここまでの作成を終えた後、このサンプルをインストールして起動すると、以下のような画面が表示されます。
「Get AccessToken」Buttonを押す事で、AccessToken取得処理が実行され、認証画面が表示されます。
認証を行うと、ToastでAccessTokenが表示されます。
デバイス一覧を取得するためのServiceDiscoveryの実装を行います。 画面にボタンを追加して、ボタン押下でServiceDiscovery処理を行わせるように実装します。 また、Toastで表示していた応答を、EditTextにて表示できるように変更も行います。
res/layout/activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="${relativePackage}.${activityClass}" >
<Button android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="System" />
<Button android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/button1"
android:text="Get AccessToken" />
<Button android:id="@+id/button3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/button2"
android:text="Network Service Discovery" />
<EditText
android:id="@+id/editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:ems="10"
android:inputType="textMultiLine" >
<requestFocus />
</EditText>
</RelativeLayout>MainActivity.java
package com.example.androidappsample;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Looper;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.deviceconnect.message.DConnectMessage;
import org.deviceconnect.message.DConnectMessage.ErrorCode;
import org.deviceconnect.message.basic.message.DConnectResponseMessage;
import org.deviceconnect.message.http.impl.factory.HttpMessageFactory;
import org.deviceconnect.profile.AuthorizationProfileConstants;
import org.deviceconnect.profile.BatteryProfileConstants;
import org.deviceconnect.profile.ConnectProfileConstants;
import org.deviceconnect.profile.DeviceOrientationProfileConstants;
import org.deviceconnect.profile.FileDescriptorProfileConstants;
import org.deviceconnect.profile.FileProfileConstants;
import org.deviceconnect.profile.MediaPlayerProfileConstants;
import org.deviceconnect.profile.MediaStreamRecordingProfileConstants;
import org.deviceconnect.profile.NotificationProfileConstants;
import org.deviceconnect.profile.PhoneProfileConstants;
import org.deviceconnect.profile.ProximityProfileConstants;
import org.deviceconnect.profile.ServiceDiscoveryProfileConstants;
import org.deviceconnect.profile.ServiceInformationProfileConstants;
import org.deviceconnect.profile.SettingsProfileConstants;
import org.deviceconnect.profile.SystemProfileConstants;
import org.deviceconnect.profile.VibrationProfileConstants;
import org.deviceconnect.utils.AuthProcesser;
import org.deviceconnect.utils.URIBuilder;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class MainActivity extends Activity implements OnClickListener {
private Button mButton1;
private Button mButton2;
private Button mButton3;
private Context mContext;
private EditText mEditText1;
private String mClientId;
private String mAccessToken;
private ErrorCode mError;
private List<SmartDevice> devices = null;
/**
* Local OAuthに使用するスコープ一覧.
*/
private String[] scopes = {
AuthorizationProfileConstants.PROFILE_NAME,
BatteryProfileConstants.PROFILE_NAME,
ConnectProfileConstants.PROFILE_NAME,
DeviceOrientationProfileConstants.PROFILE_NAME,
FileDescriptorProfileConstants.PROFILE_NAME,
FileProfileConstants.PROFILE_NAME,
LightProfileConstants.PROFILE_NAME,
MediaPlayerProfileConstants.PROFILE_NAME,
MediaStreamRecordingProfileConstants.PROFILE_NAME,
ServiceDiscoveryProfileConstants.PROFILE_NAME,
NotificationProfileConstants.PROFILE_NAME,
PhoneProfileConstants.PROFILE_NAME,
ProximityProfileConstants.PROFILE_NAME,
ServiceInformationProfileConstants.PROFILE_NAME,
SettingsProfileConstants.PROFILE_NAME,
SystemProfileConstants.PROFILE_NAME,
VibrationProfileConstants.PROFILE_NAME,
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this.getBaseContext();
mEditText1 = (EditText) findViewById(R.id.editText1);
mButton1 = (Button) findViewById(R.id.button1);
mButton2 = (Button) findViewById(R.id.button2);
mButton3 = (Button) findViewById(R.id.button3);
mButton1.setOnClickListener(this);
mButton2.setOnClickListener(this);
mButton3.setOnClickListener(this);
}
public void setTextField(String text) {
mEditText1.setText(text);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button1:
(new Thread(new Runnable() {
@Override
public void run() {
try {
String url = "http://localhost:4035/gotapi/system";
HttpGet request = new HttpGet(url);
request.addHeader("origin", getPackageName());
HttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(request);
String result = EntityUtils.toString(response.getEntity(), "UTF-8");
Looper.prepare();
Toast.makeText(mContext, result, Toast.LENGTH_LONG).show();
Looper.loop();
} catch (Exception e) {
e.printStackTrace();
}
}
})).start();
break;
case R.id.button2:
String appName = getResources().getString(R.string.app_name);
AuthProcesser.asyncAuthorize("localhost", 4035, false, getPackageName(), appName, scopes, mAuthHandler);
break;
case R.id.button3:
(new Thread(new Runnable() {
@Override
public void run() {
DConnectMessage message = new DConnectResponseMessage(DConnectMessage.RESULT_ERROR);
devices = new ArrayList<SmartDevice>();
try {
URIBuilder builder = new URIBuilder();
builder.setScheme("http");
builder.setProfile(ServiceDiscoveryProfileConstants.PROFILE_NAME);
builder.setHost("localhost");
builder.setPort(4035);
builder.addParameter(DConnectMessage.EXTRA_ACCESS_TOKEN, mAccessToken);
HttpUriRequest request = new HttpGet(builder.build());
request.addHeader("origin", getPackageName());
HttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(request);
message = (new HttpMessageFactory()).newDConnectMessage(response);
} catch (URISyntaxException e) {
e.printStackTrace();
return;
} catch (IOException e) {
e.printStackTrace();
return;
}
if (message == null) {
return;
}
int result = message.getInt(DConnectMessage.EXTRA_RESULT);
if (result == DConnectMessage.RESULT_ERROR) {
return;
}
List<Object> services
= message.getList(
ServiceDiscoveryProfileConstants.PARAM_SERVICES);
final StringBuffer sb = new StringBuffer();
if (services != null) {
for (Object object: services) {
@SuppressWarnings("unchecked")
Map<String, Object> service = (Map<String, Object>) object;
SmartDevice device = new SmartDevice(
service.get(ServiceDiscoveryProfileConstants.PARAM_ID).toString(),
service.get(ServiceDiscoveryProfileConstants.PARAM_NAME).toString());
devices.add(device);
sb.append("id:" +
service.get(ServiceDiscoveryProfileConstants.PARAM_ID).toString() + ", ");
sb.append("name:" +
service.get(ServiceDiscoveryProfileConstants.PARAM_NAME).toString() + ", "); }
}
runOnUiThread(new Runnable() {
@Override
public void run() {
mEditText1.setText(sb);
}
});
}
})).start();
break;
}
}
/**
* Local OAuth のリスナー. */
private AuthProcesser.AuthorizationHandler mAuthHandler = new AuthProcesser.AuthorizationHandler() {
@Override
public void onAuthorized(final String clientId, final String accessToken) {
mClientId = clientId;
mAccessToken = accessToken;
mError = null;
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this,
"Success. AccessToken="
+ mAccessToken + " ClientId="
+ clientId,
Toast.LENGTH_LONG).show();
} });
}
@Override
public void onAuthFailed(final ErrorCode error) {
mError = error;
mClientId = null;
mAccessToken = null;
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, error.toString(),
Toast.LENGTH_LONG).show();
}
});
}
};
}SmartDevice.java
package com.example.androidappsample;
import java.util.ArrayList;
import java.util.List;
import android.os.Parcel; import android.os.Parcelable;
/**
* Device Connect スマートデバイス. */
public class SmartDevice implements Parcelable {
/**
* Parcelable クリエイター. */
public static final Parcelable.Creator<SmartDevice> CREATOR
= new Parcelable.Creator<SmartDevice>() {
public SmartDevice createFromParcel(final Parcel in) {
return new SmartDevice(in);
}
public SmartDevice[] newArray(final int size) {
return new SmartDevice[size];
}
};
/**
* デバイス名. */
private String mName;
/**
* デバイス種別. */
private String mType;
/**
* デバイス ID. */
private String mId;
/**
* サービスリスト. */
private List<SmartService> mServiceList = new ArrayList<SmartService>();
/**
* コンストラクタ.
* @param id デバイス ID * @param name デバイス名 */
public SmartDevice(final String id, final String name) {
setId(id);
setName(name);
}
/**
* Parcelable コンストラクタ.
* @param in 入力
*/
private SmartDevice(final Parcel in) {
setName(in.readString());
setType(in.readString());
setId(in.readString());
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(final Parcel dest, final int flags) {
dest.writeString(mName);
dest.writeString(mType);
dest.writeString(mId);
}
@Override
public String toString() {
return mName;
}
/**
* デバイス ID を設定する.
* @param id デバイス ID
*/
public void setId(final String id) {
mId = id;
}
/**
* デバイス名を設定する.
* @param name デバイス名
*/
public void setName(final String name) {
mName = name;
}
/**
* デバイス種別を設定する.
* @param type デバイス種別
*/
public void setType(final String type) {
mType = type;
}
/**
* デバイス名.
* @return デバイス名
*/
public String getName() {
return mName;
}
/**
* デバイス種別を取得する.
* @return デバイス種別
*/
public String getType() {
return mType;
}
/**
* デバイス ID を取得する.
* @return デバイス ID
*/
public String getId() {
return mId;
}
/**
* サービスリストを取得する.
* @return サービスリスト
*/
public List<SmartService> getmServiceList() {
return mServiceList;
}
/**
* サービスを追加する.
* @param service サービス
*/
public void addService(final SmartService service) {
mServiceList.add(service);
}
/**
* サービスを削除する.
* @param service サービス
*/
public void removeService(final SmartService service) {
mServiceList.remove(service);
}
}SmartService.java
package com.example.androidappsample;
/**
* スマートサービス(プロファイル).
*/
public class SmartService {
/**
* プロファイル名.
*/
private String mName;
/**
* コンストラクタ.
* @param name プロファイル名
*/
public SmartService(final String name) {
mName = name;
}
@Override
public String toString() {
return mName;
}
/**
* プロファイル名を設定.
* @param name プロファイル名
*/
public void setName(final String name) {
mName = name;
}
/**
* プロファイル名を取得.
* @return プロファイル名
*/
public String getName() {
return mName;
}
/**
* アイコンを取得.
* @return アイコンID
*/
public int getIconId() {
return android.R.drawable.ic_menu_info_details;
}
}ここまでの作成を終えた後、このサンプルをインストールして起動すると、以下のような画面が表示されます。
「Service Discovery」Buttonを押す事で、Service Discovery処理が実行され、デバイスの情報が表示されます。
ここまでの実装で取得した「AccessToken」「ServiceId」を使用して、デバイスプラグインへRESTfulでの問い合わせ処理の実装を行います。 ここでは、画面にボタンを追加して、ボタン押下でService Discoveryで最初に発見されたデバイスプラグインに対して、「/serviceinformation」を実行し、その応答を得る実装を行います。
res/layout/activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="${relativePackage}.${activityClass}" >
<Button android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="System" />
<Button android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/button1"
android:text="Get AccessToken" />
<Button android:id="@+id/button3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/button2"
android:text="Service Discovery" />
<Button android:id="@+id/button4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/button3"
android:text="Device" />
<EditText
android:id="@+id/editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:ems="10"
android:inputType="textMultiLine" >
<requestFocus />
</EditText>
</RelativeLayout>MainActivity.java
package com.example.androidappsample;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Looper;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.deviceconnect.message.DConnectMessage;
import org.deviceconnect.message.DConnectMessage.ErrorCode;
import org.deviceconnect.message.basic.message.DConnectResponseMessage;
import org.deviceconnect.message.http.impl.factory.HttpMessageFactory;
import org.deviceconnect.profile.AuthorizationProfileConstants;
import org.deviceconnect.profile.BatteryProfileConstants;
import org.deviceconnect.profile.ConnectProfileConstants;
import org.deviceconnect.profile.DeviceOrientationProfileConstants;
import org.deviceconnect.profile.FileDescriptorProfileConstants;
import org.deviceconnect.profile.FileProfileConstants;
import org.deviceconnect.profile.MediaPlayerProfileConstants;
import org.deviceconnect.profile.MediaStreamRecordingProfileConstants;
import org.deviceconnect.profile.NotificationProfileConstants;
import org.deviceconnect.profile.PhoneProfileConstants;
import org.deviceconnect.profile.ProximityProfileConstants;
import org.deviceconnect.profile.ServiceDiscoveryProfileConstants;
import org.deviceconnect.profile.ServiceInformationProfileConstants;
import org.deviceconnect.profile.SettingsProfileConstants;
import org.deviceconnect.profile.SystemProfileConstants;
import org.deviceconnect.profile.VibrationProfileConstants;
import org.deviceconnect.utils.AuthProcesser;
import org.deviceconnect.utils.URIBuilder;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class MainActivity extends Activity implements OnClickListener {
private Button mButton1;
private Button mButton2;
private Button mButton3;
private Button mButton4;
private Context mContext;
private EditText mEditText1;
private String mClientId;
private String mAccessToken;
private ErrorCode mError;
private List<SmartDevice> devices = null;
/**
* Local OAuthに使用するスコープ一覧.
*/
private String[] scopes = {
ServiceInformationProfileConstants.PROFILE_NAME,
AuthorizationProfileConstants.PROFILE_NAME,
BatteryProfileConstants.PROFILE_NAME,
ConnectProfileConstants.PROFILE_NAME,
DeviceOrientationProfileConstants.PROFILE_NAME,
FileDescriptorProfileConstants.PROFILE_NAME,
FileProfileConstants.PROFILE_NAME,
MediaPlayerProfileConstants.PROFILE_NAME,
MediaStreamRecordingProfileConstants.PROFILE_NAME,
ServiceDiscoveryProfileConstants.PROFILE_NAME,
NotificationProfileConstants.PROFILE_NAME,
PhoneProfileConstants.PROFILE_NAME,
ProximityProfileConstants.PROFILE_NAME,
SettingsProfileConstants.PROFILE_NAME,
SystemProfileConstants.PROFILE_NAME,
VibrationProfileConstants.PROFILE_NAME,
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this.getBaseContext();
mEditText1 = (EditText) findViewById(R.id.editText1);
mButton1 = (Button) findViewById(R.id.button1);
mButton2 = (Button) findViewById(R.id.button2);
mButton3 = (Button) findViewById(R.id.button3);
mButton4 = (Button) findViewById(R.id.button4);
mButton1.setOnClickListener(this);
mButton2.setOnClickListener(this);
mButton3.setOnClickListener(this);
mButton4.setOnClickListener(this);
}
public void setTextField(String text) {
mEditText1.setText(text);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button1:
(new Thread(new Runnable() {
@Override
public void run() {
try {
String url = "http://localhost:4035/gotapi/system";
HttpGet reqeust = new HttpGet(url);
request.addHeader("origin", getPackageName());
HttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(reqeust);
String result = EntityUtils.toString(response.getEntity(), "UTF-8");
Looper.prepare();
Toast.makeText(mContext, result, Toast.LENGTH_LONG).show();
Looper.loop();
} catch (Exception e) {
e.printStackTrace();
}
}
})).start();
break;
case R.id.button2:
String appName = getResources().getString(R.string.app_name);
AuthProcesser.asyncAuthorize("localhost", 4035, false, getPackageName(),
appName, scopes, mAuthHandler);
break;
case R.id.button3:
(new Thread(new Runnable() {
@Override
public void run() {
DConnectMessage message = new DConnectResponseMessage(DConnectMessage.RESULT_ERROR);
devices = new ArrayList<SmartDevice>();
try {
URIBuilder builder = new URIBuilder();
builder.setScheme("http");
builder.setProfile(ServiceDiscoveryProfileConstants.PROFILE_NAME);
builder.setHost("localhost");
builder.setPort(4035);
builder.addParameter(DConnectMessage.EXTRA_ACCESS_TOKEN, mAccessToken);
HttpUriRequest request = new HttpGet(builder.build());
request.addHeader("origin", getPackageName());
DefaultHttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(request);
message = (new HttpMessageFactory()).newDConnectMessage(response);
} catch (URISyntaxException e) {
e.printStackTrace();
return;
} catch (IOException e) {
e.printStackTrace();
return;
}
if (message == null) {
return;
}
int result = message.getInt(DConnectMessage.EXTRA_RESULT);
if (result == DConnectMessage.RESULT_ERROR) {
return;
}
List<Object> services
= message.getList(
ServiceDiscoveryProfileConstants.PARAM_SERVICES);
final StringBuffer sb = new StringBuffer();
if (services != null) {
for (Object object: services) {
@SuppressWarnings("unchecked")
Map<String, Object> service = (Map<String, Object>) object;
SmartDevice device = new SmartDevice(
service.get(ServiceDiscoveryProfileConstants.PARAM_ID).toString(),
service.get(ServiceDiscoveryProfileConstants.PARAM_NAME).toString());
devices.add(device);
sb.append("id:" +
service.get(ServiceDiscoveryProfileConstants.PARAM_ID).toString()
+ ", ");
sb.append("name:" +
service.get(ServiceDiscoveryProfileConstants.PARAM_NAME).toString()
+ ", "); }
}
runOnUiThread(new Runnable() {
@Override
public void run() {
mEditText1.setText(sb);
}
});
}
})).start();
break;
case R.id.button4:
if (devices.size() == 0) {
return;
}
(new Thread(new Runnable() {
@Override
public void run() {
DConnectMessage message = new DConnectResponseMessage(DConnectMessage.RESULT_ERROR);
URIBuilder uriBuilder = new URIBuilder();
uriBuilder.setProfile(ServiceInformationProfileConstants.PROFILE_NAME);
uriBuilder.setScheme("http");
uriBuilder.setHost("localhost");
uriBuilder.setPort(4035);
uriBuilder.addParameter(DConnectMessage.EXTRA_SERVICE_ID,
devices.get(0).getId());
uriBuilder.addParameter(DConnectMessage.EXTRA_ACCESS_TOKEN, mAccessToken);
try {
HttpUriRequest req = new HttpGet(uriBuilder.build());
req.addHeader("origin", getPackageName());
HttpClient client = new DefaultHttpClient();
HttpResponse res = client.execute(req);
final String result = EntityUtils.toString(res.getEntity(), "UTF-8");
runOnUiThread(new Runnable() {
public void run() {
mEditText1.setText(result);
} });
} catch (IOException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
}
int result = message.getInt(DConnectMessage.EXTRA_RESULT);
if (result == DConnectMessage.RESULT_ERROR) {
return;
}
}
})).start();
break;
}
}
/**
* Local OAuth のリスナー. */
private AuthProcesser.AuthorizationHandler mAuthHandler
= new AuthProcesser.AuthorizationHandler() {
@Override
public void onAuthorized(final String clientId,
final String accessToken) {
mClientId = clientId;
mAccessToken = accessToken;
mError = null;
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
final String oauthMessage = "Success. AccessToken="
+ mAccessToken + " ClientId=" + clientId;
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, oauthMessage, Toast.LENGTH_LONG).show();
mEditText1.setText(oauthMessage);
}
});
} });
}
@Override
public void onAuthFailed(final ErrorCode error) {
mError = error;
mClientId = null;
mAccessToken = null;
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, error.toString(),
Toast.LENGTH_LONG).show();
}
});
}
};
}ここまでの作成を終えた後、このサンプルをインストールして起動すると、以下のような画面が表示されます。
「Get AccessToken」Button を押下し、認証を行い、AccessTokenを取得する。
「Network Service Discovery」Buttonを押下し、デバイス一覧を取得します。
「Device」Buttonを押下し、デバイスの情報を取得します。この例では、サンプルのデバイスプラグインのデバイス情報が表示されます。
Android Studioでは、必要なライブラリは、自動でインポートを行ってくれる機能があります。 それを使用することによって、インポート文を入力する手間が省くことができます。
まずは、AndroidStudioの[タイトル]>[Preferences]を選択します。
[Editor]>[Auto Import]の[Optimize imports on the fly]にチェックを入れることで、ソースコードで必要なインポート文を自動でインポートしてくれるようになります。