0

I was not able to find any tutorial on how to make a launcher app for android tv. So I went with a video which showed to make a phone launcher app. This is the video.

However I didnot completely copy cat the code in video because I knew about the required dependencies and libraries of an android tv app. The main problem is that my tv emulator is not showing the option to change the launcher. In the video its shown at 20:19 that after the emulator opens, pressing the home button asks which launcher to use but I'm not getting any such dialog box after pressing the home button also I'm not getting any errors so I'm pretty much stuck here.

App will not launch any activity at default

Here's the code:

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tvapp.myapplication">

    <uses-feature
        android:name="android.hardware.touchscreen"
        android:required="false" />
    <uses-feature
        android:name="android.software.leanback"
        android:required="true" />

    <application
        android:allowBackup="true"
        android:banner="@drawable/banner"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/Theme.MyApplication">
        <activity
            android:name=".AppListActivity"
            android:exported="true">
            <intent-filter>
                <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:launchMode="singleTask"
            android:stateNotNeeded="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.HOME" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    </application>

</manifest>

themes.xml

<resources>

    <style name="Theme.MyApplication" parent="@style/Theme.Leanback.Browse" />
</resources>

MainActivity

public class MainActivity extends FragmentActivity {

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

        Button btn = findViewById(R.id.button);
        btn.setOnClickListener(view -> {
            Intent intent = new Intent(getApplicationContext(), AppListActivity.class);
            startActivity(intent);
        });
    }

    @Override
    public void onBackPressed() {
        // do nothing
    }
}

AppListActivity

public class AppListActivity extends FragmentActivity {

    private PackageManager manager;
    private List<Item> apps;

    private ListView list;

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

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

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

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

        List<ResolveInfo> availableActivities = manager.queryIntentActivities(intent, 0);
        for(ResolveInfo ri : availableActivities) {
            Item app = new Item();
            app.label = ri.activityInfo.packageName;
            app.name = ri.loadLabel(manager);
            app.icon = ri.loadIcon(manager);
            apps.add(app);
        }
    }

    private void loadListView() {
        list = findViewById(R.id.list);

        ArrayAdapter<Item> adapter = new ArrayAdapter<Item>(this, R.layout.item, apps) {
            @NonNull

            @Override
            public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent)
            {
                if (convertView == null) {
                    convertView = getLayoutInflater().inflate(R.layout.item, null);
                }

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

                TextView appName = convertView.findViewById(R.id.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) {
                Intent intent = manager.getLaunchIntentForPackage(apps.get(position).label.toString());
                startActivity(intent);
            }
        });
    }
}

Item.java

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

main activity layout

<RelativeLayout 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"
    tools:context=".MainActivity">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/button"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="APPS" />

</RelativeLayout>

AppListActivity layout

<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:orientation="vertical"
    tools:context=".AppListActivity">
    
    <ListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/list"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:layout_marginTop="10dp"
        android:layout_marginBottom="10dp"
        android:background="#ffffff">

    </ListView>

</LinearLayout>

Items layout

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:padding="10dp">
    
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/icon"
        android:scaleType="centerInside" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/name"
        android:layout_marginTop="10dp"
        android:textSize="18sp" />

</LinearLayout>
Matt Ke
  • 3,599
  • 12
  • 30
  • 49
  • Hi, could you create a new laucher for Android TV? I tried yor code but I cannot see the laucher selection. – Tobia Jun 06 '23 at 12:33

1 Answers1

0

The android.intent.category.HOME and .DEFAULT categories should be in the AppListActivity intent filter (that has LEANBACK_LAUNCHER), to indicate that your app is a launcher for TV devices.

Harry Coder
  • 2,429
  • 2
  • 28
  • 32
sander
  • 1
  • 1