Android: désactiver temporairement les changements d’orientation dans une activité

Mon activité principale comporte du code qui modifie certaines bases de données et ne doit pas être interrompu. Je fais le gros du travail dans un autre thread et j’utilise une boîte de dialog de progression que je définis comme non annulable. Cependant, j’ai remarqué que si je fais pivoter mon téléphone, il redémarre l’activité, ce qui est vraiment mauvais pour le processus en cours, et j’obtiens une fermeture forcée.

Ce que je veux faire est de désactiver les changements d’orientation de l’écran par programmation jusqu’à la fin de mon processus, moment auquel les changements d’orientation sont activés.

Comme expliqué par Chris dans sa propre réponse , appelant

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR); 

et alors

 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR); 

fonctionne vraiment comme du charme … sur de vrais appareils!

Ne pensez pas qu’il est cassé lors des tests sur l’émulateur, le raccourci Ctrl + F11 change TOUJOURS l’orientation de l’écran, sans émuler les mouvements des capteurs.

EDIT: ce n’était pas la meilleure réponse possible. Comme expliqué dans les commentaires, cette méthode présente des problèmes. La vraie réponse est ici .

Aucune des autres réponses ne m’a parfaitement réussi, mais voici ce que j’ai trouvé.

Verrouiller l’orientation au courant …

 if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } else setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); 

Lorsque le changement d’orientation doit être autorisé à nouveau, rétablissez la valeur par défaut …

 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); 

Voici une solution plus complète et à jour qui fonctionne pour API 8+, fonctionne pour le portrait inversé et le paysage, et fonctionne sur un onglet Galaxy où l’orientation “naturelle” est paysage (appelez activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) pour déverrouiller l’orientation):

 @SuppressWarnings("deprecation") @SuppressLint("NewApi") public static void lockActivityOrientation(Activity activity) { Display display = activity.getWindowManager().getDefaultDisplay(); int rotation = display.getRotation(); int height; int width; if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR2) { height = display.getHeight(); width = display.getWidth(); } else { Point size = new Point(); display.getSize(size); height = size.y; width = size.x; } switch (rotation) { case Surface.ROTATION_90: if (width > height) activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); else activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT); break; case Surface.ROTATION_180: if (height > width) activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT); else activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE); break; case Surface.ROTATION_270: if (width > height) activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE); else activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); break; default : if (height > width) activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); else activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); } } 

Afin de gérer également les modes d’orientation inversée, j’ai utilisé ce code pour définir l’orientation de l’activité:

 int rotation = getWindowManager().getDefaultDisplay().getRotation(); switch(rotation) { case Surface.ROTATION_180: setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT); break; case Surface.ROTATION_270: setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE); break; case Surface.ROTATION_0: setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); break; case Surface.ROTATION_90: setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); break; } 

Et pour permettre à nouveau l’orientation:

 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); 

J’ai trouvé la réponse. Pour ce faire, dans une activité, vous pouvez appeler setRequestedOrientation(int) avec l’une des valeurs spécifiées ici: http://developer.android.com/reference/android/R.attr.html#screenOrientation

Avant de setRequestedOrientation(OFF) mon thread, j’ai appelé setRequestedOrientation(OFF) (OFF = nosensor) et lorsque le thread a été exécuté, j’ai appelé setRequestedOrientation(ON) (ON = capteur). Fonctionne comme un charme.

Utilisez setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED); pour verrouiller l’orientation actuelle, qu’il s’agisse d’un paysage ou d’un portrait.

Utilisez setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR); pour déverrouiller l’orientation.

Merci a tous. J’ai modifié la solution de Pilot_51 pour m’assurer de retrouver l’état précédent. J’ai également apporté un changement pour prendre en charge les écrans non-paysage et non-portrait (mais je ne l’ai pas testé sur un tel écran).

 prevOrientation = getRequestedOrientation(); if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); } else if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } else { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR); } 

Puis le restaurer

 setRequestedOrientation(prevOrientation); 

Voici une solution qui fonctionne à chaque fois et préserve l’orientation actuelle (en utilisant Activity.Info.SCREEN_ORIENTATION_PORTRAIT par exemple, les ensembles à 0 °, mais l’utilisateur peut avoir une orientation à 180 °).

 // Scope: Activity private void _lockOrientation() { if (super.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { super.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT); } else { super.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE); } } private void _unlockOrientation() { super.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); } 
 protected void setLockScreenOrientation(boolean lock) { if (Build.VERSION.SDK_INT >= 18) { setRequestedOrientation(lock?ActivityInfo.SCREEN_ORIENTATION_LOCKED:ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR); return; } if (lock) { switch (getWindowManager().getDefaultDisplay().getRotation()) { case 0: setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); break; // value 1 case 2: setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT); break; // value 9 case 1: setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); break; // value 0 case 3: setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE); break; // value 8 } } else setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR); // value 10 } 

Cela fonctionne préfet pour moi. Il résout le problème avec différentes “orientations naturelles” de la tablette / du téléphone;)

 int rotation = getWindowManager().getDefaultDisplay().getRotation(); Configuration config = getResources().getConfiguration(); int naturalOrientation; if (((rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) && config.orientation == Configuration.ORIENTATION_LANDSCAPE) || ((rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) && config.orientation == Configuration.ORIENTATION_PORTRAIT)) { naturalOrientation = Configuration.ORIENTATION_LANDSCAPE; } else { naturalOrientation = Configuration.ORIENTATION_PORTRAIT; } // because getRotation() gives "rotation from natural orientation" of device (different on phone and tablet) // we need to update rotation variable if natural orienation isn't 0 (mainly tablets) if (naturalOrientation == Configuration.ORIENTATION_LANDSCAPE) rotation = ++rotation % 4; switch (rotation) { case Surface.ROTATION_0: //0 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); break; case Surface.ROTATION_90: //1 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); break; case Surface.ROTATION_180: //2 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT); break; case Surface.ROTATION_270: //3 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE); break; } } else { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); } 

Utilisez ActivityInfo.SCREEN_ORIENTATION_USER si vous souhaitez faire pivoter l’écran uniquement s’il est activé sur le périphérique.

Je suis venu avec une solution qui dépend de la rotation de l’affichage et décide ensuite de l’orientation de l’appareil. En connaissant l’orientation, nous pouvons verrouiller l’orientation et la libérer plus tard si nécessaire. Cette solution peut également déterminer si le périphérique en mode paysage inversé .

 private void lockOrientation(){ switch (((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation()) { // Portrait case Surface.ROTATION_0: setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); break; //Landscape case Surface.ROTATION_90: setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); break; // Reversed landscape case Surface.ROTATION_270: setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE); break; } } 

Ensuite, si nous devons libérer l’orientation, nous pouvons appeler cette méthode:

 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); 

Je pense que ce code est plus facile à lire.

 private void keepOrientation() { int orientation = getResources().getConfiguration().orientation; int rotation = getWindowManager().getDefaultDisplay().getRotation(); switch (rotation) { case Surface.ROTATION_0: if (orientation == Configuration.ORIENTATION_PORTRAIT) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } else { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); } break; case Surface.ROTATION_90: if (orientation == Configuration.ORIENTATION_PORTRAIT) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT); } else { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); } break; case Surface.ROTATION_180: if (orientation == Configuration.ORIENTATION_PORTRAIT) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT); } else { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE); } break; default: if (orientation == Configuration.ORIENTATION_PORTRAIT) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } else { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE); } } } 

J’ai trouvé qu’une combinaison de valeurs de rotation / orientation existantes est nécessaire pour couvrir les quatre possibilités; il y a les valeurs portrait / paysage et l’orientation naturelle de l’appareil. Disons que l’orientation naturelle des périphériques aura une valeur de rotation de 0 degré lorsque l’écran est en mode portrait ou paysage “naturel”. De même, il y aura une valeur de rotation de 90 degrés lorsqu’il est en paysage ou en portrait (remarquez qu’il est opposé à l’orientation à 0 degré). Ainsi, les valeurs de rotation qui ne sont pas de 0 ou 90 degrés impliquent une orientation “inverse”. Ok, voici du code:

 public enum eScreenOrientation { PORTRAIT (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT), LANDSCAPE (ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE), PORTRAIT_REVERSE (ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT), LANDSCAPE_REVERSE (ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE), UNSPECIFIED_ORIENTATION (ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); public final int activityInfoValue; eScreenOrientation ( int orientation ) { activityInfoValue = orientation; } } public eScreenOrientation currentScreenOrientation ( ) { final int rotation = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation(); final int orientation = getResources().getConfiguration().orientation; switch ( orientation ) { case Configuration.ORIENTATION_PORTRAIT: if ( rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_90 ) return eScreenOrientation.PORTRAIT; else return eScreenOrientation.PORTRAIT_REVERSE; case Configuration.ORIENTATION_LANDSCAPE: if ( rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_90 ) return eScreenOrientation.LANDSCAPE; else return eScreenOrientation.LANDSCAPE_REVERSE; default: return eScreenOrientation.UNSPECIFIED_ORIENTATION; } } public void lockScreenOrientation ( ) throws UnsupportedDisplayException { eScreenOrientation currentOrientation = currentScreenOrientation( ); if ( currentOrientation == eScreenOrientation.UNSPECIFIED_ORIENTATION ) throw new UnsupportedDisplayException("Unable to lock screen - unspecified orientation"); else setRequestedOrientation( currentOrientation.activityInfoValue ); } public void unlockScreenOrientation ( ) { setRequestedOrientation( ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED ); } 

Je n’ai pas aimé la plupart des réponses ici, car dans le délocking, elles étaient réglées sur UNSPECIFIED par opposition à l’état précédent. ProjectJourneyman l’a bien pris en compte, ce qui était bien, mais j’ai préféré le code de locking par Roy. Donc, ma recommandation serait un mélange des deux:

 private int prevOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; private void unlockOrientation() { setRequestedOrientation(prevOrientation); } @SuppressWarnings("deprecation") @SuppressLint("NewApi") private void lockOrientation() { prevOrientation = getRequestedOrientation(); Display display = getWindowManager().getDefaultDisplay(); int rotation = display.getRotation(); int height; int width; if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR2) { height = display.getHeight(); width = display.getWidth(); } else { Point size = new Point(); display.getSize(size); height = size.y; width = size.x; } switch (rotation) { case Surface.ROTATION_90: if (width > height) setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); else setRequestedOrientation(9/* reversePortait */); break; case Surface.ROTATION_180: if (height > width) setRequestedOrientation(9/* reversePortait */); else setRequestedOrientation(8/* reverseLandscape */); break; case Surface.ROTATION_270: if (width > height) setRequestedOrientation(8/* reverseLandscape */); else setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); break; default : if (height > width) setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); else setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); } } 

Vous pouvez utiliser

 public void swapOrientaionLockState(){ try{ if (Settings.System.getInt(mContext.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION) == 1) { Display defaultDisplay = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); Settings.System.putInt(mContext.getContentResolver(), Settings.System.USER_ROTATION, defaultDisplay.getRotation()); Settings.System.putInt(mContext.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0); } else { Settings.System.putInt(mContext.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 1); } Settings.System.putInt(mContext.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, !orientationIsLocked() ? 1 : 0); } catch (Settings.SettingNotFoundException e){ e.printStackTrace(); } } public boolean orientationIsLocked(){ if(canModifiSetting(mContext)){ try { return Settings.System.getInt(mContext.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION) == 0; } catch (Settings.SettingNotFoundException e) { e.printStackTrace(); } } return false; } public static boolean canModifiSetting(Context context){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { return Settings.System.canWrite(context); } else { return true; } } 

utiliser cette ligne de code

 this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 

dans la méthode oncreate de l’activité ur