I am currently working on an app in which one of the tasks is to catch the notifications of different applications (phone call, Facebook, Twitter, Whatsapp etc...). Now I will have some values pre-defined for all the pre-defined applications. Values will be of type string denoting R,G,B color values. I would have to send these color values via Bluetooth to another device. For this I have created an accessibility service.
Here is my main activity:
Main Activity displays a listview with applications name declared in the currentlyEnabled
HashMap
. The newFinalPackages
HashMap
stores the application names for all the pre defined applications. The apptoRBG
HashMap
stores these application names with user-given RGB values.
public class MainActivity extends AppCompatActivity {
private Intent mailAccessabilityIntent;
private ListView actioList;
private ActionCustomAdapter adapter;
private static final String DEFAULT_COLOR = "R:255,G:255,B:255";
private static HashMap<String, String> newfinalpackages = new HashMap<String, String>();
private static HashMap<String, String> newappToRGB = new HashMap<String, String>();
static {
newfinalpackages.put("dialer", "Calls");
newfinalpackages.put("whatsapp", "WhatsApp");
newfinalpackages.put("facebook.katana", "Facebook");
newfinalpackages.put("twitter", "Twitter");
newfinalpackages.put("instagram", "Instagram");
newfinalpackages.put("gmail", "GMail");
newfinalpackages.put("batterylow", "Low Battery");
newfinalpackages.put("messenger", "Text Message");
newappToRGB.put("dialer", DEFAULT_COLOR);
newappToRGB.put("whatsapp", DEFAULT_COLOR);
newappToRGB.put("facebook", DEFAULT_COLOR);
newappToRGB.put("twitter", DEFAULT_COLOR);
newappToRGB.put("instagram", DEFAULT_COLOR);
newappToRGB.put("gmail", null);
newappToRGB.put("batterylow", null);
newappToRGB.put("messenger", null);
}
private static HashMap<String, String> currentlyEnabled = new HashMap<String, String>();
private HashMap<String, String> currentlyDisabled = new HashMap<String, String>();
public static HashMap<String, String> getCurrentlyEnabled() {
return currentlyEnabled;
}
public static HashMap<String, String> getAppToRGB() {
return newappToRGB;
}
private void DrawSelected() {
currentlyEnabled.put("dialer", "Calls");
currentlyEnabled.put("whatsapp", "WhatsApp");
currentlyEnabled.put("facebook", "Facebook");
currentlyEnabled.put("twitter", "Twitter");
currentlyEnabled.put("instagram", "Instagram");
currentlyDisabled.put("gmail", "GMail");
currentlyDisabled.put("batterylow", "Low Battery");
currentlyDisabled.put("messenger", "Text Message");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent mailAccess = new Intent(MainActivity.this, InstantMessanger.class);
startService(mailAccess);
DrawSelected();
serviceSwitch = (Switch) findViewById(R.id.serviceSwitch); //DIDN'T ADD FUNCTIONALITY YET.
actioList = (ListView) findViewById(R.id.actionList);
// Button to add applications from currentlyDisabled to CurrentlyEnabled
// Not Important here.
actioList.addFooterView(addEvent);
adapter = new ActionCustomAdapter(this, currentlyEnabled);
actioList.setAdapter(adapter);
// Just to choose the color value.Nothing Else.
actioList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
String Item = ((HashMap.Entry<String, String>) adapterView.getItemAtPosition(i)).getKey();
showColorPickerDialogDemo(Item);
}
});
}
// IGNORE THIS.
private void showColorPickerDialogDemo(final String key) {
int initialColor = Color.WHITE;
ColorPickerDialog colorPickerDialog = new ColorPickerDialog(this, initialColor, new ColorPickerDialog.OnColorSelectedListener() {
@Override
public void onColorSelected(int color) {
showToast(color);
appToRGB.put(key, "R: " + Color.red(color) + " B: " + Color.blue(color) + " G: " + Color.green(color));
InstantMessanger.addEnabledActions(key, "R: " + Color.red(color) + " B: " + Color.blue(color) + " G: " + Color.green(color));
}
});
colorPickerDialog.show();
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
showColorPickerDemo()
is for color selection.
My service class is:
When created, the enabledAction
HashMap
from MainActivity
is passed to this class using static methods.
The service class basically catches any notification posted on an Android device by any application with the listener OnAccessibility
event. Then it is extracting the actual application name from the package name in the parsePackage()
method. Then it checks if this application name is in enabledActions
. If yes, it sends the data through Bluetooth (which still needs to be implemented).
public class InstantMessanger extends AccessibilityService {
private TextView text;
private String packagename;
private String selfname = "com.example.sgoel01.checkingevents",download = "com.android.providers.downloads";
Context context = this;
private static HashMap<String,String> enabledActions = new HashMap<String, String>();
public static void addEnabledActions(String key, String value) {
enabledActions.put(key, value);
}
@Override
public void onCreate() {
Toast.makeText(this, "Service is Started for the first time", Toast.LENGTH_LONG).show();
enabledActions = MainActivity.getAppToRGB();
for(HashMap.Entry<String,String> entry : enabledActions.entrySet()) {
Log.d("enabledAct", entry.getKey() + " is equal to " + entry.getValue());
}
Toast.makeText(this, enabledActions.get("whatsapp"), Toast.LENGTH_SHORT).show();
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "Service is Started on startcommand", Toast.LENGTH_LONG).show();
enabledActions = MainActivity.getAppToRGB();
return Service.START_STICKY;
}
public void onAccessibilityEvent(AccessibilityEvent event) {
//Toast.makeText(this,"Event Catched", Toast.LENGTH_LONG).show();
if(event.getEventType() == AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED) {
packagename = String.valueOf(event.getPackageName());
Log.d("pack/call", packagename);
parsePackage(packagename);
if(packagename.equals(selfname)==false && packagename.equals("com.android.providers.downloads")==false) {
Toast.makeText(this, "Package: "+packagename,Toast.LENGTH_LONG).show();
}
if(enabledActions.get(packagename) != null) {
Toast.makeText(this, "This is Working Now " + packagename , Toast.LENGTH_LONG).show();
}
}
}
private void parsePackage (String pack) {
String name = pack.substring(pack.indexOf(".")+1,pack.length());
char[] array = pack.toCharArray();
int prev=0;
for(int i=0,n=pack.length() ; i<n ; i++) {
String temp="";
if(i==n-1) {
temp = pack.substring(prev,i+1);
Log.d("seetothis", "Name: " + temp +" has value= " + enabledActions.get(temp) );
}
else if(pack.charAt(i) == '.') {
temp = pack.substring(prev,i);
prev = i+1;
Log.d("seetothis", "Name: " + temp +" has value= " + enabledActions.get(temp) );
}
if(enabledActions.get(temp) != null) {
Log.d("printout", "Package grabbed is: "+temp+" With Value: "+enabledActions.get(temp));
}
}
}
@Override
public void onInterrupt() {
}
public static String gettheColor() {
return enabledActions.get("dialer");
}
@Override
public void onDestroy() {
Toast.makeText(this, "hUA Nhi ",Toast.LENGTH_SHORT).show();
super.onDestroy();
}
@Override
protected void onServiceConnected() {
AccessibilityServiceInfo info = new AccessibilityServiceInfo();
info.feedbackType = 1;
info.eventTypes = AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED;
info.notificationTimeout = 100;
setServiceInfo(info);
}
}
Here is my custom adapter for listview on main activity. This is taking the HashMap
s and simply displaying in listview.
public class ActionCustomAdapter extends BaseAdapter {
private Activity activity;
private ArrayList mData;
private static LayoutInflater inflater=null;
public ActionCustomAdapter(Activity a, HashMap<String,String> d) {
activity = a;
mData = new ArrayList();
mData.addAll(d.entrySet());
inflater = (LayoutInflater)activity.
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public int getCount() {
return mData.size();
}
@Override
public HashMap.Entry<String, String> getItem(int position) {
return (HashMap.Entry) mData.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
View vi=convertView;
if(convertView==null)
vi = inflater.inflate(R.layout.list_item_notification, null);
HashMap.Entry<String, String> item = getItem(position);
TextView text=(TextView)vi.findViewById(R.id.textAction);;
ImageView image=(ImageView)vi.findViewById(R.id.imageAction);
text.setText(item.getValue());
return vi;
}
}
Am I declaring too many static methods and variables? Am I passing too much data between the activities?
Also, my service intend to run in the background, so do I need a different set of variables (corresponding string values for different applications) for it always, or can I just extract them from another activity whenever required? Or there is some better way?
1 Answer 1
if(packagename.equals(selfname)==false && packagename.equals("com.android.providers.downloads")==false) {
Toast.makeText(this, "Package: "+packagename,Toast.LENGTH_LONG).show();
}
You can use this check instead:
!packagename.equals(selfname) && !packagename.equals("com.android.providers.downloads")
Explicit equality checks with false
seem out of place.
private void parsePackage (String pack) {
String name = pack.substring(pack.indexOf(".")+1,pack.length());
char[] array = pack.toCharArray();
int prev=0;
for(int i=0,n=pack.length() ; i<n ; i++) {
String temp="";
if(i==n-1) {
temp = pack.substring(prev,i+1);
Log.d("seetothis", "Name: " + temp +" has value= " + enabledActions.get(temp) );
}
else if(pack.charAt(i) == '.') {
temp = pack.substring(prev,i);
prev = i+1;
Log.d("seetothis", "Name: " + temp +" has value= " + enabledActions.get(temp) );
}
if(enabledActions.get(temp) != null) {
Log.d("printout", "Package grabbed is: "+temp+" With Value: "+enabledActions.get(temp));
}
}
}
Rather than using a complex loop here, you could make use of String.split
, then iterate over the String array afterwards. As String.split
takes a regex, you'll want to escape the delimiter:
(Escape method taken from How can I use "." as the delimiter with String.split() in java)
String[] packageNames = pack.split(Pattern.quote("."));
-
\$\begingroup\$ Thanks for your answer very much. Also I want to ask if there can be any improvement to the object oriented aspect of the program. \$\endgroup\$sgoel– sgoel2016年07月29日 14:29:47 +00:00Commented Jul 29, 2016 at 14:29
-
\$\begingroup\$ Anymore comments sir ? \$\endgroup\$sgoel– sgoel2016年07月31日 01:45:04 +00:00Commented Jul 31, 2016 at 1:45
-
\$\begingroup\$ @user3800101 sorry, I'm not familiar with Android's recommended way to split up classes. If you had a object hierarchy separate from android then I could help but I haven't programmed a whole lot of Android before... so I just reviewed it based on the fact you can use regular Java for android \$\endgroup\$Pimgd– Pimgd2016年07月31日 09:28:47 +00:00Commented Jul 31, 2016 at 9:28