Mi aplicación Android con Twitter : Escribir un tweet

Blog >Comunicación con servidor > Enviar Tweet desde aplicación Android

Continuamos con el apartado Mi aplicación Android con Twitter, vamos a ver como generar un Tweet desde nuestra aplicación.
 

Mandar un tweet desde nuestra aplicación Android
 
El proyecto que os expongo tiene las librerías y las clases necesarias para poder mandar un tweet sin Twitter instalado en el dispositivo, es decir desde esta aplicación se verifica la aplicación que previamente se ha instalado en twitter y que se comenta en este post.









La función de esta aplicación va permitirnos conectarnos realizar una conexión http a twitter mandando las claves que previamente teníamos en la cabecera de la petición.
 

1. Instalar librerías y permiso a la app de internet

Tendremos que darle a la aplicación permisos para que pueda conectarse a Internet.
Nos va a hacer falta usar varias librerias, unas que tienen que ver con el framework de twitter, otras para la autentificación y otra para la conexión http :

O también os he preparado un rar con todas ellas juntas que podreis encontrar aquí.




 2. Creación de interfad, inicio sesión configuración clases y conexión a Twitter
 
Creamos un proyecto nuevo, y vamos a darle la interfaz de usuario, pero antes agregamos estos recursos :

Carpeta values...
colores.xml :

<?xml version="1.0" encoding="utf-8"?>
<resources>
   <color name="negro" >#000000</color>
   <color name="blanco">#ffffff</color>
   <color name="colorTweet">#908686</color>
    <color name="colorFace">#3b5997</color>
   <color name="colorTwitter">#1ab2e8</color>
   <color name="RojoError">#e81a29</color>
  
</resources>

Carpeta drawable...
botontwitter : Apariencia del botón al enviar tweets

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:state_pressed="true">
        <shape>
        <!-- color de fondo -->
        <solid android:color="@android:color/white"/>
        <!-- curvatura esquinas  -->
        <corners android:radius="12dp"/>
        <!-- padding para separar entre elementos contenidos y el borde -->
            <padding android:left="10dp"
            android:right="10dp"
            android:top="10dp"
            android:bottom="10dp"/>
        </shape>
    </item>
   
twitter_check : recurso xml que cambia de forma automática la imagen del checkbox

<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:state_checked="true"
        android:state_window_focused="true"
         android:state_enabled="true"
         android:drawable="@drawable/twitter_cnn" />

    <item
        android:state_checked="false"
        android:state_window_focused="true"
         android:state_enabled="true"
         android:drawable="@drawable/twitter_desc" />
</selector>

Este ultimo recurso usa 2 imágenes que hay que arrastrar al proyecto, así que cada uno se lo personalice como quiera,y una vez tenemos esto, vamos con el activity_main.xml :




<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/TWITTTEAR"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

   <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

       <CheckBox
           android:id="@+id/twitterCheckConnection"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_marginLeft="5dp"
           android:text="Conectado" />

            <CheckBox
                android:id="@+id/twitterCheck"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="5dp"
                android:clickable="true"
                android:focusable="true"
                android:text="Conectado usuario"
                android:textColor="@color/colorTwitter"
                android:textSize="14sp" />

    </LinearLayout>

   <LinearLayout
       android:layout_width="fill_parent"
       android:layout_height="wrap_content"
       android:layout_alignParentBottom="true"
       android:layout_alignParentLeft="true"
       android:orientation="vertical" >

       <EditText
           android:id="@+id/tweet"
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:maxLines="3"
           android:textColor="@color/colorTweet" >

           <requestFocus />
       </EditText>

       <LinearLayout
           android:layout_width="fill_parent"
           android:layout_height="wrap_content"
           android:layout_marginTop="10dp" >

           <TextView
               android:id="@+id/contarCaracteresTwitter"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:layout_gravity="center_vertical"
               android:layout_marginBottom="10dp"
               android:layout_marginLeft="20dp"
               android:text="0"
               android:textColor="@color/colorTwitter"
               android:textSize="20sp" />

           <LinearLayout
               android:layout_width="fill_parent"
               android:layout_height="wrap_content"
               android:orientation="vertical" >

               <Button
                   android:id="@+id/enviarTweet"
                   style="?android:attr/buttonStyleSmall"
                   android:layout_width="wrap_content"
                   android:layout_height="wrap_content"
                   android:layout_gravity="right"
                   android:layout_marginBottom="5dp"
                   android:layout_marginRight="10dp"
                   android:background="@drawable/botontwitter"
                   android:text="Enviar"
                   android:textColor="@color/blanco" />

           </LinearLayout>

       </LinearLayout>
   </LinearLayout>

   <LinearLayout
       android:layout_width="fill_parent"
       android:layout_height="280dp"
       android:layout_alignParentLeft="false"
       android:layout_alignParentTop="false"
       android:layout_centerHorizontal="true"
       android:layout_centerVertical="true"
       android:orientation="vertical" >

       <ListView
           android:id="@+id/listView1"
           android:layout_width="match_parent"
           android:layout_height="wrap_content" >
       </ListView>
   </LinearLayout>

</RelativeLayout>

Y este es nuestro main de momento :


public class MainActivity extends Activity {
 //CLAVES
 private static final String twitter_consumer_key = "AQUI TU CONSUMER_KEY";
 private static final String twitter_secret_key = "AQUI TU TWITTER_SECRET_KEY";

 //Elementos
 private CheckBox connectionCheck;
 private CheckBox userCheck;
 private ListView lista;
 private Button BotonEnviarTweet;
 private EditText tweet;
 private TextView Ncaracteres;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //INSTANCIAMOS ELEMENTOS
        instanciarElementos();
         //INICIAMOS VARIABLES
       mTwitter = new TwitterApp(this, twitter_consumer_key,twitter_secret_key);
       mTwitter.setListener(mTwLoginDialogListener);
        //BOTON PARA ENVIAR TWEETS
        BotonEnviarTweet.setOnClickListener(new OnClickListener(){
   @Override
   public void onClick(View v) {
    // TODO Auto-generated method stub
    
   }
        });
        //CHECKBOX CONECTAR
        registerCheck.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(View v) {

   }
  });
        //CHECKBOX USER
        connectionCheck.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(View v) {

   }
  });
              
    }
   public void instanciarElementos(){
     //Elementos
     registerCheck = (CheckBox) findViewById(R.id.twitterCheckConnection);
     connectionCheck = (CheckBox) findViewById(R.id.twitterCheck);
     lista  =  (ListView) findViewById(R.id.listViewTweets);
     BotonEnviarTweet = (Button) findViewById(R.id.enviarTweet);
     tweet =  (EditText) findViewById(R.id.tweet);
     Ncaracteres =(TextView) findViewById(R.id.contarCaracteresTwitter);
    }
}


Seguimos con otra clase : TwitterSession
Esta clase contiene los datos de registro en twitter, como la gestión de las preferencias para guardar los datos para identificarte en Twitter.

public class TwitterSession {
 private SharedPreferences sharedPref;
 private Editor editor;
 
 private static final String TWEET_AUTH_KEY = "auth_key";
 private static final String TWEET_AUTH_SECRET_KEY = "auth_secret_key";
 private static final String TWEET_USER_NAME = "user_name";
 private static final String SHARED = "Twitter_Preferences";
 
 public TwitterSession(Context context) {
  sharedPref= context.getSharedPreferences(SHARED, Context.MODE_PRIVATE);
  editor= sharedPref.edit();
 }
 
 public void storeAccessToken(AccessToken accessToken, String username) {
  editor.putString(TWEET_AUTH_KEY, accessToken.getToken());
  editor.putString(TWEET_AUTH_SECRET_KEY, accessToken.getTokenSecret());
  editor.putString(TWEET_USER_NAME, username);
  
  editor.commit();
 }
 
 public void resetAccessToken() {
  editor.putString(TWEET_AUTH_KEY, null);
  editor.putString(TWEET_AUTH_SECRET_KEY, null);
  editor.putString(TWEET_USER_NAME, null);
  
  editor.commit();
 }
 
 public String getUsername() {
  return sharedPref.getString(TWEET_USER_NAME, "");
 }
 
 public AccessToken getAccessToken() {
  String token   = sharedPref.getString(TWEET_AUTH_KEY, null);
  String tokenSecret  = sharedPref.getString(TWEET_AUTH_SECRET_KEY, null);
  
  if (token != null && tokenSecret != null) 
   return new AccessToken(token, tokenSecret);
  else
   return null;
 }
}


Ahora vamos a insertar una nueva clase : TwitterApp
En ella vemos como se gestiona la llamada http, el registro mediante la cabecera en Twitter y la recogida de la respuesta.

//CLASE CON LOS PARAMETROS PARA CONECTAR EN TWITTER
public class TwitterApp {
 
 private Twitter mTwitter;
 private TwitterSession mSession;
 private AccessToken mAccessToken;
 private CommonsHttpOAuthConsumer mHttpOauthConsumer;
 private OAuthProvider mHttpOauthprovider;
 private String mConsumerKey;
 private String mSecretKey;
 private ProgressDialog mProgressDlg;
 private TwDialogListener mListener;
 private Context context;
 private boolean mInit = true;
 
 public static final String CALLBACK_URL = "twitterapp://connect";
 private static final String TAG = "TwitterApp";
 
 //CONSTRUCTOR
 public TwitterApp(Context context, String consumerKey, String secretKey) {
  this.context= context;
  
  //INSTANCIA TWITTER
  mTwitter = new TwitterFactory().getInstance();
  mSession= new TwitterSession(context);
  mProgressDlg= new ProgressDialog(context);
  
  mProgressDlg.requestWindowFeature(Window.FEATURE_NO_TITLE);
  
  //DATOS ACCESO TWITTER
  setmConsumerKey(consumerKey);
  setmSecretKey(secretKey);
  //REALIZAMOS LA CONEXION CON RESPUESTA
  mHttpOauthConsumer = new CommonsHttpOAuthConsumer(getmConsumerKey(), getmSecretKey());
  mHttpOauthprovider = new DefaultOAuthProvider("https://api.twitter.com/oauth/request_token ",
              "https://api.twitter.com/oauth/access_token",
              "https://api.twitter.com/oauth/authorize");
  
  mAccessToken= mSession.getAccessToken();
  
  configureToken();
 }
 //DEVUELVE EL LISTENER PARA EL ALERTDIALOG
 public void setListener(TwDialogListener listener) {
  mListener = listener;
 }
 
 //funcion para iniciar sesion la primera vez
 private void configureToken() {
  if (mAccessToken != null) {
   if (mInit) {
    mTwitter.setOAuthConsumer(getmConsumerKey(), getmSecretKey());
    mInit = false;
   }
   mTwitter.setOAuthAccessToken(mAccessToken);
  }
 }
 
 public boolean estasConectado() {
  if(mAccessToken == null){
   return false;
  }
   return true;
 }
 
 public void resetAccessToken() {
  if (mAccessToken != null) {
   mSession.resetAccessToken();
  
   mAccessToken = null;
  }
 }
 
 public String getUsername() {
  return mSession.getUsername();
 }
 
 public void updateStatus(String status) throws Exception {
  try {
   mTwitter.updateStatus(status);
  } catch (TwitterException e) {
   throw e;
  }
 }
 
 public void authorize() {
  mProgressDlg.setMessage("Initializing ...");
  mProgressDlg.show();
  //NUEVO HILO CON EL ALERT PARA QUE SE ABRA LA VENTANA
  new Thread() {
   @Override
   public void run() {
    String authUrl = "";
    int what = 1;
    
    try {
     //hacemos la llamada al navegador
     authUrl = mHttpOauthprovider.retrieveRequestToken(mHttpOauthConsumer, CALLBACK_URL); 
     what = 0;
     Log.d(TAG, "Request token url " + authUrl);
    } catch (Exception e) {
     //EL PROCESO HA FALLADO
     Log.d(TAG, "Failed to get request token");
     e.printStackTrace();
    }
    
    mHandler.sendMessage(mHandler.obtainMessage(what, 1, 0, authUrl));
   }
  }.start();
 }
 //
 public void processToken(String callbackUrl)  {
  mProgressDlg.setMessage("Finalizing ...");
  mProgressDlg.show();
  
  final String verifier = getVerifier(callbackUrl);

  new Thread() {
   @Override
   public void run() {
    int what = 1;
    
    try {
     mHttpOauthprovider.retrieveAccessToken(mHttpOauthConsumer, verifier);
     mAccessToken = new AccessToken(mHttpOauthConsumer.getToken(), mHttpOauthConsumer.getTokenSecret());
     Log.d(TAG, "Token: " + mAccessToken.getToken());
     configureToken();
     User user = mTwitter.verifyCredentials();
           mSession.storeAccessToken(mAccessToken, user.getName());
           what = 0;
    } catch (Exception e){
     Log.d(TAG, "Error getting access token");
     e.printStackTrace();
    }
    
    mHandler.sendMessage(mHandler.obtainMessage(what, 2, 0));
   }
  }.start();
 }
 //RECOJEMOS LA RESPUESTA
 @SuppressWarnings("deprecation")
 private String getVerifier(String callbackUrl) {
  String verifier  = "";
  
  try {
   callbackUrl = callbackUrl.replace("twitterapp", "http");
   
   URL url   = new URL(callbackUrl);
   String query  = url.getQuery();
  
   String array[] = query.split("&");

   for (String parameter : array) {
              String v[] = parameter.split("=");
              
              if (URLDecoder.decode(v[0]).equals(oauth.signpost.OAuth.OAUTH_VERIFIER)) {
               verifier = URLDecoder.decode(v[1]);
               break;
              }
         }
  } catch (MalformedURLException e) {
   e.printStackTrace();
  }
  
  return verifier;
 }
 
 private void showLoginDialog(String url) {
  final TwDialogListener listener = new TwDialogListener() {
   @Override
   public void onComplete(String value) {
    processToken(value);
   }
   
   @Override
   public void onError(String value) {
    mListener.onError("Failed opening authorization page");
   }
  };
  
  new TwitterDialog(context, url, listener).show();
 }
 
 public String getmConsumerKey() {
  return mConsumerKey;
 }
 public void setmConsumerKey(String mConsumerKey) {
  this.mConsumerKey = mConsumerKey;
 }

 public String getmSecretKey() {
  return mSecretKey;
 }
 public void setmSecretKey(String mSecretKey) {
  this.mSecretKey = mSecretKey;
 }

 private Handler mHandler = new Handler() {
  @Override
  public void handleMessage(Message msg) {
   mProgressDlg.dismiss();
   
   if (msg.what == 1) {
    if (msg.arg1 == 1)
     mListener.onError("Error getting request token");
    else
     mListener.onError("Error getting access token");
   } else {
    if (msg.arg1 == 1)
     showLoginDialog((String) msg.obj);
    else
     mListener.onComplete("");
   }
  }
 };
 
 public interface TwDialogListener {
  public void onComplete(String value);  
  
  public void onError(String value);
 }
}


Esta clase también usa una interfad como listener, esto es para que cuando esté abierto el WebView dentro del dialog, podamos interactuar con ella posteriormente de forma automática vuelve el foco a la activity.

La clase TwitterDialog, que usa un alertDialog y se introduce un webView dentro, personaliza la cabecera del dialog y usa de apoyo una clase que hereda de WebViewClient, que es la que nos vale para interactuar con el webView que hay dentro del dialog.

public class TwitterDialog extends Dialog {
    static final FrameLayout.LayoutParams FILL = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                               ViewGroup.LayoutParams.MATCH_PARENT);
    static final int MARGIN = 4;
    static final int PADDING = 2;

    private String mUrl;
    private TwDialogListener mListener;
    private ProgressDialog mDialog;
    private WebView mWebView;
    private LinearLayout mContent;
    private TextView mTitulo;

    private static final String TAG = "Twitter-WebView";
    
    public TwitterDialog(Context context, String url, TwDialogListener listener) {
        super(context);
        
        mUrl= url;
        mListener=listener;
    }

 @SuppressWarnings("deprecation")
 @Override
 //ESTA CLASE CARGA UN WEBVIEW EN UN DIALOG
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mDialog = new ProgressDialog(getContext());
        mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        mDialog.setMessage("Cargando...");
        mContent = new LinearLayout(getContext());
        mContent.setOrientation(LinearLayout.VERTICAL);
        setUpTitle();
        setUpWebView();
        
        Display display = getWindow().getWindowManager().getDefaultDisplay();
  Point outSize= new Point();
  
  int width= 0;
  int height= 0;
  
  double[] dimensions = new double[2];
          
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
   display.getSize(outSize);
   
   width = outSize.x;
   height = outSize.y;
  } else {
   width = display.getWidth();
   height = display.getHeight();
  }
  
  if (width < height) {
   dimensions[0] = 0.87 * width;
         dimensions[1] = 0.82 * height;
  } else {
   dimensions[0] = 0.75 * width;
   dimensions[1] = 0.75 * height;         
  }
        
        addContentView(mContent, new FrameLayout.LayoutParams((int) dimensions[0], (int) dimensions[1]));
    }
 //QUITA EL TITULO DEL DIALOG Y CONFIGURA UN TEXTVIEW 
 //QUE APARECERÁ COMO TÍTULO
    private void setUpTitle() {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        
        Drawable icon = getContext().getResources().getDrawable(R.drawable.twitter_desc);
        
        mTitulo = new TextView(getContext());
        
        mTitulo.setText("Twitter");
        mTitulo.setTextColor(Color.WHITE);
        mTitulo.setTypeface(Typeface.DEFAULT_BOLD);
        mTitulo.setBackgroundColor(0xFFbbd7e9);
        mTitulo.setPadding(MARGIN + PADDING, MARGIN, MARGIN, MARGIN);
        mTitulo.setCompoundDrawablePadding(MARGIN + PADDING);
        mTitulo.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
        
        mContent.addView(mTitulo);
    }

    @SuppressLint("SetJavaScriptEnabled")
 private void setUpWebView() {
     CookieSyncManager.createInstance(getContext()); 
        CookieManager cookieManager = CookieManager.getInstance();
        cookieManager.removeAllCookie();
        
        mWebView = new WebView(getContext());
        
        mWebView.setVerticalScrollBarEnabled(false);
        mWebView.setHorizontalScrollBarEnabled(false);
        mWebView.setWebViewClient(new TwitterWebViewClient());
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.loadUrl(mUrl);
        mWebView.setLayoutParams(FILL);
        
        mContent.addView(mWebView);
    }

    //CLASE QUE HEREDA DE WEBVIEWCLIENT Y LLEVA LA GESTION DE LA WEBVIEW SW CREDENCIALES
    private class TwitterWebViewClient extends WebViewClient {
     //METODO PARA CARGAR LA WEB
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
         Log.d(TAG, "Redirecting URL " + url);
         
         if (url.startsWith(TwitterApp.CALLBACK_URL)) {
          mListener.onComplete(url);
          
          TwitterDialog.this.dismiss();
          
          return true;
         }  else if (url.startsWith("authorize")) {
          return false;
         }
            return true;
        }
        //SI LA PAGINA DA ERROR
        @Override
        public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
         Log.d(TAG, "Page error: " + description);
            super.onReceivedError(view, errorCode, description, failingUrl);
            mListener.onError(description);
            TwitterDialog.this.dismiss();
        }

        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            Log.d(TAG, "Loading URL: " + url);
            super.onPageStarted(view, url, favicon);
            mDialog.show();
        }

        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            String title = mWebView.getTitle();
            if (title != null && title.length() > 0) {
                mTitulo.setText(title);
            }
            mDialog.dismiss();
        }

    }
}


Y ahora implementamos en el main 2 funciones, que dependiendo si se está registrado o no, saca el dialog con el webview para insertar las credenciales, o por otro lado si se está registrado, se prepara para enviar el tweet.

     private void onTwitterClick() {
  //SI YA ESTAS CONECTADO A TWITTER
  if (mTwitter.estasConectado()) {
   final AlertDialog.Builder builder = new AlertDialog.Builder(this);
   //MESAJE CON LA CONFIRMACION DE LA DESCONEXION
   builder.setMessage("Delete current Twitter connection?")
          .setCancelable(false)
          .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
              @SuppressLint("ResourceAsColor") 
              public void onClick(DialogInterface dialog, int id) {
               mTwitter.resetAccessToken();
               
               //ACTUALIZAMOS CHECKBOX
               registerCheck.setChecked(false);
               registerCheck.setText(" Not connected ");
               registerCheck.setTextColor(R.color.colorTweet);
              }
          })
          //EN EL CASO DE QUE SE PULSE NO, VOLVEMOS A LA PRIMERA PANTALLA
          .setNegativeButton("No", new DialogInterface.OnClickListener() {
              public void onClick(DialogInterface dialog, int id) {
                   dialog.cancel();
                   registerCheck.setChecked(true);
              }
          });
   final AlertDialog alert = builder.create();
   
   alert.show();
   //SINO ESTAS CONECTADO MANDAMOS A AUTHORIZE, DONDE APARECE
   //PARA ENVIAR LAS CREDENCIALES DE AUTENTIFICACION
  } else {
   registerCheck.setChecked(false);
   //Cargamos loading... mas credenciales de twitter
   mTwitter.authorize();
  }
 }

 @SuppressLint("ResourceAsColor") 
 private final TwDialogListener mTwLoginDialogListener = new TwDialogListener() {
  @Override
  public void onComplete(String value) {
   //YA CONECTADO PIDE EL NOMBRE A LA RESPUESTA HTTP
   String username = mTwitter.getUsername();
   username= (username.equals("")) ? "No Name" : username;
   
   registerCheck.setText("  Conectado (" + username + ")");
   registerCheck.setChecked(true);
   registerCheck.setTextColor(R.color.colorTweet);
   Toast.makeText(MainActivity.this, "Connected to Twitter as " + username, Toast.LENGTH_LONG).show();
   //startActivity(new Intent(MainActivity.this, TestPost.class));
  }
  
  @Override
  public void onError(String value) {
   
   registerCheck.setChecked(false);
   Toast.makeText(MainActivity.this, "Twitter connection failed", Toast.LENGTH_LONG).show();
  }
 };
///////Y AHORA DENTRO DEL ONCLICK DEL CHECKBOX, LLAMAR A LA FUNCION  
onTwitterClick();


Con esto debería funcionar, según se ejecuta el main, pulsamos sobre el checkbox y como resultado nos dará un dialog en el que se ha incrustado el webView, y un par de dialogs mas,además de haber personalizado la cabecera, ahí es donde tenemos que introducir nuestras credenciales.








Y si no hay problemas de conexión, este es el resultado : 




Bien, lo bueno de que se manejen preferencias, es que ahora si nos salimos de la aplicación y volvemos a entrar, abrá que repetir todo el proceso de autentificación, aunque los datos personales de la cuenta ya están almacenados, entonces hay que optimizar eso, aprobechando el hilo del onCreate después de las instancias al botón y los checkbox, ponemos una condición :

 //SI HAY CONEXION SE PULSA EL CHECKBOX
  if (mTwitter.estasConectado()) {
   registerCheck.setChecked(true);
   
   String username = mTwitter.getUsername();
   username= (username.equals("")) ? "Unknown" : username;
   //Se actualiza el estado con el nombre
   registerCheck.setText("  Twitter (" + username + ")");
   registerCheck.setTextColor(Color.WHITE);
   
  }else{
   onTwitterClick();
  }



Así, si ejecutas el proyecto otra vez, saltas el paso de las credenciales y se autentifica automáticamente

Sólo si están guardadas con anterioridad. Por supuesto como en el propio twitter, al quitar el check, te va a preguntar si quieres desconectar, que a efectos prácticos es como el cerrar sesión del twitter normal, se borran las preferencias y listo.




Como hemos tocado el código varias veces de la actividad principal, lo pongo entero para que no haya lugar a dudas :

public class MainActivity extends  Activity {
 private TwitterApp mTwitter;
 private CheckBox mTwitterBtn;

 
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  //INICIAMOS VARIABLES
  mTwitter = new TwitterApp(this, twitter_consumer_key,twitter_secret_key);
  mTwitter.setListener(mTwLoginDialogListener);
  //Checkbox para conectar A TWITTER
  mTwitterBtn = (CheckBox) findViewById(R.id.twitterCheck);
  mTwitterBtn.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(View v) {
    onTwitterClick();
   }
  });
  //AÑADI LAS LINEAS A UNA FUNCIÓN  
  ConectarPorDefecto()
  
  Button goBtn = (Button) findViewById(R.id.button1);
  goBtn.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(View v) {
    startActivity(new Intent(MainActivity.this, TestPost.class));
   }
  });
 }
     private void ConectarPorDefecto(){
     //SI HAY CONEXION SE PULSA EL CHECKBOX
  if (mTwitter.estasConectado()) {
   registerCheck.setChecked(true);
   
   String username = mTwitter.getUsername();
   username= (username.equals("")) ? "Unknown" : username;
   //Se actualiza el estado con el nombre
   registerCheck.setText("  Twitter (" + username + ")");
   registerCheck.setTextColor(Color.WHITE);
   
  }else{
   onTwitterClick();
  }
    }
 
 
 
 private void onTwitterClick() {
  //SI YA ESTAS CONECTADO A TWITTER
  if (mTwitter.estasConectado()) {
   final AlertDialog.Builder builder = new AlertDialog.Builder(this);
   //MESAJE CON LA CONFIRMACION DE LA DESCONEXION
   builder.setMessage("Delete current Twitter connection?")
          .setCancelable(false)
          .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
              @SuppressLint("ResourceAsColor") 
              public void onClick(DialogInterface dialog, int id) {
               mTwitter.resetAccessToken();
               
               //ACTUALIZAMOS CHECKBOX
               mTwitterBtn.setChecked(false);
               mTwitterBtn.setText(" Not connected ");
               mTwitterBtn.setTextColor(R.color.colorTweet);
              }
          })
          //EN EL CASO DE QUE SE PULSE NO, VOLVEMOS A LA PRIMERA PANTALLA
          .setNegativeButton("No", new DialogInterface.OnClickListener() {
              public void onClick(DialogInterface dialog, int id) {
                   dialog.cancel();
                   
                   mTwitterBtn.setChecked(true);
              }
          });
   final AlertDialog alert = builder.create();
   
   alert.show();
   //SINO ESTAS CONECTADO MANDAMOS A AUTHORIZE, DONDE APARECE
   //PARA ENVIAR LAS CREDENCIALES DE AUTENTIFICACION
  } else {
   mTwitterBtn.setChecked(false);
   //Cargamos loading... mas credenciales de twitter
   mTwitter.authorize();
  }
 }

 private final TwDialogListener mTwLoginDialogListener = new TwDialogListener() {
  @Override
  public void onComplete(String value) {
   String username = mTwitter.getUsername();
   username  = (username.equals("")) ? "No Name" : username;
  
   mTwitterBtn.setText("  Conectado como  (" + username + ")");
   mTwitterBtn.setChecked(true);
   mTwitterBtn.setTextColor(Color.WHITE);
   Toast.makeText(MainActivity.this, "Connected to Twitter as " + username, Toast.LENGTH_LONG).show();
   startActivity(new Intent(MainActivity.this, TestPost.class));
  }
  
  @Override
  public void onError(String value) {
   mTwitterBtn.setChecked(false);
   
   Toast.makeText(MainActivity.this, "Twitter connection failed", Toast.LENGTH_LONG).show();
  }
 };
}


3. Validar nuestro Tweet a enviar  

Vamos ya a lo que es, escribir el tweet. Tenemos que meter una etiqueta en el inputText para asegurarnos que si se quiere twittear, siempre se marque la etiqueta, y por otra parte en nuestro TextView, el que tiene la funcionalidad de contar los caracteres, para validar el tweet, ya que no puede estar a 0 o pasarse de 140 caracteres en total. 

El conteo de los caracteres es regresivo, es decir, no empieza en 0, sino en 140 y se va restando el numero de caracteres que cuando sea inferior a 0, tomará un color rojo. En nuestro onCreate, al final del todo :
Y en el onclick del botón azul de enviartweet :   



 tweet.addTextChangedListener(new TextWatcher() {
   int caracteres=0;
   @SuppressLint("ResourceAsColor") @Override
   public void onTextChanged(CharSequence s, int start, int before, int count) {
    caracteres=140-(tweet.getText().length() );
    Ncaracteres.setText(String.valueOf(caracteres));
    if(caracteres < 0){
    Ncaracteres.setTextColor(Ncaracteres.getContext().getResources().getColor(R.color.RojoError));
    }else{         Ncaracteres.setTextColor(Ncaracteres.getContext().getResources().getColor(R.color.colorTwitter));   
    }
   }
   @Override
   public void beforeTextChanged(CharSequence s, int start, int count,
     int after) {
    // TODO Auto-generated method stub
   }
   @Override
   public void afterTextChanged(Editable s) {
    // TODO Auto-generated method stub 
   }
  });



Añadimos en nuestra función instanciarElementos :

     // YA METO TEXTO EN EL INPUTTEXT
        tweet.setText(" #thebestandroide");
        //APAREZCA EL NUMERO CARACTERES POR DEFECTO
        Ncaracteres.setText(String.valueOf(140-(tweet.getText().length()) ) );



Y en el onclick del botón azul de enviartweet :

    if(validarTweet(String.valueOf(tweet.getText()))){
     Toast.makeText(MainActivity.this, "Hasta dentro!",Toast.LENGTH_SHORT).show();
    }else{
     Toast.makeText(MainActivity.this, "Tweet incorrecto",Toast.LENGTH_SHORT).show();
     }


Si quereis ver más claro el tema de contar caracteres de un EditText, podeis verlo en este antiguo post.





4. Posteando un tweet

Ya sólo nos queda conectarnos y enviar el  tweet, ya que aunque tengamos la session abierta, hace falta conectar con Twitter para enviar el Tweet. Está misión la lleva a cabo el método authorize() de la clase TwitterApp

Ya que esta todo dispuesto, he cambiado uno de los checkbox por un textview porque así es más sencillo, pongo la clase main entera para que no haya lugar a dudas :

public class MainActivity extends Activity {
 //CLAVES
 private static final String twitter_consumer_key = "tu_consumer_key";
 private static final String twitter_secret_key = "tu__secret_key";

 //Elementos
 private CheckBox registerCheck;
 private ListView lista;
 private Button BotonEnviarTweet;
 private EditText tweet;
 private TextView Ncaracteres;
 private TextView Conectado;
 
 //VARIABLES 
 private TwitterApp mTwitter;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //INSTANCIAMOS ELEMENTOS
        instanciarElementos();
      //INICIAMOS VARIABLES
       mTwitter = new TwitterApp(this, twitter_consumer_key,twitter_secret_key);
       mTwitter.setListener(mTwLoginDialogListener);
       
       
        //BOTON PARA ENVIAR TWEETS
        BotonEnviarTweet.setOnClickListener(new OnClickListener(){
   @Override
   public void onClick(View v) {
    // TODO Auto-generated method stub
    if(validarTweet(String.valueOf(tweet.getText()))){
     if (mTwitter.estasConectado()){
      Twittear(String.valueOf(tweet.getText()));
     }else{
      mTwitter.authorize();
      Conectado.setText(" Conectando...");
      Toast.makeText(MainActivity.this, "Estamos conectando, por favor reenvie!",Toast.LENGTH_SHORT).show();
      
     }
    
    }else{
     Toast.makeText(MainActivity.this, "Tweet incorrecto",Toast.LENGTH_SHORT).show();
     }
   }
        });
        //CHECKBOX CONECTAR
        registerCheck.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(View v) {
    onTwitterClick();
   }
  });
        tweet.addTextChangedListener(new TextWatcher() {
   int caracteres=0;
   @SuppressLint("ResourceAsColor")
   @Override
   public void onTextChanged(CharSequence s, int start, int before, int count) {
    caracteres=140-(tweet.getText().length() );
    Ncaracteres.setText(String.valueOf(caracteres));
    if(caracteres < 0){
     Ncaracteres.setTextColor(Ncaracteres.getContext().getResources().getColor(R.color.RojoError));

    }else{
     Ncaracteres.setTextColor(Ncaracteres.getContext().getResources().getColor(R.color.colorTwitter));   
    }
   }
   @Override
   public void beforeTextChanged(CharSequence s, int start, int count,
     int after) {
    // TODO Auto-generated method stub
   }
   @Override
   public void afterTextChanged(Editable s) {
    // TODO Auto-generated method stub 
   }
  });
  //CONECTAMOS POR DEFECTO
        ConectarPorDefecto();
    }
   private boolean validarTweet(String tweet){
    if(tweet.length()>140){
     return false;
    }else if(tweet.compareTo("")==0){
     return false;
    }else{
     return true;
    }

   }
    private void ConectarPorDefecto(){
     //SI HAY CONEXION SE PULSA EL CHECKBOX
  if (mTwitter.estasConectado()) {
   registerCheck.setChecked(true);
   
   String username = mTwitter.getUsername();
   username= (username.equals("")) ? "Unknown" : username;
   //Se actualiza el estado con el nombre
   registerCheck.setText("  Twitter (" + username + ")");
   
   
  }else{
   onTwitterClick();
  }
    }
    //FUNCION QUE HACE UN HILO PARA CONECTAR CON TWITTER Y POSTEAR EL TWEET
 private void Twittear(final String review) {
  new Thread() {
   @Override
   public void run() {
    int what = 0;
    
    try {
     mTwitter.updateStatus(review);
    } catch (Exception e) {
     what = 1;
     Log.e("Error Tweet NO Enviado!! excepcion"+e, "FAIL");
    }
    mHandler.sendMessage(mHandler.obtainMessage(what));
   }
  }.start();
 }
 //HANDLER QUE RECOGE EL MENSAJE
 private Handler mHandler = new Handler() {
   @Override
   public void handleMessage(Message msg) {
    String text = (msg.what == 0) ? "Posted to Twitter" : "Post to Twitter failed";
    Toast.makeText(MainActivity.this, text, Toast.LENGTH_SHORT).show();
   }
  };
    //CONEXION A TWITTER
    private void onTwitterClick() {
  //SI YA ESTAS CONECTADO A TWITTER
  if (mTwitter.estasConectado()) {
   final AlertDialog.Builder builder = new AlertDialog.Builder(this);
   //MESAJE CON LA CONFIRMACION DE LA DESCONEXION
   builder.setMessage("Delete Twitter Session?")
          .setCancelable(false)
          .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
              @SuppressLint("ResourceAsColor") 
              public void onClick(DialogInterface dialog, int id) {
               mTwitter.resetAccessToken();
               
               //ACTUALIZAMOS CHECKBOX
               registerCheck.setChecked(false);
               registerCheck.setText(" Not connected ");
               registerCheck.setTextColor(R.color.colorTweet);
              }
          })
          //EN EL CASO DE QUE SE PULSE NO, VOLVEMOS A LA PRIMERA PANTALLA
          .setNegativeButton("No", new DialogInterface.OnClickListener() {
              public void onClick(DialogInterface dialog, int id) {
                   dialog.cancel();
                   registerCheck.setChecked(true);
              }
          });
   final AlertDialog alert = builder.create();
   
   alert.show();
   //SINO ESTAS CONECTADO MANDAMOS A AUTHORIZE, DONDE APARECE
   //PARA ENVIAR LAS CREDENCIALES DE AUTENTIFICACION
  } else {
   registerCheck.setChecked(false);
   //Cargamos loading... mas credenciales de twitter
   mTwitter.authorize();
  }
 }

 @SuppressLint("ResourceAsColor") 
 private final TwDialogListener mTwLoginDialogListener = new TwDialogListener() {
  @Override
  public void onComplete(String value) {
   //YA CONECTADO PIDE EL NOMBRE A LA RESPUESTA HTTP
   String username = mTwitter.getUsername();
   username= (username.equals("")) ? "No Name" : username;
   
   Conectado.setText(" "+username);
   registerCheck.setText(" Conectado");
   registerCheck.setChecked(true);
   registerCheck.setTextColor(R.color.colorTweet);
   Toast.makeText(MainActivity.this, "Connected to Twitter as " + username, Toast.LENGTH_LONG).show();
   //startActivity(new Intent(MainActivity.this, TestPost.class));
  }
  
  @Override
  public void onError(String value) {
   
   registerCheck.setChecked(false);
   Toast.makeText(MainActivity.this, "Twitter connection failed", Toast.LENGTH_LONG).show();
  }
 };
 
 
    public void instanciarElementos(){
     //Elementos
     registerCheck = (CheckBox) findViewById(R.id.twitterCheckConnection);
     lista  =  (ListView) findViewById(R.id.listViewTweets);
     BotonEnviarTweet = (Button) findViewById(R.id.enviarTweet);
     tweet =  (EditText) findViewById(R.id.tweet);
     Ncaracteres =(TextView) findViewById(R.id.contarCaracteresTwitter);
     Conectado =(TextView) findViewById(R.id.conectado);
  Conectado.setText(" No user");
     // YA METO TEXTO EN EL INPUTTEXT
        tweet.setText(" @BestAndroide");
        //APAREZCA EL NUMERO CARACTERES POR DEFECTO
        Ncaracteres.setText(String.valueOf(140-(tweet.getText().length()) ) );
        
    }
}


Aquí vemos el resultado : 

Para conectarte con las credenciales :



Para escribir un tweet :



Y si entramos de nuevo, no se nos demandará que ingresemos las credenciales si hemos dejado la session abierta, de lo contrario sí.

Podeis descargar el código fuente de thebestandroide con sólo compartir en facebook,twitter,linkedin o suscribirte a nuestro canal RSS más abajo.




Compartir Compartir Compartir Compartir



0 comentarios:

Publicar un comentario