[Android] Notification에 큰 이미지 적용하기

Posted by Find my true self Fimtrus
2014.12.30 14:47 Programming/Android

최근에 많은 앱들이 젤리빈(Android 4.1) 버전에서 추가된 BicPictureStyle을 이용하여 


노티바에 큰 이미지를 보여주고 있다.



두손가락을 이용해 위로 드래그 하게 되면 접히고, 아래로 드래그 하면 큰이미지가 보이면서 열리게 된다.


즉..접혔을때의 컨텐츠와 열렸을때 서로 다른 컨텐츠를 지정할 수 있다.


필자는 다양한 버전을 지원하기 위해 v4 support library를 사용하였으며


해당 값들의 세팅은 임의로 지정하였다.



/**
  * 먼저 NotificationCompat Builder를 선언한다.
  *  Builder의 경우 접혔을 때 노티바에 표시할 컨텐츠를 설정한다.
  */
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
	.setSmallIcon(R.drawable.ic_launcher) //작은아이콘 세팅
	.setContentTitle(context.getResources().getString(R.string.title) ) //노티바에 표시될 타이틀
        .setContentText(context.getResources().getString(R.string.message) ) //노티바에 표시된 Description
        .setAutoCancel(true) //클릭하게 되면 사라지도록...
        .setVibrate(new long[] { 1000, 1000 }) //노티가 등록될 때 진동 패턴 1초씩 두번.
        .setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE); //노티가 등록될 때 사운드와 진동이 오도록, 기본 사운드가 울리도록.

/**
  * 두 손가락으로 드래그 했을 때 표시된 컨텐츠를 설정한다.
  */
BigPictureStyle bigPictureStyle = new NotificationCompat.BigPictureStyle(builder); //상단의 빌더를 인자로 받음..
Bitmap bigPictureBitmap  = BitmapFactory.decodeResource(context.getResources(), R.drawable.i_hero); //드래그 후 공간에 표시할 이미지.
	bigPictureStyle.bigPicture(bigPictureBitmap) //상단의 비트맵을 넣어준다.
	.setBigContentTitle(context.getResources().getString( R.string.big_title) ) //열렸을때의 타이틀
	.setSummaryText(context.getResources().getString( R.string.big_message) ); //열렸을때의 Description


위와 같이 설정을 하게 되면 기존에 드래그해도 반응이 없던 노티가


아래로 커지면서 큰이미지를 표시하게 된다.


혹시...이해가 잘안된다면 아래 샘플을 참고..



notificationSample.zip



이 댓글을 비밀 댓글로
    • 안녕하세요
    • 2015.05.11 17:00
    안드로이드 개발에 많은 도움이 되었습니다. 감사합니다.
    한 가지 질문이 있습니다 ~
    BigPictureStyle 를 이용하여 push 알림에 이미지를 추가까지 완료를 하였는데요..
    닫힌 상태로 push 알림이 와 두 손가락을 이용하여 드래그하여야 expand 가 되어 이미지가 나오는데 처음 푸시 상태에서 이미지가 열림 상태로 나오게 하는 방법이 있나요?
    • 안녕하세요

      답변이 조금 늦었네요.

      expand 관련 메쏘드는 존재하지 않는 것 같아요.

      아무래도 여러개의 앱들의 푸시가 모두 펼쳐져 있으면 유저로서 불편함을 느낄 수 있기 때문이지 않을까 생각이 드네요.

[Android] drawable 리소스를 비트맵으로 변환. drawable resource to bitmap

Posted by Find my true self Fimtrus
2014.12.26 14:45 Programming/Android

바꿀때마다 소스를 찾아봐서


글남기네요..


정말 간단한건데 자바스크립트랑 안드로이드랑 왔다갔다하니....헷갈림..



//샘플 소스
Bitmap bigPictureBitmap  = BitmapFactory.decodeResource(context.getResources(), R.drawable.i_hero);


이 댓글을 비밀 댓글로

[Android] 사진 저장 후 갤러리에 보이지 않는 경우-MediaScanner

Posted by Find my true self Fimtrus
2014.07.25 10:51 Programming/Android

개별 파일로 intent를 통해 리소스 디비 업데이트

이동~~(Click)



이번에는 폴더 전체 스캔, MediaScanner를 통해 업데이트를 해보겠습니다.


이부분도 간단하게 구현가능한데, 범용성을 위해 클래스로 뺐습니다^^;



package com.jhlibrary.util;

import android.content.Context;
import android.media.MediaScannerConnection;
import android.media.MediaScannerConnection.MediaScannerConnectionClient;
import android.net.Uri;

public class MediaScanner {
	private Context mContext;

	private String mPath;

	private MediaScannerConnection mMediaScanner; 
	private MediaScannerConnectionClient mMediaScannerClient;

	public static MediaScanner newInstance(Context context) {
		return new MediaScanner(context);
	}

	private MediaScanner(Context context) {
		mContext = context;
	}

	public void mediaScanning(final String path) {

		if (mMediaScanner == null) {
			mMediaScannerClient = new MediaScannerConnectionClient() {

				@Override
				public void onMediaScannerConnected() {
					mMediaScanner.scanFile(mPath, null); // 디렉토리
					// 가져옴
				}

				@Override
				public void onScanCompleted(String path, Uri uri) {

				}
			};
			mMediaScanner = new MediaScannerConnection(mContext, mMediaScannerClient);
		}

		mPath = path;
		mMediaScanner.connect();
	}
}


직접 구현의 경우, MediaScannerConnection 클래스를 통해 디비에 접근(?), 


파일 또는 디렉토리 전체에 대한 업데이트를  할 수 있다.


먼저 MediaScannerConnectionClient 를 객체화 해줍니다.

(이 클래스는 MediaScannerConnection에서 callback을 받기 위한 클래스입니다).


그리고  connection을 위한 MediaScannerConnection을 객체화 하면 끝~!



사용하기 위해선 아래처럼 하시면 됩니다.



MediaScanner scanner = MediaScanner.newInstance(MainActivity.this);
scanner.mediaScanning("파일경로"); 
이 댓글을 비밀 댓글로
    • 1234
    • 2015.01.23 10:34
    MediaScanner scanner = MediaScanner.newInstance(MainActivity.this);
    scanner.mediaScanning("파일경로");
    여기서 MainActivity에서 오류가나는데 왜이런거죠?
      • 1234
      • 2015.01.23 10:38
      그리고 파일경로에는 /sdcard 이런식으로 적는건가요?
    • Environment 클래스에 보면 sd카드 등 파일패스 경로가 지정되어 있습니다.

      그걸 사용하셔서 해당 파일의 위치를 지정하시면 됩니다.
    • 스르르
    • 2015.11.27 00:06
    정말정말정말 감사합니다~~ 며칠동안 고민하던거 바로 해결했어요

[Android] 사진 저장 후 갤러리에 보이지 않는 경우.

Posted by Find my true self Fimtrus
2014.07.25 10:34 Programming/Android

안드로이드에서 현재 화면을 저장하는 경우, 또는 이미지를 저장하였을 때


갤러리에서 보이지 않는 경우가 있다.


안드로이드에서는 사용자가 가지고 있는 리소스를 디비화 해서 저장하고 있는데,


해당 파일의 정보 및 썸네일까지 담고 있다.


그래서 갤러리 같은 경우, 이미지 파일을 보여주긴 하지만 상당히 빠른 속도로 화면을 볼수 있는 이유 중의 하나이다.


아무튼..갤러리에 보여주기 위해서는 디비에 업데이트 해주는 인텐트가 필요하다. 아니면 별도의 스캐너를 사용해도되고....


간단하게 인텐트를 통해 해당 파일을 업데이트하는 방법이다.




//
context.sendBroadcast(new Intent( Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file)) );
//

context : Activity 또는 해당 어플리케이션의 context

file : 업데이트할 파일 객체.


이 댓글을 비밀 댓글로

[Android, Hybrid] 앱에서 파일 다운로드 구현. URL File Download.

Posted by Find my true self Fimtrus
2014.07.10 15:09 Programming/Android

웹브라우저를 이용해서 파일을 다운로드 받을 경우, 다운로드매니저를 통해 받게 된다.(진저브레드 이상)


앱에서 다운로드 매니저를 사용하여 파일 다운로드 받는 방법을 쓰고자 한다.


앱이나 하이브리드나 다운로드 하는 방법은 동일하다.


다운로드 매소드, 그리고 다운로드매니저로부터 액션을 받을 수 있는 리시버를 만드면 끝.!


Download Method

private DownloadManager mDownloadManager; //다운로드 매니저. 
private int mDownloadQueueId; //다운로드 큐 아이디..
private String mFileName ; //파일다운로드 완료후...파일을 열기 위해 저장된 위치를 입력해둔다.
/**
 * @param url : 파일을 다운로드할 url.
 */
public void download(String url) {
	if (mDownloadManager == null) {
		mDownloadManager = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
	}
	Request request = new DownloadManager.Request( Uri.parse(url) );
	request.setTitle("==타이틀==");
	request.setDescription("==설명==");
	List<string> pathSegmentList = uri.getPathSegments();
	Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS + "/temp").mkdirs();  //경로는 입맛에 따라...바꾸시면됩니다.
	request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS + "/temp/", pathSegmentList.get(pathSegmentList.size()-1) );
	mFileName = pathSegmentList.get(pathSegmentList.size()-1);

	mDownloadQueueId = mDownloadManager.enqueue(request);
}



다운로드관련 인텐트를 받을 리시버를 만들고, 등록시켜주면 끝!

(onResume 에서 등록, onPause에서 해제를 추천한다.)


Complete Receiver

/**
 * 다운로드 완료 액션을 받을 리시버.
 */
private BroadcastReceiver mCompleteReceiver = new BroadcastReceiver() {
	@Override
	public void onReceive(Context context, Intent intent) {
		String action = intent.getAction();
		if (action.equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
			Toast.makeText(context, "Complete.", Toast.LENGTH_SHORT).show();
			Intent intent1 = new Intent();
			intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
			intent1.setAction(android.content.Intent.ACTION_VIEW);
			intent1.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

			String localUrl = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
					+ "/temp/" + mFileName; //저장했던 경로..
			String extension = MimeTypeMap.getFileExtensionFromUrl(localUrl);
			String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);

			File file = new File(localUrl);
			intent1.setDataAndType(Uri.fromFile(file), mimeType);
			try {
				startActivity(intent1);
			} catch (ActivityNotFoundException e) {
				Toast.makeText(NPF.this, "Not found. Cannot open file.", Toast.LENGTH_SHORT).show();
				e.printStackTrace();
			}
		}
	}
};


@Override
protected void onPause() {
	super.onPause();
	unregisterReceiver(mCompleteReceiver);
}

@Override
protected void onResume() {
	super.onResume();
	IntentFilter completeFilter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
	registerReceiver(mCompleteReceiver, completeFilter);
}


하이브리드 앱의 경우 JavaInterface에 해당 method를 넣어주면 되고, 일반적인 앱에서 사용할 경우에는


유틸 같은 곳에 추가하여 사용하면된다.(물론 해당 method를 조금 수정해서 context를 받도록 해야할 것이긴 하지만)



이 댓글을 비밀 댓글로
    • 2014.07.14 09:31
    비밀댓글입니다
    • 조금의(?) 수정
    • 2015.10.21 22:14
    직접 내용을 수정하여 제목, 내용 커스텀 + 경로 지정 가능하게 해보고
    일반 앱에 바로 복붙하고 Import만 하면 가능하게 대충 수정을...

    public void download(String url, String title, String des, String path) {
    DownloadManager mDownloadManager = null; //다운로드 매니저.
    int mDownloadQueueId; //다운로드 큐 아이디..
    String mFileName ; //파일다운로드 완료후...파일을 열기 위해 저장된 위치를 입력해둔다.
    if (mDownloadManager == null) {
    mDownloadManager = (DownloadManager) getApplicationContext().getSystemService(Context.DOWNLOAD_SERVICE);
    }
    DownloadManager.Request request = new DownloadManager.Request( Uri.parse(url) );
    request.setTitle(title);
    request.setDescription(des);
    List<String> pathSegmentList = Uri.parse(url).getPathSegments();
    Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS + "/" + path).mkdirs(); //경로는 입맛에 따라...바꾸시면됩니다.
    request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS + "/" + path + "/", pathSegmentList.get(pathSegmentList.size()-1) );
    mFileName = pathSegmentList.get(pathSegmentList.size()-1);

    mDownloadQueueId = (int) mDownloadManager.enqueue(request);
    }

[Android] Notification 에서 onNewIntent가 타지 않는 문제. How to call onNewIntent from Notification.

Posted by Find my true self Fimtrus
2014.06.26 11:40 Programming/Android

launchMode 가 singleTask 혹은 singleTop 인 Activity에 intent를 보내게 되면,


존재 할 경우 onNewIntent, 존재하지 않을 경우 Activity가 새로 시작하게 된다.


일반적인 방법으로 액티비티를 호출할 때에는 startActivity로 호출하지만,


Notification을 통해 호출할 경우 PendingIntent를 사용하는데,


액티비티의 모드가 singTask, singleTop 이며 존재하는데도 


강제로 액티비티를 재시작시키는 경우가 있다.

(아마도..안드로이드 레퍼런스에 코드만 보고 만들어서 그런건 아닐까 생각이 든다.)


정상적인 Activity lifecycle을 태우기 위해선, PendingIntent 생성시 requestCode를 반드시 넣어야한다.

(대부분 default값으로 0을 넣는다)




대부분 REQUEST_CODE 부분에 0 을 넣는데, private 한 값을 추가시켜주면, 정상적으로 onNewIntent가 불린다.

PendingIntent resultPendingIntent = PendingIntent.getActivity(
        context, REQUEST_CODE, 
        resultIntent, 
        PendingIntent.FLAG_UPDATE_CURRENT);



이 댓글을 비밀 댓글로
    • 날개
    • 2014.11.07 15:14
    private 한 값이 무엇인가요 ?
    • 2015.10.06 09:54
    비밀댓글입니다

[Android] 안드로이드에서 핸드폰번호(휴대폰번호) 추출.

Posted by Find my true self Fimtrus
2014.06.24 17:06 Programming/Android

딱히..설명도 없고.. 그냥 사용하면 됨!


//TelephonyManager를 받아오고..
mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
String telephone = mTelephonyManager.getLine1Number(); //전화번호를 받는다~


이 댓글을 비밀 댓글로

[Android] 안드로이드 TextView 글자에 색깔 넣기. 부분적으로 색깔 넣기. html 스타일 적용.

Posted by Find my true self Fimtrus
2014.06.24 16:49 Programming/Android

Spannable 객체를 이용할 경우.


24와 37은 인덱스 값. 24~37 사이에 있는 글자만 변경된다.

Spannable descriptionString = (Spannable) mDescriptionTextView.getText();
descriptionString.setSpan(new StyleSpan(Typeface.BOLD), 24, 37, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
descriptionString.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.guide_message_highlight)), 24, 37, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
		



Html을 이용할 경우.


html에 대해 잘 아시는 분들이면 HTML을 이용하여 글자를 꾸미는게 더 효과적일 수 있다.

(단, 기본적인 것들은 정상적으로 보이지만, 몇몇 태그, css들은 웹과 동일하게 나오지는 않는다)

//HTML
mDescriptionTextView.setText( Html.fromHtml("<div>Te<span style="color:red;">st</span> Code</div>") )"
//
이 댓글을 비밀 댓글로

[Android] TextView, 글자에 외곽선(Border, outline) 넣기

Posted by Find my true self Fimtrus
2014.06.24 16:41 Programming/Android

안드로이드에서 외곽선을 넣기 위해선 TextView를 Customizing해야한다.(다른방법이 있을 수도..;)


TextView를 상속받아서 뷰를 조금 수정해야하고,


편하게 사용하기 위해 attr을 선언해주면 된다.


먼저 TextView를 상속 받은 OutlineTextView를 만든다.


public class OutlineTextView extends TextView {

	private boolean hasStroke = false;
	private float mStrokeWidth = 0.0f;
	private int mStrokeColor;

	public OutlineTextView(Context context) {
		super(context);
	}

	public OutlineTextView(Context context, AttributeSet attrs) {
		super(context, attrs);
		initView(context, attrs);
	}

	public OutlineTextView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		initView(context, attrs);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		if (hasStroke) {
			ColorStateList states = getTextColors();
			getPaint().setStyle(Style.STROKE);
			getPaint().setStrokeWidth(mStrokeWidth);
			setTextColor(mStrokeColor);
			super.onDraw(canvas);

			getPaint().setStyle(Style.FILL);
			setTextColor(states);
		}
		super.onDraw(canvas);
	}

	private void initView(Context context, AttributeSet attrs) {
		TypedArray typeArray = context.obtainStyledAttributes(attrs, R.styleable.OutlineTextView);
		hasStroke = typeArray.getBoolean(R.styleable.OutlineTextView_textStroke, false);
		mStrokeWidth = typeArray.getFloat(R.styleable.OutlineTextView_textStrokeWidth, 0.0f);
		mStrokeColor = typeArray.getColor(R.styleable.OutlineTextView_textStrokeColor, 0xffffffff);
	}
}


그리고 attr을 선언해준다. xml 파싱과정에서 관련된 value들을 받기 위해선 필수!

(\values\attrs.xml 에 선언해주면 된다.)


아래와 같이 선언해 놓으면 OutlineTextView를 사용할 때 해당 attribute를 사용할 수 있게 된다.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="OutlineTextView">
        <attr name="textStroke" format="boolean"/>
        <attr name="textStrokeWidth" format="dimension"/>
        <attr name="textStrokeColor" format="color"/>
    </declare-styleable>
</resources>


마지막으로 layout에 추가해주면 된다.

* xmlns의 이름 부분에는 xml에서 사용할 이름을 지정하면 된다.

* 패키지명은 반드시 앱 패키지 명과 동일해야 한다.

<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" 
	xmlns:@@이름@@="http://schemas.android.com/apk/res/@@ 패키지명 @@" 
	android:layout_width="fill_parent" 
	android:layout_height="fill_parent" 
	android:orientation="vertical">
	<com.fimtrus.flicktalk.view.OutlineTextView
		android:id="@+id/outlineTextView1" 
		android:layout_width="match_parent" 
		android:layout_height="wrap_content" 
		android:gravity="center_horizontal" 
		android:layout_above="@+id/relativeLayout1" 
		android:layout_centerhorizontal="true" 
		android:textsize="50sp" 
		android:layout_marginbottom="20dp" 
		android:text=" " 
		android:textcolor="@color/white" 
		android:padding="5dp" 
		android:singleline="false" 
		@@이름@@:textstroke="true" 
		@@이름@@:textstrokecolor="#000000" 
		@@이름@@:textstrokewidth="7.0">
	</com.fimtrus.flicktalk.view.OutlineTextView>
</linearlayout>


이 댓글을 비밀 댓글로
    • 2015.12.11 14:10
    비밀댓글입니다
  1. 조금더 보태자면 <attr name="textStrokeWidth" format="float">
    textStrokeWidth를 dimension으로 변경하고,
    mStrokeWidth = typeArray.getFloat(R.styleable.OutlineTextView_textStrokeWidth, 0.0f);
    getFloat -> getDimension으로 하시면 dp 값으로 적용 가능합니다.

[Android] 안드로이드에서 httpPost multiparts로 전송하기(멀티파트, 멀티파츠)

Posted by Find my true self Fimtrus
2014.06.24 16:10 Programming/Android

안드로이드에서는 httpClient의 버전이 낮아 multiparts를 지원하지 않는다.


보내고 싶다면 httpConnection을 열고, buffer를 통해서 전송해야 하는데,


만들기가 여간 귀찮은 것이 아니다.


apache에서 httpComponents를 제공하고 있는데, 해당 라이브러리를 사용하면,


별다른 구현을 하지 않더라도 multiparts로 전송할 수 있게 된다.


물론 약 1메가 정도의...라이브러리가 추가되긴 하지만..



아파치 사이트로 이동하여 httpClient 최신버전을 다운받는다.(전 4.3.X 버전 사용중)


Download Page(Click)


당연히 jar 파일이 필요하기 때문에 binary를 클릭해서 받아준다.




다운후 압축을 해제하게 되면, examples, lib, tutorial 폴더가 나오는데,


lib에 있는 jar파일들을 안드로이드 프로젝트의 libs 폴더로 복사하면 된다.


이제 multiparts로 전송하기 위한 준비는 다 되었고, 아래의 코드를 이용하여 보내면 된다.


//Multipart 객체를 선언한다.
MultipartEntityBuilder builder = MultipartEntityBuilder.create() //객체 생성...
	.setCharset(Charset.forName("UTF-8")) //인코딩을 UTF-8로.. 다들 UTF-8쓰시죠?
	.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); 
builder.addPart("content",  new FileBody(== 파일객체 ==) ); //빌더에 FileBody 객체에 인자로 File 객체를 넣어준다.
builder.addPart("testKey",  "testData" ); //스트링 데이터..

HttpClient client = AndroidHttpClient.newInstance("Android");

HttpPost post = new HttpPost(== url ==); //전송할 URL 
try {
	post.setEntity(builder.build()); //builder.build() 메쏘드를 사용하여 httpEntity 객체를 얻는다.
	HttpResponse httpRes;
	httpRes = client.execute(post);
	HttpEntity httpEntity = httpRes.getEntity();
	if (httpEntity != null) {
		response = EntityUtils.toString(httpEntity);
	}
} catch (UnsupportedEncodingException e) {
} catch (ClientProtocolException e1) {
} catch (IOException e1) {
} catch (ParseException e) {
}


위와 같이 전송하게 되면, 내부적으로 Stream을 이용하여 서버로 전송하게 되어


따로 작업을 하지 않더라도 multiparts 형태로 전송할 수 있다.


이 댓글을 비밀 댓글로
    • huhu
    • 2015.12.19 22:16
    예제 소스 파일좀 부탁드리겠습니다. 아무리해도 적용이 안됩니다.;