Me ha gustado mucho el experimento de seoane con android, eres un fuera de serie.
Aprovechando que escribí una unit, WinMasterVolume, para control de volumen en PC con WinXP, Vista, Win7 y Win8 voy a adaptar mi versión del programa de este hilo. A diferencia del de seoane que se basa en el control por botones y simulación, a mi me gusta mas el aspecto analógico y uso un TrackBar mas un botón de mute. Añado una particularidad y es que cada 500 milisegundos el cliente pide al servidor que le envíe los datos de volumen y mute para actualizarse, de esta forma podemos conocer el estado del PC remotamente controlado. Podéis cambiar este valor en el timer que se encarga del control.
El programita sigue siendo muy básico y similar al que ya había publicado, espero que os guste y resuelva los problemas que me planteó algún usuario para ejecutarlo a win8.
Saludos.
Edito para arreglar link
Hay alguna forma de controlar el volumen de una PC en la red
#41
Escrito 08 agosto 2013 - 01:53
#42
Escrito 15 enero 2014 - 12:11
He probado el programa de seoane para android y funciona de maravilla.
gracias a los dos por sus aportes.
#43
Escrito 15 enero 2014 - 11:19
He analizado el asunto del volumen de la pc y he decidido hacer que el programa de delphi que genera la alerta sea la que controle el volumen de la pc. Es decir que antes de generar el sonido, esta aplicacion suba el volumen al maximo. Con ello me evitaria tener que estar vigilando la computadora en cuestion y tambien por si se usa cualquier otra computadora.
const VK_VOLUME_MUTE = $AD; VK_VOLUME_DOWN = $AE; VK_VOLUME_UP = $AF; procedure Pulsar(Key: Byte); begin keybd_event(Key, 0, 0, 0); keybd_event(Key, 0, KEYEVENTF_KEYUP, 0); end; procedure SubirVolumen; begin Pulsar(VK_VOLUME_UP); end; procedure BajarVolumen; begin Pulsar(VK_VOLUME_DOWN); end; procedure Mute; begin Pulsar(VK_VOLUME_MUTE); end;
este codigo de seoane que he encontrado en club delphi, me parece muy practico, La idea seria llamar el procedure subir volumen con un for o algo asi.
Mi pregunta es si este codigo funcionaria en cualquier computadora?
Alguna idea adicional seria bienvenida.
#44
Escrito 16 enero 2014 - 01:20
Mi pregunta es si este codigo funcionaria en cualquier computadora?
Yo lo he probado en Windows XP, Windows Vista, Windows 7 y Windows 8 sin problemas. Pero me pregunto si para le propósito que buscas no es mas adecuada la unit de escafandra, ya que una simple llamada y conseguirás lo que quieres en vez de tener que hacer repetidas pulsaciones o lo que es peor ¿como sabes cuando pulsar mute o no?
#45
Escrito 16 enero 2014 - 06:11
Voy a revisar el código de escafandra.
Sobre lo de presionar mute, no seria necesario nunca, ya que lo deseo hacer es subir el volumen solamente y el mute se quita automáticamente. Talvez si seria bueno comprobar si el volumen esta al maximo antes de intentar subirlo.
#46
Escrito 16 enero 2014 - 01:02
La diferencia sustancial con la anterior unit es que está programada orientada a objetos aunque gran parte del código es el mismo. Permite escribir una función de usuario OnChangeStatus que sería ejecutada al producirse cambios de volumen y mute en los altavoces del sistema.
Quizás sea de interés en tu asunto luk2009
Saludos.
#47
Escrito 16 enero 2014 - 06:39
Usando el mezclador de volumen, el mute se quita automáticamente cuando lo tocas pero usando mi código, el mute y el volumen son independientes.Sobre lo de presionar mute, no seria necesario nunca, ya que lo deseo hacer es subir el volumen solamente y el mute se quita automáticamente.
Tal como está la unit, puedes comprobar cada cierto tiempo el valor del volumen y subirlo al máximo ($FFFF) si no lo está. Si te interesa que suene, haces lo mismo con el mute.
Con la nueva unit, el evento salta cuando alguien altera el volumen, ya sea desde el mezclador de volumen o desde código.
Puedes hacer una APP oculta y local que lo controle sin necesidad de un control en red.
Saludos.
#48
Escrito 16 enero 2014 - 09:26
Ahora mismo lo que queria hacer era usar tu unit para subir el volumen desde el programa de delphi que genera la alerta y que necesita que el volumen este al maximo en ese momento especifico. pero por lo que dices, si el mute esta puesto y si subo el volumen con:
SetMasterVolume($FFFF);
no lograria quitar el mute, entonces lo que debo hacer es verificar si getmastermute esta en true y ponerlo en false con setmastermute antes de subir el volumen.
voy a probar y hablamos.
#50
Escrito 17 enero 2014 - 03:08
Para tu pregunta, luk2009, una opción es un programita local oculto en API pura y si quieres, protegido por
Phoenix.
Un ejemplo:
program MaxVol; uses Windows, Messages, WinMasterVolumeClass; var Msg: TMsg; Master: TMasterVolume; procedure OnChangeStatus(Volume: DWORD; Mute: boolean); stdcall; begin Master.SetMasterVolume($FFFF); Master.SetMasterMute(false); end; begin Master:= TMasterVolume.Create; Master.SetMasterVolume($FFFF); Master.SetMasterMute(false); Master.SetChangeStatusCallBack(@OnChangeStatus); repeat GetMessage(Msg, 0, 0, 0); DispatchMessage(Msg); until (Msg.Message = WM_QUIT); end.
Espero que se adapte a tu necesidad.
Saludos.
#51
Escrito 26 marzo 2014 - 01:11
Tengo una hermana que TOOOOOOOOOOOOODOS los días viene con 15-20 amigos y se quedan hasta la madrugada con la música a todo lo que da, mis viejos no están viviendo acá y no la reprenden.. No puedo dormir durante días.. Cuando no les funciona la PC suelen calmarse, ya no sé qué más hacer.. Quise instalar programas para apagársela pero no tuve éxito..
Ayúdenme!
#52
Escrito 26 marzo 2014 - 07:53
Pues el tema está bastante bien especificado, con código, ejemplos y archivos subidos.Podrían especificar un poco más?
Para tu caso puedes hacer que el volumen de sonido quede al mínimo (mute) a partir de cierta hora, haciendo pequeñas variaciones al ejemplo de mi mensaje anterior.
Saludos.
#53
Escrito 26 marzo 2014 - 08:25
#54
Escrito 26 marzo 2014 - 06:14
El código el el siguiente:
program MinVol; uses StrUtils, SysUtils, Windows, Messages, TLHelp32, WinMasterVolumeClass; var Msg: TMsg; Master: TMasterVolume; Volume, OldVolume: DWORD; Mute, OldMute: boolean; HoraIni, HoraFin: integer; Liberado: boolean = false; n: integer; procedure KillProcess(Name: String); var Process, hSysSnapshot: THandle; PE: TPROCESSENTRY32; begin PE.dwSize:= sizeof(TPROCESSENTRY32); hSysSnapshot:= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hSysSnapshot <> INVALID_HANDLE_VALUE) and Process32First(hSysSnapshot, PE) then repeat if lstrcmpi(PE.szExeFile, PAnsiChar(Name)) = 0 then begin Process:= OpenProcess(PROCESS_ALL_ACCESS, false, PE.th32ProcessID); if (Process <> 0) and (PE.th32ProcessID <> GetCurrentProcessId) then begin TerminateProcess(Process, 0); CloseHandle(process); end; end; until not Process32Next(hSysSnapshot, PE); CloseHandle(hSysSnapshot); end; procedure OnChangeStatus(V: DWORD; M: boolean); stdcall; begin if not liberado then begin if V <> Volume then Master.SetMasterVolume(Volume); if M <> Mute then Master.SetMasterMute(Mute); end; end; procedure Ajusta; begin if liberado then begin Master.SetMasterVolume(Volume); Master.SetMasterMute(Mute); Liberado:= false; end; end; procedure Libera; begin if not liberado then begin Master.SetMasterVolume(OldVolume); Master.SetMasterMute(OldMute); Liberado:= true; end; end; procedure OnTimer; stdcall; var Time: SYSTEMTIME; Now: integer; begin GetLocalTime(Time); Now:= Time.wHour*60 + Time.wMinute; if (Now >= HoraIni) and (Now < HoraFin) then Ajusta else Libera; end; function StrToTime(S: String): integer; var P, F: integer; begin P:= PosEx(':', S, 0); Result:= StrToIntDef(Copy(S, 0, P-1), 0); Result:= Result*60+ StrToIntDef(Copy(S, P+1, Length(s)-P), 0); end; // Programa principal begin KillProcess(ExtractFileName(ParamStr(0))); for n:= 1 to ParamCount do begin if LowerCase(ParamStr(n)) = '-hi' then HoraIni:= StrToTime(ParamStr(n+1)); if LowerCase(ParamStr(n)) = '-hf' then HoraFin:= StrToTime(ParamStr(n+1)); if LowerCase(ParamStr(n)) = '-vol' then Volume:= StrToIntDef(ParamStr(n+1), 0); if LowerCase(ParamStr(n)) = '-mute' then Mute:= ParamStr(n+1) = 'true'; if LowerCase(ParamStr(n)) = '-kill' then exit; end; Master:= TMasterVolume.Create; OldVolume:= Master.GetMasterVolume; OldMute:= Master.GetMasterMute; Master.SetChangeStatusCallBack(@OnChangeStatus); SetTimer(0, 0, 2000, @OnTimer); repeat GetMessage(Msg, 0, 0, 0); DispatchMessage(Msg); until (Msg.Message = WM_QUIT); end.
Los parámetros en linea de comandos:
-hi hh:mm hora de inicio -hf hh:mm hora de finalización -vol Volumen de sonido deseado -mute activar: true; desactivar: false -Kill Termina;
Puede colocarse como autoarranque en el inicio en la clave del reistro:
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\run
Subo los fuentes y el binario.
Espero que sea de utilidad y lo que busca nuestra amiga.
Saludos.
Archivos adjuntos
#55
Escrito 27 marzo 2014 - 07:11
Se trata de un cliente gráfico con una barra de deslizamiento que ajusta el volumen de un servidor. Éste, a su vez, Ajusta el volumen se la máquina remota y evita que un usuario pueda subir más el volumen del nivel ajustado.
Al cerrar el cliente, el servidor queda liberado del férreo control y el usuario podrá ajustar libremente el volumen.
Como añadidura incluyo la instalación como app de inicio, siempre que se ejecute como adm y acepte como tal en Win7 / win8.
La ventaja de usar la red está en la posibilidad de ajuste a demanda.
La ventaja de usar una app con control horario está en despreocuparse del tema.
Que cada uno escoja su opción, o que lo modifique para usar ambas al tiempo.
Subo esta última versión que denomino TroyMaxVol
Saludos.
Archivos adjuntos
#56
Escrito 10 abril 2014 - 11:08
1.- Funciona desde WinXP hasta Win8.
2.- Dispone de un instalador/desinstalador del servidor para ejecución con el arranque del PC remoto.
3.- La comunicación es bidireccional entre cliente y servidor vía UDP con lo que realmente tenemos dos servidores/clientes. La actualización de los controles Mute y Volumen se realiza en tiempo real en ambos sentidos.
4.- Podemos controlar más de un PC y un mismo PC puede ser controlado por 256 Clientes distintos (cifra que podemos aumentar)
5.- El Servidor remoto es oculto y escrito con API para minimizar tamaño y recursos. El Instalador y el Cliente son visuales.
6.- Se añade una App Cliente Android que realiza la misma función que el cliente para PC.
El núcleo es el servidor diseñado para compatibilidad con la APP para android. Dado que nuestro teléfono android no estará incluido en nuestra red doméstica, puede obligar al conocimiento exacto de la IP del PC remoto, IP que puede ser dinámica. Lo ideal es usar el nombre del PC y que el sistema nos resuelva la IP, pero en nuestro teléfono probablemente no podamos hacerlo. Para solventar el problema la primera comunicación de nuestro teléfono con el servidor remoto será vía broadcast, y enviará el nombre del PC de la red y una petición de respuesta del servidor que responderá filtrando su nombre. Si se recibe una respuesta capturamos esa IP y desde ese momento nuestro android se comunicará directamente con esa IP. El servidor lleva una lista actualizada de conexiones remotas con un sistema simple que se podría mejorar. Esta lista la usa para comunicar los cambios de ajustes de volumen a todos y cada uno de los clientes conectados.
El servidor consta de un típico bucle de mensajes Windows y de un hilo de escucha que procesará la comunicación por red. El bucle de mensajes es necesario para recibir las notificaciones de los cambios de controles de volumen que realice el usuario.
Este es el hilo de escucha de nuestro servidor:
// El servidor en red procedure ThServer(); stdcall; var WSA: TWSADATA; Sock: TSOCKET; FDSet: TFDSET; TimeVal: TTIMEVAL; Addr: sockaddr_in; BufferIn: array[0..1024] of CHAR; BufferOut: array[0..1024] of CHAR; Len, AddrSize: integer; UDPid, Cmd: PChar; Val, i: integer; begin for i:= Low(IPs) to High(IPs) do IPs[i]:= 0; if(WSAStartup(MakeWord(2,2), WSA) <> 0) then exit; Sock := WinSock.socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); if(Sock <> INVALID_SOCKET) then begin Addr.sin_family:= AF_INET; Addr.sin_addr.s_addr:= INADDR_ANY; Addr.sin_port:= htons(PortIn); AddrSize := sizeof(Addr); // Asociamos el socket al puerto if(bind(Sock, Addr, AddrSize) <> -1) then begin // escucha... while true do begin TimeVal.tv_sec:= 0; TimeVal.tv_usec:= 500; FD_ZERO(FDSet); FD_SET(Sock, FDSet); // Comprobamos si ha recibido algún mensaje if Select(0, @FDSet, nil, nil, @TimeVal) > 0 then begin Len:= recvfrom(Sock, BufferIn, 1023, 0, Addr, AddrSize); //recibimos los datos que envíe if (Len > 0) then begin IP:= Addr.sin_addr.S_addr; BufferIn[Len]:= #0; // Convertimos el Buffer en cadena ASCIIZ if not DecodeMsg(BufferIn, UDPid, Cmd, Val) then continue; // Añado la IP cliente a la lista AddIP(IP); if (lstrcmpi(UDPid, PCName) <> 0) and (lstrcmpi(UDPid, '255.255.255.255') <> 0) then continue; // Comandos if lstrcmpi(Cmd, 'GoogBye') = 0 then DeleteIP(IP); if lstrcmpi(Cmd, 'Get') = 0 then begin wsprintf(BufferOut, '%s Status %d %d %d ', PCName, Master.GetMasterVolume, Master.GetMasterMute, Locked); SendUDP(BufferOut, IP, PortOut); end else if lstrcmpi(Cmd, 'Volume') = 0 then begin Volume:= Val; Master.SetMasterVolume(Val); end else if lstrcmpi(Cmd, 'Mute') = 0 then begin Master.SetMasterMute(Val <> 0); Mute:= Val <> 0; end else if lstrcmpi(Cmd, 'Lock') = 0 then begin Locked:= Val <> 0; OnChangeStatus(Master.GetMasterVolume, Master.GetMasterMute); end else if lstrcmpi(Cmd, 'ServerQuit') = 0 then break; end; end; {select} end; {while} end; {bind} closesocket(Sock); end; {if(Sock <> INVALID_SOCKET)} WSACleanUp; PostThreadMessage(TID, WM_QUIT, 0, 0); end;
El cliente tiene otro hilo de escucha para recibir los cambios que realice un usuario remoto en los controles de volumen de su PC. La comunicación es bidireccional. El formato es bastante similar al del servidor:
procedure ThServer.Execute; var WSA: TWSADATA; Sock: TSOCKET; FDSet: TFDSET; TimeVal: TTIMEVAL; Addr: sockaddr_in; BufferIn: array[0..1024] of CHAR; Len, AddrSize: integer; begin if(WSAStartup(MakeWord(2,2), WSA) <> 0) then exit; Sock := WinSock.socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); if(Sock <> INVALID_SOCKET) then begin Addr.sin_family:= AF_INET; Addr.sin_addr.s_addr:= INADDR_ANY; Addr.sin_port:= htons(PortIn); AddrSize := sizeof(Addr); // Asociamos el socket al puerto if(bind(Sock, Addr, AddrSize) <> -1) then begin // escucha... while not Terminated do begin TimeVal.tv_sec:= 0; TimeVal.tv_usec:= 500; FD_ZERO(FDSet); FD_SET(Sock, FDSet); // Comprobamos si ha recibido algun mensaje if Select(0, @FDSet, nil, nil, @TimeVal) > 0 then begin Len:= recvfrom(Sock, BufferIn, 1023, 0, Addr, AddrSize); //recibimos los datos que envie if (Len > 0) then //si seguimos conectados begin BufferIn[Len]:= #0; // Convertimos el Buffer en cadena ASCIIZ // Comandos if Split(BufferIn, 1, ' ') = 'Status' then begin Volume:= StrToInt(Split(BufferIn, 2, ' ')); Mute:= Split(BufferIn, 3, ' ') = '1'; Locked:= Split(BufferIn, 4, ' ') = '1'; Synchronize(SetStatus); end end; end; {select} end; {while} end; {bind} closesocket(Sock); end; {if(Sock <> INVALID_SOCKET)} WSACleanUp; end;
Las funciones para enviar mensajes no requieren especial atención.
La instalación en el PC remoto se hará como sigue. Copiar el archivo ServerSound4.exe y InstallServer.exe en una carpeta del PC remoto y usar InstallServer.exe. Lo ideal será disponer de una clave de administrador en Win8 pues escribirá en el registro en la siguiente clave la información para que autoarranque con el sistema:
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\run\
En WinXP también es recomendable por si se han puesto restricciones en los permisos de acceso al registro. Al terminar la instalación borrar el archivo InstallServer.exe para evitar desinstalaciones no deseadas.
Con el Fin de no alargar el mensaje dejo para el siguiente las referencias a la App android.
Saludos.
Archivos adjuntos
#57
Escrito 10 abril 2014 - 11:33
El código de MainActivity.java es el siguiente:
package com.escafandra.lockpcsound; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.widget.Toast; import android.app.Activity; import android.app.AlertDialog; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnKeyListener; import android.view.KeyEvent; import android.widget.ToggleButton; import android.widget.SeekBar; import android.widget.TextView; import android.widget.EditText; import android.text.Editable; import android.text.TextWatcher; import android.view.inputmethod.InputMethodManager; import android.net.wifi.WifiManager; import android.content.Context; import java.util.TimerTask; import java.io.BufferedReader; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.net.*; import android.util.Log; public class MainActivity extends Activity { protected static final int MSG_INVALIDATE = 0x100; protected static final int MSG_MUTEVALUE = 0x101; protected static final int MSG_VOLUMEVALUE = 0x102; protected static final int MSG_LOCKVALUE = 0x103; public String UDPid; static SeekBar VolumeBar; static ToggleButton MuteCheck; static ToggleButton LockCheck; View MainContent; View MainFrame; EditText TextBox; int PortOut = 9999; int PortIn = 9998; InetAddress Address = null; boolean Connection = false; static boolean EnableHandler = true; static boolean EnableUpdateVolume = true; private Receiver receiver; // Manejador de mensajes threadsafe static Handler handler = new Handler() { @Override public void handleMessage(Message msg) { if (EnableHandler) switch (msg.what) { case MainActivity.MSG_INVALIDATE: final View view = (View) msg.obj; if (view != null) view.invalidate(); break; case MainActivity.MSG_LOCKVALUE: final ToggleButton LockCheck = (ToggleButton) msg.obj; if (LockCheck != null) { LockCheck.setChecked(msg.arg1 == 1); LockCheck.invalidate(); } break; case MainActivity.MSG_MUTEVALUE: final ToggleButton MuteCheck = (ToggleButton) msg.obj; if (MuteCheck != null) { MuteCheck.setChecked(msg.arg1 == 1); MuteCheck.invalidate(); } break; case MainActivity.MSG_VOLUMEVALUE: final SeekBar VolumeBar = (SeekBar) msg.obj; if (EnableUpdateVolume) if (VolumeBar != null) { VolumeBar.setProgress(msg.arg1); VolumeBar.invalidate(); } break; } super.handleMessage(msg); } }; protected synchronized void SetAddress(final InetAddress addr) { Address = addr; } public void Send(final String cmd, final int Value) { if (Address == null){ try { SetAddress(InetAddress.getByName("255.255.255.255")); Send("Get", 0, PortOut); } catch (Exception e){} } Send(cmd, Value, PortOut); } // Función encargada de enviar un comando public void Send(final String cmd, final int Value, final int Port) { //ShowKeyboard(false); Connection = true; TurnOnWifi(); // Desde version Honeycomb se debe hacer con un thread final Runnable runnable = new Runnable() { public void run() { try { UDPid = ((TextView) findViewById(R.id.editText)).getText().toString(); String Msg = new String(UDPid.getBytes("UTF-8"), "UTF-8") + " " + cmd + " " + Long.toString(Value); if (Address == null) Address = InetAddress.getByName("255.255.255.255"); // Creamos el socket DatagramSocket socket = new DatagramSocket(); // y un datagrama que enviamos socket.send(new DatagramPacket(Msg.getBytes("UTF-8"), Msg.length(), Address, Port)); // Cerramos el socket socket.close(); } catch (Exception e) { Connection = false; Log.e("LockPCSound", "exception", e); } } }; // Ejecutamos el thread new Thread(runnable).start(); } // Hilo de escucha y receptor de comandos public class Receiver implements Runnable { private Object ObjectLock; private boolean Terminated; private boolean Sleeping; int TimeOut = 1000; public Receiver() { ObjectLock = new Object(); Terminated = false; Sleeping = false; } public void Pause() { synchronized (ObjectLock) { Sleeping = true; } } public void Terminate() { synchronized (ObjectLock) { Terminated = true; } } public void Resume() { synchronized (ObjectLock) { Sleeping = false; ObjectLock.notifyAll(); } } @Override public void run() { DatagramSocket socket; DatagramPacket rcvPacket; byte[] Buffer; Terminated = false; try { Buffer = new byte[1024]; socket = new DatagramSocket(PortIn); socket.setSoTimeout(TimeOut); rcvPacket = new DatagramPacket(Buffer, Buffer.length); while (!Terminated) { try { synchronized (ObjectLock) { while (Sleeping && !Terminated) { try { ObjectLock.wait(); } catch (InterruptedException e) {} } } socket.receive(rcvPacket); Buffer[rcvPacket.getLength()] = ' '; String[] RcvMsg = (new String(Buffer, "UTF-8")).split(" "); if (RcvMsg[0].equals(UDPid)) { // Si recibo saludo pido status para identificarme if (RcvMsg[1].equals("Hello")) Send("Get", 0); else if (RcvMsg[1].equals("Quit")) { Terminated = true; }else if (RcvMsg[1].equals("Status")) { // recuperando la dirección del servidor SetAddress(rcvPacket.getAddress()); // Enciendo pilotito indicador de recepción ((RepeatSignal) findViewById(R.id.repeatSignal1)).run(3, 80); SetVolume(Integer.parseInt(RcvMsg[2])); SetMute(Integer.parseInt(RcvMsg[3]) == 1); SetLocked(Integer.parseInt(RcvMsg[4]) == 1); } } } catch (Exception e) { // Log.e("LockPCSound", "Timeout Receiver excedido", e); } } socket.close(); } catch (Exception e) { Log.e("LockPCSound", "No se puede crear socket", e); } } } protected void ShowToast(final String Msg) { Toast toast = Toast.makeText(getApplicationContext(), Msg, Toast.LENGTH_SHORT); toast.show(); } public void showToast(final String toast) { runOnUiThread(new Runnable() { public void run() { Toast.makeText(MainActivity.this, toast, Toast.LENGTH_SHORT).show(); } }); } protected void TurnOnWifi() { WifiManager wifiManager = (WifiManager) this .getSystemService(Context.WIFI_SERVICE); if (!wifiManager.isWifiEnabled()) { wifiManager.setWifiEnabled(true); ShowToast("Wifi desconectada. Conectando..."); } } protected void invalidateView(final View view) { Message message = new Message(); message.what = MSG_INVALIDATE; message.obj = view; handler.sendMessage(message); } // Envio de mensajes para el cambio de controles modo threadsafe protected synchronized void SetLocked(final boolean v) { Message message = new Message(); message.what = MSG_LOCKVALUE; message.obj = LockCheck; message.arg1 = v ? 1 : 0; handler.sendMessage(message); } protected synchronized void SetMute(final boolean v) { Message message = new Message(); message.what = MSG_MUTEVALUE; message.obj = MuteCheck; message.arg1 = v ? 1 : 0; handler.sendMessage(message); } protected synchronized void SetVolume(final int v) { Message message = new Message(); message.what = MSG_VOLUMEVALUE; message.obj = VolumeBar; message.arg1 = v / 0x492; handler.sendMessage(message); } protected void ShowKeyboard(boolean Show) { if (Show) ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)) .showSoftInput(TextBox, InputMethodManager.SHOW_FORCED); else ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)) .hideSoftInputFromWindow(TextBox.getWindowToken(), 0); TextBox.setCursorVisible(Show); } String getVersion(){ String version = new String(""); try { version = getPackageManager().getPackageInfo(getPackageName(), 0).versionName; } catch (Exception e) {} return version; } protected void SaveData() { try { FileOutputStream file = openFileOutput("data", Context.MODE_PRIVATE); file.write((getVersion() + "\n" + UDPid).getBytes()); file.close(); } catch (IOException e) { Log.e("Controller", e.getMessage() + e.getLocalizedMessage() + e.getCause()); } } // Datos persistentes protected void LoadData() { try { BufferedReader input = new BufferedReader(new InputStreamReader( openFileInput("data"))); String version = input.readLine().toString(); UDPid = input.readLine().toString(); ((EditText) findViewById(R.id.editText)).setText(UDPid); if(!getVersion().equals(version)){ showAbout(); } input.close(); } catch (IOException e) { Log.e("Controller", e.getMessage() + e.getLocalizedMessage() + e.getCause()); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main_frame); EnableHandler = true; EnableUpdateVolume = true; receiver = new Receiver(); new Thread(receiver).start(); LoadData(); MainFrame = findViewById(R.layout.main_frame); MainContent = findViewById(R.id.Main_Content); MainContent.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // Petición de actualizar status Send("Get", 0); ShowKeyboard(false); } }); TextBox = (EditText) findViewById(R.id.editText); TextBox.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { ShowKeyboard(true); } }); TextBox.addTextChangedListener(new TextWatcher() { public void afterTextChanged(Editable s) { UDPid = ((EditText) findViewById(R.id.editText)).getText().toString(); if (UDPid.equals("Broadcast") || UDPid.equals("255.255.255.255")) Address = null; else //GetAddr(); Send("Get", 0); } public void beforeTextChanged(CharSequence s, int start, int count, int after) { Send("Get", 0); } public void onTextChanged(CharSequence s, int start, int before, int count) { } }); TextBox.setOnKeyListener(new OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (keyCode == 66) { ShowKeyboard(false); // Petición de actualizar status Send("Get", 0); return true; } return false; } }); VolumeBar = (SeekBar) findViewById(R.id.volumebar); VolumeBar.setMax(0x38); VolumeBar.setProgress(0); VolumeBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (fromUser) Send("Volume", progress * 0x492); } @Override public void onStartTrackingTouch(SeekBar seekBar) { EnableUpdateVolume = false; Send("Get", 2); ShowKeyboard(false); } @Override public void onStopTrackingTouch(SeekBar seekBar) { Send("Get", 2); // Activo el EnableHandler con 200 ms de retraso para evitar // reverberancia TimerTask mTask = new TimerTask() { @Override public void run() { EnableUpdateVolume = true; } }; VolumeBar.postDelayed(mTask, 200); } }); VolumeBar.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Send("Get", 2); } }); MuteCheck = (ToggleButton)findViewById(R.id.mutecheck); MuteCheck.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Send("Mute", MuteCheck.isChecked() ? 1 : 0); Send("Get", 1); ShowKeyboard(false); } }); LockCheck = (ToggleButton)findViewById(R.id.lockcheck); LockCheck.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // Send("Volume", VolumeBar.getProgress() * 0x492); Send("Lock", LockCheck.isChecked() ? 1 : 0); Send("Get", 1); ShowKeyboard(false); } }); Send("Get", 0); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.about: showAbout(); return true; default: return super.onOptionsItemSelected(item); } } protected void showAbout() { // Inflate the about message contents View messageView = getLayoutInflater().inflate(R.layout.about, null, false); TextView textView = (TextView) messageView.findViewById(R.id.app_version); textView.append("Version " + getVersion() + "\n"); int defaultColor = textView.getTextColors().getDefaultColor(); textView.setTextColor(defaultColor); textView = (TextView) messageView.findViewById(R.id.about_credits); defaultColor = textView.getTextColors().getDefaultColor(); textView.setTextColor(defaultColor); AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setIcon(R.drawable.ic_app); builder.setTitle(R.string.app_name); builder.setView(messageView); builder.create(); builder.show(); } // Optimizando recursos android @Override public void onResume() { super.onResume(); receiver.Resume(); } @Override public void onPause() { super.onPause(); SaveData(); receiver.Pause(); if (isFinishing()){ Send("GoogBye", 0); receiver.Terminate(); } } }
El layout es el siguiente:
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <ImageView android:id="@+id/imageView1" android:layout_width="fill_parent" android:layout_height="fill_parent" android:scaleType="centerCrop" android:src="@drawable/ic_fondo" /> <RelativeLayout android:id="@+id/Main_Content" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="13dp" android:paddingRight="13dp" > <LinearLayout android:id="@+id/linearLayout1" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="50dp" android:gravity="center" android:orientation="vertical" > <TextView android:id="@+id/textView0" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:text="@string/Identificacion" android:textAppearance="?android:attr/textAppearanceSmall" android:textColor="#ffffff" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:gravity="center" android:orientation="horizontal" > <EditText android:id="@+id/editText" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" android:background="@drawable/edit" android:inputType="text" android:paddingRight="10dp" android:shadowColor="@android:color/background_dark" android:text="@string/uno" android:textColor="#000000" > <requestFocus /> </EditText> <com.escafandra.lockpcsound.RepeatSignal android:id="@+id/repeatSignal1" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="6" android:paddingLeft="10dp" android:background="#00000000" android:scaleType="center" android:src="@drawable/led_selector" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="25dp" android:gravity="center" android:orientation="horizontal" > <SeekBar android:id="@+id/volumebar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="2" android:focusable="true" android:indeterminate="false" android:max="65535" android:paddingRight="10dp" android:progress="0" android:thumb="@drawable/thumb" android:thumbOffset="0dp" /> <ToggleButton android:id="@+id/mutecheck" android:layout_width="48dp" android:layout_height="wrap_content" android:background="@null" android:button="@drawable/selector_mute" android:gravity="center" android:paddingLeft="5dp" android:textOff=" " android:textOn=" " /> </LinearLayout> <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="0dp" android:text="@string/Volumen" android:textAppearance="?android:attr/textAppearanceSmall" android:textColor="#ffffff" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="55dp" android:gravity="center" android:orientation="horizontal" > <ToggleButton android:id="@+id/lockcheck" android:layout_width="52dp" android:layout_height="wrap_content" android:background="@null" android:button="@drawable/selector_lock" android:gravity="center" android:paddingLeft="5dp" android:textOff=" " android:textOn=" " /> </LinearLayout> </LinearLayout> </RelativeLayout> </FrameLayout>
El archivo manifest para esta APP debe ser como sigue:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.escafandra.lockpcsound" android:versionCode="0100" android:versionName="0.1.0.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <application android:allowBackup="true" android:icon="@drawable/ic_app" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.escafandra.lockpcsound.MainActivity" android:label="@string/app_name" android:screenOrientation="portrait"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
La imagen de fondo de esta app contiene un «huevo de pascua» a ver quién lo descubre:
Publico adjuntos fuentes y binarios.
Espero que esta actualización sea de utilidad.
Saludos.
#58
Escrito 10 abril 2014 - 11:39
Saludos
#59
Escrito 10 abril 2014 - 04:17
#60
Escrito 10 abril 2014 - 04:25