주니어개발자_ฅʕ•̫͡•ʔฅ

Android 앱 런처 만들기2 (홈 만들기, 앱 추가하기) 본문

AndroidStudio

Android 앱 런처 만들기2 (홈 만들기, 앱 추가하기)

뚜비뚜밥_98 2021. 8. 17. 14:59

홈 앱에 내가 원하는 앱을 선택하여 추가하고자 한다.

 

↓↓내가 참고한 사이트↓↓

https://code.tutsplus.com/tutorials/build-a-custom-launcher-on-android--cms-21358

 

Build a Custom Launcher on Android

Introduction In its most basic form, a launcher is an application that does the following: it represents the home screen of a device it lists and launches applications that are installed on the...

code.tutsplus.com

 

일단 본인은 홈 앱에서 필요한 앱만 선택하여 추가하려고 한다.

위의 사이트에서 스마트 폰의 앱들을

리스트로 보여주는 부분이 구현되어 있기에 참고하면 좋다.

 

위의 사이트에서 구현한 앱은

홈 앱에서 버튼 클릭 → 앱 리스트에서 앱 클릭 → 앱 실행

위의 순서로 앱이 실행되는데

 

본인은 여기에 살짝 추가하여

홈 앱에서 버튼 클릭 → 앱 리스트에서 앱 클릭 → 선택된 앱 정보 홈앱에 추가됨 → 홈에 추가된 앱 클릭 → 앱 실행

순으로 실행되는 것을 구현하고자 한다.

 

일단 설명은 여기까지

밑에서 부터는 구현순서

 

먼저 앱을 런처앱(홈 앱)으로 바꿔준다.

일반 앱 런처 앱으로 바꾸기 ( feat.홈버튼, 뒤로가기, 메뉴버튼 막기 )

 

Android app을 앱 런처로 만들기 (홈 만들기)

태블릿이나 핸드폰을 켰을때 직접 만든 앱이 홈화면으로 지정되어 켜졌으면 해서 알아봤다. 먼저 앱 런처를 만들기 위해서 참고한 사이트 https://beomseok95.tistory.com/134 안드로이드 앱런처 만들기

toubi-tobap.tistory.com

매니페스트에

<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.HOME"/>

위의 두줄을 추가한 후

 

해당 앱이 실행되는 액티비티에

<activity android:name=".MainActivity"
android:launchMode="singleTask">

"singleTask"를 추가해 주면 된다.

 

본인은 MainActivity에 추가했지만

다른 액티비티로 넘어갈때가 있기때문에

넘어갈 다른 액티비티에도 추가해 줬다.

 

홈 앱으로 변경이 완료됬다면

이제 앱들을 리스트로 가져와 보도록 하자.

 

앱 리스트를 보여줄 레이아웃에 리스트뷰 작성

activity_apps_list.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ListView
        android:id="@+id/apps_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

 

앱 리스트 보여줄 인터페이스(Class) 작성

AppDetail.class

public class AppDetail {
    CharSequence label;
    CharSequence name;
    Drawable icon;
}

 

앱 리스트 보여줄 클래스 작성(Activity)

AppsListActivity.class

public class AppsListActivity extends MainActivity {

    private PackageManager manager;
    private List<AppDetail> apps;

    private ListView list;
    private View header;

    private Intent i;

    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_apps_list);

        header = getLayoutInflater().inflate(R.layout.activity_main,null,false);

        i = getIntent();

        loadApps();
        loadListView();
        addClickListener();
    }

    private void loadApps(){
        manager = getPackageManager();
        apps = new ArrayList<AppDetail>();

        Intent intent = new Intent(Intent.ACTION_MAIN, null);
        intent.addCategory(Intent.CATEGORY_LAUNCHER);

        List<ResolveInfo> availableActivities = manager.queryIntentActivities(intent,0);

        for(ResolveInfo ri:availableActivities){
            AppDetail app = new AppDetail();

            app.label = ri.loadLabel(manager); //앱 이름
            app.name = ri.activityInfo.packageName; // 앱 주소
            app.icon = ri.activityInfo.loadIcon(manager); // 앱 아이콘
            apps.add(app);
        }
    }

    private void loadListView(){

        list = (ListView)findViewById(R.id.apps_list);
        ArrayAdapter<AppDetail> adapter = new ArrayAdapter<AppDetail>(this,R.layout.list_item, apps){
            @Override
            public View getView(int position, View convertView, ViewGroup parent){
                if(convertView == null){
                    convertView = getLayoutInflater().inflate(R.layout.list_item, null);
                }

                ImageView appIcon = (ImageView)convertView.findViewById(R.id.item_app_icon);
                appIcon.setImageDrawable(apps.get(position).icon);

                TextView appLabel = (TextView) convertView.findViewById(R.id.item_app_label);
                appLabel.setText(apps.get(position).label);

                TextView appName = (TextView) convertView.findViewById(R.id.item_app_name);
                appName.setText(apps.get(position).name);

                return convertView;
            }
        };

        list.setAdapter(adapter);
    }

// 앱 리스트에서 아이템(앱) 클릭시 이벤트
    private void addClickListener(){
        list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                ByteArrayOutputStream stream = new ByteArrayOutputStream();

				// 앱 이름(String 형) MainActivity로 보내주기 위한 intent Extra
                // Extra의 name : label
                // value : apps.get(position).label
                i.putExtra("label",apps.get(position).label); 
                
                
                // 앱 주소(Strign 형) MainActivity로 보내주기 위한 intent Extra
                // Extra의 name : name
                // value : apps.get(position).name
                i.putExtra("name",apps.get(position).name); 
                
                // 앱 아이콘(bitmap to byte[] : 비트맵을 바이트배열로 변환 후 보냄)
                // MainActivity로 보내주기 위한 intent Extra
                Drawable d = apps.get(position).icon;

                Bitmap bitmap = ((BitmapDrawable)d).getBitmap();
                bitmap.compress(Bitmap.CompressFormat.JPEG,100,stream);
                byte[] byteArray = stream.toByteArray();
                
				// Extra의 name : icon
                // value : byteArray
                i.putExtra("icon",byteArray);
                
                // 위의 정보를 MainActivity(홈 클래스)로 보내기위한 신호
                setResult(RESULT_OK, i);
                finish();
                
            }
        });
    }

}

 

앱 리스트 클래스를 작성했다면

매니페스트에 추가해 주는 것을 잊지 말자!!

 <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Design.NoActionBar">
        <activity android:name=".MainActivity"
            android:launchMode="singleTask">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <!--        홈 런처 만들때 필요한 선언        -->
                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="android.intent.category.HOME"/>

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!--        앱 리스트 클래스 추가        -->
        <activity android:name=".AppsListActivity"
            android:launchMode="singleTask"/>

 

홈으로 사용할 레이아웃에 이미지 버튼 추가

본인은 버튼 6개를 만들었지만 포스팅이 길어지므로 하나만 넣었음

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    tools:context=".MainActivity">


 <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="15dp"
            android:orientation="vertical">
            
            <!--    앱 실행할 imageButton      -->
            <ImageButton
                android:id="@+id/image_btn_1"
                android:layout_width="120dp"
                android:layout_height="120dp"
                android:scaleType="fitCenter"
                android:background="@android:color/transparent"
                android:onClick="OnClick"
                android:src="@drawable/add_app"/>
        <!--    fitCenter 은 이미지 버튼에 들어갈 이미지를 버튼 크기에 맞추는거? 무튼 그런거      -->
        <!--    add_app은 임의로 넣어둔 버튼 이미지, 없어도 상관 없음      -->


        <!--    앱 이름 보여줄 TextView      -->
            <TextView
                android:id="@+id/btn1_label"
                android:layout_gravity="center"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
        </LinearLayout>
        
</LinearLayout>

 

홈 클래스 작성

MainActivity.class

public class MainActivity extends AppCompatActivity {

    private ImageButton btn1;
    private TextView btn1_label;

    private ArrayList<String> names = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        View decorView = getWindow().getDecorView();

        // 상태 표시줄을 숨김
        int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
        decorView.setSystemUiVisibility(uiOptions);   

		// 본인은 이미지 버튼 6개를 사용했었기에
        // 앱 이름을 리스트로 받아 사용하였음
        // ArrayList 사용하지 않고 그냥 String 형으로 받아서 사용해도 상관없음
        
        names = new ArrayList<>();
        for (int i = 0; i < 6; i++) {
            names.add(i, "");
        }
        
        btn1 = (ImageButton) findViewById(R.id.image_btn_1);
        btn1_label = (TextView) findViewById(R.id.btn1_label);

        btn1.setOnClickListener(view -> {
        Intent intent = new Intent(this, AppsListActivity.class);
          startApp(btn1_label.getText().toString(), intent, 1);
        });

    }

    /** 
      * 구현 한 홈 앱을 스마트폰이나 태블릿에서
      * 항상 홈으로 할 수 있게 지정하면
      * 뒤로가기나 메뉴키나 홈키를 눌러도 나가지지 않고
      * 유지되기 때문에 따로 막지 않아도 된다.
      **/

    public void startApp(String textView, Intent intent, int num) {
        PackageManager manager = this.getPackageManager();

		// 이미지 버튼에 선택된 앱이 없다면 앱 리스트 보이기
        if (textView == "") startActivityForResult(intent, num);
        // 이미지 버튼에 선택된 앱이 있다면 앱 실행
        else {
            Intent activity = manager.getLaunchIntentForPackage(names.get(num - 1).toString());
            activity.addCategory(Intent.CATEGORY_LAUNCHER);
            startActivity(activity);
        }
    }
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (resultCode == RESULT_OK) {

            Toast.makeText(getApplicationContext(), "앱이름 : " + data.getStringExtra("label") +
                    "\n앱주소 : " + data.getStringExtra("name"), Toast.LENGTH_SHORT).show();

            byte[] arr = data.getByteArrayExtra("icon");
            Bitmap bitmap = BitmapFactory.decodeByteArray(arr, 0, arr.length);

            // requestCode == 1로 호출한 경우에만 처리
            // 위에서 startActivityForResult(intent,1); >> 이부분
           
            if (requestCode == 1) {
            
            // data.getStringExtra("label") 이부분은
            // AppsListActivity에서 label이란 이름으로 보낸 String 값(앱 이름)을 가져오는 것이다.
            // data.getStringExtra("name") 이부분은 name이라는 이름으로 String 값 보냄(앱 주소)
            
                addApp(bitmap, btn1, btn1_label, 0,
                        data.getStringExtra("label"), data.getStringExtra("name"));
            } 
            
            
// 			  버튼을 여러개로 해놓고 사용한다면
// 			  밑에 주석 친 부분 처럼 추가해서 사용하면 된다.
           
//            if (requestCode == 2) {
//                addApp(bitmap, btn2, btn2_label, 1,
//                        data.getStringExtra("label"), data.getStringExtra("name"));
//            } 

        }
    }

    private void addApp(Bitmap bitmap, ImageButton btn, TextView textView, int indexNum, String label, String name) {
        btn.setImageBitmap(bitmap);
        textView.setText(label);
        names.add(indexNum, name);
    }

}

홈에 추가한 앱의 정보를

계속 유지하게 하고 싶다면

 

Android 앱 런처 만들기3 (sqlite이용, 내부저장소에 앱 정보 저장)

오늘은 저번에 만들었던 런처 앱에서 앱을 추가한 뒤 스마트폰의 전원을 껐다가 켜도 그 정보가 유지될 수 있도록 앱 이름과 앱 위치명, 앱 로고를 내부 저장소에 저장하려고 한다 내부 저장소

toubi-tobap.tistory.com