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>