Android: desative temporariamente as mudanças de orientação em uma atividade

116

Minha atividade principal tem algum código que faz algumas alterações no banco de dados que não devem ser interrompidas. Estou fazendo o trabalho pesado em outro tópico e usando uma caixa de diálogo de progresso que defini como não cancelável. No entanto, notei que se eu girar meu telefone, ele reinicia a atividade, que é MUITO ruim para o processo que estava em execução, e recebo um Forçar fechamento.

O que eu quero fazer é desativar programaticamente as alterações de orientação da tela até que meu processo seja concluído, momento em que as alterações de orientação são ativadas.

Christopher Perry
fonte
Como ninguém parece mencionar essa parte, você vai querer importar android.content.pm.ActivityInfo para usar o identificador ActivityInfo.
zsalwasser
1
Consulte: stackoverflow.com/a/32885911/2673792 para melhor solução
Sudhir Sinha

Respostas:

165

Conforme explicado por Chris em sua auto-resposta , ligando

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);

e depois

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);

realmente funciona muito bem ... em dispositivos reais!

Não pense que está quebrado ao testar no emulador, o atalho ctrl + F11 SEMPRE muda a orientação da tela, sem emular movimentos dos sensores.

EDIT: esta não era a melhor resposta possível. Conforme explicado nos comentários, há problemas com esse método. A verdadeira resposta está aqui .

Kevin gaudin
fonte
Não consegui localizar essas constantes. Obrigado por isso.
Christopher Perry,
41
Há um problema com esses métodos ... Parece que se você chamar setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_NOSENSOR); quando o dispositivo não está em seu uso de orientação padrão, a orientação da atividade é imediatamente alterada (destruída e recriada) para a orientação padrão do dispositivo. Por exemplo, em um telefone, se você segurá-lo na orientação paisagem, a atividade será alternada para retrato e de volta para paisagem ao reativar os sensores. O mesmo problema oposto com um TI Archos A5: usá-lo em retrato faz com que a atividade seja alternada para paisagem e de volta para retrato.
Kevin Gaudin
1
A verdadeira resposta para a pergunta original está aqui: stackoverflow.com/questions/3821423/…
Kevin Gaudin
2
Isto não funcionou para mim. Este funcionou: stackoverflow.com/a/10488012/1369016 Tive que chamar setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE); ou setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT); com base na orientação atual recuperada de getResources (). getConfiguration () .idance.
Tiago
ActivityInfo.SCREEN_ORIENTATION_SENSORnão respeita o bloqueio de orientação nativo do Android. Redefinir a orientação para ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIEDsim.
tvkanters
43

Nenhuma das outras respostas funcionou perfeitamente para mim, mas aqui está o que descobri que sim.

Travar orientação para o atual ...

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

Quando a mudança de orientação for permitida novamente, volte ao padrão ...

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
Pilot_51
fonte
9
O problema com isso é que Configuration.ORIENTATION_PORTRAITserá retornado em ambos os modos de paisagem (ou seja, 'normal' e reverso). Portanto, se o telefone estiver na orientação paisagem invertida e você configurá- ActivityInfo.SCREEN_ORIENTATION_LANDSCAPElo, ele ficará de cabeça para baixo. Na API 9, ActivityInfo apresenta SCREEN_ORIENTATION_REVERSE_LANDSCAPEconstante, mas não vejo uma maneira de detectar tal orientação por meio de Configurationclasse.
Błażej Czapp
1
Isso funcionou. A resposta à preocupação acima está localizada nesta resposta. stackoverflow.com/a/10453034/1223436
Zack
Funcionou como um encanto para as minhas necessidades também, brilhante obrigado
user2029541
39

Aqui está uma solução mais completa e atualizada que funciona para API 8+, funciona para retrato reverso e paisagem e funciona em uma guia do Galaxy onde a orientação "natural" é paisagem (chame activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)para desbloquear a orientação):

@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);
    }
}
Roy
fonte
Funcionou muito bem para mim com tablets e telefones.
ScruffyFox
A única resposta correta que funciona em todos os tipos de dispositivo para mim.
amdev
Definitivamente, a melhor resposta! Você pode fazer este método statice adicionar Activity activitycomo um parâmetro.
caw
18

Para gerenciar também os modos de orientação reversa, usei esse código para corrigir a orientação da atividade:

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;
    }

E para permitir novamente a orientação:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
Ivan BASART
fonte
17

Use setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);para bloquear a orientação atual, seja paisagem ou retrato.

Use setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);para desbloquear a orientação.

Sudhir Sinha
fonte
A melhor solução para um bloqueio temporário curto. Sem mexer com a orientação atual do sensor.
O incrível janeiro
2
funciona em Build.VERSION.SDK_INT> = 18, uma resposta mais completa é fornecida por tdjprog nesta página stackoverflow.com/a/41812971/5235263
bastami82
14

Eu encontrei a resposta. Para fazer isso, em uma Activity você pode chamar setRequestedOrientation(int)com um dos valores especificados aqui: http://developer.android.com/reference/android/R.attr.html#screenOrientation

Antes de iniciar meu tópico, chamei setRequestedOrientation(OFF)(OFF = nosensor) e quando o tópico estava pronto chamei setRequestedOrientation(ON)(ON = sensor). Funciona como um encanto.

Christopher Perry
fonte
11

Obrigado a todos. Modifiquei a solução do Pilot_51, para ter certeza de que restaurou ao estado anterior. Também incluí uma mudança para oferecer suporte a telas não horizontais e não retratos (mas não testei em uma tela assim).

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);
}

Então, para restaurá-lo

setRequestedOrientation(prevOrientation);
ProjectJourneyman
fonte
Coisas boas - não sei por que você não usou um switchembora.
Esqueci de limpar e mudar para um switch depois de adicionar a terceira opção.
ProjectJourneyman de
Achei que isso funciona sem ter que obter a configuração atual se você não tiver acesso ao objeto de atividade, mas apenas ao contexto ActivityInfo.SCREEN_ORIENTATION_NOSENSOR | ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
max4ever
8
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
}
tdjprog
fonte
Você poderia acrescentar alguma explicação à sua resposta?
slfan
quando você tiver alguns trabalhos em segundo plano, basta chamar setLockScreenOrientation (true) para bloquear a orientação e evitar a destruição da atividade atual para recriá-la. ao garantir que esses trabalhos sejam concluídos, chame setLockScreenOrientation (false).
tdjprog
2
Esta é a melhor resposta !
Fakher de
7

Aqui está uma solução que sempre funciona e preserva a orientação atual (usando Activity.Info.SCREEN_ORIENTATION_PORTRAITconjuntos de 0 ° por exemplo, mas o usuário pode ter uma orientação de 180 ° como a atual).

// 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);
}
Adrien Cadet
fonte
2
Vale a pena mencionar: API 18+ apenas
Dmitry Zaytsev
1

use ActivityInfo.SCREEN_ORIENTATION_USERse quiser girar a tela apenas se estiver habilitado no dispositivo.

Pawan Maheshwari
fonte
1

Isso funciona prefeito para mim. Resolve o problema com diferentes "orientações naturais" do tablet / telefone;)

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);
    }
Naxos
fonte
0

Eu descobri uma solução que depende da rotação da tela e então decide a orientação do dispositivo. Conhecendo a orientação, podemos bloquear a orientação e liberá-la mais tarde, quando necessário. Esta solução também pode determinar se o dispositivo está no modo paisagem reversa .

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;
    }
}

Depois, se precisarmos liberar a orientação, podemos chamar este método:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
Mansour Fahad
fonte
0

Acho que este código é mais fácil de ler.

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);
            }
    }
}
nor_miya
fonte
0

Eu descobri que uma combinação de valores de rotação / orientação existentes são necessários para cobrir as quatro possibilidades; há os valores retrato / paisagem e a orientação natural do dispositivo. Digamos que a orientação natural dos dispositivos terá um valor de rotação de 0 grau quando a tela estiver na orientação retrato ou paisagem "natural". Da mesma forma, haverá um valor de rotação de 90 graus quando estiver em paisagem ou retrato (observe que é o oposto da orientação a 0 graus). Portanto, os valores de rotação que não são 0 ou 90 graus implicarão na orientação "Reversa". Ok, aqui está um código:

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 );
}
Magic Hands Pellegrin
fonte
0

Não gostei da maioria das respostas aqui, pois no desbloqueio eles definiram como NÃO ESPECIFICADO ao contrário do estado anterior. O ProjectJourneyman levou isso em consideração, o que foi ótimo, mas eu preferia o código de bloqueio do Roy. Portanto, minha recomendação seria uma mistura dos dois:

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);
    }
}
Gadzair
fonte
0

Você pode usar

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;
    }
}
moviehay0032
fonte
-1

use aquela linha de código

this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);  

no seu método de criação de atividade

Zeeshan Akhter
fonte