Samsung Health : solving java.lang.IllegalArgumentException: heart_rate (READ) is invalid - java

what I want to do is developing an app that reads health data that collected by Samsung watch so I tried to use Samsung android health SDK . Moreover reading steps was very easy as there was a sample app doing the same thing . the issue appear when I was trying to read the heart rate value :
here is my code please help me address the issue :
Mainfest :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.smaunghealth">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<meta-data android:name="com.samsung.android.health.permission.read"
android:value="com.samsung.health.step_count;com.samsung.health.heart_rate"/>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
MainActivity
package com.example.smaunghealth;
import android.content.DialogInterface;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import com.samsung.android.sdk.healthdata.*;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class MainActivity extends AppCompatActivity {
public static final String APP_TAG = "SimpleHealth";
private static MainActivity mInstance = null;
private HealthDataStore mStore;
private HealthConnectionErrorResult mConnError;
private Set<HealthPermissionManager.PermissionKey> mKeySet;
private StepCountReporter mReporter;
private HeartRateReporter mHeartReporter;
TextView stepCount ;
TextView heartRate ;
private final HealthResultHolder.ResultListener<HealthPermissionManager.PermissionResult> mPermissionListener =
new HealthResultHolder.ResultListener<HealthPermissionManager.PermissionResult>() {
#Override
public void onResult(HealthPermissionManager.PermissionResult result) {
Log.d(APP_TAG, "Permission callback is received.");
Map<HealthPermissionManager.PermissionKey, Boolean> resultMap = result.getResultMap();
if (resultMap.containsValue(Boolean.FALSE)) {
// Requesting permission fails
} else {
// Get the current step count and display it
}
}
};
private final HealthDataStore.ConnectionListener mConnectionListener = new HealthDataStore.ConnectionListener() {
#Override
public void onConnected() {
Log.d(APP_TAG, "Health data service is connected.");
HealthPermissionManager pmsManager = new HealthPermissionManager(mStore);
try {
// Check whether the permissions that this application needs are acquired
Map<HealthPermissionManager.PermissionKey, Boolean> resultMap = pmsManager.isPermissionAcquired(mKeySet);
if (resultMap.containsValue(Boolean.FALSE)) {
// Request the permission for reading step counts if it is not acquired
pmsManager.requestPermissions(mKeySet, MainActivity.this).setResultListener(mPermissionListener);
} else {
// Get the current step count and display it
// ...
mReporter = new StepCountReporter(mStore);
mReporter.start(mStepCountObserver);
mHeartReporter = new HeartRateReporter(mStore);
mHeartReporter.start(heartRateObserver);
}
} catch (Exception e) {
Log.e(APP_TAG, e.getClass().getName() + " - " + e.getMessage());
Log.e(APP_TAG, "Permission setting fails.");
}
}
#Override
public void onConnectionFailed(HealthConnectionErrorResult error) {
Log.d(APP_TAG, "Health data service is not available.");
showConnectionFailureDialog(error);
}
#Override
public void onDisconnected() {
Log.d(APP_TAG, "Health data service is disconnected.");
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mInstance = this;
stepCount= (TextView) findViewById(R.id.step_count);
heartRate= (TextView) findViewById(R.id.heart_rate);
mKeySet = new HashSet<HealthPermissionManager.PermissionKey>();
// mKeySet.add(new HealthPermissionManager.PermissionKey(HealthConstants.StepCount.HEALTH_DATA_TYPE, HealthPermissionManager.PermissionType.READ));
mKeySet.add(new HealthPermissionManager.PermissionKey(HealthConstants.HeartRate.HEART_RATE, HealthPermissionManager.PermissionType.READ));
HealthDataService healthDataService = new HealthDataService();
try {
healthDataService.initialize(this);
} catch (Exception e) {
e.printStackTrace();}
mStore = new HealthDataStore(this, mConnectionListener);
// Request the connection to the health data store
mStore.connectService();
}
#Override
public void onDestroy() {
mStore.disconnectService();
super.onDestroy();
}
private StepCountReporter.StepCountObserver mStepCountObserver = count -> {
Log.d(APP_TAG, "Step reported : " + count);
updateStepCountView(String.valueOf(count));
};
private HeartRateReporter.HeartRateObserver heartRateObserver = count -> {
Log.d(APP_TAG, "Step reported : " + count);
updateHeartRateView(String.valueOf(count));
};
private void updateHeartRateView(String valueOf) {
Log.d(APP_TAG, "heart rate reported : " + valueOf);
updateHeartRateView(String.valueOf(valueOf));
}
private void updateStepCountView(String count) {
stepCount.setText(count);
}
private void showConnectionFailureDialog(HealthConnectionErrorResult error) {
AlertDialog.Builder alert = new AlertDialog.Builder(this);
mConnError = error;
String message = "Connection with Samsung Health is not available";
if (mConnError.hasResolution()) {
switch(error.getErrorCode()) {
case HealthConnectionErrorResult.PLATFORM_NOT_INSTALLED:
message = "Please install Samsung Health";
break;
case HealthConnectionErrorResult.OLD_VERSION_PLATFORM:
message = "Please upgrade Samsung Health";
break;
case HealthConnectionErrorResult.PLATFORM_DISABLED:
message = "Please enable Samsung Health";
break;
case HealthConnectionErrorResult.USER_AGREEMENT_NEEDED:
message = "Please agree with Samsung Health policy";
break;
default:
message = "Please make Samsung Health available";
break;
}
}
alert.setMessage(message);
alert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
if (mConnError.hasResolution()) {
mConnError.resolve(mInstance);
}
}
});
if (error.hasResolution()) {
alert.setNegativeButton("Cancel", null);
}
alert.show();
}
}
HeartRateReporter
package com.example.smaunghealth;
import android.util.Log;
import com.samsung.android.sdk.healthdata.*;
import java.util.Calendar;
import java.util.TimeZone;
public class HeartRateReporter {
private final HealthDataStore mStore;
private HeartRateObserver mHeartRateObserver;
private static final long ONE_DAY_IN_MILLIS = 24 * 60 * 60 * 1000L;
public HeartRateReporter(HealthDataStore store) {
mStore = store;
}
public void start(HeartRateObserver listener) {
mHeartRateObserver = listener;
HealthDataObserver.addObserver(mStore, HealthConstants.HeartRate.HEART_RATE, mObserver);
readHeartRate();
}
private void readHeartRate() {
HealthDataResolver resolver = new HealthDataResolver(mStore, null);
// Set time range from start time of today to the current time
long startTime = getStartTimeOfToday();
long endTime = startTime + ONE_DAY_IN_MILLIS;
HealthDataResolver.ReadRequest request = new HealthDataResolver.ReadRequest.Builder()
.setDataType(HealthConstants.HeartRate.HEART_RATE)
.setProperties(new String[] {HealthConstants.HeartRate.HEART_RATE})
.setLocalTimeRange(HealthConstants.HeartRate.START_TIME, HealthConstants.HeartRate.TIME_OFFSET,
startTime, endTime)
.build();
try {
resolver.read(request).setResultListener(mListener);
} catch (Exception e) {
Log.e("*&*&*&", "Getting Heart fails.", e);
}
}
private long getStartTimeOfToday() {
Calendar today = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
today.set(Calendar.HOUR_OF_DAY, 0);
today.set(Calendar.MINUTE, 0);
today.set(Calendar.SECOND, 0);
today.set(Calendar.MILLISECOND, 0);
return today.getTimeInMillis();
}
private final HealthResultHolder.ResultListener<HealthDataResolver.ReadResult> mListener = result -> {
int count = 0;
try {
for (HealthData data : result) {
count += data.getInt(HealthConstants.HeartRate.HEART_RATE);
}
} finally {
result.close();
}
if (mHeartRateObserver != null) {
mHeartRateObserver.onChanged(count);
}
};
private final HealthDataObserver mObserver = new HealthDataObserver(null) {
#Override
public void onChange(String dataTypeName) {
Log.d("*&*&*&", "Observer receives a data changed event");
readHeartRate();
}
};
public interface HeartRateObserver {
void onChanged(int count);
}
}
StepCountReporter
/**
* Copyright (C) 2014 Samsung Electronics Co., Ltd. All rights reserved.
*
* Mobile Communication Division,
* Digital Media & Communications Business, Samsung Electronics Co., Ltd.
*
* This software and its documentation are confidential and proprietary
* information of Samsung Electronics Co., Ltd. No part of the software and
* documents may be copied, reproduced, transmitted, translated, or reduced to
* any electronic medium or machine-readable form without the prior written
* consent of Samsung Electronics.
*
* Samsung Electronics makes no representations with respect to the contents,
* and assumes no responsibility for any errors that might appear in the
* software and documents. This publication and the contents hereof are subject
* to change without notice.
*/
package com.example.smaunghealth;
import android.util.Log;
import com.samsung.android.sdk.healthdata.*;
import com.samsung.android.sdk.healthdata.HealthDataResolver.ReadRequest;
import com.samsung.android.sdk.healthdata.HealthDataResolver.ReadResult;
import java.util.Calendar;
import java.util.TimeZone;
public class StepCountReporter {
private final HealthDataStore mStore;
private StepCountObserver mStepCountObserver;
private static final long ONE_DAY_IN_MILLIS = 24 * 60 * 60 * 1000L;
public StepCountReporter(HealthDataStore store) {
mStore = store;
}
public void start(StepCountObserver listener) {
mStepCountObserver = listener;
// Register an observer to listen changes of step count and get today step count
HealthDataObserver.addObserver(mStore, HealthConstants.StepCount.HEALTH_DATA_TYPE, mObserver);
readTodayStepCount();
}
// Read the today's step count on demand
private void readTodayStepCount() {
HealthDataResolver resolver = new HealthDataResolver(mStore, null);
// Set time range from start time of today to the current time
long startTime = getStartTimeOfToday();
long endTime = startTime + ONE_DAY_IN_MILLIS;
HealthDataResolver.ReadRequest request = new ReadRequest.Builder()
.setDataType(HealthConstants.StepCount.HEALTH_DATA_TYPE)
.setProperties(new String[] {HealthConstants.StepCount.COUNT})
.setLocalTimeRange(HealthConstants.StepCount.START_TIME, HealthConstants.StepCount.TIME_OFFSET,
startTime, endTime)
.build();
try {
resolver.read(request).setResultListener(mListener);
} catch (Exception e) {
Log.e(MainActivity.APP_TAG, "Getting step count fails.", e);
}
}
private long getStartTimeOfToday() {
Calendar today = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
today.set(Calendar.HOUR_OF_DAY, 0);
today.set(Calendar.MINUTE, 0);
today.set(Calendar.SECOND, 0);
today.set(Calendar.MILLISECOND, 0);
return today.getTimeInMillis();
}
private final HealthResultHolder.ResultListener<ReadResult> mListener = result -> {
int count = 0;
try {
for (HealthData data : result) {
count += data.getInt(HealthConstants.StepCount.COUNT);
}
} finally {
result.close();
}
if (mStepCountObserver != null) {
mStepCountObserver.onChanged(count);
}
};
private final HealthDataObserver mObserver = new HealthDataObserver(null) {
// Update the step count when a change event is received
#Override
public void onChange(String dataTypeName) {
Log.d(MainActivity.APP_TAG, "Observer receives a data changed event");
readTodayStepCount();
}
};
public interface StepCountObserver {
void onChanged(int count);
}
}
Here is the exception log :

<meta-data android:name="com.samsung.android.health.permission.read"
android:value="com.samsung.health.step_count;com.samsung.health.heart_rate"/>
I think you should separate this permission into two, not only one。
like:
<meta-data android:name="com.samsung.android.health.permission.read"
android:value="com.samsung.health.step_count"/>
<meta-data android:name="com.samsung.android.health.permission.read"
android:value="com.samsung.health.heart_rate"/>

After long time finally I was able to address the issue :
mKeySet.add(new HealthPermissionManager.PermissionKey(HealthConstants.StepCount.HEALTH_DATA_TYPE, HealthPermissionManager.PermissionType.READ));
mKeySet.add(new HealthPermissionManager.PermissionKey(HealthConstants.HeartRate.HEART_RATE, HealthPermissionManager.PermissionType.READ));
this is the write permissionKey :
mKeySet.add(new HealthPermissionManager.PermissionKey(HealthConstants.StepCount.HEALTH_DATA_TYPE, HealthPermissionManager.PermissionType.READ));
mKeySet.add(new HealthPermissionManager.PermissionKey(HealthConstants.HeartRate.HEALTH_DATA_TYPE, HealthPermissionManager.PermissionType.READ));

Related

Agora.io in Native Android (Java)

I know that this questions was asked before but it doesn't solved by queries mentioned below after the code .
package io.agora.tutorials1v1vcall;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.view.SurfaceView;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Toast;
import io.agora.uikit.logger.LoggerRecyclerView;
import io.agora.rtc.IRtcEngineEventHandler;
import io.agora.rtc.RtcEngine;
import io.agora.rtc.video.VideoCanvas;
import io.agora.rtc.video.VideoEncoderConfiguration;
public class VideoChatViewActivity extends AppCompatActivity {
private static final String TAG = VideoChatViewActivity.class.getSimpleName();
private static final int PERMISSION_REQ_ID = 22;
// Permission WRITE_EXTERNAL_STORAGE is not mandatory
// for Agora RTC SDK, just in case if you wanna save
// logs to external sdcard.
private static final String[] REQUESTED_PERMISSIONS = {
Manifest.permission.RECORD_AUDIO,
Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
private RtcEngine mRtcEngine;
private boolean mCallEnd;
private boolean mMuted;
private FrameLayout mLocalContainer;
private RelativeLayout mRemoteContainer;
private SurfaceView mLocalView;
private SurfaceView mRemoteView;
private ImageView mCallBtn;
private ImageView mMuteBtn;
private ImageView mSwitchCameraBtn;
// Customized logger view
private LoggerRecyclerView mLogView;
/**
* Event handler registered into RTC engine for RTC callbacks.
* Note that UI operations needs to be in UI thread because RTC
* engine deals with the events in a separate thread.
*/
private final IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() {
#Override
public void onJoinChannelSuccess(String channel, final int uid, int elapsed) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mLogView.logI("Join channel success, uid: " + (uid & 0xFFFFFFFFL));
}
});
}
#Override
public void onFirstRemoteVideoDecoded(final int uid, int width, int height, int elapsed) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mLogView.logI("First remote video decoded, uid: " + (uid & 0xFFFFFFFFL));
setupRemoteVideo(uid);
}
});
}
#Override
public void onUserOffline(final int uid, int reason) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mLogView.logI("User offline, uid: " + (uid & 0xFFFFFFFFL));
onRemoteUserLeft();
}
});
}
};
private void setupRemoteVideo(int uid) {
// Only one remote video view is available for this
// tutorial. Here we check if there exists a surface
// view tagged as this uid.
int count = mRemoteContainer.getChildCount();
View view = null;
for (int i = 0; i < count; i++) {
View v = mRemoteContainer.getChildAt(i);
if (v.getTag() instanceof Integer && ((int) v.getTag()) == uid) {
view = v;
}
}
if (view != null) {
return;
}
mRemoteView = RtcEngine.CreateRendererView(getBaseContext());
mRemoteContainer.addView(mRemoteView);
mRtcEngine.setupRemoteVideo(new VideoCanvas(mRemoteView, VideoCanvas.RENDER_MODE_HIDDEN, uid));
mRemoteView.setTag(uid);
}
private void onRemoteUserLeft() {
removeRemoteVideo();
}
private void removeRemoteVideo() {
if (mRemoteView != null) {
mRemoteContainer.removeView(mRemoteView);
}
mRemoteView = null;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video_chat_view);
initUI();
// Ask for permissions at runtime.
// This is just an example set of permissions. Other permissions
// may be needed, and please refer to our online documents.
if (checkSelfPermission(REQUESTED_PERMISSIONS[0], PERMISSION_REQ_ID) &&
checkSelfPermission(REQUESTED_PERMISSIONS[1], PERMISSION_REQ_ID) &&
checkSelfPermission(REQUESTED_PERMISSIONS[2], PERMISSION_REQ_ID)) {
initEngineAndJoinChannel();
}
}
private void initUI() {
mLocalContainer = findViewById(R.id.local_video_view_container);
mRemoteContainer = findViewById(R.id.remote_video_view_container);
mCallBtn = findViewById(R.id.btn_call);
mMuteBtn = findViewById(R.id.btn_mute);
mSwitchCameraBtn = findViewById(R.id.btn_switch_camera);
mLogView = findViewById(R.id.log_recycler_view);
// Sample logs are optional.
showSampleLogs();
}
private void showSampleLogs() {
mLogView.logI("Welcome to Agora 1v1 video call");
mLogView.logW("You will see custom logs here");
mLogView.logE("You can also use this to show errors");
}
private boolean checkSelfPermission(String permission, int requestCode) {
if (ContextCompat.checkSelfPermission(this, permission) !=
PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, REQUESTED_PERMISSIONS, requestCode);
return false;
}
return true;
}
#Override
public void onRequestPermissionsResult(int requestCode,
#NonNull String[] permissions, #NonNull int[] grantResults) {
if (requestCode == PERMISSION_REQ_ID) {
if (grantResults[0] != PackageManager.PERMISSION_GRANTED ||
grantResults[1] != PackageManager.PERMISSION_GRANTED ||
grantResults[2] != PackageManager.PERMISSION_GRANTED) {
showLongToast("Need permissions " + Manifest.permission.RECORD_AUDIO +
"/" + Manifest.permission.CAMERA + "/" + Manifest.permission.WRITE_EXTERNAL_STORAGE);
finish();
return;
}
// Here we continue only if all permissions are granted.
// The permissions can also be granted in the system settings manually.
initEngineAndJoinChannel();
}
}
private void showLongToast(final String msg) {
this.runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();
}
});
}
private void initEngineAndJoinChannel() {
// This is our usual steps for joining
// a channel and starting a call.
initializeEngine();
setupVideoConfig();
setupLocalVideo();
joinChannel();
}
private void initializeEngine() {
try {
mRtcEngine = RtcEngine.create(getBaseContext(), getString(R.string.agora_app_id), mRtcEventHandler);
} catch (Exception e) {
Log.e(TAG, Log.getStackTraceString(e));
throw new RuntimeException("NEED TO check rtc sdk init fatal error\n" + Log.getStackTraceString(e));
}
}
private void setupVideoConfig() {
// In simple use cases, we only need to enable video capturing
// and rendering once at the initialization step.
// Note: audio recording and playing is enabled by default.
mRtcEngine.enableVideo();
// Please go to this page for detailed explanation
// https://docs.agora.io/en/Video/API%20Reference/java/classio_1_1agora_1_1rtc_1_1_rtc_engine.html#af5f4de754e2c1f493096641c5c5c1d8f
mRtcEngine.setVideoEncoderConfiguration(new VideoEncoderConfiguration(
VideoEncoderConfiguration.VD_640x360,
VideoEncoderConfiguration.FRAME_RATE.FRAME_RATE_FPS_15,
VideoEncoderConfiguration.STANDARD_BITRATE,
VideoEncoderConfiguration.ORIENTATION_MODE.ORIENTATION_MODE_FIXED_PORTRAIT));
}
private void setupLocalVideo() {
// This is used to set a local preview.
// The steps setting local and remote view are very similar.
// But note that if the local user do not have a uid or do
// not care what the uid is, he can set his uid as ZERO.
// Our server will assign one and return the uid via the event
// handler callback function (onJoinChannelSuccess) after
// joining the channel successfully.
mLocalView = RtcEngine.CreateRendererView(getBaseContext());
mLocalView.setZOrderMediaOverlay(true);
mLocalContainer.addView(mLocalView);
mRtcEngine.setupLocalVideo(new VideoCanvas(mLocalView, VideoCanvas.RENDER_MODE_HIDDEN, 0));
}
private void joinChannel() {
// 1. Users can only see each other after they join the
// same channel successfully using the same app id.
// 2. One token is only valid for the channel name that
// you use to generate this token.
String token = getString(R.string.agora_access_token);
if (TextUtils.isEmpty(token) || TextUtils.equals(token, "#YOUR ACCESS TOKEN#")) {
token = null; // default, no token
}
mRtcEngine.joinChannel(token, "demoChannel1", "Extra Optional Data", 0);
}
#Override
protected void onDestroy() {
super.onDestroy();
if (!mCallEnd) {
leaveChannel();
}
RtcEngine.destroy();
}
private void leaveChannel() {
mRtcEngine.leaveChannel();
}
public void onLocalAudioMuteClicked(View view) {
mMuted = !mMuted;
mRtcEngine.muteLocalAudioStream(mMuted);
int res = mMuted ? R.drawable.btn_mute : R.drawable.btn_unmute;
mMuteBtn.setImageResource(res);
}
public void onSwitchCameraClicked(View view) {
mRtcEngine.switchCamera();
}
public void onCallClicked(View view) {
if (mCallEnd) {
startCall();
mCallEnd = false;
mCallBtn.setImageResource(R.drawable.btn_endcall);
} else {
endCall();
mCallEnd = true;
mCallBtn.setImageResource(R.drawable.btn_startcall);
}
showButtons(!mCallEnd);
}
private void startCall() {
setupLocalVideo();
joinChannel();
}
private void endCall() {
removeLocalVideo();
removeRemoteVideo();
leaveChannel();
}
private void removeLocalVideo() {
if (mLocalView != null) {
mLocalContainer.removeView(mLocalView);
}
mLocalView = null;
}
private void showButtons(boolean show) {
int visibility = show ? View.VISIBLE : View.GONE;
mMuteBtn.setVisibility(visibility);
mSwitchCameraBtn.setVisibility(visibility);
}
}
I am integrating the agora.io for one-to-one video calling functionality. I got the above code from the agora.io documentation but i am getting the black remote screen . Also i would ask that how would i connect two users dynamically. What modifications i have to do in the above code for one-to-one video call functionality. Please help.Thanks in advance.
It showing black screen because of token issue. kindly check token generation code in backend. Most probably the reason for black screen is the token expiration time.

I want to stop the my background service. When i open my application again

Here is my activity. I am started the service i.e SeviceToStartBackgroundService.class from HomeActivity . Here i want to check whether services are running or not if running then i want to stop the services.
package com.example.tracker.activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.widget.ImageView;
import android.widget.TextView;
import com.example.tracker.R;
import com.example.tracker.service.BLEService;
import com.example.tracker.service.BackgroundService;
import com.example.tracker.service.BluetoothLeService;
import com.example.tracker.service.SeviceToStartBackgroundService;
public class HomeScreenActivity extends AppCompatActivity {
String TAG="HomeScreenActivity";
public static Intent intent,intent2;
private Intent bluetoothIntent;
int i=1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home_screen);
}
#Override
protected void onResume() {
super.onResume();
stopServiceMethod();
startService(new Intent(getApplicationContext(),SeviceToStartBackgroundService.class));
}
public void stopServiceMethod(){
Log.e(TAG,"stopServiceMethod()");
stopService(new Intent(this, BackgroundService.class));
stopService(new Intent(this, SeviceToStartBackgroundService.class));
stopService(new Intent(this, BluetoothLeService.class));
stopService(new Intent(this, BLEService.class));
}
}
Here is my SeviceToStartBackgroundService.class . When i removed the app from recent apps then the onTaskRemoved(Intent rootIntent) method gets called. And one more service gets started i.e BackgroundService.class.
package com.example.tracker.service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;
public class SeviceToStartBackgroundService extends Service {
String TAG="SeviceToStartBService";
private BluetoothLeService mBluetoothLeService;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onTaskRemoved(Intent rootIntent) {
Log.e(getClass().getName(), "App just got removed from Recents!");
startService(new Intent(getApplicationContext(),BackgroundService.class));
}
#Override
public void onDestroy() {
super.onDestroy();
}
}
Here is my BackgroundService.class . I want to stop this service when app comes in user interaction (front end) .
package com.example.tracker.service;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanSettings;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;
import android.widget.Toast;
import com.example.tracker.R;
import com.example.tracker.utils.SampleGattAttributes;
import com.example.tracker.utils.SharedPreferencesUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import static android.R.attr.delay;
import static com.shalaka.tracker.constant.SharedFreferencesConstant.KEY_SP_MOBILE_NUMBER;
/**
* Created by greenlantern on 12/9/17.
*/
public class BackgroundService extends Service{
Handler handlerScan=new Handler();
private int scanPeriod;
Context context;
public static String TAG="BackgroundService";
private BluetoothAdapter mBluetoothAdapter;
private boolean mScanning;
private Handler mHandler = new Handler();
public String[] advDataTypes = new String[256];
ArrayList<BluetoothDevice> bluetoothDeviceArrayList=new ArrayList<>();
ArrayList<BluetoothDevice> bluetoothDeviceArrayListTwo=new ArrayList<>();
private static final int REQUEST_ENABLE_BT = 1;
/*--------------Connect to BLE-----------------------------------------------*/
BluetoothGattService gattService4;
public static ArrayList<BluetoothGattCharacteristic> lastCharacteristic;
// AlertDialog.Builder alertDialog;
private float avgRssi = 0.0f;
// private Dialog dialog;
public static BluetoothLeService mBluetoothLeService;
private boolean mConnected = false;
private ArrayList<ArrayList<BluetoothGattCharacteristic>> mGattCharacteristics = new ArrayList();
//service and char uuid
private static final int TRACKER_ON_OFF = 2;
private static final UUID TRACER_TRIPPLE_PRESS_SERVICE=UUID.fromString("edfec62e-9910-0bac-5241-d8bda6932a2f");
private static final UUID TRACKER_TRIPPLE_PRESS_CHAR=UUID.fromString("772ae377-b3d2-4f8e-4042-5481d1e0098c");
private static final UUID IMMEDIATE_ALERT_UUID = UUID.fromString("00001802-0000-1000-8000-00805f9b34fb");
private static final UUID ALERT_LEVEL_UUID = UUID.fromString("00002a06-0000-1000-8000-00805f9b34fb");
public static String connectionStatus;
/*-------------------------------------------------------------------------------*/
public static final String PREFS_NAME = "PreferencesFile";
public String[] mData = new String[400];
/*--------for > 21--------------*/
private BluetoothLeScanner mLEScanner;
private ScanSettings settings;
private List<ScanFilter> filters;
private BluetoothGatt mGatt;
public BackgroundService() {
}
public BackgroundService(Context context) {
this.context = context;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
int delay = 10000;
// getting systems default ringtone
handlerScan.postDelayed(new Runnable() {
#Override
public void run() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED);
intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED);
intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED);
intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE);
intentFilter.addAction(BluetoothLeService.ACTION_GATT_RSSI_UPDATE);
intentFilter.addAction(BluetoothLeService.ACTION_GATT_WRITE_FAILED);
Log.e(TAG,"OnResume()");
getApplicationContext().registerReceiver(mGattUpdateReceiver, intentFilter);
getApplicationContext().bindService(new Intent(getApplicationContext(), BluetoothLeService.class), mServiceConnection, 1);
Toast.makeText(getApplicationContext(),"CALL YOUR METHOD",Toast.LENGTH_LONG).show();
// Use this check to determine whether BLE is supported on the device. Then you can
// selectively disable BLE-related features.
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(context, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
}
// Initializes a Bluetooth adapter. For API level 18 and above, get a reference to
// BluetoothAdapter through BluetoothManager.
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
// Checks if Bluetooth is supported on the device.
if (mBluetoothAdapter == null) {
Toast.makeText(context, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
return;
}
for (int i = 0; i < 256; i += REQUEST_ENABLE_BT) {
advDataTypes[i] = "Unknown Data Type";
}
advDataTypes[REQUEST_ENABLE_BT] = "Flags";
advDataTypes[2] = "Incomplete List of 16-bit Service Class UUIDs";
advDataTypes[3] = "Complete List of 16-bit Service Class UUIDs";
advDataTypes[4] = "Incomplete List of 32-bit Service Class UUIDs";
advDataTypes[5] = "Complete List of 32-bit Service Class UUIDs";
advDataTypes[6] = "Incomplete List of 128-bit Service Class UUIDs";
advDataTypes[7] = "Complete List of 128-bit Service Class UUIDs";
advDataTypes[8] = "Shortened Local Name";
advDataTypes[9] = "Complete Local Name";
advDataTypes[10] = "Tx Power Level";
advDataTypes[13] = "Class of LocalDevice";
advDataTypes[14] = "Simple Pairing Hash";
advDataTypes[15] = "Simple Pairing Randomizer R";
advDataTypes[16] = "LocalDevice ID";
advDataTypes[17] = "Security Manager Out of Band Flags";
advDataTypes[18] = "Slave Connection Interval Range";
advDataTypes[20] = "List of 16-bit Solicitaion UUIDs";
advDataTypes[21] = "List of 128-bit Solicitaion UUIDs";
advDataTypes[22] = "Service Data";
advDataTypes[23] = "Public Target Address";
advDataTypes[24] = "Random Target Address";
advDataTypes[25] = "Appearance";
advDataTypes[26] = "Advertising Interval";
advDataTypes[61] = "3D Information Data";
advDataTypes[255] = "Manufacturer Specific Data";
scanPeriod = getApplicationContext().getSharedPreferences(PREFS_NAME, 0).getInt("scan_interval", 2000);
scanLeDevice(true);
}
// unRegisterReceicerAndService();
}, 1000);
return START_STICKY;
}
#Override
public void onCreate() {
super.onCreate();
// -------------------Connect Ble--------------------------------------
}
private void scanLeDevice(final boolean enable) {
Log.e(TAG,"scanTrackerDevices");
bluetoothDeviceArrayList.clear();
if (enable) {
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
int arraySize=bluetoothDeviceArrayListTwo.size();
Log.e(TAG,"bluetoothDeviceArrayListTwo Size in scan :"+arraySize);
for (int i=0;i<bluetoothDeviceArrayListTwo.size();i++){
BluetoothDevice bluetoothDevice=bluetoothDeviceArrayListTwo.get(i);
Log.e(TAG,"Device Name in scan :"+bluetoothDevice.getName());
Log.e(TAG,"Device Address in scan :"+bluetoothDevice.getAddress());
if (i==0){
mBluetoothLeService.connect(bluetoothDevice.getAddress());
}
}
}
}, scanPeriod);
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
String d = "";
String rd = "";
String h = "0123456789ABCDEF";
int ln = 0;
int i = 0;
while (i < scanRecord.length) {
int x = scanRecord[i] & 255;
rd = new StringBuilder(String.valueOf(rd)).append(h.substring(x / 16, (x / 16) + REQUEST_ENABLE_BT)).append(h.substring(x % 16, (x % 16) +REQUEST_ENABLE_BT)).toString();
if (i == ln) {
ln = (i + x) + REQUEST_ENABLE_BT;
if (x == 0) {
break;
}
d = new StringBuilder(String.valueOf(d)).append("\r\n Length: ").append(h.substring(x / 16, (x / 16) + REQUEST_ENABLE_BT)).append(h.substring(x % 16, (x % 16) +REQUEST_ENABLE_BT)).toString();
i += REQUEST_ENABLE_BT;
x = scanRecord[i] & 255;
d = new StringBuilder(String.valueOf(d)).append(", Type :").append(h.substring(x / 16, (x / 16) + REQUEST_ENABLE_BT)).append(h.substring(x % 16, (x % 16) + REQUEST_ENABLE_BT)).append(" = ").append(advDataTypes[x]).append(", Value: ").toString();
rd = new StringBuilder(String.valueOf(rd)).append(h.substring(x / 16, (x / 16) + REQUEST_ENABLE_BT)).append(h.substring(x % 16, (x % 16) + REQUEST_ENABLE_BT)).toString();
} else {
d = new StringBuilder(String.valueOf(d)).append(" ").append(h.substring(x / 16, (x / 16) + REQUEST_ENABLE_BT)).append(h.substring(x % 16, (x % 16) +REQUEST_ENABLE_BT)).toString();
}
i += REQUEST_ENABLE_BT;
}
Log.e(TAG,"UUID : "+device.getUuids());
String[] arrayDeviceName=String.valueOf(device.getName()).split(" ");
String deviceName0=arrayDeviceName[0];
// String deviceName1=arrayDeviceName[1];
if (deviceName0.equals("EUROtronic")){
Log.e(TAG,"Device Name :"+device.getName());
bluetoothDeviceArrayListTwo.add(device);
// Log.e(TAG,"Device Address :"+deviceName0);
}
}
};
/*-------------------Connect BLE---------------------------------------------*/
private Handler mHandler2=new Handler();;
public final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action))
{
numberOfRssi = 0;
avgRssi = 0.0f;
mConnected = true;
mHandler2.postDelayed(startRssi, 300);
Log.e(TAG,"ACTION_GATT_CONNECTED");
}
else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
mConnected = false;
Log.e(TAG,"ACTION_GATT_DISCONNECTED");
} else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
displayGattServicesForDimmer(mBluetoothLeService.getSupportedGattServices());
Log.e(TAG,"ACTION_GATT_SERVICES_DISCOVERED");
} else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
Log.e(TAG,"ACTION_DATA_AVAILABLE");
String unknownServiceString = context.getResources().getString(R.string.unknown_service);
displayDimmer2(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));
} else if (BluetoothLeService.ACTION_GATT_RSSI_UPDATE.equals(action)) {
} else if (BluetoothLeService.ACTION_GATT_WRITE_FAILED.equals(action)) {
Log.e(TAG,"ACTION_GATT_WRITE_FAILED");
}
}
};
private BluetoothGattCharacteristic mNotifyCharacteristic;
public static ServiceConnection mServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName componentName, IBinder service) {
mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();
if (!mBluetoothLeService.initialize()) {
Log.e(TAG, "Unable to initialize Bluetooth");
// getActivity().finish();
}
// mBluetoothLeService.connect(mDeviceAddress);
}
public void onServiceDisconnected(ComponentName componentName) {
mBluetoothLeService = null;
}
};
private boolean notificationActive = true;
private int numberOfRssi = 0;
private Runnable startRssi = new Runnable() {
public void run() {
if (mConnected) {
mBluetoothLeService.readRemoteRssi();
mHandler2.postDelayed(startRssi, 200);
}
}
};
public BluetoothGatt getmGatt() {
return mGatt;
}
private void displayDimmer2(String data){
if (data!=null){
Log.e(TAG,"display Dimmer2"+data);
String sosString = data.substring(0, Math.min(data.length(), 3));
Log.e(TAG,"SOS String :"+sosString);
if (sosString.equals("SOS")){
Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse("tel:"+ SharedPreferencesUtils.getStringFromSharedPreferences(KEY_SP_MOBILE_NUMBER,getApplicationContext())));
callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplicationContext().startActivity(callIntent);
}
}
}
/*-------------------------disaplay gatt service for dimmer----------------------*/
private void displayGattServicesForDimmer(List<BluetoothGattService> gattServices) {
if (gattServices != null) {
String unknownServiceString = getResources().getString(R.string.unknown_service);
String unknownCharaString = getResources().getString(R.string.unknown_characteristic);
ArrayList<HashMap<String, String>> gattServiceData = new ArrayList();
ArrayList<ArrayList<HashMap<String, String>>> gattCharacteristicData = new ArrayList();
this.mGattCharacteristics = new ArrayList();
for (BluetoothGattService gattService : gattServices) {
HashMap<String, String> currentServiceData = new HashMap();
String uuid = gattService.getUuid().toString();
currentServiceData.put("NAME", SampleGattAttributes.lookup(uuid, unknownServiceString));
currentServiceData.put("UUID", uuid);
gattServiceData.add(currentServiceData);
ArrayList<HashMap<String, String>> gattCharacteristicGroupData = new ArrayList();
List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
ArrayList<BluetoothGattCharacteristic> charas = new ArrayList();
for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
charas.add(gattCharacteristic);
HashMap<String, String> currentCharaData = new HashMap();
uuid = gattCharacteristic.getUuid().toString();
currentCharaData.put("NAME", "\t\t\t<<" + SampleGattAttributes.lookup(uuid, unknownCharaString) + ">>");
currentCharaData.put("UUID", "\t\t\tUUID: 0x" + uuid.substring(4, 8) + ", Properties: " + translateProperties(gattCharacteristic.getProperties()));
gattCharacteristicGroupData.add(currentCharaData);
Log.i(TAG,"CUrrent CHARACTERISTIC DATA"+currentCharaData);
Log.i(TAG,"UUID : "+uuid.substring(4, 8));
Log.i(TAG,"Proprties : "+gattCharacteristic.getProperties());
Log.i(TAG,"Translate Proprties : "+translateProperties(gattCharacteristic.getProperties()));
Log.i(TAG,"char list"+gattCharacteristicData.toString());
}
gattService4=gattService;
this.mGattCharacteristics.add(charas);
}
if (mGattCharacteristics.get(3)!=null) {
lastCharacteristic = new ArrayList<>(mGattCharacteristics.get(3));
enableNotifyOfCharcteristicForDimmer(lastCharacteristic);
}
}
}
private String translateProperties(int properties) {
String s = "";
if ((properties & 1) > 0) {
s = new StringBuilder(String.valueOf(s)).append("/Broadcast").toString();
}
if ((properties & 2) > 0) {
s = new StringBuilder(String.valueOf(s)).append("/Read").toString();
}
if ((properties & 4) > 0) {
s = new StringBuilder(String.valueOf(s)).append("/WriteWithoutResponse").toString();
}
if ((properties & 8) > 0) {
s = new StringBuilder(String.valueOf(s)).append("/Write").toString();
}
if ((properties & 16) > 0) {
s = new StringBuilder(String.valueOf(s)).append("/Notify").toString();
}
if ((properties & 32) > 0) {
s = new StringBuilder(String.valueOf(s)).append("/Indicate").toString();
}
if ((properties & 64) > 0) {
s = new StringBuilder(String.valueOf(s)).append("/SignedWrite").toString();
}
if ((properties & 128) > 0) {
s = new StringBuilder(String.valueOf(s)).append("/ExtendedProperties").toString();
}
if (s.length() > 1) {
return s.substring(1);
}
return s;
}
// Enable Characteristic for dimmer
public void enableNotifyOfCharcteristicForDimmer(ArrayList<BluetoothGattCharacteristic> lastCharacteristic){
if(mGattCharacteristics!=null) {
checkCharacteristicPresent(lastCharacteristic.get(0));
mBluetoothLeService.setCharacteristicNotification(lastCharacteristic.get(0), true);
notificationActive = true;
Log.e(TAG,"Characteristic index : "+0+":\nM GATT CHARACTERISTIC AT "+"Service 4 : CHAR"+ 0 +" :" +lastCharacteristic.get(0).toString());
checkCharacteristicPresent(lastCharacteristic.get(1));
mBluetoothLeService.setCharacteristicNotification(lastCharacteristic.get(1), true);
notificationActive = true;
Log.e(TAG,"Characteristic index : "+1+":\nM GATT CHARACTERISTIC AT "+"Service 4 : CHAR"+ 1 +" :" +lastCharacteristic.get(1).toString());
checkCharacteristicPresent(lastCharacteristic.get(2));
mBluetoothLeService.setCharacteristicNotification(lastCharacteristic.get(2), true);
notificationActive = true;
Log.e(TAG,"Characteristic index : "+2+":\nM GATT CHARACTERISTIC AT "+"Service 4 : CHAR"+ 2 +" :" +lastCharacteristic.get(2).toString());
checkCharacteristicPresent(lastCharacteristic.get(3));
mBluetoothLeService.setCharacteristicNotification(lastCharacteristic.get(3), true);
notificationActive = true;
Log.e(TAG,"Characteristic index : "+3+":\nM GATT CHARACTERISTIC AT "+"Service 4 : CHAR"+ 3 +" :" +lastCharacteristic.get(3).toString());
checkCharacteristicPresent(lastCharacteristic.get(4));
mBluetoothLeService.setCharacteristicNotification(lastCharacteristic.get(4), true);
notificationActive = true;
Log.e(TAG,"Characteristic index : "+4+":\nM GATT CHARACTERISTIC AT "+"Service 4 : CHAR"+ 4 +" :" +lastCharacteristic.get(4).toString());
checkCharacteristicPresent(lastCharacteristic.get(5));
mBluetoothLeService.setCharacteristicNotification(lastCharacteristic.get(5), true);
notificationActive = true;
Log.e(TAG,"Characteristic index : "+5+":\nM GATT CHARACTERISTIC AT "+"Service 4 : CHAR"+ 5 +" :" +lastCharacteristic.get(5).toString());
checkCharacteristicPresent(lastCharacteristic.get(2));
mBluetoothLeService.setCharacteristicNotification(lastCharacteristic.get(2), true);
notificationActive = true;
Log.e(TAG,"Characteristic index : "+2+":\nM GATT CHARACTERISTIC AT "+"Service 4 : CHAR"+ 2 +" :" +lastCharacteristic.get(2).toString());
}
}
// Check the type of characteristic i.e READ/WRITE/NOTIFY
public void checkCharacteristicPresent(BluetoothGattCharacteristic characteristic) {
int charaProp = characteristic.getProperties();
Log.e(TAG, "checkCharacteristicPresent Prop : " + charaProp);
mBluetoothLeService.setCurrentCharacteristic(characteristic);
if ((charaProp & 2) > 0) {
Log.e(TAG, "CharProp & 2 : " + charaProp);
mBluetoothLeService.readCharacteristic(characteristic);
}
if ((charaProp & 16) > 0) {
Log.e(TAG, "CharProp & 16 : " + charaProp);
mNotifyCharacteristic = characteristic;
} else {
if (mNotifyCharacteristic != null) {
mBluetoothLeService.setCharacteristicNotification(mNotifyCharacteristic, false);
mNotifyCharacteristic = null;
}
}
if ((charaProp & 8) > 0 || (charaProp & 4) > 0) {
Log.e(TAG, "CharProp & 4 : " + charaProp);
} else {
Log.e(TAG, "Else : " + charaProp);
}
}
public void disconnectBLEDevice(){
// if (mNotifyCharacteristic != null) {
mBluetoothLeService.disconnect();
// }
}
#Override
public void onDestroy(){
Toast.makeText(this, "Service Destroyed", Toast.LENGTH_SHORT).show();
super.onDestroy();
}
}

class NotificationManagerCompat is missing classes

I clicked on the class NotificationManagerCompat and I cannot find the public methods
areNotificationsEnabled()
getImportance()
They are also both the only methods that return variables. I need to use the method areNotificationsEnabled() does anyone have any ideas how this could be possible?
Currently my import line is as follows
import android.support.v4.app.NotificationManagerCompat;
Not sure if it helps for me to post the entire class but here it is
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.support.v4.app;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Build;
import android.os.Bundle;
import android.os.DeadObjectException;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.provider.Settings;
import android.util.Log;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Compatibility library for NotificationManager with fallbacks for older platforms.
*
* <p>To use this class, call the static function {#link #from} to get a
* {#link NotificationManagerCompat} object, and then call one of its
* methods to post or cancel notifications.
*/
public class NotificationManagerCompat {
private static final String TAG = "NotifManCompat";
/**
* Notification extras key: if set to true, the posted notification should use
* the side channel for delivery instead of using notification manager.
*/
public static final String EXTRA_USE_SIDE_CHANNEL =
NotificationCompatJellybean.EXTRA_USE_SIDE_CHANNEL;
/**
* Intent action to register for on a service to receive side channel
* notifications. The listening service must be in the same package as an enabled
* {#link android.service.notification.NotificationListenerService}.
*/
public static final String ACTION_BIND_SIDE_CHANNEL =
"android.support.BIND_NOTIFICATION_SIDE_CHANNEL";
/**
* Maximum sdk build version which needs support for side channeled notifications.
* Currently the only needed use is for side channeling group children before KITKAT_WATCH.
*/
static final int MAX_SIDE_CHANNEL_SDK_VERSION = 19;
/** Base time delay for a side channel listener queue retry. */
private static final int SIDE_CHANNEL_RETRY_BASE_INTERVAL_MS = 1000;
/** Maximum retries for a side channel listener before dropping tasks. */
private static final int SIDE_CHANNEL_RETRY_MAX_COUNT = 6;
/** Hidden field Settings.Secure.ENABLED_NOTIFICATION_LISTENERS */
private static final String SETTING_ENABLED_NOTIFICATION_LISTENERS =
"enabled_notification_listeners";
private static final int SIDE_CHANNEL_BIND_FLAGS;
/** Cache of enabled notification listener components */
private static final Object sEnabledNotificationListenersLock = new Object();
/** Guarded by {#link #sEnabledNotificationListenersLock} */
private static String sEnabledNotificationListeners;
/** Guarded by {#link #sEnabledNotificationListenersLock} */
private static Set<String> sEnabledNotificationListenerPackages = new HashSet<String>();
private final Context mContext;
private final NotificationManager mNotificationManager;
/** Lock for mutable static fields */
private static final Object sLock = new Object();
/** Guarded by {#link #sLock} */
private static SideChannelManager sSideChannelManager;
/** Get a {#link NotificationManagerCompat} instance for a provided context. */
public static NotificationManagerCompat from(Context context) {
return new NotificationManagerCompat(context);
}
private NotificationManagerCompat(Context context) {
mContext = context;
mNotificationManager = (NotificationManager) mContext.getSystemService(
Context.NOTIFICATION_SERVICE);
}
private static final Impl IMPL;
interface Impl {
void cancelNotification(NotificationManager notificationManager, String tag, int id);
void postNotification(NotificationManager notificationManager, String tag, int id,
Notification notification);
int getSideChannelBindFlags();
}
static class ImplBase implements Impl {
#Override
public void cancelNotification(NotificationManager notificationManager, String tag,
int id) {
notificationManager.cancel(id);
}
#Override
public void postNotification(NotificationManager notificationManager, String tag, int id,
Notification notification) {
notificationManager.notify(id, notification);
}
#Override
public int getSideChannelBindFlags() {
return Service.BIND_AUTO_CREATE;
}
}
static class ImplEclair extends ImplBase {
#Override
public void cancelNotification(NotificationManager notificationManager, String tag,
int id) {
NotificationManagerCompatEclair.cancelNotification(notificationManager, tag, id);
}
#Override
public void postNotification(NotificationManager notificationManager, String tag, int id,
Notification notification) {
NotificationManagerCompatEclair.postNotification(notificationManager, tag, id,
notification);
}
}
static class ImplIceCreamSandwich extends ImplEclair {
#Override
public int getSideChannelBindFlags() {
return NotificationManagerCompatIceCreamSandwich.SIDE_CHANNEL_BIND_FLAGS;
}
}
static {
if (Build.VERSION.SDK_INT >= 14) {
IMPL = new ImplIceCreamSandwich();
} else if (Build.VERSION.SDK_INT >= 5) {
IMPL = new ImplEclair();
} else {
IMPL = new ImplBase();
}
SIDE_CHANNEL_BIND_FLAGS = IMPL.getSideChannelBindFlags();
}
/**
* Cancel a previously shown notification.
* #param id the ID of the notification
*/
public void cancel(int id) {
cancel(null, id);
}
/**
* Cancel a previously shown notification.
* #param tag the string identifier of the notification.
* #param id the ID of the notification
*/
public void cancel(String tag, int id) {
IMPL.cancelNotification(mNotificationManager, tag, id);
if (Build.VERSION.SDK_INT <= MAX_SIDE_CHANNEL_SDK_VERSION) {
pushSideChannelQueue(new CancelTask(mContext.getPackageName(), id, tag));
}
}
/** Cancel all previously shown notifications. */
public void cancelAll() {
mNotificationManager.cancelAll();
if (Build.VERSION.SDK_INT <= MAX_SIDE_CHANNEL_SDK_VERSION) {
pushSideChannelQueue(new CancelTask(mContext.getPackageName()));
}
}
/**
* Post a notification to be shown in the status bar, stream, etc.
* #param id the ID of the notification
* #param notification the notification to post to the system
*/
public void notify(int id, Notification notification) {
notify(null, id, notification);
}
/**
* Post a notification to be shown in the status bar, stream, etc.
* #param tag the string identifier for a notification. Can be {#code null}.
* #param id the ID of the notification. The pair (tag, id) must be unique within your app.
* #param notification the notification to post to the system
*/
public void notify(String tag, int id, Notification notification) {
if (useSideChannelForNotification(notification)) {
pushSideChannelQueue(new NotifyTask(mContext.getPackageName(), id, tag, notification));
// Cancel this notification in notification manager if it just transitioned to being
// side channelled.
IMPL.cancelNotification(mNotificationManager, tag, id);
} else {
IMPL.postNotification(mNotificationManager, tag, id, notification);
}
}
/**
* Get the set of packages that have an enabled notification listener component within them.
*/
public static Set<String> getEnabledListenerPackages(Context context) {
final String enabledNotificationListeners = Settings.Secure.getString(
context.getContentResolver(),
SETTING_ENABLED_NOTIFICATION_LISTENERS);
// Parse the string again if it is different from the last time this method was called.
if (enabledNotificationListeners != null
&& !enabledNotificationListeners.equals(sEnabledNotificationListeners)) {
final String[] components = enabledNotificationListeners.split(":");
Set<String> packageNames = new HashSet<String>(components.length);
for (String component : components) {
ComponentName componentName = ComponentName.unflattenFromString(component);
if (componentName != null) {
packageNames.add(componentName.getPackageName());
}
}
synchronized (sEnabledNotificationListenersLock) {
sEnabledNotificationListenerPackages = packageNames;
sEnabledNotificationListeners = enabledNotificationListeners;
}
}
return sEnabledNotificationListenerPackages;
}
/**
* Returns true if this notification should use the side channel for delivery.
*/
private static boolean useSideChannelForNotification(Notification notification) {
Bundle extras = NotificationCompat.getExtras(notification);
return extras != null && extras.getBoolean(EXTRA_USE_SIDE_CHANNEL);
}
/**
* Push a notification task for distribution to notification side channels.
*/
private void pushSideChannelQueue(Task task) {
synchronized (sLock) {
if (sSideChannelManager == null) {
sSideChannelManager = new SideChannelManager(mContext.getApplicationContext());
}
}
sSideChannelManager.queueTask(task);
}
/**
* Helper class to manage a queue of pending tasks to send to notification side channel
* listeners.
*/
private static class SideChannelManager implements Handler.Callback, ServiceConnection {
private static final int MSG_QUEUE_TASK = 0;
private static final int MSG_SERVICE_CONNECTED = 1;
private static final int MSG_SERVICE_DISCONNECTED = 2;
private static final int MSG_RETRY_LISTENER_QUEUE = 3;
private static final String KEY_BINDER = "binder";
private final Context mContext;
private final HandlerThread mHandlerThread;
private final Handler mHandler;
private final Map<ComponentName, ListenerRecord> mRecordMap =
new HashMap<ComponentName, ListenerRecord>();
private Set<String> mCachedEnabledPackages = new HashSet<String>();
public SideChannelManager(Context context) {
mContext = context;
mHandlerThread = new HandlerThread("NotificationManagerCompat");
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper(), this);
}
/**
* Queue a new task to be sent to all listeners. This function can be called
* from any thread.
*/
public void queueTask(Task task) {
mHandler.obtainMessage(MSG_QUEUE_TASK, task).sendToTarget();
}
#Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_QUEUE_TASK:
handleQueueTask((Task) msg.obj);
return true;
case MSG_SERVICE_CONNECTED:
ServiceConnectedEvent event = (ServiceConnectedEvent) msg.obj;
handleServiceConnected(event.componentName, event.iBinder);
return true;
case MSG_SERVICE_DISCONNECTED:
handleServiceDisconnected((ComponentName) msg.obj);
return true;
case MSG_RETRY_LISTENER_QUEUE:
handleRetryListenerQueue((ComponentName) msg.obj);
return true;
}
return false;
}
private void handleQueueTask(Task task) {
updateListenerMap();
for (ListenerRecord record : mRecordMap.values()) {
record.taskQueue.add(task);
processListenerQueue(record);
}
}
private void handleServiceConnected(ComponentName componentName, IBinder iBinder) {
ListenerRecord record = mRecordMap.get(componentName);
if (record != null) {
record.service = INotificationSideChannel.Stub.asInterface(iBinder);
record.retryCount = 0;
processListenerQueue(record);
}
}
private void handleServiceDisconnected(ComponentName componentName) {
ListenerRecord record = mRecordMap.get(componentName);
if (record != null) {
ensureServiceUnbound(record);
}
}
private void handleRetryListenerQueue(ComponentName componentName) {
ListenerRecord record = mRecordMap.get(componentName);
if (record != null) {
processListenerQueue(record);
}
}
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Connected to service " + componentName);
}
mHandler.obtainMessage(MSG_SERVICE_CONNECTED,
new ServiceConnectedEvent(componentName, iBinder))
.sendToTarget();
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Disconnected from service " + componentName);
}
mHandler.obtainMessage(MSG_SERVICE_DISCONNECTED, componentName).sendToTarget();
}
/**
* Check the current list of enabled listener packages and update the records map
* accordingly.
*/
private void updateListenerMap() {
Set<String> enabledPackages = getEnabledListenerPackages(mContext);
if (enabledPackages.equals(mCachedEnabledPackages)) {
// Short-circuit when the list of enabled packages has not changed.
return;
}
mCachedEnabledPackages = enabledPackages;
List<ResolveInfo> resolveInfos = mContext.getPackageManager().queryIntentServices(
new Intent().setAction(ACTION_BIND_SIDE_CHANNEL), PackageManager.GET_SERVICES);
Set<ComponentName> enabledComponents = new HashSet<ComponentName>();
for (ResolveInfo resolveInfo : resolveInfos) {
if (!enabledPackages.contains(resolveInfo.serviceInfo.packageName)) {
continue;
}
ComponentName componentName = new ComponentName(
resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name);
if (resolveInfo.serviceInfo.permission != null) {
Log.w(TAG, "Permission present on component " + componentName
+ ", not adding listener record.");
continue;
}
enabledComponents.add(componentName);
}
// Ensure all enabled components have a record in the listener map.
for (ComponentName componentName : enabledComponents) {
if (!mRecordMap.containsKey(componentName)) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Adding listener record for " + componentName);
}
mRecordMap.put(componentName, new ListenerRecord(componentName));
}
}
// Remove listener records that are no longer for enabled components.
Iterator<Map.Entry<ComponentName, ListenerRecord>> it =
mRecordMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<ComponentName, ListenerRecord> entry = it.next();
if (!enabledComponents.contains(entry.getKey())) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Removing listener record for " + entry.getKey());
}
ensureServiceUnbound(entry.getValue());
it.remove();
}
}
}
/**
* Ensure we are already attempting to bind to a service, or start a new binding if not.
* #return Whether the service bind attempt was successful.
*/
private boolean ensureServiceBound(ListenerRecord record) {
if (record.bound) {
return true;
}
Intent intent = new Intent(ACTION_BIND_SIDE_CHANNEL).setComponent(record.componentName);
record.bound = mContext.bindService(intent, this, SIDE_CHANNEL_BIND_FLAGS);
if (record.bound) {
record.retryCount = 0;
} else {
Log.w(TAG, "Unable to bind to listener " + record.componentName);
mContext.unbindService(this);
}
return record.bound;
}
/**
* Ensure we have unbound from a service.
*/
private void ensureServiceUnbound(ListenerRecord record) {
if (record.bound) {
mContext.unbindService(this);
record.bound = false;
}
record.service = null;
}
/**
* Schedule a delayed retry to communicate with a listener service.
* After a maximum number of attempts (with exponential back-off), start
* dropping pending tasks for this listener.
*/
private void scheduleListenerRetry(ListenerRecord record) {
if (mHandler.hasMessages(MSG_RETRY_LISTENER_QUEUE, record.componentName)) {
return;
}
record.retryCount++;
if (record.retryCount > SIDE_CHANNEL_RETRY_MAX_COUNT) {
Log.w(TAG, "Giving up on delivering " + record.taskQueue.size() + " tasks to "
+ record.componentName + " after " + record.retryCount + " retries");
record.taskQueue.clear();
return;
}
int delayMs = SIDE_CHANNEL_RETRY_BASE_INTERVAL_MS * (1 << (record.retryCount - 1));
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Scheduling retry for " + delayMs + " ms");
}
Message msg = mHandler.obtainMessage(MSG_RETRY_LISTENER_QUEUE, record.componentName);
mHandler.sendMessageDelayed(msg, delayMs);
}
/**
* Perform a processing step for a listener. First check the bind state, then attempt
* to flush the task queue, and if an error is encountered, schedule a retry.
*/
private void processListenerQueue(ListenerRecord record) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Processing component " + record.componentName + ", "
+ record.taskQueue.size() + " queued tasks");
}
if (record.taskQueue.isEmpty()) {
return;
}
if (!ensureServiceBound(record) || record.service == null) {
// Ensure bind has started and that a service interface is ready to use.
scheduleListenerRetry(record);
return;
}
// Attempt to flush all items in the task queue.
while (true) {
Task task = record.taskQueue.peek();
if (task == null) {
break;
}
try {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Sending task " + task);
}
task.send(record.service);
record.taskQueue.remove();
} catch (DeadObjectException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Remote service has died: " + record.componentName);
}
break;
} catch (RemoteException e) {
Log.w(TAG, "RemoteException communicating with " + record.componentName, e);
break;
}
}
if (!record.taskQueue.isEmpty()) {
// Some tasks were not sent, meaning an error was encountered, schedule a retry.
scheduleListenerRetry(record);
}
}
/** A per-side-channel-service listener state record */
private static class ListenerRecord {
public final ComponentName componentName;
/** Whether the service is currently bound to. */
public boolean bound = false;
/** The service stub provided by onServiceConnected */
public INotificationSideChannel service;
/** Queue of pending tasks to send to this listener service */
public LinkedList<Task> taskQueue = new LinkedList<Task>();
/** Number of retries attempted while connecting to this listener service */
public int retryCount = 0;
public ListenerRecord(ComponentName componentName) {
this.componentName = componentName;
}
}
}
private static class ServiceConnectedEvent {
final ComponentName componentName;
final IBinder iBinder;
public ServiceConnectedEvent(ComponentName componentName,
final IBinder iBinder) {
this.componentName = componentName;
this.iBinder = iBinder;
}
}
private interface Task {
public void send(INotificationSideChannel service) throws RemoteException;
}
private static class NotifyTask implements Task {
final String packageName;
final int id;
final String tag;
final Notification notif;
public NotifyTask(String packageName, int id, String tag, Notification notif) {
this.packageName = packageName;
this.id = id;
this.tag = tag;
this.notif = notif;
}
#Override
public void send(INotificationSideChannel service) throws RemoteException {
service.notify(packageName, id, tag, notif);
}
public String toString() {
StringBuilder sb = new StringBuilder("NotifyTask[");
sb.append("packageName:").append(packageName);
sb.append(", id:").append(id);
sb.append(", tag:").append(tag);
sb.append("]");
return sb.toString();
}
}
private static class CancelTask implements Task {
final String packageName;
final int id;
final String tag;
final boolean all;
public CancelTask(String packageName) {
this.packageName = packageName;
this.id = 0;
this.tag = null;
this.all = true;
}
public CancelTask(String packageName, int id, String tag) {
this.packageName = packageName;
this.id = id;
this.tag = tag;
this.all = false;
}
#Override
public void send(INotificationSideChannel service) throws RemoteException {
if (all) {
service.cancelAll(packageName);
} else {
service.cancel(packageName, id, tag);
}
}
public String toString() {
StringBuilder sb = new StringBuilder("CancelTask[");
sb.append("packageName:").append(packageName);
sb.append(", id:").append(id);
sb.append(", tag:").append(tag);
sb.append(", all:").append(all);
sb.append("]");
return sb.toString();
}
}
}

Application receiving NFC always pops up new instance in front

I run through the following life-cycle when starting my app through the launcher:
onCreate..., onPostCreate..., onResume..., onNewIntent..., act:android.intent.action.MAIN, mNfcAdapter.disableForegroundDispatch OK.
When I then tap a tag, a new instance of application seems to be launched as I run through the following life-cycle then:
onPause..., onCreate..., onPostCreate..., onResume..., onNewIntent..., act:android.nfc.action.TAG_DISCOVERED, myTag.mId:048a1382bd2384)
Since I try to use the foreground dispatch system to disable recieving NFC events, I expected my app to ignore the NFC tag. So why is my activity recreated instead? Is it because AndroidManifest.xml allows it?
package com.example.pdf.nfcaccess;
import android.annotation.SuppressLint;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.View;
// PDf import
import android.telephony.TelephonyManager;
import android.content.Intent;
import android.content.Context;
import android.content.IntentFilter;
import android.app.PendingIntent;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.NfcAdapter.CreateNdefMessageCallback;
import android.nfc.NfcEvent;
import android.widget.TextView;
import android.widget.Toast;
import android.util.Log;
import android.nfc.tech.NfcF;
import android.nfc.Tag;
/**
* An example full-screen activity that shows and hides the system UI (i.e.
* status bar and navigation/system bar) with user interaction.
*/
public class FullscreenActivity extends AppCompatActivity {
/**
* Whether or not the system UI should be auto-hidden after
* {#link #AUTO_HIDE_DELAY_MILLIS} milliseconds.
*/
private static final boolean AUTO_HIDE = true;
/**
* If {#link #AUTO_HIDE} is set, the number of milliseconds to wait after
* user interaction before hiding the system UI.
*/
private static final int AUTO_HIDE_DELAY_MILLIS = 3000;
/**
* Some older devices needs a small delay between UI widget updates
* and a change of the status and navigation bar.
*/
private static final int UI_ANIMATION_DELAY = 300;
private final Handler mHideHandler = new Handler();
private View mContentView;
private final Runnable mHidePart2Runnable = new Runnable() {
#SuppressLint("InlinedApi")
#Override
public void run() {
// Delayed removal of status and navigation bar
// Note that some of these constants are new as of API 16 (Jelly Bean)
// and API 19 (KitKat). It is safe to use them, as they are inlined
// at compile-time and do nothing on earlier devices.
mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
}
};
private View mControlsView;
// application
static FullscreenActivity mInstance;
NfcAdapter mNfcAdapter;
Intent mNfcIntent;
PendingIntent mNfcPendingIntent;
IntentFilter mTagIntentFilter;
IntentFilter[] mIntentFiltersArray;
String[][] mTechLists;
TextView mTagContentText;
// log
//java.util.ArrayList<String> mLogItems = new java.util.ArrayList<String>();
java.util.ArrayList<String> mLogItems = new java.util.ArrayList<String>();
android.widget.ArrayAdapter<String> mLogAdapter;
android.widget.ListView mLogList;
/**/
private final Runnable mShowPart2Runnable = new Runnable() {
#Override
public void run() {
// Delayed display of UI elements
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.show();
}
mControlsView.setVisibility(View.VISIBLE);
}
};
private boolean mVisible;
private final Runnable mHideRunnable = new Runnable() {
#Override
public void run() {
hide();
}
};
/**
* Touch listener to use for in-layout UI controls to delay hiding the
* system UI. This is to prevent the jarring behavior of controls going away
* while interacting with activity UI.
*/
/* Enable NFC
*/
private final View.OnTouchListener mFuncNfcEnable = new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
traceTry("mFuncNfcEnable");
if (mNfcAdapter != null) {
try {
traceTry("mNfcAdapter.enableForegroundDispatch");
mNfcAdapter.enableForegroundDispatch(FullscreenActivity.mInstance, mNfcPendingIntent, mIntentFiltersArray, mTechLists);
traceOk();
}
catch (Throwable t) {
traceFails(t);
}
}
}
return false;
}
};
/* read Intent
*/
private final View.OnTouchListener mFuncNfcRead = new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (mNfcAdapter != null) {
try {
traceTry("onNewIntent");
onNewIntent(getIntent());
traceOk();
}
catch (Throwable t) {
traceFails(t);
}
}
return false;
}
};
/* Disable NFC
*/
private final View.OnTouchListener mFuncNfcDisable = new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN){
traceTry("mFuncNfcDisable");
if (mNfcAdapter != null) {
try {
traceTry("mNfcAdapter.disableForegroundDispatch");
mNfcAdapter.disableForegroundDispatch(FullscreenActivity.mInstance);
traceOk();
}
catch (Throwable t) {
traceFails(t);
}
}
}
return false;
}
};
/* Quit
*/
private final View.OnTouchListener mFuncBtnQuit = new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
finish();
return false;
}
};
/**/
private void trace(String m) {
Log.d("NFCTags",m);
/*TextView tv = (TextView)findViewById(R.id.logContent_value);
String previous = tv.getText().toString();
tv.setText(previous + "\n" + m);*/
if (mLogAdapter != null) {
mLogItems.add(m);
mLogAdapter.notifyDataSetChanged();
mLogList.setSelection(mLogList.getCount()-1);
}
}
String mMessage = "";
private void traceTry(String m) {
trace(m + "...");
mMessage = m;
}
private void traceOk() {
trace(mMessage + " OK");
mMessage = "";
}
private void traceFails(Throwable t) {
String msg = mMessage + " fails";
if (t != null) {
msg += " exception:" + t.getMessage();
}
trace(msg);
//Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
mMessage = "";
}
/*
*/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
trace("onCreate...");
// set global unique instance
FullscreenActivity.mInstance = this;
setContentView(R.layout.activity_fullscreen);
// log
mLogItems.add("starts");
mLogAdapter = new android.widget.ArrayAdapter<String>(this, R.layout.support_simple_spinner_dropdown_item, mLogItems);
mLogList = (android.widget.ListView) findViewById(R.id.logList_value);
mLogList.setAdapter(mLogAdapter);
mVisible = true;
mControlsView = findViewById(R.id.fullscreen_content_controls);
mContentView = findViewById(R.id.fullscreen_content);
mTagContentText = (TextView) findViewById(R.id.tagContent_value);
// Set up the user interaction to manually show or hide the system UI.
mContentView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
toggle();
}
});
// Upon interacting with UI controls, delay any scheduled hide()
// operations to prevent the jarring behavior of controls going away
// while interacting with the UI.
findViewById(R.id.nfcRead_btn).setOnTouchListener(mFuncNfcRead);
//findViewById(R.id.nfcDisable_btn).setOnTouchListener(mFuncNfcDisable);
findViewById(R.id.quit_btn).setOnTouchListener(mFuncBtnQuit);
trace("onCreate > before initializing nfc");
TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
trace("ID:" + tm.getDeviceId());
trace("Network Operator Name:" + tm.getNetworkOperatorName());
trace("Sim Operator Name:" + tm.getSimOperatorName());
trace("Sim Serial Number:" + tm.getSimSerialNumber());
trace("Phone Type:" + tm.getPhoneType());
trace("Initial Phone Number:" + tm.getLine1Number());
boolean tryNfc = true;
if (tryNfc) {
try {
mMessage = "NfcAdapter.getDefaultAdapter";
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
if (mNfcAdapter == null) {
mMessage = "NFC is not available";
traceFails(null);
return;
} else {
traceOk();
}
} catch (Throwable t) {
traceFails(t);
return;
}
// Check if NFC is enabled
try {
mMessage = "test NfcAdapter.isEnabled";
if (!mNfcAdapter.isEnabled()) {
mMessage = "NFC is not enabled. do it manually";
traceFails(null);
return;
} else {
trace("NFC is enabled.");
}
} catch (Throwable t) {
traceFails(t);
return;
}
try {
mMessage = "create new Intent";
mNfcIntent = new Intent(this, getClass());
traceOk();
} catch (Throwable t) {
traceFails(t);
return;
}
try {
mMessage = "mNfcIntent.addFlags, PendingIntent.getActivity";
mNfcIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
mNfcPendingIntent = PendingIntent.getActivity(this, 0, mNfcIntent, 0);
traceOk();
} catch (Throwable t) {
traceFails(t);
return;
}
try {
mMessage = "new IntentFilter";
mTagIntentFilter = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
mTagIntentFilter.addCategory(Intent.CATEGORY_DEFAULT);
traceOk();
} catch (Throwable t) {
traceFails(t);
return;
}
try {
mMessage = "addDataType, new IntentFilter[]";
mTagIntentFilter.addDataType("*/*");
//mTagIntentFilter.addDataType("text/plain");
mIntentFiltersArray = new IntentFilter[]{mTagIntentFilter};
traceOk();
} catch (Throwable t) {
traceFails(t);
return;
}
// Setup a tech list for all NfcF tags
try {
mMessage = "new tech list";
//mTechLists = new String[][]{new String[]{NfcF.class.getName()}};
mTechLists = new String[][]{};
traceOk();
} catch (Throwable t) {
traceFails(t);
return;
}
/*
if (mNfcAdapter != null) {
try {
mMessage = "mNfcAdapter.enableForegroundDispatch";
mNfcAdapter.enableForegroundDispatch(FullscreenActivity.mInstance, mNfcPendingIntent, mIntentFiltersArray, mTechLists);
traceOk();
}
catch (Throwable t) {
traceFails(t);
}
}
*/
}
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
trace("onPostCreate...");
// Trigger the initial hide() shortly after the activity has been
// created, to briefly hint to the user that UI controls
// are available.
//delayedHide(100);
}
private void toggle() {
trace("toggle...");
if (mVisible) {
hide();
} else {
show();
}
}
private void hide() {
trace("hide...");
// Hide UI first
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.hide();
}
mControlsView.setVisibility(View.GONE);
mVisible = false;
// Schedule a runnable to remove the status and navigation bar after a delay
mHideHandler.removeCallbacks(mShowPart2Runnable);
mHideHandler.postDelayed(mHidePart2Runnable, UI_ANIMATION_DELAY);
}
#SuppressLint("InlinedApi")
private void show() {
// Show the system bar
mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
mVisible = true;
// Schedule a runnable to display UI elements after a delay
mHideHandler.removeCallbacks(mHidePart2Runnable);
mHideHandler.postDelayed(mShowPart2Runnable, UI_ANIMATION_DELAY);
}
/**
* Schedules a call to hide() in [delay] milliseconds, canceling any
* previously scheduled calls.
*/
private void delayedHide(int delayMillis) {
mHideHandler.removeCallbacks(mHideRunnable);
mHideHandler.postDelayed(mHideRunnable, delayMillis);
}
/**/
public String intentToText(Intent intent){
String report = "?";
try {
Bundle bundle = intent.getExtras();
if (bundle != null) {
java.util.Set<String> keys = bundle.keySet();
java.util.Iterator<String> it = keys.iterator();
report = "Intent:{";
while (it.hasNext()) {
String key = it.next();
report += "\n[" + key + ":" + bundle.get(key) + "],";
}
report += "}\n";
}
}
catch(Throwable t){
trace("intentToText > " + t.getMessage());
}
return report;
}
/**/
public static String byteArrayToHex(byte[] a) {
StringBuilder sb = new StringBuilder(a.length * 2);
for(byte b: a)
sb.append(String.format("%02x", b & 0xff));
return sb.toString();
}
/**/
#Override
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
trace("onNewIntent...");
handleIntent(intent);
}
/**/
void handleIntent(Intent intent) {
if (intent == null) return;
String sAction = intent.getAction();
trace("act:" + sAction);
if( (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction()))
|| (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction()))
|| (NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction()))) {
String payload = intent.getDataString();
mTagContentText.setText("act:" + sAction + "\n" + "pload:" + payload + "\n" + intentToText(intent));
Tag myTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
if (myTag != null) {
trace("myTag.mId:" + byteArrayToHex(myTag.getId()));
mTagContentText.setText(mTagContentText.getText() + "\n" + "myTag.mId:" + byteArrayToHex(myTag.getId()));
android.os.Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if (rawMsgs != null) {
for (android.os.Parcelable p : rawMsgs) {
NdefMessage msg = (NdefMessage) p;
NdefRecord[] records = msg.getRecords();
for (NdefRecord record : records) {
short tnf = record.getTnf();
byte[] id = record.getId();
byte[] payLoad = record.getPayload();
}
}
}
}
}
}
/**/
#Override
protected void onResume() {
super.onResume();
trace("onResume...");
if (mNfcAdapter != null) {
try {
// See if the Activity is being started/resumed due to an NFC event and handle it
onNewIntent( getIntent());
}
catch (Throwable t) {
traceFails(t);
}
try {
mMessage = "mNfcAdapter.disableForegroundDispatch";
mNfcAdapter.disableForegroundDispatch(FullscreenActivity.mInstance);
traceOk();
}
catch (Throwable t) {
traceFails(t);
}
}
}
/**/
#Override
protected void onPause() {
super.onPause();
trace("onPause...");
}
}
AndroidManifest.xml is :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.pdf.nfcaccess">
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_pdflauncher"
android:label="#string/app_name"
android:supportsRtl="true"
android:debuggable="true"
android:theme="#style/AppTheme">
<activity
android:name=".FullscreenActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="#string/app_name"
android:theme="#style/FullscreenTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.TECH_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
<!--intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain"/>
</intent-filter-->
</manifest>
You receive the NFC intent (action TAG_DISCOVERED) because you registered for it in the manifest:
<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
This is also the reason why your activity is recreated upon receiving the intent.
The intent filter that you register for the foreground dispatch (action NDEF_DISCOVERED with any MIME type) does not seem to match your tag (or you did not yet invoke the piece of code that would enable the foreground dispatch).
Note that calling disableForegroundDispatch() will ony disable a foreground dispatch previously registered through enableForegroundDispatch(). It will not influence the intent filters in your manifest. See Android: Can I enable/disable an activity's intent filter programmatically? on how you could selectively disable intent filters registered in the manifest. However, with regard to NFC intents, you would probably want to register to receive events for all tags through the foreground dispatch system and then, upon receiving the event in onNewIntent() selectively ignore tags that you don't want.
A few more things about your code (actually only about the NFC parts)
For the NDEF_DISCOVERED intent filter in your manifest you would typically also want to specify a <data ... /> element that matches the data type of your tags.
Do not use a TAG_DISCOVERED intent filter in your manifest (unless you really understand and want the impact of this). The TAG_DISCOVERED intent filter (when used in the manifest) is merely a compatibility mode for API level 9 (before Android 2.3.3) where NFC support was very, very limited and a fall-back mode that can be used to create apps that handle NFC tags that are not supported by any other app.
The TECH_DISCOVERED intent filter requires a tech-list XML file in order to match any tag. Thus, your current version of this filter in your manifest will never match anything.
Calling disableForegroundDispatch() in onResume() does not make any sense. By design, the foreground dispatch could never be enabled at this point of the activity life-cycle. The reason for this is that you must not call enableForegroundDispatch() before onResume() and you are required to call disableForegroundDispatch() at latest in onPause().
In fact it does not make sense to use enableForegroundDispatch() / disableForegroundDispatch() anywhere other than in onResume() / onPause(). If you want to stop listening for tags upon other events (e.g. a pressing a button), you would simply remember your current state (process/don't process NFC events) in some flag and, when you receive a new NFC intent in onNewIntent(), you would either process or silently ignore the tag based n that flag.
Your code should not manually call activity life-cycle methods (as you currently do with onNewIntent(getIntent());).

How to send parameter to this java class?

i am completely new on java, and i am trying to implement a print test using Zebra SDK.
this Zebra SDK (at the end of the class there is a "getConfigLabel"), prints a constant "TEST", so i want to send a variable insted of constant. to get this, i understand that i have to send a parameter to the class, but it is not clear for me how to get this done.
thanks.
here is the class:
/***********************************************
* CONFIDENTIAL AND PROPRIETARY
*
* The source code and other information contained herein is the confidential and the exclusive property of
* ZIH Corp. and is subject to the terms and conditions in your end user license agreement.
* This source code, and any other information contained herein, shall not be copied, reproduced, published,
* displayed or distributed, in whole or in part, in any medium, by any means, for any purpose except as
* expressly permitted under such license agreement.
*
* Copyright ZIH Corp. 2012
*
* ALL RIGHTS RESERVED
***********************************************/
package com.zebra.android.devdemo.connectivity;
import android.app.Activity;
import android.graphics.Color;
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.RadioButton;
import android.widget.RadioGroup;
import android.widget.RadioGroup.OnCheckedChangeListener;
import android.widget.TextView;
import com.zebra.android.devdemo.R;
import com.zebra.sdk.comm.BluetoothConnection;
import com.zebra.sdk.comm.Connection;
import com.zebra.sdk.comm.ConnectionException;
import com.zebra.sdk.comm.TcpConnection;
import com.zebra.sdk.printer.PrinterLanguage;
import com.zebra.sdk.printer.ZebraPrinter;
import com.zebra.sdk.printer.ZebraPrinterFactory;
import com.zebra.sdk.printer.ZebraPrinterLanguageUnknownException;
public class ConnectivityDemo extends Activity {
private Connection printerConnection;
private RadioButton btRadioButton;
private ZebraPrinter printer;
private TextView statusField;
private EditText macAddress, ipDNSAddress, portNumber, vtextToPrint;
private Button testButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.connection_screen_with_status);
ipDNSAddress = (EditText) this.findViewById(R.id.ipAddressInput);
ipDNSAddress.setText(SettingsHelper.getIp(this));
vtextToPrint = (EditText) this.findViewById(R.id.textToPrint);
portNumber = (EditText) this.findViewById(R.id.portInput);
portNumber.setText(SettingsHelper.getPort(this));
macAddress = (EditText) this.findViewById(R.id.macInput);
macAddress.setText(SettingsHelper.getBluetoothAddress(this));
statusField = (TextView) this.findViewById(R.id.statusText);
btRadioButton = (RadioButton) this.findViewById(R.id.bluetoothRadio);
testButton = (Button) this.findViewById(R.id.testButton);
testButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
enableTestButton(false);
Looper.prepare();
doConnectionTest();
Looper.loop();
Looper.myLooper().quit();
}
}).start();
}
});
RadioGroup radioGroup = (RadioGroup) this.findViewById(R.id.radioGroup);
radioGroup.setOnCheckedChangeListener(new OnCheckedChangeListener() {
public void onCheckedChanged(RadioGroup group, int checkedId) {
if (checkedId == R.id.bluetoothRadio) {
toggleEditField(macAddress, true);
toggleEditField(portNumber, false);
toggleEditField(ipDNSAddress, false);
} else {
toggleEditField(portNumber, true);
toggleEditField(ipDNSAddress, true);
toggleEditField(macAddress, false);
}
}
});
}
private void toggleEditField(EditText editText, boolean set) {
/*
* Note: Disabled EditText fields may still get focus by some other means, and allow text input.
* See http://code.google.com/p/android/issues/detail?id=2771
*/
editText.setEnabled(set);
editText.setFocusable(set);
editText.setFocusableInTouchMode(set);
}
#Override
protected void onStop() {
super.onStop();
if (printerConnection != null && printerConnection.isConnected()) {
disconnect();
}
}
private void enableTestButton(final boolean enabled) {
runOnUiThread(new Runnable() {
public void run() {
testButton.setEnabled(enabled);
}
});
}
private boolean isBluetoothSelected() {
return btRadioButton.isChecked();
}
public ZebraPrinter connect() {
setStatus("Connecting...", Color.YELLOW);
printerConnection = null;
if (isBluetoothSelected()) {
printerConnection = new BluetoothConnection(getMacAddressFieldText());
SettingsHelper.saveBluetoothAddress(this, getMacAddressFieldText());
} else {
try {
int port = Integer.parseInt(getTcpPortNumber());
printerConnection = new TcpConnection(getTcpAddress(), port);
SettingsHelper.saveIp(this, getTcpAddress());
SettingsHelper.savePort(this, getTcpPortNumber());
} catch (NumberFormatException e) {
setStatus("Port Number Is Invalid", Color.RED);
return null;
}
}
try {
printerConnection.open();
setStatus("Connected", Color.GREEN);
} catch (ConnectionException e) {
setStatus("Comm Error! Disconnecting", Color.RED);
DemoSleeper.sleep(1000);
disconnect();
}
ZebraPrinter printer = null;
if (printerConnection.isConnected()) {
try {
printer = ZebraPrinterFactory.getInstance(printerConnection);
setStatus("Determining Printer Language", Color.YELLOW);
PrinterLanguage pl = printer.getPrinterControlLanguage();
setStatus("Printer Language " + pl, Color.BLUE);
} catch (ConnectionException e) {
setStatus("Unknown Printer Language", Color.RED);
printer = null;
DemoSleeper.sleep(1000);
disconnect();
} catch (ZebraPrinterLanguageUnknownException e) {
setStatus("Unknown Printer Language", Color.RED);
printer = null;
DemoSleeper.sleep(1000);
disconnect();
}
}
return printer;
}
public void disconnect() {
try {
setStatus("Disconnecting", Color.RED);
if (printerConnection != null) {
printerConnection.close();
}
setStatus("Not Connected", Color.RED);
} catch (ConnectionException e) {
setStatus("COMM Error! Disconnected", Color.RED);
} finally {
enableTestButton(true);
}
}
private void setStatus(final String statusMessage, final int color) {
runOnUiThread(new Runnable() {
public void run() {
statusField.setBackgroundColor(color);
statusField.setText(statusMessage);
}
});
DemoSleeper.sleep(200);
}
private String getMacAddressFieldText() {
return macAddress.getText().toString();
}
private String getTcpAddress() {
return ipDNSAddress.getText().toString();
}
private String getTcpPortNumber() {
return portNumber.getText().toString();
}
private void doConnectionTest() {
printer = connect();
if (printer != null) {
sendTestLabel();
} else {
disconnect();
}
}
private void sendTestLabel() {
try {
byte[] configLabel = getConfigLabel();
printerConnection.write(configLabel);
setStatus("Sending Data", Color.BLUE);
DemoSleeper.sleep(500);
if (printerConnection instanceof BluetoothConnection) {
String friendlyName = ((BluetoothConnection) printerConnection).getFriendlyName();
setStatus(friendlyName, Color.MAGENTA);
DemoSleeper.sleep(500);
}
} catch (ConnectionException e) {
setStatus(e.getMessage(), Color.RED);
} finally {
disconnect();
}
}
/*
* Returns the command for a test label depending on the printer control language
* The test label is a box with the word "TEST" inside of it
*
* _________________________
* | |
* | |
* | TEST |
* | |
* | |
* |_______________________|
*
*
*/
private byte[] getConfigLabel() {
PrinterLanguage printerLanguage = printer.getPrinterControlLanguage();
byte[] configLabel = null;
if (printerLanguage == PrinterLanguage.ZPL) {
configLabel = "^XA^FO17,16^GB379,371,8^FS^FT65,255^A0N,135,134^FDTEST^FS^XZ".getBytes();
} else if (printerLanguage == PrinterLanguage.CPCL) {
String cpclConfigLabel = "! 0 200 200 406 1\r\n" + "ON-FEED IGNORE\r\n" + "BOX 20 20 380 380 8\r\n" + "T 0 6 137 177 TEST\r\n" + "PRINT\r\n";
configLabel = cpclConfigLabel.getBytes();
}
return configLabel;
}
}
private byte[] getConfigLabel(String parameter) {
.....
String cpclConfigLabel = "! 0 200 200 406 1\r\n" + "ON-FEED IGNORE\r\n" + "BOX 20 20 380 380 8\r\n" + "T 0 6 137 177 " + parameter + "r\n" + "PRINT\r\n";
.......
}
This is how you take in an argument into a method.
When calling the method getConfigLabel, make sure you pass in the parameter String, if not it will causes error.
byte[] configLabel = getConfigLabel("Test");
At this line, which is 9 from the end:
configLabel = "^XA^FO17,16^GB379,371,8^FS^FT65,255^A0N,135,134^FDTEST^FS^XZ".getBytes();
you can replace TEST with your variable, e.g:
configLabel = "^XA^FO17,16^GB379,371,8^FS^FT65,255^A0N,135,134^FD" + text + "^FS^XZ".getBytes();
You also need to declare this variable somewhere in the getConfigLabel method or pass it to it.
I suggest changing method signature to getConfigLabel(String text) and modify line 9 from th end. In that case in methond sendTestLabel you can replace
byte[] configLabel = getConfigLabel();
with
String text = "some text...";
byte[] configLabel = getConfigLabel(text);
BTW, this is only the way to print something instead of "TEST". I suggest you use this only for understanding of how it works. If you want to further customize this code, you may need to add another methods, for fine printing

Categories

Resources