vincular ventanas ventana varias studio pantalla nueva navegacion inicio hacer entre enlazar crear como activities abrir android overlay

varias - navegacion entre ventanas android studio



Creación de una ventana de superposición del sistema(siempre en la parte superior) (14)

A partir de Android 4.x, el equipo de Android solucionó un problema de seguridad potencial al agregar una nueva función adjustWindowParamsLw() en la que agregará FLAG_NOT_FOCUSABLE , FLAG_NOT_TOUCHABLE y eliminará las ventanas TYPE_SYSTEM_OVERLAY para TYPE_SYSTEM_OVERLAY ventanas TYPE_SYSTEM_OVERLAY .

Es decir, una ventana TYPE_SYSTEM_OVERLAY no recibirá ningún evento táctil en la plataforma ICS y, por supuesto, usar TYPE_SYSTEM_OVERLAY no es una solución viable para ICS y dispositivos futuros.

Estoy tratando de crear un botón siempre op-top / imagen pulsable que permanece en la parte superior de todas las ventanas todo el tiempo.

La prueba de concepto es

He tenido éxito y tengo un servicio en ejecución ahora. El servicio muestra algo de texto en la esquina superior izquierda de la pantalla todo el tiempo, mientras que el usuario puede interactuar libremente con el resto de aplicaciones de manera normal.

Lo que estoy haciendo es la subclase ViewGroup y agregarlo al administrador de la ventana raíz con el indicador TYPE_SYSTEM_OVERLAY . Ahora quiero agregar un botón / imagen pulsable en lugar de este texto que puede recibir eventos táctiles en sí mismo. He intentado anular "onTouchEvent" para todo el ViewGroup pero no recibe ningún evento.

¿Cómo puedo recibir eventos solo en ciertas partes de mi grupo siempre visible? Por favor sugerir

public class HUD extends Service { HUDView mView; @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_LONG).show(); mView = new HUDView(this); WindowManager.LayoutParams params = new WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, 0, // WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE // | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, PixelFormat.TRANSLUCENT); params.gravity = Gravity.RIGHT | Gravity.TOP; params.setTitle("Load Average"); WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE); wm.addView(mView, params); } @Override public void onDestroy() { super.onDestroy(); Toast.makeText(getBaseContext(),"onDestroy", Toast.LENGTH_LONG).show(); if(mView != null) { ((WindowManager) getSystemService(WINDOW_SERVICE)).removeView(mView); mView = null; } } } class HUDView extends ViewGroup { private Paint mLoadPaint; public HUDView(Context context) { super(context); Toast.makeText(getContext(),"HUDView", Toast.LENGTH_LONG).show(); mLoadPaint = new Paint(); mLoadPaint.setAntiAlias(true); mLoadPaint.setTextSize(10); mLoadPaint.setARGB(255, 255, 0, 0); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawText("Hello World", 5, 15, mLoadPaint); } @Override protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) { } @Override public boolean onTouchEvent(MotionEvent event) { //return super.onTouchEvent(event); Toast.makeText(getContext(),"onTouchEvent", Toast.LENGTH_LONG).show(); return true; } }


Al usar el servicio puedes lograr esto:

public class PopupService extends Service{ private static final String TAG = PopupService.class.getSimpleName(); WindowManager mWindowManager; View mView; String type ; @Override public IBinder onBind(Intent intent) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { // registerOverlayReceiver(); type = intent.getStringExtra("type"); Utils.printLog("type = "+type); showDialog(intent.getStringExtra("msg")); return super.onStartCommand(intent, flags, startId); } private void showDialog(String aTitle) { if(type.equals("when screen is off") | type.equals("always")) { Utils.printLog("type = "+type); PowerManager pm = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE); WakeLock mWakeLock = pm.newWakeLock((PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), "YourServie"); mWakeLock.acquire(); mWakeLock.release(); } mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE); mView = View.inflate(getApplicationContext(), R.layout.dialog_popup_notification_received, null); mView.setTag(TAG); int top = getApplicationContext().getResources().getDisplayMetrics().heightPixels / 2; LinearLayout dialog = (LinearLayout) mView.findViewById(R.id.pop_exit); // android.widget.LinearLayout.LayoutParams lp = (android.widget.LinearLayout.LayoutParams) dialog.getLayoutParams(); // lp.topMargin = top; // lp.bottomMargin = top; // mView.setLayoutParams(lp); final EditText etMassage = (EditText) mView.findViewById(R.id.editTextInPopupMessageReceived); ImageButton imageButtonSend = (ImageButton) mView.findViewById(R.id.imageButtonSendInPopupMessageReceived); // lp = (LayoutParams) imageButton.getLayoutParams(); // lp.topMargin = top - 58; // imageButton.setLayoutParams(lp); imageButtonSend.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Utils.printLog("clicked"); // mView.setVisibility(View.INVISIBLE); if(!etMassage.getText().toString().equals("")) { Utils.printLog("sent"); etMassage.setText(""); } } }); TextView close = (TextView) mView.findViewById(R.id.TextViewCloseInPopupMessageReceived); close.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { hideDialog(); } }); TextView view = (TextView) mView.findViewById(R.id.textviewViewInPopupMessageReceived); view.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { hideDialog(); } }); TextView message = (TextView) mView.findViewById(R.id.TextViewMessageInPopupMessageReceived); message.setText(aTitle); final WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0, 0, WindowManager.LayoutParams.TYPE_SYSTEM_ERROR, WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD // | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON , PixelFormat.RGBA_8888); mView.setVisibility(View.VISIBLE); mWindowManager.addView(mView, mLayoutParams); mWindowManager.updateViewLayout(mView, mLayoutParams); } private void hideDialog(){ if(mView != null && mWindowManager != null){ mWindowManager.removeView(mView); mView = null; } } }


Aquí hay una solución simple. Todo lo que necesita es inflar el diseño XML tal como lo hace en los adaptadores de lista, simplemente haga el diseño XML para inflarlo. Aquí está el código que todo lo que necesitas.

public class HUD extends Service { View mView; LayoutInflater inflate; TextView t; Button b; @Override public void onCreate() { super.onCreate(); Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_LONG).show(); WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE); Display display = wm.getDefaultDisplay(); get phone display size int width = display.getWidth(); // deprecated - get phone display width int height = display.getHeight(); // deprecated - get phone display height WindowManager.LayoutParams params = new WindowManager.LayoutParams( width, height, WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, PixelFormat.TRANSLUCENT); params.gravity = Gravity.LEFT | Gravity.CENTER; params.setTitle("Load Average"); inflate = (LayoutInflater) getBaseContext() .getSystemService(Context.LAYOUT_INFLATER_SERVICE); mView = inflate.inflate(R.layout.canvas, null); b = (Button) mView.findViewById(R.id.button1); t = (TextView) mView.findViewById(R.id.textView1); b.setOnClickListener(new OnClickListener() { public void onClick(View v) { // TODO Auto-generated method stub t.setText("yes you click me "); } }); wm.addView(mView, params); } @Override public IBinder onBind(Intent arg0) { // TODO Auto-generated method stub return null; } }


Bueno, prueba mi código, al menos te da una cadena como superposición, puedes reemplazarlo con un botón o una imagen. No vas a creer que esta es mi primera aplicación para Android LOL. De todos modos, si tiene más experiencia con aplicaciones de Android que yo, por favor intente

  • cambiando los parámetros 2 y 3 en "nuevo WindowManager.LayoutParams"
  • probar un enfoque de evento diferente

En realidad, puedes probar WindowManager.LayoutParams.TYPE_SYSTEM_ERROR en lugar de TYPE_SYSTEM_OVERLAY. Puede sonar como un hack, pero te permite mostrar la vista sobre todo y obtener eventos táctiles.


Encontró una biblioteca que hace precisamente eso: https://github.com/recruit-lifestyle/FloatingView

Hay un proyecto de muestra en la carpeta raíz. Lo ejecuté y funciona como se requiere. Se puede hacer clic en el fondo, incluso si se trata de otra aplicación.


Esto podría ser una solución estúpida. Pero funciona. Si puedes mejorarlo, por favor házmelo saber.

Sobre la creación de su servicio: He utilizado el indicador WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH . Este es el único cambio en el servicio.

@Override public void onCreate() { super.onCreate(); Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_LONG).show(); mView = new HUDView(this); WindowManager.LayoutParams params = new WindowManager.LayoutParams( WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, PixelFormat.TRANSLUCENT); params.gravity = Gravity.RIGHT | Gravity.TOP; params.setTitle("Load Average"); WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE); wm.addView(mView, params); }

Ahora, comenzarás a recibir cada evento de clic. Por lo tanto, necesita rectificar en su controlador de eventos.

En tu evento táctil de ViewGroup

@Override public boolean onTouchEvent(MotionEvent event) { // ATTENTION: GET THE X,Y OF EVENT FROM THE PARAMETER // THEN CHECK IF THAT IS INSIDE YOUR DESIRED AREA Toast.makeText(getContext(),"onTouchEvent", Toast.LENGTH_LONG).show(); return true; }

También es posible que necesite agregar este permiso a su manifiesto:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />



Prueba esto. Funciona bien en ICS. Si desea detener el servicio, simplemente haga clic en la notificación generada en la barra de estado.

public class HUD extends Service { protected boolean foreground = false; protected boolean cancelNotification = false; private Notification notification; private View myView; protected int id = 0; private WindowManager wm; private WindowManager.LayoutParams params; @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); // System.exit(0); Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_SHORT).show(); params = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_PHONE, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT); params.gravity=Gravity.TOP|Gravity.LEFT; wm = (WindowManager) getSystemService(WINDOW_SERVICE); inflateview(); foregroundNotification(1); //moveToForeground(1,n,true); } @Override public void onDestroy() { super.onDestroy(); ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).cancel(0); Toast.makeText(getBaseContext(),"onDestroy", Toast.LENGTH_SHORT).show(); if(myView != null) { ((WindowManager) getSystemService(WINDOW_SERVICE)).removeView(myView); myView = null; } } protected Notification foregroundNotification(int notificationId) { notification = new Notification(R.drawable.ic_launcher, "my Notification", System.currentTimeMillis()); notification.flags = notification.flags | Notification.FLAG_ONGOING_EVENT | Notification.FLAG_ONLY_ALERT_ONCE; notification.setLatestEventInfo(this, "my Notification", "my Notification", notificationIntent()); ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).notify(id, notification); return notification; } private PendingIntent notificationIntent() { Intent intent = new Intent(this, stopservice.class); PendingIntent pending = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); return pending; } public void inflateview() { LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE); myView = inflater.inflate(R.layout.activity_button, null); myView.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Toast.makeText(getBaseContext(),"onToasttt", Toast.LENGTH_SHORT).show(); return false; } }); // Add layout to window manager wm.addView(myView, params); } }

ACTUALIZAR

Muestra here

Para crear una vista de superposición, al configurar los LayoutParams NO configure el tipo en TYPE_SYSTEM_OVERLAY.

Instead set it to TYPE_PHONE. Use the following flags: FLAG_NOT_TOUCH_MODAL FLAG_WATCH_OUTSIDE_TOUCH


Si alguien sigue leyendo este hilo y no puede hacer que esto funcione, siento mucho decirte que esta manera de interceptar eventos de movimiento se considera un error y se corrige en Android> = 4.2.

El evento de movimiento que interceptaste, aunque tiene acción como ACTION_OUTSIDE, devuelve 0 en getX y getY. Esto significa que no puede ver toda la posición de movimiento en la pantalla, ni puede hacer nada. Sé que el doc dijo que obtendría x y y, pero la verdad es que NO lo hará. Parece que esto es para bloquear key logger.

Si alguien tiene una solución, por favor deje su comentario.

ref: ¿Por qué ACTION_OUTSIDE devuelve 0 cada vez en KitKat 4.4.2?

https://code.google.com/p/android/issues/detail?id=72746


Siguiendo la respuesta de @Sam Lu, en efecto, Android 4.x impide que ciertos tipos escuchen eventos táctiles externos, pero algunos tipos, como TYPE_SYSTEM_ALERT , todavía hacen el trabajo.

Ejemplo

WindowManager.LayoutParams params = new WindowManager.LayoutParams( WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, PixelFormat.TRANSLUCENT); WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE); LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE); View myView = inflater.inflate(R.layout.my_view, null); myView.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.d(TAG, "touch me"); return true; } }); // Add layout to window manager wm.addView(myView, params);

Permisos

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>


Soy uno de los desarrolladores del SDK de Tooleap . También proporcionamos una forma para que los desarrolladores se muestren siempre en las ventanas y botones superiores, y hemos lidiado con una situación similar.

Un problema que las respuestas aquí no han abordado es el de los "Botones protegidos" de Android.

Los botones filterTouchesWhenObscured tienen la propiedad filterTouchesWhenObscured , que significa que no pueden interactuar con ellos, si se colocan debajo de una ventana, incluso si esa ventana no recibe ningún toque. Citando la documentación de Android:

Especifica si se deben filtrar los toques cuando la ventana de la vista está oculta por otra ventana visible. Cuando se establece en verdadero, la vista no recibirá toques cada vez que aparezca un brindis, un cuadro de diálogo u otra ventana encima de la ventana de la vista. Consulte la documentación de seguridad {@link android.view.View} para obtener más detalles.

Un ejemplo de tal botón es el botón de instalación cuando intenta instalar apks de terceros. Cualquier aplicación puede mostrar dicho botón si agrega al diseño de vista la siguiente línea:

android:filterTouchesWhenObscured="true"

Si muestra una ventana siempre visible en la parte superior sobre un "Botón asegurado", todas las partes de los botones asegurados que están cubiertas por una superposición no manejarán ningún toque, incluso si no se puede hacer clic en esa superposición. Por lo tanto, si planea mostrar una ventana de este tipo, debe proporcionar una forma para que el usuario la mueva o la descarte. Y si una parte de su superposición es transparente, tenga en cuenta que su usuario podría estar confundido porque un cierto botón en la aplicación subyacente no está funcionando para él de repente.


TRABAJANDO SIEMPRE EN EL BOTÓN DE IMAGEN SUPERIOR

en primer lugar lo siento por mi ingles

Edito sus códigos y hago que el botón de imagen de trabajo que escucha su evento táctil no le dé control táctil a sus elementos de fondo.

También da a los oyentes táctiles de otros elementos.

Las alineaciones de los botones están abajo y a la izquierda.

puede cambiar las alineaciones pero necesita seleccionar eventos en contacto en el elemento if

import android.annotation.SuppressLint; import android.app.Service; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.PixelFormat; import android.os.IBinder; import android.util.Log; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.Toast; public class HepUstte extends Service { HUDView mView; @Override public void onCreate() { super.onCreate(); Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_LONG).show(); final Bitmap kangoo = BitmapFactory.decodeResource(getResources(), R.drawable.logo_l); WindowManager.LayoutParams params = new WindowManager.LayoutParams( kangoo.getWidth(), kangoo.getHeight(), WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, PixelFormat.TRANSLUCENT); params.gravity = Gravity.LEFT | Gravity.BOTTOM; params.setTitle("Load Average"); WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE); mView = new HUDView(this,kangoo); mView.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View arg0, MotionEvent arg1) { // TODO Auto-generated method stub //Log.e("kordinatlar", arg1.getX()+":"+arg1.getY()+":"+display.getHeight()+":"+kangoo.getHeight()); if(arg1.getX()<kangoo.getWidth() & arg1.getY()>0) { Log.d("tıklandı", "touch me"); } return false; } }); wm.addView(mView, params); } @Override public IBinder onBind(Intent arg0) { // TODO Auto-generated method stub return null; } } @SuppressLint("DrawAllocation") class HUDView extends ViewGroup { Bitmap kangoo; public HUDView(Context context,Bitmap kangoo) { super(context); this.kangoo=kangoo; } protected void onDraw(Canvas canvas) { //super.onDraw(canvas); // delete below line if you want transparent back color, but to understand the sizes use back color canvas.drawColor(Color.BLACK); canvas.drawBitmap(kangoo,0 , 0, null); //canvas.drawText("Hello World", 5, 15, mLoadPaint); } protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) { } public boolean onTouchEvent(MotionEvent event) { //return super.onTouchEvent(event); // Toast.makeText(getContext(),"onTouchEvent", Toast.LENGTH_LONG).show(); return true; } }