Android: Does Custom View have startService - android

I am having a Custom View which uploading image to the server when clicked.
I get the context using getContext and use it to call start the intent service. Somehow the service didn't get started when I make a checkpoint at the onHandleIntent or onStartCommand. I have placed a reference in the manifest.
This is the code call to service in which the code was inside the Custom View which extending the ImageView:
new GraphicUtilitiesV2.SimpleImageLoadingCallback() {
#Override
public void imageAvailable(Object sender, String data) {
if (_formCOC != null && _formType != null) {
Gson gson = new Gson();
String formCOC = gson.toJson(_formCOC);
UploadAttachmentService.startActionAttachmentDeclarative
(getContext(), formCOC, _formType.getValue(), data);
}
}
});
This is my demo code of the AttachmentUploadService class :
private static final String ACTION_DECLARATIVE = "blah.Service.action.DeclarativeAttachment";
private static final String EXTRA_FORM = "blah.CERTIFI.Service.extra.Form";
private static final String EXTRA_TYPE = "blah.Service.extra.FormType";
private static final String EXTRA_DATA = "blah.Service.extra.Data";
public static void startActionAttachmentDeclarative(Context context, String form, String type, String data) {
Intent intent = new Intent(context, UploadAttachmentService.class);
intent.setAction(ACTION_DECLARATIVE);
intent.putExtra(EXTRA_FORM, form);
intent.putExtra(EXTRA_TYPE, type);
intent.putExtra(EXTRA_DATA, data);
context.startService(intent);
}
public UploadAttachmentService() {
super("UploadService");
}
#Override
protected void onHandleIntent(Intent intent) {
if (intent != null) {
final String action = intent.getAction();
if (ACTION_DECLARATIVE.equals(action)) {
final String param1 = intent.getStringExtra(EXTRA_FORM);
final String param2 = intent.getStringExtra(EXTRA_DATA);
handleActionAttachmentDeclarative(param1, param2);
}
}
}
public void handleActionAttachmentDeclarative(String form, String data) {
try {
Thread.sleep(50000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
There are no error or force close as well.
This is my manifest part:
<service
android:name=".Service.UploadAttachmentService"
android:exported="false" >
</service>
The UploadAttachmentService file was stored in a Service folder.

Related

I want to save data in SecondActivity from FirstActivity using Room

I have three activities, I capture all data but one from DetailActivity upon button click and save in database using Room; My intention is to insert all these data into the database and start ReviewActivity so as to get the arraylist of reviews and also insert it in the database. Everything seems to work fine until when I want to view review offline because I believe it has been saved, reviews does not get loaded.
This is my DetailActivity,
TextView overview_tv; ImageView image_tv; TextView name_tv; TextView ratings; Context context; TextView release_date; ImageView backdrop_poster; private ExpandableHeightListView trailers; public static ArrayList<Youtube> youtube; public static ArrayList<Review> reviews; TrailerViewAdapter adapter; public static DataObject data; DataObject dataObject; ArrayList<Review> savedReview; private static final String IMAGE_URL = "http://image.tmdb.org/t/p/w185/"; private static final String THE_MOVIEDB_URL2 = "https://api.themoviedb.org/3/movie/"; private static final String MOVIE_QUERY2 = "api_key"; private static final String API_KEY2 = "6cc4f47bd4a64e0117e157b79072ae37"; private static String SEARCH_QUERY2 = "videos"; public static int movieId; Button viewReviews; Button favourite; String movieRating; private static final int YOUTUBE_SEARCH_LOADER = 23; private static final int REVIEW_SEARCH_LOADER = 24; File file; String name; String overview; String releaseDate; int switcher; public static ArrayList<Review> favouriteReviews; TextView trev; AppDatabase mDb; //Navigation arrow on the action bar #Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == android.R.id.home) { NavUtils.navigateUpFromSameTask(this); } return super.onOptionsItemSelected(item); } #Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_detail); mDb = AppDatabase.getInstance(getApplicationContext()); youtube = new ArrayList<Youtube>(); reviews = new ArrayList<Review>(); adapter = new TrailerViewAdapter(this, youtube); //Credit to Paolorotolo #github trailers = findViewById(R.id.expandable_list); trailers.setAdapter(adapter); trailers.setExpanded(true); //Navigation arrow on the acton bar; check also override onOptionsItemSelected ActionBar actionBar = this.getSupportActionBar(); if (actionBar != null) { actionBar.setDisplayHomeAsUpEnabled(true); } context = getApplicationContext(); Intent intent = getIntent(); if (intent == null) { closeOnError(); } switcher = getIntent().getIntExtra("switch", 3); overview_tv = findViewById(R.id.overview); image_tv = findViewById(R.id.image); name_tv = findViewById(R.id.name); ratings = findViewById(R.id.ratings); release_date = findViewById(R.id.release_date); backdrop_poster = findViewById(R.id.backdrop_poster); trev = findViewById(R.id.review_show); viewReviews = findViewById(R.id.review_button); favourite = findViewById(R.id.favourite_button); addListenerOnRatingBar(ratings); if (switcher != 2) { favourite.setVisibility(View.INVISIBLE); dataObject = (DataObject) getIntent().getParcelableExtra("array"); final String favouriteName = dataObject.getName(); final String favouriteOverview = dataObject.getOverview(); final String favouriteReleaseDate = dataObject.getReleaseDate(); ArrayList<Youtube> savedTrailer = dataObject.getTrailers(); savedReview = dataObject.getMovieReviews(); movieRating = dataObject.getRating(); name_tv.setText(favouriteName); overview_tv.setText(favouriteOverview); ratings.setText("Rating: " + movieRating); release_date.setText("Release Date: " + favouriteReleaseDate);// Toast.makeText(this, "Testing Reviews " + savedReview.get(0).getAuthor(), Toast.LENGTH_SHORT).show(); String imagePath = name_tv.getText().toString() + "0i"; String backdropPath = name_tv.getText().toString() + "1b"; try { DataObjectAdapter.downloadImage(imagePath, image_tv, this); } catch (Exception e) { e.printStackTrace(); } try { DataObjectAdapter.downloadImage(backdropPath, backdrop_poster, context); } catch (Exception e) { e.printStackTrace(); } if (savedTrailer != null) { TrailerViewAdapter lv = new TrailerViewAdapter(DetailActivity.this, savedTrailer); trailers.setAdapter(lv); switcher = 3; } } else { name = getIntent().getStringExtra("Name"); overview = getIntent().getStringExtra("Overview"); final String image = getIntent().getStringExtra("Image"); movieId = getIntent().getIntExtra("movieId", 1); final String backdrop = getIntent().getStringExtra("backdrop"); releaseDate = getIntent().getStringExtra("releaseDate"); movieRating = getIntent().getStringExtra("rating"); Log.i("this", "switch " + switcher); name_tv.setText(name); overview_tv.setText(overview); ratings.setText("Rating: " + movieRating); release_date.setText("Release Date: " + releaseDate); //load backdrop poster Picasso.with(context) .load(IMAGE_URL + backdrop) .fit() .placeholder(R.drawable.placeholder_image) .error(R.drawable.placeholder_image) .into(backdrop_poster); Picasso.with(context) .load(IMAGE_URL + image) .fit() .placeholder(R.drawable.placeholder_image) .error(R.drawable.placeholder_image) .into(image_tv); getSupportLoaderManager().initLoader(YOUTUBE_SEARCH_LOADER, null, this); //getSupportLoaderManager().initLoader(REVIEW_SEARCH_LOADER, null, this); //loadTrailers(); //loadReviews(); //populateKeys(); } /** * Here manages the views(list) for reviews */ viewReviews.setOnClickListener(new View.OnClickListener() { #Override public void onClick(View v) { if (switcher == 3) { startActivity(new Intent(DetailActivity.this, ReviewActivity.class) .putExtra("switch", 3)); } else { Log.i("this", "I am from initial" + switcher); startActivity(new Intent(DetailActivity.this, ReviewActivity.class).putExtra("id", movieId)); } } } ); favourite.setOnClickListener(new View.OnClickListener() { #Override public void onClick(View v) { data = new DataObject(); data.setName(name); data.setOverview(overview); data.setRating(movieRating); data.setReleaseDate(releaseDate); data.setTrailers(youtube);// data.setMovieReviews(reviews); try { saveImage(name_tv.getText().toString() + "0i", image_tv); saveImage(name_tv.getText().toString() + "1b", backdrop_poster); } catch (IOException e) { e.printStackTrace(); } Toast.makeText(context, "The movie is saved as a favourite", Toast.LENGTH_LONG).show(); AppExecutors.getInstance().diskIO().execute(new Runnable() { #Override public void run() { mDb.dataDao().insertData(data); } }); startActivity(new Intent(DetailActivity.this, ReviewActivity.class).putExtra("id", movieId) .putExtra(ReviewActivity.EXTRA_DATA_ID, 20)); } } ); }
And my ReviewActivity
public class ReviewActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<ArrayList<Review>>{ public static ArrayList<Review> reviews; public static List<DataObject> favouriteReviews; public static RecyclerView reviewList; ArrayList<Review> r; private static final int REVIEW_SEARCH_LOADER = 24; private static final String MOVIE_QUERY3 = "api_key"; private static final String API_KEY3 = "6cc4f47bd4a64e0117e157b79072ae37"; private static String SEARCH_QUERY3 = "reviews"; private static final String THE_MOVIEDB_URL3 = "https://api.themoviedb.org/3/movie/"; private static int movId; public static final String EXTRA_DATA_ID = "extraDataId"; private static final int DEFAULT_TASK_ID = -1; private int mTaskId = DEFAULT_TASK_ID; DataObject data1; AppDatabase mDb; ReviewAdapter revAdapter; int loaderSwitch; #Override protected void onResume() { super.onResume(); } #Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_review); mDb = AppDatabase.getInstance(getApplicationContext()); reviews = new ArrayList<Review>(); favouriteReviews = new ArrayList<DataObject>(); reviewList = findViewById(R.id.review_list); LinearLayoutManager layoutManager = new LinearLayoutManager(getApplicationContext()); reviewList.setLayoutManager(layoutManager); reviewList.setHasFixedSize(true); int switcher = getIntent().getIntExtra("switch", 1); Intent intent = getIntent(); if (intent == null) { finish(); } Log.i("this", "swithcer " + switcher); Log.i("this loader", "Loader " + loaderSwitch); if (switcher == 3){ DataObject dataObject = (DataObject) getIntent().getParcelableExtra("ArrayOfReviews"); if (dataObject != null){ ArrayList<Review> movieReviews = dataObject.getMovieReviews(); Toast.makeText(this, "There are reviews saved", Toast.LENGTH_LONG).show(); revAdapter = new ReviewAdapter(this, movieReviews ); reviewList.setAdapter(revAdapter); } } else { movId = getIntent().getIntExtra("id", 20); revAdapter = new ReviewAdapter(this, reviews); reviewList.setAdapter(revAdapter); loadReviews(); //populateReview(); } DividerItemDecoration decoration = new DividerItemDecoration(this, VERTICAL); reviewList.addItemDecoration(decoration); } #Override protected void onStart() { super.onStart(); //loadReviews(); } public static URL buildUrl3(String stringUrl) { Uri uri = Uri.parse(THE_MOVIEDB_URL3).buildUpon() .appendPath(stringUrl) .appendPath(SEARCH_QUERY3) .appendQueryParameter(MOVIE_QUERY3, API_KEY3) .build(); URL url = null; try { url = new URL(uri.toString()); } catch (MalformedURLException exception) { Log.e(TAG, "Error creating URL", exception); } return url; } public void loadReviews(){ // COMPLETED (19) Create a bundle called queryBundle Bundle queryBundle = new Bundle(); // COMPLETED (20) Use putString with SEARCH_QUERY_URL_EXTRA as the key and the String value of the URL as the value// queryBundle.putString(SEARCH_QUERY_URL_EXTRA, url.toString()); // COMPLETED (21) Call getSupportLoaderManager and store it in a LoaderManager variable LoaderManager loaderManager = getSupportLoaderManager(); // COMPLETED (22) Get our Loader by calling getLoader and passing the ID we specified Loader<ArrayList<Review>> movieReviews = loaderManager.getLoader(REVIEW_SEARCH_LOADER); // COMPLETED (23) If the Loader was null, initialize it. Else, restart it. if (movieReviews == null) { loaderManager.initLoader(REVIEW_SEARCH_LOADER, queryBundle, this); } else { loaderManager.restartLoader(REVIEW_SEARCH_LOADER, queryBundle, this); } } #Override public Loader<ArrayList<Review>> onCreateLoader(int id, Bundle args) { return new AsyncTaskLoader<ArrayList<Review>>(this) { #Override protected void onStartLoading() { super.onStartLoading(); forceLoad(); } #Override public ArrayList<Review> loadInBackground() { String g = String.valueOf(movId); // Create URL object URL url = buildUrl3(g); // Perform HTTP request on the URL and receive a JSON response back String jsonResponse = ""; try { jsonResponse = getResponseFromHttpUrl(url); } catch (Exception e) { e.printStackTrace(); } reviews = MovieJsonUtils.parseReview(jsonResponse); return reviews; } }; } #Override public void onLoadFinished(Loader<ArrayList<Review>> loader, ArrayList<Review> dat) { if (reviews != null) { Intent intent = getIntent(); if (intent != null && intent.hasExtra(EXTRA_DATA_ID)) { //mButton.setText(R.string.update_button); if (mTaskId == DEFAULT_TASK_ID) { mTaskId = intent.getIntExtra(EXTRA_DATA_ID, DEFAULT_TASK_ID); AppExecutors.getInstance().diskIO().execute(new Runnable() { #Override public void run() { data.setMovieReviews(reviews); mDb.dataDao().updateData(data); //mDb.dataDao().insertData(data); final List<DataObject> task = mDb.dataDao().loadById(mTaskId); runOnUiThread(new Runnable() { #Override public void run() { populateUI(task); } }); } }); } } else { ReviewAdapter lv = new ReviewAdapter(ReviewActivity.this, reviews); reviewList.setAdapter(lv); } } } #Override public void onLoaderReset(Loader<ArrayList<Review>> loader) { }
Data gets loaded from MainActivity, the saved data is passed on to other activities as a parcellable bundle via intent, the passed data is displayed in DetailActivity but not in ReviewActivity.
Alternatively, if I can load reviews alongside YouTube keys from DetailActivity, I believe I can handle the database issue from there, but two Loaders wouldn't just work together, the app crashes; I am aware two AsyncTasks concurrently run together solved this problem, but I prefer to use Loaders because of performance on configuration change

Service and interface

In my project i user Firebase Database. With it i read data frmo db the following way:
public void getSoftwareRecords() {
final List<Software> softwareList = new ArrayList<>();
databaseReference = firebaseDatabase.getReference("software");
getSoftwareRecordsListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
softwareList.add(snapshot.getValue(Software.class));
}
Log.d(TAG, "Software from server count: " + softwareList.size());
onSoftwareTransactionListener.onSuccessSyncListOfSoftware(softwareList);
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.e(TAG, "Cant read software list from database: " + databaseError.getDetails());
// TODO describe error #102 for documentation
onSoftwareTransactionListener.onFailureSyncListOfSoftware("Ohh.");
}
};
databaseReference.addValueEventListener(getSoftwareRecordsListener);
After, this method i want to call in IntentService. As u notice, there is no return value = void. So, the question is how i can user service and interface together?
Service (as i wanted to use it):
public class ReadSoftwareListService extends IntentService implements Database.OnSoftwareTransactionListener {
private static final String TAG = ReadSoftwareListService.class.getSimpleName();
public static final String ACTION = "...";
public static final String RESULT_CODE = "RESULT_CODE";
public static final String RESULT_VALUE = "RESULT_VALUE";
private Intent in;
public ReadSoftwareListService() {
super("ReadSoftwareListService");
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
protected void onHandleIntent(Intent intent) {
in = new Intent(ACTION);
Log.d(TAG, "ReadSoftwareListService:: onHandleIntent");
Database database = new Database(com.google.firebase.database.FirebaseDatabase.getInstance());
database.getSoftwareRecords(); // <- this is a method from code above.
}
#Override
public void onSuccessSyncListOfSoftware(List<Software> softwareList) {
Log.d(TAG, "ReadSoftwareListService:: onSuccessSyncListOfSoftware");
Bundle bundle = new Bundle();
bundle.putInt(RESULT_CODE, Activity.RESULT_OK);
in.putExtras(bundle);
// bundle.putSerializable(RESULT_VALUE, softwareList);
LocalBroadcastManager.getInstance(this).sendBroadcast(in);
}
#Override
public void onFailureSyncListOfSoftware(String message) {
Log.d(TAG, "ReadSoftwareListService:: onFailureSyncListOfSoftware");
Bundle bundle = new Bundle();
bundle.putInt(RESULT_CODE, Activity.RESULT_CANCELED);
bundle.putString(RESULT_VALUE, message);
in.putExtras(bundle);
LocalBroadcastManager.getInstance(this).sendBroadcast(in);
}
And reciever:
public final BroadcastReceiver softwareListReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "softwareListReceiver:: onReceive");
Bundle bundle = intent.getExtras();
int resultCode = bundle.getInt(RESULT_CODE);
if (resultCode == Activity.RESULT_OK) {
Log.d(TAG, "RESULT CODE == OK");
// softwareListAdapter.updateData(bundle.getParcelableArrayList(RESULT_VALUE));
} else {
Log.d(TAG, "RESULT CODE == CANCEL: " + bundle.getString(RESULT_VALUE));
}
}
};
If you really wanted to use IntentService here, you can go add ResultReceiver as a callback. Example:-
Intent intentService = new Intent(context, YourIntentService.class);
intentService.putExtra(StockService.REQUEST_RECEIVER_EXTRA, new ResultReceiver(null) {
#Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
if (resultCode == StockService.RESULT_ID_QUOTE) {
...
}
}
});
startService(intentService);
Alternatively you can use Custom AsyncTask by passing interface as one of parameters.
Hope this helps.
Note: Vote up if you like this.

Unable to run a service via the react native bridge

I have created a native module in Java which is responsible for running a service in background.
I have this method in ClassA:
#ReactMethod
public void startService(final Promise promise) {
Intent intent = new Intent(getCurrentActivity(), BackgroundService.class);
intent.putExtra(BackgroundService.FILENAME, "test123.html");
intent.putExtra(BackgroundService.URL,
"http://www.vogella.com/index.html");
Activity currentActivity = getCurrentActivity();
if (currentActivity == null) {
promise.reject("Activity doesnt exist");
} else {
getCurrentActivity().startService(intent);
}
}
Here is the code in BackgroundService:
public class BackgroundService extends IntentService {
private int result = Activity.RESULT_CANCELED;
public static final String URL = "urlpath";
public static final String FILENAME = "filename";
public static final String FILEPATH = "filepath";
public static final String RESULT = "result";
public static final String NOTIFICATION = "com.vogella.android.service.receiver";
public BackgroundService() {
super("BackgroundService");
}
public String getName() {
return "BackgroundService";
}
#Override
protected void onHandleIntent(Intent intent) {
//do stuff
ClassA.servicePromise.resolve("done with service!");
}
servicePromise is defined in classA as so :
public static Promise servicePromise = null;
The problem, if I am understanding it correctly, is that getCurrentActivity.startService(intent) does not execute properly. I am able to successfully return a promise inside startService after getCurrentActivity.startService(intent), so I know the problem is not with how I am calling startService. However, I am unable to return the promise from inside BackgroundService, which is what I want.
Inside the onHandleIntent, I tried calling ClassA.servicePromise.resolve("done with service!"); before executing any other code just to test if it works, but it doesn't.
In my manifest, I have added the service as follows:
<service android:name="com.smaplePakcage.name.BackgroundService"
android:exported="false">
</service>

Is possible to initiate an Intent Service from Thread?

I'm trying to implementing a parallel download using a Thread, but all my unzip process should be sequentially. As is known Intent Service enqueue all pending task so in the end of all my downloads I'm trying to start a intent service. The problem is that I'm getting the following error:
05-30 11:49:10.520: E/AndroidRuntime(18790): FATAL EXCEPTION: main
05-30 11:49:10.520: E/AndroidRuntime(18790): java.lang.RuntimeException: Unable to instantiate service br.com.facilit.target.app.android.util.UnzipService: java.lang.InstantiationException: can't instantiate class br.com.facilit.target.app.android.util.UnzipService; no empty constructor
My Download Thread:
public class DownloadService implements Runnable {
Activity controller;
boolean post;
String urlParent;
String filePath;
String destinationPath;
ResultReceiver mReceiver;
String typeDownload;
MetaDados metaDado;
int index;
boolean isResuming;
File jsonFile = new File(Constants.DEST_PATH_PARENT + Constants.JSON_FILES_PATH);
File jsonTempFile;
public DownloadService(Activity controller, boolean post, String urlParent, String filePath,
String destinationPath, ResultReceiver mReceiver, String typeDownload, int index, MetaDados metaDado,
boolean isResuming) {
this.controller = controller;
this.post = post;
this.urlParent = urlParent;
this.filePath = filePath;
this.destinationPath = destinationPath;
this.mReceiver = mReceiver;
this.typeDownload = typeDownload;
this.index = index;
this.metaDado = metaDado;
this.isResuming = isResuming;
}
#Override
public void run() {
Log.d(Constants.DOWNLOAD_AND_UNZIP_SERVICE, "Começando processo de download");
// ALL DOWNLOAD PROCESS
// THEN CALL INTENT FOR UNZIP
final Intent service = new Intent(controller.getApplicationContext(), UnzipService.class);
service.putExtra("post", false);
service.putExtra("filePath", filePath);
service.putExtra("destinationPath", destinationPath);
service.putExtra("receiver", mReceiver);
service.putExtra("typeDownload", Constants.HTML);
service.putExtra("metaDado", metaDado);
service.putExtra("isResuming", false);
controller.runOnUiThread(new Runnable() {
#Override
public void run() {
controller.startService(service);
}
});
}
}
My Unzip Intent Service:
public class UnzipService extends IntentService {
public UnzipService(String name) {
super("UnzipService");
}
#Override
protected void onHandleIntent(Intent intent) {
String filePath = intent.getStringExtra("filePath");
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
Log.d("UnzipService", "Simulando descompactação de arquivo " + filePath);
} catch (InterruptedException e) {
}
}
}
}
Manifest:
<service android:name="br.com.facilit.target.app.android.util.UnzipService"/>
as the exception reports you have no empty constructor Change it in:
public UnzipService() {
super("UnzipService");
}

Is there a way to add a badge to an application icon in Android?

On the iPhone, you can add a numbered badge to the application icon. On BlackBerry, I've successfully painted an image onto the application's icon while in the program. I want to do this for Android as well. I don't want to use the notification bar, as it's not something that needs to be notified instantly. Instead, I just want the user to be able to see how many new messages are in the application just by looking at the application icon.
Unfortunately, Android does not allow changing of the application icon because it's sealed in the APK once the program is compiled. There is no way to programmatically change it to a 'drawable'.
You may achieve your goal by using a widget instead of an icon. Widgets are highly customisable and can do what you want.
There's a short discussion about the difference between iPhone icon notification and using widgets here:
http://www.cnet.com/8301-19736_1-10278814-251.html
As you'll notice, there is virtually no difference between using a widget or an icon, since they can be the same size and look the same.
This can also be done for Sony's Xperia Home. I've blogged about it here, but the important parts are below. Sony devices use a class named BadgeReciever.
Declare the com.sonyericsson.home.permission.BROADCAST_BADGE permission in your manifest file:
Broadcast an Intent to the BadgeReceiver:
Intent intent = new Intent();
intent.setAction("com.sonyericsson.home.action.UPDATE_BADGE");
intent.putExtra("com.sonyericsson.home.intent.extra.badge.ACTIVITY_NAME", "com.yourdomain.yourapp.MainActivity");
intent.putExtra("com.sonyericsson.home.intent.extra.badge.SHOW_MESSAGE", true);
intent.putExtra("com.sonyericsson.home.intent.extra.badge.MESSAGE", "99");
intent.putExtra("com.sonyericsson.home.intent.extra.badge.PACKAGE_NAME", "com.yourdomain.yourapp");
sendBroadcast(intent);
Done. Once this Intent is broadcast the launcher should show a badge on your application icon.
To remove the badge again, simply send a new broadcast, this time with SHOW_MESSAGE set to false:
intent.putExtra("com.sonyericsson.home.intent.extra.badge.SHOW_MESSAGE", false);
I've excluded details on how I found this to keep the answer short, but it's all available in the blog. Might be an interesting read for someone.
I've also posted a seperate SO question about this here and will add the full answer there once I'm allowed to (need 10 reputation to answer my own question within 8 hours).
ShortcutBadger library makes it possible and works with LG, Sony, Samsung, HTC and other custom Launchers.
It even has a way to display Badge Count in Pure Android devices desktop.
Updating the Badge Count in the application icon is as easy as calling:
int badgeCount = 1;
ShortcutBadger.setBadge(getApplicationContext(), badgeCount);
It includes a demo application that allows you to test its behaviour.
OR
you can also try activity-alias to do so, but in this you need to create different icons with badge values ,it will work great in case- you need to switch between 2 different App icons (need to create different activity-alias for displaying different icon i.e more icons = more activity-alias).
Asus devices:
public static class AsusHomeBadger implements Badger {
private static final String INTENT_ACTION = "android.intent.action.BADGE_COUNT_UPDATE";
private static final String INTENT_EXTRA_BADGE_COUNT = "badge_count";
private static final String INTENT_EXTRA_PACKAGENAME = "badge_count_package_name";
private static final String INTENT_EXTRA_ACTIVITY_NAME = "badge_count_class_name";
#Override
public void executeBadge(int badgeCount) {
final Intent intent = new Intent(INTENT_ACTION);
intent.putExtra(INTENT_EXTRA_BADGE_COUNT, badgeCount);
intent.putExtra(INTENT_EXTRA_PACKAGENAME, componentName.getPackageName());
intent.putExtra(INTENT_EXTRA_ACTIVITY_NAME, componentName.getClassName());
intent.putExtra("badge_vip_count", 0);
if (canResolveBroadcast(intent)) {
AndroidUtilities.runOnUIThread(new Runnable() {
#Override
public void run() {
ApplicationLoader.applicationContext.sendBroadcast(intent);
}
});
}
}
#Override
public List<String> getSupportLaunchers() {
return Arrays.asList("com.asus.launcher");
}
}
Huawei devices:
public static class HuaweiHomeBadger implements Badger {
#Override
public void executeBadge(int badgeCount) {
final Bundle localBundle = new Bundle();
localBundle.putString("package", ApplicationLoader.applicationContext.getPackageName());
localBundle.putString("class", componentName.getClassName());
localBundle.putInt("badgenumber", badgeCount);
AndroidUtilities.runOnUIThread(new Runnable() {
#Override
public void run() {
try {
ApplicationLoader.applicationContext.getContentResolver().call(Uri.parse("content://com.huawei.android.launcher.settings/badge/"), "change_badge", null, localBundle);
} catch (Exception e) {
FileLog.e(e);
}
}
});
}
#Override
public List<String> getSupportLaunchers() {
return Arrays.asList(
"com.huawei.android.launcher"
);
}
}
HTC devices:
public static class NewHtcHomeBadger implements Badger {
public static final String INTENT_UPDATE_SHORTCUT = "com.htc.launcher.action.UPDATE_SHORTCUT";
public static final String INTENT_SET_NOTIFICATION = "com.htc.launcher.action.SET_NOTIFICATION";
public static final String PACKAGENAME = "packagename";
public static final String COUNT = "count";
public static final String EXTRA_COMPONENT = "com.htc.launcher.extra.COMPONENT";
public static final String EXTRA_COUNT = "com.htc.launcher.extra.COUNT";
#Override
public void executeBadge(int badgeCount) {
final Intent intent1 = new Intent(INTENT_SET_NOTIFICATION);
intent1.putExtra(EXTRA_COMPONENT, componentName.flattenToShortString());
intent1.putExtra(EXTRA_COUNT, badgeCount);
final Intent intent = new Intent(INTENT_UPDATE_SHORTCUT);
intent.putExtra(PACKAGENAME, componentName.getPackageName());
intent.putExtra(COUNT, badgeCount);
if (canResolveBroadcast(intent1) || canResolveBroadcast(intent)) {
AndroidUtilities.runOnUIThread(new Runnable() {
#Override
public void run() {
ApplicationLoader.applicationContext.sendBroadcast(intent1);
ApplicationLoader.applicationContext.sendBroadcast(intent);
}
});
}
}
#Override
public List<String> getSupportLaunchers() {
return Arrays.asList("com.htc.launcher");
}
}
Samsung devices:
public static class SamsungHomeBadger implements Badger {
private static final String CONTENT_URI = "content://com.sec.badge/apps?notify=true";
private static final String[] CONTENT_PROJECTION = new String[]{"_id","class"};
private static DefaultBadger defaultBadger;
#Override
public void executeBadge(int badgeCount) {
try {
if (defaultBadger == null) {
defaultBadger = new DefaultBadger();
}
defaultBadger.executeBadge(badgeCount);
} catch (Exception ignore) {
}
Uri mUri = Uri.parse(CONTENT_URI);
ContentResolver contentResolver = ApplicationLoader.applicationContext.getContentResolver();
Cursor cursor = null;
try {
cursor = contentResolver.query(mUri, CONTENT_PROJECTION, "package=?", new String[]{componentName.getPackageName()}, null);
if (cursor != null) {
String entryActivityName = componentName.getClassName();
boolean entryActivityExist = false;
while (cursor.moveToNext()) {
int id = cursor.getInt(0);
ContentValues contentValues = getContentValues(componentName, badgeCount, false);
contentResolver.update(mUri, contentValues, "_id=?", new String[]{String.valueOf(id)});
if (entryActivityName.equals(cursor.getString(cursor.getColumnIndex("class")))) {
entryActivityExist = true;
}
}
if (!entryActivityExist) {
ContentValues contentValues = getContentValues(componentName, badgeCount, true);
contentResolver.insert(mUri, contentValues);
}
}
} finally {
close(cursor);
}
}
private ContentValues getContentValues(ComponentName componentName, int badgeCount, boolean isInsert) {
ContentValues contentValues = new ContentValues();
if (isInsert) {
contentValues.put("package", componentName.getPackageName());
contentValues.put("class", componentName.getClassName());
}
contentValues.put("badgecount", badgeCount);
return contentValues;
}
#Override
public List<String> getSupportLaunchers() {
return Arrays.asList(
"com.sec.android.app.launcher",
"com.sec.android.app.twlauncher"
);
}
}
Sony devices:
public static class SonyHomeBadger implements Badger {
private static final String INTENT_ACTION = "com.sonyericsson.home.action.UPDATE_BADGE";
private static final String INTENT_EXTRA_PACKAGE_NAME = "com.sonyericsson.home.intent.extra.badge.PACKAGE_NAME";
private static final String INTENT_EXTRA_ACTIVITY_NAME = "com.sonyericsson.home.intent.extra.badge.ACTIVITY_NAME";
private static final String INTENT_EXTRA_MESSAGE = "com.sonyericsson.home.intent.extra.badge.MESSAGE";
private static final String INTENT_EXTRA_SHOW_MESSAGE = "com.sonyericsson.home.intent.extra.badge.SHOW_MESSAGE";
private static final String PROVIDER_CONTENT_URI = "content://com.sonymobile.home.resourceprovider/badge";
private static final String PROVIDER_COLUMNS_BADGE_COUNT = "badge_count";
private static final String PROVIDER_COLUMNS_PACKAGE_NAME = "package_name";
private static final String PROVIDER_COLUMNS_ACTIVITY_NAME = "activity_name";
private static final String SONY_HOME_PROVIDER_NAME = "com.sonymobile.home.resourceprovider";
private final Uri BADGE_CONTENT_URI = Uri.parse(PROVIDER_CONTENT_URI);
private static AsyncQueryHandler mQueryHandler;
#Override
public void executeBadge(int badgeCount) {
if (sonyBadgeContentProviderExists()) {
executeBadgeByContentProvider(badgeCount);
} else {
executeBadgeByBroadcast(badgeCount);
}
}
#Override
public List<String> getSupportLaunchers() {
return Arrays.asList("com.sonyericsson.home", "com.sonymobile.home");
}
private static void executeBadgeByBroadcast(int badgeCount) {
final Intent intent = new Intent(INTENT_ACTION);
intent.putExtra(INTENT_EXTRA_PACKAGE_NAME, componentName.getPackageName());
intent.putExtra(INTENT_EXTRA_ACTIVITY_NAME, componentName.getClassName());
intent.putExtra(INTENT_EXTRA_MESSAGE, String.valueOf(badgeCount));
intent.putExtra(INTENT_EXTRA_SHOW_MESSAGE, badgeCount > 0);
AndroidUtilities.runOnUIThread(new Runnable() {
#Override
public void run() {
ApplicationLoader.applicationContext.sendBroadcast(intent);
}
});
}
private void executeBadgeByContentProvider(int badgeCount) {
if (badgeCount < 0) {
return;
}
if (mQueryHandler == null) {
mQueryHandler = new AsyncQueryHandler(ApplicationLoader.applicationContext.getApplicationContext().getContentResolver()) {
#Override
public void handleMessage(Message msg) {
try {
super.handleMessage(msg);
} catch (Throwable ignore) {
}
}
};
}
insertBadgeAsync(badgeCount, componentName.getPackageName(), componentName.getClassName());
}
private void insertBadgeAsync(int badgeCount, String packageName, String activityName) {
final ContentValues contentValues = new ContentValues();
contentValues.put(PROVIDER_COLUMNS_BADGE_COUNT, badgeCount);
contentValues.put(PROVIDER_COLUMNS_PACKAGE_NAME, packageName);
contentValues.put(PROVIDER_COLUMNS_ACTIVITY_NAME, activityName);
mQueryHandler.startInsert(0, null, BADGE_CONTENT_URI, contentValues);
}
private static boolean sonyBadgeContentProviderExists() {
boolean exists = false;
ProviderInfo info = ApplicationLoader.applicationContext.getPackageManager().resolveContentProvider(SONY_HOME_PROVIDER_NAME, 0);
if (info != null) {
exists = true;
}
return exists;
}
}
Xiaomi devices:
public static class XiaomiHomeBadger implements Badger {
public static final String INTENT_ACTION = "android.intent.action.APPLICATION_MESSAGE_UPDATE";
public static final String EXTRA_UPDATE_APP_COMPONENT_NAME = "android.intent.extra.update_application_component_name";
public static final String EXTRA_UPDATE_APP_MSG_TEXT = "android.intent.extra.update_application_message_text";
#Override
public void executeBadge(int badgeCount) {
try {
Class miuiNotificationClass = Class.forName("android.app.MiuiNotification");
Object miuiNotification = miuiNotificationClass.newInstance();
Field field = miuiNotification.getClass().getDeclaredField("messageCount");
field.setAccessible(true);
field.set(miuiNotification, String.valueOf(badgeCount == 0 ? "" : badgeCount));
} catch (Throwable e) {
final Intent localIntent = new Intent(INTENT_ACTION);
localIntent.putExtra(EXTRA_UPDATE_APP_COMPONENT_NAME, componentName.getPackageName() + "/" + componentName.getClassName());
localIntent.putExtra(EXTRA_UPDATE_APP_MSG_TEXT, String.valueOf(badgeCount == 0 ? "" : badgeCount));
if (canResolveBroadcast(localIntent)) {
AndroidUtilities.runOnUIThread(new Runnable() {
#Override
public void run() {
ApplicationLoader.applicationContext.sendBroadcast(localIntent);
}
});
}
}
}
#Override
public List<String> getSupportLaunchers() {
return Arrays.asList(
"com.miui.miuilite",
"com.miui.home",
"com.miui.miuihome",
"com.miui.miuihome2",
"com.miui.mihome",
"com.miui.mihome2"
);
}
}
As of API 26, this is now officially supported:
Starting with 8.0 (API level 26), notification badges (also known as notification dots) appear on a launcher icon when the associated app has an active notification. Users can long-press on the app icon to reveal the notifications (alongside any app shortcuts), as shown in figure 1.
These dots appear by default in launcher apps that support them and there's nothing your app needs to do. However, there might be situations in which you don't want the to notification dot to appear or you want to control exactly which notifications to appear there.
To set a custom number, call setNumber() on the notification:
mNotification.setNumber(messageCount)
Here's how to do it for:
Apex Launcher
Nova Launcer
I think there's also a way to do it on the LG launcher, but haven't found out how yet.

Categories

Resources