Android Options Menu

@kfrajer I found a code in a post yours on the last forum.
However it seemingly only worked on android mode version 3.0.2 and not on version 4.x
You said you would look in to that later. Did you get it working?
I have googled to try understand more of it.and found that the parameters of menu.add
are the following:

First:
The group ID – you can put items in a group and then make changes to the group. These changes will apply to all of the items in the group. This parameter is the ID of the group. We pass 0 for the groupId. Use Menu.NONE if the item should not be in a group.

Second:
The menu item ID – a unique ID to identify this menu item. We’ve defined a constant, MENU_ITEM which is initialized to the Menu class’s FIRST constant. We add 1 to MENU_ITEM for each successive item that we add to the menu

Third:
The order of appearance of the item in the menu. The order of the items is not important to us so we use the Menu.NONE constant, indicating that we don’t care about the order.

Fourth:
The resource ID of the string that will appear as the item’s name in the menu

The last one should be the Id of a string in the XML, but I have seen in many code snippets that a string may be passed directly.
What I do not understand is the use of the inflater, yet it will not inflate, meaning ‘link’ to a string value of a menu Id anyway.
The code does not give any error, but no menu will pop up.
Below I am posting a code as minimized as possible, just for the sake of oversight.
Do you have any idea how to go further?

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater; 
import android.view.MenuItem;


void setup() {
  fullScreen();
}
 
void draw() {
}

@ Override
  void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
  menu.add(0, 1, Menu.NONE, "Red");
  menu.add(0, 2, Menu.NONE, "Green");
  menu.add(0, 3, Menu.NONE, "Blue");
  super.onCreateOptionsMenu(menu, inflater);
}
 
@ Override
  boolean onOptionsItemSelected(MenuItem item) {
  switch (item.getItemId()) {
  case 1:
    background(255, 0, 0);
    break;
 
  case 2:
    background(0, 255, 0);
    break;
 
  case 3:
    background(0, 0, 255);
    break;
  }
  return super.onOptionsItemSelected(item);
}
 
@ Override 
  public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setHasOptionsMenu(true);
}

Well it is the third topic that I answer myself.
I guess I’m on my own now.
But I have received a lot of kind help on this forum so here is my contribution.
I assume that the code above of standard menu needs some kind of bar to be able to run properly.
In the code below I used a popup menu instead attached to a TextView. Clicking on the screen will enable or close the menu.
Download sketch here.

import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.PopupMenu;
import android.widget.PopupMenu.OnMenuItemClickListener;
import android.widget.TextView;
import android.app.Activity;
import android.content.Context;
import android.widget.FrameLayout;
import android.view.ViewGroup.LayoutParams;
import android.view.Gravity;
import android.R;
import android.widget.RelativeLayout;
import processing.android.CompatUtils;
import android.graphics.Color;
import android.view.WindowManager;

Activity act; 
Context mC;
FrameLayout fl;

int menuanchorId;
int menubarId;
boolean toggle;

void setup() {
  fullScreen();
  background(80, 80, 255);
  textAlign(CENTER);
  textSize(35);
  text("Click on screen to enable or close menu", width/2, height/2);
}

void draw() {
}

  public void onStart() {
  act = this.getActivity();
  mC= act.getApplicationContext();
  // To prevent status bar showing up
  act.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

  TextView menubar = new TextView(act);
  menubar.setLayoutParams(new RelativeLayout.LayoutParams(width-width/12, width/12));
  menubar.setTextSize(20);
  menubar.setX(0);
  menubar.setY(0);
  menubar.setGravity(Gravity.CENTER);
  menubar.setBackgroundColor(Color.rgb(0, 0, 120));
  menubar.setTextColor(Color.WHITE);
  menubar.setText("My Popup Menu");
  menubar.setVisibility(View.GONE);
  menubarId=CompatUtils.getUniqueViewId();
  menubar.setId(menubarId);

  TextView menuanchor = new TextView(act);
  menuanchor.setLayoutParams(new RelativeLayout.LayoutParams(width/12, width/12));
  menuanchor.setTextSize(22);
  menuanchor.setTextColor(Color.WHITE);
  menuanchor.setX(width-width/12);
  menuanchor.setY(0);
  menuanchor.setBackgroundColor(Color.rgb(0, 0, 120));
  menuanchor.setGravity(Gravity.CENTER);
  menuanchor.setText("⋮");
  menuanchor.setVisibility(View.GONE);
  menuanchorId=CompatUtils.getUniqueViewId();
  menuanchor.setId(menuanchorId);
  menuanchor.setOnClickListener(new View.OnClickListener() {
      public void onClick(View view) {
      TextView menuanchor = (TextView) act.findViewById(menuanchorId);
      PopupMenu popupMenu = new PopupMenu(mC, menuanchor);
      popupMenu.getMenu().add(Menu.NONE, 1, Menu.NONE, "Red");
      popupMenu.getMenu().add(Menu.NONE, 2, Menu.NONE, "Green");
      popupMenu.getMenu().add(Menu.NONE, 3, Menu.NONE, "Blue");
      popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
          public boolean onMenuItemClick(MenuItem item) {
          switch (item.getItemId()) {
          case 1:
            background(255, 0, 0);
            text("Click on screen to enable or close menu", width/2, height/2);
            return true;
          case 2:
            background(0, 255, 0);
            text("Click on screen to enable or close menu", width/2, height/2);
            return true;
          case 3:
            background(0, 0, 255);
            text("Click on screen to enable or close menu", width/2, height/2);
            return true;
          default:
            return false;
          }
        }
      }
      );
      popupMenu.show();
    }
  }
  );

  fl = (FrameLayout)act.findViewById(R.id.content);
  FrameLayout.LayoutParams params1 = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, Gravity.CENTER);
  fl.addView(menubar);
  fl.addView(menuanchor);
}

void mousePressed() {
  act.runOnUiThread(
    new Runnable() {
    public void run() {
      TextView tv = (TextView)act.findViewById(menuanchorId);
      TextView tvv = (TextView)act.findViewById(menubarId);
      if (toggle) {
        tv.setVisibility(View.VISIBLE);
        tvv.setVisibility(View.VISIBLE);
      } else {
        tv.setVisibility(View.GONE);
        tvv.setVisibility(View.GONE);
      }
    }
  }
  );
  toggle =! toggle;
}
1 Like

thanks,
sorry could you show a picture of that menu too?

@kll Of course.

1 Like

Know that feeling (filling before :man_facepalming::man_facepalming::man_facepalming:), I think maybe there aren’t big amount of people with deep knowledge of Android in specific here; and people like Akenaton don’t have time to study all cases.

Me, personally, don’t have much idea, many time ago I don’t work with AS (Android Studio) and neither went so deep on it possibilities, I try to answer all about I know but isn’t too much.

Thanks for contribute in the forum with your knowledge and your discovers :+1:

@noel === your code will work but that is not a menu, only a popup; you can create a “custom” menu using the ToolBar widget from Android: i have tested that and it runs… Code snippet below:::


import android.widget.Button;
import android.view.Gravity;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.view.ViewGroup;
import processing.android.CompatUtils;
import android.R;
import android.view.View;
import android.graphics.Color;
import android.R.color;
import android.widget.LinearLayout;
import android.widget.Toolbar;
import android.widget.FrameLayout;
import android.view.Window;
import android.app.Activity;
import android.view.WindowManager;
import android.os.Build;
import android.os.Looper;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;



Activity act;
boolean changeCouleur = false;
FrameLayout fl;
Toolbar toolbar;
int toolbarId;


//
@Override 
  public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

  act = this.getActivity();
  toolbar = new Toolbar(act);////creating the toolbar & adding a linear layout for it
  LinearLayout.LayoutParams toolBarParams = new LinearLayout.LayoutParams(
    Toolbar.LayoutParams.MATCH_PARENT, 
    150///of course you can change it with something like height/?
    );
  toolbar.setLayoutParams(toolBarParams);
  toolbarId=CompatUtils.getUniqueViewId();///perhaps you want to change this view after created
  toolbar.setId(toolbarId);
  ///then as usually you add the view (or ViewGroup) to the rootView

  fl = (FrameLayout) act.getWindow().getDecorView().getRootView();

  act.runOnUiThread(new Runnable() {
    //@Override
    public void run() {
      fl.addView(toolbar, 1);
    }
  }
  );
}




void settings() {
  fullScreen();
}

void setup() {

  background(255, 0, 0);
  Looper.prepare();

  act.runOnUiThread(new Runnable() {
    //@Override
    public void run() {
      toolbar.setBackgroundColor(Color.BLUE);
      toolbar.setTitle("AKENATON");///if you want a title
      toolbar.setTitleTextColor(Color.WHITE);
      toolbar.setVisibility(View.VISIBLE);
      ///Adding buttons with clicklistener
      Button bt = new Button(act);
      bt.setText("RED");
      LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
      params.gravity = Gravity.LEFT;
      bt.setLayoutParams(params);

      bt.setOnClickListener(new View.OnClickListener() {
        @Override
          public void onClick(View v) {
          println("j'ai quelque chose DE ROUGE à faire");
        }
      }
      );

      Button bt2 = new Button(act);
      bt2.setText("GREEN");
      LinearLayout.LayoutParams params2 = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
      params2.gravity = Gravity.CENTER;
      bt2.setLayoutParams(params2);

      bt2.setOnClickListener(new View.OnClickListener() {
        @Override
          public void onClick(View v) {
          println("j'ai quelque chose DE VERT à faire");
        }
      }
      );
      toolbar.addView(bt);
      toolbar.addView(bt2);
    }
  }
  );
}

void draw() {
  ///this code is only an example how you can show the menu bar with P5 though it s normally invisible
  //  if(!changeCouleur){
  //  act = this.getActivity();
  //   act.runOnUiThread(new Runnable() {
  //    //@Override
  //    public void run() {

  //   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 
  //  println("plus que lollipop");
  //  Window window = act.getWindow();


  //window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
  //window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
  //window.setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN,
  //                      WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);

  //;
  //   }else{
  //     println("before lollipop");

  //     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
  //println("je suis egal à kitkat");

  //    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN,
  //                      WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
  //}

  //   }
  //    }

  //   });
  //    changeCouleur = true;
  //  }
};
2 Likes

Hi @Akenaton Thank you for pointing out how to set up the toolbar. Now before working further on this and take full advantage of that bar, like using icons, I have to find out a way to “inflate” these.
@Kfrajer figured out how to work with xml files, but I can’t find the post. Only this
Maybe the icons can also be placed in a drawable asset folder.
But then I also need to export my sketch. But I did not fix my PC yet ( I am retired, living on a small pension :frowning: , and to be really honest I have taken it as a challenge to be able to do everything on my tablet.) But the APDE app does not have that feature.
Do you have an alternative idea how to manage this? For the moment I am converting custom made svg icons to a character in a font, and placing it as a text. It would be a lot easier to simply download standard icons.

PS. In order to run your code on KitKat (and yes, here in Brazil an awful lot of devices use that, including new devices ( actually, new, not sold, old surplus from “first world” countries)), you have to import “android.support.v7.widget.Toolbar” instead of “android.widget.Toolbar”, otherwise the sketch will crash.

@noel ===

  • you are right, using the toolbar you can add icons (you create an imageView and add your icon to it)

  • i have not tried that with P5 but i think that you have only to put the icons inside the data folder; compiling P5will put them in a drawable folder

  • Sorry i have never used APDE; but as you can use my code and vice versa i think that you have only to install P5 on a PC + of course the android mode: that will be ok if you dont want to put the app on the playstore but if you want you have to download Android studio, create a project “from existing code” and choose your android export; at this moment you can change the targetSdk which is hardcoded by P5 from 26 to 28+, using gradle.

  • as for the icons you can downoad the android material design icons from the site. There are thousands and thousands. Anyway if you want to create yours svg is the best solution

1 Like

@ noel ===
Using icons is a little more complicated that i thought: P5 does not put them in the drawable folders but into the assets folder; so to get your icons you have to use AssetManager and add a method to get the image that you add to the ImageView: code snippet below, only the new img, add it to the buttons code…

ImageView img;
img = new ImageView(act.getApplicationContext());

img.setImageBitmap(chercheDansAssets("dangers.png"));

LinearLayout.LayoutParams params3 = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
params3.gravity = Gravity.RIGHT;
img.setLayoutParams(params3);


toolbar.addView(bt);
toolbar.addView(bt2);
toolbar.addView(img);

//////and the method is:

public Bitmap chercheDansAssets(String fileName){
 
 AssetManager assetmanager = act.getAssets();
 InputStream is = null;
 try{
 
 is = assetmanager.open(fileName);
 }catch(IOException e){
 e.printStackTrace();
 }
 Bitmap bitmap = BitmapFactory.decodeStream(is);
 return bitmap;
 }

@akenaton Thank you. While my PC is in repair, I downloaded the app AIDE. You can import entire Android Eclipse projects with it. I already managed to run the exampile code of the Processing core library on it. In the next days I will try your code. I have a lot to learn!

@akenaton Finally I found out how to get the build file on APDE to be able to access assets and drawable directories.
But now I realize that like you said the assets dir contains the data files.
Your code works perfectly, and I am happy to get images on widgets now.
Below a minimal code with needed imports for whom is interested.
PS. For whom is using APDE; you must run in app mode, preview mode will not let the assets manager detect the assets dir.

import android.view.Gravity;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewGroup;
import android.graphics.Color;
import android.widget.LinearLayout;
import android.widget.FrameLayout;
import android.view.Window;
import android.app.Activity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.widget.ImageView;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

Activity act;
FrameLayout fl;
Toolbar toolbar;
ImageView img;

@Override 
  public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  act = this.getActivity();
  img = new ImageView(act.getApplicationContext());
  AssetManager assetmanager = act.getAssets();
  InputStream is = null;
  try { 
    is = assetmanager.open( "myImage.png" );
    Bitmap bitmap = BitmapFactory.decodeStream(is);
    img.setImageBitmap(bitmap);
  }
  catch(IOException e) {
    e.printStackTrace();
  }
  toolbar = new Toolbar(act);
  LinearLayout.LayoutParams toolBarParams = new LinearLayout.LayoutParams(
  Toolbar.LayoutParams.MATCH_PARENT, width/12);
  toolbar.setLayoutParams(toolBarParams);
  toolbar.setBackgroundColor(Color.BLUE);
  toolbar.addView(img);
  fl = (FrameLayout) act.getWindow().getDecorView().getRootView();
  fl.addView(toolbar, 1);
}