23

I'm writing a Widget that will display a countdown timer. I have the widget working the way I want it until I flip the phone from landscape to portrait. My widget does not update and goes to it's initial state at start of the widget until an onupdate is called by my recurring alarm. I would like to call an onupdate manually once the orientation changes to update my widget I've been researching this for a while now and I've found out that I need to use a Service which will monitor the orientation changes and call my onupdate for my widget.

My problem is I can't find a straight answer as to how to use a service to monitor the change. I've seen that with an activity I can add android:configChanges="orientation|keyboardHidden" to the manifest for an activity and use a onConfigurationChanged, but can I do this for a service. If so how? Is there a better way to monitor the orientation change? I've also read on the internet that a service isn't the best way to do this either.

I've seen tutorials for creating orientation listeners but they seem to use depreciated function calls.

Thanks in Advance

Dysen
  • 231
  • 1
  • 2
  • 5

4 Answers4

39

Service#onConfigurationChanged(Configuration newConfig) works for me. No need to register Receivers for my opinion. I also did not add any filter to AndroidManifest. Did I miss something in the discussion since nobody suggested this solution? My Service is running on foreground.

Just place inside your service:

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    //Your handling
}
OneWorld
  • 17,512
  • 21
  • 86
  • 136
  • 2
    Yes this works and is much simpler than registering for broadcast intents! – Flyview Mar 04 '16 at 18:38
  • For me, this method is getting called when a device is rotated to landscape AND when I exit the app from the landscape. When I exit the app from the portrait onConfigurationChanged() is not called, just onUnbind(). @Flyview Do you know why that happens? – Nikola Samardzija Jul 13 '21 at 05:46
  • @Nikola Probably because the screen is returning back to portrait when your app is exited? – Flyview Jul 14 '21 at 19:12
  • @Flyview Probably, but not sure about the solution. It's not an orientation change of the app itself but the device (ex. home screen) is portrait. onUnbind() doesn't get called twice. So basically it's the same event for actually unbind and orientation unbind. Do you have a suggestion on how to distinguish these two events in this case? – Nikola Samardzija Jul 15 '21 at 08:29
  • I'm confused. Is onConfigurationChanged getting called twice when you exit in landscape, or onUnbind? – Flyview Jul 19 '21 at 16:40
14

Please find below an example which does what you ask for, hope this helps.

public class ScreenOrientationListener extends Activity {

    private static final String TAG = "ScreenOrientationListener";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mContext = this;

        setContentView(R.layout.main);

        startService( new Intent(this, MyService.class) );
    }
}

and here comes MyService class

public class MyService extends Service {
    private static final String TAG = "MyService";

    private static final String BCAST_CONFIGCHANGED = "android.intent.action.CONFIGURATION_CHANGED";
    private static Context mContext;

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        Log.d(TAG, "onCreate()");

        mContext = this;

        IntentFilter filter = new IntentFilter();
        filter.addAction(BCAST_CONFIGCHANGED);
        this.registerReceiver(mBroadcastReceiver, filter);
    }

    @Override
    public void onDestroy() {           
        Log.d(TAG, "onDestroy()");
        //Unregister receiver to avoid memory leaks
        mContext.unregisterReceiver(mBroadcastReceiver);
    }

    @Override
    public void onStart(Intent intent, int startid) {
        Log.d(TAG, "onStart()");
    }

    public BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent myIntent) {

            if ( myIntent.getAction().equals( BCAST_CONFIGCHANGED ) ) {

                Log.d(TAG, "received->" + BCAST_CONFIGCHANGED);


                if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE){
                    // it's Landscape
                    Log.d(TAG, "LANDSCAPE");
                }
                else {
                    Log.d(TAG, "PORTRAIT");
                }
            }
        }
    };
}

and here is the part to define MyService in manifest file

<!-- Services -->
        <service android:enabled="true"  android:name="com.wareninja.android.external.screenorientationlistener.services.MyService">
            <intent-filter>
                <action android:name="android.intent.action.CONFIGURATION_CHANGED"/>
            </intent-filter>
        </service>
OneWorld
  • 17,512
  • 21
  • 86
  • 136
Yilmaz Guleryuz
  • 9,313
  • 3
  • 32
  • 43
  • The problem is this will only work if the application supports rotation. So if your launcher does not support rotation to landscape, it will not work from a service. My guess would be to use the sensors to get it, but I am not sure how. – Archimedes Trajano Feb 09 '12 at 23:50
  • @WareNinja: The above doesn't work if the user manually changed the orientation by clicking the "Auto Rotation" button in the notification bar. – ChuongPham Aug 12 '12 at 18:19
  • @ChuongPham:Auto rotation and manually change the orientation ? could you please explain more, its confusing what you were trying to say ? – xmen Sep 19 '14 at 16:44
2

You could create a BroadcastReceiver that listens for Intent.ACTION_CONFIGURATION_CHANGED (android.intent.action.CONFIGURATION_CHANGED)

Note that it does say:

You can not receive this through components declared in manifests, only by explicitly registering for it with Context.registerReceiver().

Which means you can't register your reciever in the manifest file. You would have to register it in code.

then get the configuration and check what the orientation is as Floern stated.

Ryan Conrad
  • 6,870
  • 2
  • 36
  • 36
  • Is it possible to _Intent.ACTION_CONFIGURATION_CHANGED_ to the appwidgetprovider since it is a modified broadcast receiver? I'm guessing not. When I create the broadcast receiver do I need to start it somewhere or will it start automatically when my Widget starts? – Dysen Jan 07 '11 at 17:47
  • I finally figured out how to implement what your talking about. My next question is why would I register the receiver in a service? wouldn't the service exit after registering? Could I register the Receiver in the widgetconfiguration activity? Does the entity that registered the broadcast receiver have to stay in memory for it to run? – Dysen Jan 10 '11 at 12:00
  • @Dysen can you provide some sample code? I have tried to implement the above thing but it is not working in Android Emulator – Raghav Satyadev Nov 17 '20 at 08:02
1

I would suggest you use an OrientationEventListener object. It does exactly what you are looking for and it is not deprecated. It's been around since API level 3.

monchote
  • 3,440
  • 2
  • 20
  • 20
  • 2
    OrientationEventListener doesn't work if the user manually changed the orientation by clicking the "Auto Rotation" button in the notification bar and have the phone flat on a surface. It will only work if the user pick up his phone and move/rotate it. – ChuongPham Aug 12 '12 at 18:20