I am facing some issues when orientation is changed from Landscape to Portrait or vice versa.
I have a scenario whether the orientation needs to be changed only in tablets not in phone. Means in Phone, the view needs to be locked and in Tablet, the view will be changed depending on the orientation.
Till now what I have done is I have created a class which extends Application
public class BaseApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
#Override
public void onActivityPreCreated(#NonNull Activity activity, #Nullable Bundle savedInstanceState) {
if (UIHelper.NeedLandscapeConstraint(activity)) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
} else {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
}
#Override
public void onActivityCreated(#NonNull Activity activity, #Nullable Bundle bundle) {
}
#Override
public void onActivityStarted(#NonNull Activity activity) {
}
#Override
public void onActivityResumed(#NonNull Activity activity) {
}
#Override
public void onActivityPaused(#NonNull Activity activity) {
}
#Override
public void onActivityStopped(#NonNull Activity activity) {
}
#Override
public void onActivitySaveInstanceState(#NonNull Activity activity, #NonNull Bundle bundle) {
}
#Override
public void onActivityDestroyed(#NonNull Activity activity) {
}
});
}
}
and in UIHelper.java I have a method which returns the type of device
public static boolean NeedLandscapeConstraint(Activity activity) {
Pair<Double, Double> screenMetrics = UIHelper.GetScreenMetrics(activity);
if (screenMetrics.first > 3.5 && screenMetrics.second > 3.5) {
// Tablet
return true;
}
return false;
}
In the AndroidManifest.xml, if I android:screenOrientation="unspecified"then everything is working fine but I cannot lock the view as portrait in Phone and if I specify android:screenOrientation="portrait" Phone view is working fine but in Tablet Portrait is loading after that the orientation gets changed to Landscape for all the Activity.
I am not getting how to solve this issue. Can anyone help me out.
Thanks in advance
Related
Is there any universal method that is called when app goes in background ? I dont want to perform the action when the activity is changes just want to perform it when app goes in background i.e.home_screen appears.
You can achieve this by using ActivityLifeCycleCallbacks:
public class LifeCycleCallbacks implements Application.ActivityLifecycleCallbacks {
/**
* Keeps a count of the activities started.
*/
private int mActivitiesStarted;
/**
* Keeps a count of the activities stopped.
*/
private int mActivitiesStopped;
#Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
#Override
public void onActivityStarted(Activity activity) {
if (mActivitiesStarted == mActivitiesStopped) {
// This is the session start
}
++mActivitiesStarted;
}
#Override
public void onActivityResumed(Activity activity) {
}
#Override
public void onActivityPaused(Activity activity) {
}
#Override
public void onActivityStopped(Activity activity) {
++mActivitiesStopped;
if ((mActivitiesStarted > 0) && (mActivitiesStarted == mActivitiesStopped)) {
/* This is session end. We can do things that we need to do when the app
* session ends, i.e. send tracking info, etc. */
}
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
#Override
public void onActivityDestroyed(Activity activity) {
}
}
Finally, register your LifeCycleCallbacks class with your Application class in onCreate:
registerActivityLifecycleCallbacks(new LifeCycleCallbacks());
I need to know when the user close the App, not when the user press on the "home" button, but when the user close the App at the "recent applications menu".
At those two cases the App go to the onPause method. Is there any way to tell them apart?
I`m asking because, I want to delete the user from my database on one situation, and not at the other.
you can try combining multiple callbacks from the activity lifecycle.
onUserLeaveHint() can be realy usefull to get know if the activity is in background or foreground
isFinishing(): can bu used to know if the activity is been closed by a finish() call or if is the system shutting down the activity to free resources
you can try using a Service for that, in this service override onTrimMemory method
#Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
switch (level) {
case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
//app was closed
break;
}
}
check more about services
I'm not sure, but maybe ActivityLifecycleCallbacks can help you. It need to test.
Example:
public class YourApplication extends Application {
#Override
public void onCreate() {
lifecycleListener = new ActivityLifecycleListener();
registerActivityLifecycleCallbacks(lifecycleListener);
}
public class ActivityLifecycleListener implements Application.ActivityLifecycleCallbacks {
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
#Override
public void onActivityStarted(Activity activity) {
}
#Override
public void onActivityResumed(Activity activity) {
}
#Override
public void onActivityPaused(Activity activity) {
}
#Override
public void onActivityStopped(Activity activity) {
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
#Override
public void onActivityDestroyed(Activity activity) {
}
}
}
Problem
The idea is very simple. Whenever an user comes back to my app from the Recents I want to show a simple dialog prompting with the password.
I know how to prompt the dialog with password, but my problem is how do I understand that the user has entered my app from the recents. If I put the prompt in the onResume in every activity, then it will get triggered everytime even if the user doesn't enter from the Recents menu.
There are lots of activities and fragments in my app. So, I would love to have a more generic or application level solution.
Implement Application.ActivityLifecycleCallbacks, that will provide all activity callback in your application class.
public class AppController extends Application implements
Application.ActivityLifecycleCallbacks
{
#Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(this);
}
#Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
#Override
public void onActivityStarted(Activity activity) {
}
#Override
public void onActivityResumed(Activity activity) {
}
#Override
public void onActivityPaused(Activity activity) {
}
#Override
public void onActivityStopped(Activity activity) {
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
#Override
public void onActivityDestroyed(Activity activity) {
}
}
You could try with this flag FLAG_ACTIVITY_LAUNCHER_FROM _HISTORY:
if((getIntent().getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY )!=0){
Log.d(TAG, "Called from history");
//clear flag from history
Intent intent = getIntent().setFlags( getIntent().getFlags() & (~ Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY));
setIntent(intent);
}
Source : Android - detecting application launch from home or history
When "A" Activity is start from recent, this flag is present.
Now this flag will be also present if "A" activity call "B" activity and on "B" user press back.
So you have to check flag and when you detect it you have clear intent by removing this flag, source: Remove a Paint Flag in Android
Try below sample
/**
* TODO : After update to API level 14 (Android 4.0),
* We should implement Application.ActivityLifecycleCallbacks
*/
public class GlobalApplication extends android.app.Application
{
private boolean inForeground = true;
private int resumed = 0;
private int paused = 0;
public void onActivityResumed( Activity activity )
{
++resumed;
if( !inForeground )
{
// Don't check for foreground or background right away
// finishing an activity and starting a new one will trigger to many
// foreground <---> background switches
//
// In half a second call foregroundOrBackground
}
}
public void onActivityPaused( Activity activity )
{
++paused;
if( inForeground )
{
// Don't check for foreground or background right away
// finishing an activity and starting a new one will trigger to many
// foreground <---> background switches
//
// In half a second call foregroundOrBackground
}
}
public void foregroundOrBackground()
{
if( paused >= resumed && inForeground )
{
inForeground = false;
}
else if( resumed > paused && !inForeground )
{
inForeground = true;
}
}
}
Put below code in your all activities.
public class BaseActivity extends android.app.Activity
{
private GlobalApplication globalApplication;
#Override
protected void onCreate()
{
globalApplication = (GlobalApplication) getApplication();
}
#Override
protected void onResume()
{
super.onResume();
globalApplication.onActivityResumed(this);
}
#Override
protected void onPause()
{
super.onPause();
globalApplication.onActivityPaused(this);
}
#Override
public void onDestroy()
{
super.onDestroy();
}
}
I would suggest using LifecycleObserver. If your Application class implements this interface it marks a class as a LifecycleObserver, it does not have any methods, instead, it relies on OnLifecycleEvent annotated methods. The usage is simple:
public class AndroidApplication extends Application implements LifecycleObserver {
#OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onAppStart() {
//enter code here
}
#OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onAppStop() {
//enter code here
}
...etc
}
With Lifecycle.Event you can access all lifecycle states through Enum. It is part of androidx.
I've implemented something similar for iOS using a quick swizzle of viewDidAppear to allow my company to track flow around the app in our own internal systems.
Now, ideally I'd like to avoid having to implement appear & disappear tracking in every activity for our internal use, so was hoping someone could shed some light into how the GA library achieves this.
I had a good google around and couldn't find any kind of internal event that's posted when an activity comes into the foreground so am at a bit of a loss at the moment.
Cheers!
I know the following is not a direct answer to your question but why not applying a basic OOP principle? Inheritance.
import android.app.Activity;
public class BaseActivity extends Activity {
#Override
protected void onResume() {
super.onResume();
// hit when activity appears. Tell Appserver!
}
#Override
protected void onPause() {
super.onPause();
// hit when activity hides. Tell Appserver!
}
}
and then have your other Acivities extend this instead of android.app.Activity?
You can use ActivityLifecycleCallback. Example below:
public class MordorApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(new ActivityLifecycleLogger());
}
}
public class ActivityLifecycleLogger implements Application.ActivityLifecycleCallbacks {
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
createActivityStateLog(activity, "created");
}
#Override
public void onActivityStarted(Activity activity) {
createActivityStateLog(activity, "started");
}
#Override
public void onActivityResumed(Activity activity) {
createActivityStateLog(activity, "resumed");
}
#Override
public void onActivityPaused(Activity activity) {
createActivityStateLog(activity, "paused");
}
#Override
public void onActivityStopped(Activity activity) {
createActivityStateLog(activity, "stopped");
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
createActivityStateLog(activity, "savingStateInstance");
}
#Override
public void onActivityDestroyed(Activity activity) {
createActivityStateLog(activity, "destroyed");
}
private void createActivityStateLog(Activity activity, String state) {
String log = String.format("Activity %s - %s", activity.getClass().getName(), state);
LOG.debug(log);
}
private static final Logger LOG = LoggerFactory.getLogger(ActivityLifecycleLogger.class);
}
Google Analytics has automatic Activity tracking feature.
See
https://developers.google.com/analytics/devguides/collection/android/v4/?hl=en#analytics-xml
or do John's answer :)
You can create delegate class (suppose GaUtils) then call that on resume/pause. Just one line, don't you?
#Override
protected void onPause() {
super.onPause();
GaUtils.onPause(screenName); // track pause
}
I'm currently developing a light-weight application where in one part of the app I would like to COMPLETELY take away the ability to take a screenshot in Android. When I say screenshot, I'm talking about iPhone's "screen capture" feature. This is for security reasons. I realize there are apps out there that allow users in Android to do this as well, and I want to block this functionality. Any way of doing this is fine, whether disabling the hardware buttons, freezing the phone, or via software.
You can use the window LayoutParam FLAG_SECURE. Add this to your onCreate method:
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
}
More on this topic can be found here.
Add an application class in your project like that to prevent the full app from screen-shot (All Activity and Fragment around your app). This is the example project and below I mentioned the core code -
public class MyApplicationContext extends Application {
private Context context;
public void onCreate() {
super.onCreate();
context = getApplicationContext();
setupActivityListener();
}
private void setupActivityListener() {
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE); }
#Override
public void onActivityStarted(Activity activity) {
}
#Override
public void onActivityResumed(Activity activity) {
}
#Override
public void onActivityPaused(Activity activity) {
}
#Override
public void onActivityStopped(Activity activity) {
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
#Override
public void onActivityDestroyed(Activity activity) {
}
});
}
}