/******************************************************************************* * Copyright 2011, 2012, 2013 fanfou.com, Xiaoke, Zhang * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ package com.fanfou.app.opensource; import java.io.File; import java.io.IOException; import android.app.Activity; import android.content.ContentUris; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.net.Uri; import android.os.Bundle; import android.provider.BaseColumns; import android.provider.MediaStore; import android.text.Editable; import android.text.Selection; import android.util.Log; import android.view.View; import android.view.WindowManager; import android.widget.ImageView; import android.widget.TextView; import com.fanfou.app.opensource.adapter.AtTokenizer; import com.fanfou.app.opensource.adapter.AutoCompleteCursorAdapter; import com.fanfou.app.opensource.api.bean.Draft; import com.fanfou.app.opensource.db.Contents.BasicColumns; import com.fanfou.app.opensource.db.Contents.DraftInfo; import com.fanfou.app.opensource.db.Contents.UserInfo; import com.fanfou.app.opensource.dialog.ConfirmDialog; import com.fanfou.app.opensource.service.Constants; import com.fanfou.app.opensource.service.PostStatusService; import com.fanfou.app.opensource.ui.ActionBar; import com.fanfou.app.opensource.ui.ActionBar.AbstractAction; import com.fanfou.app.opensource.ui.ActionManager; import com.fanfou.app.opensource.ui.TextChangeListener; import com.fanfou.app.opensource.ui.widget.MyAutoCompleteTextView; import com.fanfou.app.opensource.util.CommonHelper; import com.fanfou.app.opensource.util.IOHelper; import com.fanfou.app.opensource.util.ImageHelper; import com.fanfou.app.opensource.util.OptionHelper; import com.fanfou.app.opensource.util.StringHelper; /** * @author mcxiaoke * @version 1.0 2011.06.20 * @version 2.0 2011.10.24 * @version 3.0 2011.10.27 * @version 4.0 2011.11.08 * @version 4.7 2011.12.26 * */ public class WritePage extends BaseActivity { private class LocationMonitor implements LocationListener { @Override public void onLocationChanged(final Location location) { if (location != null) { updateLocationString(location); } } @Override public void onProviderDisabled(final String provider) { } @Override public void onProviderEnabled(final String provider) { } @Override public void onStatusChanged(final String provider, final int status, final Bundle extras) { } } private class SendAction extends AbstractAction { public SendAction() { super(R.drawable.ic_send); } @Override public void performAction(final View view) { doSend(); } } private static final String TAG = WritePage.class.getSimpleName(); private static final int REQUEST_PHOTO_CAPTURE = 0; private static final int REQUEST_PHOTO_LIBRARY = 1; private static final int REQUEST_LOCATION_ADD = 2; private static final int REQUEST_USERNAME_ADD = 3; private static final int REQUEST_PHOTO_EFFECTS = 4; private ActionBar mActionBar; private MyAutoCompleteTextView mAutoCompleteTextView; private View mPictureView; private ImageView iPicturePrieview; private ImageView iPictureRemove; private TextView tWordsCount; private ImageView iAtIcon; private ImageView iDraftIcon; private ImageView iLocationIcon; private ImageView iGalleryIcon; private ImageView iCameraIcon; private Uri photoUri; private File photo; private String contentOriginal; private String content; private int wordsCount; private String mLocationString; private LocationManager mLocationManager; private String mLocationProvider; private LocationMonitor mLocationMonitor; private boolean enableLocation; private String inReplyToStatusId; private String text; private int type; private int size; public static final int TYPE_NORMAL = 0; public static final int TYPE_REPLY = 1; public static final int TYPE_REPOST = 2; public static final int TYPE_GALLERY = 3; public static final int TYPE_CAMERA = 4; private void checkSave() { final ConfirmDialog dialog = new ConfirmDialog(this, "保存草稿", "要保存未发送内容为草稿吗?"); dialog.setButton1Text("保存"); dialog.setButton2Text("放弃"); dialog.setClickListener(new ConfirmDialog.ClickHandler() { @Override public void onButton1Click() { doSaveDrafts(); finish(); } @Override public void onButton2Click() { finish(); } }); dialog.show(); } private void deleteDraft(final int id) { if (id >= 0) { getContentResolver().delete( ContentUris.withAppendedId(DraftInfo.CONTENT_URI, id), null, null); } } private void doSaveDrafts() { final Draft d = new Draft(); d.type = this.type; d.text = this.content; d.filePath = this.photo == null ? "" : this.photo.toString(); d.replyTo = this.inReplyToStatusId; getContentResolver().insert(DraftInfo.CONTENT_URI, d.toContentValues()); } private void doSend() { if (this.wordsCount < 1) { CommonHelper.notify(this, "消息内容不能为空"); return; } CommonHelper.hideKeyboard(this, this.mAutoCompleteTextView); startSendService(); finish(); } private void hidePreview() { this.mPictureView.setVisibility(View.GONE); } private void initialize() { this.enableLocation = OptionHelper.readBoolean(this.mContext, R.string.option_location_enable, true); this.mLocationManager = (LocationManager) this .getSystemService(Context.LOCATION_SERVICE); this.mLocationMonitor = new LocationMonitor(); this.size = Float.valueOf( getResources().getDimension(R.dimen.photo_preview_width)) .intValue(); for (final String provider : this.mLocationManager.getProviders(true)) { if (LocationManager.NETWORK_PROVIDER.equals(provider) || LocationManager.GPS_PROVIDER.equals(provider)) { this.mLocationProvider = provider; break; } } if (this.mDisplayMetrics.heightPixels < 600) { getWindow().setSoftInputMode( WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED); } } private void insertNames(final Intent intent) { final String names = intent.getStringExtra(Constants.EXTRA_TEXT); if (AppContext.DEBUG) { log("doAddUserNames: " + names); } if (!StringHelper.isEmpty(names)) { final Editable editable = this.mAutoCompleteTextView .getEditableText(); editable.append(names); Selection.setSelection(editable, editable.length()); } } private void log(final String message) { Log.d(WritePage.TAG, message); } @Override protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) { if (resultCode == Activity.RESULT_OK) { switch (requestCode) { case REQUEST_LOCATION_ADD: break; case REQUEST_PHOTO_LIBRARY: if (AppContext.DEBUG) { log("onActivityResult requestCode=REQUEST_PHOTO_LIBRARY"); } if (data != null) { final Uri uri = data.getData(); onPhotoFromLibrary(uri); } break; case REQUEST_PHOTO_CAPTURE: if (AppContext.DEBUG) { log("onActivityResult requestCode=REQUEST_PHOTO_CAPTURE"); } if (data != null) { onPhotoFromCamera(data); } break; case REQUEST_PHOTO_EFFECTS: if (data != null) { log("onActivityResult requestCode=REQUEST_PHOTO_EFFECTS uri=" + data.getData()); onPhotoFromFiltered(data); } break; case REQUEST_USERNAME_ADD: if (AppContext.DEBUG) { log("onActivityResult requestCode=REQUEST_USERNAME_ADD"); } if (data != null) { insertNames(data); } break; default: break; } } } @Override public void onBackPressed() { if (AppContext.DEBUG) { log("onBackPressed content=" + this.content + " contentOriginal=" + this.contentOriginal); } if (StringHelper.isEmpty(this.content) || this.content.equals(this.contentOriginal)) { super.onBackPressed(); } else { checkSave(); } } @Override public void onClick(final View v) { final int id = v.getId(); switch (id) { case R.id.write_action_at: startAddUsername(); break; case R.id.write_action_draft: ActionManager.doShowDrafts(this); break; case R.id.write_action_location: switchLocation(); break; case R.id.write_action_gallery: startAddPicture(); break; case R.id.write_action_camera: startCameraShot(); break; case R.id.write_picture_remove: removePicture(); break; default: break; } } @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); initialize(); setLayout(); parseIntent(); } @Override protected void onNewIntent(final Intent intent) { super.onNewIntent(intent); setIntent(intent); parseIntent(); } @Override protected void onPause() { super.onPause(); if (this.enableLocation) { this.mLocationManager.removeUpdates(this.mLocationMonitor); } } private void onPhotoFromCamera(final Intent data) { try { if (AppContext.DEBUG) { log("from camera uri=" + this.photoUri); log("from camera filename=" + this.photo.getCanonicalPath()); log("file.size=" + this.photo.length()); } showPreview(); // applyEffects(photoUri); } catch (final IOException e) { e.printStackTrace(); } catch (final Exception e) { e.printStackTrace(); } } private void onPhotoFromFiltered(final Intent data) { final Uri uri = data.getData(); String path; if (uri.getScheme().equals("content")) { path = IOHelper.getRealPathFromURI(this, uri); } else { path = uri.getPath(); } this.photo = new File(path); if (this.photo.exists()) { this.photoUri = uri; } if (AppContext.DEBUG) { log("onFilteredComplete uri=" + this.photoUri); try { log("onFilteredComplete filename=" + this.photo.getCanonicalPath()); } catch (final IOException e) { } log("onFilteredComplete file.size=" + this.photo.length()); } showPreview(); } private void onPhotoFromLibrary(final Uri uri) { if (uri != null) { if (AppContext.DEBUG) { log("from gallery uri=" + this.photoUri); } String path; if (uri.getScheme().equals("content")) { path = IOHelper.getRealPathFromURI(this, uri); } else { path = uri.getPath(); } this.photo = new File(path); if (this.photo.exists()) { this.photoUri = uri; } else { this.photoUri = null; } if (AppContext.DEBUG) { log("from gallery file=" + path); } showPreview(); // applyEffects(photoUri); } } @Override protected void onResume() { super.onResume(); if (this.enableLocation && (this.mLocationProvider != null)) { this.mLocationManager.requestLocationUpdates( this.mLocationProvider, 0, 0, this.mLocationMonitor); } } private void parseIntent() { this.type = WritePage.TYPE_NORMAL; final Intent intent = getIntent(); if (intent != null) { final String action = intent.getAction(); if (action == null) { this.type = intent.getIntExtra(Constants.EXTRA_TYPE, WritePage.TYPE_NORMAL); this.text = intent.getStringExtra(Constants.EXTRA_TEXT); this.inReplyToStatusId = intent .getStringExtra(Constants.EXTRA_IN_REPLY_TO_ID); final File file = (File) intent .getSerializableExtra(Constants.EXTRA_DATA); final int draftId = intent.getIntExtra(Constants.EXTRA_ID, -1); parsePhoto(file); updateUI(); deleteDraft(draftId); } else if (action.equals(Intent.ACTION_SEND) || action.equals(Constants.ACTION_SEND)) { final Bundle extras = intent.getExtras(); if (extras != null) { this.text = extras.getString(Intent.EXTRA_TEXT); final Uri uri = extras.getParcelable(Intent.EXTRA_STREAM); onPhotoFromLibrary(uri); updateUI(); } } else if (action.equals(Constants.ACTION_SEND_FROM_GALLERY)) { this.type = WritePage.TYPE_GALLERY; startAddPicture(); } else if (action.equals(Constants.ACTION_SEND_FROM_CAMERA)) { this.type = WritePage.TYPE_CAMERA; startCameraShot(); } this.contentOriginal = this.text == null ? null : this.text.trim(); if (AppContext.DEBUG) { log("intent type=" + this.type); log("intent text=" + this.text); } } } private void parsePhoto(final File file) { if ((file != null) && file.exists()) { this.photo = file; this.photoUri = Uri.fromFile(file); if (AppContext.DEBUG) { log("from file=" + file); } } } private void removePicture() { hidePreview(); this.photo = null; this.photoUri = null; } /** * 初始化和设置ActionBar */ private void setActionBar() { this.mActionBar = (ActionBar) findViewById(R.id.actionbar); this.mActionBar.setTitle("写消息"); this.mActionBar.setRightAction(new SendAction()); this.mActionBar.setLeftAction(new ActionBar.BackAction(this)); } private void setAutoComplete() { this.mAutoCompleteTextView = (MyAutoCompleteTextView) findViewById(R.id.write_text); this.mAutoCompleteTextView .addTextChangedListener(new TextChangeListener() { @Override public void onTextChanged(final CharSequence s, final int start, final int before, final int count) { WritePage.this.content = s.toString().trim(); WritePage.this.wordsCount = WritePage.this.content .length(); showCount(WritePage.this.wordsCount); } }); this.mAutoCompleteTextView.setTokenizer(new AtTokenizer()); this.mAutoCompleteTextView.setBackgroundResource(R.drawable.input_bg); final String[] projection = new String[] { BaseColumns._ID, BasicColumns.ID, UserInfo.SCREEN_NAME, BasicColumns.TYPE, BasicColumns.OWNER_ID }; final String where = BasicColumns.OWNER_ID + " = '" + AppContext.getUserId() + "' AND " + BasicColumns.TYPE + " = '" + Constants.TYPE_USERS_FRIENDS + "'"; // Cursor cursor = managedQuery(UserInfo.CONTENT_URI, projection, where, // null, // null); final Cursor cursor = getContentResolver().query(UserInfo.CONTENT_URI, projection, where, null, null); this.mAutoCompleteTextView.setAdapter(new AutoCompleteCursorAdapter( this, cursor)); } private void setLayout() { setContentView(R.layout.write); setActionBar(); setAutoComplete(); this.mPictureView = findViewById(R.id.write_picture); this.iPicturePrieview = (ImageView) findViewById(R.id.write_picture_prieview); this.iPictureRemove = (ImageView) findViewById(R.id.write_picture_remove); this.tWordsCount = (TextView) findViewById(R.id.write_extra_words); this.iAtIcon = (ImageView) findViewById(R.id.write_action_at); this.iDraftIcon = (ImageView) findViewById(R.id.write_action_draft); this.iLocationIcon = (ImageView) findViewById(R.id.write_action_location); this.iGalleryIcon = (ImageView) findViewById(R.id.write_action_gallery); this.iCameraIcon = (ImageView) findViewById(R.id.write_action_camera); this.iAtIcon.setOnClickListener(this); this.iDraftIcon.setOnClickListener(this); this.iLocationIcon.setOnClickListener(this); this.iGalleryIcon.setOnClickListener(this); this.iCameraIcon.setOnClickListener(this); this.iPictureRemove.setOnClickListener(this); this.iLocationIcon .setImageResource(this.enableLocation ? R.drawable.ic_bar_geoon : R.drawable.ic_bar_geooff); } private void showCount(final int count) { if (count > 140) { this.tWordsCount.setTextColor(getResources().getColorStateList( R.color.write_count_alert_text)); this.tWordsCount.setText("字数超标:" + (count - 140)); } else { this.tWordsCount.setTextColor(getResources().getColorStateList( R.color.write_count_text)); this.tWordsCount.setText("剩余字数:" + (140 - count)); } } private void showPreview() { this.mPictureView.setVisibility(View.VISIBLE); try { this.iPicturePrieview .setImageBitmap(ImageHelper.getRoundedCornerBitmap( ImageHelper.resampleImage(this.photo, this.size), 6)); } catch (final Exception e) { e.printStackTrace(); } } private void startAddPicture() { final Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType("image/*"); // startActivityForResult(intent, REQUEST_PHOTO_LIBRARY); startActivityForResult(Intent.createChooser(intent, "选择照片"), WritePage.REQUEST_PHOTO_LIBRARY); } private void startAddUsername() { final Intent intent = new Intent(this, UserChoosePage.class); startActivityForResult(intent, WritePage.REQUEST_USERNAME_ADD); } private void startCameraShot() { this.photo = IOHelper.getPhotoFilePath(this); this.photoUri = Uri.fromFile(this.photo); final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT, this.photoUri); startActivityForResult(Intent.createChooser(intent, "拍摄照片"), WritePage.REQUEST_PHOTO_CAPTURE); } private void startSendService() { final Intent i = new Intent(this.mContext, PostStatusService.class); i.putExtra(Constants.EXTRA_TYPE, this.type); i.putExtra(Constants.EXTRA_TEXT, this.content); i.putExtra(Constants.EXTRA_DATA, this.photo); i.putExtra(Constants.EXTRA_LOCATION, this.mLocationString); i.putExtra(Constants.EXTRA_IN_REPLY_TO_ID, this.inReplyToStatusId); if (AppContext.DEBUG) { log("intent=" + i); } startService(i); } private void switchLocation() { this.enableLocation = !this.enableLocation; OptionHelper.saveBoolean(this.mContext, R.string.option_location_enable, this.enableLocation); if (AppContext.DEBUG) { log("location enable status=" + this.enableLocation); } if (this.enableLocation) { this.iLocationIcon.setImageResource(R.drawable.ic_bar_geoon); if (this.mLocationProvider != null) { this.mLocationManager.requestLocationUpdates( this.mLocationProvider, 0, 0, this.mLocationMonitor); } } else { this.iLocationIcon.setImageResource(R.drawable.ic_bar_geooff); this.mLocationManager.removeUpdates(this.mLocationMonitor); } } private void updateLocationString(final Location loc) { if (loc != null) { this.mLocationString = String.format("%1$.5f,%2$.5f", loc.getLatitude(), loc.getLongitude()); if (AppContext.DEBUG) { log("Location Info: " + this.mLocationString); } } } private void updateUI() { if (!StringHelper.isEmpty(this.text)) { this.mAutoCompleteTextView.setText(this.text); if (this.type != WritePage.TYPE_REPOST) { Selection.setSelection(this.mAutoCompleteTextView.getText(), this.mAutoCompleteTextView.getText().length()); } } if (this.photoUri != null) { showPreview(); } } }