반응형

Night mode 의 각 모드에 대한 설명과 각 모드가 어떻게 동작하는지 예제를 만들어보았습니다.

 

먼저 Night mode는 아래와 같은 모드를 가지고 있습니다.

모드명 설명 참고
MODE_NIGHT_UNSPECIFIED 야간 모드에 대해 지정되지 않은 모드입니다. 기본 야간 모드를 사용하기 위해 이것은 주로 setLocalNightMode ()와 함께 사용되어 기본 야간 모드를 사용할 수 있도록합니다.

기본 모드와 로컬 야간 모드가 모두 이 값으로 설정된 경우에는MODE_NIGHT_FOLLOW_SYSTEM의 기본값이 적용됩니다.
MODE_NIGHT_FOLLOW_SYSTEM 시스템의 설정에 따라서 동작  
MODE_NIGHT_AUTO_TIME 시간(일출/일몰)에 따른 동작 Deprecated 됨
MODE_NIGHT_NO 동작안하도록 함  
MODE_NIGHT_YES 동작하도록 함  
MODE_NIGHT_AUTO_BATTERY 절전모드시 동작하도록 함  

실제 Night mode 동작 확인을 위해 각 모드별 버튼을 만들어서 버튼을 클릭한 이후 어떻게 동작하는지 확인합니다.

class MainActivity() : AppCompatActivity(){
    override fun onCreate(savedInstanceState: Bundle?) {
        val modeNightText = mapOf(-100 to "MODE_NIGHT_UNSPECIFIED", -1 to "MODE_NIGHT_FOLLOW_SYSTEM",
                0 to "MODE_NIGHT_AUTO_TIME", 1 to "MODE_NIGHT_NO",
                2 to "MODE_NIGHT_YES", 3 to "MODE_NIGHT_AUTO_BATTERY")

        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val textModeNight : TextView = findViewById(R.id.tvModeNight)

        findViewById<View>(R.id.btnModeNightFollowSystem).setOnClickListener {
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
            textModeNight.text = modeNightText[AppCompatDelegate.getDefaultNightMode()]
        }
        findViewById<View>(R.id.btnModeNightAutoTime).setOnClickListener {
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_TIME)
            textModeNight.text = modeNightText[AppCompatDelegate.getDefaultNightMode()]
        }
        findViewById<View>(R.id.btnModeNightNo).setOnClickListener{
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
            textModeNight.text = modeNightText[AppCompatDelegate.getDefaultNightMode()]
        }
        findViewById<View>(R.id.btnModeNightYes).setOnClickListener {
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
            textModeNight.text = modeNightText[AppCompatDelegate.getDefaultNightMode()]
        }
        findViewById<View>(R.id.btnModeNightAutoBattery).setOnClickListener {
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY)
            textModeNight.text = modeNightText[AppCompatDelegate.getDefaultNightMode()]
        }

        textModeNight.text = modeNightText[AppCompatDelegate.getDefaultNightMode()]
    }
}

 

나이트 모드별 버튼을 가지고 있고, 마지막 버튼 아래에는 현재 동작중인 모드가 무엇인지 테스트 표시됩니다.

 

시간(주/야), 절전여부, 시스템 설정(Night mode 여부)에 따른 동작 결과

주간 / 절전 x / 시스템 설정 (Night mode x)

 

주간 / 절전 x / 시스템 설정 (Night mode o)

 

주간 / 절전 o / 시스템 설정 (Night mode x)  

 

주간 / 절전 o / 시스템 설정 (Night mode o)

 

야간 / 절전 x / 시스템 설정 (Night mode x)

 

야간 / 절전 x / 시스템 설정 (Night mode o)

 

야간 / 절전 o / 시스템 설정 (Night mode x)

 

야간 / 절전 o / 시스템 설정 (Night mode o)

 

 

반응형

안드로이드 레이아웃 XML의 android:visibility 속성은 View를 보이거나 사라지게 하는 역할을 하며 3가지 상태(visible, invisible, gone)가 있습니다.

 

디폴트는 visible이라서 별도로 아래처럼 명시하지 않더라도 View는 보이게 됩니다.

다른 2가지 상태인 invisible과 gone은 View를 사라지게 합니다.

다만 이 둘의 차이는 invisible은 View 공간을 유지하면서 사리지고, gone은 View 공간을 유지하지 않고 사라집니다.

 

이게 무슨 의미가 있겠냐 싶지만 분명히 존재의 의미가 있고 필요하다는 것을 아래 예를 들어보도록 하겠습니다.

 

먼저 간단하게 아래와 같이 이미지 버튼으로 4개와 1개의 텍스트 뷰로 구성된 ConstraintLayout을 만들었습니다.

가운데 3개의 이미지 버튼들은 Spread 스타일의 Chain으로 만들어져 있습니다.

위쪽 이미지 버튼과 아래쪽 텍스트 뷰의 경우 각각 가운데 이미지 버튼들과 가장자리 위치의 중간되는 곳에 위치하고 있습니다.

 

정중앙 버튼의 android:visibility 속성을 invisible과 gone으로 변경해서 테스트해보겠습니다.

관찰 포인트는 가로로 버튼들이 균등하게 위치 여부,

                  상단 이미지 버튼과 하단의 텍스트뷰의 원래 위치 유지 여부 입니다.

 


#테스트 1 (android:visibility="invisible" 로 설정한 경우)

아래 왼쪽 그림에 정중간 버튼이 사라진 것이 확인되고, 오른쪽 그림(Blueprint)에는 정중간 버튼이 공간을 유지하고 있는 것이 확인됩니다. 다른 뷰와의 연결도 문제가 없고, 모든 뷰들의 위치도 동일합니다.

다만, 가운데 이미지 버튼들이 하나 사라졌음에도 나머지 2개의 버튼들이 다시 정렬되어서 균등하게 위치되지 않고 원래 자리를 유지하고 있습니다.

용도: 다른 뷰의 위치와 크기에 영향을 주지 않고 사라지게 할 목적인 경우에 유용


#테스트 2 (android:visibility="gone" 으로 설정한 경우)

마찬가지 중간 버튼이 사라졌지만, 오른쪽 그림(Blueprint)에는 원래 자리를 차지하고 있던 위치에 공간이 제거되었으며 다른 뷰들의 위치가 조금씩 이동된 것이 확인됩니다.

위치가 변경되면 안되는 상단의 이미지 버튼과 하단의 텍스트 뷰까지 조금씩 위치가 바뀌었습니다. (마지막에 추가 설명)

그렇지만, 가운데 이미지 버튼들의 경우 남아있던 나머지 2개가 다시 정렬되면서 균등하게 위차하고 있습니다.

용도: 사라지는 뷰와 연동해서 다른 뷰들의 위치나 크기 조절이 필요한 경우에 유용

상단의 이미지 버튼과 하단의 텍스트 뷰의 경우 위치가 이동이 되었는데 이유는 아래 그림을 참조하시면 됩니다.

정중앙 버튼(id=>imageButtonCenter)의 Bottom과 Parent의 Bottom 간의 중앙에 위치하도록 되어 있는데, 정중앙 버튼이 사라지면서 공간도 제거되고 연결된 것도 우측 이미지 버튼의 가운데를 가르키면서 전체적으로 위쪽으로 조금씩 이동하게 된 것입니다.

<TextView
    android:id="@+id/textView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Are you ready?"
    android:textAppearance="@style/TextAppearance.AppCompat.Large"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/imageButtonCenter" />

 

이제 어떤 경우에 View의 invisible 또는 gone을 사용하는지 이해가 되셨을 것으로 생각됩니다.

이번 글은 여기까지입니다. 읽어주셔서 감사합니다.

반응형

제가 사용 중인 괜찮은 툴 소개해드립니다.

 

Codota (코도타)라는 툴인데 설치는 안드로이드 스튜디오의 플러그인(File-Settings-Plugins)에서 Codota를 검색하셔서 설치하면 됩니다.

 

플러그인 설치하는 방법을 모르시면 아래에 링크를 보시면 쉽게 하실 수 있습니다. 정말 간단합니다..

안드로이드 스튜디오에 설치방법

https://www.codota.com/get#android-studio

 

Codota - AI Code Completions for your IDE

Codota understands the world's code and provides you with the right suggestion at the right time

www.codota.com


Codota(코도타)?

Codota는 코딩 보조툴로 아래에 플러그인을 보면 AI Code completions이라고 간단히 기술되어 있습니다.

 

Android studio plugin: Codota

그런데, 코드 완성(Code completions) 기능은 안드로이드 스튜디오에서 자체 내장되어 있으며 메뉴(Code-Completion)에 세부 설정 변경도 가능합니다.

 

그러면, Codota는 안드로이드 스튜디오의 자동 완성 기능과 어떤 차별점을 가지고 있을까요?

AI 기반 (학습에 의한 코드 제시)

개발자가 코드 입력 시머신러닝 기반으로 제안된 Code completion의 작동합니다.

즉, 수백만 개의 소스 코드들에서 학습한 결과를 제시해서 보여줍니다.

 

아래 중에 어떤 것이 코딩하는데 더 도움을 줄까요?

[왼쪽: Codota의 Code completion] - [오른쪽: Android studio의 Code complettion]

Codota의 Code completion이 시각적으로도 그렇고, 통계적으로 정렬해서 이후 사용 가능성이 있는 메서드를 추천해주고 있습니다.

[왼쪽: Codota의 Code completion] - [오른쪽: Android studio의 Code complettion]

 

스니펫 제공

메서드를 사용한 예제(스니펫)가 필요할 경우에는 해당 메서드에 커서를 올려두고 우측 클릭 후 나오는 콘텍스트 메뉴에서 Get relevant examples 또는 단축키로 Ctrl+Shift+O 를 누르면 훌륭한 스니펫이 제공됩니다.

해당 메서드에서 우측 클릭후 나오는 콘텍스트 메뉴

위의 setOnClickListener에 대해서 관련 스니펫을 요청한 경우에 아래의 오른쪽과 같이 제공됩니다. 

우측에 나타나는 해당 메서드의 스니펫들

저의 경우에 Ctrl 키를 두 번 클릭해서 스니펫들을 볼 수 있도록 설정해서 사용하고 있습니다.

(Codota의 설정(Welcome - settings)에 가면 옵션이 존재합니다) 

 

Codota의 대략적인 소개는 여기까지이며 개발하는데 도움이 되길 바랍니다.

 

반응형

GetAppInfo 클래스에서는 넘겨받은 패키지명을 가지고 Play 스토어의 해당 페이지로 가서 앱 이름과 버전에 해당하는 element의 값을 Jsoup 라이브러리를 이용해서 구하게 됩니다.

public class GetAppInfo extends AsyncTask<Void, String, Boolean> {
    private String appPackageName;
    private String appName;
    private String appVersion;

    public GetAppInfo(String packageName) {
        appPackageName = packageName;
    }

    @Override
    protected Boolean doInBackground(Void... strings) {
        Elements elementsAppName;
        Elements elementsAppVersion;
        boolean result = false;
        try {
            String AppFromPlayStore = "https://play.google.com/store/apps/details?id=" + appPackageName;
            Document doc = Jsoup.connect(AppFromPlayStore).get();
            elementsAppName = doc.select("div > div.sIskre > c-wiz:nth-child(1) > h1 > span");
            if (elementsAppName.size() != 0) {
                appName = elementsAppName.text();
            } else {
                elementsAppName = doc.select("div > div.sIskre > c-wiz:nth-child(2) > h1 > span");
                if (elementsAppName.size() != 0) {
                    appName = elementsAppName.text();
                } else {
                    appName = "Crawling code(App Name) needs to be changed.";
                }
            }
            elementsAppVersion = doc.select("div > div:nth-child(4) > span > div > span");
            if (elementsAppVersion.size() != 0) {
                appVersion = elementsAppVersion.text();
            } else {
                appName = "Crawling code(App Version) needs to be changed.";
            }
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

실제 테스트한 앱은 아래와 같은 화면을 구성하고 있습니다.

패키지명을 입력하고 버튼을 누르면 Play 스토어에서 크롤링해 온 앱 이름과 버전을 표시해줍니다.

왼쪽: 버튼 누르기 전, 오른쪽: 버튼 누른 후 

아래처럼 여러 경우에 따라서 App name과 App version에 표시해주는 정보가 달라집니다.

        btnGetAppInfo = findViewById(R.id.btnGetAppInfo);
        btnGetAppInfo.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                hideKeyboard();

                if (isNetwork()) {
                    try {
                        getAppInfo = new GetAppInfo(etPackageName.getText().toString());
                        if (getAppInfo.execute().get()) {
                            tvAppName.setText(getAppInfo.getAppName());
                            tvAppVersion.setText(getAppInfo.getAppVersion());
                        } else {
                            tvAppName.setText("N/A (The package name app does not exist on the Play Store.)");
                            tvAppVersion.setText("N/A (The package name app does not exist on the Play Store.)");
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        tvAppName.setText("N/A (Error)");
                        tvAppVersion.setText("N/A (Error)");
                    }
                } else {
                    tvAppName.setText("N/A (No internet connection)");
                    tvAppVersion.setText("N/A (No internet connection)");
                }
            }
        });

 

위의 예제 소스를 첨부하였으니 참고하세요.

CrawlingAppInfo.zip
0.14MB

 

 

반응형

얼마 전 삼성개발자사이트에 들어가서 둘러보다가 아래와 같이 삼성 카메라 SDK 지원 중단이 된다는 공지를 보았습니다.

 

As of Dec. 1, 2019, the Camera SDK(v1.0.0 - v1.3.2) is deprecated on all devices. We reget any inconvenience.

그 아래에 몇 개월 전 배포된 SDK 버전이 처량하게 보입니다.

 

 

외부 개발자들을 참여시켜서 기존 Android 카메라 API에서 지원하지 않는 삼성 폰의 카메라 확장기능을 지원하고자 시작한 것 같은데 아쉽다는 생각이 들었습니다.

 

SDK가 별거 아니라고 생각하는 분도 계실 수 있지만, SDK 개발하고 검증하고 배포한 이후 유지 보수하는 데는 많은 시간이 걸립니다.

 

왜 지원을 중단했는지 나름대로 생각을 해보니 구글에서 발표한 CameraX와 연관이 있는 것 같습니다.

 

관련한 근거로 SDC(삼성 개발자 컨퍼런스)에 발표된 아래 영상이 19.11월 초에 올라왔습니다.

 

제목이 Introducing the CameraX with Samsung인데, 구글의 안드로이드 카메라 프레임워크쪽 PM이 등장합니다.

 

CameraX 기능도 삼성 카메라 SDK와 중복되는 것이 많습니다.

 

향후 2개가 동시에 존재하는 것이 불가능한 것이 "카메라 확장 기능"을 위해서 삼성 카메라 SDK보다 여러 단말 벤더들도 지원할 수 있는 CameraX를 개발자들이 선호하게 될 것이기에 어쩔 수 없는 선택이었다고 생각됩니다.

 

삼성 입장에서는 아쉬울 수도 있지만, 뻔한 결과가 보이는 것을 계속 붙잡고 있을 수는 없는 거니깐요.

 

구글 입장에서 삼성은 아주 고마운 존재일 것 입니다.

 

새로운 기술이나 하드웨어에 대해서 삼성이 앞장서서 나가주고 검증을 해주니깐요.

 

일례로 지금은 당연히 카메라가 2개 이상 지원하지만 전에는 안드로이드 초기에는 Camera API에서 1개의 카메라만 지원했습니다.

 

(제가 기억하기로는) 삼성이 먼저 피처폰에서처럼 전면 카메라를 넣어주었죠. 이후 구글은 Camera API에 다수 카메라 지원하도록 적용하였고요.

 

작년 갤럭시 폴드 개발 시에는 폴더블 API 지원이 되도록 구글에서 많은 공조가 있었을 것입니다.

 

이번 글은 여기까지입니다. 읽어주셔서 감사합니다. 

 

반응형

Camera API를 어떻게 사용하는지 궁금할 때 참조할 수 있는 좋은 방법을 알려 드리겠습니다.

 

안드로이드 단말이 GMS를 탑재하고 구글의 승인을 받으려면 구글의 요구하는 조건을 만족시켜줘야 합니다.

 

기본적으로 CDD부터 프레임워크 호환성 확인을 위한 CTS 등 여러 테스트를 거치게 됩니다.

 

이중 CTS는 안드로이드 플랫폼에서 프레임워크 동작의 신뢰성을 위한 각종 API를 테스트합니다.

 

이 테스트 코드는 구글에서 작성하였고 소스가 오픈되어 있습니다.

 

예를 들어보겠습니다.

 

Camera API 중에서 setFocusMode를 어떻게 사용하는지 궁금하면 구글 검색으로 stackoverflow.com에 참고할 수 있는 대부분의 답변이 나옵니다.

 

아래의 경우는 setFocusMode가 동작하지 않는다는 문의와 답변입니다.

(관련 링크: https://stackoverflow.com/questions/11623266/camera-parameters-setfocusmode-is-not-working)

  

 

 

 

 

간결하고 문제 해결을 위한 무난한 답변입니다.

 

위의 문제는 지원하지 않는 Camera Focus mode를 사용하려고 해서 발생하는 문제였습니다.

 

답변에서는 지원 여부를 체크(getSupportedFocusModes)해서 지원하면 설정(setFocusMode)하게 처리되어 있습니다.

 

그럼, CTS 쪽에서는 어떻게 사용하고 있는지 볼까요?

 

여기에서도 체크(getSupportedFocusModes)후 지원하면 설정(setFocusMode)하게 처리되어 있습니다.

 

 

stackoverflow나 cts 모두 setFocusMode 사용하는 방법에 대해서 가리키는 것은 argument인 focus mode가 지원하는지 getSupportedFocusModes로 체크해서 지원하면 사용하도록 처리해야 한다는 것을 알 수 있습니다.

 

CTS 쪽 검색은 구글에서 아래와 같이 해주면 됩니다. (검색창에 "API명 site:android.googlesource.com/platform/cts")

 

 

CTS에 있는 모든 코드가 무결하다고 할 수는 없지만, 아무래도 구글에서 작성한 코드이기에 일정 수준이 상의 신뢰성이 보장된다고 볼 수 있습니다. stackoverflow.com에 나와 있지 않거나 거기 있는 코드가 신뢰 되지 않는다면 CTS에서 코드를 찾아보실 것을 권장해 드립니다.

 

이번 글은 여기까지입니다. 도움이 되셨기를 바랍니다.

+ Recent posts