1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.videoeditor; 18 19 import android.app.ActionBar; 20 import android.app.AlertDialog; 21 import android.app.Dialog; 22 import android.content.DialogInterface; 23 import android.content.Intent; 24 import android.os.Bundle; 25 import android.text.InputType; 26 import android.util.DisplayMetrics; 27 import android.util.Log; 28 import android.view.Menu; 29 import android.view.MenuItem; 30 import android.view.View; 31 import android.widget.AdapterView; 32 import android.widget.Button; 33 import android.widget.GridView; 34 import android.widget.PopupMenu; 35 import android.widget.TextView; 36 import android.widget.Toast; 37 38 import com.android.videoeditor.service.ApiService; 39 import com.android.videoeditor.service.ApiServiceListener; 40 import com.android.videoeditor.service.VideoEditorProject; 41 import com.android.videoeditor.util.FileUtils; 42 43 import java.util.List; 44 45 /** 46 * Activity that lets user pick a project or create a new one. 47 */ 48 public class ProjectsActivity extends NoSearchActivity { 49 private static final String LOG_TAG = "ProjectsActivity"; 50 51 private static final int REQUEST_CODE_OPEN_PROJECT = 1; 52 private static final int REQUEST_CODE_CREATE_PROJECT = 2; 53 54 // The project path returned by the picker 55 public static final String PARAM_OPEN_PROJECT_PATH = "path"; 56 public static final String PARAM_CREATE_PROJECT_NAME = "name"; 57 58 // Menu ids 59 private static final int MENU_NEW_PROJECT_ID = 1; 60 61 // Dialog ids 62 private static final int DIALOG_NEW_PROJECT_ID = 1; 63 private static final int DIALOG_REMOVE_PROJECT_ID = 2; 64 65 // Dialog parameters 66 private static final String PARAM_DIALOG_PATH_ID = "path"; 67 68 // Threshold in width dip for showing title in action bar 69 private static final int SHOW_TITLE_THRESHOLD_WIDTH_DIP = 1000; 70 71 private GridView mGridView; 72 private List<VideoEditorProject> mProjects; 73 private ProjectPickerAdapter mAdapter; 74 75 // Listener that responds to the event when projects are loaded. It populates the grid view with 76 // project thumbnail and information. 77 private final ApiServiceListener mProjectsLoadedListener = new ApiServiceListener() { 78 @Override 79 public void onProjectsLoaded(List<VideoEditorProject> projects, Exception exception) { 80 if (projects != null && exception == null) { 81 mProjects = projects; 82 // Initialize adapter with project list and populate data in the grid view. 83 mAdapter = new ProjectPickerAdapter(ProjectsActivity.this, getLayoutInflater(), projects); 84 mGridView.setAdapter(mAdapter); 85 } 86 } 87 }; 88 89 @Override 90 public void onCreate(Bundle savedInstanceState) { 91 super.onCreate(savedInstanceState); 92 setContentView(R.layout.project_picker); 93 94 // Show action bar title only on large screens. 95 final ActionBar actionBar = getActionBar(); 96 final DisplayMetrics displayMetrics = new DisplayMetrics(); 97 getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); 98 final int widthDip = (int) (displayMetrics.widthPixels / displayMetrics.scaledDensity); 99 // Only show title on large screens (width >= 1000 dip). 100 if (widthDip >= SHOW_TITLE_THRESHOLD_WIDTH_DIP) { 101 actionBar.setDisplayOptions(actionBar.getDisplayOptions() | 102 ActionBar.DISPLAY_SHOW_TITLE); 103 actionBar.setTitle(R.string.full_app_name); 104 } 105 106 mGridView = (GridView) findViewById(R.id.projects); 107 mGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 108 @Override 109 public void onItemClick(AdapterView<?> parent, View view, 110 int position, long id) { 111 // If user clicks on the last item, then create a new project. 112 if (position == mProjects.size()) { 113 showDialog(DIALOG_NEW_PROJECT_ID); 114 } else { 115 openProject(mProjects.get(position).getPath()); 116 } 117 } 118 }); 119 // Upon long press, pop up a menu with a removal option. 120 mGridView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { 121 @Override 122 public boolean onItemLongClick(AdapterView<?> parent, View view, 123 final int position, long id) { 124 // Open new project dialog when user clicks on the "create new project" card. 125 if (position == mProjects.size()) { 126 showDialog(DIALOG_NEW_PROJECT_ID); 127 return true; 128 } 129 // Otherwise, pop up a menu with a project removal option. 130 final PopupMenu popupMenu = new PopupMenu(ProjectsActivity.this, view); 131 popupMenu.getMenuInflater().inflate(R.menu.project_menu, popupMenu.getMenu()); 132 popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { 133 @Override 134 public boolean onMenuItemClick(MenuItem menuItem) { 135 switch (menuItem.getItemId()) { 136 case R.id.action_remove_project: 137 final Bundle bundle = new Bundle(); 138 bundle.putString(PARAM_DIALOG_PATH_ID, 139 mProjects.get(position).getPath()); 140 showDialog(DIALOG_REMOVE_PROJECT_ID, bundle); 141 break; 142 default: 143 break; 144 } 145 return true; 146 } 147 }); 148 popupMenu.show(); 149 return true; 150 }}); 151 } 152 153 @Override 154 public void onResume() { 155 super.onResume(); 156 ApiService.registerListener(mProjectsLoadedListener); 157 ApiService.loadProjects(this); 158 } 159 160 @Override 161 public void onPause() { 162 super.onPause(); 163 ApiService.unregisterListener(mProjectsLoadedListener); 164 mAdapter = null; 165 mGridView.setAdapter(null); 166 } 167 168 @Override 169 public boolean onCreateOptionsMenu(Menu menu) { 170 menu.add(Menu.NONE, MENU_NEW_PROJECT_ID, Menu.NONE, R.string.projects_new_project) 171 .setIcon(R.drawable.ic_menu_add_video) 172 .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); 173 return true; 174 } 175 176 @Override 177 public boolean onOptionsItemSelected(MenuItem item) { 178 switch (item.getItemId()) { 179 case MENU_NEW_PROJECT_ID: { 180 showDialog(DIALOG_NEW_PROJECT_ID); 181 return true; 182 } 183 184 default: { 185 return false; 186 } 187 } 188 } 189 190 @Override 191 public Dialog onCreateDialog(int id, final Bundle bundle) { 192 switch (id) { 193 case DIALOG_NEW_PROJECT_ID: { 194 return AlertDialogs.createEditDialog( 195 this, 196 null, // No title 197 null, // No text in the edit box 198 getString(android.R.string.ok), 199 new DialogInterface.OnClickListener() { 200 @Override 201 public void onClick(DialogInterface dialog, int which) { 202 final TextView tv = 203 (TextView)((AlertDialog)dialog).findViewById(R.id.text_1); 204 final String projectName = tv.getText().toString(); 205 removeDialog(DIALOG_NEW_PROJECT_ID); 206 createProject(projectName); 207 } 208 }, 209 getString(android.R.string.cancel), 210 new DialogInterface.OnClickListener() { 211 @Override 212 public void onClick(DialogInterface dialog, int which) { 213 removeDialog(DIALOG_NEW_PROJECT_ID); 214 } 215 }, 216 new DialogInterface.OnCancelListener() { 217 @Override 218 public void onCancel(DialogInterface dialog) { 219 removeDialog(DIALOG_NEW_PROJECT_ID); 220 } 221 }, 222 InputType.TYPE_NULL, 223 32, 224 getString(R.string.projects_project_name)); 225 } 226 227 case DIALOG_REMOVE_PROJECT_ID: { 228 final String projectPath = bundle.getString(PARAM_DIALOG_PATH_ID); 229 return AlertDialogs.createAlert( 230 this, 231 getString(R.string.editor_delete_project), 232 0, // no icons for this dialog. 233 getString(R.string.editor_delete_project_question), 234 getString(R.string.yes), 235 new DialogInterface.OnClickListener() { 236 @Override 237 public void onClick(DialogInterface dialog, int which) { 238 removeDialog(DIALOG_REMOVE_PROJECT_ID); 239 deleteProject(projectPath); 240 } 241 }, 242 getString(R.string.no), 243 new DialogInterface.OnClickListener() { 244 @Override 245 public void onClick(DialogInterface dialog, int which) { 246 removeDialog(DIALOG_REMOVE_PROJECT_ID); 247 } 248 }, 249 new DialogInterface.OnCancelListener() { 250 @Override 251 public void onCancel(DialogInterface dialog) { 252 removeDialog(DIALOG_REMOVE_PROJECT_ID); 253 } 254 }, 255 true); 256 } 257 258 default: { 259 return null; 260 } 261 } 262 } 263 264 @Override 265 protected void onPrepareDialog(int id, Dialog dialog, Bundle args) { 266 switch (id) { 267 // A workaround to handle the OK button. We can't access the button with getButton() 268 // when building the dialog in AlertDialogs, hence we postpone the enabling/disabling 269 // of the positive button until the dialog is to be shown here. 270 case DIALOG_NEW_PROJECT_ID: 271 final AlertDialog newProjectDialog = (AlertDialog) dialog; 272 Button positiveButton = newProjectDialog.getButton(AlertDialog.BUTTON_POSITIVE); 273 final TextView inputField = 274 (TextView) newProjectDialog.findViewById(R.id.text_1); 275 positiveButton.setEnabled(inputField.getText().toString().trim().length() > 0); 276 default: 277 return; 278 } 279 } 280 281 private void deleteProject(final String projectPath) { 282 ApiService.deleteProject(ProjectsActivity.this, projectPath); 283 mAdapter.remove(projectPath); 284 } 285 286 private void createProject(String projectName) { 287 try { 288 final Intent intent = new Intent(this, VideoEditorActivity.class); 289 intent.setAction(Intent.ACTION_INSERT); 290 intent.putExtra(PARAM_CREATE_PROJECT_NAME, projectName); 291 final String projectPath = FileUtils.createNewProjectPath(this); 292 intent.putExtra(PARAM_OPEN_PROJECT_PATH, projectPath); 293 startActivityForResult(intent, REQUEST_CODE_CREATE_PROJECT); 294 } catch (Exception ex) { 295 ex.printStackTrace(); 296 Toast.makeText(this, R.string.editor_storage_not_available, 297 Toast.LENGTH_LONG).show(); 298 } 299 } 300 301 private void openProject(String projectPath) { 302 final Intent intent = new Intent(this, VideoEditorActivity.class); 303 intent.setAction(Intent.ACTION_EDIT); 304 intent.putExtra(PARAM_OPEN_PROJECT_PATH, projectPath); 305 startActivityForResult(intent, REQUEST_CODE_OPEN_PROJECT); 306 } 307 308 private static void logd(String message) { 309 if (Log.isLoggable(LOG_TAG, Log.DEBUG)) { 310 Log.d(LOG_TAG, message); 311 } 312 } 313 } 314