package org.deviceconnect.android.uiapp.activity; import android.content.Intent; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.text.Editable; import android.text.InputType; import android.text.TextWatcher; import android.text.method.LinkMovementMethod; import android.text.method.MovementMethod; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.SeekBar; import android.widget.Spinner; import android.widget.Switch; import android.widget.TextView; import android.widget.Toast; import org.deviceconnect.android.uiapp.DConnectApplication; import org.deviceconnect.android.uiapp.R; import org.deviceconnect.android.uiapp.data.DCApi; import org.deviceconnect.android.uiapp.data.DCParam; import org.deviceconnect.android.uiapp.data.DCProfile; import org.deviceconnect.android.uiapp.utils.MessageParser; import org.deviceconnect.android.uiapp.utils.Settings; import org.deviceconnect.message.DConnectEventMessage; import org.deviceconnect.message.DConnectMessage; import org.deviceconnect.message.DConnectResponseMessage; import org.deviceconnect.message.DConnectSDK; import org.deviceconnect.message.entity.BinaryEntity; import org.deviceconnect.message.entity.MultipartEntity; import org.deviceconnect.message.entity.StringEntity; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import static org.deviceconnect.android.uiapp.R.id.response; public class ApiActivity extends BasicActivity { private static final String TYPE_IMAGE = "image/*"; private DCApi mApi; private Map<Integer, TempData> mDataMap = new HashMap<>(); @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_api); Intent intent = getIntent(); if (intent != null) { String serviceId = intent.getStringExtra("serviceId"); if (serviceId != null) { getServiceInformation(serviceId, new OnReceivedServiceInformationListener() { @Override public void onReceived(final List<DCProfile> profiles) { runOnUiThread(new Runnable() { @Override public void run() { DCProfile profile = getProfile(profiles); if (profile != null) { mApi = getApi(profile); setView(mApi); } } }); } }); } String method = intent.getStringExtra("method"); String path = intent.getStringExtra("path"); setTitle(method.toUpperCase() + " " + path); } Button btn = (Button) findViewById(R.id.button_send); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(final View v) { if (mApi != null) { try { if ("event".equalsIgnoreCase(mApi.getXType())) { executeEvent(mApi); } else { executeApi(mApi); } } catch (Exception e) { showToast(); } } } }); } @Override protected void onPause() { getSDK().disconnectWebSocket(); super.onPause(); } @Override protected void onResume() { super.onResume(); getSDK().connectWebSocket(new DConnectSDK.OnWebSocketListener() { @Override public void onOpen() { } @Override public void onClose() { } @Override public void onError(final Exception e) { } }); } @Override protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) { final TempData tempData = mDataMap.get(requestCode); if (data != null && resultCode == RESULT_OK) { runOnUiThread(new Runnable() { @Override public void run() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { String dataString = data.getDataString(); tempData.mTextView.setText(dataString); tempData.mParam.setValue(dataString); } else { String dataString = data.getData().toString(); tempData.mTextView.setText(dataString); tempData.mParam.setValue(dataString); } } }); } else { super.onActivityResult(requestCode,resultCode, data); } } private void showToast() { runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(ApiActivity.this, R.string.activity_api_parameter_error, Toast.LENGTH_SHORT).show(); } }); } private View createTextField(final DCParam param) { View view = getLayoutInflater().inflate(R.layout.item_text_field, null); TextView textView = (TextView) view.findViewById(R.id.name); textView.setText(param.getName()); EditText editText = (EditText) view.findViewById(R.id.value); editText.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { param.setValue(s.toString()); } @Override public void afterTextChanged(Editable s) { } }); editText.setHint(param.getType()); CheckBox checkBox = (CheckBox) view.findViewById(R.id.checkbox); checkBox.setChecked(param.isRequired()); checkBox.setEnabled(!param.isRequired()); checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) { param.setSend(isChecked); } }); param.setSend(param.isRequired()); if ("serviceId".equals(param.getName())) { String serviceId = getIntent().getStringExtra("serviceId"); editText.setText(serviceId); param.setValue(serviceId); } return view; } private View createSwitch(final DCParam param) { View view = getLayoutInflater().inflate(R.layout.item_switch, null); TextView textView = (TextView) view.findViewById(R.id.name); textView.setText(param.getName()); Switch sw = (Switch) view.findViewById(R.id.value); sw.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) { param.setValue(String.valueOf(isChecked)); } }); CheckBox checkBox = (CheckBox) view.findViewById(R.id.checkbox); checkBox.setChecked(param.isRequired()); checkBox.setEnabled(!param.isRequired()); checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) { param.setSend(isChecked); } }); param.setSend(param.isRequired()); return view; } private View createSpinner(final DCParam param) { View view = getLayoutInflater().inflate(R.layout.item_spinner, null); TextView textView = (TextView) view.findViewById(R.id.name); textView.setText(param.getName()); final ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item); List e = param.getEnum(); for (Object o : e) { adapter.add("" + o); } Spinner spinner = (Spinner) view.findViewById(R.id.value); spinner.setAdapter(adapter); spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(final AdapterView<?> parent, final View view, final int position, final long id) { param.setValue(adapter.getItem(position)); } @Override public void onNothingSelected(final AdapterView<?> parent) { } }); CheckBox checkBox = (CheckBox) view.findViewById(R.id.checkbox); checkBox.setChecked(param.isRequired()); checkBox.setEnabled(!param.isRequired()); checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) { param.setSend(isChecked); } }); param.setSend(param.isRequired()); return view; } private View createIntegerTextField(final DCParam param) { View view = getLayoutInflater().inflate(R.layout.item_text_field, null); TextView textView = (TextView) view.findViewById(R.id.name); textView.setText(param.getName()); EditText editText = (EditText) view.findViewById(R.id.value); editText.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { param.setValue(s.toString()); } @Override public void afterTextChanged(Editable s) { } }); editText.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_SIGNED); editText.setHint(param.getType()); CheckBox checkBox = (CheckBox) view.findViewById(R.id.checkbox); checkBox.setChecked(param.isRequired()); checkBox.setEnabled(!param.isRequired()); checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) { param.setSend(isChecked); } }); param.setSend(param.isRequired()); return view; } private View createNumberTextField(final DCParam param) { View view = getLayoutInflater().inflate(R.layout.item_text_field, null); TextView textView = (TextView) view.findViewById(R.id.name); textView.setText(param.getName()); EditText editText = (EditText) view.findViewById(R.id.value); editText.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { param.setValue(s.toString()); } @Override public void afterTextChanged(Editable s) { } }); editText.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL); editText.setHint(param.getType()); CheckBox checkBox = (CheckBox) view.findViewById(R.id.checkbox); checkBox.setChecked(param.isRequired()); checkBox.setEnabled(!param.isRequired()); checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) { param.setSend(isChecked); } }); param.setSend(param.isRequired()); return view; } private View createArrayTextField(final DCParam param) { View view = getLayoutInflater().inflate(R.layout.item_text_field, null); TextView textView = (TextView) view.findViewById(R.id.name); textView.setText(param.getName()); EditText editText = (EditText) view.findViewById(R.id.value); editText.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { param.setValue(s.toString()); } @Override public void afterTextChanged(Editable s) { } }); editText.setHint(param.getType()); CheckBox checkBox = (CheckBox) view.findViewById(R.id.checkbox); checkBox.setChecked(param.isRequired()); checkBox.setEnabled(!param.isRequired()); checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) { param.setSend(isChecked); } }); param.setSend(param.isRequired()); return view; } private View createFile(final DCParam param) { View view = getLayoutInflater().inflate(R.layout.item_file, null); TextView textView = (TextView) view.findViewById(R.id.name); textView.setText(param.getName()); final TextView value = (TextView) view.findViewById(R.id.value); Button btn = (Button) view.findViewById(R.id.btn); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(final View v) { openSelectFile(param, value); } }); CheckBox checkBox = (CheckBox) view.findViewById(R.id.checkbox); checkBox.setChecked(param.isRequired()); checkBox.setEnabled(!param.isRequired()); checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) { param.setSend(isChecked); } }); param.setSend(param.isRequired()); return view; } private View createSeekBar(final DCParam param, final boolean isFloat) { View view = getLayoutInflater().inflate(R.layout.item_seek_bar, null); TextView textView = (TextView) view.findViewById(R.id.name); textView.setText(param.getName()); SeekBar seekBar = (SeekBar) view.findViewById(R.id.value); seekBar.setMax(100); seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(final SeekBar seekBar, final int progress, final boolean fromUser) { Number min = param.getMin(); Number max = param.getMax(); if (isFloat) { float result = (max.floatValue() - min.floatValue()) * (progress / 100.0f); param.setValue(String.valueOf(result)); } else { Number result = (max.intValue() - min.intValue()) * (progress / 100.0f); param.setValue(String.valueOf(result.intValue())); } } @Override public void onStartTrackingTouch(final SeekBar seekBar) { } @Override public void onStopTrackingTouch(final SeekBar seekBar) { } }); CheckBox checkBox = (CheckBox) view.findViewById(R.id.checkbox); checkBox.setChecked(param.isRequired()); checkBox.setEnabled(!param.isRequired()); checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) { param.setSend(isChecked); } }); param.setSend(param.isRequired()); return view; } private void setView(final DCApi api) { LinearLayout layout = (LinearLayout) findViewById(R.id.content); List<DCParam> paramList = api.getParameters(); if (paramList != null) { for (final DCParam param : paramList) { if ("string".equalsIgnoreCase(param.getType())) { layout.addView(createTextField(param)); } else if ("boolean".equalsIgnoreCase(param.getType())) { layout.addView(createSwitch(param)); } else if ("integer".equalsIgnoreCase(param.getType())) { if (param.getEnum() != null) { layout.addView(createSpinner(param)); } else if (param.getMax() != null && param.getMin() != null) { layout.addView(createSeekBar(param, false)); } else { layout.addView(createIntegerTextField(param)); } } else if ("number".equalsIgnoreCase(param.getType())) { if (param.getMax() != null && param.getMin() != null) { layout.addView(createSeekBar(param, true)); } else { layout.addView(createNumberTextField(param)); } } else if ("array".equalsIgnoreCase(param.getType())) { layout.addView(createArrayTextField(param)); } else if ("file".equalsIgnoreCase(param.getType())) { layout.addView(createFile(param)); } } } } private void openSelectFile(final DCParam param, final TextView textView) { int requestCode = UUID.randomUUID().hashCode(); TempData data = new TempData(); data.mParam = param; data.mTextView = textView; mDataMap.put(requestCode, data); Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType(TYPE_IMAGE); startActivityForResult(intent, requestCode); } private void openImageActivity(final String uri) { Intent intent = new Intent(); intent.setClass(this, ImageActivity.class); intent.putExtra("uri", uri); startActivity(intent); } private void showResponseText(final DConnectResponseMessage response) { View view = findViewById(R.id.response_layout); view.setVisibility(View.VISIBLE); final MessageParser parser = new MessageParser(); parser.setClickLinkListener(new MessageParser.OnClickLinkListener() { @Override public void onClick(String uri) { openImageActivity(uri); } }); MovementMethod method = LinkMovementMethod.getInstance(); TextView textView = (TextView) findViewById(R.id.response); textView.setText(parser.parse(response, 4)); textView.setMovementMethod(method); } private void showErrorText(final int errorCode, final String errorMessage) { DConnectResponseMessage response = new DConnectResponseMessage(DConnectMessage.RESULT_ERROR); response.setErrorCode(errorCode); response.setErrorMessage(errorMessage); showResponseText(response); } private void showEventText(final DConnectEventMessage event) { View view = findViewById(R.id.event_layout); view.setVisibility(View.VISIBLE); final MessageParser parser = new MessageParser(); parser.setClickLinkListener(new MessageParser.OnClickLinkListener() { @Override public void onClick(String uri) { openImageActivity(uri); } }); MovementMethod method = LinkMovementMethod.getInstance(); TextView textView = (TextView) findViewById(R.id.event); textView.setText(parser.parse(event, 4)); textView.setMovementMethod(method); } private byte[] getContent(final String uri) { InputStream in = null; ByteArrayOutputStream out = new ByteArrayOutputStream(); try { in = getContentResolver().openInputStream(Uri.parse(uri)); int len; byte[] buf = new byte[4096]; while ((len = in.read(buf)) > 0) { out.write(buf, 0, len); } } catch (IOException e) { e.printStackTrace(); } finally { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } return out.toByteArray(); } private void executeNotBodyApi(final DCApi api, final DConnectSDK.OnResponseListener listener) { DConnectSDK.URIBuilder builder = getSDK().createURIBuilder(); builder.setPath(api.getPath()); List<DCParam> paramList = api.getParameters(); for (DCParam param :paramList) { if (param.isSend()) { builder.addParameter(param.getName(), param.getValue()); } } switch (api.getMethod()) { case GET: getSDK().get(builder.build(), listener); break; case DELETE: getSDK().delete(builder.build(), listener); break; } } private void executeBodyApi(final DCApi api, final DConnectSDK.OnResponseListener listener) { DConnectSDK.URIBuilder builder = getSDK().createURIBuilder(); builder.setPath(api.getPath()); MultipartEntity data = new MultipartEntity(); List<DCParam> paramList = api.getParameters(); for (DCParam param :paramList) { if (param.isSend()) { if ("file".equals(param.getType())) { data.add(param.getName(), new BinaryEntity(getContent(param.getValue()))); } else { data.add(param.getName(), new StringEntity(param.getValue())); } } } switch (api.getMethod()) { case PUT: getSDK().put(builder.build(), data, listener); break; case POST: getSDK().post(builder.build(), data, listener); break; } } private void executeApi(final DCApi api) { View responseView = findViewById(R.id.response_layout); responseView.setVisibility(View.GONE); TextView textView = (TextView) findViewById(R.id.response); textView.setText(""); DConnectSDK.OnResponseListener listener = new DConnectSDK.OnResponseListener() { @Override public void onResponse(final DConnectResponseMessage response) { if (response.getResult() == DConnectMessage.RESULT_OK) { runOnUiThread(new Runnable() { @Override public void run() { showResponseText(response); } }); } else { int errorCode = response.getErrorCode(); switch (DConnectMessage.ErrorCode.getInstance(errorCode)) { case SCOPE: DConnectApplication.SCOPES.add(api.getProfile()); case EXPIRED_ACCESS_TOKEN: case EMPTY_ACCESS_TOKEN: case NOT_FOUND_CLIENT_ID: String[] profiles = new String[DConnectApplication.SCOPES.size()]; DConnectApplication.SCOPES.toArray(profiles); String appName = getString(R.string.app_name); getSDK().authorization(appName, profiles, new DConnectSDK.OnAuthorizationListener() { @Override public void onResponse(final String clientId, final String accessToken) { Settings.getInstance().setClientId(clientId); Settings.getInstance().setAccessToken(accessToken); getSDK().setAccessToken(accessToken); executeApi(api); } @Override public void onError(final int errorCode, final String errorMessage) { runOnUiThread(new Runnable() { @Override public void run() { showErrorText(errorCode, errorMessage); } }); } }); break; case AUTHORIZATION: default: runOnUiThread(new Runnable() { @Override public void run() { showResponseText(response); } }); break; } } } }; switch (api.getMethod()) { case GET: case DELETE: executeNotBodyApi(api, listener); break; case PUT: case POST: executeBodyApi(api, listener); break; } } private void executeEvent(final DCApi api) { TextView textView = (TextView) findViewById(response); textView.setText(""); DConnectSDK.URIBuilder builder = getSDK().createURIBuilder(); builder.setPath(api.getPath()); List<DCParam> paramList = api.getParameters(); for (DCParam param :paramList) { if (param.isSend()) { builder.addParameter(param.getName(), param.getValue()); } } switch (api.getMethod()) { case DELETE: getSDK().removeEventListener(builder.build()); break; case PUT: getSDK().addEventListener(builder.build(), new DConnectSDK.OnEventListener() { @Override public void onMessage(final DConnectEventMessage message) { runOnUiThread(new Runnable() { @Override public void run() { showEventText(message); } }); } @Override public void onResponse(final DConnectResponseMessage response) { runOnUiThread(new Runnable() { @Override public void run() { showResponseText(response); } }); } }); break; } } private class TempData { TextView mTextView; DCParam mParam; } }