I have an app made with android studio that connects to my propitiatory wind gauge that I developed. everything was working perfectly until I submitted it to google. They rejected it saying i need targetSdkVersion 29. when I build it with targetSdkVersion 29 the app no longer scans. But it works when I build it with targetSdkVersion 26
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.windgauge"
android:versionCode="1"
android:versionName="1.0" >
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-feature
android:name="android.hardware.bluetooth_le"
android:required="true" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.windgauge.ScanActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.windgauge.DeviceActivity" android:label="#string/app_name" />
</application>
</manifest>
ScanActivity.java
package com.windgauge;
import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.windgauge.util.BleUtil;
import com.windgauge.util.ScannedDevice;
import java.util.ArrayList;
import permissions.dispatcher.NeedsPermission;
import permissions.dispatcher.RuntimePermissions;
#RuntimePermissions
public class ScanActivity extends AppCompatActivity implements BluetoothAdapter.LeScanCallback {
private BluetoothAdapter mBTAdapter;
private DeviceAdapter mDeviceAdapter;
private boolean mIsScanning;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.activity_scan);
Button scan = findViewById(R.id.scan);
scan.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
ScanActivityPermissionsDispatcher.startScanWithPermissionCheck(ScanActivity.this);
}
});
init();
}
#Override
protected void onDestroy() {
super.onDestroy();
stopScan();
}
#Override
public void onLeScan(final BluetoothDevice newDeivce, final int newRssi,
final byte[] newScanRecord) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mDeviceAdapter.update(newDeivce, newRssi, newScanRecord);
}
});
}
private void init() {
// BLE check
if (!BleUtil.isBLESupported(this)) {
Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
finish();
return;
}
// BT check
BluetoothManager manager = BleUtil.getManager(this);
if (manager != null) {
mBTAdapter = manager.getAdapter();
}
if (mBTAdapter == null) {
Toast.makeText(this, R.string.bt_unavailable, Toast.LENGTH_SHORT).show();
finish();
return;
}
if (!mBTAdapter.isEnabled()) {
Toast.makeText(this, R.string.bt_disabled, Toast.LENGTH_SHORT).show();
finish();
return;
}
// init listview
ListView deviceListView = (ListView) findViewById(R.id.list);
mDeviceAdapter = new DeviceAdapter(this, R.layout.listitem_device,
new ArrayList<ScannedDevice>());
deviceListView.setAdapter(mDeviceAdapter);
deviceListView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterview, View view, int position, long id) {
ScannedDevice item = mDeviceAdapter.getItem(position);
if (item != null) {
Intent intent = new Intent(view.getContext(), DeviceActivity.class);
BluetoothDevice selectedDevice = item.getDevice();
intent.putExtra(DeviceActivity.EXTRA_BLUETOOTH_DEVICE, selectedDevice);
startActivity(intent);
// stop before change Activity
stopScan();
}
}
});
stopScan();
}
#NeedsPermission(Manifest.permission.ACCESS_COARSE_LOCATION)
void startScan() {
if ((mBTAdapter != null) && (!mIsScanning)) {
mBTAdapter.startLeScan(this);
mIsScanning = true;
setProgressBarIndeterminateVisibility(true);
invalidateOptionsMenu();
}
}
private void stopScan() {
if (mBTAdapter != null) {
mBTAdapter.stopLeScan(this);
}
mIsScanning = false;
setProgressBarIndeterminateVisibility(false);
invalidateOptionsMenu();
}
}
Related
This is a read/scan NFC code.
I'm trying it out and I need it to work so that I would write my own code for another read activity.
The app keeps on crashing and the error is always, "There's a bug, please fix it for the app to start."
The source video/code was this link https://www.youtube.com/watch?v=QzphwRdJ7r0
Main Activity
package com.example.nfcreadscan;
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.IntentFilter;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.os.Bundle;
import android.os.Parcelable;
import android.widget.TextView;
import java.util.Arrays;
public class MainActivity extends AppCompatActivity {
private TextView textView;
private IntentFilter[] readfilters;
private PendingIntent pendingintent;
#SuppressLint("UnspecifiedImmutableFlag")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.text);
try {
Intent intent = new Intent (this, getClass());
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
pendingintent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
IntentFilter jdf = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
jdf.addDataScheme("http");
jdf.addDataAuthority("javadude.com", null);
IntentFilter jdt = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED,"text/plain");
readfilters = new IntentFilter[]{jdf, jdt};
} catch (IntentFilter.MalformedMimeTypeException e) {
e.printStackTrace();
}
processNFC(getIntent());
}
private void enableRead(){
NfcAdapter.getDefaultAdapter(this).enableForegroundDispatch(this,pendingintent, readfilters,null);
}
private void disableRead(){
NfcAdapter.getDefaultAdapter(this).disableForegroundDispatch(this);
}
#Override
protected void onResume(){
super.onResume();
enableRead();
}
#Override
protected void onPause(){
super.onPause();
disableRead();
}
#Override
protected void onNewIntent(Intent intent){
super.onNewIntent(intent);
processNFC(intent);
}
private void processNFC(Intent intent){
Parcelable[] messages = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
textView.setText("");
if(messages != null){
for(Parcelable message : messages){
NdefMessage ndefMessage = (NdefMessage) message;
for(NdefRecord record : ndefMessage.getRecords()) {
if (record.getTnf() == NdefRecord.TNF_WELL_KNOWN) {
textView.append("well known: ");
if (Arrays.equals(record.getType(), NdefRecord.RTD_TEXT)) {
textView.append("text: ");
textView.append(new String(record.getPayload()));
textView.append("\n");
} else if (Arrays.equals(record.getType(), NdefRecord.RTD_URI)) {
textView.append("uri");
textView.append(new String(record.getPayload()));
textView.append("\n");
}
}
}
}
}
}
}
Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.nfcreadscan">
<uses-permission android:name="android.permission.NFC"/>
<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/Theme.Nfcreadscan">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="android.intent.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>
I'm new in this Android, and really stuck with it..
Never that was like that - on a start level and already stuck.
When register the Receiver class it returns Intent = null.. means it doesn't know anything about such request (Action, Intent)..
Tested on Nexus Emulator + Samsung device NOTE4.. same result.
Please, help me. What is a tricky thing I do not see yet?
General activity
public class MainActivity extends AppCompatActivity {
EventBroadcaster sms;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent ret;
sms = new EventBroadcaster();
sms.setMainActivity(this);
sms.say("Hello from EventBroadcaster");
IntentFilter filter = new IntentFilter();
filter.addAction("android.provider.Telephony.SMS_RECEIVED");
//filter.addCategory(Intent.CATEGORY_DEFAULT);
ret = registerReceiver(sms, filter);
//******************************************//
if (ret == null) {
sms.say("Fault to activate Broadcaster.. Intent = null");
}
}
public void showToast(String message){
// Show Alert
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(getApplicationContext(), message, duration);
toast.show();
}
}
BroadcastReceiver
public class EventBroadcaster extends BroadcastReceiver {
MainActivity ma;
public void setMainActivity(MainActivity context) {
ma = context;
say("MainActivity reference is received");
}
#Override
public void onReceive(Context context, Intent intent) {
say("Notification received");
}
public void say(String phrase){
ma.showToast(phrase);
}
}
Manifest
<manifest ...>
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<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>
==============================================
So, after Vishnu answered, I think wouldn't be extra to place the working code of the
General Activity
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;
import android.provider.Telephony;
public class MainActivity extends AppCompatActivity {
EventBroadcaster sms;
final int MY_PERMISSIONS_REQUEST_READ_SMS = 100;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sms = new EventBroadcaster();
sms.setMainActivity(this);
sms.say("Hello from EventBroadcaster");
if (VERSION.SDK_INT <= 23) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.RECEIVE_SMS},
MY_PERMISSIONS_REQUEST_READ_SMS);
}
else if (ContextCompat.checkSelfPermission(this,
Manifest.permission.RECEIVE_SMS) != PackageManager.PERMISSION_GRANTED ){
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.RECEIVE_SMS},
MY_PERMISSIONS_REQUEST_READ_SMS);
} else { /*Permission granted*/ }
}
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
Intent ret;
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_READ_SMS: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
IntentFilter filter = new IntentFilter();
filter.addAction("android.provider.Telephony.SMS_RECEIVED");
ret = registerReceiver(sms, filter);
if (ret != null) {
sms.say("Permission to READ SMS granted");
}
} else {
sms.say("Ooops, no permission to READ SMS");
}
return;
}
}
}
public void showToast(String message){
// Show Alert
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(getApplicationContext(), message, duration);
toast.show();
}
}
Apps targeting Android 6.0 and above need to handle the run-time permission.
Refer the Android documentation Requesting Permissions at Run Time
I think, this might be the reason.
try to declare receiver on your manifest
<receiver
android:name="com.example.EventBroadcaster"
android:exported="true" >
<intent-filter android:priority="1000" >
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
I am trying to build Whatsapp Notification filtering app, where I monitor all notification from Whatsapp and remove messages using some filter.
so can some one help me how to catch those notification messages so that I can manipulate them
I knew I have to use accessibility service but I am not able to get any event
all that i get is null source of event also null
https://stackoverflow.com/users/2452075/ghmulchandani
My codes are :- using accessibility service
MainActivity.java
package com.example.pavilion.accessebilityone;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
static TextView tv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView)findViewById(R.id.textView);
Intent intent = new Intent(android.provider.Settings.ACTION_ACCESSIBILITY_SETTINGS);
startActivityForResult(intent, 0);
Intent service = new Intent(this,WhatsappService.class);
startService(service);
}
}
Accessibility service class:-
import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.Notification;
import android.os.Parcelable;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityWindowInfo;
import android.widget.RemoteViews;
import android.widget.TextView;
import android.widget.Toast;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created by pavilion on 6/6/2017.
*/
public class WhatsappService extends AccessibilityService {
protected void onServiceConnected() {
Toast.makeText(this, "connectd", Toast.LENGTH_SHORT).show();
AccessibilityServiceInfo info = new AccessibilityServiceInfo();
info.eventTypes = AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED;
info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
info.notificationTimeout = 100;
setServiceInfo(info);
}
public synchronized void onAccessibilityEvent(AccessibilityEvent event) {
if (event.getEventType() == AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED) {
CharSequence pk = event.getPackageName();
//Toast.makeText(this,cl,Toast.LENGTH_SHORT).show();
Toast.makeText(this, pk, Toast.LENGTH_SHORT).show();
Notification n = (Notification) event.getParcelableData();
if (n == null)
return;
RemoteViews rv = n.contentView;
View view = rv.apply(this, null);
if (view == null)
return;
if (view instanceof ViewGroup) {
ViewGroup group = (ViewGroup) view;
searchTextView(group);
}
}
}
#Override
public void onInterrupt() {
}
private void searchTextView(ViewGroup group) {
int count = group.getChildCount();
for (int i = 0; i < count; i++) {
View v = group.getChildAt(i);
if (v instanceof TextView) {
Toast.makeText(this,((TextView) v).getText(),Toast.LENGTH_SHORT).show();
} else if (v instanceof ViewGroup) {
searchTextView((ViewGroup) v);
}
}
}
}
Manifest file:-
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.pavilion.accessebilityone">
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".WhatsappService"
android:enabled="true"
android:exported="true"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="android.accessibilityservice.AccessibilityService"/>
</intent-filter>
<meta-data android:name="android.accessibilityservice"
android:resource="#xml/accessibilityservice"/>
</service>
</application>
</manifest>
accessibility -service xml
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service
android:accessibilityEventTypes="typeNotificationStateChanged"
android:accessibilityFeedbackType="feedbackGeneric"
android:canRetrieveWindowContent="true"
android:notificationTimeout="100"
android:settingsActivity="com.example.pavilion.accessebilityone.MainActivity"
xmlns:android="http://schemas.android.com/apk/res/android">
</accessibility-service>
You need to extend the notification listener service.
#RequiresApi(api = Build.VERSION_CODES.KITKAT)
public class WhatsappNotifcationListener extends NotificationListenerService {
#Override
public IBinder onBind(Intent intent) {
return super.onBind(intent);
}
#Override
public void onNotificationPosted(StatusBarNotification statusBarNotification) {
String packageName = statusBarNotification.getPackageName();
Bundle extras = statusBarNotification.getNotification().extras;
if (extras.getCharSequence("android.text") == null) {
return;
}
String message = extras.getCharSequence("android.text").toString();
String notificationTitle = extras.getString(Notification.EXTRA_TITLE);
if (notificationTitle == null) {
return;
}
handleNotification(packageName, notificationTitle, message);
}
#Override
public void onNotificationRemoved(StatusBarNotification statusBarNotification) {
super.onNotificationRemoved(statusBarNotification);
}
private void handleNotification(String packageName, String notificationTitle, String message) {
if(!packageName.equalsIgnoreCase("whatsapp packagename"))){
return;
}
//Do something with notification title and notification message
}
}
To prompt the user to give notification access use the following from in an activity:
activity.startActivity(new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"));
Ensure that you include the following in your manifest file within the tag:
<service
android:name=".WhatsappNotifcationListener"
android:enabled="true"
android:label="#string/app_name"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
I have a service which should capture the user's location and current battery level and send it to my firebase backend. For some reason it seems like whenever I have this service enabled in my app, my app will randomly open without any user interaction (even if the user is in another app, my app will pop open). Does anyone have any idea why this is happening?
Here is my code for the service:
import android.app.Service;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.os.BatteryManager;
import android.os.Bundle;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.server.converter.StringToIntConverter;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static android.R.attr.lines;
import static com.package.R.id.location;
import static com.package.R.id.view;
public class LocationBatteryService extends Service implements
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
private String currentUser;
private String city;
private String country;
private float batteryLevel;
private int batteryLevelInt;
protected GoogleApiClient mGoogleApiClient;
protected LocationRequest mLocationRequest;
protected Location mCurrentLocation;
List<Address> addresses;
Geocoder geocoder;
#Override
public void onCreate() {
super.onCreate();
buildGoogleApiClient();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
protected synchronized void buildGoogleApiClient() {
Log.i("TAG", "Building GoogleApiClient");
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
createLocationRequest();
mGoogleApiClient.connect();
}
protected void createLocationRequest() {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
String locationSyncSettings = prefs.getString("location_sync_time", "");
long intervalTime = 5;
if(locationSyncSettings.equals("5 minutes")) {
intervalTime = 5;
}
if (locationSyncSettings.equals("10 minutes")) {
intervalTime = 10;
}
if (locationSyncSettings.equals("15 minutes")) {
intervalTime = 15;
}
if (locationSyncSettings.equals("30 minutes")) {
intervalTime = 30;
}
if (locationSyncSettings.equals("1 hour")) {
intervalTime = 60;
}
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(TimeUnit.MINUTES.toMillis(intervalTime));
mLocationRequest.setFastestInterval(60000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
}
#Override
public void onConnected(Bundle connectionHint) {
Log.i("TAG", "Connected to GoogleApiClient");
try {
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
onLocationChanged(mCurrentLocation);
}
catch (SecurityException e){
Log.d("TAG", "Error: " + e);
}
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d("TAG", "You got destoryed mate");
}
#Override
public void onLocationChanged(Location location) {
updateLocationBackend(mCurrentLocation);
}
#Override
public void onConnectionSuspended(int cause) {
// The connection to Google Play services was lost for some reason. We call connect() to
// attempt to re-establish the connection.
Log.i("TAG", "Connection suspended");
mGoogleApiClient.connect();
}
public void onTaskRemoved (Intent rootIntent){
this.stopSelf();
}
#Override
public void onConnectionFailed(ConnectionResult result) {
// Refer to the javadoc for ConnectionResult to see what error codes might be returned in
// onConnectionFailed.
Log.i("TAG", "Connection failed: ConnectionResult.getErrorCode() = " + result.getErrorCode());
}
public float getBatteryLevel() {
Intent batteryIntent = registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
int level = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
// Error checking that probably isn't needed but I added just in case.
if(level == -1 || scale == -1) {
return 50.0f;
}
return ((float)level / (float)scale) * 100.0f;
}
private void updateLocationBackend(final Location location) {
Log.i("TAG", "Location and battery being updated");
batteryLevel = getBatteryLevel();
batteryLevelInt = Math.round(batteryLevel);
// Get current user
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
currentUser = sharedPrefs.getString("Username", "");
// Get users added by you
DatabaseReference ref = FirebaseDatabase.getInstance().getReferenceFromUrl(Passwords.FB_URL).child("Relations").child(currentUser);
ref.addListenerForSingleValueEvent(
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get user value
for (DataSnapshot ds : dataSnapshot.getChildren()) {
final String contactNumber = ds.getKey();
// Check to see if users added you
final DatabaseReference ref = FirebaseDatabase.getInstance().getReferenceFromUrl(Passwords.FB_URL).child("Contacts").child(contactNumber).child(currentUser);
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (!dataSnapshot.child("name").exists()) {
// User has not added you so do not update location
}
// User has added you so update location
else {
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
boolean contactLocationSetting = sharedPrefs.getBoolean(contactNumber + "_location_pref", true);
Log.d("TAG", "ContactLocationSetting for " + contactNumber + " is equal to: " + contactLocationSetting);
if (location != null && contactLocationSetting == true) {
Map updateLocation = new HashMap();
double latitude = location.getLatitude();
double longitude = location.getLongitude();
geocoder = new Geocoder(getApplicationContext(), Locale.getDefault());
try {
addresses = geocoder.getFromLocation(latitude, longitude, 1); // Here 1 represent max location result to returned, by documents it recommended 1 to 5
} catch (IOException e) {
Log.e("TAG", "error is: " + e);
}
if (addresses.size() == 0) {
// Do nothing
} else {
city = addresses.get(0).getLocality();
country = addresses.get(0).getCountryName();
// String knownName = addresses.get(0).getFeatureName(); // Only if available else return NULL
}
updateLocation.put("battery", batteryLevelInt);
updateLocation.put("latitude", latitude);
updateLocation.put("longitude", longitude);
updateLocation.put("city", city);
updateLocation.put("country", country);
updateLocation.put("lastUpdated", System.currentTimeMillis());
ref.updateChildren(updateLocation);
Log.d("TAG", "Updated location for: " + contactNumber);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w("TAG", "getUser:onCancelled", databaseError.toException());
}
});
}
}
Here is the code where I start the service:
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private Toolbar toolbar;
private TabLayout tabLayout;
public static ViewPager viewPager;
public static ViewPagerAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
String currentUser = sharedPrefs.getString("Username", null);
if (currentUser == null) {
// Take user to log in screen
Log.d("TAG", "user needs to login");
Intent intent = new Intent(this, MyIntro.class);
startActivity(intent);
finish();
}
else {
// User already logged in
setupMainActivity();
}
}
#Override
public void onResume() {
super.onResume();
return;
}
private void setupViewPager(ViewPager viewPager) {
adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFragment(new ChalkboardFragment(), getString(R.string.chalkboard_label));
adapter.addFragment(new ContactsFragment(), getString(R.string.contacts_label));
viewPager.setAdapter(adapter);
}
class ViewPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new ChalkboardFragment();
case 1:
return new ContactsFragment();
}
return null;
}
#Override
public int getCount() {
return mFragmentList.size();
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
public void setupMainActivity() {
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
viewPager = (ViewPager) findViewById(R.id.viewpager);
setupViewPager(viewPager);
tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
boolean locationSetting = prefs.getBoolean("location_pref", false);
Log.d("TAG", "location_pref " + locationSetting);
if (isMyServiceRunning(LocationBatteryService.class) == false && locationSetting == true) {
startService(new Intent(this, LocationBatteryService.class));
}
}
private boolean isMyServiceRunning(Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
}
Application Start:
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;
import com.digits.sdk.android.Digits;
import com.twitter.sdk.android.core.TwitterAuthConfig;
import com.twitter.sdk.android.core.TwitterCore;
import io.fabric.sdk.android.Fabric;
public class ApplicationStart extends Application {
private static Context mContext;
#Override
public void onCreate() {
super.onCreate();
mContext = this.getApplicationContext();
/*if (!FirebaseApp.getApps(this).isEmpty()) {
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
}*/
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
String currentUser = sharedPrefs.getString("Username", null);
if (currentUser == null) {
// Take user to log in screen
Log.d("TAG", "user needs to login");
Intent intent = new Intent(this, MyIntro.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
else {
// User already logged in
Log.d("TAG", "user logged in: " + currentUser);
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
TwitterAuthConfig authConfig = new TwitterAuthConfig(TWITTER_KEY,TWITTER_SECRET);
Fabric.with(this, new TwitterCore(authConfig),new Digits.Builder().build());
}
public static Context getAppContext(){
return mContext;
}
}
Complete manifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.package">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" android:protectionLevel="signature" />
<application android:name=".ApplicationStart" android:allowBackup="false" android:icon="#mipmap/ic_launcher"
android:label="#string/app_name" android:supportsRtl="true" android:theme="#style/AppTheme">
<activity android:name=".MainActivity" android:label="#string/app_name" android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".LoginActivity" android:label="#string/title_activity_login"
android:parentActivityName=".MainActivity" />
<activity android:name=".ContactsSettingsActivity" android:label="Contact Settings"
android:launchMode="singleTop">
<meta-data android:name="android.support.PARENT_ACTIVITY" android:value="com.package.ContactsChalkboard" />
</activity>
<activity android:name=".MyIntro" />
<activity android:name=".ContactsChalkboard" />
<activity android:name=".AlarmActivity" />
<activity android:name=".AddContactActivity" android:parentActivityName=".MainActivity">
<meta-data android:name="android.support.PARENT_ACTIVITY" android:value="com.package.MainActivity" />
</activity>
<activity android:name=".PictureNameActivity" android:label="#string/title_activity_picture_name"
android:parentActivityName=".LoginActivity">
<meta-data android:name="android.support.PARENT_ACTIVITY" android:value="com.package.LoginActivity" />
</activity>
<activity android:name=".Test" />
<activity android:name=".SettingsActivity" android:label="Settings">
<meta-data android:name="android.support.PARENT_ACTIVITY" android:value="com.package.MainActivity" />
</activity>
<activity android:name="com.package.GeofenceActivity" android:label="#string/title_activity_geofence">
</activity>
<service android:name=".LocationBatteryService" android:enabled="true" android:exported="true" />
<service android:name=".MyFirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<service android:name=".MyFirebaseInstanceIDService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
<service android:name=".GeofenceTransitionsIntentService" />
<receiver android:name=".AlarmReceiver" android:enabled="true" android:exported="true" />
<receiver android:name=".BootReceiver" android:enabled="true" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<meta-data android:name="com.google.android.geo.API_KEY" android:value="API KEY VALUE" />
<meta-data android:name="io.fabric.ApiKey" android:value="API KEY VALUE" />
</application>
</manifest>
Well, there is no guarantee that the system keeps running your service all the time. When the application is killed, and a new location has to be delivered the play services lib will instantiate the application and start your service. You have to remove startActivity from your application class.
I'm just trying to create a dummy app for speech recognition on clicking a button (with no pop-ups or anything).
My Android manifest file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="billobob.org.speechtest">
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
And the fragment housing what's actually going on:
package myandroid.org.speechtest;
import android.content.Intent;
import android.os.Bundle;
import android.speech.RecognitionListener;
import android.speech.RecognizerIntent;
import android.speech.SpeechRecognizer;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import java.util.ArrayList;
/**
* Simple app for recognizing speech
*/
public class MainActivityFragment extends Fragment {
protected static final int RESULT_SPEECH = 1234;
private TextView mSpeechTextView1;
private TextView mSpeechTextView2;
private Button mSpeechButton;
private String speechString;
private SpeechRecognizer mSpeechRecognizer;
private Intent mSpeechRecognizerIntent;
boolean mIsListening = false;
public MainActivityFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, container, false);
mSpeechTextView1 = (TextView) view.findViewById(R.id.textView1);
mSpeechTextView2 = (TextView) view.findViewById(R.id.textView2);
mSpeechButton = (Button) view.findViewById(R.id.speechButton);
mSpeechRecognizer = SpeechRecognizer.createSpeechRecognizer(this.getContext());
mSpeechRecognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
mSpeechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
mSpeechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, this.getActivity().getPackageName());
SpeechRecognitionListener listener = new SpeechRecognitionListener();
mSpeechRecognizer.setRecognitionListener(listener);
mSpeechButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!mIsListening)
{
Log.d("UUXX", "clicked");
mIsListening = true;
mSpeechRecognizer.startListening(mSpeechRecognizerIntent);
}
}
});
return view;
}
#Override
public void onDestroyView() {
if (mSpeechRecognizer != null)
{
mSpeechRecognizer.stopListening();
mSpeechRecognizer.cancel();
mSpeechRecognizer.destroy();
}
super.onDestroyView();
}
protected class SpeechRecognitionListener implements RecognitionListener {
#Override
public void onReadyForSpeech(Bundle params) {
Log.d("UUSP", "in read");
}
#Override
public void onBeginningOfSpeech() {
Log.d("UUSP", "begin!");
}
#Override
public void onRmsChanged(float rmsdB) {
}
#Override
public void onBufferReceived(byte[] buffer) {
}
#Override
public void onEndOfSpeech() {
Log.d("UUSP", "end");
}
#Override
public void onError(int error) {
}
#Override
public void onResults(Bundle results) {
ArrayList<String> matches = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
Log.d("UUSP", matches != null ? matches.get(0) : null);
mIsListening = false;
mSpeechTextView1.setText(matches.get(0));
}
#Override
public void onPartialResults(Bundle partialResults) {
Log.d("UUSP", "partial...");
}
#Override
public void onEvent(int eventType, Bundle params) {
Log.d("UUSP", "event?");
}
}
}
The button registers the click, but nothing else happens. I noticed in the non-application log that the error:
05-20 20:56:32.022 18200-19108/? E/RecognitionService: call for recognition service without RECORD_AUDIO permissions
Always occurs, despite the fact that I ostensibly have permissions set in the manifest. I'm testing it on a 6P with Android Studio 2.1. Any help would be much appreciated!
For API 23+ (Android 6.0) it is not enough to just add permissions to the manifest. You need to request permissions at run time.
See the developer documents for more information:
https://developer.android.com/guide/topics/security/permissions.html#normal-dangerous
https://developer.android.com/training/permissions/requesting.html
You can verify this is the issue by changing your gradle targetSdkVersion back to 21. It will then use the old permission model on devices running API 23+
Add this code snippet at the instant where you want to access the audio recording feature.
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, 1);
This is asking for a run time permission to access the feature of recording audio. You can add any number of permissions in that array.
Add this in you manifest file:
<uses-permission android:name="android.permission.RECORD_AUDIO" />