blob: 9c2e8119a6c011bc99ac2e1e3a94d9fd9330e8da [file] [log] [blame]
/*
* Copyright 2012 The Android Open Source Project
*
* 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.android.notificationstudio;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnLayoutChangeListener;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.FrameLayout.LayoutParams;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RemoteViews;
import android.widget.TextView;
import com.android.notificationstudio.action.ShareCodeAction;
import com.android.notificationstudio.action.ShareMockupAction;
import com.android.notificationstudio.editor.Editors;
import com.android.notificationstudio.generator.NotificationGenerator;
import com.android.notificationstudio.model.EditableItem;
import com.android.notificationstudio.model.EditableItemConstants;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class NotificationStudioActivity extends Activity implements EditableItemConstants{
private static final String TAG = NotificationStudioActivity.class.getSimpleName();
private static final int PREVIEW_NOTIFICATION = 1;
private static final int REFRESH_DELAY = 50;
private static final ExecutorService BACKGROUND = Executors.newSingleThreadExecutor();
private boolean mRefreshPending;
private final Handler mHandler = new Handler();
private final Runnable mRefreshNotificationInner = new Runnable() {
public void run() {
refreshNotificationInner();
}};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setBackgroundDrawableResource(android.R.color.black);
setContentView(R.layout.studio);
initPreviewScroller();
EditableItem.initIfNecessary(this);
initEditors();
}
private void initPreviewScroller() {
MaxHeightScrollView preview = (MaxHeightScrollView) findViewById(R.id.preview_scroller);
if (preview == null)
return;
final int margin = ((ViewGroup.MarginLayoutParams) preview.getLayoutParams()).bottomMargin;
preview.addOnLayoutChangeListener(new OnLayoutChangeListener(){
public void onLayoutChange(View v, int left, int top, int right, int bottom,
int oldLeft, int oldTop, int oldRight, int oldBottom) {
// animate preview height changes
if (oldBottom != bottom) {
final View e = findViewById(R.id.editors);
final int y = bottom + margin;
e.animate()
.translationY(y - oldBottom)
.setListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
FrameLayout.LayoutParams lp = (LayoutParams) e.getLayoutParams();
lp.topMargin = y;
e.setTranslationY(0);
e.setLayoutParams(lp);
}
});
}
}});
// limit the max height for preview, leave room for editors + soft keyboard
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
float actualHeight = dm.heightPixels / dm.ydpi;
float pct = actualHeight < 3.5 ? .32f :
actualHeight < 4 ? .35f :
.38f;
preview.setMaxHeight((int)(dm.heightPixels * pct));
}
private void initEditors() {
LinearLayout items = (LinearLayout) findViewById(R.id.items);
items.removeAllViews();
String currentCategory = null;
for (EditableItem item : EditableItem.values()) {
String itemCategory = item.getCategory(this);
if (!itemCategory.equals(currentCategory)) {
View dividerView = getLayoutInflater().inflate(R.layout.divider, null);
((TextView) dividerView.findViewById(R.id.divider_text)).setText(itemCategory);
items.addView(dividerView);
currentCategory = itemCategory;
}
View editorView = Editors.newEditor(this, items, item);
if (editorView != null)
items.addView(editorView);
}
refreshNotification();
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
// we'll take care of restoring state
}
public void refreshNotification() {
mRefreshPending = true;
mHandler.postDelayed(mRefreshNotificationInner, REFRESH_DELAY);
}
private void refreshNotificationInner() {
if (!mRefreshPending) {
return;
}
final Notification notification = NotificationGenerator.build(this);
ViewGroup oneU = (ViewGroup) findViewById(R.id.oneU);
ViewGroup fourU = (ViewGroup) findViewById(R.id.fourU);
View oneUView = refreshRemoteViews(oneU, notification.contentView);
if (Build.VERSION.SDK_INT >= 16)
refreshRemoteViews(fourU, notification.bigContentView);
else if (Build.VERSION.SDK_INT >= 11) {
ImageView largeIcon = (ImageView) findViewById(R.id.large_icon);
largeIcon.setVisibility(notification.largeIcon == null ? View.GONE : View.VISIBLE);
if (notification.largeIcon != null)
largeIcon.setImageBitmap(notification.largeIcon);
} else if (oneUView != null) {
oneUView.setBackgroundColor(getResources().getColor(R.color.gb_background));
oneUView.setMinimumHeight(100);
}
mRefreshPending = false;
// this can take a while, run on a background thread
BACKGROUND.submit(new Runnable() {
public void run() {
NotificationManager mgr =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
try {
mgr.notify(PREVIEW_NOTIFICATION, notification);
} catch (Throwable t) {
Log.w(TAG, "Error displaying notification", t);
}
}});
}
private View refreshRemoteViews(ViewGroup parent, RemoteViews remoteViews) {
parent.removeAllViews();
if (remoteViews != null) {
parent.setVisibility(View.VISIBLE);
try {
View v = remoteViews.apply(this, parent);
parent.addView(v);
return v;
} catch (Exception e) {
TextView exceptionView = new TextView(this);
exceptionView.setText(e.getClass().getSimpleName() + ": " + e.getMessage());
parent.addView(exceptionView);
return exceptionView;
}
} else {
parent.setVisibility(View.GONE);
return null;
}
}
// action bar setup
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.action_bar, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_share_code:
ShareCodeAction.launch(this, item.getTitle());
return true;
case R.id.action_share_mockup:
ShareMockupAction.launch(this, item.getTitle());
return true;
}
return false;
}
// hides the soft keyboard more aggressively when leaving text editors
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
View v = getCurrentFocus();
boolean ret = super.dispatchTouchEvent(event);
if (v instanceof EditText) {
View currentFocus = getCurrentFocus();
int screenCoords[] = new int[2];
currentFocus.getLocationOnScreen(screenCoords);
float x = event.getRawX() + currentFocus.getLeft() - screenCoords[0];
float y = event.getRawY() + currentFocus.getTop() - screenCoords[1];
if (event.getAction() == MotionEvent.ACTION_UP
&& (x < currentFocus.getLeft() ||
x >= currentFocus.getRight() ||
y < currentFocus.getTop() ||
y > currentFocus.getBottom())) {
InputMethodManager imm =
(InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getWindow().getCurrentFocus().getWindowToken(), 0);
}
}
return ret;
}
}