Android Nougat, Oreo - How to add long press action to Quick toggles? - java

I need some help for my app that I'm developing. Current code that I'm using, on long press it launches app info. I want to change that to launch an activity of my app.
The Quick.java class.
#TargetApi(24)
public class Quick extends TileService {
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public void onTileAdded() {
super.onTileAdded();
}
#Override
public void onTileRemoved() {
super.onTileRemoved();
}
#Override
public void onStartListening() {
super.onStartListening();
}
#Override
public void onStopListening() {
super.onStopListening();
}
#Override
public void onClick() {
super.onClick();
startActivity(Main);
}
}
Just need a onLongClick() method on this code.
In my manifest under <application> tag.
<service
android:name=".Quick"
android:icon="#drawable/ic_quick"
android:label="#string/quick_title"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
</service>
Caution : It's 100% possible to do that in android N and O, for an example take look at this app

Ok I get yes you can implement the Long click listner but here is a issue
Long clicking on your quick settings tile will, by default, go to your app’s info screen. You can override that behavior by adding an intent-filter to one of your activities like so:
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES"/>
</intent-filter>
As you have done in your manifest file here a link that might be helpfull look very closely long press quick setting tile in android

Related

Sending a push notification only when app is in background

I use NotificationManager, NotificationChannel and NotificationCompat.Builder to display a push notification when an event is triggered, no online Firebase.
The push notification appears when my app is in foreground and background, but it only should appear when my app in the background.
I have 2 Activities where just only 1 knows the class, where the push notification is created. I could just set a variable that shows if my Activity is in foreground or not (with onResume and onPause), but if my other Activity starts the Activity with the notification trigger class is set in background and therefore I can't use this method. I would need to know if the whole app is in foreground or not, but I didn't find a good solution for that problem.
So is there an other way to display push notifications just when my whole app is in background?
I think you have FCMListenerService to receive your push notification as a background service. The Service should have the following declaration in the manifest file.
<service android:name=".Service.FCM.FCMListenerService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
Now you can pass the context of this service alone to check if the application is in foreground or in background. The function for checking if the application is foreground is following.
private static boolean isForeground(Context context) {
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> runningTaskInfo = manager.getRunningTasks(1);
ComponentName componentInfo = runningTaskInfo.get(0).topActivity;
return componentInfo.getPackageName().equals(Constants.ApplicationPackage);
}
Hence, in your onMessageReceived function you need to check if the application is in foreground and do not create the notification in the status bar.
public class FCMListenerService extends FirebaseMessagingService {
#Override
public void onMessageReceived(RemoteMessage message) {
if(!isForeground(this)) createNotification();
}
}
Hope that helps!
So I found a proper and very good solution for this problem.
According to this answer: https://stackoverflow.com/a/42679191/6938043
Application.ActivityLifecycleCallbacks
public class MainActivityChats extends AppCompatActivity implements Application.ActivityLifecycleCallbacks
{
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getApplication().registerActivityLifecycleCallbacks(this);
}
public void onActivityResumed(Activity activity)
{
if(msg_updater != null)
{
msg_updater.set_app_is_active(true);
}
}
public void onActivityPaused(Activity activity)
{
if(msg_updater != null)
{
msg_updater.set_app_is_active(false);
}
}
public void onActivityStopped(Activity activity) {}
public void onActivityCreated(Activity activity, Bundle bundle) {}
public void onActivityStarted(Activity activity) {}
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {}
public void onActivityDestroyed(Activity activity) {}
}

Start a one-time sound when app starts [duplicate]

I'd like to implement an update checker in an application, and I obviously only need this to show up once when you start the application. If I do the call in the onCreate() or onStart() method, it'll be shown every time the activity is created and this is not a viable solution.
So my question is: Is there a way to do something, like check for updates, just once per application start / launch?
I'm sorry if it's a bit hard to understand, I'm having difficulties explaning myself on this one.
SharedPreferences seems like ugly solution to me. It's much more neat when you use application constructor for such purposes.
All you need is to use your own Application class, not default one.
public class MyApp extends Application {
public MyApp() {
// this method fires only once per application start.
// getApplicationContext returns null here
Log.i("main", "Constructor fired");
}
#Override
public void onCreate() {
super.onCreate();
// this method fires once as well as constructor
// but also application has context here
Log.i("main", "onCreate fired");
}
}
Then you should register this class as your application class inside AndroidManifest.xml
<application android:label="#string/app_name" android:name=".MyApp"> <------- here
<activity android:name="MyActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
You even can press Back button, so application go to background, and will not waste your processor resources, only memory resource, and then you can launch it again and constructor still not fire since application was not finished yet.
You can clear memory in Task Manager, so all applications will be closed and then relaunch your application to make sure that your initialization code fire again.
looks like you might have to do something like this
PackageInfo info = getPackageManager().getPackageInfo(PACKAGE_NAME, 0);
int currentVersion = info.versionCode;
this.versionName = info.versionName;
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
int lastVersion = prefs.getInt("version_code", 0);
if (currentVersion > lastVersion) {
prefs.edit().putInt("version_code", currentVersion).commit();
// do the activity that u would like to do once here.
}
You can do this every time, to check if the app has been upgraded, so it runs only once for app upgrade
The shared preferences approach is messy, and the application class has no access to an activity.
Another alternative I've used is to have a retained fragment instance, and within that instance, a lot more stuff can be done especially if you need access to the main activity UI.
For this example, I've used asynctask within the retained fragment. My AsyncTask has callbacks to the parent activity. It is guaranteed to run only once per application because the fragment is never destroyed-recreated when the same activity is destroyed-recreated. It is a retained fragment.
public class StartupTaskFragment extends Fragment {
public interface Callbacks {
void onPreExecute();
void onProgressUpdate(int percent);
void onCancelled();
void onPostExecute();
}
public static final String TAG = "startup_task_fragment";
private Callbacks mCallbacks;
private StartupTask mTask;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mCallbacks = (Callbacks) activity;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true); // this keeps fragment in memory even if parent activity is destroyed
mTask = new StartupTask();
mTask.execute();
}
#Override
public void onDetach() {
super.onDetach();
mCallbacks = null;
}
private class StartupTask extends AsyncTask<Void, Integer, Void> {
#Override
protected void onPreExecute() {
if (mCallbacks != null) {
mCallbacks.onPreExecute();
}
}
#Override
protected Void doInBackground(Void... ignore) {
// do stuff here
return null;
}
#Override
protected void onProgressUpdate(Integer... percent) {
if (mCallbacks != null) {
mCallbacks.onProgressUpdate(percent[0]);
}
}
#Override
protected void onCancelled() {
if (mCallbacks != null) {
mCallbacks.onCancelled();
}
}
#Override
protected void onPostExecute(Void ignore) {
if (mCallbacks != null) {
mCallbacks.onPostExecute();
}
}
}
}
Then, in main (or parent) activity where you want this startup task fragment to run once.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fm = getFragmentManager();
StartupTaskFragment st = (StartupTaskFragment) fm.findFragmentByTag(StartupTaskFragment.TAG);
if(st == null) {
fm.beginTransaction().add(mStartupTaskFragment = new StartupTaskFragment(), StartupTaskFragment.TAG).commit();
}
...
}
Ideas for retained fragment came from here: http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html. I just figured out its other uses aside from config changes.
Yes you can do it Using SharedPrefernce concept of android. Just create a boolean flag and save it in SharedPrefernce and check its value in your onCreate() method .
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
if (!prefs.getBoolean("onlyonce", false)) {
// <---- run your one time code here
// mark once runned.
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean("onlyonce", true);
editor.commit();
}
}
This continues on #Vitalii's answer.
After having setup the Application class, if access to the Activity is required, we can use the aptly named android library "Once" https://github.com/jonfinerty/Once.
In the Application class's onCreate method
Once.initialise(this)
In the Activity / Fragment class's onCreate / onViewCreated method.
val helloTag = "hello"
if (!Once.beenDone(Once.THIS_APP_SESSION, helloTag)) {
//Do something that needs to be done only once
Once.markDone(helloTag) //Mark it done
}
I do this the same way as described in the other answer. I just have a global variable in the first activity which matches the release number from the manifest. I increment it for every upgrade and when the check sees a higher number, it executes the one-time code.
If successful, it writes the new number to shared preferences so it wont do it again until the next upgrade.
Make sure you assign the default to -1 when you retrieve the version from shared preferences so that you error on the side of running the code again as opposed to not running it and not having your app update correctly.
Use SharedPreference for this-
If you are not restarting your launcher activity again once your app is active then in that case you case use it.
Use this in a Splash screen if you are implementing it in the app.
If you are not using any splash screen then you need to create a activity with no view set and on it's oncreate call you can do start updation and start your main activity.
you can use counter value or boolean for this.
Here is SharedPreference doc:
http://developer.android.com/reference/android/content/SharedPreferences.html
try {
boolean firstboot = getSharedPreferences("BOOT_PREF",MODE_PRIVATE)
.getBoolean("firstboot", true);
if(firstboot){
//place your code that will run single time
getSharedPreferences("BOOT_PREF",MODE_PRIVATE).edit().
putBoolean("firstboot", false)
.commit();
}
I just solved doing this myself, I reopen my main activity multiple times throughout the application's execution. While the constructor is a valid approach for some things it doesn't let you access the current Application context to write toasts among other things.
My solution was to create a simple 'firstRun' boolean set to true in the class of my MainActivity, from there I run the contents of the if statement then set it to true. Example:
public class MainActivity extends AppCompatActivity
{
private static boolean firstRun = true;
#Override
protected void onCreate(Bundle savedInstanceState)
{
if(firstRun)
{
Toast.makeText(getApplicationContext(), "FIRST RUN", Toast.LENGTH_SHORT).show();
//YOUR FIRST RUN CODE HERE
}
firstRun = false;
super.onCreate(savedInstanceState);
//THE REST OF YOUR CODE
}

requestFeature() before adding content error when trying to make AndEngine work with Google Play Game Service

I have a game I'm working on, that uses AndEngine.
AndEngine has a "BaseGameActivity" and so does Google Play Game Service. I had to rename BaseGameActivity from AndEngine to AEBaseGameActivity and have it as a parent class BaseGameActivity instead of Activity.
But it is giving me this error:
Caused by: android.util.AndroidRuntimeException: requestFeature() must be called before adding content
at com.android.internal.policy.impl.PhoneWindow.requestFeature(PhoneWindow.java:226)
at org.andengine.util.ActivityUtils.requestFullscreen(ActivityUtils.java:56)
at org.andengine.ui.activity.AEBaseGameActivity.applyEngineOptions(AEBaseGameActivity.java:427)
at org.andengine.ui.activity.AEBaseGameActivity.onCreate(AEBaseGameActivity.java:83)
Now AndEngine has this piece of code:
public static void requestFullscreen(final Activity pActivity) {
final Window window = pActivity.getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
window.clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
window.requestFeature(Window.FEATURE_NO_TITLE);
}
if I comment the requestFeature line, my projects runs! But it has an ugly title bar.
Does anyone please know a fix for this ?
EDIT, HERE IS SOME MORE CODE:
PS: AEBaseGameActivity.php extends BaseActivity which extends BaseGameActivity (previously just activity)
AEBaseGameActivity.php
public abstract class AEBaseGameActivity extends BaseActivity implements IGameInterface, IRendererListener {
#Override
protected void onCreate(final Bundle pSavedInstanceState) {
if(BuildConfig.DEBUG) {
Debug.d(this.getClass().getSimpleName() + ".onCreate" + " #(Thread: '" + Thread.currentThread().getName() + "')");
}
super.onCreate(pSavedInstanceState);
this.mGamePaused = true;
this.mEngine = this.onCreateEngine(this.onCreateEngineOptions());
this.mEngine.startUpdateThread();
this.applyEngineOptions(); //REQUEST FULLSCREEN
this.onSetContentView(); //SET CONTENT VIEW
}
...
private void applyEngineOptions() {
final EngineOptions engineOptions = this.mEngine.getEngineOptions();
if(engineOptions.isFullscreen()) {
ActivityUtils.requestFullscreen(this); //ACTIVITY UTIL SHOWN LATER
}
...
}
...
protected void onSetContentView() {
this.mRenderSurfaceView = new RenderSurfaceView(this);
this.mRenderSurfaceView.setRenderer(this.mEngine, this);
this.setContentView(this.mRenderSurfaceView, AEBaseGameActivity.createSurfaceViewLayoutParams());
}
}
ActivityUtils.java
public class ActivityUtils {
public static void requestFullscreen(final Activity pActivity) {
final Window window = pActivity.getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
window.clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
window.requestFeature(Window.FEATURE_NO_TITLE); //IF COMMENTING THIS, THE GAME IS RUNNING
}
...
}
EDIT2:
The code is basically only AndEngine, here is the original code:
https://github.com/nicolasgramlich/AndEngine/tree/GLES2/src/org/andengine/ui/activity
My changes:
renamed BaseGameActivity to AEBaseGameActivity
BaseActivity extends BaseGameActivity (taken from Google Play Game Service) instead of Activity
BaseGameActivity and GameHelper.java taken from BaseGameUtils from Google Play Game Service.
Ok so this is what I did:
I commented out the line that is causing the problem (ActivityUtils.java line 56 of AndEngine)
I added this in my activity to the Android Manifest:
android:theme="#android:style/Theme.NoTitleBar"
It ends up looking something like:
<activity
android:name=".GameActivity"
android:theme="#android:style/Theme.NoTitleBar"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Exception requestFeature() must be called before adding content telling everything
call requestFullscreen() before setContenview()
Edit
try REQUEST FULLSCREEN after super.onCreate()
#Override
protected void onCreate(final Bundle pSavedInstanceState) {
super.onCreate(pSavedInstanceState);
this.applyEngineOptions(); //REQUEST FULLSCREEN

Class Not found Exception Android

I am trying to learn android programming and I am creating an app that starts with a splash screen and loads a menu class after that. the problem is I get this exception
06-04 10:59:37.166: E/AndroidRuntime(926): Caused by: java.lang.ClassNotFoundException: Didn't find class "com.em.example1.MENU" on path: /data/app/com.em.example1-1.apk
I understand what the exception states but I do not understand why this is happening. In my splash screen class I load the Menu activity like this
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
Thread timer = new Thread() {
public void run() {
try {
sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
Intent mainApp = new Intent("com.em.example1.MENU");
startActivity(mainApp);
}
}
};
timer.start();
and the menu class is defined in the manifest file like this
<activity
android:name="com.em.example1.MENU"
android:label="#string/app_name" >
<intent-filter>
<action android:name="com.em.example1.MENU" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
When i was loading a main activity with two buttons and a label everything was working ok. But when I changed it (inside my splash screen activity) so it would load Menu Activity it keeps giving me this error.
Thanks in advance
Right click on your project goto properties. Java Build Path. Choose Order export tab. Make sure that Android Private Libraries is selected. If you have referenced library project. do the same for the library project also. Clean and Build.
Maybe you should use this:
Intent mainApp = new Intent(this,com.em.example1.MENU.class);
startActivity(mainApp);
You may use this code, i have made some changes. it may be help u..
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
Thread timer = new Thread() {
public void run() {
try {
sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
MENU.this.runOnUiThread(new Runnable() {
#Override
public void run() {
Intent mainApp = new Intent(MENU.this,com.em.example1.MENU.class);
MENU.this.startActivity(mainApp);
}
});
}
}
};
timer.start();
the stuff f in manifest before what you listed is what? What you are looking for is that to seee what the app package name is..
Try changing this line in your manifest file.
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
And also try this thing
Try going to Project -> Properties -> Java Build Path -> Order & Export and ensure Android Private Libraries are checked for your project and for all other library projects you are using. Clean all projects afterwards and see what happens.
As it turns out I the error was too simple to realize...... I had the word Menu capitalized in Android Manifest in the name and not only in action name. Thanks for trying to help me everyone

How to set alarm when mobile has been idle using android?

Hi I want to set alarm when the phone hasn't been touched. If the screen hasn't been touched for nearly 2 minutes, the alarm sound would be raised. How can I do this? Can anybody help me?
Thanks in advance.
Pass the AlarmService through out the below code. This will find how long your device has been in idle.
idle.java
Handler hl_timeout = new Handler();
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try{
hl_timeout.postDelayed(DoOnTimeOut, 15000);
}catch(Exception e)
{
e.printStackTrace();
}
}
// Toast
Thread DoOnTimeOut = new Thread() {
public void run() {
try{
Toast.makeText(getApplicationContext(), "System is idle", Toast.LENGTH_LONG).show();
}catch(Exception e)
{
e.printStackTrace();
}
}
};
#Override
public void onUserInteraction()
{
super.onUserInteraction();
//Remove any previous callback
try{
hl_timeout.removeCallbacks(DoOnTimeOut);
hl_timeout.postDelayed(DoOnTimeOut, 15000);
}catch(Exception e)
{
e.printStackTrace();
}
}
Hope this helps you.
You can create AlarmService to play sound even when application/device is idle
Extend method onUserInteraction of Activity Class to reset timer and start again for two minutes.
If I understand your question correctly, you need to trigger an alarm, when there is no any user interaction happened within some time interval. And one of the main requirements, there is no your activity running in foreground. So the case with onUserInteraction doesn't work for you.
In this case you still can receive updates on every user action if you make your own AccessibilityService.
Add this to your manifest to declare the service:
<service android:name=".MyAccessibilityService">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
</service>
And your service implementation should look similar to this:
public class MyAccessibilityService extends AccessibilityService
{
#Override
public void onServiceConnected() {
AccessibilityServiceInfo info = new AccessibilityServiceInfo();
// we are interested in all types of accessibility events
info.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
// we want to receive events in a certain interval
info.notificationTimeout = 100;
setServiceInfo(info);
Log.e("ALEX", "service connected!");
}
#Override
public void onAccessibilityEvent(AccessibilityEvent arg0)
{
Log.e("ALEX", "Event happened!");
}
}
Now any time user touches the screen for example, you will get onAccessibilityEvent() triggered and will be able to restart a timer which will launch your Alarm.
HOWEVER, this approach has one disadvantage: in order to make it working, you will need to go to the phone settings -> Accessibility and enable your application there. Otherwise, system will not launch your service.

Categories