Activity picker

  • 19 Antworten
  • Neuester Beitrag
Diskutiere Activity picker im Android App Entwicklung im Bereich Betriebssysteme & Apps.
N

Nonsens

Gast
Hallo alle,

ich hab ein kleines Problem und finde keine Lösung :mad2:

Das Problem:
Ich möchte in meinen Launcher eine Möglichkeit einbauen installierte APP zu starten.

Mein 1. Versuch liefert eine Tabelle mit APPS welche CATEGORY_DEFAULT im manifest haben. Das Problem ist, dass viele Entwickler im manifest vergessen dies einzutragen.
Code:
Intent intent = new Intent(Intent.ACTION_MAIN);
                    intent.addCategory(Intent.CATEGORY_LAUNCHER);
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(Intent.createChooser(intent, null));
Mein 2. Versuch liefert eine Liste mit allen APPS, auch die welche man nicht sehen will
Code:
Intent intent = new Intent(Intent.ACTION_PICK_ACTIVITY);
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(Intent.createChooser(intent, null));

Der 3. Versuch liefert eine leere Liste:
Code:
Intent intent = new Intent(Intent.ACTION_ALL_APPS);
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(Intent.createChooser(intent, null));
Grüße
 
Zuletzt bearbeitet von einem Moderator:
swa00

swa00

Moderator
Teammitglied
Hallo Nonsens,

du musst dir erst die ResolveInfo aus den Packages ermitteln und dann sowas hier

ResolveInfo clickedResolveInfo = (ResolveInfo)parent.getItemAtPosition(position); <-- kommt bei mir aus einem ListArray
ActivityInfo clickedActivityInfo = clickedResolveInfo.activityInfo;
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setClassName(clickedActivityInfo.applicationInfo.packageName,clickedActivityInfo.name);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
//Log.d("XXX",clickedActivityInfo.applicationInfo.packageName+"-"+clickedActivityInfo.name);
startActivity(intent);
Läuft bei mir ohne Probleme
 
Zuletzt bearbeitet:
N

Nonsens

Gast
swa00 schrieb:
Hallo Nonsense,

du musst dir erst die ResolveInfo aus den Packages ermitteln und dann sowas hier

ResolveInfo clickedResolveInfo = (ResolveInfo)parent.getItemAtPosition(position); <-- kommt bei mir aus einem ListArray
ActivityInfo clickedActivityInfo = clickedResolveInfo.activityInfo;
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setClassName(clickedActivityInfo.applicationInfo.packageName,clickedActivityInfo.name);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
//Log.d("XXX",clickedActivityInfo.applicationInfo.packageName+"-"+clickedActivityInfo.name);
startActivity(intent);
Läuft bei mir ohne Probleme
Danke für die Antwort. Wenn ich mir deinen Code so anschaue startet der die bereits ausgesuchte APP. Das starten Einer APP ist aber nicht das Problem, sondern einen Picker zu bauen wo der Benutzer die APP auswählen kann. Im Anhang ist ein Screenshot, welcher den aktuellen Picker anzeigt und wie oben beschrieben werden nur die APP angezeigt welche das Attribut CATEGORY_DEFAULT besitzen und das vergessen viele Entwickler anzugeben. So fehlen sehr viele APP
 

Anhänge

swa00

swa00

Moderator
Teammitglied
Das starten Einer APP ist aber nicht das Problem, sondern einen Picker zu bauen wo der Benutzer die APP auswählen kann.
Es tut mir ja leid, aber das hast du oben mit keinem Wort erwähnt. :)


Mein 1. Versuch liefert eine Tabelle mit APPS welche CATEGORY_DEFAULT im manifest haben. Das Problem ist, dass viele Entwickler im manifest vergessen dies einzutragen.
(P.S das CAT_DEF wurde nicht vergessen , sondern bewusst weggelassen)
.
-----------------------------------------------------------------------------------------------------------------------------------------
Und ich komme trotzdem auf meine Antwort von eben zurück .. diese beinhaltet bereits die Lösung :

Du musst dir eine Liste mit den ResolveInfos bauen und diese dann z.B. in einem GridView & BaseAdapter anzeigen .

Der Code darunter war nur noch das BonBon für dich - weil der ein wenig tricky ist
 
Zuletzt bearbeitet:
N

Nonsens

Gast
swa00 schrieb:
.......Du musst dir eine Liste mit den ResolveInfos bauen und diese dann z.B. in einem GridView & BaseAdapter anzeigen .
Genau das hab ich befürchtet, dass ich einen eigenen APP-Picker bauen muss. Aber das geht gegen das Konzept meines launchers. Das Konzept sieht nicht vor einen APP-Picker zu integrieren weil es dafür schon sehr viele APPs gibt die das sehr gut können. Dass ich dennoch einen APP-Picker integriert habe ist, dass der Anwender nicht den Launcher wechseln muss nur um eine APP zu installieren, die APPs starten kann :blink:

Nun, da es keinen einfache Lösung gibt, bleibt es wie es ist.

Ich danke dir dennoch um deinen Vorschlag :biggrin:

Grüße
 
swa00

swa00

Moderator
Teammitglied
Genau das hab ich befürchtet, dass ich einen eigenen APP-Picker bauen muss. Aber das geht gegen das Konzept meines launchers. Das Konzept sieht nicht vor einen APP-Picker zu integrieren weil es dafür schon sehr viele APPs gibt die das sehr gut können.
Genau vor dieser Entscheidung stand ich auch bei meinem "FullScreen" Launcher.
Man kommt m.E. nicht drumrum , denn nur so kannst du auch die entsprechenden Events & CallBack abfangen , um deinem Launcher auch ein Feedback zu geben .
Abgesehen davon , dass es sinn macht , das Layout einheitlich aussehen zu lassen , sonst wirkt es schnell "zusammengeschustert"

Und so neben bei , um dir das Leben ein wenig leichter zu machen.

a) GridView/Listview bist du ja bestimmt machtig
b) Deine Liste machste so
Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> intentList = getActivity().getPackageManager().queryIntentActivities(intent, 0);
c) Dein Sortieren so
Collections.sort(intentList, new Comparator<ResolveInfo>()
{
@override
public int compare(ResolveInfo p1, ResolveInfo p2)
{
return p1.loadLabel(myPackageManager).toString().compareToIgnoreCase(p2.loadLabel(myPackageManager).toString());
}
});
und Dein Click wie oben

Schon ist der Käse in max einer Stunde gegessen :)
 
Zuletzt bearbeitet:
N

Nonsens

Gast
swa00 schrieb:
Mein 1. Versuch liefert eine Tabelle mit APPS welche CATEGORY_DEFAULT im manifest haben. Das Problem ist, dass viele Entwickler im manifest vergessen dies einzutragen.
(P.S das CAT_DEF wurde nicht vergessen , sondern bewusst weggelassen)
Das glaube ich nicht, denn es gibt die Kategorie CATEGORY_CALCULATOR, damit sollte es möglich sein alle "Taschenrechner" sich in einer Liste anzeigen zu lassen. Aber es wird kein einziger angezeigt. Ich vermute, dass viele Entwickler einfach nicht wissen, dass sie ihre APP den default Kategorien zuordnen müssen.

Hier den manifest Eintrag meines messengers, denn ich aktuell entwickle und der wird in meinem Launcher auch richtig angezeigt.
Code:
<intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.APP_MESSAGING" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
 
swa00

swa00

Moderator
Teammitglied
Ich vermute, dass viele Entwickler einfach nicht wissen, dass sie ihre APP den default Kategorien zuordnen müssen.
Das stimmt leider nicht so - das wird als Alternative behandelt

schau dir mal bitte hierzu die Erklärung an
Intent | Android Developers

category -- Gives additional information about the action to execute. For example, CATEGORY_LAUNCHER means it should appear in the Launcher as a top-level application, while CATEGORY_ALTERNATIVE means it should be included in a list of alternative actions the user can perform on a piece of data.
und im zusammenhang mit diesem Context
The categories, if supplied, must all be listed by the activity as categories it handles. That is, if you include the categories CATEGORY_LAUNCHER and CATEGORY_ALTERNATIVE, then you will only resolve to components with an intent that lists both of those categories. Activities will very often need to support the CATEGORY_DEFAULT so that they can be found by Context.startActivity().
 
Zuletzt bearbeitet:
N

Nonsens

Gast
swa00 schrieb:
Genau das hab ich befürchtet, dass ich einen eigenen APP-Picker bauen muss. Aber das geht gegen das Konzept meines launchers. Das Konzept sieht nicht vor einen APP-Picker zu integrieren weil es dafür schon sehr viele APPs gibt die das sehr gut können.
Genau vor dieser Entscheidung stand ich auch bei meinem "FullScreen" Launcher.
Man kommt m.E. nicht drumrum , denn nur so kannst du auch die entsprechenden Events & CallBack abfangen , um deinem Launcher auch ein Feedback zu geben .
Abgesehen davon , dass es sinn macht , das Layout einheitlich aussehen zu lassen , sonst wirkt es schnell "zusammengeschustert"

Und so neben bei , um dir das Leben ein wenig leichter zu machen.

a) GridView/Listview bist du ja bestimmt machtig
b) Deine Liste machste so
myPackageManager = getActivity().getPackageManager();
Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> intentList = getActivity().getPackageManager().queryIntentActivities(intent, 0);
c) Dein Sortieren so
Collections.sort(intentList, new Comparator<ResolveInfo>()
{
@override
public int compare(ResolveInfo p1, ResolveInfo p2)
{
return p1.loadLabel(myPackageManager).toString().compareToIgnoreCase(p2.loadLabel(myPackageManager).toString());
}
});
und Dein Click wie oben

Schon ist der Käse in max einer Stunde gegessen :)
Hm, das muss ich ausprobieren. Ich denke du hast ein extra Activity dafür geschrieben. Mit ListView hab ich schon was gemacht mit GridView nicht. Bin da aber kein Experte. Mit dem PackageManager hab ich schon etwas experimentiert, bis auf die Category launcher hab ich es genau so gemacht. Jedoch wollte ich weitere Kategorien abfragen um eine intelligente Gruppierung vornehmen zu können. Wo haben die APP-Entwickler ihre APP-Infos versteckt, zum beispiel Spiele und welche Art von Spiele, usw. Das hab ich aber in der ApplicationInfo nicht gefunden :confused2:

Auf Styles und Layouts nehme ich keine Rücksicht, da mache ich es so wie es am einfachsten ist. Es sehen ja auch nicht alle Häuser gleich aus.
 
swa00

swa00

Moderator
Teammitglied
Ich denke du hast ein extra Activity dafür geschrieben
Nein , alles in Fragmenten (v4) um den LiveCycle/SingleTon sicher zu stellen, sonst bist du ganz schnell im Nirvana
 
N

Nonsens

Gast
swa00 schrieb:
Ich vermute, dass viele Entwickler einfach nicht wissen, dass sie ihre APP den default Kategorien zuordnen müssen.
Das stimmt leider nicht so - das wird als Alternative behandelt

schau dir mal bitte hierzu die Erklärung an
Intent | Android Developers
[/QUOTE]

Das hab ich mir schon durchgelesen, jedoch kann ich mit der Kategorie Alternative nicht viel anfangen. Hab mir auch mit manifestviewer einige Manifests angesehen. Und wie wird die Alternative angewendet, abgefragt?
 
swa00

swa00

Moderator
Teammitglied
Und wie wird die Alternative angewendet, abgefragt?
Mein "Alternative" war nicht auf die Categorien bezogen , sondern um dir zu verdeutlichen ,
das der Eintrag CATEGORY_DEFAULT drin sein KANN aber nicht MUSS.

Je nachdem , was der Entwickler zulassen möchte oder nicht .
Die verschiedenen Optionen sind ja dort beschrieben und lassen deinem Herzen die Wünsche offen
 
N

Nonsens

Gast
swa00 schrieb:
Und wie wird die Alternative angewendet, abgefragt?
Mein "Alternative" war nicht auf die Categorien bezogen , sondern um dir zu verdeutlichen ,
das der Eintrag CATEGORY_DEFAULT drin sein KANN aber nicht MUSS.

Je nachdem , was der Entwickler zulassen möchte oder nicht .
Die verschiedenen Optionen sind ja dort beschrieben und lassen deinem Herzen die Wünsche offen
Ach so, aber das weis ich doch bereits :biggrin:, jedoch sollte CATEGORY_DEFAULT bei der Haupt Activity drin sein. Das hab ich auch erst herausgefunden weil mein eigener Messenger nicht angezeigt wurde.

Da es keine einfache Lösung gibt ist es auf Eis gelegt, denn da muss ich einen eigenen Picker schreiben und der wird dann doch sehr umfangreich, so dass es da dann doch etwas länger dauert bis der fertig ist (fremde Picker will ich nicht nutzen) Du kannst ja mal meinen Launcher installieren (keine Angst, der tutu nichts böses) und meine menu-Lösung mal angucken und einen Kommentar schreiben :biggrin:.

Grüße
 
N

Nonsens

Gast
Hi alle,

hab nun den App-Picker programmiert. Wie man sieht ist das Ergebnis nicht zufrieden stellend. Ich verwende ImageButton als Container, und tausche das Image aus. Nun sollte der Button Hintergrund noch durchsichtig und gleich groß werden. hier den Entry-Code
Code:
<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:orientation="vertical"
   android:id="@+id/app_picker_grid_entry"
   android:background="#00000000"
   android:layout_height="100dp">

   <TextView
      android:text="xxx"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:id="@+id/app_label"
      android:layout_alignParentBottom="true"
      android:layout_alignParentEnd="true"
      android:layout_alignParentStart="true"
      android:gravity="center_horizontal" />

   <TextView
      android:text="TextView"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerVertical="true"
      android:layout_centerHorizontal="true"
      android:id="@+id/app_index"
      android:visibility="gone" />

   <ImageButton
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:src="@drawable/ic_launcher"
      android:layout_below="@+id/app_index"
      android:layout_alignParentEnd="true"
      android:id="@+id/app_image"
      android:layout_alignParentStart="true"
      android:layout_above="@+id/app_label" />

</RelativeLayout>


Screenshot_20161115-153814[1].png
 
swa00

swa00

Moderator
Teammitglied
Du musst dein Background auf

a) transparent stellen
oder
b) Custom background mit xml
oder
c) ImageView ohne Angabe

verwenden

P.S Ein Imageview hat den Vorteil , dass du einheitlich Scalieren kannst und alles gleich aussieht
(Feste Grösse setzen)

Bsp :
Code:
 <ImageView
        android:id="@+id/item_image"
        android:layout_width="80dp"
        android:layout_height="80dp">
 
N

Nonsens

Gast
@swa00

Ich hab den Post gekürzt, da der dieser Teil sowieso veraltet ist :biggrin:
Manchmal hat man halt ein Brett vom Kopf, danke :blink:

-- Dieser Beitrag wurde automatisch mit dem folgenden Beitrag zusammengeführt --
Hallo alle,


Wunderbar, nun will ich die Liste noch filtern. Aber der Filter sollte intelligent sein. Es soll das menu (siehe Screenshot) welches nun mit vorgegeben Kategorien befüllt ist mit dynamischen Kategorien befüllt werden. Also Spiele, Tools, Mail, Doc usw. so wie es im Playstore Kategorisiert ist. Eine denkbare Lösung wäre im Playstore nachzuschauen wie es dort Kategorisiert ist.Hat jemand eine einfache Lösung :confused2:


Screenshot_20161115-181721[1].png
 

Anhänge

Zuletzt bearbeitet von einem Moderator:
N

Nonsens

Gast
swa00 schrieb:
Hallo Nonsens,

du musst dir erst die ResolveInfo aus den Packages ermitteln und dann sowas hier

ResolveInfo clickedResolveInfo = (ResolveInfo)parent.getItemAtPosition(position); <-- kommt bei mir aus einem ListArray
ActivityInfo clickedActivityInfo = clickedResolveInfo.activityInfo;
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setClassName(clickedActivityInfo.applicationInfo.packageName,clickedActivityInfo.name);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
//Log.d("XXX",clickedActivityInfo.applicationInfo.packageName+"-"+clickedActivityInfo.name);
startActivity(intent);
Läuft bei mir ohne Probleme
Danke noch für das Beispiel, das hat mir nun sehr geholfen :thumbsup:

grüße
 
swa00

swa00

Moderator
Teammitglied
Schön , dass man dir helfen konnte :)

Man sieht / liest sich
 
N

Nonsens

Gast
swa00 schrieb:
Schön , dass man dir helfen konnte :)

Man sieht / liest sich
die Variante im Post #16, siehe Screenshots, hab ich aufgegeben weil zu kompliziert und es auch nicht Idee-konform ist. Das Menu und den APP-Picker hab ich als Fragmente im Launcher integriert. Beide warten im Hintergrund bis sie gebraucht werden. Allerdings ruckelt meine GridView noch sehr obwohl ich Tag verwende. Hat ein Weilchen gedauert bis ich das mit den Tag geschnallt hab. Und wie du unschwer erkennen kannst findest du deinen Beispielcode in angepasster Form wieder :thumbsup:. Da der APP-Picker im Hintergrund auf Eingabe lauert mach ihn super schnell beim Aufruf. Ich frag mich ob es eine Möglichkeit gibt, den kompletten GridView im Hintergund komplett zu befüllen was das Scrollen wohl extrem beschleunigen würde :confused2:

Wie auch immer, nun kommt der leichte Teil und das Update ist fertig :rolleyes2:

Ups, hab grad enteckt, dass dein Codebeispiel in der anderen date ist :blink: hier den Code

Der APP-Picker schickt die Daten an den launcher und dieser startet dann die App

Code:
 protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);

        String action = intent.getAction();
        Bundle bundle = intent.getExtras();

     
[cut]     

        else if(action.equals(ACTION_START_ACTIVITY)){
            menu_container.setVisibility(View.GONE);

            Intent intX = new Intent(Intent.ACTION_MAIN);
            intX.addCategory(Intent.CATEGORY_LAUNCHER);
            intX.setClassName(intent.getStringExtra(KEY_PACKAGE_NAME), intent.getStringExtra(KEY_CLASS_NAME));
            intX.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
            startActivity(intX);

        }


Code:
       public void onClick(View v){
            ViewHolder vh = (ViewHolder) v.getTag();

            ResolveInfo resolveInfo = resolveInfos.get(vh.position);
            ActivityInfo activityInfo = resolveInfo.activityInfo;

            Intent intent = new Intent(context, ActivityLauncher.class);
            intent.setAction(ActivityLauncher.ACTION_START_ACTIVITY);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
            intent.putExtra(ActivityLauncher.KEY_PACKAGE_NAME, activityInfo.applicationInfo.packageName);
            intent.putExtra(ActivityLauncher.KEY_CLASS_NAME, activityInfo.name);
            context.startActivity(intent);
        }

        @NonNull
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {

            ViewHolder vh;

            if (convertView == null) {
                convertView = inflater.inflate(R.layout.app_entry, parent, false);
                convertView.setOnClickListener(this);

                vh = new ViewHolder();
                vh.label  = ((TextView) convertView.findViewById(R.id.app_label));
                vh.image  = (ImageView) convertView.findViewById(R.id.imageView);

                convertView.setTag(vh);

            }
            else {
                vh = (ViewHolder) convertView.getTag();
            }

            //werte zuweisen
            vh.position = position;
            vh.label.setText(labels.get(position));
            vh.image.setImageDrawable(resolveInfos.get(position).loadIcon(pm));

            return convertView;
        }
    }

    static class ViewHolder {
        int position;
        TextView label;
        ImageView image;
    }
 
Zuletzt bearbeitet von einem Moderator:
N

Nonsens

Gast
Hal alle,

das Scrollproblem ist gelöst :biggrin:

Ich hab den GridView durch einen Gridlayout ersetzt und diesen mit den Items komplett befüllt.

Im Internet hab ich sehr komplizierte Beispiele zum Befüllen des GridLayout gefunden. Jedoch nach einigem probieren hab ich dann eine wesentlich einfachere Methode gefunden.

Code:
void app_refresh(){
        app_container.removeAllViews();

        [cut]

        //calculate cols
        float density = displayMetrics.density;
        int cols =  (int)(displayMetrics.widthPixels/density/80);
        app_container.setColumnCount(cols);
        app_container.setRowCount(resolveInfos.size()/cols +1);

        for(int i=0; i < resolveInfos.size(); i++){
            app_container.addView(app_getView(resolveInfos.get(i)));
        }
    }